添加定时任务管理功能

This commit is contained in:
刘倡
2025-07-11 14:50:30 +08:00
parent 32300ccaaa
commit dcdf1e75f1
5 changed files with 1252 additions and 0 deletions

View File

@ -0,0 +1,346 @@
import React, { useEffect, useState } from 'react';
import {
Modal,
Form,
Input,
Select,
Switch,
message,
Row,
Col,
Card,
Tooltip,
Button,
Space,
} from 'antd';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { addTask, editTask, validateCron } from '../service';
const { Option } = Select;
const { TextArea } = Input;
interface TaskFormProps {
visible: boolean;
editingTask?: any;
onCancel: () => void;
onSuccess: () => void;
}
const TaskForm: React.FC<TaskFormProps> = ({
visible,
editingTask,
onCancel,
onSuccess,
}) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [cronValidating, setCronValidating] = useState(false);
const isEdit = !!editingTask;
// 常用Cron表达式示例
const cronExamples = [
{ label: '每分钟执行', value: '0 * * * * ?' },
{ label: '每5分钟执行', value: '0 */5 * * * ?' },
{ label: '每30分钟执行', value: '0 */30 * * * ?' },
{ label: '每小时执行', value: '0 0 * * * ?' },
{ label: '每天凌晨2点执行', value: '0 0 2 * * ?' },
{ label: '每周一凌晨执行', value: '0 0 0 ? * MON' },
{ label: '每月1号凌晨执行', value: '0 0 0 1 * ?' },
];
// 请求方法选项
const requestMethods = [
{ label: 'GET', value: 'GET' },
{ label: 'POST', value: 'POST' },
{ label: 'PUT', value: 'PUT' },
{ label: 'DELETE', value: 'DELETE' },
];
useEffect(() => {
if (visible) {
if (isEdit) {
// 编辑模式,填充表单数据
form.setFieldsValue({
...editingTask,
requestParams: editingTask.requestParams ? JSON.stringify(JSON.parse(editingTask.requestParams), null, 2) : '',
requestHeaders: editingTask.requestHeaders ? JSON.stringify(JSON.parse(editingTask.requestHeaders), null, 2) : '',
});
} else {
// 新增模式,设置默认值
form.setFieldsValue({
status: 1,
requestMethod: 'POST',
requestParams: '{}',
requestHeaders: '{"Content-Type": "application/json"}',
});
}
}
}, [visible, editingTask, isEdit, form]);
// 验证Cron表达式
const handleCronValidate = async () => {
const cronExpression = form.getFieldValue('cronExpression');
if (!cronExpression) {
message.warning('请先输入Cron表达式');
return;
}
setCronValidating(true);
try {
const { success, data } = await validateCron(cronExpression);
if (success) {
message.success('Cron表达式验证通过');
if (data?.nextExecuteTimes) {
Modal.info({
title: '接下来5次执行时间',
content: (
<div>
{data.nextExecuteTimes.map((time: string, index: number) => (
<div key={index}>{time}</div>
))}
</div>
),
});
}
} else {
message.error('Cron表达式格式错误');
}
} catch (error) {
message.error('验证失败');
} finally {
setCronValidating(false);
}
};
// 使用示例Cron表达式
const useCronExample = (cronExpression: string) => {
form.setFieldsValue({ cronExpression });
};
// 表单提交
const handleSubmit = async () => {
try {
const values = await form.validateFields();
// 验证JSON格式
try {
if (values.requestParams) {
JSON.parse(values.requestParams);
}
if (values.requestHeaders) {
JSON.parse(values.requestHeaders);
}
} catch (error) {
message.error('请求参数或请求头必须是有效的JSON格式');
return;
}
setLoading(true);
const { success } = isEdit
? await editTask({ ...values, taskId: editingTask.taskId })
: await addTask(values);
if (success) {
message.success(isEdit ? '修改成功' : '新增成功');
onSuccess();
}
} catch (error) {
console.error('表单提交失败:', error);
} finally {
setLoading(false);
}
};
return (
<Modal
title={isEdit ? '编辑定时任务' : '新增定时任务'}
visible={visible}
onCancel={onCancel}
onOk={handleSubmit}
confirmLoading={loading}
width={800}
destroyOnClose
okText="确定"
cancelText="取消"
>
<Form
form={form}
layout="vertical"
preserve={false}
>
<Row gutter={16}>
<Col span={12}>
<Form.Item
label="任务名称"
name="taskName"
rules={[
{ required: true, message: '请输入任务名称' },
{ max: 100, message: '任务名称不能超过100个字符' },
]}
>
<Input placeholder="请输入任务名称" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="任务状态"
name="status"
valuePropName="checked"
>
<Switch
checkedChildren="启用"
unCheckedChildren="禁用"
onChange={(checked) => form.setFieldsValue({ status: checked ? 1 : 0 })}
/>
</Form.Item>
</Col>
</Row>
<Form.Item
label="任务描述"
name="taskDesc"
rules={[{ max: 500, message: '任务描述不能超过500个字符' }]}
>
<TextArea
rows={3}
placeholder="请输入任务描述"
/>
</Form.Item>
<Card title="Cron配置" size="small" style={{ marginBottom: 16 }}>
<Form.Item
label={
<span>
Cron表达式
<Tooltip title="格式:秒 分 时 日 月 周例如0 0 2 * * ? 表示每天凌晨2点执行">
<QuestionCircleOutlined style={{ marginLeft: 4 }} />
</Tooltip>
</span>
}
name="cronExpression"
rules={[
{ required: true, message: '请输入Cron表达式' },
{
pattern: /^[0-9\*\-\/\,\?\s]+$/,
message: 'Cron表达式格式不正确'
},
]}
>
<Input
placeholder="请输入Cron表达式0 0 2 * * ?"
addonAfter={
<Button
size="small"
loading={cronValidating}
onClick={handleCronValidate}
>
</Button>
}
/>
</Form.Item>
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
</div>
<Space wrap>
{cronExamples.map((example, index) => (
<Button
key={index}
size="small"
type="link"
onClick={() => useCronExample(example.value)}
style={{ padding: '0 4px', height: 'auto' }}
>
{example.label}
</Button>
))}
</Space>
</div>
</Card>
<Card title="接口配置" size="small" style={{ marginBottom: 16 }}>
<Row gutter={16}>
<Col span={12}>
<Form.Item
label="目标服务"
name="targetService"
rules={[
{ required: true, message: '请输入目标服务名称' },
{ max: 100, message: '服务名称不能超过100个字符' },
]}
>
<Input placeholder="如user-service" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="请求方法"
name="requestMethod"
rules={[{ required: true, message: '请选择请求方法' }]}
>
<Select placeholder="请选择请求方法">
{requestMethods.map(method => (
<Option key={method.value} value={method.value}>
{method.label}
</Option>
))}
</Select>
</Form.Item>
</Col>
</Row>
<Form.Item
label="目标接口"
name="targetApi"
rules={[
{ required: true, message: '请输入目标接口路径' },
{ max: 200, message: '接口路径不能超过200个字符' },
]}
>
<Input placeholder="如:/api/user/sync" />
</Form.Item>
<Form.Item
label={
<span>
<Tooltip title="JSON格式的请求参数">
<QuestionCircleOutlined style={{ marginLeft: 4 }} />
</Tooltip>
</span>
}
name="requestParams"
>
<TextArea
rows={4}
placeholder='JSON格式{"type": "sync"}'
/>
</Form.Item>
<Form.Item
label={
<span>
<Tooltip title="JSON格式的请求头信息">
<QuestionCircleOutlined style={{ marginLeft: 4 }} />
</Tooltip>
</span>
}
name="requestHeaders"
>
<TextArea
rows={3}
placeholder='JSON格式{"Content-Type": "application/json"}'
/>
</Form.Item>
</Card>
</Form>
</Modal>
);
};
export default TaskForm;

View File

@ -0,0 +1,216 @@
import React, { useRef, useEffect } from 'react';
import { Modal, Tag, Tooltip } from 'antd';
import ProTable, { ProColumns, ActionType } from '@ant-design/pro-table';
import { getTaskLogs } from '../service';
interface TaskLogModalProps {
visible: boolean;
taskId: string;
onCancel: () => void;
}
const TaskLogModal: React.FC<TaskLogModalProps> = ({
visible,
taskId,
onCancel,
}) => {
const actionRef = useRef<ActionType>();
// 执行状态映射
const statusMap = {
SUCCESS: { text: '成功', color: 'success' },
FAILED: { text: '失败', color: 'error' },
RUNNING: { text: '执行中', color: 'processing' },
};
// 表格列配置
const columns: ProColumns<any>[] = [
{
title: '序号',
valueType: 'index',
width: 50,
},
{
title: '开始时间',
dataIndex: 'startTime',
width: 160,
valueType: 'dateTime',
sorter: true,
},
{
title: '结束时间',
dataIndex: 'endTime',
width: 160,
valueType: 'dateTime',
hideInSearch: true,
},
{
title: '执行耗时(ms)',
dataIndex: 'duration',
width: 120,
hideInSearch: true,
render: (text) => {
if (!text) return '-';
const duration = Number(text);
let color = 'default';
if (duration < 1000) color = 'success';
else if (duration < 5000) color = 'warning';
else color = 'error';
return <Tag color={color}>{duration}</Tag>;
},
},
{
title: '执行状态',
dataIndex: 'executeStatus',
width: 100,
render: (text) => {
const status = statusMap[text as keyof typeof statusMap];
return (
<Tag color={status?.color}>
{status?.text || text}
</Tag>
);
},
valueEnum: {
SUCCESS: { text: '成功', status: 'Success' },
FAILED: { text: '失败', status: 'Error' },
RUNNING: { text: '执行中', status: 'Processing' },
},
},
{
title: '执行结果',
dataIndex: 'executeResult',
width: 200,
hideInSearch: true,
ellipsis: true,
render: (text) => {
if (!text) return '-';
const maxLength = 50;
const displayText = text.length > maxLength ? `${text.substring(0, maxLength)}...` : text;
return (
<Tooltip title={<pre style={{ whiteSpace: 'pre-wrap', maxHeight: 300, overflow: 'auto' }}>{text}</pre>}>
<span style={{ cursor: 'pointer' }}>{displayText}</span>
</Tooltip>
);
},
},
{
title: '错误信息',
dataIndex: 'errorMessage',
width: 200,
hideInSearch: true,
ellipsis: true,
render: (text) => {
if (!text) return '-';
const maxLength = 50;
const displayText = text.length > maxLength ? `${text.substring(0, maxLength)}...` : text;
return (
<Tooltip title={<pre style={{ whiteSpace: 'pre-wrap', maxHeight: 300, overflow: 'auto', color: 'red' }}>{text}</pre>}>
<span style={{ cursor: 'pointer', color: '#ff4d4f' }}>{displayText}</span>
</Tooltip>
);
},
},
{
title: '请求URL',
dataIndex: 'requestUrl',
width: 200,
hideInSearch: true,
ellipsis: true,
render: (text) => {
if (!text) return '-';
return (
<Tooltip title={text}>
<code style={{
background: '#f5f5f5',
padding: '2px 4px',
borderRadius: '3px',
fontSize: '12px'
}}>
{text}
</code>
</Tooltip>
);
},
},
{
title: '响应状态码',
dataIndex: 'responseStatus',
width: 120,
hideInSearch: true,
render: (text) => {
if (!text) return '-';
const status = Number(text);
let color = 'default';
if (status >= 200 && status < 300) color = 'success';
else if (status >= 400 && status < 500) color = 'warning';
else if (status >= 500) color = 'error';
return <Tag color={color}>{text}</Tag>;
},
},
];
// 重新加载数据
useEffect(() => {
if (visible && taskId) {
actionRef.current?.reload();
}
}, [visible, taskId]);
return (
<Modal
title="任务执行日志"
visible={visible}
onCancel={onCancel}
width={1200}
footer={null}
destroyOnClose
>
<ProTable
actionRef={actionRef}
rowKey="logId"
search={{
labelWidth: 80,
defaultCollapsed: false,
collapseRender: false,
}}
request={async (params) => {
const { current, pageSize, ...searchParams } = params;
const response = await getTaskLogs({
taskId,
pageNo: current,
pageSize,
...searchParams,
});
return {
data: response?.data?.records || [],
success: response?.success,
total: response?.data?.total || 0,
};
}}
columns={columns}
scroll={{ x: 1000 }}
pagination={{
defaultPageSize: 10,
showSizeChanger: true,
showQuickJumper: true,
}}
dateFormatter="string"
headerTitle="执行日志列表"
options={{
density: false,
fullScreen: false,
reload: true,
setting: false,
}}
/>
</Modal>
);
};
export default TaskLogModal;

View File

@ -0,0 +1,197 @@
.scheduled-task-page {
.ant-pro-table {
.ant-pro-table-list-toolbar {
padding: 16px 0;
}
}
// 状态开关样式调整
.ant-switch-small {
margin: 0 4px;
}
// Cron表达式代码样式
code {
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Monaco, 'Courier New', monospace;
word-break: break-all;
}
// 表格操作列按钮间距
.ant-pro-table-list-toolbar-container {
.ant-btn + .ant-btn {
margin-left: 8px;
}
}
// 表格内容样式
.ant-table-tbody {
.ant-tag {
margin: 0;
}
.ant-btn-link {
padding: 0 4px;
height: auto;
line-height: 1.2;
}
}
// 模态框内表格样式
.ant-modal-body {
.ant-pro-table {
.ant-pro-table-search {
padding: 16px 0 0 0;
}
}
}
// 任务表单卡片样式
.ant-card {
&.ant-card-small {
.ant-card-head {
border-bottom: 1px solid #f0f0f0;
min-height: 38px;
.ant-card-head-title {
font-size: 14px;
font-weight: 500;
}
}
.ant-card-body {
padding: 16px;
}
}
}
// 表单布局调整
.ant-form-vertical {
.ant-form-item {
margin-bottom: 16px;
&:last-child {
margin-bottom: 0;
}
}
.ant-form-item-label {
padding-bottom: 4px;
label {
font-weight: 500;
.anticon {
color: #1890ff;
cursor: help;
}
}
}
}
// Cron示例按钮样式
.cron-examples {
.ant-btn {
font-size: 12px;
border: none;
padding: 2px 6px;
height: auto;
line-height: 1.4;
&:hover {
background: #f5f5f5;
}
}
}
// 日志弹窗内容样式
.task-log-modal {
.ant-table-cell {
// 日志内容显示样式
pre {
margin: 0;
white-space: pre-wrap;
word-break: break-word;
font-size: 12px;
line-height: 1.4;
}
}
// 状态标签样式
.ant-tag {
border: none;
font-size: 12px;
&.ant-tag-success {
background: #f6ffed;
color: #52c41a;
}
&.ant-tag-error {
background: #fff2f0;
color: #ff4d4f;
}
&.ant-tag-processing {
background: #e6f7ff;
color: #1890ff;
}
}
}
// 响应式样式
@media (max-width: 768px) {
.ant-pro-table {
.ant-table-thead {
th {
font-size: 12px;
padding: 8px 4px;
}
}
.ant-table-tbody {
td {
font-size: 12px;
padding: 8px 4px;
}
}
}
.ant-modal {
margin: 0;
max-width: 100vw;
.ant-modal-content {
border-radius: 0;
}
}
}
// 加载状态样式
.loading-overlay {
position: relative;
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.8);
z-index: 1;
}
}
// 工具提示样式增强
.ant-tooltip {
.ant-tooltip-inner {
max-width: 400px;
pre {
margin: 0;
font-size: 12px;
line-height: 1.4;
}
}
}
}

View File

@ -0,0 +1,405 @@
import React, { useState, useRef, useEffect } from 'react';
import {
message,
Modal,
Button,
Switch,
Tag,
Space,
Popconfirm,
Tooltip,
Input,
InputNumber
} from 'antd';
import ProTable, { ProColumns, ActionType } from '@ant-design/pro-table';
import {
PlusOutlined,
PlayCircleOutlined,
FileTextOutlined,
DeleteOutlined,
EditOutlined
} from '@ant-design/icons';
import {
getTaskList,
deleteTask,
enableTask,
disableTask,
executeTask,
cleanLogs
} from './service';
import TaskForm from './components/TaskForm';
import TaskLogModal from './components/TaskLogModal';
import './index.less';
const ScheduledTask: React.FC = () => {
const actionRef = useRef<ActionType>();
const [taskFormVisible, setTaskFormVisible] = useState(false);
const [logModalVisible, setLogModalVisible] = useState(false);
const [cleanLogsVisible, setCleanLogsVisible] = useState(false);
const [editingTask, setEditingTask] = useState<any>(null);
const [selectedTaskId, setSelectedTaskId] = useState<string>('');
const [cleanDays, setCleanDays] = useState<number>(30);
// 任务状态映射
const statusMap = {
1: { text: '启用', color: 'success' },
0: { text: '禁用', color: 'default' },
};
// 请求方法映射
const methodMap = {
'GET': { text: 'GET', color: 'blue' },
'POST': { text: 'POST', color: 'green' },
'PUT': { text: 'PUT', color: 'orange' },
'DELETE': { text: 'DELETE', color: 'red' },
};
// 表格列配置
const columns: ProColumns<any>[] = [
{
title: '序号',
valueType: 'index',
width: 50,
fixed: 'left',
},
{
title: '任务名称',
dataIndex: 'taskName',
ellipsis: true,
width: 150,
fixed: 'left',
},
{
title: '任务描述',
dataIndex: 'taskDesc',
ellipsis: true,
width: 200,
hideInSearch: true,
},
{
title: 'Cron表达式',
dataIndex: 'cronExpression',
width: 150,
hideInSearch: true,
render: (text) => (
<Tooltip title={text}>
<code style={{
background: '#f5f5f5',
padding: '2px 4px',
borderRadius: '3px',
fontSize: '12px'
}}>
{text}
</code>
</Tooltip>
),
},
{
title: '目标服务',
dataIndex: 'targetService',
width: 120,
hideInSearch: true,
},
{
title: '目标接口',
dataIndex: 'targetApi',
width: 150,
hideInSearch: true,
ellipsis: true,
},
{
title: '请求方法',
dataIndex: 'requestMethod',
width: 100,
hideInSearch: true,
render: (text) => {
const method = methodMap[text as keyof typeof methodMap];
return (
<Tag color={method?.color || 'default'}>
{method?.text || text}
</Tag>
);
},
},
{
title: '状态',
dataIndex: 'status',
width: 80,
hideInSearch: true,
render: (text) => {
const status = statusMap[text as keyof typeof statusMap];
return (
<Tag color={status?.color}>
{status?.text}
</Tag>
);
},
},
{
title: '上次执行时间',
dataIndex: 'lastExecuteTime',
width: 160,
hideInSearch: true,
valueType: 'dateTime',
},
{
title: '下次执行时间',
dataIndex: 'nextExecuteTime',
width: 160,
hideInSearch: true,
valueType: 'dateTime',
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 160,
hideInSearch: true,
valueType: 'dateTime',
},
{
title: '操作',
valueType: 'option',
width: 250,
fixed: 'right',
render: (_, record) => [
<Button
key="edit"
type="link"
size="small"
icon={<EditOutlined />}
onClick={() => handleEdit(record)}
>
</Button>,
<Switch
key="status"
size="small"
checked={record.status === 1}
loading={record.statusLoading}
onChange={(checked) => handleStatusChange(record, checked)}
/>,
<Button
key="execute"
type="link"
size="small"
icon={<PlayCircleOutlined />}
onClick={() => handleExecute(record)}
disabled={record.status === 0}
>
</Button>,
<Button
key="logs"
type="link"
size="small"
icon={<FileTextOutlined />}
onClick={() => handleViewLogs(record)}
>
</Button>,
<Popconfirm
key="delete"
title="确定要删除这个任务吗?"
onConfirm={() => handleDelete(record)}
okText="确定"
cancelText="取消"
>
<Button
type="link"
size="small"
danger
icon={<DeleteOutlined />}
>
</Button>
</Popconfirm>,
],
},
];
// 新增任务
const handleAdd = () => {
setEditingTask(null);
setTaskFormVisible(true);
};
// 编辑任务
const handleEdit = (record: any) => {
setEditingTask(record);
setTaskFormVisible(true);
};
// 删除任务
const handleDelete = async (record: any) => {
try {
const { success } = await deleteTask(record.taskId);
if (success) {
message.success('删除成功');
actionRef.current?.reload();
}
} catch (error) {
message.error('删除失败');
}
};
// 状态切换
const handleStatusChange = async (record: any, checked: boolean) => {
// 设置加载状态
record.statusLoading = true;
actionRef.current?.reload();
try {
const { success } = checked
? await enableTask(record.id)
: await disableTask(record.id);
if (success) {
message.success(checked ? '启用成功' : '禁用成功');
actionRef.current?.reload();
} else {
record.statusLoading = false;
actionRef.current?.reload();
}
} catch (error) {
message.error(checked ? '启用失败' : '禁用失败');
record.statusLoading = false;
actionRef.current?.reload();
}
};
// 执行任务
const handleExecute = async (record: any) => {
try {
const { success } = await executeTask(record.taskId);
if (success) {
message.success('任务执行请求已提交');
}
} catch (error) {
message.error('执行失败');
}
};
// 查看日志
const handleViewLogs = (record: any) => {
setSelectedTaskId(record.taskId);
setLogModalVisible(true);
};
// 清理日志
const handleCleanLogs = async () => {
try {
const { success } = await cleanLogs(cleanDays);
if (success) {
message.success(`已清理${cleanDays}天前的日志`);
setCleanLogsVisible(false);
}
} catch (error) {
message.error('清理失败');
}
};
// 表单提交成功回调
const handleFormSuccess = () => {
setTaskFormVisible(false);
setEditingTask(null);
actionRef.current?.reload();
};
return (
<div className="scheduled-task-page">
<ProTable
headerTitle="定时任务管理"
actionRef={actionRef}
rowKey="taskId"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button
key="clean"
onClick={() => setCleanLogsVisible(true)}
>
</Button>,
<Button
key="add"
type="primary"
icon={<PlusOutlined />}
onClick={handleAdd}
>
</Button>,
]}
request={async (params) => {
const { current, pageSize, ...searchParams } = params;
const response = await getTaskList({
pageNo: current,
pageSize,
...searchParams,
});
return {
data: response?.data?.records || [],
success: response?.success,
total: response?.data?.total || 0,
};
}}
columns={columns}
scroll={{ x: 1400 }}
pagination={{
defaultPageSize: 10,
showSizeChanger: true,
showQuickJumper: true,
}}
/>
{/* 任务表单弹窗 */}
<TaskForm
visible={taskFormVisible}
editingTask={editingTask}
onCancel={() => {
setTaskFormVisible(false);
setEditingTask(null);
}}
onSuccess={handleFormSuccess}
/>
{/* 任务日志弹窗 */}
<TaskLogModal
visible={logModalVisible}
taskId={selectedTaskId}
onCancel={() => {
setLogModalVisible(false);
setSelectedTaskId('');
}}
/>
{/* 清理日志弹窗 */}
<Modal
title="清理执行日志"
visible={cleanLogsVisible}
onOk={handleCleanLogs}
onCancel={() => setCleanLogsVisible(false)}
okText="确定"
cancelText="取消"
>
<div style={{ marginBottom: 16 }}>
<span> </span>
<InputNumber
min={1}
max={365}
value={cleanDays}
onChange={(value) => setCleanDays(value || 30)}
style={{ width: 80 }}
/>
<span> </span>
</div>
<div style={{ color: '#999', fontSize: 12 }}>
</div>
</Modal>
</div>
);
};
export default ScheduledTask;

View File

@ -0,0 +1,88 @@
import request from '@/utils/request';
// 分页查询定时任务
export async function getTaskList(params: any) {
return request('/api/sys/scheduled/task/list', {
method: 'GET',
params,
});
}
// 新增定时任务
export async function addTask(params: any) {
return request('/api/sys/scheduled/task/add', {
method: 'POST',
data: params,
});
}
// 修改定时任务
export async function editTask(params: any) {
return request('/api/sys/scheduled/task/edit', {
method: 'POST',
data: params,
});
}
// 删除定时任务
export async function deleteTask(taskId: string) {
return request('/api/sys/scheduled/task/delete', {
method: 'POST',
data: { taskId },
});
}
// 启用任务
export async function enableTask(taskId: string) {
return request('/api/sys/scheduled/task/enable', {
method: 'POST',
data: { taskId },
});
}
// 禁用任务
export async function disableTask(taskId: string) {
return request('/api/sys/scheduled/task/disable', {
method: 'POST',
data: { taskId },
});
}
// 立即执行任务
export async function executeTask(taskId: string) {
return request('/api/sys/scheduled/task/execute', {
method: 'POST',
data: { taskId },
});
}
// 验证Cron表达式
export async function validateCron(cronExpression: string) {
return request('/api/sys/scheduled/task/validateCron', {
method: 'POST',
data: { cronExpression },
});
}
// 查询任务执行日志
export async function getTaskLogs(params: any) {
return request('/api/sys/scheduled/task/logs', {
method: 'GET',
params,
});
}
// 清理执行日志
export async function cleanLogs(days: number) {
return request('/api/sys/scheduled/task/cleanLogs', {
method: 'POST',
data: { days },
});
}
// 根据ID获取任务详情
export async function getTaskById(taskId: string) {
return request(`/api/sys/scheduled/task/${taskId}`, {
method: 'GET',
});
}