Vue3项目-生成Cron表达式组件
最近做的一个vue3项目过程中,需要用到cron表达式功能,而对于普通业务人员,他们是不懂cron表达式规则的,所以需要做一个可手动配置生成cron表达式的功能。从网上查找了一些相关资料,然后结合vue3+Element Plus,改造成适合自己项目的组件。记录代码如下:
实现功能:
1、在下拉框里手动选择后生成cron表达式
2、根据cron表达式,各个下拉框最选中的回显
3、根据cron表达式,打印表达式会在最近5次的执行时间
1、components目录下新建 vue3Cron/Index.vue
src/components/vue3Cron/Index.vue
<template> <div class="v3c"> <ul class="v3c-tab"> <li class="v3c-tab-item" style="display:none;" :class="{ 'v3c-active': tabActive == 1 }" @click="onHandleTab(1)">秒 </li> <li class="v3c-tab-item" :class="{ 'v3c-active': tabActive == 2 }" @click="onHandleTab(2)">分</li> <li class="v3c-tab-item" :class="{ 'v3c-active': tabActive == 3 }" @click="onHandleTab(3)">时</li> <li class="v3c-tab-item" :class="{ 'v3c-active': tabActive == 4 }" @click="onHandleTab(4)">天</li> <li class="v3c-tab-item" :class="{ 'v3c-active': tabActive == 5 }" @click="onHandleTab(5)">月</li> <!-- <li class="v3c-tab-item" :class="{ 'v3c-active': tabActive == 6 }" @click="onHandleTab(6)">年</li> --> </ul> <!-- 秒 --> <div class="v3c-content" v-show="tabActive == 1"> <!-- 每一秒 --> <div> <el-radio label="1" v-model="state.second.cronEvery">每一秒钟</el-radio> </div> <!-- 每隔多久 --> <div class="mt-15"> <el-radio label="2" v-model="state.second.cronEvery">每隔</el-radio> <el-input-number v-model="state.second.incrementIncrement" :min="1" :max="60" controls-position="right" /> <span class="ml-5 mr-5">秒执行, 从</span> <el-input-number v-model="state.second.incrementStart" :min="0" :max="59" controls-position="right" /> <span>秒开始</span> </div> <!-- 具体秒数 --> <div class="mt-15"> <el-radio label="3" v-model="state.second.cronEvery">具体秒数(可多选)</el-radio> <el-select v-model="state.second.specificSpecific" multiple clearable style="width: 140px"> <el-option v-for="(item, index) in 60" :key="index" :label="index" :value="index" /> </el-select> </div> <!-- 周期从 --> <div class="mt-15"> <el-radio label="4" v-model="state.second.cronEvery">周期从</el-radio> <el-input-number v-model="state.second.rangeStart" :min="0" :max="59" controls-position="right" /> <sapn>秒</sapn><span class="ml-10 mr-5">到</span> <el-input-number v-model="state.second.rangeEnd" :min="0" :max="59" controls-position="right" /> <sapn>秒</sapn> </div> </div> <!-- 分钟 --> <div class="v3c-content" v-show="tabActive == 2"> <!-- 每一分钟 --> <div> <el-radio label="1" v-model="state.minute.cronEvery">每一分钟</el-radio> </div> <!-- 每隔多久 --> <div class="mt-15"> <el-radio label="2" v-model="state.minute.cronEvery">每隔</el-radio> <el-input-number v-model="state.minute.incrementIncrement" :min="1" :max="60" controls-position="right" /> <span class="ml-5 mr-5">分执行,从</span> <el-input-number v-model="state.minute.incrementStart" :min="0" :max="59" controls-position="right" /> <span>分开始</span> </div> <!-- 具体分钟数 --> <div class="mt-15"> <el-radio label="3" v-model="state.minute.cronEvery">具体分钟数(可多选)</el-radio> <el-select v-model="state.minute.specificSpecific" multiple clearable style="width: 140px"> <el-option v-for="(item, index) in 60" :key="index" :label="index" :value="index" /> </el-select> </div> <!-- 周期从 --> <div class="mt-15"> <el-radio label="4" v-model="state.minute.cronEvery">周期从</el-radio> <el-input-number v-model="state.minute.rangeStart" :min="0" :max="59" controls-position="right" /> <span>分</span><span class="ml-10 mr-5">到</span> <el-input-number v-model="state.minute.rangeEnd" :min="0" :max="59" controls-position="right" /> <span>分</span> </div> </div> <!-- 小时 --> <div class="v3c-content" v-show="tabActive == 3"> <!-- 每一小时 --> <div> <el-radio label="1" v-model="state.hour.cronEvery">每一小时</el-radio> </div> <!-- 每隔多久 --> <div class="mt-15"> <el-radio label="2" v-model="state.hour.cronEvery">每隔</el-radio> <el-input-number v-model="state.hour.incrementIncrement" :min="1" :max="24" controls-position="right" /> <span class="ml-5 mr-5">小时执行,从</span> <el-input-number v-model="state.hour.incrementStart" :min="0" :max="23" controls-position="right" /> <span>小时开始</span> </div> <!-- 具体小时数 --> <div class="mt-15"> <el-radio label="3" v-model="state.hour.cronEvery">具体小时数(可多选)</el-radio> <el-select v-model="state.hour.specificSpecific" multiple clearable style="width: 140px"> <el-option v-for="(item, index) in 24" :key="index" :label="index" :value="index" /> </el-select> </div> <!-- 周期从 --> <div class="mt-15"> <el-radio label="4" v-model="state.hour.cronEvery">周期从</el-radio> <el-input-number v-model="state.hour.rangeStart" :min="0" :max="23" controls-position="right" /> <span>时</span><span class="ml-10 mr-5">到</span> <el-input-number v-model="state.hour.rangeEnd" :min="0" :max="23" controls-position="right" /> <span>时</span> </div> </div> <!-- 天 --> <div class="v3c-content" v-show="tabActive == 4"> <!-- 1 --> <div> <el-radio label="1" v-model="state.day.cronEvery">每一天</el-radio> </div> <!-- 2 --> <div class="mt-15"> <el-radio label="2" v-model="state.day.cronEvery">每隔</el-radio> <el-input-number v-model="state.week.incrementIncrement" :min="1" :max="60" controls-position="right" /> <span class="ml-5 mr-5">周执行,从</span> <el-input-number v-model="state.week.incrementStart" :min="1" :max="52" controls-position="right" /> <span>周开始</span> </div> <!-- 3 --> <div class="mt-15"> <el-radio label="3" v-model="state.day.cronEvery">每隔</el-radio> <el-input-number v-model="state.day.incrementIncrement" :min="1" :max="30" controls-position="right" /> <span class="ml-5 mr-5">天执行,从</span> <el-input-number v-model="state.day.incrementStart" :min="1" :max="30" controls-position="right" /> <span>天开始</span> </div> <!-- 4 --> <div class="mt-15"> <el-radio label="4" v-model="state.day.cronEvery">具体星期几(可多选)</el-radio> <el-select v-model="state.week.specificSpecific" multiple clearable style="width: 140px"> <el-option v-for="(item, index) in weekList" :key="index" :label="item.name" :value="item.value" /> </el-select> </div> <!-- 5 --> <div class="mt-15"> <el-radio label="5" v-model="state.day.cronEvery">具体天数(可多选)</el-radio> <el-select v-model="state.day.specificSpecific" multiple clearable style="width: 140px"> <el-option v-for="(item, index) in 31" :key="index" :label="item" :value="item" /> </el-select> </div> <!-- 6 --> <!-- <div class="mt-15"> <el-radio label="6" v-model="state.day.cronEvery">在这个月的最后一天</el-radio> </div> --> <!-- 7 --> <!-- <div class="mt-15"> <el-radio label="7" v-model="state.day.cronEvery">在这个月的最后一个工作日</el-radio> </div> --> <!-- 8 --> <!-- <div class="mt-15"> <el-radio label="8" v-model="state.day.cronEvery">在这个月的最后一个</el-radio> <el-select v-model="state.day.cronLastSpecificDomDay" style="width: 140px"> <el-option v-for="(item, index) in weekList" :key="index" :label="item.name" :value="item.val" /> </el-select> </div> --> <!-- 9 --> <!-- <div class="mt-15"> <el-radio label="9" v-model="state.day.cronEvery">{{ }}</el-radio> <el-input-number v-model="state.day.cronDaysBeforeEomMinus" :min="1" :max="31" controls-position="right" /> <span>在本月底前</span> </div> --> <!-- 10 --> <!-- <div class="mt-15"> <el-radio label="10" v-model="state.day.cronEvery">最近的工作日(周一至周五)至本月</el-radio> <el-input-number v-model="state.day.cronDaysNearestWeekday" :min="1" :max="31" controls-position="right" /> <span>日</span> </div> --> <!-- 11 --> <!-- <div class="mt-15"> <el-radio label="11" v-model="state.day.cronEvery">在这个月的第</el-radio> <el-input-number v-model="state.week.cronNthDayNth" :min="1" :max="5" controls-position="right" /> <span>个</span> <el-select v-model="state.week.cronNthDayDay" style="width: 140px"> <el-option v-for="(item, index) in weekList" :key="index" :label="item.name" :value="item.val" /> </el-select> </div> --> </div> <!-- 月 --> <div class="v3c-content" v-show="tabActive == 5"> <!-- 1 --> <div> <el-radio label="1" v-model="state.month.cronEvery">每一月</el-radio> </div> <!-- 2 --> <div class="mt-15"> <el-radio label="2" v-model="state.month.cronEvery">每隔</el-radio> <el-input-number v-model="state.month.incrementIncrement" :min="1" :max="12" controls-position="right" /> <span class="ml-5 mr-5">月执行,从</span> <el-input-number v-model="state.month.incrementStart" :min="1" :max="12" controls-position="right" /> <span>月开始</span> </div> <!-- 3 --> <div class="mt-15"> <el-radio label="3" v-model="state.month.cronEvery">具体月数(可多选)</el-radio> <el-select multiple clearable v-model="state.month.specificSpecific" style="width: 140px"> <el-option v-for="(item, index) in 12" :key="index" :label="item" :value="item" /> </el-select> </div> <!-- 4 --> <div class="mt-15"> <el-radio label="4" v-model="state.month.cronEvery">周期从</el-radio> <el-input-number v-model="state.month.rangeStart" :min="1" :max="12" controls-position="right" /> <span>月</span><span class="ml-10 mr-5">到</span> <el-input-number v-model="state.month.rangeEnd" :min="1" :max="12" controls-position="right" /> <span>月</span> </div> </div> <!-- 年 --> <div class="v3c-content" v-show="tabActive == 6"> <!-- 1 --> <div> <el-radio label="1" v-model="state.year.cronEvery">每一年</el-radio> </div> <!-- 2 --> <div class="mt-15"> <el-radio label="2" v-model="state.year.cronEvery">每隔</el-radio> <el-input-number v-model="state.year.incrementIncrement" :min="1" :max="99" controls-position="right" /> <span class="ml-5 mr-5">年执行,从</span> <el-input-number v-model="state.year.incrementStart" :min="currYear" :max="currYear + 10" controls-position="right" style="width:100px;" /> <span>年开始</span> </div> <!-- 3 --> <div class="mt-15"> <el-radio label="3" v-model="state.year.cronEvery">具体年份(可多选)</el-radio> <el-select multiple clearable v-model="state.year.specificSpecific" style="width: 140px"> <el-option v-for="(item, index) in 100" :key="index" :label="currYear + item" :value="currYear + item" /> </el-select> </div> <!-- 4 --> <div class="mt-15"> <el-radio label="4" v-model="state.year.cronEvery">周期从</el-radio> <el-input-number v-model="state.year.rangeStart" :min="currYear" :max="currYear + 10" controls-position="right" style="width:100px;" /> <span>年</span><span class="ml-10 mr-5">到</span> <el-input-number v-model="state.year.rangeEnd" :min="currYear" :max="currYear + 10" controls-position="right" style="width:100px;" /> <span>年</span> </div> </div> <!-- 结果 --> <!-- <div class="v3c-footer"> <div style="flex: 1"> CRON : <span class="cron">{{ state.cron }}</span> <button class="btn-ok" @click.stop="handleChange">生成cron</button> </div> </div> --> </div> </template> <script setup> import { reactive, computed, onMounted, ref, watch } from "vue"; //定义子组件需要接收的值 const props = defineProps({ maxHeight: { type: String }, value: { type: String }, defaultCron: { type: String }, }); // 注册事件 const emits = defineEmits(["change", "onShowError"]); onMounted(() => {
// 根据表达式做下拉框的选中回显 console.log('-=-==-', props.value) let arr = props.value.split(' '); console.log(arr) let minT = arr[1]; // 分 if (minT == '*') { state.minute.cronEvery = '1'; } else if (minT.indexOf('/') > -1) { state.minute.cronEvery = '2'; state.minute.incrementStart = minT.split('/')[0] - 0; state.minute.incrementIncrement = minT.split('/')[1] - 0; } else if (minT.indexOf('-') > -1) { state.minute.cronEvery = '4'; state.minute.rangeStart = minT.split('-')[0] - 0; state.minute.rangeEnd = minT.split('-')[1] - 0; } else { state.minute.cronEvery = '3'; state.minute.specificSpecific = minT.split(',').map(item => item - 0); } let hourT = arr[2]; // 时 if (hourT == '*') { state.hour.cronEvery = '1'; } else if (hourT.indexOf('/') > -1) { state.hour.cronEvery = '2'; state.hour.incrementStart = hourT.split('/')[0] - 0; state.hour.incrementIncrement = hourT.split('/')[1] - 0; } else if (hourT.indexOf('-') > -1) { state.hour.cronEvery = '4'; state.hour.rangeStart = hourT.split('-')[0] - 0; state.hour.rangeEnd = hourT.split('-')[1] - 0; } else { state.hour.cronEvery = '3'; state.hour.specificSpecific = hourT.split(',').map(item => item - 0); } let dayT = arr[3]; // 天 if (dayT == '*') { state.day.cronEvery = '1'; } else if (dayT == '?') { // state.day.cronEvery 为2或4 let text = arr[5]; if (text.indexOf('/') > -1) { // state.day.cronEvery 为2 state.day.cronEvery = '2'; state.week.incrementStart = text.split('/')[0] - 0; state.week.incrementIncrement = text.split('/')[1] - 0; } else { state.day.cronEvery = '4'; state.week.specificSpecific = text.split(','); } } else if (dayT.indexOf('/') > -1) { state.day.cronEvery = '3'; state.day.incrementStart = dayT.split('/')[0] - 0; state.day.incrementIncrement = dayT.split('/')[1] - 0; } else { state.day.cronEvery = '5'; state.day.specificSpecific = dayT.split(',').map(item => item - 0); } let monthT = arr[4]; // 月 if (monthT == '*') { state.month.cronEvery = '1'; } else if (monthT.indexOf('/') > -1) { state.month.cronEvery = '2'; state.month.incrementStart = monthT.split('/')[0] - 0; state.month.incrementIncrement = monthT.split('/')[1] - 0; } else if (monthT.indexOf('-') > -1) { state.month.cronEvery = '4'; state.month.rangeStart = monthT.split('-')[0] - 0; state.month.rangeEnd = monthT.split('-')[1] - 0; } else { state.month.cronEvery = '3'; state.month.specificSpecific = monthT.split(',').map(item => item - 0); } }) const weekList = ref([ { name: '星期日', value: 'SUN', val: 1, }, { name: '星期一', value: 'MON', val: 2, }, { name: '星期二', value: 'TUE', val: 3, }, { name: '星期三', value: 'WED', val: 4, }, { name: '星期四', value: 'THU', val: 5, }, { name: '星期五', value: 'FRI', val: 6, }, { name: '星期六', value: 'SAT', val: 7, }, ]) const tabActive = ref(2); const currYear = ref(new Date().getFullYear()); const onHandleTab = (index) => { tabActive.value = index; }; let errArr = ['', '', '', '']; const state = reactive({ second: { cronEvery: "3", incrementStart: 0, incrementIncrement: 1, rangeStart: 0, rangeEnd: 0, specificSpecific: [0], }, minute: { cronEvery: "1", incrementStart: 0, incrementIncrement: 1, rangeStart: 0, rangeEnd: 0, specificSpecific: [], }, hour: { cronEvery: "1", incrementStart: 1, incrementIncrement: 1, rangeStart: 0, rangeEnd: 0, specificSpecific: [], }, day: { cronEvery: "1", incrementStart: 1, incrementIncrement: 1, rangeStart: 0, rangeEnd: 0, specificSpecific: [], cronLastSpecificDomDay: 1, cronDaysBeforeEomMinus: 0, cronDaysNearestWeekday: 1, }, week: { cronEvery: "1", incrementStart: 1, incrementIncrement: 1, specificSpecific: [], cronNthDayDay: 1, cronNthDayNth: 1, }, month: { cronEvery: "1", incrementStart: 1, incrementIncrement: 1, rangeStart: 1, rangeEnd: 1, specificSpecific: [], }, year: { cronEvery: "1", incrementStart: new Date().getFullYear(), incrementIncrement: 1, rangeStart: new Date().getFullYear(), rangeEnd: new Date().getFullYear(), specificSpecific: [], }, output: { second: "", minute: "", hour: "", day: "", month: "", Week: "", year: "", }, secondsText: computed(() => { let seconds = ""; let cronEvery = state.second.cronEvery; switch (cronEvery?.toString()) { case "1": seconds = "*"; break; case "2": seconds = state.second.incrementStart + "/" + state.second.incrementIncrement; break; case "3": state.second.specificSpecific.map((val) => { seconds += val + ","; }); seconds = seconds.slice(0, -1); break; case "4": seconds = state.second.rangeStart + "-" + state.second.rangeEnd; break; } return seconds; }), minutesText: computed(() => { console.log('bbb') let minutes = ""; let cronEvery = state.minute.cronEvery; switch (cronEvery?.toString()) { case "1": minutes = "*"; break; case "2": minutes = state.minute.incrementStart + "/" + state.minute.incrementIncrement; break; case "3": state.minute.specificSpecific.map((val) => { minutes += val + ","; }); minutes = minutes.slice(0, -1); break; case "4": minutes = state.minute.rangeStart + "-" + state.minute.rangeEnd; break; } return minutes; }), hoursText: computed(() => { let hours = ""; let cronEvery = state.hour.cronEvery; switch (cronEvery?.toString()) { case "1": hours = "*"; break; case "2": hours = state.hour.incrementStart + "/" + state.hour.incrementIncrement; break; case "3": state.hour.specificSpecific.map((val) => { hours += val + ","; }); hours = hours.slice(0, -1); break; case "4": hours = state.hour.rangeStart + "-" + state.hour.rangeEnd; break; } return hours; }), daysText: computed(() => { let days = ""; let cronEvery = state.day.cronEvery; switch (cronEvery?.toString()) { case "1": break; case "2": case "4": case "11": days = "?"; break; case "3": days = state.day.incrementStart + "/" + state.day.incrementIncrement; break; case "5": state.day.specificSpecific.map((val) => { days += val + ","; }); days = days.slice(0, -1); break; case "6": days = "L"; break; case "7": days = "LW"; break; case "8": days = state.day.cronLastSpecificDomDay + "L"; break; case "9": days = "L-" + state.day.cronDaysBeforeEomMinus; break; case "10": days = state.day.cronDaysNearestWeekday + "W"; break; } return days; }), weeksText: computed(() => { let weeks = ""; let cronEvery = state.day.cronEvery; switch (cronEvery?.toString()) { case "1": case "3": case "5": weeks = "?"; break; case "2": weeks = state.week.incrementStart + "/" + state.week.incrementIncrement; break; case "4": state.week.specificSpecific.map((val) => { weeks += val + ","; }); weeks = weeks.slice(0, -1); break; case "6": case "7": case "8": case "9": case "10": weeks = "?"; break; case "11": weeks = state.week.cronNthDayDay + "#" + state.week.cronNthDayNth; break; } return weeks; }), monthsText: computed(() => { let months = ""; let cronEvery = state.month.cronEvery; switch (cronEvery?.toString()) { case "1": months = "*"; break; case "2": months = state.month.incrementStart + "/" + state.month.incrementIncrement; break; case "3": state.month.specificSpecific.map((val) => { months += val + ","; }); months = months.slice(0, -1); break; case "4": months = state.month.rangeStart + "-" + state.month.rangeEnd; break; } return months; }), yearsText: computed(() => { let years = ""; // TODO,目前先不指定年份,注释以下代码 let cronEvery = state.year.cronEvery; switch (cronEvery?.toString()) { case "1": years = "*"; break; case "2": years = state.year.incrementStart + "/" + state.year.incrementIncrement; break; case "3": state.year.specificSpecific.map((val) => { years += val + ","; }); years = years.slice(0, -1); break; case "4": years = state.year.rangeStart + "-" + state.year.rangeEnd; break; } return years; }), cron: computed(() => { // TODO,目前不指定年份,取消掉${state.yearsText} // const cronText = `${state.secondsText || "*"} ${state.minutesText || "*"} ${state.hoursText || "*"} ${state.daysText || "*"} ${state.monthsText || "*"} ${state.weeksText || "?"} ${state.yearsText || "*"}`; const cronText = `${state.secondsText || "*"} ${state.minutesText || "*"} ${state.hoursText || "*"} ${state.daysText || "*"} ${state.monthsText || "*"} ${state.weeksText || "?"}`; // console.log('----', cronText,[state.minute.cronEvery, state.hour.cronEvery, state.day.cronEvery, state.month.cronEvery]) const cronArr = cronText.split(' '); console.log('表达式:', cronText, cronArr) if (state.minute.cronEvery == '3' && cronArr[1] == '*') { //选择的是具体分钟数,下拉框却没选择数值 errArr[0] = '勾选具体分钟数(可多选)时,请在下拉框中选择值'; } else { errArr[0] = ''; } if (state.hour.cronEvery == '3' && cronArr[2] == '*') { //选择的是具体小时数,下拉框却没选择数值 errArr[1] = '勾选具体小时数(可多选)时,请在下拉框中选择值'; } else { errArr[1] = ''; } if (state.day.cronEvery == '4' && cronArr[5] == '?') { //选择的是具体星期几,下拉框却没选择数值 errArr[2] = '勾选具体星期几(可多选)时,请在下拉框中选择值'; } else if (state.day.cronEvery == '5' && cronArr[3] == '*') { //选择的是具体天数,下拉框却没选择数值 errArr[2] = '勾选具体天数(可多选)时,请在下拉框中选择值'; } else { errArr[2] = ''; } if (state.month.cronEvery == '3' && cronArr[4] == '*') { //选择的是具体月数,下拉框却没选择数值 errArr[3] = '勾选具体月数(可多选)时,请在下拉框中选择值'; } else { errArr[3] = ''; } emits("onShowError", errArr); return cronText; }), }); const handleChange = () => { if (typeof state.cron !== "string") return false; emits("change", state.cron, [state.min.cronEvery, state.hour.cronEvery, state.day.cronEvery, state.month.cronEvery]); }; const rest = (data) => { for (let i in data) { if (data[i] instanceof Object) { this.rest(data[i]); } else { switch (typeof data[i]) { case "object": data[i] = []; break; case "string": data[i] = ""; break; } } } }; watch( () => state.cron, (value) => { if (typeof state.cron !== "string") return; emits("update:value", value); } ); </script> <style lang="css" scoped> :deep(.el-input-number) { width: 80px; margin-right: 5px; } :deep(.el-radio) { margin-right: 10px; } .v3c { width: auto; border: 1px solid #f5f7fa; } .v3c-tab { padding: 0; list-style: none; margin: 0; background-color: #f5f7fa; display: flex; } .v3c-tab-item { flex: 1; text-align: center; cursor: pointer; padding: 6px; } .v3c-tab-item.v3c-active { background-color: #409eff; color: #ffffff; } .v3c-lang-btn { background-color: #61ddaa; color: #ffffff; /* border-radius: 10px; */ } .v3c-content { padding: 20px; max-height: v-bind(maxHeight); overflow: hidden; overflow-y: auto; } .p-20 { padding: 20px; } .v3c-footer { background-color: #f5f7fa; padding-top: 10px; padding-bottom: 10px; display: flex; text-align: center; } .v3c input[type="text"] { width: 80px; } .v3c input[type="number"] { width: 80px; height: 28px; border: 1px solid #d9d9d9; } .v3c select { width: 80px; height: 32px; border: 1px solid #d9d9d9; } .v3c select[multiple] { width: 80px; height: 100px; border: 1px solid #d9d9d9; } .btn-ok { line-height: 1.5715; position: relative; display: inline-block; font-weight: 400; white-space: nowrap; text-align: center; background-image: none; border: 1px solid transparent; box-shadow: 0 2px #00000004; cursor: pointer; transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; touch-action: manipulation; height: 32px; padding: 4px 15px; font-size: 14px; border-radius: 2px; color: #fff; background: #409eff; border-color: #409eff; text-shadow: 0 -1px 0 rgb(0 0 0 / 12%); box-shadow: 0 2px #0000000b; } .btn-close { line-height: 1.5715; position: relative; display: inline-block; font-weight: 400; white-space: nowrap; text-align: center; background-image: none; border: 1px solid transparent; box-shadow: 0 2px #00000004; cursor: pointer; transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; touch-action: manipulation; height: 32px; padding: 4px 15px; font-size: 14px; border-radius: 2px; color: #fff; background: #61ddaa; border-color: #61ddaa; text-shadow: 0 -1px 0 rgb(0 0 0 / 12%); box-shadow: 0 2px #0000000b; } .cron { background-color: #61ddaa; padding: 5px; padding-left: 10px; padding-right: 10px; color: #ffffff; } </style>
2、根据cron表达式获取最近5次的执行时间
由于需要根据cron表达式获取最近5次执行时间,所以从网上找到了别人写的一个插件,我没有做改造,首先下载了这个插件(later.min.js)后,然后把它放置到项目里,最后在项目根目录的index.html使用script标签引入该js文件
later.min.js:
var later = function() { "use strict"; var e = { version: "1.2.0" }; return Array.prototype.indexOf || (Array.prototype.indexOf = function(e) { if (null == this) throw new TypeError; var t = Object(this) , n = t.length >>> 0; if (0 === n) return -1; var r = 0; if (arguments.length > 1 && (r = Number(arguments[1]), r != r ? r = 0 : 0 != r && r != 1 / 0 && r != -(1 / 0) && (r = (r > 0 || -1) * Math.floor(Math.abs(r)))), r >= n) return -1; for (var a = r >= 0 ? r : Math.max(n - Math.abs(r), 0); n > a; a++) if (a in t && t[a] === e) return a; return -1 } ), String.prototype.trim || (String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, "") } ), e.array = {}, e.array.sort = function(e, t) { e.sort(function(e, t) { return +e - +t }), t && 0 === e[0] && e.push(e.shift()) } , e.array.next = function(e, t, n) { for (var r, a = 0 !== n[0], i = 0, u = t.length - 1; u > -1; --u) { if (r = t[u], r === e) return r; if (!(r > e || 0 === r && a && n[1] > e)) break; i = u } return t[i] } , e.array.nextInvalid = function(e, t, n) { for (var r = n[0], a = n[1], i = t.length, u = 0 === t[i - 1] && 0 !== r ? a : 0, o = e, f = t.indexOf(e), d = o; o === (t[f] || u); ) if (o++, o > a && (o = r), f++, f === i && (f = 0), o === d) return; return o } , e.array.prev = function(e, t, n) { for (var r, a = t.length, i = 0 !== n[0], u = a - 1, o = 0; a > o; o++) { if (r = t[o], r === e) return r; if (!(e > r || 0 === r && i && n[1] < e)) break; u = o } return t[u] } , e.array.prevInvalid = function(e, t, n) { for (var r = n[0], a = n[1], i = t.length, u = 0 === t[i - 1] && 0 !== r ? a : 0, o = e, f = t.indexOf(e), d = o; o === (t[f] || u); ) if (o--, r > o && (o = a), f--, -1 === f && (f = i - 1), o === d) return; return o } , e.day = e.D = { name: "day", range: 86400, val: function(t) { return t.D || (t.D = e.date.getDate.call(t)) }, isValid: function(t, n) { return e.D.val(t) === (n || e.D.extent(t)[1]) }, extent: function(t) { if (t.DExtent) return t.DExtent; var n = e.M.val(t) , r = e.DAYS_IN_MONTH[n - 1]; return 2 === n && 366 === e.dy.extent(t)[1] && (r += 1), t.DExtent = [1, r] }, start: function(t) { return t.DStart || (t.DStart = e.date.next(e.Y.val(t), e.M.val(t), e.D.val(t))) }, end: function(t) { return t.DEnd || (t.DEnd = e.date.prev(e.Y.val(t), e.M.val(t), e.D.val(t))) }, next: function(t, n) { n = n > e.D.extent(t)[1] ? 1 : n; var r = e.date.nextRollover(t, n, e.D, e.M) , a = e.D.extent(r)[1]; return n = n > a ? 1 : n || a, e.date.next(e.Y.val(r), e.M.val(r), n) }, prev: function(t, n) { var r = e.date.prevRollover(t, n, e.D, e.M) , a = e.D.extent(r)[1]; return e.date.prev(e.Y.val(r), e.M.val(r), n > a ? a : n || a) } }, e.dayOfWeekCount = e.dc = { name: "day of week count", range: 604800, val: function(t) { return t.dc || (t.dc = Math.floor((e.D.val(t) - 1) / 7) + 1) }, isValid: function(t, n) { return e.dc.val(t) === n || 0 === n && e.D.val(t) > e.D.extent(t)[1] - 7 }, extent: function(t) { return t.dcExtent || (t.dcExtent = [1, Math.ceil(e.D.extent(t)[1] / 7)]) }, start: function(t) { return t.dcStart || (t.dcStart = e.date.next(e.Y.val(t), e.M.val(t), Math.max(1, 7 * (e.dc.val(t) - 1) + 1 || 1))) }, end: function(t) { return t.dcEnd || (t.dcEnd = e.date.prev(e.Y.val(t), e.M.val(t), Math.min(7 * e.dc.val(t), e.D.extent(t)[1]))) }, next: function(t, n) { n = n > e.dc.extent(t)[1] ? 1 : n; var r = e.date.nextRollover(t, n, e.dc, e.M) , a = e.dc.extent(r)[1]; n = n > a ? 1 : n; var i = e.date.next(e.Y.val(r), e.M.val(r), 0 === n ? e.D.extent(r)[1] - 6 : 1 + 7 * (n - 1)); return i.getTime() <= t.getTime() ? (r = e.M.next(t, e.M.val(t) + 1), e.date.next(e.Y.val(r), e.M.val(r), 0 === n ? e.D.extent(r)[1] - 6 : 1 + 7 * (n - 1))) : i }, prev: function(t, n) { var r = e.date.prevRollover(t, n, e.dc, e.M) , a = e.dc.extent(r)[1]; return n = n > a ? a : n || a, e.dc.end(e.date.prev(e.Y.val(r), e.M.val(r), 1 + 7 * (n - 1))) } }, e.dayOfWeek = e.dw = e.d = { name: "day of week", range: 86400, val: function(t) { return t.dw || (t.dw = e.date.getDay.call(t) + 1) }, isValid: function(t, n) { return e.dw.val(t) === (n || 7) }, extent: function() { return [1, 7] }, start: function(t) { return e.D.start(t) }, end: function(t) { return e.D.end(t) }, next: function(t, n) { return n = n > 7 ? 1 : n || 7, e.date.next(e.Y.val(t), e.M.val(t), e.D.val(t) + (n - e.dw.val(t)) + (n <= e.dw.val(t) ? 7 : 0)) }, prev: function(t, n) { return n = n > 7 ? 7 : n || 7, e.date.prev(e.Y.val(t), e.M.val(t), e.D.val(t) + (n - e.dw.val(t)) + (n >= e.dw.val(t) ? -7 : 0)) } }, e.dayOfYear = e.dy = { name: "day of year", range: 86400, val: function(t) { return t.dy || (t.dy = Math.ceil(1 + (e.D.start(t).getTime() - e.Y.start(t).getTime()) / e.DAY)) }, isValid: function(t, n) { return e.dy.val(t) === (n || e.dy.extent(t)[1]) }, extent: function(t) { var n = e.Y.val(t); return t.dyExtent || (t.dyExtent = [1, n % 4 ? 365 : 366]) }, start: function(t) { return e.D.start(t) }, end: function(t) { return e.D.end(t) }, next: function(t, n) { n = n > e.dy.extent(t)[1] ? 1 : n; var r = e.date.nextRollover(t, n, e.dy, e.Y) , a = e.dy.extent(r)[1]; return n = n > a ? 1 : n || a, e.date.next(e.Y.val(r), e.M.val(r), n) }, prev: function(t, n) { var r = e.date.prevRollover(t, n, e.dy, e.Y) , a = e.dy.extent(r)[1]; return n = n > a ? a : n || a, e.date.prev(e.Y.val(r), e.M.val(r), n) } }, e.hour = e.h = { name: "hour", range: 3600, val: function(t) { return t.h || (t.h = e.date.getHour.call(t)) }, isValid: function(t, n) { return e.h.val(t) === n }, extent: function() { return [0, 23] }, start: function(t) { return t.hStart || (t.hStart = e.date.next(e.Y.val(t), e.M.val(t), e.D.val(t), e.h.val(t))) }, end: function(t) { return t.hEnd || (t.hEnd = e.date.prev(e.Y.val(t), e.M.val(t), e.D.val(t), e.h.val(t))) }, next: function(t, n) { n = n > 23 ? 0 : n; var r = e.date.next(e.Y.val(t), e.M.val(t), e.D.val(t) + (n <= e.h.val(t) ? 1 : 0), n); return !e.date.isUTC && r.getTime() <= t.getTime() && (r = e.date.next(e.Y.val(r), e.M.val(r), e.D.val(r), n + 1)), r }, prev: function(t, n) { return n = n > 23 ? 23 : n, e.date.prev(e.Y.val(t), e.M.val(t), e.D.val(t) + (n >= e.h.val(t) ? -1 : 0), n) } }, e.minute = e.m = { name: "minute", range: 60, val: function(t) { return t.m || (t.m = e.date.getMin.call(t)) }, isValid: function(t, n) { return e.m.val(t) === n }, extent: function(e) { return [0, 59] }, start: function(t) { return t.mStart || (t.mStart = e.date.next(e.Y.val(t), e.M.val(t), e.D.val(t), e.h.val(t), e.m.val(t))) }, end: function(t) { return t.mEnd || (t.mEnd = e.date.prev(e.Y.val(t), e.M.val(t), e.D.val(t), e.h.val(t), e.m.val(t))) }, next: function(t, n) { var r = e.m.val(t) , a = e.s.val(t) , i = n > 59 ? 60 - r : r >= n ? 60 - r + n : n - r , u = new Date(t.getTime() + i * e.MIN - a * e.SEC); return !e.date.isUTC && u.getTime() <= t.getTime() && (u = new Date(t.getTime() + (i + 120) * e.MIN - a * e.SEC)), u }, prev: function(t, n) { return n = n > 59 ? 59 : n, e.date.prev(e.Y.val(t), e.M.val(t), e.D.val(t), e.h.val(t) + (n >= e.m.val(t) ? -1 : 0), n) } }, e.month = e.M = { name: "month", range: 2629740, val: function(t) { return t.M || (t.M = e.date.getMonth.call(t) + 1) }, isValid: function(t, n) { return e.M.val(t) === (n || 12) }, extent: function() { return [1, 12] }, start: function(t) { return t.MStart || (t.MStart = e.date.next(e.Y.val(t), e.M.val(t))) }, end: function(t) { return t.MEnd || (t.MEnd = e.date.prev(e.Y.val(t), e.M.val(t))) }, next: function(t, n) { return n = n > 12 ? 1 : n || 12, e.date.next(e.Y.val(t) + (n > e.M.val(t) ? 0 : 1), n) }, prev: function(t, n) { return n = n > 12 ? 12 : n || 12, e.date.prev(e.Y.val(t) - (n >= e.M.val(t) ? 1 : 0), n) } }, e.second = e.s = { name: "second", range: 1, val: function(t) { return t.s || (t.s = e.date.getSec.call(t)) }, isValid: function(t, n) { return e.s.val(t) === n }, extent: function() { return [0, 59] }, start: function(e) { return e }, end: function(e) { return e }, next: function(t, n) { var r = e.s.val(t) , a = n > 59 ? 60 - r : r >= n ? 60 - r + n : n - r , i = new Date(t.getTime() + a * e.SEC); return !e.date.isUTC && i.getTime() <= t.getTime() && (i = new Date(t.getTime() + (a + 7200) * e.SEC)), i }, prev: function(t, n, r) { return n = n > 59 ? 59 : n, e.date.prev(e.Y.val(t), e.M.val(t), e.D.val(t), e.h.val(t), e.m.val(t) + (n >= e.s.val(t) ? -1 : 0), n) } }, e.time = e.t = { name: "time", range: 1, val: function(t) { return t.t || (t.t = 3600 * e.h.val(t) + 60 * e.m.val(t) + e.s.val(t)) }, isValid: function(t, n) { return e.t.val(t) === n }, extent: function() { return [0, 86399] }, start: function(e) { return e }, end: function(e) { return e }, next: function(t, n) { n = n > 86399 ? 0 : n; var r = e.date.next(e.Y.val(t), e.M.val(t), e.D.val(t) + (n <= e.t.val(t) ? 1 : 0), 0, 0, n); return !e.date.isUTC && r.getTime() < t.getTime() && (r = e.date.next(e.Y.val(r), e.M.val(r), e.D.val(r), e.h.val(r), e.m.val(r), n + 7200)), r }, prev: function(t, n) { return n = n > 86399 ? 86399 : n, e.date.next(e.Y.val(t), e.M.val(t), e.D.val(t) + (n >= e.t.val(t) ? -1 : 0), 0, 0, n) } }, e.weekOfMonth = e.wm = { name: "week of month", range: 604800, val: function(t) { return t.wm || (t.wm = (e.D.val(t) + (e.dw.val(e.M.start(t)) - 1) + (7 - e.dw.val(t))) / 7) }, isValid: function(t, n) { return e.wm.val(t) === (n || e.wm.extent(t)[1]) }, extent: function(t) { return t.wmExtent || (t.wmExtent = [1, (e.D.extent(t)[1] + (e.dw.val(e.M.start(t)) - 1) + (7 - e.dw.val(e.M.end(t)))) / 7]) }, start: function(t) { return t.wmStart || (t.wmStart = e.date.next(e.Y.val(t), e.M.val(t), Math.max(e.D.val(t) - e.dw.val(t) + 1, 1))) }, end: function(t) { return t.wmEnd || (t.wmEnd = e.date.prev(e.Y.val(t), e.M.val(t), Math.min(e.D.val(t) + (7 - e.dw.val(t)), e.D.extent(t)[1]))) }, next: function(t, n) { n = n > e.wm.extent(t)[1] ? 1 : n; var r = e.date.nextRollover(t, n, e.wm, e.M) , a = e.wm.extent(r)[1]; return n = n > a ? 1 : n || a, e.date.next(e.Y.val(r), e.M.val(r), Math.max(1, 7 * (n - 1) - (e.dw.val(r) - 2))) }, prev: function(t, n) { var r = e.date.prevRollover(t, n, e.wm, e.M) , a = e.wm.extent(r)[1]; return n = n > a ? a : n || a, e.wm.end(e.date.next(e.Y.val(r), e.M.val(r), Math.max(1, 7 * (n - 1) - (e.dw.val(r) - 2)))) } }, e.weekOfYear = e.wy = { name: "week of year (ISO)", range: 604800, val: function(t) { if (t.wy) return t.wy; var n = e.dw.next(e.wy.start(t), 5) , r = e.dw.next(e.Y.prev(n, e.Y.val(n) - 1), 5); return t.wy = 1 + Math.ceil((n.getTime() - r.getTime()) / e.WEEK) }, isValid: function(t, n) { return e.wy.val(t) === (n || e.wy.extent(t)[1]) }, extent: function(t) { if (t.wyExtent) return t.wyExtent; var n = e.dw.next(e.wy.start(t), 5) , r = e.dw.val(e.Y.start(n)) , a = e.dw.val(e.Y.end(n)); return t.wyExtent = [1, 5 === r || 5 === a ? 53 : 52] }, start: function(t) { return t.wyStart || (t.wyStart = e.date.next(e.Y.val(t), e.M.val(t), e.D.val(t) - (e.dw.val(t) > 1 ? e.dw.val(t) - 2 : 6))) }, end: function(t) { return t.wyEnd || (t.wyEnd = e.date.prev(e.Y.val(t), e.M.val(t), e.D.val(t) + (e.dw.val(t) > 1 ? 8 - e.dw.val(t) : 0))) }, next: function(t, n) { n = n > e.wy.extent(t)[1] ? 1 : n; var r = e.dw.next(e.wy.start(t), 5) , a = e.date.nextRollover(r, n, e.wy, e.Y); 1 !== e.wy.val(a) && (a = e.dw.next(a, 2)); var i = e.wy.extent(a)[1] , u = e.wy.start(a); return n = n > i ? 1 : n || i, e.date.next(e.Y.val(u), e.M.val(u), e.D.val(u) + 7 * (n - 1)) }, prev: function(t, n) { var r = e.dw.next(e.wy.start(t), 5) , a = e.date.prevRollover(r, n, e.wy, e.Y); 1 !== e.wy.val(a) && (a = e.dw.next(a, 2)); var i = e.wy.extent(a)[1] , u = e.wy.end(a); return n = n > i ? i : n || i, e.wy.end(e.date.next(e.Y.val(u), e.M.val(u), e.D.val(u) + 7 * (n - 1))) } }, e.year = e.Y = { name: "year", range: 31556900, val: function(t) { return t.Y || (t.Y = e.date.getYear.call(t)) }, isValid: function(t, n) { return e.Y.val(t) === n }, extent: function() { return [1970, 2099] }, start: function(t) { return t.YStart || (t.YStart = e.date.next(e.Y.val(t))) }, end: function(t) { return t.YEnd || (t.YEnd = e.date.prev(e.Y.val(t))) }, next: function(t, n) { return n > e.Y.val(t) && n <= e.Y.extent()[1] ? e.date.next(n) : e.NEVER }, prev: function(t, n) { return n < e.Y.val(t) && n >= e.Y.extent()[0] ? e.date.prev(n) : e.NEVER } }, e.fullDate = e.fd = { name: "full date", range: 1, val: function(e) { return e.fd || (e.fd = e.getTime()) }, isValid: function(t, n) { return e.fd.val(t) === n }, extent: function() { return [0, 3250368e7] }, start: function(e) { return e }, end: function(e) { return e }, next: function(t, n) { return e.fd.val(t) < n ? new Date(n) : e.NEVER }, prev: function(t, n) { return e.fd.val(t) > n ? new Date(n) : e.NEVER } }, e.modifier = {}, e.modifier.after = e.modifier.a = function(e, t) { var n = t[0]; return { name: "after " + e.name, range: (e.extent(new Date)[1] - n) * e.range, val: e.val, isValid: function(e, t) { return this.val(e) >= n }, extent: e.extent, start: e.start, end: e.end, next: function(t, r) { return r != n && (r = e.extent(t)[0]), e.next(t, r) }, prev: function(t, r) { return r = r === n ? e.extent(t)[1] : n - 1, e.prev(t, r) } } } , e.modifier.before = e.modifier.b = function(e, t) { var n = t[t.length - 1]; return { name: "before " + e.name, range: e.range * (n - 1), val: e.val, isValid: function(e, t) { return this.val(e) < n }, extent: e.extent, start: e.start, end: e.end, next: function(t, r) { return r = r === n ? e.extent(t)[0] : n, e.next(t, r) }, prev: function(t, r) { return r = r === n ? n - 1 : e.extent(t)[1], e.prev(t, r) } } } , e.compile = function(t) { function n(e) { return "next" === e ? function(e, t) { return e.getTime() > t.getTime() } : function(e, t) { return t.getTime() > e.getTime() } } var r, a = [], i = 0; for (var u in t) { var o = u.split("_") , f = o[0] , d = o[1] , v = t[u] , l = d ? e.modifier[d](e[f], v) : e[f]; a.push({ constraint: l, vals: v }), i++ } return a.sort(function(e, t) { var n = e.constraint.range , r = t.constraint.range; return n > r ? -1 : r > n ? 1 : 0 }), r = a[i - 1].constraint, { start: function(t, n) { for (var u, o = n, f = e.array[t], d = 1e3; d-- && !u && o; ) { u = !0; for (var v = 0; i > v; v++) { var l = a[v].constraint , c = l.val(o) , s = l.extent(o) , m = f(c, a[v].vals, s); if (!l.isValid(o, m)) { o = l[t](o, m), u = !1; break } } } return o !== e.NEVER && (o = "next" === t ? r.start(o) : r.end(o)), o }, end: function(t, r) { for (var u, o = e.array[t + "Invalid"], f = n(t), d = i - 1; d >= 0; d--) { var v, l = a[d].constraint, c = l.val(r), s = l.extent(r), m = o(c, a[d].vals, s); void 0 !== m && (v = l[t](r, m), !v || u && !f(u, v) || (u = v)) } return u }, tick: function(t, n) { return new Date("next" === t ? r.end(n).getTime() + e.SEC : r.start(n).getTime() - e.SEC) }, tickStart: function(e) { return r.start(e) } } } , e.schedule = function(t) { function n(t, n, x, g, p) { var D, M, b, Y = s(t), k = n, E = 1e3, T = [], O = [], S = [], N = "next" === t, R = N ? 0 : 1, C = N ? 1 : 0; if (x = x ? new Date(x) : new Date, !x || !x.getTime()) throw new Error("Invalid start date."); for (a(t, h, T, x), u(t, w, O, x); E-- && k && (D = m(T, Y)) && (!g || !Y(D, g)); ) if (y && (o(t, w, O, D), M = v(t, O, D))) i(t, h, T, M); else { if (p) { var V = l(O, Y); M = c(t, h, T, D, V); var I = N ? [new Date(Math.max(x, D)), M ? new Date(g ? Math.min(M, g) : M) : void 0] : [M ? new Date(g ? Math.max(g, M.getTime() + e.SEC) : M.getTime() + e.SEC) : void 0, new Date(Math.min(x, D.getTime() + e.SEC))]; if (b && I[R].getTime() === b[C].getTime() ? (b[C] = I[C], k++) : (b = I, S.push(b)), !M) break; i(t, h, T, M) } else S.push(N ? new Date(Math.max(x, D)) : d(h, T, D, g)), f(t, h, T, D); k-- } for (var U = 0, A = S.length; A > U; U++) { var W = S[U]; S[U] = "[object Array]" === Object.prototype.toString.call(W) ? [r(W[0]), r(W[1])] : r(W) } return 0 === S.length ? e.NEVER : 1 === n ? S[0] : S } function r(e) { return e instanceof Date && !isNaN(e.valueOf()) ? new Date(e) : void 0 } function a(e, t, n, r) { for (var a = 0, i = t.length; i > a; a++) n[a] = t[a].start(e, r) } function i(e, t, n, r) { for (var a = s(e), i = 0, u = t.length; u > i; i++) n[i] && !a(n[i], r) && (n[i] = t[i].start(e, r)) } function u(t, n, r, a) { for (var i = (s(t), 0), u = n.length; u > i; i++) { var o = n[i].start(t, a); o ? r[i] = [o, n[i].end(t, o)] : r[i] = e.NEVER } } function o(t, n, r, a) { for (var i = s(t), u = 0, o = n.length; o > u; u++) if (r[u] && !i(r[u][0], a)) { var f = n[u].start(t, a); f ? r[u] = [f, n[u].end(t, f)] : r[u] = e.NEVER } } function f(e, t, n, r) { for (var a = 0, i = t.length; i > a; a++) n[a] && n[a].getTime() === r.getTime() && (n[a] = t[a].start(e, t[a].tick(e, r))) } function d(e, t, n, r) { for (var a, i = 0, u = t.length; u > i; i++) if (t[i] && t[i].getTime() === n.getTime()) { var o = e[i].tickStart(n); if (r && r > o) return r; (!a || o > a) && (a = o) } return a } function v(e, t, n) { for (var r, a = s(e), i = 0, u = t.length; u > i; i++) { var o = t[i]; !o || a(o[0], n) || o[1] && !a(o[1], n) || (!r || a(o[1], r)) && (r = o[1]) } return r } function l(e, t) { for (var n, r = 0, a = e.length; a > r; r++) !e[r] || n && !t(n, e[r][0]) || (n = e[r][0]); return n } function c(e, t, n, r, a) { for (var i, u = s(e), o = 0, f = t.length; f > o; o++) { var d = n[o]; if (d && d.getTime() === r.getTime()) { var v = t[o].end(e, d); if (a && (!v || u(v, a))) return a; (!i || u(v, i)) && (i = v) } } return i } function s(e) { return "next" === e ? function(e, t) { return !t || e.getTime() > t.getTime() } : function(e, t) { return !e || t.getTime() > e.getTime() } } function m(e, t) { for (var n = e[0], r = 1, a = e.length; a > r; r++) e[r] && t(n, e[r]) && (n = e[r]); return n } if (!t) throw new Error("Missing schedule definition."); if (!t.schedules) throw new Error("Definition must include at least one schedule."); for (var h = [], x = t.schedules.length, w = [], y = t.exceptions ? t.exceptions.length : 0, g = 0; x > g; g++) h.push(e.compile(t.schedules[g])); for (var p = 0; y > p; p++) w.push(e.compile(t.exceptions[p])); return { isValid: function(t) { return n("next", 1, t, t) !== e.NEVER }, next: function(e, t, r) { return n("next", e || 1, t, r) }, prev: function(e, t, r) { return n("prev", e || 1, t, r) }, nextRange: function(e, t, r) { return n("next", e || 1, t, r, !0) }, prevRange: function(e, t, r) { return n("prev", e || 1, t, r, !0) } } } , e.setTimeout = function(t, n) { function r() { var e = Date.now() , n = i.next(2, e); if (!n[0]) return void (a = void 0); var u = n[0].getTime() - e; 1e3 > u && (u = n[1] ? n[1].getTime() - e : 1e3), a = 2147483647 > u ? setTimeout(t, u) : setTimeout(r, 2147483647) } var a, i = e.schedule(n); return t && r(), { isDone: function() { return !a }, clear: function() { clearTimeout(a) } } } , e.setInterval = function(t, n) { function r() { i || (t(), a = e.setTimeout(r, n)) } if (t) { var a = e.setTimeout(r, n) , i = a.isDone(); return { isDone: function() { return a.isDone() }, clear: function() { i = !0, a.clear() } } } } , e.date = {}, e.date.timezone = function(t) { e.date.build = t ? function(e, t, n, r, a, i) { return new Date(e,t,n,r,a,i) } : function(e, t, n, r, a, i) { return new Date(Date.UTC(e, t, n, r, a, i)) } ; var n = t ? "get" : "getUTC" , r = Date.prototype; e.date.getYear = r[n + "FullYear"], e.date.getMonth = r[n + "Month"], e.date.getDate = r[n + "Date"], e.date.getDay = r[n + "Day"], e.date.getHour = r[n + "Hours"], e.date.getMin = r[n + "Minutes"], e.date.getSec = r[n + "Seconds"], e.date.isUTC = !t } , e.date.UTC = function() { e.date.timezone(!1) } , e.date.localTime = function() { e.date.timezone(!0) } , e.date.UTC(), e.SEC = 1e3, e.MIN = 60 * e.SEC, e.HOUR = 60 * e.MIN, e.DAY = 24 * e.HOUR, e.WEEK = 7 * e.DAY, e.DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], e.NEVER = 0, e.date.next = function(t, n, r, a, i, u) { return e.date.build(t, void 0 !== n ? n - 1 : 0, void 0 !== r ? r : 1, a || 0, i || 0, u || 0) } , e.date.nextRollover = function(t, n, r, a) { var i = r.val(t) , u = r.extent(t)[1]; return i >= (n || u) || n > u ? new Date(a.end(t).getTime() + e.SEC) : a.start(t) } , e.date.prev = function(t, n, r, a, i, u) { var o = arguments.length; return n = 2 > o ? 11 : n - 1, r = 3 > o ? e.D.extent(e.date.next(t, n + 1))[1] : r, a = 4 > o ? 23 : a, i = 5 > o ? 59 : i, u = 6 > o ? 59 : u, e.date.build(t, n, r, a, i, u) } , e.date.prevRollover = function(e, t, n, r) { var a = n.val(e); return t >= a || !t ? r.start(r.prev(e, r.val(e) - 1)) : r.start(e) } , e.parse = {}, e.parse.cron = function(e, t) { function n(e, t, n) { return isNaN(e) ? s[e] || null : Math.min(+e + (t || 0), n || 9999) } function r(e) { var t, n = {}; for (t in e) "dc" !== t && "d" !== t && (n[t] = e[t].slice(0)); return n } function a(e, t, n, r, a) { var i = n; for (e[t] || (e[t] = []); r >= i; ) e[t].indexOf(i) < 0 && e[t].push(i), i += a || 1; e[t].sort(function(e, t) { return e - t }) } function i(e, t, n, i) { (t.d && !t.dc || t.dc && t.dc.indexOf(i) < 0) && (e.push(r(t)), t = e[e.length - 1]), a(t, "d", n, n), a(t, "dc", i, i) } function u(e, t, n) { var r = {} , i = {}; 1 === n ? (a(t, "D", 1, 3), a(t, "d", s.MON, s.FRI), a(r, "D", 2, 2), a(r, "d", s.TUE, s.FRI), a(i, "D", 3, 3), a(i, "d", s.TUE, s.FRI)) : (a(t, "D", n - 1, n + 1), a(t, "d", s.MON, s.FRI), a(r, "D", n - 1, n - 1), a(r, "d", s.MON, s.THU), a(i, "D", n + 1, n + 1), a(i, "d", s.TUE, s.FRI)), e.exceptions.push(r), e.exceptions.push(i) } function o(e, t, r, i, u, o) { var f = e.split("/") , d = +f[1] , v = f[0]; if ("*" !== v && "0" !== v) { var l = v.split("-"); i = n(l[0], o, u), u = n(l[1], o, u) || u } a(t, r, i, u, d) } function f(e, t, r, f, d, v) { var l, c, s = t.schedules, m = s[s.length - 1]; "L" === e && (e = f - 1), null !== (l = n(e, v, d)) ? a(m, r, l, l) : null !== (l = n(e.replace("W", ""), v, d)) ? u(t, m, l) : null !== (l = n(e.replace("L", ""), v, d)) ? i(s, m, l, f - 1) : 2 === (c = e.split("#")).length ? (l = n(c[0], v, d), i(s, m, l, n(c[1]))) : o(e, m, r, f, d, v) } function d(e) { return e.indexOf("#") > -1 || e.indexOf("L") > 0 } function v(e, t) { return d(e) && !d(t) ? 1 : e - t } function l(e) { var t, n, r, a, i = { schedules: [{}], exceptions: [] }, u = e.replace(/(\s)+/g, " ").split(" "); for (t in h) if (n = h[t], r = u[n[0]], r && "*" !== r && "?" !== r) { a = r.split(",").sort(v); var o, d = a.length; for (o = 0; d > o; o++) f(a[o], i, t, n[1], n[2], n[3]) } return i } function c(e) { var t = e.toUpperCase(); return m[t] || t } var s = { JAN: 1, FEB: 2, MAR: 3, APR: 4, MAY: 5, JUN: 6, JUL: 7, AUG: 8, SEP: 9, OCT: 10, NOV: 11, DEC: 12, SUN: 1, MON: 2, TUE: 3, WED: 4, THU: 5, FRI: 6, SAT: 7 } , m = { "* * * * * *": "0/1 * * * * *", "@YEARLY": "0 0 1 1 *", "@ANNUALLY": "0 0 1 1 *", "@MONTHLY": "0 0 1 * *", "@WEEKLY": "0 0 * * 0", "@DAILY": "0 0 * * *", "@HOURLY": "0 * * * *" } , h = { s: [0, 0, 59], m: [1, 0, 59], h: [2, 0, 23], D: [3, 1, 31], M: [4, 1, 12], Y: [6, 1970, 2099], d: [5, 1, 7, 1] } , x = c(e); return l(t ? x : "0 " + x) } , e.parse.recur = function() { function t(e, t, l) { if (e = u ? e + "_" + u : e, n || (s.push({}), n = s[0]), n[e] || (n[e] = []), r = n[e], i) { for (a = [], d = t; l >= d; d += i) a.push(d); v = { n: e, x: i, c: r.length, m: l } } a = o ? [t] : f ? [l] : a; var c = a.length; for (d = 0; c > d; d += 1) { var m = a[d]; r.indexOf(m) < 0 && r.push(m) } a = i = u = o = f = 0 } var n, r, a, i, u, o, f, d, v, l = [], c = [], s = l; return { schedules: l, exceptions: c, on: function() { return a = arguments[0]instanceof Array ? arguments[0] : arguments, this }, every: function(e) { return i = e || 1, this }, after: function(e) { return u = "a", a = [e], this }, before: function(e) { return u = "b", a = [e], this }, first: function() { return o = 1, this }, last: function() { return f = 1, this }, time: function() { for (var e = 0, n = a.length; n > e; e++) { var r = a[e].split(":"); r.length < 3 && r.push(0), a[e] = 3600 * +r[0] + 60 * +r[1] + +r[2] } return t("t"), this }, second: function() { return t("s", 0, 59), this }, minute: function() { return t("m", 0, 59), this }, hour: function() { return t("h", 0, 23), this }, dayOfMonth: function() { return t("D", 1, f ? 0 : 31), this }, dayOfWeek: function() { return t("d", 1, 7), this }, onWeekend: function() { return a = [1, 7], this.dayOfWeek() }, onWeekday: function() { return a = [2, 3, 4, 5, 6], this.dayOfWeek() }, dayOfWeekCount: function() { return t("dc", 1, f ? 0 : 5), this }, dayOfYear: function() { return t("dy", 1, f ? 0 : 366), this }, weekOfMonth: function() { return t("wm", 1, f ? 0 : 5), this }, weekOfYear: function() { return t("wy", 1, f ? 0 : 53), this }, month: function() { return t("M", 1, 12), this }, year: function() { return t("Y", 1970, 2450), this }, fullDate: function() { for (var e = 0, n = a.length; n > e; e++) a[e] = a[e].getTime(); return t("fd"), this }, customModifier: function(t, n) { var r = e.modifier[t]; if (!r) throw new Error("Custom modifier " + t + " not recognized!"); return u = t, a = arguments[1]instanceof Array ? arguments[1] : [arguments[1]], this }, customPeriod: function(n) { var r = e[n]; if (!r) throw new Error("Custom time period " + n + " not recognized!"); return t(n, r.extent(new Date)[0], r.extent(new Date)[1]), this }, startingOn: function(e) { return this.between(e, v.m) }, between: function(e, r) { return n[v.n] = n[v.n].splice(0, v.c), i = v.x, t(v.n, e, r), this }, and: function() { return n = s[s.push({}) - 1], this }, except: function() { return s = c, n = null, this } } } , e.parse.text = function(t) { function n(e, t, n, r) { return { startPos: e, endPos: t, text: n, type: r } } function r(e) { var t, r, a, i, u, o, f = e instanceof Array ? e : [e], d = /\s+/; for (f.push(d), u = w; !t || t.type === d; ) { o = -1, r = y.substring(u), t = n(u, u, y.split(d)[0]); var v, l = f.length; for (v = 0; l > v; v++) i = f[v], a = i.exec(r), a && 0 === a.index && a[0].length > o && (o = a[0].length, t = n(u, u + o, r.substring(0, o), i)); t.type === d && (u = t.endPos) } return t } function a(e) { var t = r(e); return w = t.endPos, t } function i(e) { for (var t = +s(e), n = l(g.through) ? +s(e) : t, r = [], a = t; n >= a; a++) r.push(a); return r } function u(e) { for (var t = i(e); l(g.and); ) t = t.concat(i(e)); return t } function o(e) { var t, n, r, a; l(g.weekend) ? e.on(p.sun, p.sat).dayOfWeek() : l(g.weekday) ? e.on(p.mon, p.tue, p.wed, p.thu, p.fri).dayOfWeek() : (t = s(g.rank), e.every(t), n = v(e), l(g.start) ? (t = s(g.rank), e.startingOn(t), c(n.type)) : l(g.between) && (r = s(g.rank), l(g.and) && (a = s(g.rank), e.between(r, a)))) } function f(e) { l(g.first) ? e.first() : l(g.last) ? e.last() : e.on(u(g.rank)), v(e) } function d(e) { w = 0, y = e, h = -1; for (var t = x(); w < y.length && 0 > h; ) { var n = c([g.every, g.after, g.before, g.onthe, g.on, g.of, g["in"], g.at, g.and, g.except, g.also]); switch (n.type) { case g.every: o(t); break; case g.after: void 0 !== r(g.time).type ? (t.after(s(g.time)), t.time()) : (t.after(s(g.rank)), v(t)); break; case g.before: void 0 !== r(g.time).type ? (t.before(s(g.time)), t.time()) : (t.before(s(g.rank)), v(t)); break; case g.onthe: f(t); break; case g.on: t.on(u(g.dayName)).dayOfWeek(); break; case g.of: t.on(u(g.monthName)).month(); break; case g["in"]: t.on(u(g.yearIndex)).year(); break; case g.at: for (t.on(s(g.time)).time(); l(g.and); ) t.on(s(g.time)).time(); break; case g.and: break; case g.also: t.and(); break; case g.except: t.except(); break; default: h = w } } return { schedules: t.schedules, exceptions: t.exceptions, error: h } } function v(e) { var t = c([g.second, g.minute, g.hour, g.dayOfYear, g.dayOfWeek, g.dayInstance, g.day, g.month, g.year, g.weekOfMonth, g.weekOfYear]); switch (t.type) { case g.second: e.second(); break; case g.minute: e.minute(); break; case g.hour: e.hour(); break; case g.dayOfYear: e.dayOfYear(); break; case g.dayOfWeek: e.dayOfWeek(); break; case g.dayInstance: e.dayOfWeekCount(); break; case g.day: e.dayOfMonth(); break; case g.weekOfMonth: e.weekOfMonth(); break; case g.weekOfYear: e.weekOfYear(); break; case g.month: e.month(); break; case g.year: e.year(); break; default: h = w } return t } function l(e) { var t = r(e).type === e; return t && a(e), t } function c(e) { var t = a(e); return t.type ? t.text = m(t.text, e) : h = w, t } function s(e) { return c(e).text } function m(e, t) { var n = e; switch (t) { case g.time: var r = e.split(/(:|am|pm)/) , a = "pm" === r[3] && r[0] < 12 ? parseInt(r[0], 10) + 12 : r[0] , i = r[2].trim(); n = (1 === a.length ? "0" : "") + a + ":" + i; break; case g.rank: n = parseInt(/^\d+/.exec(e)[0], 10); break; case g.monthName: case g.dayName: n = p[e.substring(0, 3)] } return n } var h, x = e.parse.recur, w = 0, y = "", g = { eof: /^$/, rank: /^((\d+)(st|nd|rd|th)?)\b/, time: /^((([0]?[1-9]|1[0-2]):[0-5]\d(\s)?(am|pm))|(([0]?\d|1\d|2[0-3]):[0-5]\d))\b/, dayName: /^((sun|mon|tue(s)?|wed(nes)?|thu(r(s)?)?|fri|sat(ur)?)(day)?)\b/, monthName: /^(jan(uary)?|feb(ruary)?|ma((r(ch)?)?|y)|apr(il)?|ju(ly|ne)|aug(ust)?|oct(ober)?|(sept|nov|dec)(ember)?)\b/, yearIndex: /^(\d\d\d\d)\b/, every: /^every\b/, after: /^after\b/, before: /^before\b/, second: /^(s|sec(ond)?(s)?)\b/, minute: /^(m|min(ute)?(s)?)\b/, hour: /^(h|hour(s)?)\b/, day: /^(day(s)?( of the month)?)\b/, dayInstance: /^day instance\b/, dayOfWeek: /^day(s)? of the week\b/, dayOfYear: /^day(s)? of the year\b/, weekOfYear: /^week(s)?( of the year)?\b/, weekOfMonth: /^week(s)? of the month\b/, weekday: /^weekday\b/, weekend: /^weekend\b/, month: /^month(s)?\b/, year: /^year(s)?\b/, between: /^between (the)?\b/, start: /^(start(ing)? (at|on( the)?)?)\b/, at: /^(at|@)\b/, and: /^(,|and\b)/, except: /^(except\b)/, also: /(also)\b/, first: /^(first)\b/, last: /^last\b/, "in": /^in\b/, of: /^of\b/, onthe: /^on the\b/, on: /^on\b/, through: /(-|^(to|through)\b)/ }, p = { jan: 1, feb: 2, mar: 3, apr: 4, may: 5, jun: 6, jul: 7, aug: 8, sep: 9, oct: 10, nov: 11, dec: 12, sun: 1, mon: 2, tue: 3, wed: 4, thu: 5, fri: 6, sat: 7, "1st": 1, fir: 1, "2nd": 2, sec: 2, "3rd": 3, thi: 3, "4th": 4, "for": 4 }; return d(t.toLowerCase()) } , e }();
3、业务代码中引入vue3Cron/Index.vue使用即可
<template>
<el-drawer :model-value="isShow" direction="rtl" :show-close="false" :destroy-on-close="true"
:close-on-click-modal="false" :title="!!curRecord ? '编辑触发器' : '创建触发器'" @open="onOpen" @closed="onCancel" size="500px">
<div class="pr-20">
<el-form class="edit-form" :model="formData" ref="formRef" :rules="rules" label-width="100px">
// 删除部分代码 -- START
// 删除部分代码 -- END
<el-form-item label="cron表达式" prop="logicConfig"> <el-input v-model="formData.logicConfig" placeholder="请输入cron表达式"> <template #append> <el-tooltip content="配置cron表达式" placement="top"> <el-button :icon="ArrowDown" @click="() => { isShowCronCore = !isShowCronCore }" /> </el-tooltip> </template> </el-input> </el-form-item> <div style="width:100%;padding-left: 10px;margin-top: -5px;" v-show="isShowCronCore"> <div v-if="formData.logicConfig.length > 0"> <Vue3Cron @change="changeCron" @onShowError="onShowError" v-model:value="formData.logicConfig" :defaultCron="defaultCron" /> <div style="display:flex;"> <el-button type="primary" plain size="small" class="mt-10" @click="getRecentRunTime">最近5次运行时间</el-button> <div style="width:150px;text-align: center;"> <p v-for="item in runTimeList" :key="item" class="mt-10">{{ item }}</p> </div> </div> </div> </div> </el-form> </div> <template #footer> <span class="dialog-footer"> <el-button @click="onCancel">取 消</el-button> <el-button type="primary" v-if="modalType != 'view'" :loading="submiting" @click="onSubmit">确 定</el-button> </span> </template> </el-drawer> </template> <script setup> import { ref, reactive } from "vue"; import { ElMessage, ElMessageBox } from "element-plus"; import { ArrowDown } from '@element-plus/icons-vue' import { isValidCron } from 'cron-validator'; import cronParse from 'cron-parser'; import { regex, sexTypeList } from '@/common/constant'; import triggerApi from '@/api/triggerApi'; import Vue3Cron from "@/components/vue3Cron/Index.vue"; const sysUser = JSON.parse(sessionStorage.getItem('sysUser')); //定义子组件需要接收的值 const props = defineProps({ isShow: { type: Boolean, default: false }, //是否显示弹窗 curRecord: { type: Object, default: null }, // 当前条目 }); // 注册事件 const emits = defineEmits(["onClose"]); // 定义数据 const errList = ref(['', '', '', '']); const defaultCron = "0 * * * * ?"; // 默认cron表达式 const isShowCronCore = ref(true); // 是否打开cron表达式配置框 const runTimeList = ref([]); // 最近5次运行时间 const submiting = ref(false); // 是否正在提交中 const formRef = ref(null); const formData = reactive({ // 表单数据 logicConfig: '', // cron表达式(当触发逻辑=cron_express,填充cron配置,其它情况为空)(默认是每一分钟一次,不指定年份) operatoruserId: sysUser.userId, }); const changeCron = (cron, arr) => { runTimeList.value = []; if (typeof cron !== "string") return false; formData.logicConfig = cron; }; const onShowError = (errArr) => { console.log('=====', errArr) errList.value = errArr; } const getRecentRunTime = () => { runTimeList.value = []; let cronText = formData.logicConfig; if (cronText.trim() == '') { ElMessage.warning('cron表达式为空'); } else { cronText = cronText.trim().substring(2, 100) var sched = later.parse.cron(cronText); later.date.localTime(); var results = later.schedule(sched).next(5); let list = []; for (var i = 0; i < results.length; i++) { list.push(results[i].toLocaleString()); } runTimeList.value = list; } } // 校验cron表达式 const validateCronExpression = (rule, value, callback) => { if (value) { try { const interval = cronParse.parseExpression(value) } catch (e) { callback('cron表达式语法错误,请检查') } } else { callback('执行表达式不能为空!') } callback() } // 表单校验 const rules = { name: [{ required: true, max: 20, whitespace: true, message: '名称不能为空且不能大于20个字符', trigger: 'blur' }], description: [{ max: 100, whitespace: true, message: '描述不能大于100个字符', trigger: 'blur' },], triggerLogic: [{ required: true, message: '请选择触发逻辑', trigger: 'blur' }], logicConfig: [ { required: true, whitespace: true, message: '请选择cron表达式', trigger: 'change' }, // { validator: validateCronExpression, trigger: ['blur'] } ], } // 打开弹窗的回调 const onOpen = () => { if (!!props.curRecord) { // 是编辑 for (let key in formData) { if (key != 'roleIds') { formData[key] = props.curRecord[key] } } } else { // 是新增 formData.logicConfig = defaultCron; } }; // 点击取消按钮 const onCancel = () => { submiting.value = false; formRef.value.resetFields(); runTimeList.value = []; emits("onClose", false); }; const tips = (res) => { submiting.value = false; runTimeList.value = []; if (res && res.code == 200) { ElMessage.success(res.msg || '操作成功'); formRef.value.resetFields(); emits("onClose", true); } else { ElMessage.warning(res.msg || '操作失败'); } } // 点击确定按钮 const onSubmit = () => { runTimeList.value = []; formRef.value.validate(valid => { if (valid) { if (errList.value.join('').length) { console.log('有错误信息'); let html = '<div>'; errList.value.forEach(item => { if (item) html += `<p>${item}</p>`; }) html += '</div>'; console.log(html) ElMessageBox.alert( html, '错误提示', { dangerouslyUseHTMLString: true, type:'warning' } ) return; } submiting.value = true; let params = { ...formData }; if (props.curRecord == null) { // 是新增 triggerApi.trigerAdd(params).then(res => { tips(res); }) } else { // 是编辑 params.id = props.curRecord.id; triggerApi.trigerEdit(params).then(res => { tips(res); }) } } }); } </script>
4、效果
例如:勾选配置为:每天10:30执行一次,输入框显示的表达式如下
注:由于公司项目的需求,这里隐藏了秒和年的选项,天的选项里也注释了部分选项
附上cron表达式基本介绍:
1、Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:
(1)、秒 分 时 日 月 周 年
(2)、秒 分 时 日 月 周
corn从左到右(用空格隔开):秒 分 小时 月份中的日期 月份 星期中的日期 年份
二、各字段的含义
字段 | 允许值 | 允许的特殊字符 |
秒(Seconds) | 0~59的整数 | , - * / 四个字符 |
分(Minutes) | 0~59的整数 | , - * / 四个字符 |
小时(Hours) | 0~23的整数 | , - * / 四个字符 |
日期(DayofMonth) | 1~31的整数(但是你需要考虑你月的天数) | ,- * ? / L W C 八个字符 |
月份(Month) | 1~12的整数或者 JAN-DEC | , - * / 四个字符 |
星期(DayofWeek) | 1~7的整数或者 SUN-SAT (1=SUN) | , - * ? / L C # 八个字符 |
年(可选,留空)(Year) | 1970~2099 | , - * / 四个字符 |
注意事项:
每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:
(1)*:表示匹配该域的任意值。假如在Minutes域使用*, 即表示每分钟都会触发事件。
(2)?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。
(3)-:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
(4)/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.
(5),:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
(6)L:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
(7)W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。
(8)LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
(9)#:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。
三、常用表达式例子
(1)0 0 2 1 * ? * 表示在每月的1日的凌晨2点调整任务
(2)0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业
(3)0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作
(4)0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
(5)0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
(6)0 0 12 ? * WED 表示每个星期三中午12点
(7)0 0 12 * * ? 每天中午12点触发
(8)0 15 10 ? * * 每天上午10:15触发
(9)0 15 10 * * ? 每天上午10:15触发
(10)0 15 10 * * ? * 每天上午10:15触发
(11)0 15 10 * * ? 2005 2005年的每天上午10:15触发
(12)0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发
(13)0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
(14)0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
(15)0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发
(16)0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发
(17)0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
(18)0 15 10 15 * ? 每月15日上午10:15触发
(19)0 15 10 L * ? 每月最后一日的上午10:15触发
(20)0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
(21)0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发
(22)0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
注:
(1)有些子表达式能包含一些范围或列表
例如:子表达式(天(星期))可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT”
“*”字符代表所有可能的值
因此,“*”在子表达式(月)里表示每个月的含义,“*”在子表达式(天(星期))表示星期的每一天
“/”字符用来指定数值的增量
例如:在子表达式(分钟)里的“0/15”表示从第0分钟开始,每15分钟
在子表达式(分钟)里的“3/20”表示从第3分钟开始,每20分钟(它和“3,23,43”)的含义一样
“?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值
当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?”
“L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写
但是它在两个子表达式里的含义是不同的。
在天(月)子表达式中,“L”表示一个月的最后一天
在天(星期)自表达式中,“L”表示一个星期的最后一天,也就是SAT
如果在“L”前有具体的内容,它就具有其他的含义了
例如:“6L”表示这个月的倒数第6天,“FRIL”表示这个月的最一个星期五
注意:在使用“L”参数时,不要指定列表或范围,因为这会导致问题