Files
SecMPS/gb28181_web-main/app/components/xui/table-query.tsx
T

149 lines
4.0 KiB
TypeScript

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { ColumnsType } from "antd/es/table";
import { forwardRef, useImperativeHandle, useState } from "react";
import { ErrorHandle } from "~/service/config/error";
import { XTable } from "./table";
interface TableQueryProps<T> {
queryKey: string; // 查询key
fetchFn: (params: any) => Promise<any>; // 查询函数
deleteFn?: (id: string) => Promise<any>; // 删除函数
columns: ColumnsType<T>; // 列配置
// 过滤条件/分页
defaultFilters?: {
page: number;
size: number;
[property: string]: any;
};
}
export interface TableQueryRef<T> {
setFilters: (filters: any) => void; // 设置过滤条件
handleAddSuccess: () => void; // 添加成功处理
handleEditSuccess: (item: T) => void; // 编辑成功处理
delMutate: (id: string) => void; // 删除
delIsPending: boolean; // 删除状态
}
export const TableQuery = forwardRef<TableQueryRef<any>, TableQueryProps<any>>(
function TableQuery(
{
queryKey,
fetchFn,
deleteFn,
columns,
defaultFilters = { page: 1, size: 10 },
},
ref,
) {
const [filters, setFilters] = useState(defaultFilters);
const queryClient = useQueryClient();
// 查询数据
const { data, isLoading } = useQuery({
queryKey: [queryKey, filters],
queryFn: () => fetchFn(filters),
refetchInterval: 5000,
throwOnError: (err) => {
ErrorHandle(err);
return true;
},
});
// 删除功能
const { mutate: delMutate, isPending: delIsPending } = useMutation({
mutationFn: deleteFn,
onError: ErrorHandle,
onSuccess: (data) => {
queryClient.setQueryData([queryKey, filters], (old: any) => {
const newItems = old.data.items.filter(
(item: any) => item.id !== data.data.id,
);
// 如果当前页数据为空且不是第一页,回退一页
if (newItems.length === 0 && filters.page > 1) {
setTimeout(() => {
setFilters((prev) => ({ ...prev, page: prev.page - 1 }));
}, 370);
}
// 如果是第一页且数据为空,刷新当前页
else if (newItems.length === 0 && filters.page === 1) {
setTimeout(() => {
queryClient.invalidateQueries({
queryKey: [queryKey, filters],
});
}, 370);
}
return {
...old,
data: {
...old.data,
items: newItems,
},
};
});
},
});
// 添加成功处理
const handleAddSuccess = () => {
if (filters.page !== 1) {
setFilters({ page: 1, size: filters.size });
return;
}
queryClient.invalidateQueries({
queryKey: [queryKey],
});
};
// 编辑成功处理
const handleEditSuccess = (updatedItem: any) => {
queryClient.setQueryData([queryKey, filters], (old: any) => {
if (!old?.data) {
console.log("🚀 ~ queryClient.setQueryData ~ old:", old);
queryClient.invalidateQueries({
queryKey: [queryKey],
});
return old;
}
return {
...old,
data: {
...old.data,
items: old.data.items.map((item: any) =>
item.id === updatedItem.id ? updatedItem : item,
),
},
};
});
};
// 暴露内部方法
useImperativeHandle(ref, () => ({
setFilters,
handleAddSuccess,
handleEditSuccess,
delMutate,
delIsPending,
}));
return (
<XTable
columns={columns}
dataSource={data?.data.items}
loading={isLoading}
rowKey="id"
pagination={{
current: filters.page,
pageSize: filters.size,
total: data?.data.total,
onChange: (page, size) => {
setFilters({ ...filters, page, size });
},
}}
/>
);
},
);