EasyVQD/web/src/components/VqdTask.tsx
2026-01-28 14:00:33 +08:00

279 lines
7.3 KiB
TypeScript

import { useRef, useState, useMemo } from "react";
import { Table, Button, Space, Popconfirm, Flex, message, Tooltip, Switch, Popover, Tag } from "antd";
import { EditOutlined, DeleteOutlined, PlusOutlined } from "@ant-design/icons";
import { useQuery, useMutation } from "@tanstack/react-query";
import { GetVqdTask, DeleteVqdTask, UpdateVqdTask } from "../api/vqdtask";
import type { VqdTaskItem, CreateVqdTaskReq } from "../types/vqdtask";
import type { ColumnsType } from "antd/es/table";
import AddVqdTask, { AddVqdTaskRef } from "./AddVqdTask";
import { useGlobal } from "../Context";
import { FormatFileSizeToString } from "../utils/rate";
import { formatSecondsToHMS } from "../utils/time";
import Filter from "./Filter";
export default function VqdTaskPage() {
const { ErrorHandle } = useGlobal();
const dialogRef = useRef<AddVqdTaskRef>(null);
const [pagination, setPagination] = useState({
page: 1,
size: 10,
name: ""
});
// 获取任务列表
const {
data: storageResponse,
isLoading,
refetch,
} = useQuery({
queryKey: ["storage", pagination],
queryFn: () =>
GetVqdTask({ ...pagination })
.then((res) => res.data)
.catch((err) => {
ErrorHandle(err);
throw err;
}),
// refetchInterval: 4000,
retry: 2,
});
// 删除任务
const [delLoadings, setDelLoadings] = useState<number[]>([]);
const { mutate: deleteMutation } = useMutation({
mutationFn: DeleteVqdTask,
onMutate: (id: number) => {
setDelLoadings((prev) => [...prev, id]);
},
onSuccess: (_, ctx) => {
setDelLoadings((prev) => prev.filter((item) => item !== ctx));
message.success("删除成功");
refetch();
},
onError: (error: Error, ctx) => {
setDelLoadings((prev) => prev.filter((item) => item !== ctx));
ErrorHandle(error);
},
});
// 打开新增模态框
const handleAdd = () => {
dialogRef.current?.open();
};
// 打开编辑模态框
const handleEdit = (disk: VqdTaskItem) => {
dialogRef.current?.open(disk);
};
// 处理分页变化
const handleTableChange = (page: number, pageSize?: number) => {
setPagination((prev) => ({
...prev,
page: page,
size: pageSize || prev.size,
}));
};
// 客户端分页数据
const dataSource = useMemo(() => {
const items = storageResponse?.items || [];
const start = (pagination.page - 1) * pagination.size;
const end = start + pagination.size;
return items.slice(start, end);
}, [storageResponse, pagination]);
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const rowSelection = {
selectedRowKeys,
onChange: (
newSelectedRowKeys: React.Key[],
selectedRows: VqdTaskItem[]
) => {
setSelectedRowKeys([...newSelectedRowKeys]);
},
};
const { mutate: updateMutate } = useMutation({
mutationFn: UpdateVqdTask,
onSuccess: () => {
message.success("更新成功");
setTimeout(() => {
refetch()
}, 500);
},
onError: ErrorHandle,
});
const saveTemplate = (disk: VqdTaskItem, t: boolean) => {
const payload = disk as CreateVqdTaskReq;
payload.enable = t
updateMutate({ id: String(disk.id), ...payload })
};
// 表格列定义
const columns: ColumnsType<VqdTaskItem> = [
{
title: "诊断任务",
dataIndex: "name",
align: "center",
},
{
title: "关联通道",
dataIndex: "channel_name",
align: "center",
render: (text, record) => (
<Space>
{text}
</Space>
),
},
{
title: "诊断参数",
dataIndex: "task_template_name",
align: "center",
render: (text, record) => (
<Space>
{text}
</Space>
),
},
{
title: "诊断时间",
dataIndex: "time_template_name",
align: "center",
render: (text, record) => (
<Space>
{text}
</Space>
),
},
{
title: "状态",
dataIndex: "status",
align: "center",
render: (text, record) => (
<Space>
{text == 0 && <Tag color="#ccc"></Tag>}
{text == 1 && <Tag color="#87d068"></Tag>}
{text == 2 &&
<Popover content={
<>
{record.error_msg}
</>
} title="异常详情">
<Tag color="#f50"></Tag>
</Popover>
}
</Space>
),
},
{
title: "启用",
dataIndex: "enable",
align: "center",
render: (text, record) => (
<Space>
<Switch value={text} defaultChecked onChange={(t) => {
saveTemplate(record, t)
}} />
</Space>
),
},
{
title: "描述",
dataIndex: "des",
align: "center",
},
{
title: "创建日期",
dataIndex: "created_at",
align: "center",
render: (text: string) => (text ? new Date(text).toLocaleString() : "-"),
},
{
title: "操作",
align: "center",
width: 120,
fixed: "right",
render: (_, record) => (
<Space>
<Tooltip placement="top" title="编辑" color="#fff">
<Button icon={<EditOutlined />} onClick={() => handleEdit(record)} />
</Tooltip>
<Popconfirm
title="确定要删除这个任务吗?"
onConfirm={() => {
if (record.id) {
deleteMutation(record.id);
}
}}
okText="确定"
cancelText="取消"
>
<Button
loading={delLoadings.includes(record.id)}
danger
icon={<DeleteOutlined />}
/>
</Popconfirm>
</Space>
),
},
];
return (
<div>
<Flex justify="space-between" align="center" className="mb-4">
<Space>
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
</Button>
{/* <Popconfirm
title="确定要批量删除文件吗?"
onConfirm={() => {
}}
okText="确定"
cancelText="取消"
>
<Button color="danger" variant="solid">
批量删除
</Button>
</Popconfirm> */}
</Space>
<Filter
searchLoading={isLoading}
onSearchChange={(value: string) => {
setPagination({ ...pagination, name: value });
}}
/>
</Flex>
{/* 表格 */}
<Table
columns={columns}
// rowSelection={rowSelection}
dataSource={storageResponse?.items}
rowKey="id"
loading={isLoading}
scroll={{ x: "max-content" }}
pagination={{
current: pagination.page,
pageSize: pagination.size,
total: storageResponse?.total || 0,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `${total}`,
onChange: handleTableChange,
onShowSizeChange: handleTableChange,
}}
/>
{/* 编辑模态框 */}
<AddVqdTask
ref={dialogRef}
title="添加/编辑诊断任务"
onSuccess={() => refetch()}
/>
</div>
);
}