feat:新增快速生成 Cron 表达式功能
This commit is contained in:
parent
8c57536513
commit
df4c4cfeab
@ -0,0 +1,77 @@
|
||||
<script setup>
|
||||
import { ElDescriptions, ElDescriptionsItem } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const cronExample = ref([
|
||||
{
|
||||
value: '0 0 10,15,16 * * ?',
|
||||
label: '每天上午10点,下午3点,4点'
|
||||
},
|
||||
{
|
||||
value: '0 0/30 9-17 * * ?',
|
||||
label: '朝九晚五工作时间内每半小时'
|
||||
},
|
||||
{
|
||||
value: '0 0 12 ? * WED ',
|
||||
label: '表示每个星期三中午12点'
|
||||
},
|
||||
{
|
||||
value: '0 0 12 * * ?',
|
||||
label: '每天中午12点触发'
|
||||
},
|
||||
{
|
||||
value: '0 15 10 ? * *',
|
||||
label: '每天上午10:15触发'
|
||||
},
|
||||
{
|
||||
value: '0 15 10 * * ?',
|
||||
label: '每天上午10:15触发 (跟上面的一样)'
|
||||
},
|
||||
{
|
||||
value: '0 15 10 * * ? 2005',
|
||||
label: '2005年的每天上午10:15触发'
|
||||
},
|
||||
{
|
||||
value: '0 * 14 * * ?',
|
||||
label: '在每天下午2点到下午2:59期间的每1分钟触发'
|
||||
},
|
||||
{
|
||||
value: '0 0/5 14 * * ?',
|
||||
label: '在每天下午2点到下午2:55期间的每5分钟触发'
|
||||
},
|
||||
{
|
||||
value: '0 0/5 14,18 * * ?',
|
||||
label: '在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发'
|
||||
},
|
||||
{
|
||||
value: '0 0-5 14 * * ?',
|
||||
label: '在每天下午2点到下午2:05期间的每1分钟触发'
|
||||
},
|
||||
{
|
||||
value: '0 10,44 14 ? 3 WED',
|
||||
label: '每年三月的星期三的下午2:10和2:44触发'
|
||||
},
|
||||
{
|
||||
value: '0 15 10 ? * MON-FRI',
|
||||
label: '周一至周五的上午10:15触发'
|
||||
},
|
||||
{
|
||||
value: '0 15 10 15 * ?',
|
||||
label: '每月15日上午10:15触发'
|
||||
},
|
||||
{
|
||||
value: '0 15 10 L * ?',
|
||||
label: '每月最后一日的上午10:15触发'
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElDescriptions :column="1" :border="true">
|
||||
<ElDescriptionsItem v-for="(item, index) in cronExample" :key="index" :label="item.value">{{
|
||||
item.label
|
||||
}}</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
@ -0,0 +1,681 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
ElTabs,
|
||||
ElTabPane,
|
||||
ElRadioGroup,
|
||||
ElRadio,
|
||||
ElInput,
|
||||
ElCheckboxGroup,
|
||||
ElCheckbox,
|
||||
ElTable,
|
||||
ElTableColumn,
|
||||
ElButton,
|
||||
ElMessage
|
||||
} from 'element-plus'
|
||||
import type { TableColumnCtx } from 'element-plus'
|
||||
import cron from 'cron-validate'
|
||||
import { Dialog } from '@/components/Dialog'
|
||||
import RunDatetimeList from './RunDatetimeList.vue'
|
||||
import CronExample from './CronExample.vue'
|
||||
|
||||
const activeName = ref('seconds')
|
||||
|
||||
const tableData = ref([
|
||||
{
|
||||
title: '表达式字段',
|
||||
seconds: '*',
|
||||
minutes: '*',
|
||||
hour: '*',
|
||||
day: '*',
|
||||
month: '*',
|
||||
week: '?',
|
||||
year: ''
|
||||
},
|
||||
{
|
||||
title: 'Cron 表达式',
|
||||
seconds: '* * * * * ?',
|
||||
minutes: '',
|
||||
hour: '',
|
||||
day: '',
|
||||
month: '',
|
||||
week: '',
|
||||
year: ''
|
||||
}
|
||||
])
|
||||
|
||||
const seconds = ref('0')
|
||||
const seconds1_1 = ref()
|
||||
const seconds1_2 = ref()
|
||||
const seconds2_1 = ref()
|
||||
const seconds2_2 = ref()
|
||||
const seconds3_1 = ref()
|
||||
|
||||
// 秒改变事件
|
||||
const secondsChange = () => {
|
||||
const secondsValue = ref('*')
|
||||
if (seconds.value === '1' && seconds1_1.value && seconds1_2.value) {
|
||||
secondsValue.value = `${seconds1_1.value}-${seconds1_2.value}`
|
||||
} else if (seconds.value === '2' && seconds2_1.value && seconds2_2.value) {
|
||||
secondsValue.value = `${seconds2_1.value}/${seconds2_2.value}`
|
||||
} else if (seconds.value === '3' && seconds3_1.value) {
|
||||
secondsValue.value = seconds3_1.value.join(',')
|
||||
}
|
||||
tableData.value[0].seconds = secondsValue.value
|
||||
fieldToCron(tableData.value[0])
|
||||
}
|
||||
|
||||
const minutes = ref('0')
|
||||
const minutes1_1 = ref()
|
||||
const minutes1_2 = ref()
|
||||
const minutes2_1 = ref()
|
||||
const minutes2_2 = ref()
|
||||
const minutes3_1 = ref()
|
||||
|
||||
// 分改变事件
|
||||
const minutesChange = () => {
|
||||
const minutesValue = ref('*')
|
||||
if (minutes.value === '1' && minutes1_1.value && minutes1_2.value) {
|
||||
minutesValue.value = `${minutes1_1.value}-${minutes1_2.value}`
|
||||
} else if (minutes.value === '2' && minutes2_1.value && minutes2_2.value) {
|
||||
minutesValue.value = `${minutes2_1.value}/${minutes2_2.value}`
|
||||
} else if (minutes.value === '3' && minutes3_1.value) {
|
||||
minutesValue.value = minutes3_1.value.join(',')
|
||||
}
|
||||
tableData.value[0].minutes = minutesValue.value
|
||||
fieldToCron(tableData.value[0])
|
||||
}
|
||||
|
||||
const hour = ref('0')
|
||||
const hour1_1 = ref()
|
||||
const hour1_2 = ref()
|
||||
const hour2_1 = ref()
|
||||
const hour2_2 = ref()
|
||||
const hour3_1 = ref()
|
||||
|
||||
// 小时改变事件
|
||||
const hourChange = () => {
|
||||
const hourValue = ref('*')
|
||||
if (hour.value === '1' && hour1_1.value && hour1_2.value) {
|
||||
hourValue.value = `${hour1_1.value}-${hour1_2.value}`
|
||||
} else if (hour.value === '2' && hour2_1.value && hour2_2.value) {
|
||||
hourValue.value = `${hour2_1.value}/${hour2_2.value}`
|
||||
} else if (hour.value === '3' && hour3_1.value) {
|
||||
hourValue.value = hour3_1.value.join(',')
|
||||
}
|
||||
tableData.value[0].hour = hourValue.value
|
||||
fieldToCron(tableData.value[0])
|
||||
}
|
||||
|
||||
const day = ref('0')
|
||||
const day1_1 = ref()
|
||||
const day1_2 = ref()
|
||||
const day2_1 = ref()
|
||||
const day2_2 = ref()
|
||||
const day3_1 = ref()
|
||||
const day4_1 = ref()
|
||||
|
||||
// 日改变事件
|
||||
const dayChange = () => {
|
||||
const dayValue = ref('*')
|
||||
if (day.value === '1') {
|
||||
dayValue.value = '?'
|
||||
} else if (day.value === '2') {
|
||||
dayValue.value = 'L'
|
||||
} else if (day.value === '3' && day1_1.value && day1_2.value) {
|
||||
dayValue.value = `${day1_1.value}-${day1_2.value}`
|
||||
} else if (day.value === '4' && day2_1.value && day2_2.value) {
|
||||
dayValue.value = `${day2_1.value}/${day2_2.value}`
|
||||
} else if (day.value === '5' && day3_1.value) {
|
||||
dayValue.value = `${day3_1.value}W`
|
||||
} else if (day.value === '6' && day4_1.value) {
|
||||
dayValue.value = day4_1.value.join(',')
|
||||
}
|
||||
tableData.value[0].day = dayValue.value
|
||||
if (day.value !== '1') {
|
||||
week.value = '1'
|
||||
tableData.value[0].week = '?'
|
||||
}
|
||||
fieldToCron(tableData.value[0])
|
||||
}
|
||||
|
||||
const month = ref('0')
|
||||
const month1_1 = ref()
|
||||
const month1_2 = ref()
|
||||
const month2_1 = ref()
|
||||
const month2_2 = ref()
|
||||
const month3_1 = ref()
|
||||
|
||||
// 月改变事件
|
||||
const monthChange = () => {
|
||||
const monthValue = ref('*')
|
||||
if (month.value === '1' && month1_1.value && month1_2.value) {
|
||||
monthValue.value = `${month1_1.value}-${month1_2.value}`
|
||||
} else if (month.value === '2' && month2_1.value && month2_2.value) {
|
||||
monthValue.value = `${month2_1.value}/${month2_2.value}`
|
||||
} else if (month.value === '3' && month3_1.value) {
|
||||
monthValue.value = month3_1.value.join(',')
|
||||
}
|
||||
tableData.value[0].month = monthValue.value
|
||||
fieldToCron(tableData.value[0])
|
||||
}
|
||||
|
||||
const weekListData = ref(['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'])
|
||||
const week = ref('1')
|
||||
const week1_1 = ref()
|
||||
const week1_2 = ref()
|
||||
const week2_1 = ref()
|
||||
const week2_2 = ref()
|
||||
const week3_1 = ref()
|
||||
const week4_1 = ref()
|
||||
|
||||
// 周改变事件
|
||||
const weekChange = () => {
|
||||
const weekValue = ref('*')
|
||||
if (week.value === '1') {
|
||||
weekValue.value = '?'
|
||||
} else if (week.value === '2' && week1_1.value && week1_2.value) {
|
||||
weekValue.value = `${week1_1.value}-${week1_2.value}`
|
||||
} else if (week.value === '3' && week2_1.value && week2_2.value) {
|
||||
weekValue.value = `${week2_1.value}#${week2_2.value}`
|
||||
} else if (week.value === '4' && week3_1.value) {
|
||||
weekValue.value = `${week3_1.value}L`
|
||||
} else if (week.value === '5' && week4_1.value) {
|
||||
weekValue.value = week4_1.value.join(',')
|
||||
}
|
||||
tableData.value[0].week = weekValue.value
|
||||
if (week.value !== '1') {
|
||||
day.value = '1'
|
||||
tableData.value[0].day = '?'
|
||||
}
|
||||
fieldToCron(tableData.value[0])
|
||||
}
|
||||
|
||||
const year = ref()
|
||||
const year1_1 = ref()
|
||||
const year1_2 = ref()
|
||||
|
||||
// 年改变事件
|
||||
const yearChange = () => {
|
||||
const yearValue = ref('')
|
||||
if (year.value === '0') {
|
||||
yearValue.value = '*'
|
||||
} else if (year.value === '1') {
|
||||
yearValue.value = ''
|
||||
} else if (year.value === '2' && year1_1.value && year1_2.value) {
|
||||
yearValue.value = `${year1_1.value}-${year1_2.value}`
|
||||
}
|
||||
tableData.value[0].year = yearValue.value
|
||||
fieldToCron(tableData.value[0])
|
||||
}
|
||||
|
||||
interface SpanMethodProps {
|
||||
row: any
|
||||
column: TableColumnCtx<any>
|
||||
rowIndex: number
|
||||
columnIndex: number
|
||||
}
|
||||
|
||||
// 表格合并单元格
|
||||
const arraySpanMethod = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
|
||||
if (rowIndex === 1 && columnIndex >= 1 && columnIndex <= 6) {
|
||||
return {
|
||||
rowspan: 1,
|
||||
colspan: 6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表达式字段 转 Cron 表达式
|
||||
const fieldToCron = (row) => {
|
||||
const seconds = row.seconds !== '' ? row.seconds : '*'
|
||||
const minutes = row.minutes !== '' ? row.minutes : '*'
|
||||
const hour = row.hour !== '' ? row.hour : '*'
|
||||
const day = row.day !== '' ? row.day : '*'
|
||||
const month = row.month !== '' ? row.month : '*'
|
||||
const week = row.week !== '' ? row.week : '?'
|
||||
const year = row.year !== '' ? row.year : ''
|
||||
|
||||
const cron = ref(`${seconds} ${minutes} ${hour} ${day} ${month} ${week} ${year}`)
|
||||
tableData.value[1].seconds = cron.value.trim()
|
||||
}
|
||||
|
||||
// Cron 表达式 转 表达式字段
|
||||
const cronToField = () => {
|
||||
const cronExpression = tableData.value[1].seconds // 获取 Cron 表达式
|
||||
const [seconds, minutes, hour, day, month, week, year] = cronExpression.split(' ')
|
||||
|
||||
// 更新表达式字段的值
|
||||
tableData.value[0].seconds = seconds
|
||||
tableData.value[0].minutes = minutes
|
||||
tableData.value[0].hour = hour
|
||||
tableData.value[0].day = day
|
||||
tableData.value[0].month = month
|
||||
tableData.value[0].week = week
|
||||
tableData.value[0].year = year
|
||||
}
|
||||
|
||||
// 验证 cron 表达式
|
||||
// https://blog.csdn.net/a2524289/article/details/109177764
|
||||
// 生成工具:https://cron.qqe2.com/
|
||||
// cron 表达式转中文描述:https://github.com/bradymholt/cRonstrue
|
||||
// cronjs 解析器与匹配器(五位):https://github.com/datasert/cronjs
|
||||
// cron 表达式验证器:https://github.com/Airfooox/cron-validate
|
||||
const validate = () => {
|
||||
const cronExpression = tableData.value[1].seconds // 获取 Cron 表达式
|
||||
const fields = cronExpression.split(' ')
|
||||
const [seconds, minutes, hour, day, month, week, year] = fields
|
||||
let useYears = true
|
||||
|
||||
if (fields.length === 6) {
|
||||
useYears = false
|
||||
} else if (fields.length === 7) {
|
||||
useYears = true
|
||||
} else {
|
||||
ElMessage.error('验证失败')
|
||||
return
|
||||
}
|
||||
// 验证字段是否为空
|
||||
if (!seconds || !minutes || !hour || !day || !month || !week) {
|
||||
ElMessage.error('验证失败')
|
||||
return
|
||||
}
|
||||
|
||||
// 验证日字段和周字段的冲突
|
||||
if (day === '?' && week === '?') {
|
||||
ElMessage.error('验证失败')
|
||||
return
|
||||
}
|
||||
const result = cron(cronExpression, {
|
||||
override: {
|
||||
useSeconds: true,
|
||||
useYears: useYears,
|
||||
useBlankDay: true,
|
||||
useLastDayOfMonth: true,
|
||||
useLastDayOfWeek: true,
|
||||
useNearestWeekday: true,
|
||||
useNthWeekdayOfMonth: true
|
||||
}
|
||||
}).isValid()
|
||||
if (result) {
|
||||
ElMessage.success('验证成功')
|
||||
} else {
|
||||
ElMessage.error('验证失败')
|
||||
}
|
||||
}
|
||||
|
||||
const dialogVisible1 = ref(false)
|
||||
const dialogVisible2 = ref(false)
|
||||
|
||||
// 获取最近十次运行时间
|
||||
const getRunDatetime = () => {
|
||||
dialogVisible1.value = true
|
||||
}
|
||||
|
||||
// Cron 表达式示例
|
||||
const getCronExample = () => {
|
||||
dialogVisible2.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="cron-expression-box">
|
||||
<ElTabs v-model="activeName" type="border-card">
|
||||
<ElTabPane label="秒" name="seconds">
|
||||
<ElRadioGroup class="!block" v-model="seconds" @change="secondsChange">
|
||||
<div class="list-item">
|
||||
<ElRadio label="0">每秒</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio label="1">
|
||||
<ElInput v-model="seconds1_1" @change="secondsChange" class="!w-[300px]">
|
||||
<template #prepend> 周期从 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="seconds1_2" @change="secondsChange" class="!w-[300px]">
|
||||
<template #prepend> - </template>
|
||||
<template #append>秒</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-4">
|
||||
<ElRadio label="2">
|
||||
<ElInput v-model="seconds2_1" @change="secondsChange" class="!w-[200px]">
|
||||
<template #prepend> 从 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="seconds2_2" @change="secondsChange" class="!w-[400px]">
|
||||
<template #prepend> 秒开始,每 </template>
|
||||
<template #append>秒执行一次</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio class="!whitespace-normal !inline" label="3">
|
||||
<span>指定</span>
|
||||
<ElCheckboxGroup class="ml-6" v-model="seconds3_1" @change="secondsChange">
|
||||
<ElCheckbox v-for="(num, index) in 60" :key="num" :label="index.toString()" />
|
||||
</ElCheckboxGroup>
|
||||
</ElRadio>
|
||||
</div>
|
||||
</ElRadioGroup>
|
||||
</ElTabPane>
|
||||
<ElTabPane label="分" name="minutes">
|
||||
<ElRadioGroup class="!block" v-model="minutes" @change="minutesChange">
|
||||
<div class="list-item">
|
||||
<ElRadio label="0">每分</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio label="1">
|
||||
<ElInput v-model="minutes1_1" @change="minutesChange" class="!w-[300px]">
|
||||
<template #prepend> 周期从 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="minutes1_2" @change="minutesChange" class="!w-[300px]">
|
||||
<template #prepend> - </template>
|
||||
<template #append>分</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-4">
|
||||
<ElRadio label="2">
|
||||
<ElInput v-model="minutes2_1" @change="minutesChange" class="!w-[200px]">
|
||||
<template #prepend> 从 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="minutes2_2" @change="minutesChange" class="!w-[400px]">
|
||||
<template #prepend> 分开始,每 </template>
|
||||
<template #append>分执行一次</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio class="!whitespace-normal !inline" label="3">
|
||||
<span>指定</span>
|
||||
<ElCheckboxGroup class="ml-6" v-model="minutes3_1" @change="minutesChange">
|
||||
<ElCheckbox v-for="(num, index) in 60" :key="num" :label="index.toString()" />
|
||||
</ElCheckboxGroup>
|
||||
</ElRadio>
|
||||
</div>
|
||||
</ElRadioGroup>
|
||||
</ElTabPane>
|
||||
<ElTabPane label="时" name="hour">
|
||||
<ElRadioGroup class="!block" v-model="hour" @change="hourChange">
|
||||
<div class="list-item">
|
||||
<ElRadio label="0">每小时</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio label="1">
|
||||
<ElInput v-model="hour1_1" @change="hourChange" class="!w-[300px]">
|
||||
<template #prepend> 周期从 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="hour1_2" @change="hourChange" class="!w-[300px]">
|
||||
<template #prepend> - </template>
|
||||
<template #append>小时</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-4">
|
||||
<ElRadio label="2">
|
||||
<ElInput v-model="hour2_1" @change="hourChange" class="!w-[200px]">
|
||||
<template #prepend> 从 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="hour2_2" @change="hourChange" class="!w-[400px]">
|
||||
<template #prepend> 小时开始,每 </template>
|
||||
<template #append>小时执行一次</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio class="!whitespace-normal !inline" label="3">
|
||||
<span>指定</span>
|
||||
<ElCheckboxGroup class="ml-6" v-model="hour3_1" @change="hourChange">
|
||||
<ElCheckbox v-for="(num, index) in 24" :key="num" :label="index.toString()" />
|
||||
</ElCheckboxGroup>
|
||||
</ElRadio>
|
||||
</div>
|
||||
</ElRadioGroup>
|
||||
</ElTabPane>
|
||||
<ElTabPane label="日" name="day">
|
||||
<ElRadioGroup class="!block" v-model="day" @change="dayChange">
|
||||
<div class="list-item">
|
||||
<ElRadio label="0">每天</ElRadio>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<ElRadio label="1">不指定</ElRadio>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<ElRadio label="2">月最后一天</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio label="3">
|
||||
<ElInput v-model="day1_1" @change="dayChange" class="!w-[300px]">
|
||||
<template #prepend> 周期从 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="day1_2" @change="dayChange" class="!w-[300px]">
|
||||
<template #prepend> - </template>
|
||||
<template #append>日</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-4">
|
||||
<ElRadio label="4">
|
||||
<ElInput v-model="day2_1" @change="dayChange" class="!w-[200px]">
|
||||
<template #prepend> 从 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="day2_2" @change="dayChange" class="!w-[400px]">
|
||||
<template #prepend> 日开始,每 </template>
|
||||
<template #append>日执行一次</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-4">
|
||||
<ElRadio label="5">
|
||||
<ElInput v-model="day3_1" @change="dayChange" class="!w-[600px]">
|
||||
<template #prepend> 每月 </template>
|
||||
<template #append>号最近的那个工作日</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio class="!whitespace-normal !inline" label="6">
|
||||
<span>指定</span>
|
||||
<ElCheckboxGroup class="ml-6" v-model="day4_1" @change="dayChange">
|
||||
<ElCheckbox v-for="num in 31" :key="num" :label="num" />
|
||||
</ElCheckboxGroup>
|
||||
</ElRadio>
|
||||
</div>
|
||||
</ElRadioGroup>
|
||||
</ElTabPane>
|
||||
<ElTabPane label="月" name="month">
|
||||
<ElRadioGroup class="!block" v-model="month" @change="monthChange">
|
||||
<div class="list-item">
|
||||
<ElRadio label="0">每月</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio label="1">
|
||||
<ElInput v-model="month1_1" @change="monthChange" class="!w-[300px]">
|
||||
<template #prepend> 周期从 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="month1_2" @change="monthChange" class="!w-[300px]">
|
||||
<template #prepend> - </template>
|
||||
<template #append>月</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-4">
|
||||
<ElRadio label="2">
|
||||
<ElInput v-model="month2_1" @change="monthChange" class="!w-[200px]">
|
||||
<template #prepend> 从 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="month2_2" @change="monthChange" class="!w-[400px]">
|
||||
<template #prepend> 月开始,每 </template>
|
||||
<template #append>月执行一次</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio class="!whitespace-normal !inline" label="3">
|
||||
<span>指定</span>
|
||||
<ElCheckboxGroup class="ml-6" v-model="month3_1" @change="monthChange">
|
||||
<ElCheckbox v-for="num in 12" :key="num" :label="num" />
|
||||
</ElCheckboxGroup>
|
||||
</ElRadio>
|
||||
</div>
|
||||
</ElRadioGroup>
|
||||
</ElTabPane>
|
||||
<ElTabPane label="周" name="week">
|
||||
<ElRadioGroup class="!block" v-model="week" @change="weekChange">
|
||||
<div class="list-item">
|
||||
<ElRadio label="0">每周</ElRadio>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<ElRadio label="1">不指定</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio label="2">
|
||||
<ElInput v-model="week1_1" @change="weekChange" class="!w-[300px]">
|
||||
<template #prepend> 周期从星期 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="week1_2" @change="weekChange" class="!w-[300px]">
|
||||
<template #prepend> - 星期</template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-4">
|
||||
<ElRadio label="3">
|
||||
<ElInput v-model="week2_1" @change="weekChange" class="!w-[300px]">
|
||||
<template #prepend> 第 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="week2_2" @change="weekChange" class="!w-[300px]">
|
||||
<template #prepend> 星期的星期 </template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-4">
|
||||
<ElRadio label="4">
|
||||
<ElInput v-model="week3_1" @change="weekChange" class="!w-[600px]">
|
||||
<template #prepend> 本月最后一个星期 </template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio class="!whitespace-normal !inline" label="5">
|
||||
<span>指定</span>
|
||||
<ElCheckboxGroup class="ml-6" v-model="week4_1" @change="weekChange">
|
||||
<ElCheckbox v-for="(item, index) in weekListData" :key="index" :label="index">{{
|
||||
item
|
||||
}}</ElCheckbox>
|
||||
</ElCheckboxGroup>
|
||||
</ElRadio>
|
||||
</div>
|
||||
</ElRadioGroup>
|
||||
</ElTabPane>
|
||||
<ElTabPane label="年" name="year">
|
||||
<ElRadioGroup class="!block" v-model="year" @change="yearChange">
|
||||
<div class="list-item">
|
||||
<ElRadio label="0">每年</ElRadio>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<ElRadio label="1">不指定</ElRadio>
|
||||
</div>
|
||||
<div class="list-item mt-2">
|
||||
<ElRadio label="2">
|
||||
<ElInput v-model="year1_1" @change="yearChange" class="!w-[300px]">
|
||||
<template #prepend> 周期从 </template>
|
||||
</ElInput>
|
||||
<ElInput v-model="year1_2" @change="yearChange" class="!w-[300px]">
|
||||
<template #prepend> - </template>
|
||||
<template #append> 年 </template>
|
||||
</ElInput>
|
||||
</ElRadio>
|
||||
</div>
|
||||
</ElRadioGroup>
|
||||
</ElTabPane>
|
||||
</ElTabs>
|
||||
<div class="mt-5">
|
||||
<span class="text-[17px]">生成表达式</span>
|
||||
<ElTable
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
:span-method="arraySpanMethod"
|
||||
class="mt-2"
|
||||
:border="true"
|
||||
>
|
||||
<ElTableColumn prop="title" label="" />
|
||||
<ElTableColumn prop="seconds" label="秒" align="center">
|
||||
<template #default="{ row, $index }">
|
||||
<ElInput v-if="$index === 0" v-model="row.seconds" @change="fieldToCron(row)" />
|
||||
<ElInput v-if="$index === 1" v-model="row.seconds" />
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="minutes" label="分钟" align="center">
|
||||
<template #default="{ row, $index }">
|
||||
<ElInput v-if="$index === 0" v-model="row.minutes" @change="fieldToCron(row)" />
|
||||
<ElButton v-if="$index === 1" type="primary" link @click="cronToField">
|
||||
解析为字段
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="hour" label="小时" align="center">
|
||||
<template #default="{ row, $index }">
|
||||
<ElInput v-if="$index === 0" v-model="row.hour" @change="fieldToCron(row)" />
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="day" label="日" align="center">
|
||||
<template #default="{ row, $index }">
|
||||
<ElInput v-if="$index === 0" v-model="row.day" @change="fieldToCron(row)" />
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="month" label="月" align="center">
|
||||
<template #default="{ row, $index }">
|
||||
<ElInput v-if="$index === 0" v-model="row.month" @change="fieldToCron(row)" />
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="week" label="星期" align="center">
|
||||
<template #default="{ row, $index }">
|
||||
<ElInput v-if="$index === 0" v-model="row.week" @change="fieldToCron(row)" />
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="year" label="年" align="center">
|
||||
<template #default="{ row, $index }">
|
||||
<ElInput v-if="$index === 0" v-model="row.year" @change="fieldToCron(row)" />
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
<div class="mt-3 text-center">
|
||||
<ElButton type="primary" @click="getRunDatetime">获取最近十次运行时间</ElButton>
|
||||
<ElButton type="primary" @click="validate">Cron 表达式验证</ElButton>
|
||||
<ElButton type="primary" @click="getCronExample">Cron 表达式示例</ElButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog
|
||||
v-model="dialogVisible1"
|
||||
title="获取最近十次运行时间"
|
||||
width="600px"
|
||||
height="400px"
|
||||
top="13vh"
|
||||
>
|
||||
<RunDatetimeList :expression="tableData[1].seconds" />
|
||||
</Dialog>
|
||||
|
||||
<Dialog v-model="dialogVisible2" title="Cron 表达式示例" width="700px" height="620px" top="12vh">
|
||||
<CronExample />
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.cron-expression-box {
|
||||
.el-input {
|
||||
.el-input-group__prepend {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.el-input-group__append {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.el-input__wrapper {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,565 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
|
||||
const props = defineProps({
|
||||
expression: propTypes.string.def('')
|
||||
})
|
||||
|
||||
let dateArr = []
|
||||
let isShow = false
|
||||
let dayRule = ''
|
||||
let dayRuleSup = ''
|
||||
let resultList = []
|
||||
|
||||
/**
|
||||
* 计算 Cron 表达式最近五次运行时间结果
|
||||
* 感谢若依:http://vue.ruoyi.vip/monitor/job
|
||||
*/
|
||||
const expressionChange = (expression) => {
|
||||
// 计算开始-隐藏结果
|
||||
isShow = false
|
||||
// 获取规则数组[0秒、1分、2时、3日、4月、5星期、6年]
|
||||
let ruleArr = expression.split(' ')
|
||||
// 用于记录进入循环的次数
|
||||
let nums = 0
|
||||
// 用于暂时存符号时间规则结果的数组
|
||||
let resultArr = []
|
||||
// 获取当前时间精确至[年、月、日、时、分、秒]
|
||||
let nTime = new Date()
|
||||
let nYear = nTime.getFullYear()
|
||||
let nMonth = nTime.getMonth() + 1
|
||||
let nDay = nTime.getDate()
|
||||
let nHour = nTime.getHours()
|
||||
let nMin = nTime.getMinutes()
|
||||
let nSecond = nTime.getSeconds()
|
||||
// 根据规则获取到近100年可能年数组、月数组等等
|
||||
getSecondArr(ruleArr[0])
|
||||
getMinArr(ruleArr[1])
|
||||
getHourArr(ruleArr[2])
|
||||
getDayArr(ruleArr[3])
|
||||
getMonthArr(ruleArr[4])
|
||||
getWeekArr(ruleArr[5])
|
||||
getYearArr(ruleArr[6], nYear)
|
||||
// 将获取到的数组赋值-方便使用
|
||||
let sDate = dateArr[0]
|
||||
let mDate = dateArr[1]
|
||||
let hDate = dateArr[2]
|
||||
let DDate = dateArr[3]
|
||||
let MDate = dateArr[4]
|
||||
let YDate = dateArr[5]
|
||||
// 获取当前时间在数组中的索引
|
||||
let sIdx = getIndex(sDate, nSecond)
|
||||
let mIdx = getIndex(mDate, nMin)
|
||||
let hIdx = getIndex(hDate, nHour)
|
||||
let DIdx = getIndex(DDate, nDay)
|
||||
let MIdx = getIndex(MDate, nMonth)
|
||||
let YIdx = getIndex(YDate, nYear)
|
||||
// 重置月日时分秒的函数(后面用的比较多)
|
||||
const resetSecond = function () {
|
||||
sIdx = 0
|
||||
nSecond = sDate[sIdx]
|
||||
}
|
||||
const resetMin = function () {
|
||||
mIdx = 0
|
||||
nMin = mDate[mIdx]
|
||||
resetSecond()
|
||||
}
|
||||
const resetHour = function () {
|
||||
hIdx = 0
|
||||
nHour = hDate[hIdx]
|
||||
resetMin()
|
||||
}
|
||||
const resetDay = function () {
|
||||
DIdx = 0
|
||||
nDay = DDate[DIdx]
|
||||
resetHour()
|
||||
}
|
||||
const resetMonth = function () {
|
||||
MIdx = 0
|
||||
nMonth = MDate[MIdx]
|
||||
resetDay()
|
||||
}
|
||||
// 如果当前年份不为数组中当前值
|
||||
if (nYear !== YDate[YIdx]) {
|
||||
resetMonth()
|
||||
}
|
||||
// 如果当前月份不为数组中当前值
|
||||
if (nMonth !== MDate[MIdx]) {
|
||||
resetDay()
|
||||
}
|
||||
// 如果当前“日”不为数组中当前值
|
||||
if (nDay !== DDate[DIdx]) {
|
||||
resetHour()
|
||||
}
|
||||
// 如果当前“时”不为数组中当前值
|
||||
if (nHour !== hDate[hIdx]) {
|
||||
resetMin()
|
||||
}
|
||||
// 如果当前“分”不为数组中当前值
|
||||
if (nMin !== mDate[mIdx]) {
|
||||
resetSecond()
|
||||
}
|
||||
|
||||
// 循环年份数组
|
||||
goYear: for (let Yi = YIdx; Yi < YDate.length; Yi++) {
|
||||
let YY = YDate[Yi]
|
||||
// 如果到达最大值时
|
||||
if (nMonth > MDate[MDate.length - 1]) {
|
||||
resetMonth()
|
||||
continue
|
||||
}
|
||||
// 循环月份数组
|
||||
goMonth: for (let Mi = MIdx; Mi < MDate.length; Mi++) {
|
||||
// 赋值、方便后面运算
|
||||
let MM = MDate[Mi]
|
||||
MM = MM < 10 ? '0' + MM : MM
|
||||
// 如果到达最大值时
|
||||
if (nDay > DDate[DDate.length - 1]) {
|
||||
resetDay()
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMonth()
|
||||
continue goYear
|
||||
}
|
||||
continue
|
||||
}
|
||||
// 循环日期数组
|
||||
goDay: for (let Di = DIdx; Di < DDate.length; Di++) {
|
||||
// 赋值、方便后面运算
|
||||
let DD = DDate[Di]
|
||||
let thisDD = DD < 10 ? '0' + DD : DD
|
||||
|
||||
// 如果到达最大值时
|
||||
if (nHour > hDate[hDate.length - 1]) {
|
||||
resetHour()
|
||||
if (Di == DDate.length - 1) {
|
||||
resetDay()
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMonth()
|
||||
continue goYear
|
||||
}
|
||||
continue goMonth
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// 判断日期的合法性,不合法的话也是跳出当前循环
|
||||
if (
|
||||
checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true &&
|
||||
dayRule !== 'workDay' &&
|
||||
dayRule !== 'lastWeek' &&
|
||||
dayRule !== 'lastDay'
|
||||
) {
|
||||
resetDay()
|
||||
continue goMonth
|
||||
}
|
||||
// 如果日期规则中有值时
|
||||
if (dayRule == 'lastDay') {
|
||||
// 如果不是合法日期则需要将前将日期调到合法日期即月末最后一天
|
||||
|
||||
if (checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
while (DD > 0 && checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
DD--
|
||||
|
||||
thisDD = DD < 10 ? '0' + DD : DD
|
||||
}
|
||||
}
|
||||
} else if (dayRule == 'workDay') {
|
||||
// 校验并调整如果是2月30号这种日期传进来时需调整至正常月底
|
||||
if (checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
while (DD > 0 && checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
DD--
|
||||
thisDD = DD < 10 ? '0' + DD : DD
|
||||
}
|
||||
}
|
||||
// 获取达到条件的日期是星期X
|
||||
let thisWeek = formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week')
|
||||
// 当星期日时
|
||||
if (thisWeek == 1) {
|
||||
// 先找下一个日,并判断是否为月底
|
||||
DD++
|
||||
thisDD = DD < 10 ? '0' + DD : DD
|
||||
// 判断下一日已经不是合法日期
|
||||
if (checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
DD -= 3
|
||||
}
|
||||
} else if (thisWeek == 7) {
|
||||
// 当星期6时只需判断不是1号就可进行操作
|
||||
if (dayRuleSup !== 1) {
|
||||
DD--
|
||||
} else {
|
||||
DD += 2
|
||||
}
|
||||
}
|
||||
} else if (dayRule == 'weekDay') {
|
||||
// 如果指定了是星期几
|
||||
// 获取当前日期是属于星期几
|
||||
let thisWeek = formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week')
|
||||
// 校验当前星期是否在星期池(dayRuleSup)中
|
||||
if (dayRuleSup.indexOf(thisWeek) < 0) {
|
||||
// 如果到达最大值时
|
||||
if (Di == DDate.length - 1) {
|
||||
resetDay()
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMonth()
|
||||
continue goYear
|
||||
}
|
||||
continue goMonth
|
||||
}
|
||||
continue
|
||||
}
|
||||
} else if (dayRule == 'assWeek') {
|
||||
// 如果指定了是第几周的星期几
|
||||
// 获取每月1号是属于星期几
|
||||
let thisWeek = formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week')
|
||||
if (dayRuleSup[1] >= thisWeek) {
|
||||
DD = (dayRuleSup[0] - 1) * 7 + dayRuleSup[1] - thisWeek + 1
|
||||
} else {
|
||||
DD = dayRuleSup[0] * 7 + dayRuleSup[1] - thisWeek + 1
|
||||
}
|
||||
} else if (dayRule == 'lastWeek') {
|
||||
// 如果指定了每月最后一个星期几
|
||||
// 校验并调整如果是2月30号这种日期传进来时需调整至正常月底
|
||||
if (checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
while (DD > 0 && checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
|
||||
DD--
|
||||
thisDD = DD < 10 ? '0' + DD : DD
|
||||
}
|
||||
}
|
||||
// 获取月末最后一天是星期几
|
||||
let thisWeek = formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week')
|
||||
// 找到要求中最近的那个星期几
|
||||
if (dayRuleSup < thisWeek) {
|
||||
DD -= thisWeek - dayRuleSup
|
||||
} else if (dayRuleSup > thisWeek) {
|
||||
DD -= 7 - (dayRuleSup - thisWeek)
|
||||
}
|
||||
}
|
||||
// 判断时间值是否小于10置换成“05”这种格式
|
||||
DD = DD < 10 ? '0' + DD : DD
|
||||
|
||||
// 循环“时”数组
|
||||
goHour: for (let hi = hIdx; hi < hDate.length; hi++) {
|
||||
let hh = hDate[hi] < 10 ? '0' + hDate[hi] : hDate[hi]
|
||||
|
||||
// 如果到达最大值时
|
||||
if (nMin > mDate[mDate.length - 1]) {
|
||||
resetMin()
|
||||
if (hi == hDate.length - 1) {
|
||||
resetHour()
|
||||
if (Di == DDate.length - 1) {
|
||||
resetDay()
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMonth()
|
||||
continue goYear
|
||||
}
|
||||
continue goMonth
|
||||
}
|
||||
continue goDay
|
||||
}
|
||||
continue
|
||||
}
|
||||
// 循环"分"数组
|
||||
goMin: for (let mi = mIdx; mi < mDate.length; mi++) {
|
||||
let mm = mDate[mi] < 10 ? '0' + mDate[mi] : mDate[mi]
|
||||
|
||||
// 如果到达最大值时
|
||||
if (nSecond > sDate[sDate.length - 1]) {
|
||||
resetSecond()
|
||||
if (mi == mDate.length - 1) {
|
||||
resetMin()
|
||||
if (hi == hDate.length - 1) {
|
||||
resetHour()
|
||||
if (Di == DDate.length - 1) {
|
||||
resetDay()
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMonth()
|
||||
continue goYear
|
||||
}
|
||||
continue goMonth
|
||||
}
|
||||
continue goDay
|
||||
}
|
||||
continue goHour
|
||||
}
|
||||
continue
|
||||
}
|
||||
// 循环"秒"数组
|
||||
goSecond: for (let si = sIdx; si <= sDate.length - 1; si++) {
|
||||
let ss = sDate[si] < 10 ? '0' + sDate[si] : sDate[si]
|
||||
// 添加当前时间(时间合法性在日期循环时已经判断)
|
||||
if (MM !== '00' && DD !== '00') {
|
||||
resultArr.push(YY + '-' + MM + '-' + DD + ' ' + hh + ':' + mm + ':' + ss)
|
||||
nums++
|
||||
}
|
||||
// 如果条数满了就退出循环
|
||||
if (nums == 5) break goYear
|
||||
// 如果到达最大值时
|
||||
if (si == sDate.length - 1) {
|
||||
resetSecond()
|
||||
if (mi == mDate.length - 1) {
|
||||
resetMin()
|
||||
if (hi == hDate.length - 1) {
|
||||
resetHour()
|
||||
if (Di == DDate.length - 1) {
|
||||
resetDay()
|
||||
if (Mi == MDate.length - 1) {
|
||||
resetMonth()
|
||||
continue goYear
|
||||
}
|
||||
continue goMonth
|
||||
}
|
||||
continue goDay
|
||||
}
|
||||
continue goHour
|
||||
}
|
||||
continue goMin
|
||||
}
|
||||
} //goSecond
|
||||
} //goMin
|
||||
} //goHour
|
||||
} //goDay
|
||||
} //goMonth
|
||||
}
|
||||
// 判断100年内的结果条数
|
||||
if (resultArr.length == 0) {
|
||||
resultList = ['没有达到条件的结果!']
|
||||
} else {
|
||||
resultList = resultArr
|
||||
if (resultArr.length !== 5) {
|
||||
resultList.push('最近100年内只有上面' + resultArr.length + '条结果!')
|
||||
}
|
||||
}
|
||||
// 计算完成-显示结果
|
||||
isShow = true
|
||||
}
|
||||
// 用于计算某位数字在数组中的索引
|
||||
const getIndex = (arr, value) => {
|
||||
if (value <= arr[0] || value > arr[arr.length - 1]) {
|
||||
return 0
|
||||
} else {
|
||||
for (let i = 0; i < arr.length - 1; i++) {
|
||||
if (value > arr[i] && value <= arr[i + 1]) {
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 获取"年"数组
|
||||
const getYearArr = (rule, year) => {
|
||||
dateArr[5] = getOrderArr(year, year + 100)
|
||||
if (rule !== undefined) {
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
dateArr[5] = getCycleArr(rule, year + 100, false)
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
dateArr[5] = getAverageArr(rule, year + 100)
|
||||
} else if (rule !== '*') {
|
||||
dateArr[5] = getAssignArr(rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 获取"月"数组
|
||||
const getMonthArr = (rule) => {
|
||||
dateArr[4] = getOrderArr(1, 12)
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
dateArr[4] = getCycleArr(rule, 12, false)
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
dateArr[4] = getAverageArr(rule, 12)
|
||||
} else if (rule !== '*') {
|
||||
dateArr[4] = getAssignArr(rule)
|
||||
}
|
||||
}
|
||||
// 获取"日"数组-主要为日期规则
|
||||
const getWeekArr = (rule) => {
|
||||
// 只有当日期规则的两个值均为“”时则表达日期是有选项的
|
||||
if (dayRule == '' && dayRuleSup == '') {
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
dayRule = 'weekDay'
|
||||
dayRuleSup = getCycleArr(rule, 7, false)
|
||||
} else if (rule.indexOf('#') >= 0) {
|
||||
dayRule = 'assWeek'
|
||||
let matchRule = rule.match(/[0-9]{1}/g)
|
||||
dayRuleSup = [Number(matchRule[1]), Number(matchRule[0])]
|
||||
dateArr[3] = [1]
|
||||
if (dayRuleSup[1] == 7) {
|
||||
dayRuleSup[1] = 0
|
||||
}
|
||||
} else if (rule.indexOf('L') >= 0) {
|
||||
dayRule = 'lastWeek'
|
||||
dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0])
|
||||
dateArr[3] = [31]
|
||||
if (dayRuleSup == 7) {
|
||||
dayRuleSup = 0
|
||||
}
|
||||
} else if (rule !== '*' && rule !== '?') {
|
||||
dayRule = 'weekDay'
|
||||
dayRuleSup = getAssignArr(rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 获取"日"数组-少量为日期规则
|
||||
const getDayArr = (rule) => {
|
||||
dateArr[3] = getOrderArr(1, 31)
|
||||
dayRule = ''
|
||||
dayRuleSup = ''
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
dateArr[3] = getCycleArr(rule, 31, false)
|
||||
dayRuleSup = 'null'
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
dateArr[3] = getAverageArr(rule, 31)
|
||||
dayRuleSup = 'null'
|
||||
} else if (rule.indexOf('W') >= 0) {
|
||||
dayRule = 'workDay'
|
||||
dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0])
|
||||
dateArr[3] = [dayRuleSup]
|
||||
} else if (rule.indexOf('L') >= 0) {
|
||||
dayRule = 'lastDay'
|
||||
dayRuleSup = 'null'
|
||||
dateArr[3] = [31]
|
||||
} else if (rule !== '*' && rule !== '?') {
|
||||
dateArr[3] = getAssignArr(rule)
|
||||
dayRuleSup = 'null'
|
||||
} else if (rule == '*') {
|
||||
dayRuleSup = 'null'
|
||||
}
|
||||
}
|
||||
// 获取"时"数组
|
||||
const getHourArr = (rule) => {
|
||||
dateArr[2] = getOrderArr(0, 23)
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
dateArr[2] = getCycleArr(rule, 24, true)
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
dateArr[2] = getAverageArr(rule, 23)
|
||||
} else if (rule !== '*') {
|
||||
dateArr[2] = getAssignArr(rule)
|
||||
}
|
||||
}
|
||||
// 获取"分"数组
|
||||
const getMinArr = (rule) => {
|
||||
dateArr[1] = getOrderArr(0, 59)
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
dateArr[1] = getCycleArr(rule, 60, true)
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
dateArr[1] = getAverageArr(rule, 59)
|
||||
} else if (rule !== '*') {
|
||||
dateArr[1] = getAssignArr(rule)
|
||||
}
|
||||
}
|
||||
// 获取"秒"数组
|
||||
const getSecondArr = (rule) => {
|
||||
dateArr[0] = getOrderArr(0, 59)
|
||||
if (rule.indexOf('-') >= 0) {
|
||||
dateArr[0] = getCycleArr(rule, 60, true)
|
||||
} else if (rule.indexOf('/') >= 0) {
|
||||
dateArr[0] = getAverageArr(rule, 59)
|
||||
} else if (rule !== '*') {
|
||||
dateArr[0] = getAssignArr(rule)
|
||||
}
|
||||
}
|
||||
// 根据传进来的min-max返回一个顺序的数组
|
||||
const getOrderArr = (min, max) => {
|
||||
let arr = []
|
||||
for (let i = min; i <= max; i++) {
|
||||
arr.push(i)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
// 根据规则中指定的零散值返回一个数组
|
||||
const getAssignArr = (rule) => {
|
||||
let arr = []
|
||||
let assiginArr = rule.split(',')
|
||||
for (let i = 0; i < assiginArr.length; i++) {
|
||||
arr[i] = Number(assiginArr[i])
|
||||
}
|
||||
arr.sort(compare)
|
||||
return arr
|
||||
}
|
||||
// 根据一定算术规则计算返回一个数组
|
||||
const getAverageArr = (rule, limit) => {
|
||||
let arr = []
|
||||
let agArr = rule.split('/')
|
||||
let min = Number(agArr[0])
|
||||
let step = Number(agArr[1])
|
||||
while (min <= limit) {
|
||||
arr.push(min)
|
||||
min += step
|
||||
}
|
||||
return arr
|
||||
}
|
||||
// 根据规则返回一个具有周期性的数组
|
||||
const getCycleArr = (rule, limit, status) => {
|
||||
// status--表示是否从0开始(则从1开始)
|
||||
let arr = []
|
||||
let cycleArr = rule.split('-')
|
||||
let min = Number(cycleArr[0])
|
||||
let max = Number(cycleArr[1])
|
||||
if (min > max) {
|
||||
max += limit
|
||||
}
|
||||
for (let i = min; i <= max; i++) {
|
||||
let add = 0
|
||||
if (status == false && i % limit == 0) {
|
||||
add = limit
|
||||
}
|
||||
arr.push(Math.round((i % limit) + add))
|
||||
}
|
||||
arr.sort(compare)
|
||||
return arr
|
||||
}
|
||||
// 比较数字大小(用于Array.sort)
|
||||
const compare = (value1, value2) => {
|
||||
if (value2 - value1 > 0) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
// 格式化日期格式如:2017-9-19 18:04:33
|
||||
const formatDate = (value, type) => {
|
||||
// 计算日期相关值
|
||||
let time = typeof value == 'number' ? new Date(value) : value
|
||||
let Y = time.getFullYear()
|
||||
let M = time.getMonth() + 1
|
||||
let D = time.getDate()
|
||||
let h = time.getHours()
|
||||
let m = time.getMinutes()
|
||||
let s = time.getSeconds()
|
||||
let week = time.getDay()
|
||||
// 如果传递了type的话
|
||||
if (type == undefined) {
|
||||
return (
|
||||
Y +
|
||||
'-' +
|
||||
(M < 10 ? '0' + M : M) +
|
||||
'-' +
|
||||
(D < 10 ? '0' + D : D) +
|
||||
' ' +
|
||||
(h < 10 ? '0' + h : h) +
|
||||
':' +
|
||||
(m < 10 ? '0' + m : m) +
|
||||
':' +
|
||||
(s < 10 ? '0' + s : s)
|
||||
)
|
||||
} else if (type == 'week') {
|
||||
// 在quartz中 1为星期日
|
||||
return week + 1
|
||||
}
|
||||
}
|
||||
// 检查日期是否存在
|
||||
const checkDate = (value) => {
|
||||
let time = new Date(value)
|
||||
let format = formatDate(time)
|
||||
return value === format
|
||||
}
|
||||
|
||||
// 执行
|
||||
expressionChange(props.expression)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul class="text-center">
|
||||
<li v-for="(item, index) in resultList" :key="index" class="leading-9"> {{ item }}</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
@ -174,7 +174,7 @@ export const schema = reactive<FormSchema[]>([
|
||||
style: {
|
||||
width: '100%'
|
||||
},
|
||||
placeholder: 'cron 表达式,六位或七位,分别表示秒、分钟、小时、天、月、星期几、年'
|
||||
placeholder: 'cron 表达式,六位或七位,分别表示秒、分钟、小时、天、月、星期几、年(可选)'
|
||||
},
|
||||
ifshow: (values) => values.exec_strategy === 'cron'
|
||||
},
|
||||
|
@ -30,6 +30,7 @@ import { Dialog } from '@/components/Dialog'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { useRouter } from 'vue-router'
|
||||
import Write from './components/Write.vue'
|
||||
import CronExpression from './components/CronExpression.vue'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const { t } = useI18n()
|
||||
@ -67,6 +68,7 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
const cronDialogVisible = ref(false)
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('')
|
||||
const loading = ref(false)
|
||||
@ -98,7 +100,6 @@ getOptions()
|
||||
// 跳转到调度日志页面
|
||||
const toRecord = (row: any) => {
|
||||
if (row) {
|
||||
console.log(row)
|
||||
push(`/system/record/task?job_id=${row._id}`)
|
||||
} else {
|
||||
push(`/system/record/task`)
|
||||
@ -205,7 +206,7 @@ const save = async () => {
|
||||
|
||||
// 生成 cron 表达式
|
||||
const generateCronExpression = () => {
|
||||
ElMessage.info('下一个版本更新')
|
||||
cronDialogVisible.value = true
|
||||
}
|
||||
|
||||
getList()
|
||||
@ -225,7 +226,7 @@ getList()
|
||||
<ElCol :span="1.5">
|
||||
<ElButton type="primary" @click="addAction">添加定时任务</ElButton>
|
||||
<ElButton type="primary" @click="toRecord(null)">调度日志</ElButton>
|
||||
<ElButton type="primary" @click="generateCronExpression">生成 Cron 表达式</ElButton>
|
||||
<ElButton type="primary" @click="generateCronExpression">快速生成 Cron 表达式</ElButton>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<RightToolbar
|
||||
@ -285,5 +286,9 @@ getList()
|
||||
<ElButton @click="dialogVisible = false">{{ t('dialogDemo.close') }}</ElButton>
|
||||
</template>
|
||||
</Dialog>
|
||||
|
||||
<Dialog v-model="cronDialogVisible" title="快速生成 Cron 表达式" width="920px" height="680px">
|
||||
<CronExpression />
|
||||
</Dialog>
|
||||
</ContentWrap>
|
||||
</template>
|
||||
|
@ -113,6 +113,8 @@ class ScheduledTask:
|
||||
logger.info(content)
|
||||
print(content)
|
||||
getattr(self, operation)(**task)
|
||||
else:
|
||||
print("意外", message)
|
||||
|
||||
def start_mongo(self) -> None:
|
||||
"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user