Merge branch 'master' into net6.0

This commit is contained in:
不做码农 2022-03-17 21:38:30 +08:00
commit cb9bc0ea8f
17 changed files with 422 additions and 368 deletions

View File

@ -1,4 +1,11 @@
# ZRAdmin.NET
<h2 align="center"> ZRAdmin.NET后台管理系统</h2>
<h4 align="center">基于.NET5 + vue前后端分离的.net快速开发框架</h4>
<p align="center">
<a href="https://gitee.com/izory/ZrAdminNetCore"><img src="https://gitee.com/izory/ZrAdminNetCore/badge/star.svg?theme=dark"></a>
<a href="https://gitee.com/izory/ZrAdminNetCore/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
</p>
## 🍟概述
* 本项目适合有一定NetCore和 vue基础的开发人员
@ -11,7 +18,7 @@
* 七牛云通用云产品优惠券:[点我进入](https://s.qiniu.com/FzEfay)。
* 腾讯云秒杀场:[点我进入](https://curl.qcloud.com/4yEoRquq)。
* 腾讯云优惠券:[点我领取](https://curl.qcloud.com/5J4nag8D)。
*
```
如果对您有帮助,您可以点右上角 “Star” 收藏一下 ,这样作者才有继续免费下去的动力,谢谢!~
```
@ -123,6 +130,7 @@ Vue版前端技术栈 基于vue、vuex、vue-router 、vue-cli 、axios 和 e
## 💐 特别鸣谢
- 👉Ruoyi.vue[Ruoyi](http://www.ruoyi.vip/)
- 👉SqlSugar[SqlSugar](https://gitee.com/dotnetchina/SqlSugar)
- 👉vue-element-admin[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
## 🎀捐赠
如果这个项目对您有所帮助,请扫下方二维码就当打发要饭的吧。

View File

@ -86,7 +86,7 @@ namespace ZR.Admin.WebApi.Controllers
{
throw new CustomException($"添加 {parm.Name} 失败,该用任务存在,不能重复!");
}
if (string.IsNullOrEmpty(parm.Cron) || !CronExpression.IsValidExpression(parm.Cron))
if (!string.IsNullOrEmpty(parm.Cron) && !CronExpression.IsValidExpression(parm.Cron))
{
throw new CustomException($"cron表达式不正确");
}
@ -116,11 +116,11 @@ namespace ZR.Admin.WebApi.Controllers
{
throw new CustomException($"更新 {parm.Name} 失败,该用任务存在,不能重复!");
}
if (string.IsNullOrEmpty(parm.Cron))
if (string.IsNullOrEmpty(parm.Cron) && parm.TriggerType == 1)
{
throw new CustomException($"触发器 Corn 模式下,运行时间表达式必须填写");
}
if (!CronExpression.IsValidExpression(parm.Cron))
if (!string.IsNullOrEmpty(parm.Cron) && !CronExpression.IsValidExpression(parm.Cron))
{
throw new CustomException($"cron表达式不正确");
}
@ -150,7 +150,7 @@ namespace ZR.Admin.WebApi.Controllers
if (response > 0)
{
//先暂停原先的任务
var respon = await _schedulerServer.UpdateTaskScheduleAsync(tasksQz, tasksQz.JobGroup);
var respon = await _schedulerServer.UpdateTaskScheduleAsync(tasksQz);
}
return SUCCESS(response);
@ -264,11 +264,6 @@ namespace ZR.Admin.WebApi.Controllers
var tasksQz = _tasksQzService.GetFirst(m => m.ID == id);
var taskResult = await _schedulerServer.RunTaskScheduleAsync(tasksQz);
if (taskResult.Code == 200)
{
//_tasksQzService.Update(tasksQz);
}
return ToResponse(taskResult);
}

View File

@ -28,7 +28,7 @@ namespace ZR.Admin.WebApi.Extensions
{
string connStr = Configuration.GetConnectionString(OptionsSetting.ConnAdmin);
string connStrBus = Configuration.GetConnectionString(OptionsSetting.ConnBus);
string dbKey = Configuration[OptionsSetting.DbKey];
int dbType = Convert.ToInt32(Configuration[OptionsSetting.ConnDbType]);
int dbType_bus = Convert.ToInt32(Configuration[OptionsSetting.ConnBusDbType]);
@ -45,8 +45,10 @@ namespace ZR.Admin.WebApi.Extensions
IsAutoCloseConnection = true
}
});
//每次Sql执行前事件
DbScoped.SugarScope.GetConnection(0).Aop.OnLogExecuting = (sql, pars) =>
SugarIocServices.ConfigurationSugar(db =>
{
#region db0
db.GetConnection(0).Aop.OnLogExecuting = (sql, pars) =>
{
var param = DbScoped.SugarScope.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value));
@ -54,28 +56,33 @@ namespace ZR.Admin.WebApi.Extensions
logger.Info($"{sql}{param}");
};
//出错打印日志
DbScoped.SugarScope.GetConnection(0).Aop.OnError = (e) =>
db.GetConnection(0).Aop.OnError = (e) =>
{
logger.Error(e, $"执行SQL出错{e.Message}");
};
//SQL执行完
DbScoped.SugarScope.GetConnection(0).Aop.OnLogExecuted = (sql, pars) =>
db.GetConnection(0).Aop.OnLogExecuted = (sql, pars) =>
{
//执行完了可以输出SQL执行时间 (OnLogExecutedDelegate)
};
#endregion
#region db1
//Db1
DbScoped.SugarScope.GetConnection(1).Aop.OnLogExecuting = (sql, pars) =>
db.GetConnection(1).Aop.OnLogExecuting = (sql, pars) =>
{
var param = DbScoped.SugarScope.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value));
logger.Info($"Sql语句{sql}, {param}");
};
//Db1错误日志
DbScoped.SugarScope.GetConnection(1).Aop.OnError = (e) =>
db.GetConnection(1).Aop.OnError = (e) =>
{
logger.Error($"执行Sql语句失败{e.Sql},原因:{e.Message}");
};
#endregion
});
}
/// <summary>

View File

@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Quartz.Spi;
using System;
using System.Threading.Tasks;
using ZR.Service.System.IService;
using ZR.Tasks;
@ -20,7 +21,7 @@ namespace ZR.Admin.WebApi.Extensions
//添加Quartz服务
services.AddSingleton<IJobFactory, JobFactory>();
//添加我们的服务
services.AddTransient<Job_SyncTest>();
//services.AddTransient<Job_SyncTest>();
services.AddTransient<ITaskSchedulerServer, TaskSchedulerServer>();
}
@ -41,7 +42,11 @@ namespace ZR.Admin.WebApi.Extensions
//程序启动后注册所有定时任务
foreach (var task in tasks)
{
_schedulerServer.AddTaskScheduleAsync(task);
var result = _schedulerServer.AddTaskScheduleAsync(task);
if (result.Result.Code == 200)
{
Console.WriteLine($"注册任务[{task.Name}]ID{task.ID}成功");
}
}
return app;

View File

@ -47,6 +47,9 @@
<target name="console" xsi:type="ColoredConsole"
layout="${date:format=MM-dd HH\:mm\:ss} | ${uppercase:${level}} | ${logger} | ${aspnet-request-iP} | ${aspnet-request-url} | ${message}"/>
<target name="consoleSql" xsi:type="ColoredConsole"
layout="${date:format=MM-dd HH\:mm\:ss} | ${aspnet-request-url} ${newline} ${message}"/>
<!--写入黑洞-->
<target name="blackhole" xsi:type="Null" />
</targets>
@ -59,6 +62,7 @@
<!--<logger name="System.*" writeTo="blackhole" final="true" />-->
<!-- Quartz -->
<logger name="Quartz*" minlevel="Trace" maxlevel="Info" final="true" />
<logger name="ZR.Admin.WebApi.Extensions.DbExtension" final="true" writeTo="consoleSql"/>
<logger name="*" minLevel="Debug" writeTo="console"/>
<logger name="ZR.Admin.WebApi.Extensions.DbExtension" final="true" writeTo="sqlfile"/>

View File

@ -153,5 +153,9 @@ namespace ZR.Model.System
[SugarColumn(IsOnlyIgnoreInsert = true)]//设置后插入数据不会有此字段
[JsonProperty(propertyName: "UpdateTime")]
public DateTime Update_time { get; set; } = DateTime.Now;
/// <summary>
/// 最后运行时间
/// </summary>
public DateTime? LastRunTime { get; set; }
}
}

View File

@ -63,7 +63,7 @@ namespace ZR.Service.System
foreach (var dictId in dictIds)
{
SysDictType dictType = DictRepository.GetFirst(x => x.DictId == dictId);
if (DictRepository.Count(f => f.DictType == dictType.DictType) > 0)
if (DictDataRepository.Count(f => f.DictType == dictType.DictType) > 0)
{
throw new CustomException($"{dictType.DictName}已分配,不能删除");
}

View File

@ -23,6 +23,6 @@ namespace ZR.Tasks
Task<ApiResult> RunTaskScheduleAsync(SysTasksQz tasksQz);
Task<ApiResult> UpdateTaskScheduleAsync(SysTasksQz tasksQz, string groupName);
Task<ApiResult> UpdateTaskScheduleAsync(SysTasksQz tasksQz);
}
}

View File

@ -2,7 +2,6 @@
using NLog;
using Quartz;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using ZR.Model.System;
@ -22,7 +21,7 @@ namespace ZR.Tasks
/// </summary>
/// <param name="context">作业上下文</param>
/// <param name="job">业务逻辑方法</param>
public async Task<Dictionary<string,object>> ExecuteJob(IJobExecutionContext context, Func<Task> job)
public async Task<SysTasksLog> ExecuteJob(IJobExecutionContext context, Func<Task> job)
{
double elapsed = 0;
int status = 0;
@ -37,54 +36,54 @@ namespace ZR.Tasks
await job();
stopwatch.Stop();
elapsed = stopwatch.Elapsed.TotalMilliseconds;
logMsg = "Succeed";
logMsg = "success";
}
catch (Exception ex)
{
JobExecutionException e2 = new JobExecutionException(ex);
JobExecutionException e2 = new(ex)
{
//true 是立即重新执行任务
e2.RefireImmediately = true;
RefireImmediately = true
};
status = 1;
logMsg = $"FailException{ex.Message}";
}
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("elapsed", elapsed);
dic.Add("status", status);
dic.Add("content", logMsg);
RecordTaskLog(context, dic);
return dic;
var logModel = new SysTasksLog()
{
Elapsed = elapsed,
Status = status.ToString(),
JobMessage = logMsg
};
RecordTaskLog(context, logModel);
return logModel;
}
/// <summary>
/// 记录到日志
/// </summary>
/// <param name="context"></param>
/// <param name="executeLog"></param>
protected void RecordTaskLog(IJobExecutionContext context, Dictionary<string, object> executeLog)
/// <param name="logModel"></param>
protected void RecordTaskLog(IJobExecutionContext context, SysTasksLog logModel)
{
var tasksLogService = (ISysTasksLogService)App.GetRequiredService(typeof(ISysTasksLogService));
var taskQzService = (ISysTasksQzService)App.GetRequiredService(typeof(ISysTasksQzService));
// 可以直接获取 JobDetail 的值
IJobDetail job = context.JobDetail;
//var param = context.MergedJobDataMap;
// 也可以通过数据库配置,获取传递过来的参数
//JobDataMap data = context.JobDetail.JobDataMap;
//int jobId = data.GetInt("JobParam");
var logModel = new SysTasksLog();
logModel.InvokeTarget = job.JobType.FullName;
logModel.Elapsed = (double)executeLog.GetValueOrDefault("elapsed", "0");
logModel.JobMessage = executeLog.GetValueOrDefault("content").ToString();
logModel.Status = executeLog.GetValueOrDefault("status", "0").ToString();
logModel = tasksLogService.AddTaskLog(job.Key.Name, logModel);
//成功后执行次数+1
if (logModel.Status == "0")
{
taskQzService.Update(f => f.ID == job.Key.Name, f => new SysTasksQz()
{
RunTimes = f.RunTimes + 1
RunTimes = f.RunTimes + 1,
LastRunTime = DateTime.Now
});
}
logger.Info($"执行任务【{job.Key.Name}|{logModel.JobName}】结果={logModel.JobMessage}");
}
}

View File

@ -1,11 +1,14 @@
using Quartz;
using Infrastructure.Attribute;
using Quartz;
using System.Threading.Tasks;
namespace ZR.Tasks
namespace ZR.Tasks.TaskScheduler
{
/// <summary>
/// 定时任务测试
/// 使用如下注册后TaskExtensions里面不用再注册了
/// </summary>
[AppService(ServiceType = typeof(Job_SyncTest), ServiceLifetime = LifeTime.Scoped)]
public class Job_SyncTest : JobBase, IJob
{
//private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
@ -20,6 +23,7 @@ namespace ZR.Tasks
await Task.Delay(1);
//TODO 业务逻辑
System.Console.WriteLine("job test");
}
}
}

View File

@ -2,10 +2,13 @@
using NLog;
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Matchers;
using Quartz.Impl.Triggers;
using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using ZR.Model.System;
@ -153,11 +156,15 @@ namespace ZR.Tasks
trigger = CreateCronTrigger(tasksQz);
//解决Quartz启动后第一次会立即执行问题解决办法
((CronTriggerImpl)trigger).MisfireInstruction = MisfireInstruction.CronTrigger.DoNothing;
}
else
{
trigger = CreateSimpleTrigger(tasksQz);
((SimpleTriggerImpl)trigger).MisfireInstruction = MisfireInstruction.CronTrigger.DoNothing;
}
// 5、将触发器和任务器绑定到调度器中
await _scheduler.Result.ScheduleJob(job, trigger);
}
//任务没有启动、暂停任务
if (!tasksQz.IsStart)
{
@ -252,8 +259,19 @@ namespace ZR.Tasks
try
{
JobKey jobKey = new JobKey(tasksQz.ID, tasksQz.JobGroup);
List<JobKey> jobKeys = _scheduler.Result.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(tasksQz.JobGroup)).Result.ToList();
if (jobKeys == null || jobKeys.Count == 0)
{
return new ApiResult(110, $"未找到分组[{ tasksQz.JobGroup }]");
}
var triggers = await _scheduler.Result.GetTriggersOfJob(jobKey);
if (triggers.Count <= 0)
{
return new ApiResult(110, $"未找到触发器[{jobKey.Name}]");
}
await _scheduler.Result.TriggerJob(jobKey);
return ApiResult.Success($"运行计划任务:【{tasksQz.Name}】成功");
}
catch (Exception ex)
@ -267,11 +285,11 @@ namespace ZR.Tasks
/// </summary>
/// <param name="tasksQz"></param>
/// <returns></returns>
public async Task<ApiResult> UpdateTaskScheduleAsync(SysTasksQz tasksQz, string groupName)
public async Task<ApiResult> UpdateTaskScheduleAsync(SysTasksQz tasksQz)
{
try
{
JobKey jobKey = new JobKey(tasksQz.ID, groupName);
JobKey jobKey = new JobKey(tasksQz.ID, tasksQz.JobGroup);
if (await _scheduler.Result.CheckExists(jobKey))
{
//防止创建时存在数据问题 先移除,然后在执行创建操作
@ -294,33 +312,30 @@ namespace ZR.Tasks
/// </summary>
/// <param name="tasksQz"></param>
/// <returns></returns>
//private ITrigger CreateSimpleTrigger(SysTasksQz tasksQz)
//{
// if (tasksQz.RunTimes > 0)
// {
// ITrigger trigger = TriggerBuilder.Create()
// .WithIdentity(tasksQz.ID, tasksQz.JobGroup)
// .StartAt(tasksQz.BeginTime.Value)
// .EndAt(tasksQz.EndTime.Value)
// .WithSimpleSchedule(x =>
// x.WithIntervalInSeconds(tasksQz.IntervalSecond)
// .WithRepeatCount(tasksQz.RunTimes)).ForJob(tasksQz.ID, tasksQz.JobGroup).Build();
// return trigger;
// }
// else
// {
// ITrigger trigger = TriggerBuilder.Create()
// .WithIdentity(tasksQz.ID, tasksQz.JobGroup)
// .StartAt(tasksQz.BeginTime.Value)
// .EndAt(tasksQz.EndTime.Value)
// .WithSimpleSchedule(x =>
// x.WithIntervalInSeconds(tasksQz.IntervalSecond)
// .RepeatForever()).ForJob(tasksQz.ID, tasksQz.JobGroup).Build();
// return trigger;
// }
// // 触发作业立即运行然后每10秒重复一次无限循环
//}
private ITrigger CreateSimpleTrigger(SysTasksQz tasksQz)
{
if (tasksQz.RunTimes > 0)
{
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity(tasksQz.ID, tasksQz.JobGroup)
.StartAt(tasksQz.BeginTime.Value)
.EndAt(tasksQz.EndTime.Value)
.WithSimpleSchedule(x => x.WithIntervalInSeconds(tasksQz.IntervalSecond)
.WithRepeatCount(tasksQz.RunTimes)).ForJob(tasksQz.ID, tasksQz.JobGroup).Build();
return trigger;
}
else
{
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity(tasksQz.ID, tasksQz.JobGroup)
.StartAt(tasksQz.BeginTime.Value)
.EndAt(tasksQz.EndTime.Value)
.WithSimpleSchedule(x => x.WithIntervalInSeconds(tasksQz.IntervalSecond)
.RepeatForever()).ForJob(tasksQz.ID, tasksQz.JobGroup).Build();
return trigger;
}
// 触发作业立即运行然后每10秒重复一次无限循环
}
/// <summary>
/// 创建类型Cron的触发器

View File

@ -21,7 +21,15 @@ export default {
}
if (title) {
vnodes.push(<span slot='title'>{(title)}</span>)
if (title.length > 5) {
vnodes.push(
<span slot='title' title={title}>
{title}
</span>
)
} else {
vnodes.push(<span slot='title'>{title}</span>)
}
}
return vnodes
}

View File

@ -2,7 +2,7 @@ module.exports = {
/**
* 框架版本号
*/
version: '3.7.7',
version: '3.7.8',
title: 'ZrAdmin.NET-后台管理',
/**
* 主题颜色

View File

@ -34,23 +34,23 @@
<right-toolbar :showSearch.sync="searchToggle" @queryTable="handleQuery"></right-toolbar>
</el-row>
<el-row>
<el-table ref="tasks" v-loading="loading" :data="dataTasks" border="" row-key="id" :height="tableHeight*0.65" @sort-change="handleSortable"
@selection-change="handleSelectionChange">
<!-- <el-table-column type="selection" width="55" align="center" /> -->
<el-table ref="tasks" v-loading="loading" :data="dataTasks" border="" row-key="id" @sort-change="handleSortable">
<el-table-column type="index" :index="handleIndexCalc" label="#" align="center" />
<el-table-column prop="name" :show-overflow-tooltip="true" label="任务名称" />
<el-table-column prop="jobGroup" :show-overflow-tooltip="true" align="center" label="任务分组" />
<el-table-column prop="name" :show-overflow-tooltip="true" label="任务名称" width="80" />
<el-table-column prop="jobGroup" :show-overflow-tooltip="true" align="center" label="任务分组" width="80" />
<el-table-column prop="assemblyName" align="center" label="程序集名称" :show-overflow-tooltip="true" />
<el-table-column prop="className" align="center" label="任务类名" :show-overflow-tooltip="true" />
<el-table-column prop="runTimes" align="center" label="运行次数"/>
<el-table-column prop="cron" align="center" label="运行表达式" />
<el-table-column prop="runTimes" align="center" label="运行次数" width="80" />
<el-table-column prop="intervalSecond" align="center" label="执行间隔(s)" width="90" />
<el-table-column prop="cron" align="center" label="运行表达式" :show-overflow-tooltip="true" />
<el-table-column sortable prop="isStart" align="center" label="任务状态" width="100">
<template slot-scope="scope">
<el-tag size="mini" :type="scope.row.isStart ? 'success' : 'danger'" disable-transitions>{{ scope.row.isStart ? "运行中":"已停止" }}</el-tag>
<el-tag size="mini" :type="scope.row.isStart ? 'success' : 'danger'">{{ scope.row.isStart ? "运行中":"已停止" }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="lastRunTime" align="center" label="最后运行时间" :show-overflow-tooltip="true" />
<el-table-column prop="remark" align="center" label="备注" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" width="250" class-name="small-padding fixed-width">
<el-table-column label="操作" align="center" width="230" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button type="text" size="mini" icon="el-icon-view" v-hasPermi="['monitor:job:query']">
<router-link :to="{path: 'job/log', query: {jobId: scope.row.id}}">日志</router-link>
@ -72,7 +72,7 @@
<pagination :total="total" :page.sync="queryParams.PageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
</el-row>
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body @close="cancel">
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="24" v-if="this.form.id">
@ -114,19 +114,16 @@
<el-input v-model="form.jobParams" placeholder="传入参数" />
</el-form-item>
</el-col>
<el-col :span="16" v-show="form.triggerType == 1">
<el-col :span="24" v-show="form.triggerType == 1">
<el-form-item label="间隔(Cron)" prop="cron">
<el-input v-model="form.cron" placeholder="如10分钟执行一次0/0 0/10 * * * ?" />
</el-form-item>
</el-col>
<el-col :span="8" v-show="form.triggerType == 1">
<el-form-item label-width="20px">
<el-link href="https://cron.qqe2.com/" type="primary" target="_blank" class="mr10">cyon在线生成</el-link>
<el-input placeholder="如10分钟执行一次0/0 0/10 * * * ?" v-model="form.cron">
<el-link slot="append" href="https://qqe2.com/cron" type="primary" target="_blank" class="mr10">cron在线生成</el-link>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开始日期" prop="beginTime">
<el-date-picker v-model="form.beginTime" style="width:100%" type="date" placeholder="选择开始日期" />
<el-date-picker v-model="form.beginTime" style="width:100%" type="date" :picker-options="pickerOptions" placeholder="选择开始日期" />
</el-form-item>
</el-col>
<el-col :span="12">
@ -147,8 +144,8 @@
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="cancel"> </el-button>
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
@ -163,55 +160,55 @@ import {
startTasks,
stopTasks,
runTasks,
exportTasks,
} from "@/api/monitor/job";
exportTasks
} from '@/api/monitor/job'
export default {
name: "job",
name: 'job',
data() {
var cronValidate = (rule, value, callback) => {
if (this.form.triggerType === 1) {
if (value === "" || value === undefined) {
callback(new Error("运行时间表达式不能为空!"));
if (value === '' || value === undefined) {
callback(new Error('运行时间表达式不能为空!'))
} else {
callback();
callback()
}
} else {
callback();
callback()
}
}
};
var beginTimeValidate = (rule, value, callback) => {
if (this.form.triggerType === 0) {
if (value === "" || value === undefined) {
callback(new Error("选择开始日期!"));
if (value === '' || value === undefined) {
callback(new Error('选择开始日期!'))
} else {
callback();
callback()
}
} else {
callback();
callback()
}
}
};
var endTimeValidate = (rule, value, callback) => {
if (this.form.triggerType === 0) {
if (value === "" || value === undefined) {
callback(new Error("选择结束日期!"));
if (value === '' || value === undefined) {
callback(new Error('选择结束日期!'))
} else {
callback();
callback()
}
} else {
callback();
callback()
}
}
};
var intervalSecondValidate = (rule, value, callback) => {
if (this.form.triggerType === 0) {
if (value === "" || value === undefined) {
callback(new Error("请设置执行间隔!"));
if (value === '' || value === undefined) {
callback(new Error('请设置执行间隔!'))
} else {
callback();
callback()
}
} else {
callback();
callback()
}
}
};
return {
//
ids: [],
@ -224,7 +221,7 @@ export default {
//
form: {},
//
title: "",
title: '',
//
searchToggle: true,
//
@ -238,107 +235,118 @@ export default {
queryText: undefined,
PageNum: 1,
pageSize: 10,
orderby: "createTime",
sort: "descending",
orderby: 'createTime',
sort: 'descending'
},
//
dataTasks: [],
//
isStartOptions: [
{ dictLabel: "运行中", dictValue: "true" },
{ dictLabel: "已停止", dictValue: "false", listClass: "danger" },
{ dictLabel: '运行中', dictValue: 'true' },
{ dictLabel: '已停止', dictValue: 'false', listClass: 'danger' }
],
//
jobGroupOptions: [],
//
triggerTypeOptions: [
{
label: "Simple / [普通]",
value: 0,
label: '[普通]',
value: 0
},
{
label: "Cron / [表达式]",
value: 1,
},
label: '[表达式]',
value: 1
}
],
//
rules: {
name: [
{ required: true, message: "任务名称不能为空", trigger: "blur" },
{ required: true, message: '任务名称不能为空', trigger: 'blur' }
],
jobGroup: [
{ required: true, message: "任务分组不能为空", trigger: "blur" },
{ required: true, message: '任务分组不能为空', trigger: 'blur' }
],
assemblyName: [
{ required: true, message: "程序集名称不能为空", trigger: "blur" },
{ required: true, message: '程序集名称不能为空', trigger: 'blur' }
],
className: [
{ required: true, message: "任务类名不能为空", trigger: "blur" },
{ required: true, message: '任务类名不能为空', trigger: 'blur' }
],
triggerType: [
{ required: true, message: "请选择触发器类型", trigger: "blur" },
{ required: true, message: '请选择触发器类型', trigger: 'blur' }
],
cron: [{ validator: cronValidate, trigger: "blur" }],
beginTime: [{ validator: beginTimeValidate, trigger: "blur" }],
endTime: [{ validator: endTimeValidate, trigger: "blur" }],
cron: [{ validator: cronValidate, trigger: 'blur' }],
beginTime: [{ validator: beginTimeValidate, trigger: 'blur' }],
endTime: [{ validator: endTimeValidate, trigger: 'blur' }],
intervalSecond: [
{
validator: intervalSecondValidate,
type: "number",
trigger: "blur",
type: 'number',
trigger: 'blur'
}
]
},
],
},
};
//
pickerOptions: {
disabledDate(time) {
return time.getTime() < Date.now() - 8.64e7;
}
}
}
},
created() {
this.getList();
this.getDicts("sys_job_group").then((response) => {
this.jobGroupOptions = response.data;
});
this.getList()
this.getDicts('sys_job_group').then((response) => {
this.jobGroupOptions = response.data
})
},
watch: {
'form.triggerType': {
handler(val) {
console.log(val)
if (val == 0) {
this.form.cron = undefined
}
},
deep: true,
immediate: true
}
},
methods: {
/** 查询计划任务列表 */
getList() {
this.loading = true;
this.loading = true
queryTasks(this.queryParams).then((response) => {
this.dataTasks = response.data.result;
this.total = response.data.totalNum;
this.loading = false;
});
this.dataTasks = response.data.result
this.total = response.data.totalNum
this.loading = false
})
},
handleQuery() {
this.getList();
this.getList()
},
/** 重置按钮操作 */
handleReset() {
this.queryParams.queryText = "";
this.getList();
this.queryParams.queryText = ''
this.getList()
},
/** 新增按钮操作 */
handleCreate() {
this.reset();
this.open = true;
this.title = "添加计划任务";
this.reset()
this.open = true
this.title = '添加计划任务'
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.reset()
this.form = row;
this.open = true;
this.title = "修改计划任务";
this.form = row
this.open = true
this.title = '修改计划任务'
},
/** 任务日志列表查询 */
handleJobLog(param) {
this.$router.push({ path: "job/log", params: param });
},
//
handleSelectionChange(selection) {
console.log(selection);
this.ids = selection; // selection.map(item => item.id);
this.single = selection.length != 1;
this.multiple = !selection.length;
this.$router.push({ path: 'job/log', params: param })
},
//
handleStart(row) {
@ -346,12 +354,12 @@ export default {
if (response.code === 200) {
this.$message({
message: response.msg,
type: "success",
});
this.open = false;
this.getList();
type: 'success'
})
this.open = false
this.getList()
}
});
})
},
//
handleStop(row) {
@ -359,93 +367,94 @@ export default {
if (response.code === 200) {
this.$message({
message: response.msg,
type: "success",
});
this.open = false;
this.getList();
type: 'success'
})
this.open = false
this.getList()
}
});
})
},
/** 删除按钮操作 */
handleDelete(row) {
const jobInfo = row;
const jobInfo = row
this.$confirm(
'是否确认删除名称为"' + jobInfo.name + '"的计划任务?',
"警告",
'警告',
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
.then(() => {
deleteTasks(jobInfo.id).then((response) => {
if (response.code === 200) {
this.getList();
this.getList()
this.$message({
message: "删除成功",
type: "success",
});
}
});
message: '删除成功',
type: 'success'
})
.catch(function () {});
}
})
})
.catch(function() {})
},
/* 立即执行一次 */
handleRun(row) {
const jobInfo = row;
const jobInfo = row
this.$confirm('确认要立即执行一次"' + jobInfo.name + '"任务吗?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
this.$confirm('确认要立即执行一次"' + jobInfo.name + '"任务吗?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then((res) => {
runTasks(jobInfo.id).then((res) => {
if (res.code === 200) {
this.$message({
message: "执行成功",
type: "success",
});
message: '执行成功',
type: 'success'
})
this.getList()
}
});
});
})
})
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate((valid) => {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.form.id !== undefined) {
updateTasks(this.form).then((response) => {
if (response.code === 200) {
this.$message({
message: "修改成功",
type: "success",
});
this.open = false;
this.getList();
message: '修改成功',
type: 'success'
})
this.open = false
this.getList()
}
});
})
} else {
createTasks(this.form).then((response) => {
if (response.code === 200) {
this.$message({
message: "新增成功",
type: "success",
});
this.open = false;
this.getList();
message: '新增成功',
type: 'success'
})
this.open = false
this.getList()
}
});
})
}
}
});
})
},
//
handleSortable(val) {
this.queryParams.orderby = val.prop;
this.queryParams.sort = val.order;
this.getList();
this.queryParams.orderby = val.prop
this.queryParams.sort = val.order
this.getList()
},
//
reset() {
@ -453,41 +462,42 @@ export default {
id: undefined,
name: undefined,
jobGroup: undefined,
assemblyName: undefined,
assemblyName: 'ZR.Tasks',
className: undefined,
jobParams: undefined,
triggerType: 1,
beginTime: undefined,
endTime: undefined,
intervalSecond: 1,
};
cron: undefined
}
this.resetForm('form')
},
// Id
handleIndexCalc(index) {
return (
(this.queryParams.PageNum - 1) * this.queryParams.pageSize + index + 1
);
)
},
//
cancel() {
this.open = false;
this.reset();
this.getList();
this.open = false
this.reset()
},
/** 导出按钮操作 */
handleExport() {
this.$confirm("是否确认导出所有任务?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
this.$confirm('是否确认导出所有任务?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
return exportTasks();
return exportTasks()
})
.then((response) => {
this.download(response.data.path);
});
},
},
};
this.download(response.data.path)
})
}
}
}
</script>

View File

@ -46,7 +46,7 @@
<el-table-column label="执行状态" align="center" prop="status" :formatter="statusFormat" />
<el-table-column label="作业用时" align="center" prop="elapsed">
<template slot-scope="scope">
<span :style="scope.row.elapsed < 1000 ? 'color:green':scope.row.elapsed <3000 ?'color:orange':'color:red'">{{ scope.row.elapsed }} ms</span>
<span :style="scope.row.elapsed < 1000 ? 'color:green':scope.row.elapsed <3000 ?'color:orange':'color:red'">{{ scope.row.elapsed /1000 }} ms</span>
</template>
</el-table-column>
<el-table-column label="执行时间" align="center" prop="createTime" width="180">
@ -87,13 +87,13 @@
<div v-else-if="form.status == 1">失败</div>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="异常信息:" v-if="form.status == 1">{{ form.exceptionInfo }}</el-form-item>
<el-col :span="24" v-if="form.status == 1">>
<el-form-item label="异常信息:">{{ form.exception }}</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="open = false"> </el-button>
<el-button type="text" @click="open = false"> </el-button>
</div>
</el-dialog>
</div>

View File

@ -5,33 +5,34 @@ SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for Sys_TasksQz
-- ----------------------------
DROP TABLE IF EXISTS `Sys_TasksQz`;
DROP TABLE IF EXISTS `sys_tasksQz`;
CREATE TABLE `Sys_TasksQz` (
`ID` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'UID',
`Name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务名称',
`JobGroup` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务分组',
`Cron` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '运行时间表达式',
`AssemblyName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '程序集名称',
`ClassName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务所在类',
`Remark` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '任务描述',
`RunTimes` int(11) NOT NULL COMMENT '执行次数',
`BeginTime` datetime(0) NULL DEFAULT NULL COMMENT '开始时间',
`EndTime` datetime(0) NULL DEFAULT NULL COMMENT '结束时间',
`TriggerType` int(11) NOT NULL COMMENT '触发器类型0、simple 1、cron',
`IntervalSecond` int(11) NOT NULL COMMENT '执行间隔时间(单位:秒)',
`IsStart` tinyint(4) NOT NULL COMMENT '是否启动',
`JobParams` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '传入参数',
`id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'UID',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务名称',
`jobGroup` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务分组',
`cron` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '运行时间表达式',
`assemblyName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '程序集名称',
`className` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务所在类',
`remark` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '任务描述',
`runTimes` int(11) NOT NULL COMMENT '执行次数',
`beginTime` datetime(0) NULL DEFAULT NULL COMMENT '开始时间',
`endTime` datetime(0) NULL DEFAULT NULL COMMENT '结束时间',
`triggerType` int(11) NOT NULL COMMENT '触发器类型0、simple 1、cron',
`intervalSecond` int(11) NOT NULL COMMENT '执行间隔时间(单位:秒)',
`isStart` tinyint(4) NOT NULL COMMENT '是否启动',
`jobParams` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '传入参数',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '最后更新时间',
`create_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人编码',
`update_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人编码',
`lastRunTime` datetime(0) NULL DEFAULT NULL COMMENT '最后执行时间',
PRIMARY KEY (`ID`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '计划任务' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of Sys_TasksQz
-- ----------------------------
INSERT INTO `Sys_TasksQz` VALUES ('1410905433996136448', '测试任务', 'SYSTEM', '0 0/10 * * * ? ', 'ZR.Tasks', 'Job_SyncTest', NULL, 0, '2021-07-02 18:17:31', '9999-12-31 00:00:00', 1, 1, 1, NULL, '2021-07-02 18:17:23', '2021-07-02 18:17:31', 'admin', NULL);
INSERT INTO `sys_tasksQz` VALUES ('1410905433996136448', '测试任务', 'SYSTEM', '0 0/10 * * * ? ', 'ZR.Tasks', 'TaskScheduler.Job_SyncTest', NULL, 0, '2021-07-02 18:17:31', '9999-12-31 00:00:00', 1, 1, 1, NULL, '2021-07-02 18:17:23', '2021-07-02 18:17:31', 'admin', NULL, NULL);
-- ----------------------------
-- Table structure for sys_Tasks_log
@ -51,13 +52,6 @@ CREATE TABLE `sys_Tasks_log` (
PRIMARY KEY (`jobLogId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 198 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '定时任务调度日志表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_Tasks_log
-- ----------------------------
INSERT INTO `sys_Tasks_log` VALUES (196, '1410905433996136448', '测试任务', 'SYSTEM', 'Succeed', '0', NULL, SYSDATE(), 'ZRTasks.Job_SyncTest', 18);
INSERT INTO `sys_Tasks_log` VALUES (197, '1410905433996136448', '测试任务', 'SYSTEM', 'Succeed', '0', NULL, SYSDATE(), 'ZRTasks.Job_SyncTest', 14);
-- ----------------------------
-- 通知公告表
-- ----------------------------

View File

@ -2,36 +2,37 @@
GO
USE ZrAdmin
GO
if OBJECT_ID(N'Sys_tasksQz',N'U') is not NULL DROP TABLE Sys_tasksQz
if OBJECT_ID(N'sys_tasksQz',N'U') is not NULL DROP TABLE sys_tasksQz
GO
CREATE TABLE Sys_tasksQz
CREATE TABLE sys_tasksQz
(
ID VARCHAR(100) NOT NULL PRIMARY KEY, --ID
Name VARCHAR(50) NOT NULL, --
JobGroup varchar(255) NOT NULL, --'任务分组',
Cron varchar(255) NOT NULL , --'运行时间表达式',
AssemblyName varchar(255) NOT NULL , --'程序集名称',
ClassName varchar(255) NOT NULL , --'任务所在类',
Remark VARCHAR(200) NULL , --'任务描述',
RunTimes int NOT NULL , --'执行次数',
BeginTime datetime NULL DEFAULT NULL , --'开始时间',
EndTime datetime NULL DEFAULT NULL , --'结束时间',
TriggerType int NOT NULL , --'触发器类型0、simple 1、cron',
IntervalSecond int NOT NULL , --'执行间隔时间(单位:秒)',
IsStart int NOT NULL , --'是否启动',
JobParams TEXT NULL , --'传入参数',
id VARCHAR(100) NOT NULL PRIMARY KEY, --ID
name VARCHAR(50) NOT NULL, --
jobGroup varchar(255) NOT NULL, --'任务分组',
cron varchar(255) NOT NULL , --'运行时间表达式',
assemblyName varchar(255) NOT NULL , --'程序集名称',
className varchar(255) NOT NULL , --'任务所在类',
remark VARCHAR(200) NULL , --'任务描述',
runTimes int NOT NULL , --'执行次数',
beginTime datetime NULL DEFAULT NULL , --'开始时间',
endTime datetime NULL DEFAULT NULL , --'结束时间',
triggerType int NOT NULL , --'触发器类型0、simple 1、cron',
intervalSecond int NOT NULL , --'执行间隔时间(单位:秒)',
isStart int NOT NULL , --'是否启动',
jobParams TEXT NULL , --'传入参数',
create_time datetime NULL DEFAULT NULL , --'创建时间',
update_time datetime NULL DEFAULT NULL , --'最后更新时间',
create_by varchar(50) NULL DEFAULT NULL , --'创建人编码',
update_by varchar(50) NULL DEFAULT NULL , --'更新人编码',
lastRunTime datetime , --
)
GO
INSERT INTO Sys_TasksQz VALUES ('1410905433996136448', '测试任务', 'SYSTEM', '0 0/10 * * * ? ', 'ZR.Tasks', 'Job_SyncTest', NULL, 0, '2021-07-02 18:17:31', '9999-12-31 00:00:00', 1, 1, 1, NULL, '2021-07-02 18:17:23', '2021-07-02 18:17:31', 'admin', NULL);
INSERT INTO sys_tasksQz VALUES ('1410905433996136448', '测试任务', 'SYSTEM', '0 0/10 * * * ? ', 'ZR.Tasks', 'TaskScheduler.Job_SyncTest', NULL, 0, '2021-07-02 18:17:31', '9999-12-31 00:00:00', 1, 1, 1, NULL, '2021-07-02 18:17:23', '2021-07-02 18:17:31', 'admin', NULL, NULL);
GO
if OBJECT_ID(N'sys_Tasks_log',N'U') is not NULL DROP TABLE sys_Tasks_log
GO
/**定时任务调度日志表*/
CREATE TABLE sys_Tasks_log (
CREATE TABLE sys_tasks_log (
jobLogId bigint NOT NULL PRIMARY KEY IDENTITY(1,1), -- '任务日志ID',
jobId varchar(20) NOT NULL , -- '任务id',
jobName varchar(64) NOT NULL , -- '任务名称',