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;