EasyVQD/web/src/components/VqdAlarm.tsx
2026-01-27 10:42:21 +08:00

333 lines
10 KiB
TypeScript

import { useRef, useState, useMemo } from "react";
import { Table, Button, Space, Popconfirm, Flex, message, Tooltip, Select, Row, Col, Empty, Pagination, Tag, Popover } from "antd";
import { EditOutlined, DeleteOutlined, InfoCircleOutlined } from "@ant-design/icons";
import { useQuery, useMutation } from "@tanstack/react-query";
import { GetVqdAlarm, DeleteVqdAlarm, DeleteVqdAlarmAll } from "../api/vqdalarm";
import type { VqdAlarmItem } from "../types/vqdalarm";
import type { ColumnsType } from "antd/es/table";
import { useGlobal } from "../Context";
import { FormatFileSizeToString } from "../utils/rate";
import { formatSecondsToHMS } from "../utils/time";
import Filter from "./Filter";
import AlarmSnap from './Snap';
const variants = ['filled'] as const;
export default function VqdAlarmPage() {
const { ErrorHandle } = useGlobal();
const [pagination, setPagination] = useState({
page: 1,
size: 12,
name: ""
});
const [arrList, setArrList] = useState<any>([{ name: "全部类型", id: 0 }]);
const [templateData, setTemplateData] = useState<VqdAlarmItem[]>([]);
// 获取任务列表
const {
data: storageResponse,
isLoading,
refetch,
} = useQuery({
queryKey: ["storage", pagination],
queryFn: () =>
GetVqdAlarm({ ...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: DeleteVqdAlarm,
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 onAlarmPageChange = (page: number, pageSize?: number) => {
setPagination((prev) => ({
...prev,
page: page,
size: pageSize || prev.size,
}));
}
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: VqdAlarmItem[]
) => {
setSelectedRowKeys([...newSelectedRowKeys]);
},
};
// 批量删除任务
const { mutate: deleteMutationAll, isPending: delAllLoadings } = useMutation({
mutationFn: DeleteVqdAlarmAll,
onSuccess: () => {
message.success("批量删除成功");
refetch()
setSelectedRowKeys([])
},
onError: ErrorHandle,
retry: 0,
});
// 表格列定义
const columns: ColumnsType<VqdAlarmItem> = [
{
title: "名称",
dataIndex: "alarm_name",
align: "center",
},
{
title: "文件名称",
dataIndex: "file_path",
align: "center",
render: (text, record) => (
<Space>
{text}
</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>
<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>
<Popconfirm
title="确定要批量删除文件吗?"
onConfirm={() => {
deleteMutationAll({ ids: selectedRowKeys as number[] })
}}
okText="确定"
cancelText="取消"
>
<Button color="danger" variant="solid" loading={delAllLoadings} disabled={selectedRowKeys.length == 0} >
批量删除
</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,
}}
/> */}
<Flex justify="space-between" className="mr-2" align="center">
<Space className="pl-2">
<Popconfirm
title="确定要批量删除文件吗?"
onConfirm={() => {
const ids = storageResponse?.items.map(item => item.id);
deleteMutationAll({ ids: ids as number[] })
}}
okText="确定"
cancelText="取消"
>
<Button color="danger" variant="solid" loading={delAllLoadings} >
</Button>
</Popconfirm>
</Space>
{/* <DatePicker
defaultDate={moment().format('YYYY-MM-DD')}
moonData={moonReq}
onChangePanel={handleSelectMoon}
onSelectDate={handleSelectDate}
loading={moonLoading}
/> */}
<div className="w-[150px] ml-[20px]">
{/* <Select
defaultValue={0}
className="w-[100%] mr-2"
placeholder="选择类型"
onChange={(v) => {
console.log("类型", v);
}
}
options={arrList.map((item: any) => {
return {
label: item.name,
value: item.id,
};
})}
optionRender={(option) => (
<Space>
<span>
{option.data.label}
</span>
</Space>
)}
/> */}
<Filter
searchLoading={isLoading}
onSearchChange={(value: string) => {
setPagination({ ...pagination, name: value });
}}
/>
</div>
</Flex>
<br />
<Row gutter={[16, 16]} className="pl-2 pr-2">
{storageResponse?.items.map((item) => {
return (
<Col xxl={6} xl={8} lg={12} md={12} sm={12} xs={24} key={item.id} >
<div className="overflow-hidden relative rounded-lg h-full w-full cursor-pointer shadow">
<AlarmSnap filePath={item.file_path} />
<div className="pl-3 pr-2 pb-1">
<Flex align="center" wrap gap="small">
{
item.abnormals.map((item) => {
return (<>
<Tag bordered={false} color="#87d068" className="m-0 mt-2">{item.name}</Tag>
</>)
})
}
</Flex>
<div>
<Space className="pt-2"> :{item.task_name}</Space>
</div>
{/* <Space className="pt-2"> 通道:{item.channel_name || item.channel_id}</Space> */}
<Flex justify="space-between" align="center">
<p className="m-0"> {item.created_at}</p>
<div>
<Popover content={(<>
<div>: {item.channel_name || item.channel_id}</div>
<div>: {item.plan_name}</div>
<div className="pb-2">: {item.task_template_name} </div>
</>)} title="详情">
<Button type="text" icon={<InfoCircleOutlined />}></Button>
</Popover>
<Tooltip title="删除">
<Popconfirm
title="删除告警"
description="确定要删除此告警吗?"
onConfirm={() => {
deleteMutation(item.id)
}}
>
{/* loading={isDelLoading} */}
<Button type="text" danger icon={<DeleteOutlined />}></Button>
</Popconfirm>
</Tooltip>
</div>
</Flex>
</div>
</div>
</Col>
);
})}
{storageResponse?.items.length === 0 && (
<Col span={24}>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
</Col>
)}
</Row>
<Flex justify="flex-end" className="mr-[20px] mt-6 mb-3" align="center">
<Pagination onChange={onAlarmPageChange} defaultCurrent={pagination.page} defaultPageSize={pagination.size} total={storageResponse?.total} />
</Flex>
</div>
);
}