React CRON定时器

  1. CRON概念
  2. REACT框架下制作CRON定时器
  3. 参考:在线CRON表达式生成器
  4. Github Repository - Cron Generator
  5. 使用UI组件库:Alibaba Fusion

一、CRON 概念

  1. 七个阈:秒、分、小时、日、月、星期、年
  2. 阈值详解:
cron Seconds Minutes Hours Day of Month Month Day of Week Year
阈名 小时 星期
数值范围 0-59 0-59 0-23 0-31 1-12 1-7 1970 - 2099
表达式 , - * / , - * / , - * / , - * /
? L W C
, - * / , - * /
? L C #
, - * /
  1. 表达式解释:
表达式 解释 样例
- 表示范围 周期从第1秒到第5秒:1-5
/ 起始触发事件/相隔时间 从第5min开始,每20min触发一次(5min,25min,45min):5/20
, 枚举值 5,12,20
L 用于“星期(Day of Week)”、“日(Day of Month)”中,表示最后。
备注:使用L的时候,不要指定范围
本月最后一个周五触发:5L
W 用于“日(Day of Month)”中,表示距离X日最近的一个本月的工作日 距离5号的最近的一个工作日:5W
LW 某月最后一个工作日(周五)
# 用于“星期(Day of Week)”,表示每月第几个星期几 第二周的周四:2#4
? 用于“星期(Day of Week)”、“日(Day of Month)”中,表示“不指定”

备注:关于C的解释暂未找到相关细节

  1. 特殊约束:
  • 选择月份的时候,日期不能为 * 和 ?
  • 星期默认值为 ?
  • 不能同时指定星期和日期,其中之一必须为 ?

二、构建核心代码模块

  1. 分析:
  • 七个阈值共同的部分:


    七个阈共同内容:, - * /
  • 日期特殊部分:


    日期特殊部分:? L W
  • 星期(周)特殊部分:


    星期特殊部分:? L #
  1. 根据cron七个阈,创建所需使用的state对象:
state = {
        // 各个cron阈表达式
        express: {
            second: '*',
            minute: '*',
            hour: '*',
            date: '*',
            month: '*',
            week: '?',
            year: '*'
        },

        // 每个阈选择的表达式类型
        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 },
        },

        // 循环选择 - 开始时间./ 执行周期
        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 },
        },

        // 枚举指定选择 - 指定时间节点数组,例如日期数组
        enumTime: {
            second: [],
            minute: [],
            hour: [],
            date: [],
            month: [],
            week: []
        },

        // 最近工作日 - 距离X日最近的工作日
        mostRecentWorkDay: 1,

        // 当前月份最后一个星期X
        lastWeekDay: 1,

        // 指定X周的星期X - 例如:第一周的星期三
        weekday: {
            weekNum: 1,
            weekDayNum: 1
        },

        alertMsg: null
    }
  1. 选择每个阈的类型的时候,根据所选值,获取当前域的表达式
    /**
  * @name: 选择每个表达式的具体展示类型
  * @param {*} type 表达式内容类型: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 }, () => {
            // 特殊逻辑判断,获取最新表达式
            this.judgeSpecialCRON(type, expressType)
        })
    }

/**
  * @name: 表达式校验并对表达式进行赋值
  * @param {*} type 当前选中阈值的表达式类型,例如:everyTime
  * @param {*} expressType 当前选中的阈值的类型,例如: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 = '*'
                }
                // 日期和星期不可同时指定内容(非?)
                if (expressState.date !== '?' && expressState.week !== '?') {
                    Message.warning('日期和星期不可同时指定任何值')
                    expressState.week = '?'
                }
                break
            }
            case 'month': {
                // 当月份选择为*(任意)时,星期设定为?(不指定)
                Message.warning('当月份选择为任意值时,星期设定为不指定模式(?)')
                if (expressState.month === '*') {
                    expressState.week = '?'
                    if (expressState.date === '?') {
                        expressState.date = '*'
                    }
                }
                break
            }
            case 'week': {
                // 日期和星期不可同时为?(不指定)
                if (expressState.week === '?' && expressState.date === '?') {
                    expressState.date = '*'
                    Message.warning('日期和星期不可同时均不指定任何值')
                }
                // 日期和星期不可同时指定内容(非?)
                if (expressState.week !== '?' && expressState.date !== '?') {
                    expressState.date = '?'
                    Message.warning('日期和星期不可同时指定任何值')
                }
                break
            }
            default: break
        }

        this.setState({ express: expressState })
    }
  1. 根据每个阈的规则,获取每个阈的cron表达式:
  /**
  * @name: 获取每个cron阈的表达式字符串
  * @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表达式
  * @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 '*'
        }
    }
  1. 反解析cron表达式到UI的方法:
/**
  * @name: 反编译解析表达式
  * @param {*} express 表达式对象
  * @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表达式到UI时,每个阈内容进行解析 - 获取每个阈使用的类型和具体值
  * @param {*} expStr cron表达式内容,例如:*,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
    }
  1. render()渲染部分代码:请参考github代码内容

  2. 组件引用方法:

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 (
      

CRON Generator Sample:

) } }
参数名称 参数描述 参数类型 默认值 备注
isPreview 是否开启预览模式 Boolean false 该模式下,将不会显示新增取消按钮
initCron 需传入解析到UI界面的CRON字符串 String - -
dialogVisible CRON对话框显示 Boolean false -
onClose 关闭对话框对应方法,且取消获取CRON Function - -
onConfirm 关闭对话框且获取到最新的CRON表达式 Function - 该方法中会传入一个参数val,代表生成的cron表达式

三、结果页面:

首页 - 文本输入框 + 获取cron表达式按钮,包含初始化默认表达式
second
minute
hour
Day of Month
month
Day of Week
year

你可能感兴趣的:(React CRON定时器)