import React, { PureComponent, Fragment, useState, useEffect } from 'react';
import {
Button,
message,
Modal,
Table,
Tag,
Space,
Tooltip,
Dropdown,
Menu,
Typography,
Input,
} from 'antd';
import {
ClockCircleOutlined,
Loading3QuartersOutlined,
CloseCircleOutlined,
FileTextOutlined,
EllipsisOutlined,
PlayCircleOutlined,
CheckCircleOutlined,
EditOutlined,
StopOutlined,
DeleteOutlined,
PauseCircleOutlined,
FieldTimeOutlined,
} from '@ant-design/icons';
import config from '@/utils/config';
import { PageContainer } from '@ant-design/pro-layout';
import { request } from '@/utils/http';
import CronModal from './modal';
import CronLogModal from './logModal';
import { useCtx, useTheme } from '@/utils/hooks';
const { Text } = Typography;
const { Search } = Input;
enum CrontabStatus {
'running',
'idle',
'disabled',
'queued',
}
const CrontabSort: any = { 0: 0, 3: 1, 1: 2, 4: 3 };
enum OperationName {
'启用',
'禁用',
'运行',
'停止',
}
enum OperationPath {
'enable',
'disable',
'run',
'stop',
}
const Crontab = () => {
const columns = [
{
title: '任务名',
dataIndex: 'name',
key: 'name',
align: 'center' as const,
render: (text: string, record: any) => (
{record.name || record._id}
),
sorter: {
compare: (a: any, b: any) => a.name.localeCompare(b.name),
multiple: 2,
},
},
{
title: '任务',
dataIndex: 'command',
key: 'command',
width: '40%',
align: 'center' as const,
render: (text: string, record: any) => {
return (
{text}
);
},
sorter: {
compare: (a: any, b: any) => a.command.localeCompare(b.command),
multiple: 3,
},
},
{
title: '任务定时',
dataIndex: 'schedule',
key: 'schedule',
align: 'center' as const,
sorter: {
compare: (a: any, b: any) => a.schedule.localeCompare(b.schedule),
multiple: 1,
},
},
{
title: '状态',
key: 'status',
dataIndex: 'status',
align: 'center' as const,
width: 60,
render: (text: string, record: any) => (
<>
{(!record.isDisabled || record.status !== CrontabStatus.idle) && (
<>
{record.status === CrontabStatus.idle && (
} color="default">
空闲中
)}
{record.status === CrontabStatus.running && (
}
color="processing"
>
运行中
)}
{record.status === CrontabStatus.queued && (
} color="default">
队列中
)}
>
)}
{record.isDisabled === 1 && record.status === CrontabStatus.idle && (
} color="error">
已禁用
)}
>
),
},
{
title: '操作',
key: 'action',
align: 'center' as const,
render: (text: string, record: any, index: number) => {
const isPc = !isPhone;
return (
{record.status === CrontabStatus.idle && (
{
runCron(record, index);
}}
>
)}
{record.status !== CrontabStatus.idle && (
{
stopCron(record, index);
}}
>
)}
{
setLogCron({ ...record, timestamp: Date.now() });
}}
>
);
},
},
];
const [value, setValue] = useState([]);
const [loading, setLoading] = useState(true);
const [isModalVisible, setIsModalVisible] = useState(false);
const [editedCron, setEditedCron] = useState();
const [searchText, setSearchText] = useState('');
const [isLogModalVisible, setIsLogModalVisible] = useState(false);
const [logCron, setLogCron] = useState();
const [selectedRowIds, setSelectedRowIds] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(20);
const { headerStyle, isPhone } = useCtx();
const getCrons = () => {
setLoading(true);
request
.get(`${config.apiPrefix}crons?searchValue=${searchText}`)
.then((data: any) => {
setValue(
data.data.sort((a: any, b: any) => {
const sortA = a.isDisabled ? 4 : a.status;
const sortB = b.isDisabled ? 4 : b.status;
return CrontabSort[sortA] - CrontabSort[sortB];
}),
);
})
.finally(() => setLoading(false));
};
const addCron = () => {
setEditedCron(null as any);
setIsModalVisible(true);
};
const editCron = (record: any, index: number) => {
setEditedCron(record);
setIsModalVisible(true);
};
const delCron = (record: any, index: number) => {
Modal.confirm({
title: '确认删除',
content: (
<>
确认删除定时任务{' '}
{record.name}
{' '}
吗
>
),
onOk() {
request
.delete(`${config.apiPrefix}crons`, { data: [record._id] })
.then((data: any) => {
if (data.code === 200) {
message.success('删除成功');
const result = [...value];
result.splice(index + pageSize * (currentPage - 1), 1);
setValue(result);
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const runCron = (record: any, index: number) => {
Modal.confirm({
title: '确认运行',
content: (
<>
确认运行定时任务{' '}
{record.name}
{' '}
吗
>
),
onOk() {
request
.put(`${config.apiPrefix}crons/run`, { data: [record._id] })
.then((data: any) => {
if (data.code === 200) {
const result = [...value];
result.splice(index + pageSize * (currentPage - 1), 1, {
...record,
status: CrontabStatus.running,
});
setValue(result);
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const stopCron = (record: any, index: number) => {
Modal.confirm({
title: '确认停止',
content: (
<>
确认停止定时任务{' '}
{record.name}
{' '}
吗
>
),
onOk() {
request
.put(`${config.apiPrefix}crons/stop`, { data: [record._id] })
.then((data: any) => {
if (data.code === 200) {
const result = [...value];
result.splice(index + pageSize * (currentPage - 1), 1, {
...record,
pid: null,
status: CrontabStatus.idle,
});
setValue(result);
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const enabledOrDisabledCron = (record: any, index: number) => {
Modal.confirm({
title: `确认${record.isDisabled === 1 ? '启用' : '禁用'}`,
content: (
<>
确认{record.isDisabled === 1 ? '启用' : '禁用'}
定时任务{' '}
{record.name}
{' '}
吗
>
),
onOk() {
request
.put(
`${config.apiPrefix}crons/${
record.isDisabled === 1 ? 'enable' : 'disable'
}`,
{
data: [record._id],
},
)
.then((data: any) => {
if (data.code === 200) {
const newStatus = record.isDisabled === 1 ? 0 : 1;
const result = [...value];
result.splice(index + pageSize * (currentPage - 1), 1, {
...record,
isDisabled: newStatus,
});
setValue(result);
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const MoreBtn: React.FC<{
record: any;
index: number;
}> = ({ record, index }) => (
action(key, record, index)}>
}>
编辑
) : (
)
}
>
{record.isDisabled === 1 ? '启用' : '禁用'}
{record.isSystem !== 1 && (
}>
删除
)}
}
>
);
const action = (key: string | number, record: any, index: number) => {
switch (key) {
case 'edit':
editCron(record, index);
break;
case 'enableordisable':
enabledOrDisabledCron(record, index);
break;
case 'delete':
delCron(record, index);
break;
default:
break;
}
};
const handleCancel = (cron?: any) => {
setIsModalVisible(false);
if (cron) {
handleCrons(cron);
}
};
const onSearch = (value: string) => {
setSearchText(value);
};
const handleCrons = (cron: any) => {
const index = value.findIndex((x) => x._id === cron._id);
const result = [...value];
if (index === -1) {
result.unshift(cron);
} else {
result.splice(index, 1, {
...cron,
});
}
setValue(result);
};
const getCronDetail = (cron: any) => {
request
.get(`${config.apiPrefix}crons/${cron._id}`)
.then((data: any) => {
const index = value.findIndex((x) => x._id === cron._id);
const result = [...value];
result.splice(index, 1, {
...cron,
...data.data,
});
setValue(result);
})
.finally(() => setLoading(false));
};
const onSelectChange = (selectedIds: any[]) => {
setSelectedRowIds(selectedIds);
};
const rowSelection = {
selectedRowIds,
onChange: onSelectChange,
selections: [
Table.SELECTION_ALL,
Table.SELECTION_INVERT,
Table.SELECTION_NONE,
],
};
const delCrons = () => {
Modal.confirm({
title: '确认删除',
content: <>确认删除选中的定时任务吗>,
onOk() {
request
.delete(`${config.apiPrefix}crons`, { data: selectedRowIds })
.then((data: any) => {
if (data.code === 200) {
message.success('批量删除成功');
setSelectedRowIds([]);
getCrons();
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const operateCrons = (operationStatus: number) => {
Modal.confirm({
title: `确认${OperationName[operationStatus]}`,
content: <>确认{OperationName[operationStatus]}选中的定时任务吗>,
onOk() {
request
.put(`${config.apiPrefix}crons/${OperationPath[operationStatus]}`, {
data: selectedRowIds,
})
.then((data: any) => {
if (data.code === 200) {
getCrons();
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const onPageChange = (page: number, pageSize: number | undefined) => {
setCurrentPage(page);
setPageSize(pageSize as number);
localStorage.setItem('pageSize', pageSize + '');
};
useEffect(() => {
if (logCron) {
localStorage.setItem('logCron', logCron._id);
setIsLogModalVisible(true);
}
}, [logCron]);
useEffect(() => {
getCrons();
}, [searchText]);
useEffect(() => {
setPageSize(parseInt(localStorage.getItem('pageSize') || '20'));
}, []);
return (
,
,
]}
header={{
style: headerStyle,
}}
>
{selectedRowIds.length > 0 && (
已选择
{selectedRowIds?.length}项
)}
`第 ${range[0]}-${range[1]} 条/总共 ${total} 条`,
}}
dataSource={value}
rowKey="_id"
size="middle"
scroll={{ x: 768 }}
loading={loading}
rowSelection={rowSelection}
/>
{
getCronDetail(logCron);
setIsLogModalVisible(false);
}}
cron={logCron}
/>
);
};
export default Crontab;