diff --git a/assets/res/Statements.ln b/assets/res/Statements.ln index 1d159ae8..5487add1 100644 --- a/assets/res/Statements.ln +++ b/assets/res/Statements.ln @@ -23,6 +23,7 @@ XML注释文件不存在 学历不正确 密码不能为空 已处理完毕 +并发冲突请稍后重试 开始事务 性别不正确 手机号码不正确 diff --git a/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs b/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs index d2446a83..46e0ce5b 100644 --- a/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs +++ b/src/backend/NetAdmin.Infrastructure/Constant/Chars.cs @@ -14,6 +14,7 @@ public static class Chars public const string FLG_CONTEXT_OWNER_DEPT_ID = nameof(FLG_CONTEXT_OWNER_DEPT_ID); public const string FLG_CONTEXT_USER_ID = nameof(FLG_CONTEXT_USER_ID); public const string FLG_CONTEXT_USER_INFO = nameof(FLG_CONTEXT_USER_INFO); + public const string FLG_CRON_PER_SECS = "* * * * * *"; public const string FLG_DB_EXCEPTION_PRIVATE_KEY_CONFLICT = "PRIMARY KEY"; public const string FLG_DB_FIELD_TYPE_NVARCHAR = "nvarchar"; public const string FLG_DB_FIELD_TYPE_NVARCHAR_1022 = "nvarchar(1022)"; diff --git a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IJobModule.cs b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IJobModule.cs index 04efbb7e..dfddacbd 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IJobModule.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Modules/Sys/IJobModule.cs @@ -20,6 +20,11 @@ public interface IJobModule : ICrudModule Task EditAsync(UpdateJobReq req); + /// + /// 执行作业 + /// + Task ExecuteAsync(QueryJobReq req); + /// /// 获取作业记录条形图数据 /// diff --git a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs index 9277052b..2855ed23 100644 --- a/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs +++ b/src/backend/NetAdmin.SysComponent.Application/Services/Sys/JobService.cs @@ -1,4 +1,5 @@ using Cronos; +using FreeSql.Internal; using NetAdmin.Application.Repositories; using NetAdmin.Application.Services; using NetAdmin.Domain.DbMaps.Sys; @@ -84,6 +85,41 @@ public sealed class JobService(DefaultRepository rpo, IJobRecordService return (await update.ExecuteUpdatedAsync().ConfigureAwait(false))[0].Adapt(); } + /// + public async Task ExecuteAsync(QueryJobReq req) + { + req.ThrowIfInvalid(); + var df = new DynamicFilterInfo { + Filters = [ + new DynamicFilterInfo { + Field = nameof(QueryJobReq.Enabled) + , Operator = DynamicFilterOperators.Eq + , Value = true + } + , new DynamicFilterInfo { + Field = nameof(QueryJobReq.Status) + , Operator = DynamicFilterOperators.Eq + , Value = JobStatues.Idle + } + ] + }; + var job = await QueryInternal(new QueryReq { Count = 1, Filter = req, DynamicFilter = df }) + .ToOneAsync() + .ConfigureAwait(false) ?? throw new NetAdminInvalidOperationException(Ln.未获取到待执行任务); + + var nextExecTime = GetNextExecTime(Chars.FLG_CRON_PER_SECS); + try { + _ = await UpdateAsync(job.Adapt() with { + NextExecTime = nextExecTime + , NextTimeId = nextExecTime?.TimeUnixUtc() + }) + .ConfigureAwait(false); + } + catch (DbUpdateVersionException) { + throw new NetAdminInvalidOperationException(Ln.并发冲突请稍后重试); + } + } + /// public Task ExistAsync(QueryReq req) { diff --git a/src/backend/NetAdmin.SysComponent.Cache/Sys/JobCache.cs b/src/backend/NetAdmin.SysComponent.Cache/Sys/JobCache.cs index b1ac6a01..68db7111 100644 --- a/src/backend/NetAdmin.SysComponent.Cache/Sys/JobCache.cs +++ b/src/backend/NetAdmin.SysComponent.Cache/Sys/JobCache.cs @@ -42,6 +42,12 @@ public sealed class JobCache(IDistributedCache cache, IJobService service) return Service.EditAsync(req); } + /// + public Task ExecuteAsync(QueryJobReq req) + { + return Service.ExecuteAsync(req); + } + /// public Task ExistAsync(QueryReq req) { diff --git a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/JobController.cs b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/JobController.cs index fca95089..d6e44192 100644 --- a/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/JobController.cs +++ b/src/backend/NetAdmin.SysComponent.Host/Controllers/Sys/JobController.cs @@ -60,6 +60,14 @@ public sealed class JobController(IJobCache cache) : ControllerBase + /// 执行作业 + /// + public Task ExecuteAsync(QueryJobReq req) + { + return Cache.ExecuteAsync(req); + } + /// /// 计划作业是否存在 /// diff --git a/src/frontend/admin/src/api/sys/job.js b/src/frontend/admin/src/api/sys/job.js index a654552b..e08cb631 100644 --- a/src/frontend/admin/src/api/sys/job.js +++ b/src/frontend/admin/src/api/sys/job.js @@ -60,6 +60,17 @@ export default { }, }, + /** + * 执行作业 + */ + execute: { + url: `${config.API_URL}/api/sys/job/execute`, + name: `执行作业`, + post: async function (data = {}, config = {}) { + return await http.post(this.url, data, config) + }, + }, + /** * 计划作业是否存在 */ diff --git a/src/frontend/admin/src/views/sys/job/index.vue b/src/frontend/admin/src/views/sys/job/index.vue index 90313389..06f4160e 100644 --- a/src/frontend/admin/src/views/sys/job/index.vue +++ b/src/frontend/admin/src/views/sys/job/index.vue @@ -137,13 +137,19 @@ @@ -171,6 +177,7 @@ export default { inject: ['reload'], data() { return { + timer: null, loading: false, query: { dynamicFilter: { @@ -220,6 +227,31 @@ export default { } this.$refs.table.refresh() }, + async execute(row) { + try { + await this.$API.sys_job.execute.post({ id: row.id }) + this.$refs.table.refresh() + this.$notify.success({ + dangerouslyUseHTMLString: true, + message: `
已发起执行请求,5 秒后弹出执行结果
`, + onClose: async () => { + clearInterval(this.timer) + this.loading = true + this.dialog.save = true + await this.$nextTick() + await this.$refs.saveDialog.open('view', row, 1) + this.loading = false + }, + }) + + this.timer = setInterval(() => { + const countdown = new RegExp('\\d+').exec(document.getElementById('countdown').innerText)[0] + document.getElementById('countdown').innerText = document + .getElementById('countdown') + .innerText.replace(countdown, `${parseInt(countdown) - 1}`) + }, 1000) + } catch {} + }, //删除 async rowDel(row) { try { diff --git a/src/frontend/admin/src/views/sys/job/save.vue b/src/frontend/admin/src/views/sys/job/save.vue index 2acdc698..43249db1 100644 --- a/src/frontend/admin/src/views/sys/job/save.vue +++ b/src/frontend/admin/src/views/sys/job/save.vue @@ -189,7 +189,7 @@ export default { mounted() {}, methods: { //显示 - async open(mode = 'add', data) { + async open(mode = 'add', data, tabIndex = 0) { this.visible = true this.loading = true this.mode = mode @@ -198,6 +198,7 @@ export default { Object.assign(this.form, res.data) } this.loading = false + this.tabIndex = tabIndex return this },