安全修复: - 提取 sanitizeHtml 共享工具,修复 article/detail RichText XSS 风险 - request.ts 生产环境强制 HTTPS,消除 HTTP 回退风险 - 错误信息净化:后端错误码映射为用户友好消息,不再透传原始内容 - Token 生命周期管理:利用 expires_in 记录过期时间,请求前主动刷新 工程修复: - Babel 依赖从 dependencies 移至 devDependencies(包体积优化) 架构改进: - 新增 usePagination hook(分页加载 + hasMore + refresh,10+ 页面可复用) - 新增 useAuthRequired hook(登录态 + 患者档案 + 角色判断统一入口) - 新增 usePageRefresh hook(下拉刷新统一封装,17 页面可复用) 文档: - 五专家组深度分析+头脑风暴报告(架构7.2/安全5.5/UX6.0/工程5.5/产品7.2)
66 lines
1.8 KiB
TypeScript
66 lines
1.8 KiB
TypeScript
import { useState, useCallback, useRef } from 'react';
|
|
|
|
interface PaginationResult<T> {
|
|
list: T[];
|
|
setList: React.Dispatch<React.SetStateAction<T[]>>;
|
|
loading: boolean;
|
|
hasMore: boolean;
|
|
total: number;
|
|
loadMore: () => Promise<void>;
|
|
refresh: () => Promise<void>;
|
|
}
|
|
|
|
export function usePagination<T>(
|
|
fetcher: (page: number, pageSize: number) => Promise<{ data: T[]; total: number }>,
|
|
pageSize = 10,
|
|
): PaginationResult<T> {
|
|
const [list, setList] = useState<T[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [hasMore, setHasMore] = useState(true);
|
|
const [total, setTotal] = useState(0);
|
|
const pageRef = useRef(1);
|
|
const loadingRef = useRef(false);
|
|
|
|
const loadMore = useCallback(async () => {
|
|
if (loadingRef.current || !hasMore) return;
|
|
loadingRef.current = true;
|
|
setLoading(true);
|
|
try {
|
|
const res = await fetcher(pageRef.current, pageSize);
|
|
const items = res.data || [];
|
|
setList((prev) => [...prev, ...items]);
|
|
setTotal(res.total);
|
|
setHasMore(items.length >= pageSize);
|
|
pageRef.current += 1;
|
|
} catch {
|
|
// 错误由调用方处理
|
|
} finally {
|
|
loadingRef.current = false;
|
|
setLoading(false);
|
|
}
|
|
}, [fetcher, pageSize, hasMore]);
|
|
|
|
const refresh = useCallback(async () => {
|
|
if (loadingRef.current) return;
|
|
loadingRef.current = true;
|
|
setLoading(true);
|
|
pageRef.current = 1;
|
|
setHasMore(true);
|
|
try {
|
|
const res = await fetcher(1, pageSize);
|
|
const items = res.data || [];
|
|
setList(items);
|
|
setTotal(res.total);
|
|
setHasMore(items.length >= pageSize);
|
|
pageRef.current = 2;
|
|
} catch {
|
|
// 错误由调用方处理
|
|
} finally {
|
|
loadingRef.current = false;
|
|
setLoading(false);
|
|
}
|
|
}, [fetcher, pageSize]);
|
|
|
|
return { list, setList, loading, hasMore, total, loadMore, refresh };
|
|
}
|