202 lines
4.9 KiB
TypeScript
202 lines
4.9 KiB
TypeScript
import { useState, useCallback, useEffect } from 'react';
|
|
import { message, Modal } from 'antd';
|
|
import type { Page } from '@/types/base/page';
|
|
import type { TablePaginationConfig } from 'antd/es/table';
|
|
import type { FilterValue, SorterResult } from 'antd/es/table/interface';
|
|
|
|
// 表格服务接口
|
|
export interface TableService<T, Q = any, C = Partial<T>, U = Partial<T>> {
|
|
list: (params: Q & { pageNum?: number; pageSize?: number }) => Promise<Page<T>>;
|
|
create?: (data: C) => Promise<T>;
|
|
update?: (id: number, data: U) => Promise<T>;
|
|
delete?: (id: number) => Promise<void>;
|
|
}
|
|
|
|
// 表格状态
|
|
interface TableState<T> {
|
|
list: T[];
|
|
pagination: TablePaginationConfig;
|
|
loading: boolean;
|
|
selectedRowKeys?: React.Key[];
|
|
selectedRows?: T[];
|
|
}
|
|
|
|
// 表格配置
|
|
interface TableConfig {
|
|
defaultPageSize?: number;
|
|
selection?: boolean;
|
|
message?: {
|
|
createSuccess?: string;
|
|
updateSuccess?: string;
|
|
deleteSuccess?: string;
|
|
};
|
|
}
|
|
|
|
export function useTableData<
|
|
T extends { id: number },
|
|
Q extends Record<string, any> = any,
|
|
C = any,
|
|
U = any
|
|
>({
|
|
service,
|
|
defaultParams,
|
|
config = {}
|
|
}: {
|
|
service: TableService<T, Q, C, U>;
|
|
defaultParams?: Partial<Q>;
|
|
config?: TableConfig;
|
|
}) {
|
|
// 初始化状态
|
|
const [state, setState] = useState<TableState<T>>({
|
|
list: [],
|
|
pagination: {
|
|
current: 1,
|
|
pageSize: config.defaultPageSize || 10,
|
|
total: 0,
|
|
showSizeChanger: true,
|
|
showQuickJumper: true,
|
|
showTotal: (total) => `共 ${total} 条`
|
|
},
|
|
loading: false
|
|
});
|
|
|
|
// 加载数据
|
|
const loadData = useCallback(async (params?: Partial<Q>) => {
|
|
setState(prev => ({ ...prev, loading: true }));
|
|
try {
|
|
const pageData = await service.list({
|
|
...defaultParams,
|
|
...params,
|
|
pageNum: state.pagination.current,
|
|
pageSize: state.pagination.pageSize
|
|
});
|
|
|
|
setState(prev => ({
|
|
...prev,
|
|
list: pageData.content || [],
|
|
pagination: {
|
|
...prev.pagination,
|
|
total: pageData.totalElements || 0
|
|
},
|
|
loading: false
|
|
}));
|
|
} catch (error) {
|
|
setState(prev => ({ ...prev, loading: false }));
|
|
throw error;
|
|
}
|
|
}, [service, defaultParams, state.pagination]);
|
|
|
|
// 表格变化处理
|
|
const handleTableChange = (
|
|
pagination: TablePaginationConfig,
|
|
filters: Record<string, FilterValue | null>,
|
|
sorter: SorterResult<T> | SorterResult<T>[]
|
|
) => {
|
|
const { current, pageSize } = pagination;
|
|
setState(prev => ({
|
|
...prev,
|
|
pagination: {
|
|
...prev.pagination,
|
|
current,
|
|
pageSize
|
|
}
|
|
}));
|
|
|
|
const params: Record<string, any> = {};
|
|
|
|
// 处理排序
|
|
if (!Array.isArray(sorter)) {
|
|
const { field, order } = sorter;
|
|
if (field && order) {
|
|
params.sortField = field as string;
|
|
params.sortOrder = order === 'ascend' ? 'asc' : 'desc';
|
|
}
|
|
}
|
|
|
|
// 处理筛选
|
|
Object.entries(filters).forEach(([key, value]) => {
|
|
if (value) {
|
|
params[key] = value;
|
|
}
|
|
});
|
|
|
|
loadData(params as Partial<Q>);
|
|
};
|
|
|
|
// 创建
|
|
const handleCreate = async (data: C) => {
|
|
if (!service.create) return false;
|
|
try {
|
|
await service.create(data);
|
|
message.success(config.message?.createSuccess || '创建成功');
|
|
loadData();
|
|
return true;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
// 更新
|
|
const handleUpdate = async (id: number, data: U) => {
|
|
if (!service.update) return false;
|
|
try {
|
|
await service.update(id, data);
|
|
message.success(config.message?.updateSuccess || '更新成功');
|
|
loadData();
|
|
return true;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
// 删除
|
|
const handleDelete = async (id: number) => {
|
|
if (!service.delete) return false;
|
|
return new Promise<boolean>((resolve, reject) => {
|
|
Modal.confirm({
|
|
title: '确认删除',
|
|
content: '确定要删除该记录吗?',
|
|
okText: '确定',
|
|
okType: 'danger',
|
|
cancelText: '取消',
|
|
onOk: async () => {
|
|
try {
|
|
await service.delete(id);
|
|
message.success(config.message?.deleteSuccess || '删除成功');
|
|
loadData();
|
|
resolve(true);
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
},
|
|
onCancel: () => resolve(false)
|
|
});
|
|
});
|
|
};
|
|
|
|
// 选择行
|
|
const handleSelectChange = (selectedRowKeys: React.Key[], selectedRows: T[]) => {
|
|
if (!config.selection) return;
|
|
setState(prev => ({
|
|
...prev,
|
|
selectedRowKeys,
|
|
selectedRows
|
|
}));
|
|
};
|
|
|
|
// 监听分页变化自动加载数据
|
|
useEffect(() => {
|
|
loadData();
|
|
}, [state.pagination.current, state.pagination.pageSize]);
|
|
|
|
return {
|
|
...state,
|
|
loadData,
|
|
handleTableChange,
|
|
handleCreate,
|
|
handleUpdate,
|
|
handleDelete,
|
|
handleSelectChange,
|
|
refresh: () => loadData()
|
|
};
|
|
}
|