mirror of
https://github.com/nsnail/NetAdmin.git
synced 2025-04-23 22:52:51 +08:00
feat: ✨ cron表达式的自然语言表达 (#156)
Co-authored-by: tk <fiyne1a@dingtalk.com>
This commit is contained in:
parent
1733802e02
commit
6d4ccf3445
@ -1,6 +1,8 @@
|
|||||||
|
using CronExpressionDescriptor;
|
||||||
using NetAdmin.Domain.Dto.Sys.User;
|
using NetAdmin.Domain.Dto.Sys.User;
|
||||||
using NetAdmin.Domain.Enums.Sys;
|
using NetAdmin.Domain.Enums.Sys;
|
||||||
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
|
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
|
||||||
|
using Options = CronExpressionDescriptor.Options;
|
||||||
|
|
||||||
namespace NetAdmin.Domain.Dto.Sys.Job;
|
namespace NetAdmin.Domain.Dto.Sys.Job;
|
||||||
|
|
||||||
@ -9,6 +11,13 @@ namespace NetAdmin.Domain.Dto.Sys.Job;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public record QueryJobRsp : Sys_Job
|
public record QueryJobRsp : Sys_Job
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Cron 表达式描述
|
||||||
|
/// </summary>
|
||||||
|
[JsonInclude]
|
||||||
|
public string CronDescription =>
|
||||||
|
ExpressionDescriptor.GetDescription(ExecutionCron, new Options { Locale = "zh-CN" });
|
||||||
|
|
||||||
/// <inheritdoc cref="Sys_Job.LastStatusCode" />
|
/// <inheritdoc cref="Sys_Job.LastStatusCode" />
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
public new virtual string LastStatusCode =>
|
public new virtual string LastStatusCode =>
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
<ProjectReference Include="../NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj"/>
|
<ProjectReference Include="../NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CronExpressionDescriptor" Version="2.33.0"/>
|
||||||
|
<PackageReference Include="Cronos" Version="0.8.4"/>
|
||||||
<PackageReference Include="CsvHelper.NS" Version="33.0.2-ns2"/>
|
<PackageReference Include="CsvHelper.NS" Version="33.0.2-ns2"/>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.6"/>
|
||||||
|
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -6,18 +6,15 @@
|
|||||||
<Import Project="$(SolutionDir)/build/copy.pkg.xml.comment.files.targets"/>
|
<Import Project="$(SolutionDir)/build/copy.pkg.xml.comment.files.targets"/>
|
||||||
<Import Project="$(SolutionDir)/build/prebuild.targets"/>
|
<Import Project="$(SolutionDir)/build/prebuild.targets"/>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Cronos" Version="0.8.4"/>
|
|
||||||
<PackageReference Include="FreeSql.DbContext.NS" Version="3.2.821-ns1"/>
|
<PackageReference Include="FreeSql.DbContext.NS" Version="3.2.821-ns1"/>
|
||||||
<PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.821-ns1"/>
|
<PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.821-ns1"/>
|
||||||
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.4"/>
|
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.4"/>
|
||||||
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.4-ns1"/>
|
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.4-ns1"/>
|
||||||
<PackageReference Include="Furion.Pure.NS" Version="4.9.4-ns1"/>
|
<PackageReference Include="Furion.Pure.NS" Version="4.9.4-ns1"/>
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0-preview.5.24306.11"/>
|
|
||||||
<PackageReference Include="Minio" Version="6.0.3"/>
|
<PackageReference Include="Minio" Version="6.0.3"/>
|
||||||
<PackageReference Include="NSExt" Version="2.2.0"/>
|
<PackageReference Include="NSExt" Version="2.2.0"/>
|
||||||
<PackageReference Include="RedLock.net" Version="2.3.2"/>
|
<PackageReference Include="RedLock.net" Version="2.3.2"/>
|
||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0"/>
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0"/>
|
||||||
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14"/>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="*.json">
|
<None Update="*.json">
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
<ProjectReference Include="../NetAdmin.Host/NetAdmin.Host.csproj"/>
|
<ProjectReference Include="../NetAdmin.Host/NetAdmin.Host.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="xunit" Version="2.8.1"/>
|
<PackageReference Include="xunit" Version="2.9.0"/>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0-preview.5.24306.11"/>
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0-preview.5.24306.11"/>
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<template v-for="(item, i) in Array.isArray(row[prop]) ? row[prop] : [row[prop]]" :key="i">
|
<template v-for="(item, i) in Array.isArray(row[prop]) ? row[prop] : [row[prop]]" :key="i">
|
||||||
<el-tag v-if="item" @click="$emit('click', item)">
|
<el-tag
|
||||||
|
v-if="item"
|
||||||
|
:type="['success', 'danger', 'info', 'primary', 'warning'][$TOOL.crypto.hashCode(item[field]) % 5]"
|
||||||
|
@click="$emit('click', item)">
|
||||||
{{ item ? item[field] : '' }}
|
{{ item ? item[field] : '' }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
|
@ -34,7 +34,7 @@ const Time = {
|
|||||||
return date.getFullYear() + '-' + month + '-' + day
|
return date.getFullYear() + '-' + month + '-' + day
|
||||||
},
|
},
|
||||||
//转换时间
|
//转换时间
|
||||||
getFormateTime: function (timestamp) {
|
getFormatTime: function (timestamp) {
|
||||||
timestamp = new Date(timestamp)
|
timestamp = new Date(timestamp)
|
||||||
const now = this.getUnix()
|
const now = this.getUnix()
|
||||||
const today = this.getTodayUnix()
|
const today = this.getTodayUnix()
|
||||||
@ -48,10 +48,10 @@ const Time = {
|
|||||||
tip = '刚刚'
|
tip = '刚刚'
|
||||||
} else if (timer < 3600) {
|
} else if (timer < 3600) {
|
||||||
tip = Math.floor(timer / 60) + '分钟前'
|
tip = Math.floor(timer / 60) + '分钟前'
|
||||||
} else if (timer >= 3600 && timestamp - today >= 0) {
|
} else if (timer >= 3600 && (timestamp - today >= 0 || Math.floor(timer / 86400) <= 0)) {
|
||||||
tip = Math.floor(timer / 3600) + '小时前'
|
tip = Math.floor(timer / 3600) + '小时前'
|
||||||
} else if (timer / 86400 <= 31) {
|
} else if (timer / 86400 <= 31) {
|
||||||
tip = Math.ceil(timer / 86400) + '天前'
|
tip = Math.floor(timer / 86400) + '天前'
|
||||||
} else {
|
} else {
|
||||||
tip = this.getLastDate(timestamp)
|
tip = this.getLastDate(timestamp)
|
||||||
}
|
}
|
||||||
@ -68,9 +68,9 @@ export default (el, binding) => {
|
|||||||
value = value * 1000
|
value = value * 1000
|
||||||
}
|
}
|
||||||
if (modifiers.tip) {
|
if (modifiers.tip) {
|
||||||
el.innerHTML = Time.getFormateTime(value)
|
el.innerHTML = Time.getFormatTime(value)
|
||||||
el.__timeout__ = setInterval(() => {
|
el.__timeout__ = setInterval(() => {
|
||||||
el.innerHTML = Time.getFormateTime(value)
|
el.innerHTML = Time.getFormatTime(value)
|
||||||
}, 60000)
|
}, 60000)
|
||||||
} else {
|
} else {
|
||||||
const format = el.getAttribute('format') || undefined
|
const format = el.getAttribute('format') || undefined
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<div class="jobMain">
|
<div class="jobMain">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<h2>{{ job.jobName }}</h2>
|
<h2>{{ job.jobName }}</h2>
|
||||||
<p>{{ $t('上次执行:') }}<span v-time.tip="job.lastExecTime"></span></p>
|
<p>{{ $t('上次执行:') }}<span v-time.tip="job.lastExecTime" :title="job.lastExecTime"></span></p>
|
||||||
<p>
|
<p>
|
||||||
下次执行:<span>{{ job.nextExecTime }}</span>
|
下次执行:<span>{{ job.nextExecTime }}</span>
|
||||||
</p>
|
</p>
|
||||||
|
@ -151,6 +151,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
const roleDefaultGrid = this.$GLOBAL.user.roles.filter((x) => x.displayDashboard).sort((x, y) => y.id - x.id)[0].dashboardLayout
|
||||||
|
if (roleDefaultGrid) {
|
||||||
|
this.defaultGrid = JSON.parse(roleDefaultGrid)
|
||||||
|
}
|
||||||
this.loadGrid()
|
this.loadGrid()
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p>{{ msg.sender.userName }}</p>
|
<p>{{ msg.sender.userName }}</p>
|
||||||
<p v-time.tip="msg.createdTime"></p>
|
<p v-time.tip="msg.createdTime" :title="msg.createdTime"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
label: 'name',
|
label: 'name',
|
||||||
}"
|
}"
|
||||||
@node-click="click"
|
@node-click="click"
|
||||||
default-expand-all
|
|
||||||
node-key="id"
|
node-key="id"
|
||||||
ref="dic">
|
ref="dic">
|
||||||
<template #default="{ _, data }">
|
<template #default="{ _, data }">
|
||||||
|
@ -113,7 +113,12 @@
|
|||||||
<el-table-column type="selection" />
|
<el-table-column type="selection" />
|
||||||
<na-col-id :label="$t('作业编号')" prop="id" sortable="custom" width="170" />
|
<na-col-id :label="$t('作业编号')" prop="id" sortable="custom" width="170" />
|
||||||
<el-table-column :label="$t('作业名称')" prop="jobName" show-overflow-tooltip sortable="custom" />
|
<el-table-column :label="$t('作业名称')" prop="jobName" show-overflow-tooltip sortable="custom" />
|
||||||
<el-table-column :label="$t('执行计划')" align="right" prop="executionCron" sortable="custom" width="150" />
|
<el-table-column :label="$t('执行计划')" align="right" prop="executionCron" sortable="custom" width="150">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<p>{{ row.cronDescription }}</p>
|
||||||
|
<p>{{ row.executionCron }}</p>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<na-col-indicator
|
<na-col-indicator
|
||||||
:label="$t('作业状态')"
|
:label="$t('作业状态')"
|
||||||
:options="
|
:options="
|
||||||
@ -151,7 +156,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('时间')" align="right" prop="lastExecTime" sortable="custom" width="100">
|
<el-table-column :label="$t('时间')" align="right" prop="lastExecTime" sortable="custom" width="100">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span v-if="row.lastExecTime" v-time.tip="row.lastExecTime"></span>
|
<span v-if="row.lastExecTime" v-time.tip="row.lastExecTime" :title="row.lastExecTime"></span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
|
Loading…
x
Reference in New Issue
Block a user