├── .gitignore ├── LICENSE ├── index.js ├── lib └── index.js ├── package.json ├── readme.md ├── snapshot └── snapshot.png ├── src ├── components │ ├── BaseEditor.js │ ├── Between.js │ ├── CheckBoxEditor.js │ ├── DayEditor.js │ ├── FromEvery.js │ ├── HourEditor.js │ ├── InputNumber.js │ ├── LastWeekDay.js │ ├── LastWorkDay.js │ ├── MinuteEditor.js │ ├── MonthEditor.js │ ├── SecondEditor.js │ ├── WeekDay.js │ ├── WeekEditor.js │ ├── YearEditor.js │ └── reg.js └── index.js ├── webpack.config.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dr.Liu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import CronEditor from './lib'; 2 | export default CronEditor; 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "antd-cron-editor", 3 | "version": "1.1.0", 4 | "description": "A cron expression generator to be used in React applications", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "webpack --progress", 8 | "watch": "webpack --watch --progress" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/liudongrong/cron-editor.git" 13 | }, 14 | "keywords": [ 15 | "cron", 16 | "editor", 17 | "react", 18 | "antd", 19 | "quartz" 20 | ], 21 | "author": "Ladtor", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/liudongrong/cron-editor/issues" 25 | }, 26 | "homepage": "https://github.com/liudongrong/cron-editor#readme", 27 | "dependencies": { 28 | "antd": "3.11.6", 29 | "babel-plugin-import": "1.11.0", 30 | "babel-runtime": "^6.26.0", 31 | "moment": "2.23.0", 32 | "react": "^16.7.0", 33 | "react-dom": "^16.7.0" 34 | }, 35 | "devDependencies": { 36 | "babel-core": "^6.26.0", 37 | "babel-loader": "^7.1.4", 38 | "babel-preset-env": "1.7.0", 39 | "babel-preset-es2015": "6.24.1", 40 | "babel-preset-react": "^6.24.1", 41 | "babel-preset-stage-2": "^6.24.1", 42 | "clean-webpack-plugin": "^0.1.19", 43 | "css-loader": "^0.28.11", 44 | "style-loader": "^0.20.3", 45 | "webpack": "^4.2.0", 46 | "webpack-cli": "3.2.0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # cron-editor 2 | 3 | ![image-20190107170123819](./snapshot/snapshot.png) 4 | 5 | ## usage 6 | 7 | - npm install antd-cron-editor 8 | - quick start 9 | 10 | ```jsx 11 | import React from 'react'; 12 | import CronEditor from 'antd-cron-editor'; 13 | 14 | const Test = () => { 15 | const handleChange = (cronText) => { 16 | console.log(cronText); 17 | }; 18 | 19 | return ; 20 | }; 21 | 22 | export default Test; 23 | 24 | ``` 25 | 26 | - with input area 27 | 28 | ```jsx 29 | import React from 'react'; 30 | import { Input } from 'antd'; 31 | import CronEditor from 'antd-cron-editor'; 32 | 33 | class Test extends React.Component { 34 | state = { 35 | value: '0-2 32,2 * * * ?', 36 | inputText: '0-2 32,2 * * * ?', 37 | }; 38 | 39 | handleChange = (cronText) => { 40 | console.log(cronText); 41 | this.setState({ value: cronText, inputText: cronText }); 42 | }; 43 | 44 | handleInputChange = ({ target: { value: inputText } }) => { 45 | this.setState({ inputText }); 46 | }; 47 | 48 | handlePressEnter = ({ target: { value: inputText } }) => { 49 | this.setState({ value: inputText, inputText }); 50 | }; 51 | 52 | render() { 53 | 54 | const { value, inputText } = this.state; 55 | 56 | return ( 57 |
58 | 59 | 60 |
61 | ); 62 | }; 63 | } 64 | 65 | export default Test; 66 | ``` 67 | -------------------------------------------------------------------------------- /snapshot/snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ladtor/cron-editor/832e0839779833b0d0300c621254d748cf97a79b/snapshot/snapshot.png -------------------------------------------------------------------------------- /src/components/BaseEditor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { index } from './Reg'; 3 | 4 | class BaseEditor extends React.Component{ 5 | notifyChange = (radio, value) => { 6 | const { onChange } = this.props; 7 | onChange && onChange(value); 8 | }; 9 | 10 | handleRadioChange = ({ target: { value: radio } }) => { 11 | const { value } = this.state; 12 | this.setState({ radio }); 13 | this.notifyChange(radio, value[radio]); 14 | }; 15 | 16 | handleValueChange = (radio, v) => { 17 | const { value } = this.state; 18 | value[radio] = v; 19 | this.setState({ radio, value }); 20 | this.notifyChange(radio, v); 21 | }; 22 | 23 | handleRegChange = (radio, v) => { 24 | const { value } = this.state; 25 | if (value[radio] === undefined) { 26 | console.error('cannot get radio index from radioMap', radio, value); 27 | radio = index.EVERY; 28 | v = '*'; 29 | } 30 | value[radio] = v; 31 | this.setState({ value, radio }); 32 | this.notifyChange(radio, v); 33 | }; 34 | } 35 | 36 | export default BaseEditor; 37 | -------------------------------------------------------------------------------- /src/components/Between.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input } from 'antd'; 3 | import InputNumber from './InputNumber'; 4 | 5 | const style = { width: 70, textAlign: 'center', paddingRight: '0px', paddingLeft: '0px' }; 6 | const InputGroup = Input.Group; 7 | 8 | const Between = ({ value, onChange, min = 0, max }) => { 9 | const splits = value.split('-'); 10 | const minValue = parseInt(splits[0], 0); 11 | const maxValue = parseInt(splits[1], 0); 12 | 13 | const notifyChange = (minValue, maxValue) => { 14 | const s = `${minValue}-${maxValue}`; 15 | onChange && onChange(s); 16 | }; 17 | 18 | const handleMinChange = (value) => { 19 | notifyChange(value, maxValue); 20 | }; 21 | 22 | const handleMaxChange = (value) => { 23 | notifyChange(minValue, value); 24 | }; 25 | 26 | return ( 27 | 28 | 36 | 41 | 49 | 50 | ); 51 | }; 52 | 53 | export default Between; 54 | -------------------------------------------------------------------------------- /src/components/CheckBoxEditor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Checkbox, Row, Col } from 'antd'; 3 | 4 | const CheckBoxEditor = ({ onChange, min = 0, max, span = 2, value }) => { 5 | const checkBoxs = (min, max) => { 6 | const items = []; 7 | for (let i = min; i <= max; i += 1) { 8 | items.push( 9 | 10 | {i} 11 | , 12 | ); 13 | } 14 | return items; 15 | }; 16 | 17 | const handleChange = (values) => { 18 | if (values.length === 0) onChange('*'); 19 | else onChange(values.sort((a, b) => a - b).join(',')); 20 | }; 21 | 22 | let checked = []; 23 | if (value === '*') ; 24 | else if (value) { 25 | checked = value.split(',') 26 | .map(i => parseInt(i, 0)) 27 | .filter(v => v >= min && v <= max) 28 | .sort((a, b) => a - b); 29 | 30 | const s = checked.join(','); 31 | s !== value && onChange && onChange(s); 32 | } 33 | 34 | return ( 35 |
36 | 37 | 38 | {checkBoxs(min, max)} 39 | 40 | 41 |
42 | ); 43 | }; 44 | 45 | export default CheckBoxEditor; 46 | -------------------------------------------------------------------------------- /src/components/DayEditor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Radio } from 'antd'; 3 | import Between from './Between'; 4 | import CheckBoxEditor from './CheckBoxEditor'; 5 | import FromEvery from './FromEvery'; 6 | import LastWorkDay from './LastWorkDay'; 7 | import Reg,{index} from './Reg'; 8 | import BaseEditor from './BaseEditor'; 9 | 10 | const RadioGroup = Radio.Group; 11 | 12 | const defaultRadioKeyValue = {}; 13 | defaultRadioKeyValue[index.EVERY] = '*'; 14 | defaultRadioKeyValue[index.ANY] = '?'; 15 | defaultRadioKeyValue[index.BETWEEN] = '1-2'; 16 | defaultRadioKeyValue[index.FROM_EVERY] = '1/1'; 17 | defaultRadioKeyValue[index.LAST_WORK_DAY] = '1W'; 18 | defaultRadioKeyValue[index.LAST_MONTH_DAY] = 'L'; 19 | defaultRadioKeyValue[index.CHECK_BOX] = '*'; 20 | 21 | class DayEditor extends BaseEditor{ 22 | state = { 23 | radio: index.EVERY, 24 | value: defaultRadioKeyValue, 25 | }; 26 | 27 | render() { 28 | const { radioStyle, value:defaultValue, ...config } = this.props; 29 | const { radio, value } = this.state; 30 | 31 | return ( 32 | 33 | 34 | 35 | 每日 36 | 37 | 38 | 不指定 39 | 40 | 41 | 周期 42 | 43 | 44 | 52 | 53 | 54 | 每月 号最近的那个工作日 55 | 56 | 57 | 本月最后一天 58 | 59 | 60 | 指定 61 | 62 | 63 | 64 | ); 65 | } 66 | } 67 | 68 | export default DayEditor; 69 | -------------------------------------------------------------------------------- /src/components/FromEvery.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import InputNumber from './InputNumber'; 3 | 4 | const inputNumberStyle = { 5 | margin: '0 5px', 6 | }; 7 | 8 | const FromEvery = ({ value, onChange, front, middle, back, fromMin = 0, fromMax = 59, everyMin = 1, everyMax = 59 }) => { 9 | 10 | const splits = value.split('/'); 11 | const from = splits[0]; 12 | const every = splits[1]; 13 | 14 | const notifyChange = (from, every) => { 15 | const s = `${from}/${every}`; 16 | onChange && onChange(s); 17 | }; 18 | 19 | const handleFromChange = (v) => { 20 | notifyChange(v, every); 21 | }; 22 | 23 | const handleEveryChange = (v) => { 24 | notifyChange(from, v); 25 | }; 26 | 27 | return ( 28 | 29 | {front} 30 | 37 | {middle} 38 | 45 | {back} 46 | 47 | ); 48 | }; 49 | 50 | export default FromEvery; 51 | -------------------------------------------------------------------------------- /src/components/HourEditor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Radio } from 'antd'; 3 | import Between from './Between'; 4 | import CheckBoxEditor from './CheckBoxEditor'; 5 | import FromEvery from './FromEvery'; 6 | import Reg, { index } from './Reg'; 7 | import BaseEditor from './BaseEditor'; 8 | 9 | const RadioGroup = Radio.Group; 10 | 11 | const defaultRadioKeyValue = {}; 12 | defaultRadioKeyValue[index.EVERY] = '*'; 13 | defaultRadioKeyValue[index.BETWEEN] = '0-23'; 14 | defaultRadioKeyValue[index.FROM_EVERY] = '0/1'; 15 | defaultRadioKeyValue[index.CHECK_BOX] = '*'; 16 | 17 | class HourEditor extends BaseEditor{ 18 | state = { 19 | radio: index.EVERY, 20 | value: defaultRadioKeyValue, 21 | }; 22 | 23 | render() { 24 | const { radioStyle, value: defaultValue, ...config } = this.props; 25 | const { radio, value } = this.state; 26 | 27 | return ( 28 | 29 | 30 | 31 | 每时 32 | 33 | 34 | 周期 35 | 36 | 37 | 47 | 48 | 49 | 指定 50 | 51 | 52 | 53 | ); 54 | } 55 | } 56 | 57 | export default HourEditor; 58 | -------------------------------------------------------------------------------- /src/components/InputNumber.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input } from 'antd'; 3 | 4 | class InputNumber extends React.Component { 5 | state = {}; 6 | 7 | componentWillReceiveProps(nextProps) { 8 | const { value, min, max } = nextProps; 9 | const v = this.getValue(value, min, max); 10 | this.setState({ value: v }); 11 | if (v != value) this.notify(); 12 | } 13 | 14 | getValue = (value, min, max) => { 15 | if (/^\d+$/.test(value)) { 16 | value = parseInt(value, 0); 17 | if (value < min) value = min; 18 | if (value > max) value = max; 19 | return value; 20 | } 21 | return min; 22 | }; 23 | 24 | handleChange = ({ target: { value } }) => { 25 | this.setState({ value }); 26 | }; 27 | 28 | handleBlur = () => { 29 | this.notify(); 30 | }; 31 | 32 | handleEnter = () => { 33 | this.notify(); 34 | }; 35 | 36 | notify = () => { 37 | const { onChange, min, max } = this.props; 38 | const { value } = this.state; 39 | onChange && onChange(this.getValue(value, min, max)); 40 | }; 41 | 42 | render() { 43 | const { placeholder = 'number', style } = this.props; 44 | const { value } = this.state; 45 | return ; 53 | } 54 | } 55 | 56 | export default InputNumber; 57 | -------------------------------------------------------------------------------- /src/components/LastWeekDay.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import InputNumber from './InputNumber'; 3 | 4 | const LastWeekDay = ({ value, onChange }) => { 5 | const splits = value.split('L'); 6 | 7 | const notifyChange = (v) => { 8 | const s = `${v}L`; 9 | onChange && onChange(s); 10 | }; 11 | 12 | const handleChange = (value) => { 13 | notifyChange(value); 14 | }; 15 | 16 | return ( 17 | 23 | ); 24 | }; 25 | 26 | export default LastWeekDay; 27 | -------------------------------------------------------------------------------- /src/components/LastWorkDay.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import InputNumber from './InputNumber'; 3 | 4 | const LastWorkDay = ({ onChange, value }) => { 5 | const handleChange = (v) =>{ 6 | const s = `${v}W`; 7 | onChange && onChange(s); 8 | }; 9 | 10 | const splits = value.split('W'); 11 | 12 | return ( 13 | 19 | ); 20 | }; 21 | 22 | export default LastWorkDay; 23 | -------------------------------------------------------------------------------- /src/components/MinuteEditor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Radio } from 'antd'; 3 | import Between from './Between'; 4 | import CheckBoxEditor from './CheckBoxEditor'; 5 | import FromEvery from './FromEvery'; 6 | import Reg, { index } from './Reg'; 7 | import BaseEditor from './BaseEditor'; 8 | 9 | const RadioGroup = Radio.Group; 10 | 11 | const defaultRadioKeyValue = {}; 12 | defaultRadioKeyValue[index.EVERY] = '*'; 13 | defaultRadioKeyValue[index.BETWEEN] = '0-59'; 14 | defaultRadioKeyValue[index.FROM_EVERY] = '0/1'; 15 | defaultRadioKeyValue[index.CHECK_BOX] = '*'; 16 | 17 | class MinuteEditor extends BaseEditor{ 18 | state = { 19 | radio: index.EVERY, 20 | value: defaultRadioKeyValue, 21 | }; 22 | 23 | 24 | render() { 25 | const { radioStyle, value: defaultValue, ...config } = this.props; 26 | const { radio, value } = this.state; 27 | return ( 28 | 29 | 30 | 31 | 每分 32 | 33 | 34 | 周期 35 | 42 | 43 | 44 | 52 | 53 | 54 | 指定 55 | 56 | 57 | 58 | ); 59 | } 60 | } 61 | 62 | export default MinuteEditor; 63 | -------------------------------------------------------------------------------- /src/components/MonthEditor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Radio } from 'antd'; 3 | import Between from './Between'; 4 | import CheckBoxEditor from './CheckBoxEditor'; 5 | import FromEvery from './FromEvery'; 6 | import Reg, { index } from './Reg'; 7 | import BaseEditor from './BaseEditor'; 8 | 9 | const RadioGroup = Radio.Group; 10 | 11 | const defaultRadioKeyValue = {}; 12 | defaultRadioKeyValue[index.EVERY] = '*'; 13 | defaultRadioKeyValue[index.BETWEEN] = '1-2'; 14 | defaultRadioKeyValue[index.FROM_EVERY] = '1/1'; 15 | defaultRadioKeyValue[index.CHECK_BOX] = '*'; 16 | 17 | class MonthEditor extends BaseEditor { 18 | state = { 19 | radio: index.EVERY, 20 | value: defaultRadioKeyValue, 21 | }; 22 | 23 | render() { 24 | const { radioStyle, value:defaultValue, ...config } = this.props; 25 | const { radio, value } = this.state; 26 | 27 | return ( 28 | 29 | 30 | 31 | 每月 32 | 33 | 34 | 周期 35 | 36 | 37 | 47 | 48 | 49 | 指定 50 | 51 | 52 | 53 | ); 54 | } 55 | } 56 | 57 | export default MonthEditor; 58 | -------------------------------------------------------------------------------- /src/components/SecondEditor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Radio } from 'antd'; 3 | import Between from './Between'; 4 | import CheckBoxEditor from './CheckBoxEditor'; 5 | import FromEvery from './FromEvery'; 6 | import Reg, { index } from './Reg'; 7 | import BaseEditor from './BaseEditor'; 8 | 9 | const RadioGroup = Radio.Group; 10 | const defaultRadioKeyValue = {}; 11 | defaultRadioKeyValue[index.EVERY] = '*'; 12 | defaultRadioKeyValue[index.BETWEEN] = '0-59'; 13 | defaultRadioKeyValue[index.FROM_EVERY] = '0/1'; 14 | defaultRadioKeyValue[index.CHECK_BOX] = '*'; 15 | 16 | class SecondEditor extends BaseEditor { 17 | state = { 18 | radio: index.EVERY, 19 | value: defaultRadioKeyValue, 20 | }; 21 | 22 | render() { 23 | const { radioStyle, value: defaultValue, ...config } = this.props; 24 | const { radio, value } = this.state; 25 | 26 | return ( 27 | 28 | 29 | 30 | 每秒 31 | 32 | 33 | 周期 34 | 40 | 41 | 42 | 50 | 51 | 52 | 指定 53 | 55 | 56 | 57 | ); 58 | } 59 | } 60 | 61 | export default SecondEditor; 62 | -------------------------------------------------------------------------------- /src/components/WeekDay.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import InputNumber from './InputNumber'; 3 | 4 | const inputNumberStyle = { 5 | margin: '0 5px', 6 | }; 7 | 8 | const WeekDay = ({ value, onChange }) => { 9 | const splits = value.split('#'); 10 | const week = splits[0]; 11 | const weekDay = splits[1]; 12 | 13 | const notifyChange = (week, weekDay) => { 14 | const s = `${week}#${weekDay}`; 15 | onChange && onChange(s); 16 | }; 17 | 18 | const handleWeekChange = (v) => { 19 | notifyChange(v, weekDay); 20 | }; 21 | 22 | const handleWeekDayChange = (v) => { 23 | notifyChange(week, v); 24 | }; 25 | 26 | return ( 27 | 28 | 第 29 | 36 | 周的星期 37 | 44 | 45 | ); 46 | }; 47 | 48 | export default WeekDay; 49 | -------------------------------------------------------------------------------- /src/components/WeekEditor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Radio } from 'antd'; 3 | import Between from './Between'; 4 | import CheckBoxEditor from './CheckBoxEditor'; 5 | import WeekDay from './WeekDay'; 6 | import LastWeekDay from './LastWeekDay'; 7 | import Reg, { index } from './Reg'; 8 | import BaseEditor from './BaseEditor'; 9 | 10 | const RadioGroup = Radio.Group; 11 | 12 | const defaultRadioKeyValue = {}; 13 | defaultRadioKeyValue[index.EVERY] = '*'; 14 | defaultRadioKeyValue[index.ANY] = '?'; 15 | defaultRadioKeyValue[index.BETWEEN] = '1-2'; 16 | defaultRadioKeyValue[index.WEEK_DAY] = '1#1'; 17 | defaultRadioKeyValue[index.LAST_WEEK_DAY] = '1L'; 18 | defaultRadioKeyValue[index.CHECK_BOX] = '*'; 19 | 20 | class WeekEditor extends BaseEditor{ 21 | state = { 22 | radio: index.EVERY, 23 | value: defaultRadioKeyValue, 24 | }; 25 | 26 | render() { 27 | const { radioStyle, value: defaultValue, ...config } = this.props; 28 | const { radio, value } = this.state; 29 | 30 | return ( 31 | 32 | 33 | 34 | 每周 35 | 36 | 37 | 不指定 38 | 39 | 40 | 周期 41 | 42 | 43 | 48 | 49 | 50 | 本月最后一个星期 51 | 52 | 53 | 指定 54 | 55 | 56 | 57 | ); 58 | } 59 | } 60 | 61 | export default WeekEditor; 62 | -------------------------------------------------------------------------------- /src/components/YearEditor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Radio } from 'antd'; 3 | import moment from 'moment'; 4 | import Between from './Between'; 5 | import Reg, { index } from './Reg'; 6 | import BaseEditor from './BaseEditor'; 7 | 8 | const RadioGroup = Radio.Group; 9 | const MIN_YEAR = moment().year(); 10 | const MAX_YEAR = 2099; 11 | 12 | const defaultRadioKeyValue = {}; 13 | defaultRadioKeyValue[index.EVERY] = '*'; 14 | defaultRadioKeyValue[index.BETWEEN] = `${MIN_YEAR}-${MAX_YEAR}`; 15 | class YearEditor extends BaseEditor { 16 | state = { 17 | radio: index.EVERY, 18 | value: defaultRadioKeyValue, 19 | }; 20 | 21 | render() { 22 | const { radioStyle, value:defaultValue, ...config } = this.props; 23 | const { radio, value } = this.state; 24 | 25 | return ( 26 | 27 | 28 | 29 | 每年 30 | 31 | 32 | 周期 33 | 34 | 35 | ); 36 | } 37 | } 38 | 39 | export default YearEditor; 40 | -------------------------------------------------------------------------------- /src/components/reg.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const EVERY = /^\*$/; 4 | const ANY = /^\?$/; 5 | const BETWEEN = /^\d+-\d+$/; 6 | const FROM_EVERY = /^\d+\/\d+$/; 7 | const CHECK_BOX = /^(\*|((\d+,)*\d+))$/; 8 | const LAST_WORK_DAY = /^\d+W$/; 9 | const LAST_MONTH_DAY = /^L$/; 10 | const LAST_WEEK_DAY = /^\d+L$/; 11 | const WEEK_DAY = /^\d+#\d+$/; 12 | 13 | const index = { 14 | EVERY: 'EVERY', 15 | ANY: 'ANY', 16 | BETWEEN: 'BETWEEN', 17 | FROM_EVERY: 'FROM_EVERY', 18 | CHECK_BOX: 'CHECK_BOX', 19 | LAST_WORK_DAY: 'LAST_WORK_DAY', 20 | LAST_MONTH_DAY: 'LAST_MONTH_DAY', 21 | LAST_WEEK_DAY: 'LAST_WEEK_DAY', 22 | WEEK_DAY: 'WEEK_DAY', 23 | }; 24 | 25 | const REG = {}; 26 | REG[index.EVERY] = EVERY; 27 | REG[index.ANY] = ANY; 28 | REG[index.BETWEEN] = BETWEEN; 29 | REG[index.FROM_EVERY] = FROM_EVERY; 30 | REG[index.CHECK_BOX] = CHECK_BOX; 31 | REG[index.LAST_WORK_DAY] = LAST_WORK_DAY; 32 | REG[index.LAST_MONTH_DAY] = LAST_MONTH_DAY; 33 | REG[index.LAST_WEEK_DAY] = LAST_WEEK_DAY; 34 | REG[index.WEEK_DAY] = WEEK_DAY; 35 | 36 | class Reg extends React.Component { 37 | 38 | constructor(props) { 39 | super(props); 40 | const {value, currentIndex, onChange} = props; 41 | this.updateCron(value, currentIndex, onChange) 42 | } 43 | 44 | componentWillReceiveProps(nextProps) { 45 | const {value, currentIndex, onChange} = nextProps; 46 | if(this.value !== value){ 47 | this.value = value; 48 | this.updateCron(value, currentIndex, onChange); 49 | } 50 | } 51 | 52 | updateCron = (cronText, currentIndex, onChange) => { 53 | if(currentIndex && REG[currentIndex].test(cronText)){ 54 | onChange && onChange(currentIndex, cronText); 55 | return; 56 | } 57 | for (const key in REG) { 58 | const reg = REG[key]; 59 | if (reg.test(cronText)) { 60 | onChange && onChange(key, cronText); 61 | return ; 62 | } 63 | } 64 | onChange && onChange(index.EVERY, '*'); 65 | }; 66 | 67 | render() { 68 | return
; 69 | } 70 | }; 71 | 72 | export default Reg; 73 | 74 | export { index }; 75 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Tabs } from 'antd'; 3 | import SecondEditor from './components/SecondEditor'; 4 | import MinuteEditor from './components/MinuteEditor'; 5 | import HourEditor from './components/HourEditor'; 6 | import DayEditor from './components/DayEditor'; 7 | import MonthEditor from './components/MonthEditor'; 8 | import WeekEditor from './components/WeekEditor'; 9 | import YearEditor from './components/YearEditor'; 10 | 11 | const TabPane = Tabs.TabPane; 12 | 13 | const radioStyle = { 14 | display: 'block', 15 | lineHeight: '30px', 16 | padding: '5px', 17 | }; 18 | 19 | const containerStyle = { 20 | padding: '12px 12px', 21 | }; 22 | 23 | class CronEditor extends React.Component { 24 | state = { 25 | cron: [ 26 | '*', 27 | '*', 28 | '*', 29 | '?', 30 | '*', 31 | '?', 32 | ], 33 | }; 34 | 35 | constructor(props) { 36 | super(props); 37 | const { defaultValue } = props; 38 | this.updateCron(defaultValue, false); 39 | } 40 | 41 | componentWillReceiveProps(nextProps) { 42 | const { value } = nextProps; 43 | this.updateCron(value); 44 | } 45 | 46 | updateCron = (cronText, isSet = true) => { 47 | cronText = cronText && cronText.trim(); 48 | if (cronText) { 49 | const { cron } = this.state; 50 | const cronArr = cronText.split(' '); 51 | for (let i = 0; i < cronArr.length; i += 1) { 52 | cron[i] = cronArr[i]; 53 | } 54 | if(cron[3] === '?'){ 55 | if(cron[5] === '?') cron[5] = '*'; 56 | }else { 57 | cron[5] = '?'; 58 | } 59 | isSet ? this.setState({ cron }) : (this.state.cron = cron); 60 | } 61 | }; 62 | 63 | cronChange = (value, index) => { 64 | const { onChange } = this.props; 65 | const { cron } = this.state; 66 | cron[index] = value; 67 | if (index === 3) { 68 | if(value === '?'){ 69 | if(cron[5] === '?') cron[5] = '*'; 70 | }else { 71 | cron[5] = '?'; 72 | } 73 | } else if (index === 5) { 74 | if(value === '?'){ 75 | if(cron[3] === '?') cron[3] = '*'; 76 | }else { 77 | cron[3] = '?'; 78 | } 79 | } 80 | this.setState({ cron }); 81 | const cronText = cron.join(' '); 82 | onChange && onChange(cronText); 83 | }; 84 | 85 | secondChange = (value) => { 86 | this.cronChange(value, 0); 87 | }; 88 | 89 | minuteChange = (value) => { 90 | this.cronChange(value, 1); 91 | }; 92 | 93 | hourChange = (value) => { 94 | this.cronChange(value, 2); 95 | }; 96 | 97 | dayChange = (value) => { 98 | this.cronChange(value, 3); 99 | }; 100 | 101 | monthChange = (value) => { 102 | this.cronChange(value, 4); 103 | }; 104 | 105 | weekChange = (value) => { 106 | this.cronChange(value, 5); 107 | }; 108 | 109 | yearChange = (value) => { 110 | this.cronChange(value, 6); 111 | }; 112 | 113 | render() { 114 | const { style = containerStyle, second, minute, hour, day, month, week, year, defaultValue, value, onChange, ...config } = this.props; 115 | const { cron } = this.state; 116 | return ( 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | ); 141 | } 142 | } 143 | 144 | export default CronEditor; 145 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 3 | 4 | module.exports = { 5 | mode: 'production', 6 | 7 | entry: { 8 | index: './src/index.js' 9 | }, 10 | 11 | output: { 12 | filename: '[name].js', 13 | path: path.resolve(__dirname, "lib"), 14 | libraryTarget: 'commonjs2' 15 | }, 16 | 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.js$/, 21 | exclude: /node_modules/, 22 | loader: 'babel-loader', 23 | query: { 24 | presets: [ 25 | "env", "es2015", "stage-2", "react" 26 | ], 27 | plugins: [ 28 | [ 29 | "import", 30 | {libraryName: "antd", style: 'css'} 31 | ] //antd按需加载 32 | ] 33 | } 34 | }, 35 | { 36 | test: /\.css$/, 37 | use: ['style-loader', 'css-loader'] 38 | } 39 | ] 40 | }, 41 | 42 | plugins: [ 43 | new CleanWebpackPlugin(['lib']) 44 | ] 45 | }; 46 | --------------------------------------------------------------------------------