Files
shaguabijia-admin-web/src/lib/usePagedList.ts
T
linkeyu ca7c3f27f0 功能:新增统一限制白名单管理页面 (#99)
## 需求背景
新增统一白名单管理页面,让运营人员能够查看和调整全局限制,并按手机号或设备批量配置临时不限或风险免告警。

## 主要改动
- 新增白名单导航与完整管理页面
- 全局限制按五类分页展示并支持修改
- 白名单按主体聚合,展示各分类数量及悬浮明细
- 支持手机号与设备搜索、批量多选限制项和统一有效期
- 支持手动筛选、十条分页、主体点击编辑及启用开关
- 风控监控增加快捷加入白名单入口
- 旧引导视频配置页与统一限制入口保持一致

## 验证
- Next.js 生产构建通过
- TypeScript 类型检查通过
- 共 26 个页面完成静态/动态构建
- 已与后端 PR #207 配套验证

---------

Co-authored-by: linkeyu <798648091@qq.com>
Reviewed-on: #99
Co-authored-by: linkeyu <linkeyu@wonderable.ai>
Co-committed-by: linkeyu <linkeyu@wonderable.ai>
2026-07-31 17:08:13 +08:00

81 lines
2.3 KiB
TypeScript

'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<T>(
url: string,
filters: Record<string, unknown>,
initialPageSize = 20,
offsetParam: 'cursor' | 'offset' = 'cursor',
) {
const [items, setItems] = useState<T[]>([]);
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,
[offsetParam]: (p - 1) * ps,
};
const { data } = await api.get<CursorPage<T>>(url, { params });
if (requestSeq.current !== seq) return; // 丢弃过期响应(快速切页/筛选)
setItems(data.items);
setTotal(data.total ?? 0);
} finally {
if (requestSeq.current === seq) setLoading(false);
}
},
[url, filtersKey, offsetParam],
);
// 筛选变化:回第 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), // 写操作后刷新当前页
};
}