cron
parent
5fb7de0b81
commit
a297536102
|
|
@ -77,7 +77,7 @@ function scheduleTypeChange(val: string) {
|
||||||
} else if (val === 'Fixed') {
|
} else if (val === 'Fixed') {
|
||||||
taskFormData.value.scheduleConf = '1'
|
taskFormData.value.scheduleConf = '1'
|
||||||
} else if (val === 'Cron') {
|
} else if (val === 'Cron') {
|
||||||
taskFormData.value.scheduleConf = '* * * * * ? ?'
|
taskFormData.value.scheduleConf = '* * * * * ?'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,13 +120,8 @@ defineExpose({
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
status.value = 'add'
|
status.value = 'add'
|
||||||
data.scheduleConf = '* * * * * ? ?'
|
data.scheduleConf = '* * * * * ?'
|
||||||
taskFormData.value = data
|
taskFormData.value = data
|
||||||
// taskFormData = {}
|
|
||||||
// for (const key in taskFormData) {
|
|
||||||
// taskFormData[key] = undefined
|
|
||||||
// // delete taskFormData[key]
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
if (newVal !== undefined && newVal !== cronVal.value) {
|
if (newVal !== undefined && newVal !== cronVal.value) {
|
||||||
console.log('设置', newVal)
|
|
||||||
cronVal.value = newVal
|
cronVal.value = newVal
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -26,11 +25,11 @@ watch(
|
||||||
cronVal,
|
cronVal,
|
||||||
(newCronVal) => {
|
(newCronVal) => {
|
||||||
if (newCronVal !== props.modelValue) {
|
if (newCronVal !== props.modelValue) {
|
||||||
console.log('更新')
|
|
||||||
emits('update:modelValue', newCronVal)
|
emits('update:modelValue', newCronVal)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
function openPanel() {
|
function openPanel() {
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
}
|
}
|
||||||
|
|
@ -43,6 +42,7 @@ function openPanel() {
|
||||||
</template>
|
</template>
|
||||||
</ElInput>
|
</ElInput>
|
||||||
<ElDialog v-model="showDialog"
|
<ElDialog v-model="showDialog"
|
||||||
|
title="配置面板"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
destroy-on-close width="50vw">
|
destroy-on-close width="50vw">
|
||||||
<CronPanel/>
|
<CronPanel/>
|
||||||
|
|
|
||||||
|
|
@ -1,241 +0,0 @@
|
||||||
/**
|
|
||||||
* 提供类 Unix 风格 Cron 表达式的解析器和求值器。Cron 表达式能够指定复杂的时间组合,
|
|
||||||
* 例如“每周一至周五的上午 8:00”或“每月最后一个周五的凌晨 1:30”。
|
|
||||||
*
|
|
||||||
* <P>
|
|
||||||
* Cron 表达式由 6 个必填字段和 1 个可选字段组成,字段之间通过空格分隔。各字段的详细说明如下:
|
|
||||||
*
|
|
||||||
* <table cellspacing="8">
|
|
||||||
* <tr>
|
|
||||||
* <th align="left">字段名称</th>
|
|
||||||
* <th align="left"> </th>
|
|
||||||
* <th align="left">允许值</th>
|
|
||||||
* <th align="left"> </th>
|
|
||||||
* <th align="left">允许的特殊字符</th>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td align="left"><code>秒(Seconds)</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>0-59</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>, - * /</code></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td align="left"><code>分(Minutes)</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>0-59</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>, - * /</code></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td align="left"><code>时(Hours)</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>0-23</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>, - * /</code></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td align="left"><code>日(Day-of-month)</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>1-31</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>, - * ? / L W</code></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td align="left"><code>月(Month)</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>0-11 或 JAN-DEC(一月至十二月)</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>, - * /</code></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td align="left"><code>周(Day-of-Week)</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>1-7 或 SUN-SAT(周日至周六)</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>, - * ? / L #</code></td>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td align="left"><code>年(Year,可选)</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>空值、1970-2199</code></td>
|
|
||||||
* <td align="left"> </th>
|
|
||||||
* <td align="left"><code>, - * /</code></td>
|
|
||||||
* </tr>
|
|
||||||
* </table>
|
|
||||||
* <P>
|
|
||||||
* '*' 字符用于指定“所有可能的值”。例如,在“分钟”字段中使用 "*" 表示“每分钟”。
|
|
||||||
* <P>
|
|
||||||
* '?' 字符仅允许在“日(Day-of-month)”和“周(Day-of-Week)”字段中使用,
|
|
||||||
* 用于表示“不指定具体值”。当你需要在这两个字段中的一个指定条件,而另一个无需指定时,该字符非常有用。
|
|
||||||
* <P>
|
|
||||||
* '-' 字符用于指定时间范围。例如,在“小时”字段中使用 "10-12" 表示“上午 10 点、11 点和中午 12 点”。
|
|
||||||
* <P>
|
|
||||||
* ',' 字符用于指定多个额外的取值。例如,在“周”字段中使用 "MON,WED,FRI" 表示“周一、周三和周五”。
|
|
||||||
* <P>
|
|
||||||
* '/' 字符用于指定递增步长。例如,在“秒”字段中使用 "0/15" 表示“第 0 秒、15 秒、30 秒和 45 秒”;
|
|
||||||
* 而 "5/15" 在“秒”字段中表示“第 5 秒、20 秒、35 秒和 50 秒”。在 '/' 前指定 '*' 等价于以 0 作为起始值。
|
|
||||||
* 本质上,表达式的每个字段都对应一组可启用或禁用的数字集合:秒和分的范围是 0-59,小时是 0-23,
|
|
||||||
* 日是 1-31,月是 0-11(对应 JAN 至 DEC)。'/' 字符的作用是在指定集合中启用“每隔 n 个”的取值。
|
|
||||||
* 需要注意一个细节:在“月”字段中使用 "7/6" 仅会启用“7 月”,并不表示“每 6 个月”。
|
|
||||||
* <P>
|
|
||||||
* 'L' 字符仅允许在“日(Day-of-month)”和“周(Day-of-Week)”字段中使用,是“last(最后一个)”的缩写,
|
|
||||||
* 但在两个字段中的含义有所不同。例如,在“日”字段中使用 "L" 表示“当月的最后一天”——1 月对应 31 日,
|
|
||||||
* 非闰年的 2 月对应 28 日。若在“周”字段中单独使用 "L",仅表示“7”或“SAT(周六)”;
|
|
||||||
* 若在其他值后使用,则表示“当月最后一个指定星期几”,例如 "6L" 表示“当月最后一个周五”。
|
|
||||||
* 你也可以指定相对于月末的偏移量,例如 "L-3" 表示“当月的倒数第三天”。
|
|
||||||
* <i>注意:使用 'L' 选项时,请勿同时指定多个取值(列表)或范围,否则会得到混乱或不符合预期的结果。</i>
|
|
||||||
* <P>
|
|
||||||
* 'W' 字符仅允许在“日(Day-of-month)”字段中使用,用于指定“距离给定日期最近的工作日(周一至周五)”。
|
|
||||||
* 例如,若在“日”字段中指定 "15W",含义是“当月 15 日附近最近的工作日”:如果 15 日是周六,
|
|
||||||
* 则触发时间为 14 日(周五);如果 15 日是周日,则触发时间为 16 日(周一);如果 15 日是周二,
|
|
||||||
* 则触发时间为 15 日(周二)本身。若指定 "1W" 且 1 日是周六,触发时间会是 3 日(周一),
|
|
||||||
* 因为该字符不会“跨越”月份的边界。'W' 字符仅能在“日”字段指定单个日期时使用,
|
|
||||||
* 不能用于日期范围或多个日期列表。
|
|
||||||
* <P>
|
|
||||||
* 'L' 和 'W' 字符可在“日(Day-of-month)”字段中组合使用,形成 "LW",含义是“当月的最后一个工作日”。
|
|
||||||
* <P>
|
|
||||||
* '#' 字符仅允许在“周(Day-of-Week)”字段中使用,用于指定“当月第 n 个星期几”。
|
|
||||||
* 例如,在“周”字段中使用 "6#3" 表示“当月第三个周五”(6 对应周五,"#3" 对应第三个)。
|
|
||||||
* 其他示例:"2#1" 表示“当月第一个周一”,"4#5" 表示“当月第五个周三”。
|
|
||||||
* 注意:若指定了 "#5" 但当月不存在对应的第 5 个星期几,则该月不会触发任务。
|
|
||||||
* 此外,使用 '#' 字符时,“周”字段中只能包含一个表达式(例如 "3#1,6#3" 是无效的,因为它包含两个表达式)。
|
|
||||||
* <P>
|
|
||||||
* <!--'C' 字符仅允许在“日(Day-of-month)”和“周(Day-of-Week)”字段中使用,是“calendar(日历)”的缩写。
|
|
||||||
* 这意味着取值会根据关联的日历(若有)进行计算;若未关联日历,则等价于使用全包含日历。
|
|
||||||
* 在“日”字段中使用 "5C" 表示“日历中包含的、5 日或 5 日之后的第一天”;
|
|
||||||
* 在“周”字段中使用 "1C" 表示“日历中包含的、周日或周日之后的第一天”。-->
|
|
||||||
* <P>
|
|
||||||
* 所有合法字符以及月份、星期几的名称均不区分大小写。
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* <b>注意事项:</b>
|
|
||||||
* <ul>
|
|
||||||
* <li> 同时指定“日(Day-of-month)”和“周(Day-of-Week)”字段的功能尚未完善,
|
|
||||||
* 你需要在其中一个字段中使用 '?' 字符。</li>
|
|
||||||
* <li> 支持“溢出范围”(即范围左侧的数字大于右侧):例如,你可以使用 22-2 表示“晚上 10 点至次日凌晨 2 点”,
|
|
||||||
* 或使用 NOV-FEB 表示“11 月至次年 2 月”。但需要特别注意,过度使用溢出范围会产生无意义的时间范围,
|
|
||||||
* 且 CronExpression 不会对这些无效范围进行特殊判断和处理(例如表达式 "0 0 14-6 ? * FRI-MON" 就是一个无意义的溢出范围示例)。</li>
|
|
||||||
* </ul>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author 沙拉达·詹布拉、詹姆斯·豪斯
|
|
||||||
* @author 贡献者:麦兹·亨德森
|
|
||||||
* @author 重构者:艾伦·克雷文(将功能从 CronTrigger 重构为 CronExpression)
|
|
||||||
* <p>
|
|
||||||
* 源自 Quartz 框架 v2.3.1 版本
|
|
||||||
*/
|
|
||||||
|
|
||||||
export class CronExpression {
|
|
||||||
// 公共常量:最大年份(当前年份+100,与 Java 保持一致)
|
|
||||||
public static readonly MAX_YEAR: number = new Date().getFullYear() + 100
|
|
||||||
|
|
||||||
// 私有静态常量:字段索引(秒、分、时、日、月、周、年)
|
|
||||||
private static readonly SECOND: number = 0
|
|
||||||
private static readonly MINUTE: number = 1
|
|
||||||
private static readonly HOUR: number = 2
|
|
||||||
private static readonly DAY_OF_MONTH: number = 3
|
|
||||||
private static readonly MONTH: number = 4
|
|
||||||
private static readonly DAY_OF_WEEK: number = 5
|
|
||||||
private static readonly YEAR: number = 6
|
|
||||||
|
|
||||||
// 私有静态常量:特殊标记值(* 对应 99,? 对应 98)
|
|
||||||
private static readonly ALL_SPEC_INT: number = 99 // 对应 '*'
|
|
||||||
private static readonly NO_SPEC_INT: number = 98 // 对应 '?'
|
|
||||||
private static readonly ALL_SPEC: number = CronExpression.ALL_SPEC_INT
|
|
||||||
private static readonly NO_SPEC: number = CronExpression.NO_SPEC_INT
|
|
||||||
|
|
||||||
// 私有静态映射:月份英文缩写 -> 数字(0-11,与 Java 一致)
|
|
||||||
private static readonly monthMap: Record<string, number> = {JAN: 0, FEB: 1, MAR: 2, APR: 3, MAY: 4, JUN: 5, JUL: 6, AUG: 7, SEP: 8, OCT: 9, NOV: 10, DEC: 11}
|
|
||||||
// 私有静态映射:星期英文缩写 -> 数字(1-7,与 Java 一致)
|
|
||||||
private static readonly dayMap: Record<string, number> = {SUN: 1, MON: 2, TUE: 3, WED: 4, THU: 5, FRI: 6, SAT: 7}
|
|
||||||
|
|
||||||
// 实例属性
|
|
||||||
private readonly cronExpression: string
|
|
||||||
private seconds?: number[] // TS 中无原生TreeSet,后续可实现或用SortedSet替代
|
|
||||||
private minutes?: number[]
|
|
||||||
private hours?: number[]
|
|
||||||
private daysOfMonth?: number[]
|
|
||||||
private months?: number[]
|
|
||||||
private daysOfWeek?: number[]
|
|
||||||
private years?: number[]
|
|
||||||
|
|
||||||
private lastdayOfWeek: boolean = false
|
|
||||||
private nthdayOfWeek: number = 0
|
|
||||||
private lastdayOfMonth: boolean = false
|
|
||||||
private nearestWeekday: boolean = false
|
|
||||||
private lastdayOffset: number = 0
|
|
||||||
private expressionParsed: boolean = false
|
|
||||||
private timeZone?: TimeZone // 对应 Java TimeZone,TS 中可用 string 或原生 TimeZone 替代
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据指定的参数构造一个新的 <code>CronExpression</code> 实例。
|
|
||||||
*
|
|
||||||
* @param cronExpression 字符串形式的 Cron 表达式,该表达式将由新建的对象进行承载
|
|
||||||
* @throws Error 如果传入的字符串表达式无法被解析为一个有效的 <code>CronExpression</code> 实例,则抛出该异常
|
|
||||||
*/
|
|
||||||
constructor(cronExpression: string) {
|
|
||||||
if (cronExpression == null) {
|
|
||||||
throw new Error('表达式不能为空')
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cronExpression = cronExpression.toUpperCase(Locale.US)
|
|
||||||
|
|
||||||
buildExpression(this.cronExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 复制现有实例,创建新的 Cron 表达式
|
|
||||||
*/
|
|
||||||
constructor(expression: CronExpression) {
|
|
||||||
this.cronExpression = expression.getCronExpression()
|
|
||||||
buildExpression(cronExpression)
|
|
||||||
if (expression.getTimeZone() != null) {
|
|
||||||
setTimeZone(<TimeZone>expression.getTimeZone().clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查指定的 Cron 表达式是否能够被解析为一个有效的 Cron 表达式
|
|
||||||
* @param cronExpression 待校验的 Cron 表达式字符串
|
|
||||||
* @returns 布尔值:如果传入的表达式是有效的 Cron 表达式,返回 true;否则返回 false
|
|
||||||
*/
|
|
||||||
public static isValidExpression(cronExpression: string): boolean {
|
|
||||||
try {
|
|
||||||
new CronExpression(cronExpression)
|
|
||||||
} catch (e: Error) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断指定的日期是否满足当前 Cron 表达式的规则。
|
|
||||||
* 注意:该方法会忽略日期的毫秒部分,因此在同一秒钟内不同毫秒数的两个日期,在此方法中会返回相同的结果。
|
|
||||||
* @param date 待校验的日期对象
|
|
||||||
* @returns 布尔值:如果指定日期满足 Cron 表达式规则,返回 true;否则返回 false
|
|
||||||
*/
|
|
||||||
public isSatisfiedBy(date: Date): boolean {
|
|
||||||
const testDateCal = new Date(date.getTime())
|
|
||||||
testDateCal.setMilliseconds(0)
|
|
||||||
|
|
||||||
const originalDate = new Date(testDateCal.getTime())
|
|
||||||
|
|
||||||
testDateCal.setSeconds(date.getSeconds() - 1)
|
|
||||||
|
|
||||||
const timeAfter = this.getTimeAfter(testDateCal)
|
|
||||||
|
|
||||||
return timeAfter !== null && timeAfter.getTime() === originalDate.getTime()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 时间区类型(简化版,对应 Java TimeZone)
|
|
||||||
* 可根据实际需求扩展,此处保持与原代码结构一致
|
|
||||||
*/
|
|
||||||
type TimeZone = {
|
|
||||||
id: string;
|
|
||||||
offset: number;
|
|
||||||
} | null;
|
|
||||||
|
|
@ -7,6 +7,11 @@ import MonthPanel from '@/pages/sys/task/cron/cron-panel/MonthPanel.vue'
|
||||||
import WeekPanel from '@/pages/sys/task/cron/cron-panel/WeekPanel.vue'
|
import WeekPanel from '@/pages/sys/task/cron/cron-panel/WeekPanel.vue'
|
||||||
import YearPanel from '@/pages/sys/task/cron/cron-panel/YearPanel.vue'
|
import YearPanel from '@/pages/sys/task/cron/cron-panel/YearPanel.vue'
|
||||||
import { useCronStore } from '@/pages/sys/task/cron/cron-store.ts'
|
import { useCronStore } from '@/pages/sys/task/cron/cron-store.ts'
|
||||||
|
import Strings from '@/common/utils/strings.ts'
|
||||||
|
import TaskApi from '@/pages/sys/task/task-api.ts'
|
||||||
|
import type { R } from '@/common/utils/http-util.ts'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import type { TabsPaneContext } from 'element-plus'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
secondVal,
|
secondVal,
|
||||||
|
|
@ -16,12 +21,30 @@ const {
|
||||||
monthVal,
|
monthVal,
|
||||||
weekVal,
|
weekVal,
|
||||||
yearVal,
|
yearVal,
|
||||||
|
cronVal,
|
||||||
} = toRefs(useCronStore())
|
} = toRefs(useCronStore())
|
||||||
|
|
||||||
|
const nexts = ref<string[]>([])
|
||||||
|
|
||||||
|
function checkExpression(pane: TabsPaneContext) {
|
||||||
|
if (pane.paneName !== 'next-list') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
TaskApi.checkExpression(cronVal.value)
|
||||||
|
.then(res => {
|
||||||
|
ElMessage.success('获取成功')
|
||||||
|
nexts.value = res.data
|
||||||
|
})
|
||||||
|
.catch((res: R<string[]>) => {
|
||||||
|
ElMessage.success(res.msg ?? (res.message ?? '获取失败'))
|
||||||
|
console.log(res)
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="cron-panel">
|
<div class="cron-panel">
|
||||||
<ElTabs type="border-card">
|
<ElTabs type="border-card" @tab-click="checkExpression">
|
||||||
<ElTabPane :label="`秒(${secondVal})`">
|
<ElTabPane :label="`秒(${secondVal})`">
|
||||||
<SecondPanel/>
|
<SecondPanel/>
|
||||||
</ElTabPane>
|
</ElTabPane>
|
||||||
|
|
@ -40,9 +63,14 @@ const {
|
||||||
<ElTabPane :label="`周(${weekVal})`">
|
<ElTabPane :label="`周(${weekVal})`">
|
||||||
<WeekPanel/>
|
<WeekPanel/>
|
||||||
</ElTabPane>
|
</ElTabPane>
|
||||||
<ElTabPane :label="`年(${yearVal})`">
|
<ElTabPane :label="`年${Strings.isBlank(yearVal)?'':'('+yearVal+')'}`">
|
||||||
<YearPanel/>
|
<YearPanel/>
|
||||||
</ElTabPane>
|
</ElTabPane>
|
||||||
|
<ElTabPane label="最近几次执行时间" name="next-list">
|
||||||
|
<div class="next-list">
|
||||||
|
<div v-for="next in nexts" :key="next">{{ next }}</div>
|
||||||
|
</div>
|
||||||
|
</ElTabPane>
|
||||||
</ElTabs>
|
</ElTabs>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -59,4 +87,8 @@ const {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.next-list {
|
||||||
|
position relative
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -11,21 +11,21 @@ const {dayState} = toRefs(useCronStore())
|
||||||
<ElRadio value="last">每月最后一天</ElRadio>
|
<ElRadio value="last">每月最后一天</ElRadio>
|
||||||
<ElRadio value="near">
|
<ElRadio value="near">
|
||||||
<span>每月</span>
|
<span>每月</span>
|
||||||
<ElInputNumber v-model="dayState.near" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="dayState.near" :controls="false" :max="31" :min="1" size="small"/>
|
||||||
<span>号最近的那个工作日</span>
|
<span>号最近的那个工作日</span>
|
||||||
</ElRadio>
|
</ElRadio>
|
||||||
<ElRadio value="period1">
|
<ElRadio value="period1">
|
||||||
<span>周期,从</span>
|
<span>周期,从</span>
|
||||||
<ElInputNumber v-model="dayState.period1.start" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="dayState.period1.start" :controls="false" :max="30" :min="1" size="small"/>
|
||||||
<span>号到</span>
|
<span>号到</span>
|
||||||
<ElInputNumber v-model="dayState.period1.end" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="dayState.period1.end" :controls="false" :max="31" :min="dayState.period1.start" size="small"/>
|
||||||
<span>号</span>
|
<span>号</span>
|
||||||
</ElRadio>
|
</ElRadio>
|
||||||
<ElRadio value="period2">
|
<ElRadio value="period2">
|
||||||
<span>周期,从第</span>
|
<span>周期,从第</span>
|
||||||
<ElInputNumber v-model="dayState.period2.start" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="dayState.period2.start" :controls="false" :max="31" :min="1" size="small"/>
|
||||||
<span>天开始,每</span>
|
<span>天开始,每</span>
|
||||||
<ElInputNumber v-model="dayState.period2.end" :controls="false" :max="60" :min="1" size="small"/>
|
<ElInputNumber v-model="dayState.period2.end" :controls="false" :max="31" :min="1" size="small"/>
|
||||||
<span>天执行一次</span>
|
<span>天执行一次</span>
|
||||||
</ElRadio>
|
</ElRadio>
|
||||||
<ElRadio value="specify">
|
<ElRadio value="specify">
|
||||||
|
|
@ -46,16 +46,8 @@ const {dayState} = toRefs(useCronStore())
|
||||||
flex-wrap nowrap
|
flex-wrap nowrap
|
||||||
|
|
||||||
:deep(.el-input-number) {
|
:deep(.el-input-number) {
|
||||||
margin 0 5px
|
margin 0 10px
|
||||||
width: 60px
|
width: 80px
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-radio):nth-child(4) {
|
|
||||||
position relative
|
|
||||||
}
|
|
||||||
|
|
||||||
.second-item {
|
|
||||||
position relative
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-checkbox-group) {
|
:deep(.el-checkbox-group) {
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,16 @@ const {hourState} = toRefs(useCronStore())
|
||||||
<ElRadio value="every">每小时</ElRadio>
|
<ElRadio value="every">每小时</ElRadio>
|
||||||
<ElRadio value="period1">
|
<ElRadio value="period1">
|
||||||
<span>周期,从</span>
|
<span>周期,从</span>
|
||||||
<ElInputNumber v-model="hourState.period1.start" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="hourState.period1.start" :controls="false" :max="23" :min="0" size="small"/>
|
||||||
<span>时到</span>
|
<span>时到</span>
|
||||||
<ElInputNumber v-model="hourState.period1.end" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="hourState.period1.end" :controls="false" :max="23" :min="hourState.period1.start" size="small"/>
|
||||||
<span>时</span>
|
<span>时</span>
|
||||||
</ElRadio>
|
</ElRadio>
|
||||||
<ElRadio value="period2">
|
<ElRadio value="period2">
|
||||||
<span>周期,从第</span>
|
<span>周期,从第</span>
|
||||||
<ElInputNumber v-model="hourState.period2.start" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="hourState.period2.start" :controls="false" :max="23" :min="0" size="small"/>
|
||||||
<span>时开始,每</span>
|
<span>时开始,每</span>
|
||||||
<ElInputNumber v-model="hourState.period2.end" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="hourState.period2.end" :controls="false" :max="23" :min="0" size="small"/>
|
||||||
<span>小时执行一次</span>
|
<span>小时执行一次</span>
|
||||||
</ElRadio>
|
</ElRadio>
|
||||||
<ElRadio value="specify">
|
<ElRadio value="specify">
|
||||||
|
|
@ -39,16 +39,8 @@ const {hourState} = toRefs(useCronStore())
|
||||||
flex-wrap nowrap
|
flex-wrap nowrap
|
||||||
|
|
||||||
:deep(.el-input-number) {
|
:deep(.el-input-number) {
|
||||||
margin 0 5px
|
margin 0 10px
|
||||||
width: 60px
|
width: 80px
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-radio):nth-child(4) {
|
|
||||||
position relative
|
|
||||||
}
|
|
||||||
|
|
||||||
.second-item {
|
|
||||||
position relative
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-checkbox-group) {
|
:deep(.el-checkbox-group) {
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,16 @@ const {minuteState} = toRefs(useCronStore())
|
||||||
<ElRadio value="every">每分钟</ElRadio>
|
<ElRadio value="every">每分钟</ElRadio>
|
||||||
<ElRadio value="period1">
|
<ElRadio value="period1">
|
||||||
<span>周期,从</span>
|
<span>周期,从</span>
|
||||||
<ElInputNumber v-model="minuteState.period1.start" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="minuteState.period1.start" :controls="false" :max="58" :min="0" size="small"/>
|
||||||
<span>到</span>
|
<span>分到</span>
|
||||||
<ElInputNumber v-model="minuteState.period1.end" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="minuteState.period1.end" :controls="false" :max="59" :min="minuteState.period1.start" size="small"/>
|
||||||
|
<span>分</span>
|
||||||
</ElRadio>
|
</ElRadio>
|
||||||
<ElRadio value="period2">
|
<ElRadio value="period2">
|
||||||
<span>周期,从第</span>
|
<span>周期,从第</span>
|
||||||
<ElInputNumber v-model="minuteState.period2.start" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="minuteState.period2.start" :controls="false" :max="59" :min="0" size="small"/>
|
||||||
<span>分钟开始,每</span>
|
<span>分钟开始,每</span>
|
||||||
<ElInputNumber v-model="minuteState.period2.end" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="minuteState.period2.end" :controls="false" :max="59" :min="0" size="small"/>
|
||||||
<span>分钟执行一次</span>
|
<span>分钟执行一次</span>
|
||||||
</ElRadio>
|
</ElRadio>
|
||||||
<ElRadio value="specify">
|
<ElRadio value="specify">
|
||||||
|
|
@ -39,16 +40,8 @@ const {minuteState} = toRefs(useCronStore())
|
||||||
flex-wrap nowrap
|
flex-wrap nowrap
|
||||||
|
|
||||||
:deep(.el-input-number) {
|
:deep(.el-input-number) {
|
||||||
margin 0 5px
|
margin 0 10px
|
||||||
width: 60px
|
width: 80px
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-radio):nth-child(4) {
|
|
||||||
position relative
|
|
||||||
}
|
|
||||||
|
|
||||||
.second-item {
|
|
||||||
position relative
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-checkbox-group) {
|
:deep(.el-checkbox-group) {
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,10 @@ const months = [ '一月', '二月', '三月', '四月', '五月', '六月', '
|
||||||
<ElRadio value="every">每月</ElRadio>
|
<ElRadio value="every">每月</ElRadio>
|
||||||
<ElRadio value="period1">
|
<ElRadio value="period1">
|
||||||
<span>周期,从</span>
|
<span>周期,从</span>
|
||||||
<!-- <ElInputNumber v-model="monthState.period1.start" :controls="false" :max="59" :min="1" size="small"/> -->
|
|
||||||
<ElSelect v-model="monthState.period1.start" size="small">
|
<ElSelect v-model="monthState.period1.start" size="small">
|
||||||
<ElOption v-for="(month,i) in months" :key="'monthState.period1.start' + i" :label="month" :value="i"/>
|
<ElOption v-for="(month,i) in months" :key="'monthState.period1.start' + i" :label="month" :value="i"/>
|
||||||
</ElSelect>
|
</ElSelect>
|
||||||
<span>到</span>
|
<span>到</span>
|
||||||
<!-- <ElInputNumber v-model="monthState.period1.end" :controls="false" :max="59" :min="1" size="small"/> -->
|
|
||||||
<ElSelect v-model="monthState.period1.end" size="small">
|
<ElSelect v-model="monthState.period1.end" size="small">
|
||||||
<ElOption v-for="(month,i) in months" :key="'monthState.period1.end' + i" :disabled="i <= monthState.period1.start" :label="month" :value="i"/>
|
<ElOption v-for="(month,i) in months" :key="'monthState.period1.end' + i" :disabled="i <= monthState.period1.start" :label="month" :value="i"/>
|
||||||
</ElSelect>
|
</ElSelect>
|
||||||
|
|
@ -48,16 +46,13 @@ const months = [ '一月', '二月', '三月', '四月', '五月', '六月', '
|
||||||
flex-wrap nowrap
|
flex-wrap nowrap
|
||||||
|
|
||||||
:deep(.el-input-number) {
|
:deep(.el-input-number) {
|
||||||
margin 0 5px
|
margin 0 10px
|
||||||
width: 60px
|
width: 80px
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-radio):nth-child(4) {
|
:deep(.el-select) {
|
||||||
position relative
|
margin 0 10px
|
||||||
}
|
width: 80px
|
||||||
|
|
||||||
.second-item {
|
|
||||||
position relative
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-checkbox-group) {
|
:deep(.el-checkbox-group) {
|
||||||
|
|
@ -67,10 +62,10 @@ const months = [ '一月', '二月', '三月', '四月', '五月', '六月', '
|
||||||
display flex
|
display flex
|
||||||
flex-wrap wrap
|
flex-wrap wrap
|
||||||
gap 10px
|
gap 10px
|
||||||
width 500px
|
width 420px
|
||||||
|
|
||||||
.el-checkbox {
|
.el-checkbox {
|
||||||
width 40px;
|
width 60px;
|
||||||
margin 0
|
margin 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,16 @@ const {secondState} = toRefs(useCronStore())
|
||||||
<ElRadio value="every">每秒</ElRadio>
|
<ElRadio value="every">每秒</ElRadio>
|
||||||
<ElRadio value="period1">
|
<ElRadio value="period1">
|
||||||
<span>周期,从</span>
|
<span>周期,从</span>
|
||||||
<ElInputNumber v-model="secondState.period1.start" :controls="false" :max="59" :min="0" size="small"/>
|
<ElInputNumber v-model="secondState.period1.start" :controls="false" :max="58" :min="0" size="small"/>
|
||||||
<span>到</span>
|
<span>秒到</span>
|
||||||
<ElInputNumber v-model="secondState.period1.end" :controls="false" :max="59" :min="0" size="small"/>
|
<ElInputNumber v-model="secondState.period1.end" :controls="false" :max="59" :min="secondState.period1.start + 1" size="small"/>
|
||||||
|
<span>秒</span>
|
||||||
</ElRadio>
|
</ElRadio>
|
||||||
<ElRadio value="period2">
|
<ElRadio value="period2">
|
||||||
<span>周期,从第</span>
|
<span>周期,从第</span>
|
||||||
<ElInputNumber v-model="secondState.period2.start" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="secondState.period2.start" :controls="false" :max="59" :min="0" size="small"/>
|
||||||
<span>秒开始,每</span>
|
<span>秒开始,每</span>
|
||||||
<ElInputNumber v-model="secondState.period2.end" :controls="false" :max="59" :min="1" size="small"/>
|
<ElInputNumber v-model="secondState.period2.end" :controls="false" :max="59" :min="0" size="small"/>
|
||||||
<span>秒执行一次</span>
|
<span>秒执行一次</span>
|
||||||
</ElRadio>
|
</ElRadio>
|
||||||
<ElRadio value="specify">
|
<ElRadio value="specify">
|
||||||
|
|
@ -39,16 +40,8 @@ const {secondState} = toRefs(useCronStore())
|
||||||
flex-wrap nowrap
|
flex-wrap nowrap
|
||||||
|
|
||||||
:deep(.el-input-number) {
|
:deep(.el-input-number) {
|
||||||
margin 0 5px
|
margin 0 10px
|
||||||
width: 60px
|
width: 80px
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-radio):nth-child(4) {
|
|
||||||
position relative
|
|
||||||
}
|
|
||||||
|
|
||||||
.second-item {
|
|
||||||
position relative
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-checkbox-group) {
|
:deep(.el-checkbox-group) {
|
||||||
|
|
|
||||||
|
|
@ -48,19 +48,17 @@ const weeks = [ '星期一', '星期二', '星期三', '星期四', '星期五',
|
||||||
align-items start
|
align-items start
|
||||||
gap 10px
|
gap 10px
|
||||||
width 100%;
|
width 100%;
|
||||||
|
|
||||||
flex-wrap nowrap
|
flex-wrap nowrap
|
||||||
|
|
||||||
:deep(.el-input-number) {
|
:deep(.el-input-number) {
|
||||||
margin 0 5px
|
margin 0 10px
|
||||||
width: 60px
|
width: 80px
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-radio):nth-child(4) {
|
:deep(.el-select) {
|
||||||
position relative
|
margin 0 10px
|
||||||
}
|
width: 80px
|
||||||
|
|
||||||
.second-item {
|
|
||||||
position relative
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-checkbox-group) {
|
:deep(.el-checkbox-group) {
|
||||||
|
|
@ -73,7 +71,7 @@ const weeks = [ '星期一', '星期二', '星期三', '星期四', '星期五',
|
||||||
width 500px
|
width 500px
|
||||||
|
|
||||||
.el-checkbox {
|
.el-checkbox {
|
||||||
width 40px;
|
width 90px;
|
||||||
margin 0
|
margin 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,31 +28,8 @@ let year = new Date().getFullYear()
|
||||||
flex-wrap nowrap
|
flex-wrap nowrap
|
||||||
|
|
||||||
:deep(.el-input-number) {
|
:deep(.el-input-number) {
|
||||||
margin 0 5px
|
margin 0 10px
|
||||||
width: 60px
|
width: 80px
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-radio):nth-child(4) {
|
|
||||||
position relative
|
|
||||||
}
|
|
||||||
|
|
||||||
.second-item {
|
|
||||||
position relative
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-checkbox-group) {
|
|
||||||
position absolute
|
|
||||||
top 0
|
|
||||||
left 60px
|
|
||||||
display flex
|
|
||||||
flex-wrap wrap
|
|
||||||
gap 10px
|
|
||||||
width 500px
|
|
||||||
|
|
||||||
.el-checkbox {
|
|
||||||
width 40px;
|
|
||||||
margin 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -383,16 +383,16 @@ export const useCronStore = defineStore('Cron', () => {
|
||||||
|
|
||||||
})
|
})
|
||||||
const yearVal = computed(() => {
|
const yearVal = computed(() => {
|
||||||
let data: string = '*'
|
let data: string = ''
|
||||||
if (yearState.mode === 'none') {
|
if (yearState.mode === 'none') {
|
||||||
data = '?'
|
data = ''
|
||||||
} else if (yearState.mode === 'period1') {
|
} else if (yearState.mode === 'period1') {
|
||||||
data = `${yearState.period1.start}-${yearState.period1.end}`
|
data = `${yearState.period1.start}-${yearState.period1.end}`
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
})
|
})
|
||||||
const setYearVal = (val: string) => {
|
const setYearVal = (val: string) => {
|
||||||
if (val === '?') {
|
if (val === '') {
|
||||||
yearState.mode = 'none'
|
yearState.mode = 'none'
|
||||||
} else if (val.includes('-')) {
|
} else if (val.includes('-')) {
|
||||||
const s = val.split('-')
|
const s = val.split('-')
|
||||||
|
|
@ -403,18 +403,19 @@ export const useCronStore = defineStore('Cron', () => {
|
||||||
yearState.mode = 'every'
|
yearState.mode = 'every'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cronVal = computed({
|
const cronVal = computed({
|
||||||
get() {
|
get() {
|
||||||
console.log('获取值', `${secondVal.value} ${minuteVal.value} ${hourVal.value} ${dayVal.value} ${monthVal.value} ${weekVal.value} ${yearVal.value}`)
|
|
||||||
return `${secondVal.value} ${minuteVal.value} ${hourVal.value} ${dayVal.value} ${monthVal.value} ${weekVal.value} ${yearVal.value}`
|
return `${secondVal.value} ${minuteVal.value} ${hourVal.value} ${dayVal.value} ${monthVal.value} ${weekVal.value} ${yearVal.value}`
|
||||||
},
|
},
|
||||||
set(val: string = '* * * * * ? ?') {
|
set(val: string = '* * * * * ?') {
|
||||||
|
|
||||||
let sections = val.split(' ')
|
let sections = val.split(' ')
|
||||||
if (sections.length != 7) {
|
if (sections.length === 6) {
|
||||||
sections = '* * * * * ? ?'.split(' ')
|
sections.push('')
|
||||||
|
}
|
||||||
|
if (sections.length != 7) {
|
||||||
|
sections = [ '*', '*', '*', '*', '*', '*', '' ]
|
||||||
}
|
}
|
||||||
console.log('设置值', val, sections)
|
|
||||||
setSecondVal(sections[0])
|
setSecondVal(sections[0])
|
||||||
setMinuteVal(sections[1])
|
setMinuteVal(sections[1])
|
||||||
setHourVal(sections[2])
|
setHourVal(sections[2])
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@ export default {
|
||||||
disable(id: string, disable: boolean) {
|
disable(id: string, disable: boolean) {
|
||||||
return get<boolean>('/task/disable', {id, disable})
|
return get<boolean>('/task/disable', {id, disable})
|
||||||
},
|
},
|
||||||
|
checkExpression(expression: string) {
|
||||||
|
return get<string[]>('/task/check_expression', {expression})
|
||||||
|
},
|
||||||
add(data: TaskTypes.AddTaskParam) {
|
add(data: TaskTypes.AddTaskParam) {
|
||||||
return post('/task/add', data)
|
return post('/task/add', data)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue