cron-editor-react
Version:
基于antd、react的crontab表达式生成工具
616 lines (588 loc) • 23 kB
JSX
/**
* 功能:主界面
* 作者:宋鑫鑫
* 日期:2019.11.04
*/
import React, { PureComponent } from "react";
import PropTypes from 'prop-types'
import { Tabs, Dropdown, Row, Col, Input, List, Collapse } from "antd";
import Year from "./components/Year";
import Month from "./components/Month";
import Week from "./components/Week";
import Day from "./components/Day";
import Hour from "./components/Hour";
import Minute from "./components/Minute";
import Second from "./components/Second";
import CronParse from "./parse-lib/index";
import CronParser from "cron-parser";
import moment from "moment";
const { TabPane } = Tabs;
const { Panel } = Collapse;
import "./css/index.less";
const noop = function () { }
const dateMinute = "YYYY-MM-DD HH:mm";
class Cron extends PureComponent {
constructor(props) {
super(props);
const date = new Date();
this.state = {
activeKey: "second",
year: {
type: "",
start: date.getFullYear(),
end: date.getFullYear()
},
month: {
start: 1,
end: 2,
begin: 1,
beginEvery: 1,
type: "*",
some: ['1']
},
week: {
start: 1,
end: 2,
last: 1,
begin: 1,
beginEvery: 1,
type: "?",
some: [1]
},
day: {
last: 1,
closeWorkDay: 1,
start: 1,
end: 2,
begin: 1,
beginEvery: 1,
type: "*",
some: ['1']
},
hour: {
start: 0,
end: 1,
begin: 0,
beginEvery: 1,
type: "*",
some: ['0']
},
minute: {
start: 0,
end: 1,
begin: 0,
beginEvery: 1,
type: "*",
some: ['0']
},
second: {
start: 0,
end: 1,
begin: 0,
beginEvery: 1,
type: "*",
some: ['0']
},
runTime: []
};
}
initValue() {
let { value } = this.props
value = value.toUpperCase()
const valuesArray = value.split(" ");
let newState = { ...this.state };
newState.second.value = valuesArray[0] || "";
newState.minute.value = valuesArray[1] || "";
newState.hour.value = valuesArray[2] || "";
newState.day.value = valuesArray[3] || "";
newState.month.value = valuesArray[4] || "";
newState.week.value = valuesArray[5] || "";
newState.year.value = valuesArray[6] || "";
this.setState(newState, () => {
this.parse();
});
}
componentDidMount(props) {
this.initValue(props);
}
componentDidUpdate(props) {
const { value } = this.props
if (props.value !== value && value) {
this.initValue();
}
}
parse() {
let { year, month, week, day, hour, minute, second } = this.state;
if (year.value.indexOf("-") > -1) {
year.type = "period";
const period = year.value.split("-")[0];
year.start = period[0];
year.end = period[1];
} else {
year.type = year.value;
}
if (week.value.indexOf("-") > -1) {
week.type = "period";
const period = week.value.split("-")[0];
week.start = period[0];
week.end = period[1];
} else if (week.value.indexOf("L") > -1) {
week.type = "last";
week.last = week.value.split("L")[0] || 1;
} else if (week.value.indexOf("#") > -1) {
week.type = "beginInterval";
week.begin = week.value.split("#")[0];
week.beginEvery = week.value.split("#")[1];
} else if (week.value.indexOf(",") > -1 || /^[0-9]+$/.test(week.value)) {
week.type = "some";
week.some = week.value.split(",");
} else {
week.type = week.value || "?";
}
if (month.value.indexOf("-") > -1) {
month.type = "period";
month.start = month.value.split("-")[0];
month.end = month.value.split("-")[1];
} else if (month.value.indexOf("/") > -1) {
month.type = "beginInterval";
month.begin = month.value.split("/")[0];
month.beginEvery = month.value.split("/")[1];
} else if (month.value.indexOf(",") > -1 || /^[0-9]+$/.test(month.value)) {
month.type = "some";
month.some = month.value.split(",");
} else {
month.type = month.value || "?";
}
if (day.value.indexOf("-") > -1) {
day.type = "period";
day.start = day.value.split("-")[0];
day.end = day.value.split("-")[1];
} else if (day.value.indexOf("W") > -1) {
day.type = "closeWorkDay";
day.closeWorkDay = day.value.split("W")[0] || 1;
} else if (day.value.indexOf("L") > -1) {
day.type = "last";
day.last = day.value.split("L")[0] || 1;
} else if (day.value.indexOf("/") > -1) {
day.type = "beginInterval";
day.begin = day.value.split("/")[0];
day.beginEvery = day.value.split("/")[1];
} else if (day.value.indexOf(",") > -1 || /^[0-9]+$/.test(day.value)) {
day.type = "some";
day.some = day.value.split(",");
} else {
day.type = day.value || "?";
}
if (hour.value.indexOf("-") > -1) {
hour.type = "period";
hour.start = hour.value.split("-")[0];
hour.end = hour.value.split("-")[1];
} else if (hour.value.indexOf("/") > -1) {
hour.type = "beginInterval";
hour.begin = hour.value.split("/")[0];
hour.beginEvery = hour.value.split("/")[1];
} else if (hour.value.indexOf(",") > -1 || /^[0-9]+$/.test(hour.value)) {
hour.type = "some";
hour.some = hour.value.split(",");
} else {
hour.type = hour.value || "?";
}
if (minute.value.indexOf("-") > -1) {
minute.type = "period";
minute.start = minute.value.split("-")[0];
minute.end = minute.value.split("-")[1];
} else if (minute.value.indexOf("/") > -1) {
minute.type = "beginInterval";
minute.begin = minute.value.split("/")[0];
minute.beginEvery = minute.value.split("/")[1];
} else if (minute.value.indexOf(",") > -1 || /^[0-9]+$/.test(minute.value)) {
minute.type = "some";
minute.some = minute.value.split(",");
} else {
minute.type = minute.value || "?";
}
if (second.value.indexOf("-") > -1) {
second.type = "period";
second.start = second.value.split("-")[0];
second.end = second.value.split("-")[1];
} else if (second.value.indexOf("/") > -1) {
second.type = "beginInterval";
second.begin = second.value.split("/")[0];
second.beginEvery = second.value.split("/")[1];
} else if (second.value.indexOf(",") > -1 || /^[0-9]+$/.test(second.value)) {
second.type = "some";
second.some = second.value.split(",");
} else {
second.type = second.value || "?";
}
this.setState({
year: { ...year },
month: { ...month },
week: { ...week },
day: { ...day },
hour: { ...hour },
minute: { ...minute },
second: { ...second }
});
console.log("this.state :", this.state);
}
format() {
const { year, month, week, day, hour, minute, second } = this.state;
return `${second.value} ${minute.value} ${hour.value} ${day.value} ${month.value} ${week.value} ${year.value}`;
}
changeState(state) {
this.setState(state, () => {
this.culcCron();
});
}
// 计算用户的cron
culcCron() {
const { n2s } = this;
let { year, month, week, day, hour, minute, second } = this.state;
if (year.type === "period") {
year.value = `${n2s(year.start)}-${n2s(year.end)}`;
} else {
year.value = year.type;
}
if (month.type === "period") {
month.value = `${n2s(month.start)}-${n2s(month.end)}`;
} else if (month.type === "beginInterval") {
month.value = `${n2s(month.begin)}/${n2s(month.beginEvery)}`;
} else if (month.type === "some") {
month.value = month.some.join(",");
} else {
month.value = month.type;
}
if (week.type === "period") {
week.value = `${n2s(week.start)}-${n2s(week.end)}`;
} else if (week.type === "beginInterval") {
week.value = `${n2s(week.begin)}#${n2s(week.beginEvery)}`;
} else if (week.type === "last") {
week.value = n2s(week.last) + "L";
} else if (week.type === "some") {
week.value = week.some.join(",");
} else {
week.value = week.type;
}
if (day.type === "period") {
day.value = `${n2s(day.start)}-${n2s(day.end)}`;
} else if (day.type === "beginInterval") {
day.value = `${n2s(day.begin)}/${n2s(day.beginEvery)}`;
} else if (day.type === "closeWorkDay") {
day.value = n2s(day.closeWorkDay || 1) + "W";
} else if (day.type === "last") {
// day.value = n2s(day.last || 1) + "L";
day.value = "L";
} else if (day.type === "some") {
day.value = day.some.join(",");
} else {
day.value = day.type;
}
if (hour.type === "period") {
hour.value = `${n2s(hour.start)}-${n2s(hour.end)}`;
} else if (hour.type === "beginInterval") {
hour.value = `${n2s(hour.begin)}/${n2s(hour.beginEvery)}`;
} else if (hour.type === "some") {
hour.value = hour.some.join(",");
} else {
hour.value = hour.type;
}
if (minute.type === "period") {
minute.value = `${n2s(minute.start)}-${n2s(minute.end)}`;
} else if (minute.type === "beginInterval") {
minute.value = `${n2s(minute.begin)}/${n2s(minute.beginEvery)}`;
} else if (minute.type === "some") {
minute.value = minute.some.join(",");
} else {
minute.value = minute.type;
}
if (second.type === "period") {
second.value = `${n2s(second.start)}-${n2s(second.end)}`;
} else if (second.type === "beginInterval") {
second.value = `${n2s(second.begin)}/${n2s(second.beginEvery)}`;
} else if (second.type === "some") {
second.value = second.some.join(",");
} else {
second.value = second.type;
}
this.setState(
{
year: { ...year },
month: { ...month },
week: { ...week },
day: { ...day },
hour: { ...hour },
minute: { ...minute },
second: { ...second }
},
() => {
this.triggerChange();
}
);
}
n2s(number) {
if (typeof number === "number" && number !== NaN) {
return `${number}`;
}
return number;
}
triggerChange() {
const { onChange, showRunTime } = this.props
const crontab = this.format();
console.log('crontab', crontab)
onChange && onChange(crontab);
if (!showRunTime) return; // 既然不需要,那就不算了
let tempArr = [];
const weekCron = crontab.split(" ")[5];
try {
if (weekCron !== "?") {
const interval = CronParser.parseExpression(String(crontab).trim());
for (let i = 0; i < 5; i++) {
const temp = moment(interval.next().toString()).format(dateMinute);
tempArr.push(temp);
}
} else {
const cron = new CronParse();
tempArr = cron.expressionChange(String(crontab).trim());
}
} catch (error) {
// console.log("error :", error);
tempArr.push("暂无最新执行周期");
}
if (tempArr.length > 0) {
this.setState({
runTime: tempArr
});
}
}
// 发生表单值改变,重新计算
onChange = (type, value) => {
this.state[type].value = value;
this.setState({ ...this.state }, () => {
this.parse();
});
};
renderOverLay() {
const { activeKey, week, day } = this.state;
const { tabType } = this.props
return (
<Tabs
activeKey={activeKey}
onChange={key => {
this.setState({ activeKey: key });
}}
type={tabType}
>
<TabPane tab="秒" key="second">
<Second
{...this.state}
onChange={state => {
this.changeState({ second: state });
}}
/>
</TabPane>
<TabPane tab="分钟" key="minute">
<Minute
{...this.state}
onChange={state => {
this.changeState({ minute: state });
}}
/>
</TabPane>
<TabPane tab="小时" key="hour">
<Hour
{...this.state}
onChange={state => {
this.changeState({ hour: state });
}}
/>
</TabPane>
<TabPane tab="日" key="day">
<Day
{...this.state}
onChange={state => {
if (week.type === '?' && state.type === '?') {
const obj = { ...week, type: "*" }
console.log('obj', obj)
this.setState({
week: obj
})
} else {
const obj = { ...week, type: "?" }
console.log('obj', obj)
this.setState({
week: obj
})
}
this.changeState({ day: state });
}}
/>
</TabPane>
<TabPane tab="月" key="month">
<Month
{...this.state}
onChange={state => {
this.changeState({ month: state });
}}
/>
</TabPane>
<TabPane tab="周" key="week">
<Week
{...this.state}
onChange={state => {
if (day.type === '?' && state.type === '?') {
const obj = { ...week, type: "*" }
console.log('obj', obj)
this.setState({
day: obj
})
} else {
const obj = { ...week, type: "?" }
console.log('obj', obj)
this.setState({
day: obj
})
}
this.changeState({ week: state });
}}
/>
</TabPane>
<TabPane tab="年" key="year">
<Year
{...this.state}
onChange={state => {
this.changeState({ year: state });
}}
/>
</TabPane>
</Tabs>
);
}
render() {
const state = JSON.parse(JSON.stringify(this.state));
const { year, month, week, day, hour, minute, second, runTime } = state;
const { showRunTime, showCrontab } = this.props
return (
<div className="cron-editor-react">
{this.renderOverLay()}
{
showCrontab && (
<List bordered style={{ marginTop: 10 }} >
<List.Item className="cron-list-type">
<Row type="flex" gutter={5} style={{ width: "100%", textAlign: "center" }}>
<Col span={3}>秒</Col>
<Col span={3}>分</Col>
<Col span={3}>小时</Col>
<Col span={3}>天</Col>
<Col span={3}>月</Col>
<Col span={3}>星期</Col>
<Col span={3}>年</Col>
</Row>
</List.Item>
<List.Item>
<Row type="flex" gutter={5} style={{ width: "100%", textAlign: "center" }}>
<Col span={3}>
<Input
value={second.value}
onChange={e => {
this.onChange("second", e.target.value);
}}
disabled
/>
</Col>
<Col span={3}>
<Input
value={minute.value}
onChange={e => {
this.onChange("minute", e.target.value);
}}
disabled
/>
</Col>
<Col span={3}>
<Input
value={hour.value}
onChange={e => {
this.onChange("hour", e.target.value);
}}
disabled
/>
</Col>
<Col span={3}>
<Input
value={day.value}
onChange={e => {
this.onChange("day", e.target.value);
}}
disabled
/>
</Col>
<Col span={3}>
<Input
value={month.value}
onChange={e => {
this.onChange("month", e.target.value);
}}
disabled
/>
</Col>
<Col span={3}>
<Input
value={week.value}
onChange={e => {
this.onChange("week", e.target.value);
}}
disabled
/>
</Col>
<Col span={3}>
<Input
value={year.value}
onChange={e => {
this.onChange("year", e.target.value);
}}
disabled
/>
</Col>
</Row>
</List.Item>
</List>
)
}
{
showRunTime
&& (
<Collapse>
<Panel header="近5次执行时间" key="1">
<List
bordered
dataSource={runTime}
renderItem={(item, index) => (
<List.Item>
第{index + 1}执行时间: {item}
</List.Item>
)}
/>
</Panel>
</Collapse>
)
}
</div>
);
}
}
Cron.propTypes = {
onChange: PropTypes.func,
showRunTime: PropTypes.bool,
value: PropTypes.string,
tabType: PropTypes.string,
showCrontab: PropTypes.bool
}
Cron.defaultProps = {
onChange: noop,
showRunTime: false,
value: '0 0 0 * * ?',
tabType: 'line',
showCrontab: true
}
export default Cron;