/** * 统一 QueryKey 工厂。 * * 每个模块一个命名空间,key 由工厂函数生成: * - 避免散落字符串字面量导致拼写不一致、缓存串扰 * - invalidate / refetch / prefetch 与 useQuery 使用同一来源,不会对不上 * * 约定: * - `all` 是该模块的「根 key」,用于整体失效(invalidateQueries 会匹配前缀) * - 列表 key 按过滤条件展开;详情/子资源用固定段 + 参数 */ export const queryKeys = { students: { all: ['students'] as const, list: (filters: { search?: string; status?: string; archived?: boolean; organizationId?: number; classId?: number; teacherId?: number; }) => ['students', filters] as const, organizations: (canView: boolean) => ['students', 'organizations', canView] as const, filterLookups: () => ['students', 'filter-lookups'] as const, }, classes: { all: ['classes'] as const, list: (filters: { status?: string; type?: string; archived?: boolean }) => ['classes', filters] as const, detail: (id: number) => ['classes', 'detail', id] as const, schedule: (id: number, dateRange: unknown) => ['classes', 'schedule', id, dateRange] as const, attendanceSummary: (id: number, dateRange: unknown) => ['classes', 'attendance-summary', id, dateRange] as const, }, classSchedules: { all: ['class-schedules'] as const, list: (params: { startDate?: string; endDate?: string; classroomIds?: unknown[] }) => ['class-schedules', params] as const, }, classrooms: { all: ['classrooms'] as const, list: (archived: boolean) => ['classrooms', archived] as const, }, classroomRentals: { all: ['classroom-rentals'] as const, list: (month?: string) => ['classroom-rentals', month] as const, schedule: (year: number, month: number) => ['classroom-rentals', 'schedule', year, month] as const, meta: () => ['classroom-rentals', 'meta'] as const, }, organizations: { all: ['organizations'] as const, list: () => ['organizations'] as const, options: () => ['organizations', 'options'] as const, }, rbac: { all: ['rbac'] as const, users: (archived: boolean) => ['rbac', 'users', archived] as const, allUsers: () => ['rbac', 'users', 'all'] as const, teachers: (params: { page: number; pageSize: number; search?: string }) => ['rbac', 'teachers', params] as const, teacherWorkspace: () => ['rbac', 'teacher-workspace'] as const, roles: () => ['rbac', 'roles'] as const, permissionTree: () => ['rbac', 'roles', 'permission-tree'] as const, permissionsTree: () => ['rbac', 'permissions', 'tree'] as const, }, expenses: { all: ['expenses'] as const, list: (archived: boolean) => ['expenses', archived ? 'archived' : 'active'] as const, }, expenseTypes: { map: () => ['expense-types', 'map'] as const, }, expenseLookups: { all: ['expense-lookups'] as const, }, bills: { all: ['bills'] as const, list: (filters: { status?: string; expenseType?: string }) => ['bills', filters] as const, }, wallets: { all: ['wallets'] as const, list: (params: { keyword?: string; debtOnly?: boolean; roomType?: string }) => ['wallets', params] as const, transactions: (studentId: number) => ['wallets', 'transactions', studentId] as const, roomTypes: () => ['wallets', 'room-types'] as const, }, deposits: { all: ['deposits'] as const, list: () => ['deposits'] as const, eligible: (roomType?: string) => ['deposits', 'eligible', roomType] as const, }, occupancies: { all: ['occupancies'] as const, list: (params: { viewMode?: string; dateRange?: unknown }) => ['occupancies', params] as const, }, rooms: { all: ['rooms'] as const, overview: (archived: boolean) => ['rooms', 'overview', archived] as const, visual: (params: { historical: boolean; asOf?: unknown }) => ['rooms', 'visual', params] as const, }, exams: { all: ['exams'] as const, detail: (id: number) => ['exams', 'detail', id] as const, classes: () => ['exams', 'classes'] as const, }, operationLogs: { all: ['operation-logs'] as const, list: (params: { page: number; pageSize: number; module?: string; dateRange?: unknown }) => ['operation-logs', params] as const, }, attendance: { all: ['attendance'] as const, workspace: () => ['attendance', 'workspace'] as const, syncStatus: () => ['attendance', 'sync-status'] as const, schedules: (classId: number, date: string) => ['attendance', 'schedules', classId, date] as const, meta: { periods: () => ['attendance', 'meta', 'periods'] as const, classes: () => ['attendance', 'meta', 'classes'] as const, alerts: () => ['attendance', 'meta', 'alerts'] as const, }, }, attendanceDevices: { all: ['attendance-devices'] as const, }, dashboard: { all: ['dashboard'] as const, summary: (period: unknown) => ['dashboard', period] as const, }, integration: { config: () => ['integration', 'config'] as const, }, sync: { jinshujuRules: () => ['sync', 'jinshuju', 'rules'] as const, }, archive: { detail: (studentId: number) => ['archive', studentId] as const, }, ai: { config: () => ['ai', 'config'] as const, }, } as const; export type QueryKeys = typeof queryKeys;