import { useState, useCallback, useRef, useEffect } from 'react'; import { message } from 'antd'; interface PaginatedState { data: T[]; total: number; page: number; loading: boolean; } /** * 通用分页数据 Hook,封装 data / total / page / loading / fetch 逻辑。 * * 支持三种签名: * 1. 泛型筛选 (page, pageSize, filters: F) — 带结构化筛选的列表页 * 2. 三参数 (page, pageSize, search: string) — 带搜索的列表页 * 3. 两参数 (page, pageSize) — 纯分页,不含搜索 */ // 重载签名 export function usePaginatedData( fetchFn: (page: number, pageSize: number, filters: F) => Promise<{ data: T[]; total: number }>, options: { pageSize?: number; defaultFilters: F; autoFetch?: boolean }, ): PaginatedResult; export function usePaginatedData( fetchFn: | ((page: number, pageSize: number, search: string) => Promise<{ data: T[]; total: number }>) | ((page: number, pageSize: number) => Promise<{ data: T[]; total: number }>), pageSize?: number, autoFetch?: boolean, ): PaginatedResult; export function usePaginatedData( fetchFn: (...args: any[]) => Promise<{ data: T[]; total: number }>, pageSizeOrOptions?: number | { pageSize?: number; defaultFilters: F; autoFetch?: boolean }, autoFetch = true, ): PaginatedResult { const isOptions = typeof pageSizeOrOptions === 'object' && pageSizeOrOptions !== null; const pageSize = isOptions ? (pageSizeOrOptions as any).pageSize ?? 20 : (pageSizeOrOptions as number) ?? 20; const shouldAutoFetch = isOptions ? (pageSizeOrOptions as any).autoFetch ?? true : autoFetch; const defaultFilters = isOptions ? (pageSizeOrOptions as any).defaultFilters : ('' as unknown as F); const [state, setState] = useState>({ data: [], total: 0, page: 1, loading: false, }); const [searchText, setSearchText] = useState(''); const [filters, setFilters] = useState(defaultFilters); const fetchFnRef = useRef(fetchFn); fetchFnRef.current = fetchFn; const searchTextRef = useRef(searchText); searchTextRef.current = searchText; const filtersRef = useRef(filters); filtersRef.current = filters; const refresh = useCallback( async (p?: number) => { const targetPage = p ?? state.page; setState((s) => ({ ...s, loading: true })); try { const result = await (fetchFnRef.current as any)( targetPage, pageSize, filtersRef.current ?? searchTextRef.current, ); setState({ data: result.data, total: result.total, page: targetPage, loading: false }); } catch { message.error('加载数据失败'); setState((s) => ({ ...s, loading: false })); } }, [pageSize, state.page], ); useEffect(() => { if (shouldAutoFetch) { refresh(1); } }, [shouldAutoFetch, refresh]); return { ...state, searchText, setSearchText, filters, setFilters, refresh }; } interface PaginatedResult extends PaginatedState { searchText: string; setSearchText: (text: string) => void; filters: F; setFilters: (filters: F | ((prev: F) => F)) => void; refresh: (page?: number) => Promise; }