/** * GraphQL client + queries/mutations(ARB-001 P2 第一版 schema) * * 维护者:ai13(teacher-portal) * 关联:coord.md §1 ARB-001、02-architecture-design.md §4 * * schema 来源:packages/shared-ts/contracts/graphql/teacher-bff.graphql(ai03 维护) * P2 第一版 Query 范围(ARB-001 §1.2):dashboard / viewports / me / classes / class(5 个) * P2 不包含 Mutation(P3+ 扩展) * * 错误处理(ARB-001 §1.3): * - BFF 始终返回 ActionState 信封(success/errors/data) * - GraphQL errors[].extensions.code = BFF_TEACHER_*(G14 裁决) * - 前端按前缀路由 i18n key(F11: error.teacher_bff.) */ import { createClient, cacheExchange, fetchExchange } from "urql"; import { gql } from "urql"; import type { Client } from "urql"; // ============ Types(对齐 ARB-001 §1.2 schema) ============ export type DataScope = "SELF" | "CLASS" | "GRADE" | "SCHOOL" | "DISTRICT" | "ALL"; export type ExamStatus = "DRAFT" | "PUBLISHED" | "IN_PROGRESS" | "GRADING" | "SCORED" | "ARCHIVED"; export type SubmissionStatus = "NOT_SUBMITTED" | "SUBMITTED" | "GRADED"; export interface User { id: string; email: string; name: string; roles: string[]; dataScope: DataScope; } export interface ViewportItem { key: string; label: string; route: string; icon: string | null; sortOrder: string; requiredPermission: string | null; } export interface Class { id: string; name: string; gradeId: string; studentCount: number; } export interface DashboardStats { totalExams: number; pendingGrading: number; todayHomework: number; } export interface DashboardData { user: User; classes: Class[]; viewports: ViewportItem[]; stats: DashboardStats; } // ============ urql client 单例(总裁 §2.17 方案 A) ============ /** * 创建 urql client 单例 * * Shell(teacher-portal)调用此函数创建 client,通过 GraphQLProvider 注入给所有 Remote。 * token 从 localStorage 读取(F12: P2 用 localStorage,P6 迁移 httpOnly cookie)。 */ export function createGraphQLClient(): Client { const url = process.env.NEXT_PUBLIC_TEACHER_BFF_GRAPHQL_URL || "/api/v1/teacher/graphql"; return createClient({ url, fetchOptions: () => { const headers: Record = { "Content-Type": "application/json", }; // F12: P2 token 存 localStorage if (typeof window !== "undefined") { const token = window.localStorage.getItem("edu_access_token"); if (token) { headers["Authorization"] = `Bearer ${token}`; } } return { headers }; }, exchanges: [cacheExchange, fetchExchange], }); } // ============ P2 Query(ARB-001 §1.2,5 个 Must Have) ============ /** 仪表盘聚合查询(并行:iam.me + iam.viewports + iam.permissions + classes.byTeacher) */ export const DashboardQuery = gql` query Dashboard { dashboard { user { id email name roles dataScope } classes { id name gradeId studentCount } viewports { key label route icon sortOrder requiredPermission } stats { totalExams pendingGrading todayHomework } } } `; /** 视口配置查询(导航) */ export const ViewportsQuery = gql` query Viewports { viewports { key label route icon sortOrder requiredPermission } } `; /** 当前用户信息查询 */ export const MeQuery = gql` query Me { me { id email name roles dataScope } } `; /** 班级列表查询(按教师 dataScope 过滤) */ export const ClassesQuery = gql` query Classes { classes { id name gradeId studentCount } } `; /** 班级详情查询 */ export const ClassQuery = gql` query Class($id: ID!) { class(id: $id) { id name gradeId studentCount } } `; // ============ P3 Query/Mutation(MSW mock,待 teacher-bff P3+ 实现) ============ // 以下查询对应 workline.md §3 P3-P5 交付物,schema 尚未在 ARB-001 P2 第一版中定义。 // 开发期通过 MSW 拦截返回 mock 响应;上游就绪后由 ai03 在 teacher-bff.graphql 扩展。 /** 学生信息(iam 数据,经 teacher-bff 聚合) */ export interface Student { id: string; name: string; email: string; avatarUrl: string | null; } /** 班级学生名单查询(P3 扩展,MSW mock) */ export const ClassStudentsQuery = gql` query ClassStudents($classId: ID!) { classStudents(classId: $classId) { id name email avatarUrl } } `; /** 考试项(core-edu 域) */ export interface ExamItem { id: string; classId: string; title: string; description: string | null; examDate: string; duration: number; totalScore: number; status: ExamStatus; } /** 班级考试列表查询(P3 扩展,MSW mock) */ export const ClassExamsQuery = gql` query ClassExams($classId: ID!) { classExams(classId: $classId) { id classId title description examDate duration totalScore status } } `; /** 作业项(core-edu 域) */ export interface HomeworkItem { id: string; classId: string; title: string; description: string | null; dueDate: string; status: SubmissionStatus; } /** 班级作业列表查询(P3 扩展,MSW mock) */ export const ClassHomeworkQuery = gql` query ClassHomework($classId: ID!) { classHomework(classId: $classId) { id classId title description dueDate status } } `; /** 成绩项(core-edu 域) */ export interface GradeItem { id: string; studentId: string; studentName: string; examId: string | null; homeworkId: string | null; score: number; feedback: string | null; } /** 考试成绩列表查询(P3 扩展,MSW mock) */ export const ExamGradesQuery = gql` query ExamGrades($examId: ID!) { examGrades(examId: $examId) { id studentId studentName examId homeworkId score feedback } } `; /** 更新用户信息 Mutation(P3 扩展,MSW mock) */ export const UpdateUserMutation = gql` mutation UpdateUser($input: UpdateUserInput!) { updateUser(input: $input) { id email name roles dataScope } } `;