react + antd + js 简单Cron组件,支持国际化
Cron.js
import React, { Fragment, useState, useCallback, useRef, useEffect } from 'react'; import { Select, TimePicker, Input } from 'antd'; const Option = Select.Option; const mwidth80 = { minWidth: 80, marginRight: 10 }; const width150 = { width: 150 }; const eachNum = (start, end, str) => { const back = []; for (let i = start; i <= end; i++) { back.push({ value: `${i}`, label: `${i} ${str}`, }); } return back; }; const zhCNLanguage = { dayOfWeekList: [ { label: '周一', value: 'MON' }, { label: '周二', value: 'TUE' }, { label: '周三', value: 'WED' }, { label: '周四', value: 'THU' }, { label: '周五', value: 'FRI' }, { label: '周六', value: 'SAT' }, { label: '周日', value: 'SUN' }, ], minuteOfHoursList: eachNum(0, 59, '分'), dayOfMonthList: [ ...eachNum(1, 31, '号'), { label: '月末', value: 'L', exclusive: true, }, ], monthOfYearList: eachNum(1, 12, '月'), freqList: [ { value: 'everyHours', label: '每小时' }, { value: 'everyday', label: '每天' }, { value: 'week', label: '每周' }, { value: 'month', label: '每月' }, // { value: 'year', label: '每年' }, { value: 'custom', label: '自定义' }, ], date:'日期', month:'月份', week:'星期', minute:'分钟', } const enUSLanguage = { dayOfWeekList: [ { label: 'Monday', value: 'MON' }, { label: 'Tuesday', value: 'TUE' }, { label: 'Wednesday', value: 'WED' }, { label: 'Thursday', value: 'THU' }, { label: 'Friday', value: 'FRI' }, { label: 'Saturday', value: 'SAT' }, { label: 'Sunday', value: 'SUN' }, ], minuteOfHoursList: eachNum(0, 59, 'Branch'), dayOfMonthList: [ ...eachNum(1, 31, 'Day'), { label: 'at the end of the month', value: 'L', exclusive: true, }, ], monthOfYearList: eachNum(1, 12, 'Month'), freqList: [ { value: 'everyHours', label: 'every hour' }, { value: 'everyday', label: 'every day' }, { value: 'week', label: 'weekly' }, { value: 'month', label: 'monthly' }, // { value: 'year', label: '每年' }, { value: 'custom', label: 'custom' }, ], date:'date', month:'month', week:'week', minute:'minute', } let labelObj = zhCNLanguage; const exclusiveDays = labelObj.dayOfMonthList.filter((d) => d.exclusive).map((d) => d.value); const checkIncludeExclusive = (dd) => { return !!(dd || []).find((d) => exclusiveDays.includes(d)); }; const cornFormat = (corn, mode) => { const value = corn || '0 0 0 * * ?'; const cronElements = value.split(' '); let [ss, mm, HH, dd, MM, week, yyyy] = cronElements; let freq; if (yyyy !== '*' || /[-\/#]/.test(value) || (!mode && /[,]/.test(value))) { freq = 'custom'; } else if (week !== '?') { freq = 'week'; } else if (MM === '*' && dd === '*' && HH === '*' && mm !== '*' && ss === '0') { freq = 'everyHours'; } else if (MM === '*' && dd === '*') { freq = 'everyday'; } else if (MM === '*') { freq = 'month'; } else if (MM !== '*') { freq = 'year'; } return { freq, stringValue: value, ss: parseInt(ss) || 0, mm: freq === 'everyHours' && !!mode ? mm.split(',').filter((i) => !!i) : parseInt(mm) || 0, HH: parseInt(HH) || 0, dd: dd.split(',').filter((i) => !!i), MM: MM.split(',').filter((i) => !!i), week: week.split(',').filter((i) => !!i), yyyy, }; }; const cornStringify = ({ freq, stringValue, ss, mm, HH, dd, MM, week, yyyy }) => { if (freq === 'custom') { return stringValue; } else if (freq === 'year') { week = '?'; if (!dd || dd.length <= 0) { dd = '*'; } } else if (freq === 'month') { MM = '*'; week = '?'; } else if (freq === 'week') { MM = '*'; dd = '?'; } else if (freq === 'everyday') { MM = '*'; week = '?'; dd = '*'; } else if (freq === 'everyHours') { MM = '*'; week = '?'; dd = '*'; HH = '*'; ss = '0'; } return `${ss} ${mm} ${HH} ${dd} ${MM} ${week}`; }; export default function CronForm({ defaultValue, value, onChange, multiple, disabled, language }) { if(language === 'en'){ labelObj = enUSLanguage; } const [objValue, setObjValue] = useState({}); const thisCron = useRef(''); const changeValue = useCallback((newObj) => { const cronString = cornStringify(newObj); thisCron.current = cronString; onChange && onChange(cronString); }); const onFreqChanged = useCallback((freq) => { setObjValue((oldObj) => { const newObj = { ...oldObj, freq, week: freq === 'week' ? ['MON'] : [], dd: freq === 'month' ? ['1'] : [], mm: Array.isArray(oldObj.mm) ? 0 : oldObj.mm, ...(freq === 'everyHours' && multiple ? { mm: ['0'], } : {}), MM: freq === 'year' ? ['1'] : '*', ...(freq === 'custom' ? { stringValue: cornStringify(oldObj), } : {}), }; changeValue(newObj); return newObj; }); }, []); const onMonthOfYearChanged = useCallback((MM) => { setObjValue((oldObj) => { const newObj = { ...oldObj, MM, }; changeValue(newObj); return newObj; }); }, []); const onDayOfWeekChanged = useCallback((week) => { setObjValue((oldObj) => { const newObj = { ...oldObj, week, }; changeValue(newObj); return newObj; }); }, []); const onDayOfMonthChanged = useCallback((dd) => { setObjValue((oldObj) => { const newObj = { ...oldObj, dd, }; changeValue(newObj); return newObj; }); }, []); const onFreqTimeChanged = useCallback((time) => { setObjValue((oldObj) => { const newTime = time ? { ss: time.second(), mm: time.minute(), HH: time.hour() } : { ss: 0, mm: 0, HH: 0 }; const newObj = { ...oldObj, ...newTime, }; changeValue(newObj); return newObj; }); }, []); const onMinuteOfHoursListChanged = useCallback((mm) => { setObjValue((oldObj) => { const newObj = { ...oldObj, mm, }; changeValue(newObj); return newObj; }); }, []); const onStringValueChanged = useCallback((e) => { e.persist(); setObjValue((oldObj) => { const newObj = { ...oldObj, stringValue: e.target.value, }; changeValue(newObj); return newObj; }); }, []); useEffect(() => { thisCron.current = value; const objValue = cornFormat(value || defaultValue, multiple); setObjValue(objValue); // 默认按天调度 if (!value && !defaultValue) { changeValue(objValue); } }, []); useEffect(() => { if (thisCron.current !== value) { thisCron.current = value; setObjValue(cornFormat(value, multiple)); } }, [value]); const { freq, stringValue, ss, mm, HH, dd = [], MM, week = [] } = objValue; const mode = multiple ? 'multiple' : undefined; const isYear = freq === 'year', isMonth = freq === 'month', isWeek = freq === 'week', isHours = freq === 'everyHours', isCustom = freq === 'custom'; const isIncludeExclusive = mode && checkIncludeExclusive(dd); return ( <Fragment> <Select value={freq} onChange={onFreqChanged} style={mwidth80} disabled={disabled}> {labelObj.freqList.map(({ value, label }) => ( <Option key={value} value={value}> {label} </Option> ))} </Select> {isYear && ( <Select value={MM} onChange={onMonthOfYearChanged} mode={mode} style={mwidth80} placeholder={labelObj.month} disabled={disabled} > {labelObj.monthOfYearList.map(({ value, label }) => ( <Option key={value} value={value}> {label} </Option> ))} </Select> )} {(isYear || isMonth) && ( <Select value={dd} onChange={onDayOfMonthChanged} mode={mode} style={mwidth80} placeholder={labelObj.date} allowClear={isYear} disabled={disabled} > {labelObj.dayOfMonthList.map(({ value, label, exclusive }) => ( <Option key={value} value={value} disabled={ mode && dd && dd.length > 0 && isIncludeExclusive === !exclusive } > {label} </Option> ))} </Select> )} {isWeek && ( <Select value={week} onChange={onDayOfWeekChanged} mode={mode} style={mwidth80} placeholder={labelObj.week} disabled={disabled} > {labelObj.dayOfWeekList.map(({ value, label }) => ( <Option key={value} value={value}> {label} </Option> ))} </Select> )} {isHours && ( <Select value={mm} onChange={onMinuteOfHoursListChanged} mode={mode} style={mwidth80} placeholder={labelObj.minute} disabled={disabled} > {labelObj.minuteOfHoursList.map(({ value, label }) => ( <Option key={value} value={value}> {label} </Option> ))} </Select> )} {!isHours && !isCustom && ( <TimePicker // defaultOpenValue={dayjs('00:00:00', 'HH:mm:ss')} onChange={onFreqTimeChanged} disabled={disabled} /> )} {isCustom && ( <Input style={width150} value={stringValue} onChange={onStringValueChanged} disabled={disabled} /> )} </Fragment> ); }
使用
<Corn value={cronValue} multiple={true} language={getLocale() === 'zh-CN' ? 'cn' : 'en'} onChange={(v: any) => { console.log("当前选中时间",v) setCronValue(v); }} />