fix(mp): 安全 P0 修复 + 架构 Hook 层补充 + 五专家组分析报告
安全修复: - 提取 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)
This commit is contained in:
65
apps/miniprogram/src/hooks/usePagination.ts
Normal file
65
apps/miniprogram/src/hooks/usePagination.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
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 };
|
||||
}
|
||||
Reference in New Issue
Block a user