Files
Edu/apps/teacher-portal/src/lib/graphql-p7-advanced.ts
SpecialX d49d211425 feat(teacher-portal): 完成参考项目差距闭环 P3-P7 全量实现
- P3 考试/作业/成绩 mutation + 详情页 + 批改界面 + 乐观更新 + 多 Tab 同步
- P4 知识图谱 SVG 可视化 + 学情分析仪表盘 + parent-portal Remote
- P5 WebSocket 通知中心 + AI 出题(SSE) + AI 教案 + AI 学情报告
- P6 可观测性硬化:Sentry + WebVitals + OTel + A11y + 性能配置 + Cookie 迁移
- P7 参考项目差距闭环:新增 35 个页面覆盖 13 个缺失模块
  - attendance(考勤 4 页)/questions(题库)/textbooks(教材 2 页)
  - classes/[id] 详情 + classes/schedule 课表
  - course-plans(2 页)/diagnostic(2 页)/error-book/practice
  - exams/[id]/build 组卷 + exams/[id]/analytics 考后分析
  - exams/[id]/edit-rich 富文本编辑 + exams/[id]/proctoring 监考
  - grades/entry 批量录入 + grades/stats 统计 + grades/analytics 分析 + grades/report-card 报告卡
  - homework/submissions 列表 + assignments/[id]/submissions 批量批改
  - homework/submissions/[submissionId] 单份批改 + scan-grading 扫描批改
  - lesson-plans 编辑器 + library + calendar + heatmap 5 页
  - elective 选修课 3 页 /leave 请假 /schedule-changes 调课
- P7 基础设施:61 GraphQL operations + 5 handlers + 13 fixtures + 11 viewports
- 集成 browser.ts/server.ts 注册所有 p7 handlers(fallthrough 顺序)
- viewports.ts 扩展 11 个新导航项
- 验证:tsc --noEmit 零错误 + eslint 零错误
- 文档:workline.md 新增 §5 P7 参考项目差距闭环(含完整文件清单)
2026-07-13 14:27:04 +08:00

500 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* GraphQL operations - P7 扩展(选修课 + 富文本编辑 + 监考 + 扫描批改 + 课标热力图)
*
* 维护者ai13teacher-portal
* 关联graphql.ts P2/P3 扩展、workline.md §3 P7 交付物
*
* schema 尚未在 ARB-001 P2 第一版中定义,开发期通过 MSW 拦截返回 mock 响应;
* 上游就绪后由 ai03 在 teacher-bff.graphql 扩展,届时合并本文件到 graphql.ts。
*
* 查询范围P7-advanced
* - ElectiveCourses / ElectiveCourseDetail选修课列表 + 详情
* - CreateElectiveCourse / UpdateElectiveCourse / PublishElectiveCourse / CancelElectiveCourse
* - ExamRichEditor / SaveExamRichContent富文本试卷内容
* - ProctoringStatus / ProctoringEvent监考状态 + 事件
* - SubmissionScanGrading / SaveScanGrading扫描批改
* - LessonPlanHeatmap课标覆盖热力图
*/
import { gql } from "urql";
// ============ Types选修课 ============
/** 选修课状态 */
export type ElectiveCourseStatus =
| "draft"
| "open"
| "closed"
| "cancelled";
/** 选课学生项 */
export interface ElectiveStudent {
studentId: string;
studentName: string;
studentNo: string;
enrolledAt: string;
status: "enrolled" | "cancelled";
}
/** 选修课列表项 */
export interface ElectiveCourseItem {
id: string;
title: string;
subject: string;
grade: string;
capacity: number;
enrolledCount: number;
teacherId: string;
teacherName: string;
semester: string;
status: ElectiveCourseStatus;
description: string | null;
}
/** 选修课详情(含学生列表) */
export interface ElectiveCourseDetail extends ElectiveCourseItem {
students: ElectiveStudent[];
createdAt: string;
updatedAt: string;
}
/** 创建选修课输入 */
export interface CreateElectiveCourseInput {
title: string;
subject: string;
grade: string;
capacity: number;
semester: string;
description?: string | null;
}
/** 更新选修课输入 */
export interface UpdateElectiveCourseInput {
id: string;
title?: string;
subject?: string;
grade?: string;
capacity?: number;
semester?: string;
description?: string | null;
}
/** 创建/更新结果 */
export interface ElectiveCourseMutationResult {
id: string;
status: ElectiveCourseStatus;
updatedAt: string;
}
// ============ Types富文本编辑 ============
/** 富文本试卷内容Tiptap examNodes JSON 结构mock 用 JSON */
export interface ExamRichContent {
examId: string;
title: string;
totalScore: number;
questionCount: number;
content: unknown; // Tiptap JSON结构由编辑器决定
updatedAt: string;
}
/** 保存富文本输入 */
export interface SaveExamRichContentInput {
examId: string;
content: unknown;
}
/** 保存富文本结果 */
export interface SaveExamRichContentResult {
examId: string;
updatedAt: string;
}
// ============ Types监考 ============
/** 监考学生状态 */
export type ProctoringStudentStatus =
| "online"
| "offline"
| "submitted"
| "flagged";
/** 监考摘要 */
export interface ProctoringSummary {
examId: string;
expectedCount: number;
onlineCount: number;
submittedCount: number;
flaggedCount: number;
isProctoring: boolean;
startedAt: string | null;
}
/** 监考学生状态项 */
export interface ProctoringStudent {
studentId: string;
studentName: string;
studentNo: string;
status: ProctoringStudentStatus;
lastEventAt: string | null;
ipAddress: string | null;
}
/** 监考事件类型 */
export type ProctoringEventType = "WARNING" | "FLAG" | "NOTE";
/** 监考事件项 */
export interface ProctoringEvent {
eventId: string;
examId: string;
studentId: string;
studentName: string;
studentNo: string;
eventType: ProctoringEventType;
note: string | null;
createdAt: string;
}
/** 监考状态完整结构 */
export interface ProctoringStatus {
summary: ProctoringSummary;
students: ProctoringStudent[];
recentEvents: ProctoringEvent[];
}
/** 提交监考事件输入 */
export interface ProctoringEventInput {
examId: string;
studentId: string;
eventType: ProctoringEventType;
note?: string | null;
}
/** 提交监考事件结果 */
export interface ProctoringEventResult {
eventId: string;
createdAt: string;
}
// ============ Types扫描批改 ============
/** 扫描图片项 */
export interface ScanImage {
imageId: string;
url: string;
page: number;
}
/** 扫描批改单题项 */
export interface ScanGradingItem {
questionId: string;
questionTitle: string;
questionOrder: number;
maxScore: number;
recognizedAnswer: string;
aiSuggestedScore: number | null;
aiSuggestion: string | null;
score: number | null;
feedback: string | null;
}
/** 扫描批改视图 */
export interface SubmissionScanGrading {
submissionId: string;
homeworkTitle: string;
studentName: string;
studentNo: string;
submittedAt: string;
images: ScanImage[];
items: ScanGradingItem[];
prevSubmissionId: string | null;
nextSubmissionId: string | null;
}
/** 保存扫描批改单项 */
export interface SaveScanGradingItem {
questionId: string;
score: number;
feedback?: string | null;
}
/** 保存扫描批改输入 */
export interface SaveScanGradingInput {
submissionId: string;
items: SaveScanGradingItem[];
}
/** 保存扫描批改结果 */
export interface SaveScanGradingResult {
submissionId: string;
totalScore: number;
savedAt: string;
}
// ============ Types课标热力图 ============
/** 热力图知识点项 */
export interface HeatmapKnowledgePoint {
kpId: string;
name: string;
chapterName: string;
}
/** 热力图课案项 */
export interface HeatmapLessonPlan {
planId: string;
title: string;
}
/** 热力图覆盖矩阵单元格 */
export interface HeatmapCell {
kpId: string;
planId: string;
coverage: number; // 0-3 覆盖课案数
}
/** 课标覆盖热力图 */
export interface LessonPlanHeatmap {
textbookId: string;
textbookTitle: string;
knowledgePoints: HeatmapKnowledgePoint[];
lessonPlans: HeatmapLessonPlan[];
cells: HeatmapCell[];
}
// ============ Queries / Mutations选修课 ============
/** 选修课列表查询(按状态筛选,教师范围) */
export const ElectiveCoursesQuery = gql`
query ElectiveCourses($status: String, $subject: String) {
electiveCourses(status: $status, subject: $subject) {
id
title
subject
grade
capacity
enrolledCount
teacherId
teacherName
semester
status
description
}
}
`;
/** 选修课详情查询(含学生列表) */
export const ElectiveCourseDetailQuery = gql`
query ElectiveCourseDetail($id: ID!) {
electiveCourseDetail(id: $id) {
id
title
subject
grade
capacity
enrolledCount
teacherId
teacherName
semester
status
description
students {
studentId
studentName
studentNo
enrolledAt
status
}
createdAt
updatedAt
}
}
`;
/** 创建选修课 Mutation */
export const CreateElectiveCourseMutation = gql`
mutation CreateElectiveCourse($input: CreateElectiveCourseInput!) {
createElectiveCourse(input: $input) {
id
status
updatedAt
}
}
`;
/** 更新选修课 Mutation */
export const UpdateElectiveCourseMutation = gql`
mutation UpdateElectiveCourse($input: UpdateElectiveCourseInput!) {
updateElectiveCourse(input: $input) {
id
status
updatedAt
}
}
`;
/** 发布选修课 Mutation */
export const PublishElectiveCourseMutation = gql`
mutation PublishElectiveCourse($id: ID!) {
publishElectiveCourse(id: $id) {
id
status
updatedAt
}
}
`;
/** 取消选修课 Mutation */
export const CancelElectiveCourseMutation = gql`
mutation CancelElectiveCourse($id: ID!) {
cancelElectiveCourse(id: $id) {
id
status
updatedAt
}
}
`;
// ============ Queries / Mutations富文本编辑 ============
/** 富文本试卷内容查询 */
export const ExamRichEditorQuery = gql`
query ExamRichEditor($examId: ID!) {
examRichEditor(examId: $examId) {
examId
title
totalScore
questionCount
content
updatedAt
}
}
`;
/** 保存富文本内容 Mutation */
export const SaveExamRichContentMutation = gql`
mutation SaveExamRichContent($input: SaveExamRichContentInput!) {
saveExamRichContent(input: $input) {
examId
updatedAt
}
}
`;
// ============ Queries / Mutations监考 ============
/** 监考状态查询 */
export const ProctoringStatusQuery = gql`
query ProctoringStatus($examId: ID!) {
proctoringStatus(examId: $examId) {
summary {
examId
expectedCount
onlineCount
submittedCount
flaggedCount
isProctoring
startedAt
}
students {
studentId
studentName
studentNo
status
lastEventAt
ipAddress
}
recentEvents {
eventId
examId
studentId
studentName
studentNo
eventType
note
createdAt
}
}
}
`;
/** 提交监考事件 Mutation */
export const ProctoringEventMutation = gql`
mutation ProctoringEvent($input: ProctoringEventInput!) {
proctoringEvent(input: $input) {
eventId
createdAt
}
}
`;
// ============ Queries / Mutations扫描批改 ============
/** 扫描批改视图查询 */
export const SubmissionScanGradingQuery = gql`
query SubmissionScanGrading($submissionId: ID!) {
submissionScanGrading(submissionId: $submissionId) {
submissionId
homeworkTitle
studentName
studentNo
submittedAt
images {
imageId
url
page
}
items {
questionId
questionTitle
questionOrder
maxScore
recognizedAnswer
aiSuggestedScore
aiSuggestion
score
feedback
}
prevSubmissionId
nextSubmissionId
}
}
`;
/** 保存扫描批改 Mutation */
export const SaveScanGradingMutation = gql`
mutation SaveScanGrading($input: SaveScanGradingInput!) {
saveScanGrading(input: $input) {
submissionId
totalScore
savedAt
}
}
`;
// ============ Queries课标热力图 ============
/** 课标覆盖热力图查询(按教材 ID */
export const LessonPlanHeatmapQuery = gql`
query LessonPlanHeatmap($textbookId: ID!) {
lessonPlanHeatmap(textbookId: $textbookId) {
textbookId
textbookTitle
knowledgePoints {
kpId
name
chapterName
}
lessonPlans {
planId
title
}
cells {
kpId
planId
coverage
}
}
}
`;