"use client"; /** * Universal domain API * * 涵盖 7 个 universal widget 的查询函数: * - useGrades / useHomework / useSchedule / useAttendance / useExams * - useNotifications / useAnnouncements * * widget 通过 `import { useGrades } from "@/lib/api"` 调用, * 不再各自内嵌 gql/接口/手写类型。 * * universal domain 全部为查询,无 mutation。 * * 关联:spec §2.2、§5.6 统一 Hook、M8 验收 */ import type { FetchPolicy } from "@apollo/client"; import { GET_GRADES_DOC, GET_HOMEWORKS_DOC, GET_SCHEDULE_DOC, GET_ATTENDANCE_DOC, GET_EXAMS_DOC, GET_NOTIFICATIONS_LIST_DOC, GET_ANNOUNCEMENTS_DOC, } from "@/lib/api/operations/universal.graphql"; import { useWidgetQuery } from "@/lib/useWidgetQuery"; import type { Pagination, UseQueryResult } from "./types"; // ===== 领域模型类型 ===== export interface Grade { studentId: string; score: number; } export interface Homework { id: string; title: string; dueDate: string; status: string; } export interface ScheduleItem { id: string; subject: string; startTime: string; endTime: string; teacherName: string; } export interface AttendanceStats { present: number; absent: number; late: number; total: number; } export interface Exam { id: string; name: string; examDate: string; subject: string; maxScore: number; } export interface Notification { id: string; title: string; body: string; createdAt: string; type: string; } export interface NotificationList { items: Notification[]; total: number; } export interface Announcement { id: string; title: string; body: string; author: string; publishedAt: string; } // ===== 查询选项(透传 useWidgetQuery,但 fallbackData 由本层处理) ===== export interface UniversalQueryOptions { /** 是否启用查询(false 时跳过) */ enabled?: boolean; /** 轮询间隔(ms) */ pollInterval?: number; /** Apollo fetchPolicy */ fetchPolicy?: FetchPolicy; } // ===== 内部 Query 类型(codegen skipDocumentsValidation,用 inline 类型) ===== // 注意:Vars 使用 type alias 而非 interface,以满足 useWidgetQuery 的 // `TVars extends Record` 约束(known-issues §2.17 TS2344)。 interface GradesQueryData { grades: Grade[]; } type GradesQueryVars = { classId: string; }; interface HomeworksQueryData { homeworks: Homework[]; } type HomeworksQueryVars = { classId: string; limit: number; }; interface ScheduleQueryData { schedule: ScheduleItem[]; } type ScheduleQueryVars = { classId: string; dayOfWeek: number; }; interface AttendanceQueryData { attendance: AttendanceStats; } type AttendanceQueryVars = { classId: string; termId: string; }; interface ExamsQueryData { exams: Exam[]; } type ExamsQueryVars = { classId: string; limit: number; }; interface NotificationsListQueryData { notifications: NotificationList; } type NotificationsListQueryVars = { limit: number; offset: number; }; interface AnnouncementsQueryData { announcements: Announcement[]; } type AnnouncementsQueryVars = { limit: number; }; // ===== Hooks ===== /** * 查询班级成绩列表。 * * 关联:portal-shell spec §5.6 统一 Hook、M8 验收 */ export function useGrades( classId: string, options?: UniversalQueryOptions, ): UseQueryResult { const result = useWidgetQuery( GET_GRADES_DOC, { classId }, options, ); return { data: result.data?.grades, loading: result.loading, error: result.error, refetch: result.refetch, }; } /** * 查询班级作业列表,可指定返回条数。 * * 关联:portal-shell spec §5.6 统一 Hook、M8 验收 */ export function useHomework( classId: string, limit: number, options?: UniversalQueryOptions, ): UseQueryResult { const result = useWidgetQuery( GET_HOMEWORKS_DOC, { classId, limit }, options, ); return { data: result.data?.homeworks, loading: result.loading, error: result.error, refetch: result.refetch, }; } /** * 查询班级当日课表(按星期几过滤)。 * * 关联:portal-shell spec §5.6 统一 Hook、M8 验收 */ export function useSchedule( classId: string, dayOfWeek: number, options?: UniversalQueryOptions, ): UseQueryResult { const result = useWidgetQuery( GET_SCHEDULE_DOC, { classId, dayOfWeek }, options, ); return { data: result.data?.schedule, loading: result.loading, error: result.error, refetch: result.refetch, }; } /** * 查询班级学期考勤统计。 * * 关联:portal-shell spec §5.6 统一 Hook、M8 验收 */ export function useAttendance( classId: string, termId: string, options?: UniversalQueryOptions, ): UseQueryResult { const result = useWidgetQuery( GET_ATTENDANCE_DOC, { classId, termId }, options, ); return { data: result.data?.attendance, loading: result.loading, error: result.error, refetch: result.refetch, }; } /** * 查询班级考试列表,可指定返回条数。 * * 关联:portal-shell spec §5.6 统一 Hook、M8 验收 */ export function useExams( classId: string, limit: number, options?: UniversalQueryOptions, ): UseQueryResult { const result = useWidgetQuery( GET_EXAMS_DOC, { classId, limit }, options, ); return { data: result.data?.exams, loading: result.loading, error: result.error, refetch: result.refetch, }; } /** * 查询通知列表(分页),返回 items + total。 * * 关联:portal-shell spec §5.6 统一 Hook、M8 验收 */ export function useNotifications( pagination: Pagination, ): UseQueryResult { const result = useWidgetQuery< NotificationsListQueryData, NotificationsListQueryVars >(GET_NOTIFICATIONS_LIST_DOC, { limit: pagination.limit, offset: pagination.offset, }); return { data: result.data?.notifications, loading: result.loading, error: result.error, refetch: result.refetch, }; } /** * 查询公告列表,可指定返回条数。 * * 关联:portal-shell spec §5.6 统一 Hook、M8 验收 */ export function useAnnouncements( limit: number, ): UseQueryResult { const result = useWidgetQuery( GET_ANNOUNCEMENTS_DOC, { limit }, ); return { data: result.data?.announcements, loading: result.loading, error: result.error, refetch: result.refetch, }; }