'use client'; import { useCallback, useEffect, useRef, useState } from 'react'; import { api } from './api'; import type { CursorPage } from './types'; /** * 页码分页列表 hook(对接后端 offset 分页 + total)。 * 与 useCursorList(「加载更多」)并存:需要页码/跳页/共 N 条的主列表页用本 hook。 * * 约定:后端 cursor 即 offset,本 hook 按 (page-1)*pageSize 计算;CursorPage.total 为符合 * 筛选条件的总条数(供 antd Table pagination 渲染)。filters 变化自动回第 1 页重载。 */ export function usePagedList( url: string, filters: Record, initialPageSize = 20, ) { const [items, setItems] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(initialPageSize); const [loading, setLoading] = useState(false); const requestSeq = useRef(0); const filtersKey = JSON.stringify(filters); const load = useCallback( async (p: number, ps: number) => { const seq = requestSeq.current + 1; requestSeq.current = seq; setLoading(true); try { const params = { ...JSON.parse(filtersKey), limit: ps, cursor: (p - 1) * ps }; const { data } = await api.get>(url, { params }); if (requestSeq.current !== seq) return; // 丢弃过期响应(快速切页/筛选) setItems(data.items); setTotal(data.total ?? 0); } finally { if (requestSeq.current === seq) setLoading(false); } }, [url, filtersKey], ); // 筛选变化:回第 1 页重载 useEffect(() => { setPage(1); load(1, pageSize); // eslint-disable-next-line react-hooks/exhaustive-deps }, [load]); // antd Table pagination.onChange(page, pageSize):页变或每页条数变都走这里 const onChange = (p: number, ps: number) => { if (ps !== pageSize) { // 每页条数变 → 回第 1 页,避免越界空页 setPageSize(ps); setPage(1); load(1, ps); } else { setPage(p); load(p, ps); } }; return { items, total, page, pageSize, loading, onChange, reload: () => load(page, pageSize), // 写操作后刷新当前页 }; }