mirror of
https://github.com/whyour/qinglong.git
synced 2025-05-24 07:16:08 +08:00
增加任务详情
This commit is contained in:
parent
c959cec738
commit
634e9705a7
165
src/pages/crontab/detail.tsx
Normal file
165
src/pages/crontab/detail.tsx
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
Modal,
|
||||||
|
message,
|
||||||
|
Input,
|
||||||
|
Form,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Tag,
|
||||||
|
Popover,
|
||||||
|
Divider,
|
||||||
|
} from 'antd';
|
||||||
|
import {
|
||||||
|
ClockCircleOutlined,
|
||||||
|
CloseCircleOutlined,
|
||||||
|
FieldTimeOutlined,
|
||||||
|
Loading3QuartersOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import { CrontabStatus } from './index';
|
||||||
|
import { diffTime } from '@/utils/date';
|
||||||
|
|
||||||
|
const contentList: any = {
|
||||||
|
log: <p>log content</p>,
|
||||||
|
script: <p>script content</p>,
|
||||||
|
};
|
||||||
|
|
||||||
|
const tabList = [
|
||||||
|
{
|
||||||
|
key: 'log',
|
||||||
|
tab: '日志',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'script',
|
||||||
|
tab: '脚本',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const language = navigator.language || navigator.languages[0];
|
||||||
|
|
||||||
|
const CronDetailModal = ({
|
||||||
|
cron = {},
|
||||||
|
handleCancel,
|
||||||
|
visible,
|
||||||
|
}: {
|
||||||
|
cron?: any;
|
||||||
|
visible: boolean;
|
||||||
|
handleCancel: (needUpdate?: boolean) => void;
|
||||||
|
}) => {
|
||||||
|
const [activeTabKey, setActiveTabKey] = useState('log');
|
||||||
|
|
||||||
|
const onTabChange = (key: string) => {
|
||||||
|
setActiveTabKey(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title={
|
||||||
|
<>
|
||||||
|
<span>{cron.name}</span>
|
||||||
|
<Divider type="vertical"></Divider>
|
||||||
|
{cron.labels?.length > 0 &&
|
||||||
|
cron.labels[0] !== '' &&
|
||||||
|
cron.labels?.map((label: string, i: number) => (
|
||||||
|
<Tag color="blue" style={{ marginRight: 5 }}>
|
||||||
|
{label}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
centered
|
||||||
|
visible={visible}
|
||||||
|
forceRender
|
||||||
|
footer={false}
|
||||||
|
onCancel={() => handleCancel()}
|
||||||
|
width={'80vw'}
|
||||||
|
bodyStyle={{ background: '#eee', padding: 12 }}
|
||||||
|
>
|
||||||
|
<div style={{ height: '70vh', overflowY: 'auto' }}>
|
||||||
|
<Card bodyStyle={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||||
|
<div className="cron-detail-info-item">
|
||||||
|
<div className="cron-detail-info-title">状态</div>
|
||||||
|
<div className="cron-detail-info-value">
|
||||||
|
{(!cron.isDisabled || cron.status !== CrontabStatus.idle) && (
|
||||||
|
<>
|
||||||
|
{cron.status === CrontabStatus.idle && (
|
||||||
|
<Tag icon={<ClockCircleOutlined />} color="default">
|
||||||
|
空闲中
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
{cron.status === CrontabStatus.running && (
|
||||||
|
<Tag
|
||||||
|
icon={<Loading3QuartersOutlined spin />}
|
||||||
|
color="processing"
|
||||||
|
>
|
||||||
|
运行中
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
{cron.status === CrontabStatus.queued && (
|
||||||
|
<Tag icon={<FieldTimeOutlined />} color="default">
|
||||||
|
队列中
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{cron.isDisabled === 1 && cron.status === CrontabStatus.idle && (
|
||||||
|
<Tag icon={<CloseCircleOutlined />} color="error">
|
||||||
|
已禁用
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="cron-detail-info-item">
|
||||||
|
<div className="cron-detail-info-title">任务</div>
|
||||||
|
<div className="cron-detail-info-value">{cron.command}</div>
|
||||||
|
</div>
|
||||||
|
<div className="cron-detail-info-item">
|
||||||
|
<div className="cron-detail-info-title">定时</div>
|
||||||
|
<div className="cron-detail-info-value">{cron.schedule}</div>
|
||||||
|
</div>
|
||||||
|
<div className="cron-detail-info-item">
|
||||||
|
<div className="cron-detail-info-title">最后运行时间</div>
|
||||||
|
<div className="cron-detail-info-value">
|
||||||
|
{cron.last_execution_time
|
||||||
|
? new Date(cron.last_execution_time * 1000)
|
||||||
|
.toLocaleString(language, {
|
||||||
|
hour12: false,
|
||||||
|
})
|
||||||
|
.replace(' 24:', ' 00:')
|
||||||
|
: '-'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="cron-detail-info-item">
|
||||||
|
<div className="cron-detail-info-title">最后运行时长</div>
|
||||||
|
<div className="cron-detail-info-value">
|
||||||
|
{cron.last_running_time ? diffTime(cron.last_running_time) : '-'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="cron-detail-info-item">
|
||||||
|
<div className="cron-detail-info-title">下次运行时间</div>
|
||||||
|
<div className="cron-detail-info-value">
|
||||||
|
{cron.nextRunTime &&
|
||||||
|
cron.nextRunTime
|
||||||
|
.toLocaleString(language, {
|
||||||
|
hour12: false,
|
||||||
|
})
|
||||||
|
.replace(' 24:', ' 00:')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
<Card
|
||||||
|
style={{ marginTop: 16 }}
|
||||||
|
tabList={tabList}
|
||||||
|
activeTabKey={activeTabKey}
|
||||||
|
onTabChange={(key) => {
|
||||||
|
onTabChange(key);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{contentList[activeTabKey]}
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CronDetailModal;
|
|
@ -1,3 +1,21 @@
|
||||||
.ant-table-pagination.ant-pagination {
|
.ant-table-pagination.ant-pagination {
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cron {
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cron-detail-info-item {
|
||||||
|
flex: auto;
|
||||||
|
|
||||||
|
.cron-detail-info-title {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cron-detail-info-value {
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ import { PageContainer } from '@ant-design/pro-layout';
|
||||||
import { request } from '@/utils/http';
|
import { request } from '@/utils/http';
|
||||||
import CronModal, { CronLabelModal } from './modal';
|
import CronModal, { CronLabelModal } from './modal';
|
||||||
import CronLogModal from './logModal';
|
import CronLogModal from './logModal';
|
||||||
|
import CronDetailModal from './detail';
|
||||||
import cron_parser from 'cron-parser';
|
import cron_parser from 'cron-parser';
|
||||||
import { diffTime } from '@/utils/date';
|
import { diffTime } from '@/utils/date';
|
||||||
import { getTableScroll } from '@/utils/index';
|
import { getTableScroll } from '@/utils/index';
|
||||||
|
@ -42,7 +43,7 @@ import './index.less';
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
const { Search } = Input;
|
const { Search } = Input;
|
||||||
|
|
||||||
enum CrontabStatus {
|
export enum CrontabStatus {
|
||||||
'running',
|
'running',
|
||||||
'idle',
|
'idle',
|
||||||
'disabled',
|
'disabled',
|
||||||
|
@ -84,7 +85,26 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
goToScriptManager(record);
|
goToScriptManager(record);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{record.name || record._id}{' '}
|
<Popover
|
||||||
|
placement="right"
|
||||||
|
trigger={isPhone ? 'click' : 'hover'}
|
||||||
|
content={
|
||||||
|
<div>
|
||||||
|
{record.labels?.map((label: string, i: number) => (
|
||||||
|
<Tag
|
||||||
|
color="blue"
|
||||||
|
onClick={() => {
|
||||||
|
onSearch(`label:${label}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{record.name || '-'}
|
||||||
|
</Popover>
|
||||||
{record.isPinned ? (
|
{record.isPinned ? (
|
||||||
<span>
|
<span>
|
||||||
<PushpinOutlined />
|
<PushpinOutlined />
|
||||||
|
@ -93,32 +113,6 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
''
|
''
|
||||||
)}
|
)}
|
||||||
</a>
|
</a>
|
||||||
<span>
|
|
||||||
{record.labels?.length > 0 && record.labels[0] !== '' ? (
|
|
||||||
<Popover
|
|
||||||
placement="right"
|
|
||||||
trigger={isPhone ? 'click' : 'hover'}
|
|
||||||
content={
|
|
||||||
<div>
|
|
||||||
{record.labels?.map((label: string, i: number) => (
|
|
||||||
<Tag
|
|
||||||
color="blue"
|
|
||||||
onClick={() => {
|
|
||||||
onSearch(`label:${label}`);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</Tag>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Tag color="blue">{record.labels[0]}</Tag>
|
|
||||||
</Popover>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
sorter: {
|
sorter: {
|
||||||
|
@ -316,7 +310,8 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
{record.status === CrontabStatus.idle && (
|
{record.status === CrontabStatus.idle && (
|
||||||
<Tooltip title={isPc ? '运行' : ''}>
|
<Tooltip title={isPc ? '运行' : ''}>
|
||||||
<a
|
<a
|
||||||
onClick={() => {
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
runCron(record, index);
|
runCron(record, index);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -327,7 +322,8 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
{record.status !== CrontabStatus.idle && (
|
{record.status !== CrontabStatus.idle && (
|
||||||
<Tooltip title={isPc ? '停止' : ''}>
|
<Tooltip title={isPc ? '停止' : ''}>
|
||||||
<a
|
<a
|
||||||
onClick={() => {
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
stopCron(record, index);
|
stopCron(record, index);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -337,7 +333,8 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
)}
|
)}
|
||||||
<Tooltip title={isPc ? '日志' : ''}>
|
<Tooltip title={isPc ? '日志' : ''}>
|
||||||
<a
|
<a
|
||||||
onClick={() => {
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
setLogCron({ ...record, timestamp: Date.now() });
|
setLogCron({ ...record, timestamp: Date.now() });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -354,7 +351,7 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
const [value, setValue] = useState<any[]>([]);
|
const [value, setValue] = useState<any[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||||
const [isLabelModalVisible, setisLabelModalVisible] = useState(false);
|
const [isLabelModalVisible, setIsLabelModalVisible] = useState(false);
|
||||||
const [editedCron, setEditedCron] = useState();
|
const [editedCron, setEditedCron] = useState();
|
||||||
const [searchText, setSearchText] = useState('');
|
const [searchText, setSearchText] = useState('');
|
||||||
const [isLogModalVisible, setIsLogModalVisible] = useState(false);
|
const [isLogModalVisible, setIsLogModalVisible] = useState(false);
|
||||||
|
@ -363,6 +360,8 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [pageSize, setPageSize] = useState(20);
|
const [pageSize, setPageSize] = useState(20);
|
||||||
const [tableScrollHeight, setTableScrollHeight] = useState<number>();
|
const [tableScrollHeight, setTableScrollHeight] = useState<number>();
|
||||||
|
const [isDetailModalVisible, setIsDetailModalVisible] = useState(false);
|
||||||
|
const [detailCron, setDetailCron] = useState<any>();
|
||||||
|
|
||||||
const goToScriptManager = (record: any) => {
|
const goToScriptManager = (record: any) => {
|
||||||
const cmd = record.command.split(' ') as string[];
|
const cmd = record.command.split(' ') as string[];
|
||||||
|
@ -629,7 +628,12 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
arrow
|
arrow
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
overlay={
|
overlay={
|
||||||
<Menu onClick={({ key }) => action(key, record, index)}>
|
<Menu
|
||||||
|
onClick={({ key, domEvent }) => {
|
||||||
|
domEvent.stopPropagation();
|
||||||
|
action(key, record, index);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Menu.Item key="edit" icon={<EditOutlined />}>
|
<Menu.Item key="edit" icon={<EditOutlined />}>
|
||||||
编辑
|
编辑
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
@ -659,7 +663,7 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
</Menu>
|
</Menu>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<a>
|
<a onClick={(e) => e.stopPropagation()}>
|
||||||
<EllipsisOutlined />
|
<EllipsisOutlined />
|
||||||
</a>
|
</a>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
@ -804,7 +808,7 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRowClassName = (record: any, index: number) => {
|
const getRowClassName = (record: any, index: number) => {
|
||||||
return record.isPinned ? 'pinned-cron' : '';
|
return record.isPinned ? 'pinned-cron cron' : 'cron';
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -890,7 +894,7 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => setisLabelModalVisible(true)}
|
onClick={() => setIsLabelModalVisible(true)}
|
||||||
style={{ marginLeft: 8, marginRight: 8 }}
|
style={{ marginLeft: 8, marginRight: 8 }}
|
||||||
>
|
>
|
||||||
批量修改标签
|
批量修改标签
|
||||||
|
@ -912,7 +916,15 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
defaultPageSize: 20,
|
defaultPageSize: 20,
|
||||||
showTotal: (total: number, range: number[]) =>
|
showTotal: (total: number, range: number[]) =>
|
||||||
`第 ${range[0]}-${range[1]} 条/总共 ${total} 条`,
|
`第 ${range[0]}-${range[1]} 条/总共 ${total} 条`,
|
||||||
pageSizeOptions: [10, 20, 50, 100, 200, 500, 1000],
|
pageSizeOptions: [20, 100, 500, 1000] as any,
|
||||||
|
}}
|
||||||
|
onRow={(record) => {
|
||||||
|
return {
|
||||||
|
onClick: (event) => {
|
||||||
|
setDetailCron(record);
|
||||||
|
setIsDetailModalVisible(true);
|
||||||
|
},
|
||||||
|
};
|
||||||
}}
|
}}
|
||||||
dataSource={value}
|
dataSource={value}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
|
@ -938,13 +950,20 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
||||||
<CronLabelModal
|
<CronLabelModal
|
||||||
visible={isLabelModalVisible}
|
visible={isLabelModalVisible}
|
||||||
handleCancel={(needUpdate?: boolean) => {
|
handleCancel={(needUpdate?: boolean) => {
|
||||||
setisLabelModalVisible(false);
|
setIsLabelModalVisible(false);
|
||||||
if (needUpdate) {
|
if (needUpdate) {
|
||||||
getCrons();
|
getCrons();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
ids={selectedRowIds}
|
ids={selectedRowIds}
|
||||||
/>
|
/>
|
||||||
|
<CronDetailModal
|
||||||
|
visible={isDetailModalVisible}
|
||||||
|
handleCancel={() => {
|
||||||
|
setIsDetailModalVisible(false);
|
||||||
|
}}
|
||||||
|
cron={detailCron}
|
||||||
|
/>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user