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

@@ -28,6 +28,7 @@ import { message } from '../../ui/app-message';
import { useQuery } from '@tanstack/react-query';
import { useApiMutation } from '../../hooks/useApiMutation';
import { validateResponse } from '../../utils/validate';
import { queryKeys } from '../../api/queryKeys';
import { organizationOptionsSchema, studentProfileAggregateSchema } from '../../api/schemas';
import EditableCell from '../EditableCell';
import { usePermission } from '../../hooks/usePermission';
@@ -481,7 +482,7 @@ const StudentProfileContent: React.FC<StudentProfileContentProps> = ({
isError,
refetch,
} = useQuery<StudentProfileAggregate | null>({
queryKey: ['archive', studentId],
queryKey: queryKeys.archive.detail(studentId),
queryFn: async () => {
return validateResponse<StudentProfileAggregate>(
studentProfileAggregateSchema,
@@ -492,7 +493,7 @@ const StudentProfileContent: React.FC<StudentProfileContentProps> = ({
const { data: organizations = [] } = useQuery<
Array<{ id: number; name: string; isHost?: boolean }>
>({
queryKey: ['organizations', 'options'],
queryKey: queryKeys.organizations.options(),
enabled: canLoadOrganizations,
queryFn: async () => {
try {