- CRON概念
- REACT框架下制作CRON定時器
- 參考:在線CRON表達(dá)式生成器
- Github Repository - Cron Generator
- 使用UI組件庫:Alibaba Fusion
一纷跛、CRON 概念
- 七個閾:秒艳丛、分嚷缭、小時、日辜窑、月、星期纷纫、年
- 閾值詳解:
cron | Seconds | Minutes | Hours | Day of Month | Month | Day of Week | Year |
---|---|---|---|---|---|---|---|
閾名 | 秒 | 分 | 小時 | 日 | 月 | 星期 | 年 |
數(shù)值范圍 | 0-59 | 0-59 | 0-23 | 0-31 | 1-12 | 1-7 | 1970 - 2099 |
表達(dá)式 | , - * / | , - * / | , - * / | , - * / ? L W C |
, - * / | , - * / ? L C # |
, - * / |
- 表達(dá)式解釋:
表達(dá)式 | 解釋 | 樣例 |
---|---|---|
- | 表示范圍 | 周期從第1秒到第5秒:1-5 |
/ | 起始觸發(fā)事件/相隔時間 | 從第5min開始里覆,每20min觸發(fā)一次(5min,25min烹骨,45min):5/20 |
, | 枚舉值 | 5,12,20 |
L | 用于“星期(Day of Week)”翻伺、“日(Day of Month)”中,表示最后沮焕。 備注:使用L的時候吨岭,不要指定范圍 |
本月最后一個周五觸發(fā):5L |
W | 用于“日(Day of Month)”中,表示距離X日最近的一個本月的工作日 | 距離5號的最近的一個工作日:5W |
LW | 某月最后一個工作日(周五) | |
# | 用于“星期(Day of Week)”峦树,表示每月第幾個星期幾 | 第二周的周四:2#4 |
? | 用于“星期(Day of Week)”辣辫、“日(Day of Month)”中,表示“不指定” |
備注:關(guān)于C的解釋暫未找到相關(guān)細(xì)節(jié)
- 特殊約束:
- 選擇月份的時候空入,日期不能為 * 和 ?
- 星期默認(rèn)值為 络它?
- 不能同時指定星期和日期,其中之一必須為 歪赢?
二、構(gòu)建核心代碼模塊
- 分析:
-
七個閾值共同的部分:
七個閾共同內(nèi)容:, - * / -
日期特殊部分:
日期特殊部分:? L W -
星期(周)特殊部分:
星期特殊部分:? L #
- 根據(jù)cron七個閾单料,創(chuàng)建所需使用的state對象:
state = {
// 各個cron閾表達(dá)式
express: {
second: '*',
minute: '*',
hour: '*',
date: '*',
month: '*',
week: '?',
year: '*'
},
// 每個閾選擇的表達(dá)式類型
expressType: {
second: 'everyTime',
minute: 'everyTime',
hour: 'everyTime',
date: 'everyTime',
month: 'everyTime',
week: 'everyTime',
year: 'everyTime',
},
// 周期選擇 - 最小時間 / 最大時間
periodTime: {
second: { max:2, min:1 },
minute: { max: 2, min: 1 },
hour: { max: 2, min: 1 },
date: { max: 2, min: 1 },
month: { max: 2, min: 1 },
week: { max: 2, min: 1 },
year: { max: 2020, min: 2020 },
},
// 循環(huán)選擇 - 開始時間./ 執(zhí)行周期
loopTime: {
second: { startTime:1, period:1 },
minute: { startTime: 1, period: 1 },
hour: { startTime: 1, period: 1 },
date: { startTime: 1, period: 1 },
month: { startTime: 1, period: 1 },
},
// 枚舉指定選擇 - 指定時間節(jié)點(diǎn)數(shù)組埋凯,例如日期數(shù)組
enumTime: {
second: [],
minute: [],
hour: [],
date: [],
month: [],
week: []
},
// 最近工作日 - 距離X日最近的工作日
mostRecentWorkDay: 1,
// 當(dāng)前月份最后一個星期X
lastWeekDay: 1,
// 指定X周的星期X - 例如:第一周的星期三
weekday: {
weekNum: 1,
weekDayNum: 1
},
alertMsg: null
}
- 選擇每個閾的類型的時候,根據(jù)所選值扫尖,獲取當(dāng)前域的表達(dá)式
/**
* @name: 選擇每個表達(dá)式的具體展示類型
* @param {*} type 表達(dá)式內(nèi)容類型:everyTime, period, loop, enum 等
* @param {*} expressType cron類型:second, minute, hour, date, month, week, year
* @return {*}
*/
onSelectType = (type, expressType) => {
let expressionTypeState = this.state.expressType
expressionTypeState[expressType] = type
this.setState({ expressType: expressionTypeState }, () => {
// 特殊邏輯判斷白对,獲取最新表達(dá)式
this.judgeSpecialCRON(type, expressType)
})
}
/**
* @name: 表達(dá)式校驗(yàn)并對表達(dá)式進(jìn)行賦值
* @param {*} type 當(dāng)前選中閾值的表達(dá)式類型,例如:everyTime
* @param {*} expressType 當(dāng)前選中的閾值的類型换怖,例如:date甩恼、minute
* @return {*}
*/
judgeSpecialCRON = (type, expressType) => {
let expressState = JSON.parse(JSON.stringify(this.state.express))
if (type === this.state.expressType[expressType]) {
expressState[expressType] = this.getExpressStr(type, expressType)
}
// 特殊賦值邏輯
switch (expressType) {
case 'date': {
// 日期和星期不可同時為?(不指定)
if (expressState.date === '?' && expressState.week === '?') {
Message.warning('日期和星期不可同時均不指定任何值')
expressState.week = '*'
}
// 日期和星期不可同時指定內(nèi)容(非?)
if (expressState.date !== '?' && expressState.week !== '?') {
Message.warning('日期和星期不可同時指定任何值')
expressState.week = '?'
}
break
}
case 'month': {
// 當(dāng)月份選擇為*(任意)時条摸,星期設(shè)定為悦污?(不指定)
Message.warning('當(dāng)月份選擇為任意值時,星期設(shè)定為不指定模式(?)')
if (expressState.month === '*') {
expressState.week = '?'
if (expressState.date === '?') {
expressState.date = '*'
}
}
break
}
case 'week': {
// 日期和星期不可同時為钉蒲?(不指定)
if (expressState.week === '?' && expressState.date === '?') {
expressState.date = '*'
Message.warning('日期和星期不可同時均不指定任何值')
}
// 日期和星期不可同時指定內(nèi)容(非切端?)
if (expressState.week !== '?' && expressState.date !== '?') {
expressState.date = '?'
Message.warning('日期和星期不可同時指定任何值')
}
break
}
default: break
}
this.setState({ express: expressState })
}
- 根據(jù)每個閾的規(guī)則,獲取每個閾的cron表達(dá)式:
/**
* @name: 獲取每個cron閾的表達(dá)式字符串
* @param {*} type
* @param {*} expressType
* @return {*}
*/
getExpressStr = (type, expressType) => {
switch (type) {
case 'everyTime': return '*'
case 'none': return '?'
case 'lastDay': return 'L'
case 'period': return this.expressGenerator(type, this.state.periodTime[expressType])
case 'loop': return this.expressGenerator(type, this.state.loopTime[expressType])
case 'enum': return this.expressGenerator(type, this.state.enumTime[expressType])
case 'mostRecentWorkDay': return this.state.mostRecentWorkDay + 'W'
case 'lastWeekDay': return this.state.lastWeekDay + 'L'
case 'weekday': return this.expressGenerator(type, this.state.weekday)
case 'optional': return ''
default: return
}
}
/**
* @name: 獲取cron表達(dá)式
* @param {type}
* @return {type}
*/
expressGenerator = (type, value) => {
function getEnumString (values) {
if (values.length > 0) {
let str = ''
values.map(item => {
str = str + ',' + item
})
str = str.substring(1, str.length)
return str
}
else
return '*'
}
switch (type) {
case 'everyTime': return '*'
case 'period': return value ? value.min + '-' + value.max : ''
case 'loop': return value ? value.startTime + '/' + value.period : ''
case 'enum': return getEnumString(value)
case 'weekday': return value ? value.weekNum + '#' + value.weekDayNum : ''
default: return '*'
}
}
- 反解析cron表達(dá)式到UI的方法:
/**
* @name: 反編譯解析表達(dá)式
* @param {*} express 表達(dá)式對象
* @return {*}
*/
reverseGenerateCRON = (express) => {
let newExpressType = JSON.parse(JSON.stringify(this.state.expressType))
newExpressType.second = this.getType(express.second, 'second')
newExpressType.minute = this.getType(express.minute, 'minute')
newExpressType.hour = this.getType(express.hour, 'hour')
newExpressType.date = this.getType(express.date, 'date')
newExpressType.month = this.getType(express.month, 'month')
newExpressType.week = this.getType(express.week, 'week')
newExpressType.year = this.getType(express.year, 'year')
this.setState({ expressType: newExpressType })
}
/**
* @name: 反解析cron表達(dá)式到UI時顷啼,每個閾內(nèi)容進(jìn)行解析 - 獲取每個閾使用的類型和具體值
* @param {*} expStr cron表達(dá)式內(nèi)容踏枣,例如:*,5L
* @param {*} expressType cron閾類型钙蒙,例如:minute茵瀑,hour,week
* @return {*} 每個閾使用的類型
*/
getType = (expStr, expressType) => {
if (expStr === '*') return 'everyTime'
else if (expStr === '?') return 'none'
else if (expStr === 'L') return 'lastDay'
else if (new RegExp('[-]').test(expStr)) {
let newPeriodTime = this.state.periodTime
let values = expStr.split('-')
newPeriodTime[expressType] = { max: parseInt(values[1]), min: parseInt(values[0]) }
this.setState({ periodTime: newPeriodTime })
return 'period'
}
else if (new RegExp('[/]').test(expStr)) {
let newLoopTime = this.state.loopTime
let values = expStr.split('/')
newLoopTime[expressType] = { startTime: parseInt(values[0]), period: parseInt(values[1]) }
this.setState({ loopTime: newLoopTime })
return 'loop'
}
else if (new RegExp('[,]').test(expStr)) {
let newEnumTime = this.state.enumTime
let values = expStr.split(',')
for (let i = 0; i < values.length; i++) {
values[i] = parseInt(values[i])
}
newEnumTime[expressType] = values
this.setState({ enumTime: newEnumTime })
return 'enum'
}
else if (new RegExp('[W]').test(expStr)) {
let value = parseInt(expStr.substring(0, 1))
console.log(value)
this.setState({ mostRecentWorkDay: value })
return 'mostRecentWorkDay'
}
else if (new RegExp('[L]').test(expStr)) {
this.setState({ lastWeekDay: parseInt(expStr.substring(0, 1)) })
return 'lastWeekDay'
}
else if (new RegExp('[#]').test(expStr)) {
let newWeekday = this.state.weekday
let values = expStr.split('#')
newWeekday = { weekNum: parseInt(values[0]), weekDayNum: parseInt(values[1]) }
this.setState({ weekday: newWeekday })
return 'weekday'
}
else if (expStr === '') {
return 'optional'
}
else return
}
render()渲染部分代碼:請參考github代碼內(nèi)容
組件引用方法:
import CronGenerator from '@/components/CronGenerator'
export default class App extends React.Component {
state = {
cronGeneratorVisible: false,
cronString: '* * * ? * * *'
}
onClose = () => {
this.setState({ cronGeneratorVisible: false })
}
onConfirm = (val) => {
this.setState({ cronString: val})
}
render () {
return (
<div className="cronGeneratorApp">
<p>CRON Generator Sample:</p>
<div className="cron_input">
<Input value={cronString} />
<Button type="primary" onClick={() => { this.setState({ cronGeneratorVisible: true }) }}>CRON</Button>
</div>
<CronGenerator
isPreview
initCron={cronString}
dialogVisible={cronGeneratorVisible}
onClose={this.onClose}
onConfirm={this.onConfirm}
/>
</div>
)
}
}
參數(shù)名稱 | 參數(shù)描述 | 參數(shù)類型 | 默認(rèn)值 | 備注 |
---|---|---|---|---|
isPreview | 是否開啟預(yù)覽模式 | Boolean | false | 該模式下躬厌,將不會顯示新增取消按鈕 |
initCron | 需傳入解析到UI界面的CRON字符串 | String | - | - |
dialogVisible | CRON對話框顯示 | Boolean | false | - |
onClose | 關(guān)閉對話框?qū)?yīng)方法马昨,且取消獲取CRON | Function | - | - |
onConfirm | 關(guān)閉對話框且獲取到最新的CRON表達(dá)式 | Function | - | 該方法中會傳入一個參數(shù)val,代表生成的cron表達(dá)式 |
三烤咧、結(jié)果頁面:
首頁 - 文本輸入框 + 獲取cron表達(dá)式按鈕偏陪,包含初始化默認(rèn)表達(dá)式
second
minute
hour
Day of Month
month
Day of Week
year