mirror of
https://github.com/lzh-1625/go_process_manager.git
synced 2025-10-06 00:16:53 +08:00
add task ui
This commit is contained in:
@@ -4,7 +4,6 @@ import LandingLayout from "@/layouts/LandingLayout.vue";
|
|||||||
import DefaultLayout from "@/layouts/DefaultLayout.vue";
|
import DefaultLayout from "@/layouts/DefaultLayout.vue";
|
||||||
import AuthLayout from "@/layouts/AuthLayout.vue";
|
import AuthLayout from "@/layouts/AuthLayout.vue";
|
||||||
|
|
||||||
import BackToTop from "@/components/common/BackToTop.vue";
|
|
||||||
import Snackbar from "@/components/common/Snackbar.vue";
|
import Snackbar from "@/components/common/Snackbar.vue";
|
||||||
import { useAppStore } from "@/stores/appStore";
|
import { useAppStore } from "@/stores/appStore";
|
||||||
import { useTheme } from "vuetify";
|
import { useTheme } from "vuetify";
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
|
import { TaskItem } from "../types/tassk/task";
|
||||||
import api from "./api";
|
import api from "./api";
|
||||||
|
|
||||||
export function getTaskAll() {
|
export function getTaskAll() {
|
||||||
return api.get("/task/all", undefined).then((res) => res);
|
return api.get<TaskItem[]>("/task/all", undefined).then((res) => res);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTaskAllWait() {
|
export function getTaskAllWait() {
|
||||||
@@ -9,7 +10,7 @@ export function getTaskAllWait() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getTaskById(id) {
|
export function getTaskById(id) {
|
||||||
return api.get("/task", { id }).then((res) => res);
|
return api.get<TaskItem>("/task", { id }).then((res) => res);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function startTaskById(id) {
|
export function startTaskById(id) {
|
||||||
|
@@ -14,7 +14,6 @@ import VueVirtualScroller from "vue-virtual-scroller";
|
|||||||
import "vue-virtual-scroller/dist/vue-virtual-scroller.css";
|
import "vue-virtual-scroller/dist/vue-virtual-scroller.css";
|
||||||
import VueApexCharts from "vue3-apexcharts";
|
import VueApexCharts from "vue3-apexcharts";
|
||||||
import piniaPersist from "pinia-plugin-persist";
|
import piniaPersist from "pinia-plugin-persist";
|
||||||
import { PerfectScrollbarPlugin } from 'vue3-perfect-scrollbar';
|
|
||||||
import 'vue3-perfect-scrollbar/style.css';
|
import 'vue3-perfect-scrollbar/style.css';
|
||||||
import "@/styles/main.scss";
|
import "@/styles/main.scss";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
@@ -31,7 +30,6 @@ const app = createApp(App);
|
|||||||
app.config.globalProperties.$echarts = echarts;
|
app.config.globalProperties.$echarts = echarts;
|
||||||
app.directive('permission', permission);
|
app.directive('permission', permission);
|
||||||
app.use(router);
|
app.use(router);
|
||||||
app.use(PerfectScrollbarPlugin);
|
|
||||||
app.use(MasonryWall);
|
app.use(MasonryWall);
|
||||||
app.use(VueVirtualScroller);
|
app.use(VueVirtualScroller);
|
||||||
app.use(VueApexCharts);
|
app.use(VueApexCharts);
|
||||||
|
19
resources/src/types/tassk/task.ts
Normal file
19
resources/src/types/tassk/task.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
export interface TaskItem {
|
||||||
|
id: number;
|
||||||
|
processId: number;
|
||||||
|
condition: number;
|
||||||
|
nextId: null;
|
||||||
|
operation: number;
|
||||||
|
triggerEvent: null;
|
||||||
|
triggerTarget: null;
|
||||||
|
operationTarget: number;
|
||||||
|
cron: string;
|
||||||
|
enable: boolean;
|
||||||
|
apiEnable: boolean;
|
||||||
|
key: string;
|
||||||
|
processName: string;
|
||||||
|
targetName: string;
|
||||||
|
triggerName: string;
|
||||||
|
startTime: Date;
|
||||||
|
running: boolean;
|
||||||
|
}
|
@@ -31,7 +31,6 @@ import {
|
|||||||
killProcessAll,
|
killProcessAll,
|
||||||
startProcessAll,
|
startProcessAll,
|
||||||
} from "~/src/api/process";
|
} from "~/src/api/process";
|
||||||
import ConfirmButton from "~/src/components/ConfirmButton.vue";
|
|
||||||
import ProcessCreate from "~/src/components/process/ProcessCreate.vue";
|
import ProcessCreate from "~/src/components/process/ProcessCreate.vue";
|
||||||
import { useSnackbarStore } from "~/src/stores/snackbarStore";
|
import { useSnackbarStore } from "~/src/stores/snackbarStore";
|
||||||
import { ProcessItem } from "~/src/types/process/process";
|
import { ProcessItem } from "~/src/types/process/process";
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<v-data-table
|
<v-data-table
|
||||||
:headers="headers"
|
:headers="headers"
|
||||||
:items="items"
|
:items="taskData"
|
||||||
:items-per-page="5"
|
:items-per-page="5"
|
||||||
item-key="id"
|
item-key="id"
|
||||||
class="elevation-1"
|
class="elevation-1"
|
||||||
@@ -15,21 +15,42 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #item.enable="{ item }">
|
<template #item.enable="{ item }">
|
||||||
<v-chip size="small" variant="tonal">{{
|
<v-switch
|
||||||
item.enable ? "启用" : "未启用"
|
color="primary"
|
||||||
}}</v-chip>
|
@change="changeEnable(item)"
|
||||||
|
v-model="item.enable"
|
||||||
|
></v-switch>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #item.apiEnable="{ item }">
|
<template #item.apiEnable="{ item }">
|
||||||
<v-chip size="small" variant="tonal">{{
|
<v-switch
|
||||||
item.apiEnable ? "可用" : "不可用"
|
color="primary"
|
||||||
}}</v-chip>
|
@change="edit(item)"
|
||||||
|
v-model="item.apiEnable"
|
||||||
|
></v-switch>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #item.running="{ item }">
|
<template #item.running="{ item }">
|
||||||
<v-chip size="small" variant="tonal">{{
|
<svg
|
||||||
item.running ? "运行中" : "未运行"
|
v-if="item.running"
|
||||||
}}</v-chip>
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 48 48"
|
||||||
|
fill="#000000"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M25 34a1 1 0 011 1v10a1 1 0 01-1 1h-2a1 1 0 01-1-1V35a1 1 0 011-1h2zm8.192-3.636l7.072 7.071a1 1 0 010 1.414l-1.415 1.415a1 1 0 01-1.414 0l-7.071-7.072a1 1 0 010-1.414l1.414-1.414a1 1 0 011.414 0zm-16.97 0l1.414 1.414a1 1 0 010 1.414l-7.071 7.072a1 1 0 01-1.414 0l-1.414-1.415a1 1 0 010-1.414l7.07-7.071a1 1 0 011.415 0zM45 22a1 1 0 011 1v2a1 1 0 01-1 1H35a1 1 0 01-1-1v-2a1 1 0 011-1h10zm-32 0a1 1 0 011 1v2a1 1 0 01-1 1H3a1 1 0 01-1-1v-2a1 1 0 011-1h10zM10.565 7.737l7.071 7.07a1 1 0 010 1.415l-1.414 1.414a1 1 0 01-1.414 0l-7.071-7.071a1 1 0 010-1.414L9.15 7.737a1 1 0 011.414 0zm28.284 0l1.415 1.414a1 1 0 010 1.414l-7.072 7.071a1 1 0 01-1.414 0l-1.414-1.414a1 1 0 010-1.414l7.071-7.071a1 1 0 011.414 0zM25 2a1 1 0 011 1v10a1 1 0 01-1 1h-2a1 1 0 01-1-1V3a1 1 0 011-1h2z"
|
||||||
|
fill="#000000"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<svg v-else width="20" height="20" viewBox="0 0 48 48" fill="#000000">
|
||||||
|
<path
|
||||||
|
d="M42.02 12.71l-1.38-1.42a1 1 0 00-1.41 0L18.01 32.5l-9.9-9.89a1 1 0 00-1.41 0l-1.41 1.41a1 1 0 000 1.41l10.6 10.61 1.42 1.41a1 1 0 001.41 0l1.41-1.41 21.92-21.92a1 1 0 00-.03-1.41z"
|
||||||
|
fill="#000000"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #item.startTime="{ item }">
|
<template #item.startTime="{ item }">
|
||||||
@@ -41,16 +62,138 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 如果需要可以加 actions 列 -->
|
<!-- 如果需要可以加 actions 列 -->
|
||||||
<template #body.append>
|
<template #item.operate="{ item }">
|
||||||
<!-- 这里可以放底部说明或按钮 -->
|
<!-- 这里可以放底部说明或按钮 -->
|
||||||
|
<v-icon class="mr-2" v-if="!item.running"> mdi-play </v-icon>
|
||||||
|
<v-icon class="mr-2" v-else> mdi-stop </v-icon>
|
||||||
|
<v-icon class="mr-2"> mdi-pencil </v-icon>
|
||||||
|
<v-icon> mdi-delete </v-icon>
|
||||||
</template>
|
</template>
|
||||||
</v-data-table>
|
</v-data-table>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
|
<v-dialog v-model="taskDialog" max-width="500px">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title class="text-h5">{{
|
||||||
|
addTask ? "添加任务" : "修改任务"
|
||||||
|
}}</v-card-title>
|
||||||
|
<v-card-text style="margin-top: 20px">
|
||||||
|
<v-autocomplete
|
||||||
|
label="判断条件"
|
||||||
|
item-text="name"
|
||||||
|
item-value="value"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
:items="conditionSelect"
|
||||||
|
v-model="taskForm.condition"
|
||||||
|
></v-autocomplete>
|
||||||
|
<v-autocomplete
|
||||||
|
v-if="taskForm.condition != 3"
|
||||||
|
label="判断目标"
|
||||||
|
item-text="name"
|
||||||
|
item-value="value"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
:items="processSelect"
|
||||||
|
v-model="taskForm.processId"
|
||||||
|
></v-autocomplete>
|
||||||
|
<v-autocomplete
|
||||||
|
label="操作目标"
|
||||||
|
item-text="name"
|
||||||
|
item-value="value"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
:items="processSelect"
|
||||||
|
v-model="taskForm.operationTarget"
|
||||||
|
></v-autocomplete>
|
||||||
|
<v-autocomplete
|
||||||
|
label="执行操作"
|
||||||
|
item-text="name"
|
||||||
|
item-value="value"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
:items="operationSelect"
|
||||||
|
v-model="taskForm.operation"
|
||||||
|
></v-autocomplete>
|
||||||
|
<v-autocomplete
|
||||||
|
label="触发目标"
|
||||||
|
item-text="name"
|
||||||
|
item-value="value"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
:items="processSelect"
|
||||||
|
v-model="taskForm.triggerTarget"
|
||||||
|
></v-autocomplete>
|
||||||
|
<v-autocomplete
|
||||||
|
v-if="taskForm.triggerTarget != null"
|
||||||
|
label="触发事件"
|
||||||
|
item-text="name"
|
||||||
|
item-value="value"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
:items="eventSelect"
|
||||||
|
v-model="taskForm.triggerEvent"
|
||||||
|
></v-autocomplete>
|
||||||
|
<v-autocomplete
|
||||||
|
label="后续任务"
|
||||||
|
item-text="name"
|
||||||
|
item-value="value"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
:items="taskSelect"
|
||||||
|
v-model="taskForm.nextId"
|
||||||
|
></v-autocomplete>
|
||||||
|
<v-text-field
|
||||||
|
label="定时任务"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
v-model="taskForm.cron"
|
||||||
|
></v-text-field>
|
||||||
|
<v-text-field
|
||||||
|
@click="copyToClipboard"
|
||||||
|
:disabled="taskForm?.key == null"
|
||||||
|
label="api"
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
readonly
|
||||||
|
:value="taskForm.key != null ? urlBase + taskForm.key : '未创建api'"
|
||||||
|
></v-text-field>
|
||||||
|
|
||||||
|
<v-btn @click="changeApi" color="primary">
|
||||||
|
{{ taskForm?.key != null ? "刷新api" : "创建api" }}
|
||||||
|
<v-icon right dark>
|
||||||
|
{{ taskForm?.key != null ? "mdi-refresh" : "mdi-plus" }}</v-icon
|
||||||
|
>
|
||||||
|
</v-btn>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="blue darken-1" text @click="taskDialog = false"
|
||||||
|
>取消</v-btn
|
||||||
|
>
|
||||||
|
<v-btn color="blue darken-1" text @click="submit">确认</v-btn>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
import {
|
||||||
|
changeTaskKey,
|
||||||
|
editTask,
|
||||||
|
editTaskEnable,
|
||||||
|
getTaskAll,
|
||||||
|
getTaskById,
|
||||||
|
} from "~/src/api/task";
|
||||||
|
import { useSnackbarStore } from "~/src/stores/snackbarStore";
|
||||||
|
import { TaskItem } from "~/src/types/tassk/task";
|
||||||
|
|
||||||
|
const snackbarStore = useSnackbarStore();
|
||||||
|
const taskDialog = ref(false);
|
||||||
|
const taskForm = ref<Partial<TaskItem>>({});
|
||||||
|
const addTask = ref(false);
|
||||||
/**
|
/**
|
||||||
* 自定义列头:title -> 显示标题(中文),key -> 对应数据字段名
|
* 自定义列头:title -> 显示标题(中文),key -> 对应数据字段名
|
||||||
* (Vuetify 3 的 headers 使用 title/key 风格)
|
* (Vuetify 3 的 headers 使用 title/key 风格)
|
||||||
@@ -58,47 +201,21 @@ import { ref } from "vue";
|
|||||||
const headers = [
|
const headers = [
|
||||||
{ title: "任务ID", key: "id" },
|
{ title: "任务ID", key: "id" },
|
||||||
{ title: "任务名", key: "processName" },
|
{ title: "任务名", key: "processName" },
|
||||||
{ title: "流程 ID", key: "processId" },
|
{ title: "进程ID", key: "processId" },
|
||||||
{ title: "条件", key: "condition" },
|
|
||||||
{ title: "下一步 ID", key: "nextId" },
|
{ title: "下一步 ID", key: "nextId" },
|
||||||
{ title: "触发进程", key: "targetName" },
|
|
||||||
{ title: "触发名称", key: "triggerName" },
|
|
||||||
{ title: "操作", key: "operation" },
|
|
||||||
{ title: "触发事件", key: "triggerEvent" },
|
|
||||||
{ title: "触发目标", key: "triggerTarget" },
|
|
||||||
{ title: "操作目标", key: "operationTarget" },
|
|
||||||
{ title: "定时任务", key: "cron" },
|
{ title: "定时任务", key: "cron" },
|
||||||
{ title: "是否启用", key: "enable" },
|
|
||||||
{ title: "API 可用", key: "apiEnable" },
|
|
||||||
{ title: "开始时间", key: "startTime" },
|
{ title: "开始时间", key: "startTime" },
|
||||||
{ title: "状态", key: "running" },
|
{ title: "状态", key: "running" },
|
||||||
|
{ title: "启用定时任务", key: "enable" },
|
||||||
|
{ title: "启用API", key: "apiEnable" },
|
||||||
|
{ title: "操作", key: "operate" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const rawData = {
|
|
||||||
id: 1,
|
|
||||||
processId: 0,
|
|
||||||
condition: 3,
|
|
||||||
nextId: null,
|
|
||||||
operation: 0,
|
|
||||||
triggerEvent: null,
|
|
||||||
triggerTarget: null,
|
|
||||||
operationTarget: 112,
|
|
||||||
cron: "",
|
|
||||||
enable: false,
|
|
||||||
apiEnable: true,
|
|
||||||
key: "bhCSw2QDdu",
|
|
||||||
processName: "",
|
|
||||||
targetName: "push",
|
|
||||||
triggerName: "",
|
|
||||||
startTime: "0001-01-01T00:00:00Z",
|
|
||||||
running: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 单行数组(v-data-table 接受 items 数组)
|
// 单行数组(v-data-table 接受 items 数组)
|
||||||
const items = ref([rawData]);
|
const taskData = ref<TaskItem[]>();
|
||||||
|
|
||||||
/** 格式化开始时间(兼容 null / 空字符串) */
|
/** 格式化开始时间(兼容 null / 空字符串) */
|
||||||
function formatStartTime(v) {
|
const formatStartTime = (v) => {
|
||||||
if (!v) return "-";
|
if (!v) return "-";
|
||||||
try {
|
try {
|
||||||
const d = new Date(v);
|
const d = new Date(v);
|
||||||
@@ -107,7 +224,49 @@ function formatStartTime(v) {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initTask();
|
||||||
|
});
|
||||||
|
|
||||||
|
const initTask = () => {
|
||||||
|
getTaskAll().then((e) => {
|
||||||
|
taskData.value = e.data!;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const edit = (item) => {
|
||||||
|
editTask(item).then((e) => {
|
||||||
|
if (e.code == 0) {
|
||||||
|
snackbarStore.showSuccessMessage("success");
|
||||||
|
initTask();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeEnable = (item) => {
|
||||||
|
editTaskEnable({
|
||||||
|
id: item.id,
|
||||||
|
enable: item.enable,
|
||||||
|
}).then((e) => {
|
||||||
|
if (e.code == 0) {
|
||||||
|
snackbarStore.showSuccessMessage("success");
|
||||||
|
initTask();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeApi = () => {
|
||||||
|
changeTaskKey(taskForm.value?.id).then((resp) => {
|
||||||
|
if (resp.code == 0) {
|
||||||
|
snackbarStore.showSuccessMessage("success");
|
||||||
|
getTaskById(taskForm.value?.id).then((e) => {
|
||||||
|
Object.assign(taskForm.value, e.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
Reference in New Issue
Block a user