feat(admin): 深化 TanStack Query 数据层

- 新增 queryKeys.ts 统一 QueryKey 工厂(覆盖全部模块,invalidate/refetch/prefetch 同源)
- 新增 queryClient.ts 全局配置:retry 1、staleTime 30s、gcTime 5min、refetchOnWindowFocus false
- 新增 useApiQuery:zod schema 校验 + 类型收敛 + select 转换,消除页面重复 validateResponse 样板
- useApiMutation 支持 onMutate/onSettled/context(乐观更新)
- 示范迁移:Organizations(useApiQuery + 乐观更新归档/恢复)、Students(useApiQuery + queryKeys + 打开抽屉前 prefetch 档案聚合)
- StudentProfileContent queryKey 统一为 queryKeys.archive.detail,prefetch 可命中缓存
This commit is contained in:
2026-08-08 18:37:55 +08:00
parent 4dd7b5a0b1
commit 9565a0f23c
8 changed files with 310 additions and 63 deletions

View File

@@ -0,0 +1,31 @@
import { useQuery } from '@tanstack/react-query';
import type { QueryKey } from '@tanstack/react-query';
import type { z } from 'zod';
import { validateResponse } from '../utils/validate';
interface UseApiQueryOptions<T, TSelected = T> {
queryKey: QueryKey;
queryFn: () => Promise<unknown>;
/** zod schema响应校验失败会抛出带字段路径的错误由统一错误处理展示 */
schema: z.ZodType<unknown>;
enabled?: boolean;
staleTime?: number;
/** 可选的数据转换React Query select例如列表原始行 → UI 模型 */
select?: (data: T) => TSelected;
}
/**
* useQuery 的类型安全封装queryFn 返回 unknown
* 由 zod schema 校验并收敛为 T消除各页面重复的
* `validateResponse(schema, await api.get(...))` 样板。
*/
export function useApiQuery<T, TSelected = T>(options: UseApiQueryOptions<T, TSelected>) {
const { queryKey, queryFn, schema, enabled, staleTime, select } = options;
return useQuery<T, Error, TSelected>({
queryKey,
enabled,
staleTime,
queryFn: async () => validateResponse<T>(schema, await queryFn()),
select,
});
}