mirror of
https://github.com/nsnail/NetAdmin.git
synced 2025-04-23 14:42:51 +08:00
feat: ✨ 手动执行计划作业 (#122)
This commit is contained in:
parent
7214a22ea5
commit
3b8336105a
@ -23,6 +23,7 @@ XML注释文件不存在
|
|||||||
学历不正确
|
学历不正确
|
||||||
密码不能为空
|
密码不能为空
|
||||||
已处理完毕
|
已处理完毕
|
||||||
|
并发冲突请稍后重试
|
||||||
开始事务
|
开始事务
|
||||||
性别不正确
|
性别不正确
|
||||||
手机号码不正确
|
手机号码不正确
|
||||||
|
@ -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_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_ID = nameof(FLG_CONTEXT_USER_ID);
|
||||||
public const string FLG_CONTEXT_USER_INFO = nameof(FLG_CONTEXT_USER_INFO);
|
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_EXCEPTION_PRIVATE_KEY_CONFLICT = "PRIMARY KEY";
|
||||||
public const string FLG_DB_FIELD_TYPE_NVARCHAR = "nvarchar";
|
public const string FLG_DB_FIELD_TYPE_NVARCHAR = "nvarchar";
|
||||||
public const string FLG_DB_FIELD_TYPE_NVARCHAR_1022 = "nvarchar(1022)";
|
public const string FLG_DB_FIELD_TYPE_NVARCHAR_1022 = "nvarchar(1022)";
|
||||||
|
@ -20,6 +20,11 @@ public interface IJobModule : ICrudModule<CreateJobReq, QueryJobRsp // 创建类
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Task<QueryJobRsp> EditAsync(UpdateJobReq req);
|
Task<QueryJobRsp> EditAsync(UpdateJobReq req);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行作业
|
||||||
|
/// </summary>
|
||||||
|
Task ExecuteAsync(QueryJobReq req);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取作业记录条形图数据
|
/// 获取作业记录条形图数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Cronos;
|
using Cronos;
|
||||||
|
using FreeSql.Internal;
|
||||||
using NetAdmin.Application.Repositories;
|
using NetAdmin.Application.Repositories;
|
||||||
using NetAdmin.Application.Services;
|
using NetAdmin.Application.Services;
|
||||||
using NetAdmin.Domain.DbMaps.Sys;
|
using NetAdmin.Domain.DbMaps.Sys;
|
||||||
@ -84,6 +85,41 @@ public sealed class JobService(DefaultRepository<Sys_Job> rpo, IJobRecordService
|
|||||||
return (await update.ExecuteUpdatedAsync().ConfigureAwait(false))[0].Adapt<QueryJobRsp>();
|
return (await update.ExecuteUpdatedAsync().ConfigureAwait(false))[0].Adapt<QueryJobRsp>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
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<QueryJobReq> { 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<UpdateJobReq>() with {
|
||||||
|
NextExecTime = nextExecTime
|
||||||
|
, NextTimeId = nextExecTime?.TimeUnixUtc()
|
||||||
|
})
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (DbUpdateVersionException) {
|
||||||
|
throw new NetAdminInvalidOperationException(Ln.并发冲突请稍后重试);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<bool> ExistAsync(QueryReq<QueryJobReq> req)
|
public Task<bool> ExistAsync(QueryReq<QueryJobReq> req)
|
||||||
{
|
{
|
||||||
|
@ -42,6 +42,12 @@ public sealed class JobCache(IDistributedCache cache, IJobService service)
|
|||||||
return Service.EditAsync(req);
|
return Service.EditAsync(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task ExecuteAsync(QueryJobReq req)
|
||||||
|
{
|
||||||
|
return Service.ExecuteAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<bool> ExistAsync(QueryReq<QueryJobReq> req)
|
public Task<bool> ExistAsync(QueryReq<QueryJobReq> req)
|
||||||
{
|
{
|
||||||
|
@ -60,6 +60,14 @@ public sealed class JobController(IJobCache cache) : ControllerBase<IJobCache, I
|
|||||||
return Cache.EditAsync(req);
|
return Cache.EditAsync(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行作业
|
||||||
|
/// </summary>
|
||||||
|
public Task ExecuteAsync(QueryJobReq req)
|
||||||
|
{
|
||||||
|
return Cache.ExecuteAsync(req);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 计划作业是否存在
|
/// 计划作业是否存在
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -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)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计划作业是否存在
|
* 计划作业是否存在
|
||||||
*/
|
*/
|
||||||
|
@ -137,13 +137,19 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<na-col-operation
|
<na-col-operation
|
||||||
:buttons="
|
:buttons="
|
||||||
naColOperation.buttons.concat({
|
naColOperation.buttons.concat(
|
||||||
|
{
|
||||||
|
icon: 'el-icon-video-play',
|
||||||
|
click: execute,
|
||||||
|
},
|
||||||
|
{
|
||||||
icon: 'el-icon-delete',
|
icon: 'el-icon-delete',
|
||||||
confirm: true,
|
confirm: true,
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
title: $t('删除作业'),
|
title: $t('删除作业'),
|
||||||
click: rowDel,
|
click: rowDel,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
"
|
"
|
||||||
:vue="this" />
|
:vue="this" />
|
||||||
</sc-table>
|
</sc-table>
|
||||||
@ -171,6 +177,7 @@ export default {
|
|||||||
inject: ['reload'],
|
inject: ['reload'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
timer: null,
|
||||||
loading: false,
|
loading: false,
|
||||||
query: {
|
query: {
|
||||||
dynamicFilter: {
|
dynamicFilter: {
|
||||||
@ -220,6 +227,31 @@ export default {
|
|||||||
}
|
}
|
||||||
this.$refs.table.refresh()
|
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: `<div id="countdown">已发起执行请求,5 秒后弹出执行结果</div>`,
|
||||||
|
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) {
|
async rowDel(row) {
|
||||||
try {
|
try {
|
||||||
|
@ -189,7 +189,7 @@ export default {
|
|||||||
mounted() {},
|
mounted() {},
|
||||||
methods: {
|
methods: {
|
||||||
//显示
|
//显示
|
||||||
async open(mode = 'add', data) {
|
async open(mode = 'add', data, tabIndex = 0) {
|
||||||
this.visible = true
|
this.visible = true
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.mode = mode
|
this.mode = mode
|
||||||
@ -198,6 +198,7 @@ export default {
|
|||||||
Object.assign(this.form, res.data)
|
Object.assign(this.form, res.data)
|
||||||
}
|
}
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
this.tabIndex = tabIndex
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user