├── .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 | 
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 |
--------------------------------------------------------------------------------