diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskCreateInput.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskCreateInput.cs index 36023b4f..2b142b6b 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskCreateInput.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskCreateInput.cs @@ -14,13 +14,13 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Task public JobTypeEnum Type { get; set; } - public string Cron { get; set; } + public string? Cron { get; set; } - public int Millisecond { get; set; } + public int? Millisecond { get; set; } public bool Concurrent { get; set; } - //public Dictionary? Properties { get; set; } + // public Dictionary? Properties { get; set; } public string? Description { get; set; } } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetListInput.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetListInput.cs index 799db9d7..06bf1cac 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetListInput.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetListInput.cs @@ -4,7 +4,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Task { public class TaskGetListInput : PagedAllResultRequestDto { - public string JobId { get; set; } - public string GroupName { get; set; } + public string? JobId { get; set; } + public string? GroupName { get; set; } } } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetListOutput.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetListOutput.cs index 518e6df2..b6cafa9c 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetListOutput.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetListOutput.cs @@ -57,7 +57,7 @@ /// 作业更新时间 /// - public DateTime? UpdatedTime { get; internal set; } + public DateTime? LastRunTime { get; internal set; } /// /// 标记其他作业正在执行 diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetOutput.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetOutput.cs index 1a00c57f..ce885a72 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetOutput.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskGetOutput.cs @@ -1,4 +1,6 @@ -namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Task +using Yi.Framework.Rbac.Domain.Shared.Enums; + +namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Task { public class TaskGetOutput { @@ -68,5 +70,15 @@ public DateTime? LastRunTime { get; set; } public long NumberOfRuns { get; set; } + + /// + /// 状态 + /// + public string Status { get; set; } + + /// + /// 触发器类型 + /// + public JobTypeEnum Type { get; set; } } } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskUpdateInput.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskUpdateInput.cs index 9ebfe125..207d8d86 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskUpdateInput.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Task/TaskUpdateInput.cs @@ -7,18 +7,18 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Task public string AssemblyName { get; set; } public string JobType { get; set; } - + public string JobId { get; set; } public string? GroupName { get; set; } public JobTypeEnum Type { get; set; } public string? Cron { get; set; } - public int Millisecond { get; set; } + public int? Millisecond { get; set; } public bool Concurrent { get; set; } - // public Dictionary? Properties { get; set; } + // public Dictionary? Properties { get; set; } public string? Description { get; set; } } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/TaskService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/TaskService.cs index d299ec88..d119f0e0 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/TaskService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/TaskService.cs @@ -3,8 +3,10 @@ using Mapster; using Microsoft.AspNetCore.Mvc; using Quartz; using Quartz.Impl.Matchers; +using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; +using Volo.Abp.Timing; using Yi.Framework.Rbac.Application.Contracts.Dtos.Task; using Yi.Framework.Rbac.Application.Contracts.IServices; using Yi.Framework.Rbac.Domain.Shared.Enums; @@ -14,8 +16,10 @@ namespace Yi.Framework.Rbac.Application.Services public class TaskService : ApplicationService, ITaskService { private readonly ISchedulerFactory _schedulerFactory; - public TaskService(ISchedulerFactory schedulerFactory) + private readonly IClock _clock; + public TaskService(ISchedulerFactory schedulerFactory, IClock clock) { + _clock=clock; _schedulerFactory = schedulerFactory; } @@ -25,8 +29,8 @@ namespace Yi.Framework.Rbac.Application.Services /// /// /// - [HttpGet("{jobId}")] - public async Task GetByIdAsync([FromRoute] string jobId) + [HttpGet("task/{jobId}")] + public async Task GetAsync([FromRoute] string jobId) { var scheduler = await _schedulerFactory.GetScheduler(); @@ -34,6 +38,8 @@ namespace Yi.Framework.Rbac.Application.Services var trigger = (await scheduler.GetTriggersOfJob(new JobKey(jobId))).First(); //状态 var state = await scheduler.GetTriggerState(trigger.Key); + + var output = new TaskGetOutput { JobId = jobDetail.Key.Name, @@ -42,17 +48,21 @@ namespace Yi.Framework.Rbac.Application.Services Properties = Newtonsoft.Json.JsonConvert.SerializeObject(jobDetail.JobDataMap), Concurrent = !jobDetail.ConcurrentExecutionDisallowed, Description = jobDetail.Description, - LastRunTime = trigger.GetPreviousFireTimeUtc()?.DateTime, + LastRunTime = _clock.Normalize( trigger.GetPreviousFireTimeUtc()?.DateTime??DateTime.MinValue), + NextRunTime = _clock.Normalize(trigger.GetNextFireTimeUtc()?.DateTime ?? DateTime.MinValue), + AssemblyName = jobDetail.JobType.Assembly.GetName().Name, + Status = state.ToString() }; if (trigger is ISimpleTrigger simple) { - output.TriggerArgs = simple.RepeatInterval.TotalMilliseconds.ToString() + "毫秒"; - + output.TriggerArgs =Math.Round(simple.RepeatInterval.TotalMinutes,2) .ToString() + "分钟"; + output.Type = JobTypeEnum.Millisecond; } else if (trigger is ICronTrigger cron) { output.TriggerArgs = cron.CronExpressionString!; + output.Type = JobTypeEnum.Cron; } return output; } @@ -61,8 +71,7 @@ namespace Yi.Framework.Rbac.Application.Services /// 多查job /// /// - [HttpGet("")] - public async Task> GetList([FromQuery] TaskGetListInput input) + public async Task> GetListAsync([FromQuery] TaskGetListInput input) { var items = new List(); @@ -77,7 +86,7 @@ namespace Yi.Framework.Rbac.Application.Services string jobName = jobKey.Name; string jobGroup = jobKey.Group; var triggers = (await scheduler.GetTriggersOfJob(jobKey)).First(); - items.Add(await GetByIdAsync(jobName)); + items.Add(await GetAsync(jobName)); } } @@ -93,7 +102,7 @@ namespace Yi.Framework.Rbac.Application.Services /// /// /// - public async Task Create(TaskCreateInput input) + public async Task CreateAsync(TaskCreateInput input) { var scheduler = await _schedulerFactory.GetScheduler(); @@ -101,7 +110,12 @@ namespace Yi.Framework.Rbac.Application.Services //jobBuilder - var jobClassType = Assembly.LoadFrom(input.AssemblyName).GetType(input.JobType); + var jobClassType = Assembly.Load(input.AssemblyName).GetTypes().Where(x => x.Name == input.JobType).FirstOrDefault(); + + if (jobClassType is null) + { + throw new UserFriendlyException($"程序集:{input.AssemblyName},{input.JobType} 不存在"); + } var jobBuilder = JobBuilder.Create(jobClassType).WithIdentity(new JobKey(input.JobId, input.GroupName)) .WithDescription(input.Description); @@ -115,8 +129,8 @@ namespace Yi.Framework.Rbac.Application.Services switch (input.Type) { case JobTypeEnum.Cron: - triggerBuilder = - TriggerBuilder.Create().StartNow() + triggerBuilder = + TriggerBuilder.Create() .WithCronSchedule(input.Cron); @@ -127,7 +141,7 @@ namespace Yi.Framework.Rbac.Application.Services triggerBuilder = TriggerBuilder.Create().StartNow() .WithSimpleSchedule(x => x - .WithInterval(TimeSpan.FromMilliseconds(input.Millisecond)) + .WithInterval(TimeSpan.FromMilliseconds(input.Millisecond ?? 10000)) .RepeatForever() ); break; @@ -140,12 +154,12 @@ namespace Yi.Framework.Rbac.Application.Services /// /// 移除job /// - /// + /// /// - public async Task Remove(string jobId) - { + public async Task DeleteAsync(IEnumerable id) + { var scheduler = await _schedulerFactory.GetScheduler(); - await scheduler.ResumeJob(new JobKey(jobId)); + await scheduler.DeleteJobs(id.Select(x => new JobKey(x)).ToList()); } /// @@ -154,7 +168,7 @@ namespace Yi.Framework.Rbac.Application.Services /// /// [HttpPut] - public async Task Pause(string jobId) + public async Task PauseAsync(string jobId) { var scheduler = await _schedulerFactory.GetScheduler(); await scheduler.PauseJob(new JobKey(jobId)); @@ -166,7 +180,7 @@ namespace Yi.Framework.Rbac.Application.Services /// /// [HttpPut] - public async Task Start(string jobId) + public async Task StartAsync(string jobId) { var scheduler = await _schedulerFactory.GetScheduler(); await scheduler.ResumeJob(new JobKey(jobId)); @@ -175,28 +189,30 @@ namespace Yi.Framework.Rbac.Application.Services /// /// 更新job /// - /// + /// /// /// - public async Task Update(string jobId, TaskUpdateInput input) + public async Task UpdateAsync(string id, TaskUpdateInput input) { - await Remove(jobId); - await Create(input.Adapt()); + await DeleteAsync(new List() { id }); + await CreateAsync(input.Adapt()); } - [HttpPost] - public async Task RunOnce(string jobId) + [HttpPost("task/run-once/{id}")] + public async Task RunOnceAsync([FromRoute] string id) { var scheduler = await _schedulerFactory.GetScheduler(); - var jobDetail = await scheduler.GetJobDetail(new JobKey(jobId)); + var jobDetail = await scheduler.GetJobDetail(new JobKey(id)); + var jobBuilder = JobBuilder.Create(jobDetail.JobType).WithIdentity(new JobKey(Guid.NewGuid().ToString())); //设置启动时执行一次,然后最大只执行一次 var trigger = TriggerBuilder.Create().WithIdentity(Guid.NewGuid().ToString()).StartNow() .WithSimpleSchedule(x => x + .WithIntervalInHours(1) .WithRepeatCount(1)) .Build(); - await scheduler.ScheduleJob(jobDetail, trigger); + await scheduler.ScheduleJob(jobBuilder.Build(), trigger); } } } diff --git a/Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/DemoResetJob.cs b/Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/DemoResetJob.cs new file mode 100644 index 00000000..9f4a40a7 --- /dev/null +++ b/Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/DemoResetJob.cs @@ -0,0 +1,56 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Quartz; +using Quartz.Logging; +using Volo.Abp.BackgroundWorkers.Quartz; +using Volo.Abp.Data; +using Yi.Framework.Rbac.Domain.Entities; +using Yi.Framework.SqlSugarCore.Abstractions; + +namespace Yi.Abp.Application.Jobs +{ + public class DemoResetJob : QuartzBackgroundWorkerBase + { + private ISqlSugarDbContext _dbContext; + private ILogger _logger => LoggerFactory.CreateLogger(); + private IDataSeeder _dataSeeder; + private IConfiguration _configuration; + public DemoResetJob(ISqlSugarDbContext dbContext, IDataSeeder dataSeeder, IConfiguration configuration) + { + _dbContext = dbContext; + JobDetail = JobBuilder.Create().WithIdentity(nameof(DemoResetJob)).Build(); + + //每天01点与13点,演示环境进行重置 + Trigger = TriggerBuilder.Create().WithIdentity(nameof(DemoResetJob)).WithCronSchedule("0 0 1,13 * * ? ").Build(); + // Trigger = TriggerBuilder.Create().WithIdentity(nameof(DemoResetJob)).WithSimpleSchedule(x=>x.WithIntervalInSeconds(10)).Build(); + _dataSeeder = dataSeeder; + _configuration = configuration; + } + public override async Task Execute(IJobExecutionContext context) + { + //开启演示环境重置功能 + if (_configuration["EnableDemoReset"] == "true") + { + //定时任务,非常简单 + _logger.LogWarning("演示环境正在还原!"); + var db = _dbContext.SqlSugarClient.CopyNew(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + + //删除种子数据 + await _dataSeeder.SeedAsync(); + _logger.LogWarning("演示环境还原成功!"); + + } + + + } + } +} diff --git a/Yi.Abp.Net8/src/Yi.Abp.Application/Yi.Abp.Application.csproj b/Yi.Abp.Net8/src/Yi.Abp.Application/Yi.Abp.Application.csproj index 94b4a956..e4cdbd88 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Application/Yi.Abp.Application.csproj +++ b/Yi.Abp.Net8/src/Yi.Abp.Application/Yi.Abp.Application.csproj @@ -14,7 +14,6 @@ - diff --git a/Yi.RuoYi.Vue3/src/api/monitor/job.js b/Yi.RuoYi.Vue3/src/api/monitor/job.js index 575b4de3..4ad0bb62 100644 --- a/Yi.RuoYi.Vue3/src/api/monitor/job.js +++ b/Yi.RuoYi.Vue3/src/api/monitor/job.js @@ -36,10 +36,11 @@ export function updateJob(jobId,data) { } // 删除定时任务调度 -export function delJob(jobId) { +export function delJob(ids) { return request({ - url: '/task/' + jobId, - method: 'delete' + url: '/task', + method: 'delete', + params:{id:ids} }) } diff --git a/Yi.RuoYi.Vue3/src/views/monitor/job/index.vue b/Yi.RuoYi.Vue3/src/views/monitor/job/index.vue index d7e503dd..a4b8bf19 100644 --- a/Yi.RuoYi.Vue3/src/views/monitor/job/index.vue +++ b/Yi.RuoYi.Vue3/src/views/monitor/job/index.vue @@ -103,7 +103,7 @@ - + @@ -151,14 +151,14 @@ v-hasPermi="['monitor:job:query']" > - + @@ -248,7 +248,7 @@ - +