Quellcode durchsuchen

增加任务调度(定时器)管理页面

zuohuaijun vor 3 Jahren
Ursprung
Commit
5713da3b9e

+ 0 - 5
Admin.NET/Admin.NET.Core/Admin.NET.Core.xml

@@ -6338,11 +6338,6 @@
             任务状态
             </summary>
         </member>
-        <member name="T:Admin.NET.Core.Service.TimerMethod">
-            <summary>
-            定时任务方法
-            </summary>
-        </member>
         <member name="P:Admin.NET.Core.Service.TimerMethod.MethodName">
             <summary>
             方法名

+ 4 - 2
Admin.NET/Admin.NET.Core/Service/Timer/Dto/TimerInput.cs

@@ -18,14 +18,16 @@ public class AddTimerInput : SysTimer
     public override string TimerName { get; set; }
 }
 
-public class DeleteTimerInput : BaseIdInput
+[NotTable]
+public class UpdateTimerInput : AddTimerInput
 {
 }
 
-public class UpdateTimerInput : AddTimerInput
+public class DeleteTimerInput : BaseIdInput
 {
 }
 
+[NotTable]
 public class StopTimerInput : AddTimerInput
 {
 }

+ 0 - 3
Admin.NET/Admin.NET.Core/Service/Timer/Dto/TimerMethod.cs

@@ -1,8 +1,5 @@
 namespace Admin.NET.Core.Service;
 
-/// <summary>
-/// 定时任务方法
-/// </summary>
 [NotTable]
 public class TimerMethod : SysTimer
 {

+ 1 - 1
vue-next-admin/src/views/system/log/difflog/index.vue

@@ -11,7 +11,7 @@
 				<el-form-item>
 					<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
 					<el-button type="primary" icon="ele-Search" @click="handleQuery"> 查询 </el-button>
-					<el-button icon="ele-DeleteFilled" @click="clearLog"> 清空 </el-button>
+					<el-button icon="ele-DeleteFilled" type="danger" @click="clearLog"> 清空 </el-button>
 				</el-form-item>
 			</el-form>
 		</el-card>

+ 1 - 1
vue-next-admin/src/views/system/log/exlog/index.vue

@@ -11,7 +11,7 @@
 				<el-form-item>
 					<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
 					<el-button type="primary" icon="ele-Search" @click="handleQuery"> 查询 </el-button>
-					<el-button icon="ele-DeleteFilled" @click="clearLog"> 清空 </el-button>
+					<el-button icon="ele-DeleteFilled" type="danger" @click="clearLog"> 清空 </el-button>
 				</el-form-item>
 			</el-form>
 		</el-card>

+ 1 - 1
vue-next-admin/src/views/system/log/oplog/index.vue

@@ -11,7 +11,7 @@
 				<el-form-item>
 					<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
 					<el-button type="primary" icon="ele-Search" @click="handleQuery"> 查询 </el-button>
-					<el-button icon="ele-DeleteFilled" @click="clearLog"> 清空 </el-button>
+					<el-button icon="ele-DeleteFilled" type="danger" @click="clearLog"> 清空 </el-button>
 				</el-form-item>
 			</el-form>
 		</el-card>

+ 1 - 1
vue-next-admin/src/views/system/log/vislog/index.vue

@@ -11,7 +11,7 @@
 				<el-form-item>
 					<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
 					<el-button type="primary" icon="ele-Search" @click="handleQuery"> 查询 </el-button>
-					<el-button icon="ele-DeleteFilled" @click="clearLog"> 清空 </el-button>
+					<el-button icon="ele-DeleteFilled" type="danger" @click="clearLog"> 清空 </el-button>
 				</el-form-item>
 			</el-form>
 		</el-card>

+ 0 - 1
vue-next-admin/src/views/system/server/index.vue

@@ -177,7 +177,6 @@ export default defineComponent({
 		onDeactivated(() => {
 			clearInterval(state.timer);
 		});
-
 		return {
 			loadMachineBaseInfo,
 			loadMachineUseInfo,

+ 146 - 0
vue-next-admin/src/views/system/timer/component/editTimer.vue

@@ -0,0 +1,146 @@
+<template>
+	<div class="sys-timer-container">
+		<el-dialog v-model="isShowDialog" width="769px">
+			<template #header>
+				<div style="font-size: large" v-drag="['.el-dialog', '.el-dialog__header']">
+					{{ title }}
+				</div>
+			</template>
+			<el-form :model="ruleForm" :rules="ruleRules" ref="ruleFormRef" size="default" label-width="100px">
+				<el-row :gutter="35">
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="任务名称" prop="timerName">
+							<el-input v-model="ruleForm.timerName" placeholder="任务名称" clearable></el-input>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="请求地址" prop="requestUrl">
+							<el-input v-model="ruleForm.requestUrl" placeholder="请求地址" clearable></el-input>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="请求类型" prop="requestType">
+							<el-radio-group v-model="ruleForm.requestType">
+								<el-radio :label="0">RUN</el-radio>
+								<el-radio :label="1">GET</el-radio>
+								<el-radio :label="2">POST</el-radio>
+								<el-radio :label="3">PUT</el-radio>
+								<el-radio :label="4">DELETE</el-radio>
+							</el-radio-group>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="请求参数" prop="requestPara">
+							<el-input v-model="ruleForm.requestPara" placeholder="所属分类" clearable type="textarea"></el-input>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="任务类型" prop="timerType">
+							<el-select v-model="ruleForm.timerType" placeholder="岗位状态" style="width: 100%">
+								<el-option label="间隔模式" :value="0" />
+								<el-option label="Cron模式" :value="1" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="执行间隔" prop="interval" v-if="ruleForm.timerType == 0">
+							<el-input v-model="ruleForm.interval" placeholder="执行间隔" clearable></el-input>
+						</el-form-item>
+						<el-form-item label="Cron表达式" prop="cron" v-else>
+							<el-input v-model="ruleForm.cron" placeholder="Cron表达式" clearable></el-input>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="备注">
+							<el-input v-model="ruleForm.remark" placeholder="请输入备注内容" clearable type="textarea"> </el-input>
+						</el-form-item>
+					</el-col>
+				</el-row>
+			</el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel" size="default">取 消</el-button>
+					<el-button type="primary" @click="submit" size="default">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts">
+import { reactive, toRefs, defineComponent, getCurrentInstance, ref } from 'vue';
+
+import { getAPI } from '/@/utils/axios-utils';
+import { SysTimerApi } from '/@/api-services/api';
+
+export default defineComponent({
+	name: 'sysEditTimer',
+	components: {},
+	props: {
+		// 弹窗标题
+		title: {
+			type: String,
+			default: '',
+		},
+	},
+	setup() {
+		const { proxy } = getCurrentInstance() as any;
+		const ruleFormRef = ref();
+		const state = reactive({
+			isShowDialog: false,
+			ruleForm: {
+				id: 0, // Id
+				timerName: '', // 任务名称
+				requestUrl: '', // 请求地址
+				requestType: 1, // 请求类型
+				requestPara: '', // 请求参数
+				timerType: 0, // 任务类型
+				interval: 5, // 执行间隔
+				cron: '', // cron表达式
+				remark: '', // 备注
+			},
+			ruleRules: {
+				timerName: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
+				requestUrl: [{ required: true, message: '请求地址不能为空', trigger: 'blur' }],
+				requestType: [{ required: true, message: '请求类型不能为空', trigger: 'blur' }],
+				timerType: [{ required: true, message: '任务类型不能为空', trigger: 'blur' }],
+			},
+		});
+		// 打开弹窗
+		const openDialog = (row: any) => {
+			console.log(row);
+			state.ruleForm = row;
+			state.isShowDialog = true;
+		};
+		// 关闭弹窗
+		const closeDialog = () => {
+			proxy.mittBus.emit('submitRefresh');
+			state.isShowDialog = false;
+		};
+		// 取消
+		const cancel = () => {
+			state.isShowDialog = false;
+		};
+		// 提交
+		const submit = () => {
+			ruleFormRef.value.validate(async (valid: boolean) => {
+				if (!valid) return;
+				if (state.ruleForm.id != undefined && state.ruleForm.id > 0) {
+					await getAPI(SysTimerApi).sysTimerUpdatePost(state.ruleForm);
+				} else {
+					await getAPI(SysTimerApi).sysTimerAddPost(state.ruleForm);
+				}
+				closeDialog();
+			});
+		};
+		return {
+			ruleFormRef,
+			openDialog,
+			closeDialog,
+			cancel,
+			submit,
+			...toRefs(state),
+		};
+	},
+});
+</script>

+ 200 - 0
vue-next-admin/src/views/system/timer/index.vue

@@ -0,0 +1,200 @@
+<template>
+	<div class="sys-timer-container">
+		<el-card shadow="hover" :body-style="{ paddingBottom: '0' }">
+			<el-form :model="queryParams" ref="queryForm" :inline="true">
+				<el-form-item label="任务名称" prop="timerName">
+					<el-input placeholder="任务名称" clearable @keyup.enter="handleQuery" v-model="queryParams.timerName" />
+				</el-form-item>
+				<el-form-item>
+					<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
+					<el-button type="primary" icon="ele-Search" @click="handleQuery"> 查询 </el-button>
+					<el-button icon="ele-Plus" @click="openAddTimer"> 新增 </el-button>
+				</el-form-item>
+			</el-form>
+		</el-card>
+
+		<el-card shadow="hover" style="margin-top: 8px">
+			<el-table :data="timerData" style="width: 100%" v-loading="loading" border>
+				<el-table-column type="index" label="序号" width="55" align="center" />
+				<el-table-column prop="timerName" label="任务名称" show-overflow-tooltip></el-table-column>
+				<el-table-column prop="requestUrl" label="请求地址" show-overflow-tooltip></el-table-column>
+				<el-table-column prop="requestType" label="请求类型" width="100" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-tag type="info" v-if="scope.row.requestType == 0"> {{ 'RUN' }} </el-tag>
+						<el-tag type="info" v-else-if="scope.row.requestType == 1"> {{ 'GET' }} </el-tag>
+						<el-tag type="info" v-else-if="scope.row.requestType == 2"> {{ 'POST' }} </el-tag>
+						<el-tag type="info" v-else-if="scope.row.requestType == 3"> {{ 'PUT' }} </el-tag>
+						<el-tag type="info" v-else-if="scope.row.requestType == 4"> {{ 'DELETE' }} </el-tag>
+					</template>
+				</el-table-column>
+				<el-table-column prop="timerType" label="任务类型" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						{{ scope.row.timerType == 0 ? scope.row.interval : scope.row.cron }}
+					</template>
+				</el-table-column>
+				<el-table-column prop="executeType" label="执行类型" width="100" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						{{ scope.row.executeType == 0 ? '并行' : '串行' }}
+					</template>
+				</el-table-column>
+				<el-table-column prop="doOnce" label="执行一次" width="100" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						{{ scope.row.doOnce ? '是' : '否' }}
+					</template>
+				</el-table-column>
+				<el-table-column prop="startNow" label="立即执行" width="100" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						{{ scope.row.startNow ? '是' : '否' }}
+					</template>
+				</el-table-column>
+				<el-table-column prop="status" label="任务状态" width="100" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-tag type="success" v-if="scope.row.status == 0"> {{ '运行中' }} </el-tag>
+						<el-tag type="danger" v-else-if="scope.row.status == 1"> {{ '已停止' }} </el-tag>
+						<el-tag type="danger" v-else-if="scope.row.status == 2"> {{ '已失败' }} </el-tag>
+						<el-tag type="danger" v-else-if="scope.row.status == 3"> {{ '已删除' }} </el-tag>
+					</template>
+				</el-table-column>
+				<el-table-column prop="status" label="启动停止" width="100" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1" size="small" @change="changeStatus(scope.row)" v-auth="'sysTimer:setStatus'" />
+					</template>
+				</el-table-column>
+				<el-table-column prop="tally" label="执行次数" width="100" align="center" show-overflow-tooltip></el-table-column>
+				<el-table-column prop="createTime" label="修改时间" align="center" show-overflow-tooltip></el-table-column>
+				<el-table-column prop="remark" label="备注" show-overflow-tooltip></el-table-column>
+				<el-table-column label="操作" width="140" fixed="right" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-button icon="ele-Edit" size="small" text type="primary" @click="openEditTimer(scope.row)"> 编辑 </el-button>
+						<el-button icon="ele-Delete" size="small" text type="danger" @click="delTimer(scope.row)"> 删除 </el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+			<el-pagination
+				v-model:currentPage="tableParams.page"
+				v-model:page-size="tableParams.pageSize"
+				:total="tableParams.total"
+				:page-sizes="[10, 20, 50, 100]"
+				small
+				background
+				@size-change="handleSizeChange"
+				@current-change="handleCurrentChange"
+				layout="total, sizes, prev, pager, next, jumper"
+			/>
+		</el-card>
+		<EditTimer ref="editTimerRef" :title="editTimerTitle" />
+	</div>
+</template>
+
+<script lang="ts">
+import { toRefs, reactive, onMounted, ref, defineComponent, onUnmounted, getCurrentInstance, onActivated, onDeactivated } from 'vue';
+import { ElMessageBox, ElMessage } from 'element-plus';
+import EditTimer from '/@/views/system/timer/component/editTimer.vue';
+
+import { getAPI } from '/@/utils/axios-utils';
+import { SysTimerApi } from '/@/api-services';
+
+export default defineComponent({
+	name: 'sysTimer',
+	components: { EditTimer },
+	setup() {
+		const { proxy } = getCurrentInstance() as any;
+		const editTimerRef = ref();
+		const state = reactive({
+			loading: true,
+			timerData: [] as any,
+			queryParams: {
+				timerName: undefined,
+			},
+			tableParams: {
+				page: 1,
+				pageSize: 10,
+				total: 0 as any,
+			},
+			editTimerTitle: '',
+			timer: null as any,
+		});
+		onMounted(async () => {
+			handleQuery();
+
+			proxy.mittBus.on('submitRefresh', () => {
+				handleQuery();
+			});
+		});
+		onUnmounted(() => {
+			proxy.mittBus.off('submitRefresh');
+		});
+		// 查询操作
+		const handleQuery = async () => {
+			state.loading = true;
+			var res = await getAPI(SysTimerApi).sysTimerPageGet(state.queryParams.timerName, state.tableParams.page, state.tableParams.pageSize);
+			state.timerData = res.data.result?.items;
+			state.tableParams.total = res.data.result?.total;
+			state.loading = false;
+		};
+		// 重置操作
+		const resetQuery = () => {
+			state.queryParams.timerName = undefined;
+			handleQuery();
+		};
+		// 打开新增页面
+		const openAddTimer = () => {
+			state.editTimerTitle = '添加任务';
+			editTimerRef.value.openDialog({});
+		};
+		// 打开编辑页面
+		const openEditTimer = (row: any) => {
+			state.editTimerTitle = '编辑任务';
+			editTimerRef.value.openDialog(row);
+		};
+		// 删除
+		const delTimer = (row: any) => {
+			ElMessageBox.confirm(`确定删除任务:【${row.timerName}】?`, '提示', {
+				confirmButtonText: '确定',
+				cancelButtonText: '取消',
+				type: 'warning',
+			})
+				.then(async () => {
+					await getAPI(SysTimerApi).sysTimerDeletePost({ id: row.id });
+					handleQuery();
+					ElMessage.success('删除成功');
+				})
+				.catch(() => {});
+		};
+		// 改变页面容量
+		const handleSizeChange = (val: number) => {
+			state.tableParams.pageSize = val;
+			handleQuery();
+		};
+		// 改变页码序号
+		const handleCurrentChange = (val: number) => {
+			state.tableParams.page = val;
+			handleQuery();
+		};
+		// 修改状态
+		const changeStatus = async (row: any) => {
+			await getAPI(SysTimerApi).sysTimerSetStatusPost({ timerName: row.timerName, status: row.status });
+		};
+		onActivated(() => {
+			state.timer = setInterval(() => {
+				handleQuery();
+			}, 10000);
+		});
+		onDeactivated(() => {
+			clearInterval(state.timer);
+		});
+		return {
+			handleQuery,
+			resetQuery,
+			editTimerRef,
+			openAddTimer,
+			openEditTimer,
+			delTimer,
+			handleSizeChange,
+			handleCurrentChange,
+			changeStatus,
+			...toRefs(state),
+		};
+	},
+});
+</script>