feat(exams,homework,proctoring): 长期问题修复与竞品差距补齐
P1-1 跨模块直查消除: - homework/data-access-classes.ts 移除对 exams/subjects 表的 JOIN 直查 - 改为调用 exams/data-access.getExamSubjectIdMap + school/data-access.getSubjectNameMapByIds - school/data-access.ts 新增 getSubjectNameMapByIds 批量科目名称映射函数 P1-2 as 断言消除(exam-mode-config.tsx): - 移除全部 10 处 as 类型断言 - 改用 useFormContext 替代 Control prop,避免 Control<T> 不变型问题 - exam-form.tsx 调用方简化为 <ExamModeConfig />(已集成到考试表单) P1-3 as 断言消除(proctoring-dashboard.tsx): - 用类型守卫函数 isProctoringEventType + toProctoringEventTypes 替代 Object.keys(...) as ProctoringEventType[] 断言 P0-竞品倒计时(对标智学网/猿题库): - 新增 hooks/use-exam-countdown.ts 考试倒计时 Hook - homework-take-view.tsx 集成限时/监考模式倒计时显示与到时自动提交 - data-access.ts 的 getStudentHomeworkTakeData 新增 examModeConfig + startedAt 字段 - types.ts 扩展 StudentHomeworkTakeData 类型 - i18n 补充 timedExam/timeRemaining/timeUpAutoSubmit 翻译键 架构文档同步: - 004/005 更新 homework/proctoring/school/exams 模块导出与依赖关系 - 005 新增 homework.hooks.useExamCountdown 与 school.dataAccess.getSubjectNameMapByIds - 005 依赖矩阵 homework→school 补充 getSubjectNameMapByIds 验证:tsc --noEmit 零错误,eslint 零错误(3 个预存 warning 无关)
This commit is contained in:
@@ -583,13 +583,13 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
**导出函数**:
|
||||
- Actions:`createHomeworkAssignmentAction` / `startHomeworkSubmissionAction` / `saveHomeworkAnswerAction` / `submitHomeworkAction` / `gradeHomeworkSubmissionAction` / `batchAutoGradeSubmissionsAction`(V3-7 新增:批量自动批改,HOMEWORK_GRADE 权限+非管理员仅可批改自己创建的作业)(✅ P1-2 已修复:actions 层不再直接访问 DB,全部下沉到 data-access/data-access-write)
|
||||
- Data-access:`getHomeworkAssignments` / `getHomeworkAssignmentById` / `getHomeworkSubmissions` / `getStudentHomeworkAssignments` / `getStudentHomeworkTakeData` / `getHomeworkAssignmentReviewList` / `getHomeworkSubmissionDetails` / `getDemoStudentUser`(已迁移至 users 模块 `getCurrentStudentUser`,此处为 re-export 向后兼容)/ `isRecord` / `toQuestionContent` / `getAssignmentMaxScoreById`(后三者供 stats-service 使用)/ `getHomeworkAssignmentsByExamId`(V3-8 新增:按考试 ID 查作业+目标/提交/批改计数)/ `getGradedSubmissionsByExamId`(V3-8 新增:按考试 ID 查已批改提交,按学生去重)/ `getStudentSubmissionResult`(V3-9 新增:查学生指定作业最新提交,用于结果页)/ `getStudentExamResults`(V3-11 新增:查学生考试结果列表,供家长端展示)
|
||||
- Data-access-classes:`getAssignmentIdsForStudents` / `getHomeworkAssignmentsWithSubject` / `getHomeworkAssignmentsByIds` / `getAssignmentTargetCounts` / `getHomeworkSubmissionsForStudents` / `getPublishedHomeworkAssignmentsWithSubject` / `getHomeworkSubmissionsForAssignments`(P0-7 新增,供 classes 模块跨模块调用,封装 homework/exams 表查询)
|
||||
- Data-access-classes:`getAssignmentIdsForStudents` / `getHomeworkAssignmentsWithSubject` / `getHomeworkAssignmentsByIds` / `getAssignmentTargetCounts` / `getHomeworkSubmissionsForStudents` / `getPublishedHomeworkAssignmentsWithSubject` / `getHomeworkSubmissionsForAssignments`(P0-7 新增,供 classes 模块跨模块调用;✅ P1-1 已修复:内部不再直查 exams/subjects 表,改为调用 `exams/data-access.getExamSubjectIdMap` + `school/data-access.getSubjectNameMapByIds`)
|
||||
- Data-access-write:11 个写操作函数(P1-2 新增 10 个从 actions 下沉 + V3-7 新增 `batchAutoGradeSubmissions`)
|
||||
- Stats-service:`getTeacherGradeTrends` / `getHomeworkAssignmentAnalytics` / `getStudentDashboardGrades`(从 data-access.ts re-export 以保持向后兼容)
|
||||
- Components(V3-7/V3-9 新增):`HomeworkBatchGradingView`(批量批改视图:勾选+一键批改+toast 反馈)/ `HomeworkSubmissionResult`(提交后即时反馈:分数汇总+对错分布+错题预览)
|
||||
|
||||
**依赖关系**:
|
||||
- 依赖:`shared/*`、`@/auth`、`exams`(✅ P1-1 已修复:通过 exams data-access.getExamIdsByGradeIds/getExamSubjectIdMap/getExamWithQuestionsForHomework)、`classes`(✅ P1-1 已修复:通过 classes data-access.getStudentIdsByClassId 等 7 个函数)、`school`(✅ P1-1 已修复:通过 school data-access.getSubjectOptions)、`users`(✅ P1-1 已修复:通过 users data-access.getUserWithRole/getUserNamesByIds)
|
||||
- 依赖:`shared/*`、`@/auth`、`exams`(✅ P1-1 已修复:通过 exams data-access.getExamIdsByGradeIds/getExamSubjectIdMap/getExamWithQuestionsForHomework/getExamForProctoringCrossModule)、`classes`(✅ P1-1 已修复:通过 classes data-access.getStudentIdsByClassId 等 7 个函数)、`school`(✅ P1-1 已修复:通过 school data-access.getSubjectOptions/getSubjectNameMapByIds)、`users`(✅ P1-1 已修复:通过 users data-access.getUserWithRole/getUserNamesByIds)
|
||||
- 被依赖:`dashboard`(通过 data-access,合理)、`parent`(通过 data-access,合理;V3-11 新增 `getStudentExamResults` 供 parent 调用)、`classes`(✅ P0-7 已修复:classes 通过 `homework/data-access-classes` 获取作业数据,不再反向直查 homework/exams 表)、`exams`(V3-8 新增:`exams/stats-service.getExamAnalytics` 调用 `getHomeworkAssignmentsByExamId` / `getGradedSubmissionsByExamId`,合理跨模块调用)
|
||||
|
||||
**已知问题**:
|
||||
@@ -597,7 +597,8 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
- ✅ P0 已解决:`getStudentDashboardGrades` 排名计算逻辑迁移至 `stats-service.ts`
|
||||
- ✅ P0 已解决:`getHomeworkAssignmentAnalytics` 错误率统计逻辑迁移至 `stats-service.ts`
|
||||
- ✅ P0-7 已修复:新增 `data-access-classes.ts`,将 classes 模块对 homework/exams 表的直查封装为 homework 模块的导出函数,恢复三层架构
|
||||
- ✅ P1-1 已修复:~~5 处直查 `exams` 表~~ 改为调用 `exams/data-access.getExamIdsByGradeIds` / `getExamSubjectIdMap` / `getExamWithQuestionsForHomework`
|
||||
- ✅ P1-1 已修复:~~5 处直查 `exams` 表~~ 改为调用 `exams/data-access.getExamIdsByGradeIds` / `getExamSubjectIdMap` / `getExamWithQuestionsForHomework`;`data-access-classes.ts` 内部 JOIN exams+subjects 也改为调用 `exams/data-access.getExamSubjectIdMap` + `school/data-access.getSubjectNameMapByIds`,彻底消除跨模块直查
|
||||
- ✅ P0-竞品已修复:新增 `hooks/use-exam-countdown.ts` 倒计时 Hook(对标智学网/猿题库),`homework-take-view.tsx` 集成限时/监考模式倒计时显示与到时自动提交;`data-access.ts` 的 `getStudentHomeworkTakeData` 新增 `examModeConfig` + `startedAt` 字段供客户端计算截止时间
|
||||
- ✅ P1-2 已修复:~~`actions.ts` 多处直接 DB 操作(`createHomeworkAssignmentAction` 157 行)~~ DB 操作已下沉到 `data-access-write.ts`,actions.ts 现 239 行
|
||||
- ✅ V3-7:新增 `batchAutoGradeSubmissionsAction` + `batchAutoGradeSubmissions` + `HomeworkBatchGradingView`,提交列表页接入批量批改
|
||||
- ✅ V3-8:新增 `getHomeworkAssignmentsByExamId` + `getGradedSubmissionsByExamId`,供 exams 模块跨模块调用
|
||||
@@ -610,14 +611,15 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
|------|------|------|
|
||||
| `data-access.ts` | 598+ | 作业 CRUD + 学生视角 + 批改(含 re-export stats 函数;V3-8/V3-9/V3-11 新增 4 个查询函数) |
|
||||
| `data-access-write.ts` | 285+ | 作业写操作(P1-2 新增 10 个写函数从 actions 下沉;V3-7 新增 `batchAutoGradeSubmissions`) |
|
||||
| `data-access-classes.ts` | 232 | 跨模块查询封装(P0-7 新增,供 classes 模块调用,封装 homework/exams 表查询) |
|
||||
| `data-access-classes.ts` | 240+ | 跨模块查询封装(P0-7 新增;✅ P1-1 已修复:内部通过 exams/school data-access 获取考试科目信息,不再直查 exams/subjects 表) |
|
||||
| `stats-service.ts` | 425 | 统计分析(教师趋势/作业分析/学生仪表盘成绩) |
|
||||
| `actions.ts` | 239+ | 6 个 Server Action(P1-2 已修复,无直接 DB 操作;V3-7 新增 `batchAutoGradeSubmissionsAction`) |
|
||||
| `types.ts` | 186 | 类型定义 |
|
||||
| `schema.ts` | 29 | Zod 校验 |
|
||||
| `components/homework-batch-grading-view.tsx` | - | V3-7 新增:批量批改视图(use client) |
|
||||
| `components/homework-submission-result.tsx` | - | V3-9 新增:提交后即时反馈页 |
|
||||
| `components/homework-take-view.tsx` | - | V3-9/V3-12 增强:提交后跳转结果页+移动端触摸优化 |
|
||||
| `components/homework-take-view.tsx` | - | V3-9/V3-12 增强:提交后跳转结果页+移动端触摸优化;✅ P0-竞品:集成限时/监考模式倒计时(useExamCountdown)+ 到时自动提交 |
|
||||
| `hooks/use-exam-countdown.ts` | 122 | P0-竞品新增:考试倒计时 Hook(每秒更新、紧急状态高亮、到时回调自动提交) |
|
||||
|
||||
---
|
||||
|
||||
@@ -723,12 +725,13 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
**职责**:成绩分析(录入/查询/统计/导出/趋势对比分析)。
|
||||
|
||||
**导出函数**:
|
||||
- Actions:`getGradeRecordsAction` / `createGradeRecordAction` / `updateGradeRecordAction` / `deleteGradeRecordAction` / `exportGradesAction` / `getGradeTrendAction` / `getClassComparisonAction` / `getSubjectComparisonAction` / `getGradeDistributionAction` / `getClassRankingAction` / `getRankingTrendAction` / `getGradeRecordByIdAction` / `getClassGradeStatsAction` / `getStudentGradeSummaryAction` / `batchCreateGradeRecordsAction` / `assertClassInScope`(✅ P3 新增导出:班级 scope 校验工具,供 actions-analytics 复用)/ `saveGradeDraftAction` / `getGradeDraftAction` / `deleteGradeDraftAction`(✅ v3-P2 新增:成绩录入草稿 Server Actions,分别使用 GRADE_RECORD_MANAGE/GRADE_RECORD_READ/GRADE_RECORD_MANAGE 权限)
|
||||
- Actions:`getGradeRecordsAction` / `createGradeRecordAction`(v4-P1-6 增强:成绩录入后通知学生和家长,调用 `notifyGradeEntered`)/ `updateGradeRecordAction` / `deleteGradeRecordAction` / `exportGradesAction`(v4-P1-12 增强:新增可选 `studentId` 参数,支持按学生导出,家长视角调用 `exportStudentGradeRecordsToExcel`,校验 studentId 属于家长子女)/ `getGradeTrendAction` / `getClassComparisonAction` / `getSubjectComparisonAction` / `getGradeDistributionAction` / `getClassRankingAction` / `getRankingTrendAction` / `getGradeRecordByIdAction` / `getClassGradeStatsAction` / `getStudentGradeSummaryAction` / `batchCreateGradeRecordsAction`(v4-P1-6 增强:批量成绩录入后通知学生和家长)/ `assertClassInScope`(✅ P3 新增导出:班级 scope 校验工具,供 actions-analytics 复用)/ `saveGradeDraftAction` / `getGradeDraftAction` / `deleteGradeDraftAction`(✅ v3-P2 新增:成绩录入草稿 Server Actions,分别使用 GRADE_RECORD_MANAGE/GRADE_RECORD_READ/GRADE_RECORD_MANAGE 权限)
|
||||
- Data-access:`getGradeRecords` / `getStudentGradeSummary` / `getClassRanking` / `getClassStudentsForEntry` / `getClassGradeStats` / `getClassGradeStatsWithMeta` / `getGradeTrend` / `getClassComparison` / `getSubjectComparison` / `getGradeDistribution` / `getRankingTrend` / `PaginatedGradeRecords`(✅ P3 新增:分页结果接口 `{ records, total }`)/ `saveGradeDraft` / `getGradeDraft` / `deleteGradeDraft`(✅ v3-P2 新增:成绩录入草稿 CRUD,upsert + 24 小时过期)/ `getExamOptionsForGrades` / `getSchoolWideGradeSummary`(✅ v3-P2 新增:考试选项查询 + 全校各年级成绩汇总,管理员视图按年级聚合平均分/及格率/优秀率/学生数/班级数,加权平均计算全校汇总)
|
||||
- Types(✅ v3-P2 新增):`SchoolWideGradeSummaryItem`(全校汇总按年级聚合项:gradeId/gradeName/schoolName/classCount/studentCount/averageScore/passRate/excellentRate/recordCount)/ `SchoolWideGradeSummary`(全校汇总:grades 数组 + totals 汇总对象)/ `GradeDraftData`(草稿数据接口:{ scores: Record<string, string>, timestamp: number },位于 data-access.ts)
|
||||
- Lib(✅ P1-2 新增,✅ P3 更新签名,✅ P3-26 拆分):`toNumber` / `normalize`(位于 `lib/grade-utils.ts`);`buildScopeClassFilter(scope, currentUserId?)`(P3-26 从 grade-utils.ts 迁移至 `lib/scope-filter.ts`,P3 修复:`class_members` scope 内置 studentId 过滤,需传入 currentUserId 参数)
|
||||
- Stats-service(✅ P1-1 新增):`computeGradeStats` / `computeAverageScore` / `buildGradeTrendPoints` / `computeTrendAverage` / `computeClassComparisonStats` / `computeSubjectComparisonStats` / `computeGradeDistribution` / `buildRankingTrendPoints`(从 3 个 data-access 文件抽取的纯函数,使数据层专注 DB I/O,统计逻辑可独立测试)
|
||||
- Components(✅ P1-5 新增):`WidgetBoundary`(Error Boundary + Suspense + Skeleton 组合,含 a11y 属性)/ `SchoolWideSummaryCard`(✅ v3-P2 新增:管理员全校成绩汇总卡片,4 个统计卡片 + 各年级对比表格)
|
||||
- Export(✅ v4-P1-12 新增):`exportGradeRecordsToExcel` / `exportClassGradeReportToExcel` / `exportStudentGradeRecordsToExcel`(v4-P1-12 新增:导出单个学生成绩单家长视角,仅含成绩明细 + 个人统计,不含班级数据,scope 为 children 自动按 studentId 过滤)/ `formatDateForFile`(已迁移至 shared/lib/utils)
|
||||
- Components(✅ P1-5 新增):`WidgetBoundary`(Error Boundary + Suspense + Skeleton 组合,含 a11y 属性)/ `SchoolWideSummaryCard`(✅ v3-P2 新增:管理员全校成绩汇总卡片,4 个统计卡片 + 各年级对比表格)/ `ScoreCell`(✅ v4-P1-7 新增:成绩单元格组件,根据得分率着色——红<60%/黄60-84%/绿≥85%,使用语义化 Tailwind 类名避免动态拼接,fullScore<=0 时不着色)
|
||||
|
||||
**依赖关系**:
|
||||
- 依赖:`shared/*`、`@/auth`、`classes`(✅ P1-1 已修复:通过 classes data-access.getClassExists/getClassNameById/getClassNamesByIds/getActiveStudentIdsByClassId/getStudentActiveClassId/getClassesByGradeId)、`school`(✅ P1-1 已修复:通过 school data-access.getSubjectOptions/getGradeOptions)、`users`(✅ P1-1 已修复:通过 users data-access.getUserNamesByIds)
|
||||
@@ -767,30 +770,36 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
- ✅ v3-P2 改进(2026-06-23):新增 `getSchoolWideGradeSummary` data-access 函数 + `SchoolWideSummaryCard` 组件 + `SchoolWideGradeSummary`/`SchoolWideGradeSummaryItem` 类型,管理员全校成绩汇总视图(按年级聚合平均分/及格率/优秀率/学生数/班级数,加权平均计算全校汇总);admin/school/grades/insights/page.tsx 顶部新增 SchoolWideSummaryCard
|
||||
- ✅ v3-P2 改进(2026-06-23):parent/grades/page.tsx 为每个子女并行查询 `getClassAverageTrend`,渲染 GradeTrendCard
|
||||
- ✅ v3-P3-4 改进(2026-06-23):GradeTrendCard 新增日期范围选择器(全部/近7天/近30天/近90天),通过 nuqs `trendRange` URL 参数持久化,useEffect 中计算截止时间戳避免渲染阶段调用 Date.now()
|
||||
- ✅ v4-P3-4 改进(2026-06-23):GradeDistributionChart 色盲友好双重编码——每个分数段使用不同 SVG pattern(条纹/点状/交叉线/反向条纹/网格)+ 颜色,`SimpleBarChart` 新增 `defs` prop 支持自定义 SVG 图案
|
||||
- ✅ P3 修复(2026-06-23):~~`lib/grade-utils.ts` 72 行超 40 行工具函数上限~~ P3-26 将 `buildScopeClassFilter` 迁移至 `lib/scope-filter.ts`,grade-utils.ts 仅保留 toNumber/normalize(20 行)
|
||||
- ✅ P3 修复(2026-06-23):~~`stats-service.ts` createDefaultBuckets 不必要导出~~ P3-10 移除 export 关键字,改为内部函数
|
||||
- ✅ P3 修复(2026-06-23):~~`stats-service.ts` buildGradeTrendPoints 使用 as 断言~~ P3-24 新增 isGradeTrendType 类型守卫函数替代 as 断言
|
||||
- ✅ P3 修复(2026-06-23):~~`export.ts` 局部 avg 函数与 stats-service.computeAverageScore 重复~~ P3-6 删除局部 avg,复用 computeAverageScore
|
||||
- ✅ P3 修复(2026-06-23):~~`export.ts` TYPE_LABELS 硬编码中文~~ P3-7 改用 next-intl getTranslations,新增 export.sheets/columns/metrics i18n 键(zh-CN/en 同步)
|
||||
- ✅ v4-P1-6 改进(2026-06-23):`createGradeRecordAction` / `batchCreateGradeRecordsAction` 成绩录入后通知学生和家长(调用 `notifyGradeEntered`,内部使用 `parent/data-access.getParentIdsByStudentIds` 批量查询家长 ID),通知失败不阻断成绩录入
|
||||
- ✅ v4-P1-7 改进(2026-06-23):新增 `ScoreCell` 组件(components/score-cell.tsx),根据得分率着色(红<60%/黄60-84%/绿≥85%),使用语义化 Tailwind 类名避免动态拼接
|
||||
- ✅ v4-P1-10 改进(2026-06-23):`grade-record-list.tsx` 使用 `ScoreCell` 替代纯文本分数展示 + 表格 `overflow-x-auto` 水平滚动
|
||||
- ✅ v4-P1-12 改进(2026-06-23):`exportGradesAction` 新增可选 `studentId` 参数,支持按学生导出(家长视角);新增 `exportStudentGradeRecordsToExcel` 导出函数(仅含成绩明细 + 个人统计,不含班级数据);parent/grades/page.tsx 传 studentId 到 ParentExportButton;ParentExportButton 接入 exportGradesAction
|
||||
|
||||
**文件清单**:
|
||||
| 文件 | 行数 | 职责 |
|
||||
|------|------|------|
|
||||
| `actions.ts` | 396+ | 18 个 Server Action(含 Zod 校验,含 v2-P1-5 安全修复:assertClassInScope + 行级 scope 校验;P3 修复:handleActionError + safeJsonParse + scope 传递 + DB 层分页;v3-P2 新增:saveGradeDraftAction/getGradeDraftAction/deleteGradeDraftAction) |
|
||||
| `actions.ts` | 631+ | 18 个 Server Action(含 Zod 校验,含 v2-P1-5 安全修复:assertClassInScope + 行级 scope 校验;P3 修复:handleActionError + safeJsonParse + scope 传递 + DB 层分页;v3-P2 新增:saveGradeDraftAction/getGradeDraftAction/deleteGradeDraftAction;v4-P1-6:createGradeRecordAction/batchCreateGradeRecordsAction 新增通知;v4-P1-12:exportGradesAction 新增 studentId 参数) |
|
||||
| `actions-analytics.ts` | 170 | 5 个分析 Action(含 Zod 校验,P3 修复:handleActionError + assertClassInScope 校验) |
|
||||
| `data-access.ts` | 428+ | 成绩 CRUD + 统计 + 草稿(含 v2-P2-9 修复:recorderName 批量查询;P3 修复:PaginatedGradeRecords 接口 + DB 层分页 + 事务 + 存在性检查 + scope 过滤 + 并列排名;v3-P2 新增:saveGradeDraft/getGradeDraft/deleteGradeDraft + GradeDraftData 接口) |
|
||||
| `data-access-analytics.ts` | 200+ | 趋势/对比分析(P3 修复:getClassComparison 应用 buildScopeClassFilter;v3-P2 新增:getExamOptionsForGrades/getSchoolWideGradeSummary;getGradeTrend/getClassComparison/getSubjectComparison/getGradeDistribution 新增 semester/examId 可选参数) |
|
||||
| `data-access-ranking.ts` | 83 | 排名查询(P3 修复:getRankingTrend 接受 scope 参数 + class_taught 校验) |
|
||||
| `stats-service.ts` | 285 | 统计计算纯函数(P1-1 新增:8 个纯函数 + 2 个常量 + 2 个接口;P3-10:createDefaultBuckets 改为内部函数;P3-24:buildGradeTrendPoints 使用 isGradeTrendType 类型守卫替代 as 断言) |
|
||||
| `export.ts` | 209 | Excel 导出(v2-P1-5 修复:传递 currentUserId 到 data-access;P3 修复:适配 PaginatedGradeRecords 结构 + 传递 scope;P3-6:复用 stats-service.computeAverageScore 替代局部 avg;P3-7:硬编码中文改用 next-intl getTranslations) |
|
||||
| `export.ts` | 290+ | Excel 导出(v2-P1-5 修复:传递 currentUserId 到 data-access;P3 修复:适配 PaginatedGradeRecords 结构 + 传递 scope;P3-6:复用 stats-service.computeAverageScore 替代局部 avg;P3-7:硬编码中文改用 next-intl getTranslations;v4-P1-12 新增:exportStudentGradeRecordsToExcel 家长视角单学生导出) |
|
||||
| `schema.ts` | 113+ | Zod 校验(含 12 个查询 schema;P3 修复:score .max(1000) + records .max(500) + 补全查询字段;v3-P2 新增:grade_drafts 表定义第 1444-1469 行) |
|
||||
| `lib/grade-utils.ts` | 20 | 公共工具函数(toNumber/normalize;P3-26:buildScopeClassFilter 迁移至 scope-filter.ts) |
|
||||
| `lib/scope-filter.ts` | 56 | DB 行级权限过滤(buildScopeClassFilter;P3-26 从 grade-utils.ts 迁移;v2-P2-2 修复:改用 classes data-access 子查询;P3 修复:新增 currentUserId 参数) |
|
||||
| `types.ts` | 168+ | 类型定义(v3-P2 新增:SchoolWideGradeSummaryItem/SchoolWideGradeSummary) |
|
||||
| `components/widget-boundary.tsx` | 136 | Widget 边界组件(P1-5 新增,v2-P1-1 已在 3 个页面应用) |
|
||||
| `components/school-wide-summary-card.tsx` | - | v3-P2 新增:管理员全校成绩汇总卡片(4 个统计卡片 + 各年级对比表格) |
|
||||
| `components/score-cell.tsx` | 41 | v4-P1-7 新增:成绩单元格组件,根据得分率着色(红<60%/黄60-84%/绿≥85%),使用语义化 Tailwind 类名 |
|
||||
| `components/grade-trend-card.tsx` | 69 | 趋势卡片(v2-P2-9 修复:a11y;v2-P1-4:i18n;P3 修复:NaN 日期检查 + fullScore > 0 守卫) |
|
||||
| `components/grade-record-list.tsx` | 125 | 成绩记录列表(v2-P1-4:i18n;P3 修复:safeActionCall 包装删除操作) |
|
||||
| `components/grade-record-list.tsx` | 125 | 成绩记录列表(v2-P1-4:i18n;P3 修复:safeActionCall 包装删除操作;v4-P1-7:使用 ScoreCell;v4-P1-10:overflow-x-auto) |
|
||||
| `components/grade-distribution-chart.tsx` | 100 | 分数分布图(v2-P1-4:i18n) |
|
||||
| `components/subject-comparison-chart.tsx` | 62 | 科目对比图(v2-P1-4:i18n) |
|
||||
| `components/class-comparison-chart.tsx` | 58 | 班级对比图(v2-P1-4:i18n) |
|
||||
@@ -858,7 +867,7 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
|
||||
**导出函数**:
|
||||
- Actions:`createSchoolAction` / `updateSchoolAction` / `deleteSchoolAction` / `createAcademicYearAction` / `updateAcademicYearAction` / `deleteAcademicYearAction` / `createDepartmentAction` / `updateDepartmentAction` / `deleteDepartmentAction` / `createGradeAction` / `updateGradeAction` / `deleteGradeAction` / `promoteGradesAction`(编排层:权限校验 + Zod 校验 + 调用 data-access + revalidatePath + after(logAudit);`promoteGradesAction` 年级升级,审计日志 `grade.promote`)
|
||||
- Data-access:只读查询(`getSchools` / `getGrades` / `getDepartments` / `getAcademicYears` / `getStaffOptions` / `getGradesForStaff` / `getOrgTree`)+ 写操作(`create/update/delete` × `Department/School/Grade/AcademicYear`)+ `promoteGrades(schoolId)` 年级升级(order +1 + 名称升级,辅助函数 `promoteGradeName`)
|
||||
- Data-access:只读查询(`getSchools` / `getGrades` / `getDepartments` / `getAcademicYears` / `getStaffOptions` / `getGradesForStaff` / `getOrgTree` / `getSubjectOptions` / `getGradeOptions` / `getSubjectNameMapByIds`(P1-1 新增:批量科目名称映射,供 homework/data-access-classes 调用))+ 写操作(`create/update/delete` × `Department/School/Grade/AcademicYear`)+ `promoteGrades(schoolId)` 年级升级(order +1 + 名称升级,辅助函数 `promoteGradeName`)
|
||||
|
||||
**依赖关系**:
|
||||
- 依赖:`shared/*`、`@/auth`、`users`(⚠️ `getStaffOptions` 直查 users/roles,可接受)
|
||||
@@ -946,18 +955,24 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
**职责**:考勤记录管理 + 统计分析 + 规则配置。
|
||||
|
||||
**导出函数**:
|
||||
- Actions(10 个):`recordAttendanceAction` / `batchRecordAttendanceAction` / `updateAttendanceAction` / `deleteAttendanceAction` / `getAttendanceAction` / `getStudentAttendanceAction` / `getClassAttendanceStatsAction` / `getClassAttendanceForDateAction` / `saveAttendanceRulesAction` / `getAttendanceRulesAction`
|
||||
- Data-access:`getAttendanceRecords` / `createAttendanceRecord` / `updateAttendanceRecord` / `deleteAttendanceRecord` / `getClassStudentsForAttendance` / `getAttendanceStats`(管理员考勤总览页统计概览,基于 `getAttendanceRecords` 聚合)/ `upsertAttendanceRules` / `getAttendanceRules`
|
||||
- Data-access-stats:`getStudentAttendanceSummary` / `getClassAttendanceStats` / `computeStats`(⚠️ 未导出,无法单测)
|
||||
- Components:`AttendanceSheet`(批量点名表单)/ `AttendanceRecordList`(记录列表 + 删除)/ `AttendanceFilters`(URL 同步筛选器)/ `AttendanceStatsCard`(单卡片统计)/ `AttendanceStatsCards`(管理员 6 卡片总览)/ `AttendanceStatsClassSelector`(班级筛选 ChipNav)/ `AttendanceRulesForm`(规则配置表单)/ `StudentAttendanceView`(学生/家长只读视图)
|
||||
- Actions(10 个):`recordAttendanceAction` / `batchRecordAttendanceAction` / `updateAttendanceAction` / `deleteAttendanceAction` / `getAttendanceAction` / `getStudentAttendanceAction` / `getClassAttendanceStatsAction` / `getClassAttendanceForDateAction` / `saveAttendanceRulesAction` / `getAttendanceRulesAction`(✅ P2-2:5 个写 Action 错误消息改用 `getTranslations("attendance")` 国际化)
|
||||
- Data-access:`getAttendanceRecords` / `createAttendanceRecord` / `updateAttendanceRecord` / `deleteAttendanceRecord` / `getClassStudentsForAttendance` / `getAttendanceStats`(✅ P2-1 已修复:改用 SQL `COUNT()` + `SUM(CASE WHEN ...)` 聚合查询,不再依赖 `getAttendanceRecords` 分页结果)/ `upsertAttendanceRules` / `getAttendanceRules`
|
||||
- Data-access-stats:`getStudentAttendanceSummary`(✅ P2-6 已修复:stats 改用 SQL 聚合查询,recentRecords 增加 `recentLimit` 参数默认 20,不再加载全部记录)/ `getClassAttendanceStats` / `computeStats`
|
||||
- Import-export:`exportAttendanceRecordsToExcel`(✅ P2-11 新增:Sheet1 考勤明细 + Sheet2 统计汇总,列头 i18n 化)
|
||||
- Components:`AttendanceSheet`(批量点名表单)/ `AttendanceRecordList`(记录列表 + 删除)/ `AttendanceFilters`(URL 同步筛选器)/ `AttendanceStatsCard`(单卡片统计)/ `AttendanceStatsCards`(管理员 6 卡片总览)/ `AttendanceStatsClassSelector`(班级筛选 ChipNav)/ `AttendanceRulesForm`(规则配置表单)/ `StudentAttendanceView`(学生/家长只读视图)/ `AttendancePageLayout`(✅ P2-3 新增:页面布局骨架,admin/teacher 考勤页复用)
|
||||
|
||||
**依赖关系**:
|
||||
- 依赖:`shared/*`、`@/auth`、`classes`(⚠️ P1-1 未修复:`getClassStudentsForAttendance` 仍直查 `classEnrollments` 表)
|
||||
- 被依赖:`parent`(⚠️ 跨模块 UI 类型依赖:3 个 parent 组件直接 import `@/modules/attendance/types`)
|
||||
- 依赖:`shared/*`、`@/auth`、`classes`(⚠️ P1-1 未修复:`getClassStudentsForAttendance` 仍直查 `classEnrollments` 表)、`next-intl`(✅ P2-2:Server Action 错误消息 i18n)
|
||||
- 被依赖:`parent`(⚠️ 跨模块 UI 类型依赖:3 个 parent 组件直接 import `@/modules/attendance/types`)、`app/api/export`(✅ P2-11:通过 `exportAttendanceRecordsToExcel`)
|
||||
|
||||
**已知问题**(详见 `docs/architecture/audit/attendance-elective-audit-report.md`):
|
||||
- ❌ P0:`getAttendanceStats` 统计失真——调用 `getAttendanceRecords`(默认 pageSize=20)后对 `items` 聚合,仅基于前 20 条记录计算总览数据
|
||||
- ❌ P0:`getClassStudentsForAttendance` 仍直查 `classEnrollments` 表(架构图此前声称已修复,实际未修复)
|
||||
- ✅ P2-1 已修复:`getAttendanceStats` 改用 SQL 聚合查询,消除分页截断导致统计失真
|
||||
- ✅ P2-2 已修复:5 个写 Action 错误消息改用 `getTranslations("attendance")` 国际化
|
||||
- ✅ P2-3 已修复:新增 `AttendancePageLayout` 组件,admin/teacher 考勤页复用布局
|
||||
- ✅ P2-5 已修复:`parent-attendance-calendar.tsx` 增加键盘导航(ARIA grid 模式,方向键/Home/End)
|
||||
- ✅ P2-6 已修复:`getStudentAttendanceSummary` stats 改用 SQL 聚合 + recentRecords 分页限制
|
||||
- ✅ P2-11 已修复:新增 `export.ts`,考勤记录/统计可导出 Excel
|
||||
- ❌ P0:`getClassStudentsForAttendance` 仍直查 `classEnrollments` 表
|
||||
- ❌ P0:6 个读 Action 无调用方(页面绕过 Action 直接调用 data-access),违反三层架构
|
||||
- ❌ P0:update/delete Action 缺资源归属校验(教师 A 可修改/删除教师 B 的记录)
|
||||
- ❌ P0:i18n 完全缺失(`ATTENDANCE_STATUS_LABELS` 硬编码英文,组件中硬编码中文)
|
||||
@@ -973,9 +988,10 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
**文件清单**:
|
||||
| 文件 | 行数 | 职责 |
|
||||
|------|------|------|
|
||||
| `actions.ts` | 271 | 10 个 Server Action(含权限校验、Zod 校验) |
|
||||
| `data-access.ts` | 309 | 考勤 CRUD + 班级学生查询 + 规则 upsert + 总览统计 |
|
||||
| `data-access-stats.ts` | 145 | 学生/班级考勤汇总(拆分范例,`computeStats` 未导出) |
|
||||
| `actions.ts` | 271 | 10 个 Server Action(含权限校验、Zod 校验;P2-2:错误消息 i18n 化) |
|
||||
| `data-access.ts` | 340 | 考勤 CRUD + 班级学生查询 + 规则 upsert + 总览统计(P2-1:`getAttendanceStats` 改 SQL 聚合) |
|
||||
| `data-access-stats.ts` | 180 | 学生/班级考勤汇总(P2-6:stats 改 SQL 聚合 + recentRecords 分页) |
|
||||
| `export.ts` | 90 | Excel 导出(P2-11 新增:考勤明细 + 统计汇总双 Sheet) |
|
||||
| `schema.ts` | 43 | Zod 校验(5 个 schema) |
|
||||
| `types.ts` | 103 | 类型定义 + 状态标签/颜色常量(硬编码英文) |
|
||||
| `components/attendance-sheet.tsx` | 353 | 批量点名表单(键盘快捷键、状态按钮组) |
|
||||
@@ -986,6 +1002,7 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
| `components/attendance-stats-class-selector.tsx` | 27 | 班级筛选 ChipNav |
|
||||
| `components/attendance-rules-form.tsx` | 148 | 考勤规则配置表单 |
|
||||
| `components/student-attendance-view.tsx` | 104 | 学生/家长视图(统计 + 最近记录) |
|
||||
| `components/attendance-page-layout.tsx` | 38 | 页面布局骨架(P2-3 新增:header/stats/filters/children 插槽) |
|
||||
|
||||
---
|
||||
|
||||
@@ -1142,13 +1159,14 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
**职责**:多渠道通知分发(SMS/Email/WeChat/InApp)+ 站内通知 CRUD + 通知偏好管理 + 通知 UI 组件。
|
||||
|
||||
**导出函数**:
|
||||
- Actions:`sendNotificationAction` / `sendClassNotificationAction` / `getNotificationsAction` / `getUnreadNotificationCountAction` / `markNotificationAsReadAction` / `markAllNotificationsAsReadAction`(✅ P1-4 新增:后 4 个通知 CRUD Action 从 messaging 模块迁移)
|
||||
- Actions:`sendNotificationAction` / `sendClassNotificationAction` / `getNotificationsAction` / `getUnreadNotificationCountAction` / `markNotificationAsReadAction` / `markAllNotificationsAsReadAction` / `archiveNotificationAction`(✅ P1-4 新增:后 4 个通知 CRUD Action 从 messaging 模块迁移;✅ V2-P2-13b 新增:archiveNotificationAction 归档 Action)
|
||||
- Dispatcher:`sendNotification(payload)` / `sendBatchNotifications(payloads)`
|
||||
- Data-access:`createNotification` / `getNotifications` / `markNotificationAsRead` / `markAllNotificationsAsRead` / `getUnreadNotificationCount` / `getUserContactInfo` / `logNotificationSend` / `logNotificationSendBatch`(✅ P0-4 / P1-5 修复后从 messaging 迁移)
|
||||
- Data-access:`createNotification` / `getNotifications` / `markNotificationAsRead` / `markAllNotificationsAsRead` / `getUnreadNotificationCount` / `archiveNotification` / `unarchiveNotification` / `getUserContactInfo` / `logNotificationSend` / `logNotificationSendBatch`(✅ P0-4 / P1-5 修复后从 messaging 迁移;✅ V2-P2-13b 新增:archiveNotification / unarchiveNotification 归档函数)
|
||||
- Preferences:`getNotificationPreferences` / `upsertNotificationPreferences`(✅ P0-4 / P1-5 修复后从 messaging 迁移)
|
||||
- Channels:`InAppChannelSender` / `SmsChannelSender` / `EmailChannelSender` / `WeChatChannelSender`
|
||||
- Components:`NotificationList` / `NotificationDropdown`(✅ P1-4 新增:从 messaging/components 迁移)
|
||||
- Components:`NotificationList` / `NotificationDropdown`(✅ P1-4 新增:从 messaging/components 迁移;✅ V2-P2-13b:NotificationList 支持优先级 Badge 显示和归档操作)
|
||||
- Hooks:`useNotificationStream`(✅ V2-P3 新增:SSE 实时推送 + 轮询降级 Hook)
|
||||
- Types:`NotificationPriority`(✅ V2-P2-13b 新增:通知优先级类型 low/normal/high/urgent)
|
||||
|
||||
**依赖关系**:
|
||||
- 依赖:`shared/*`、`@/auth`、`classes`(✅ P1-1 已修复:通过 classes data-access.getClassExists/getStudentIdsByClassId)
|
||||
@@ -1163,6 +1181,7 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
- ✅ V2-P0-1 已修复:~~通知 i18n 键混在 messages.json 中~~ 新增独立的 `notifications.json` 命名空间(zh-CN/en),通知组件 `useTranslations` 从 `"messages"` 切换到 `"notifications"`;`src/i18n/request.ts` 新增 notifications 命名空间加载
|
||||
- ✅ V2-P2-1 已修复:~~轮询间隔魔法数字~~ `notification-dropdown.tsx` 轮询间隔提取为 `POLL_INTERVAL_MS` 常量(30_000ms)
|
||||
- ✅ V2-P3 已优化:~~30 秒轮询~~ `notification-dropdown.tsx` 改为 SSE 实时推送(`/api/notifications/stream`),SSE 不可用时自动降级为轮询(调用 Server Actions,间隔 30 秒)
|
||||
- ✅ V2-P2-13b 新增:通知优先级和归档功能。schema.ts `messageNotifications` 表新增 `priority`(low/normal/high/urgent,默认 normal)和 `isArchived`(默认 false)字段 + 2 个索引;types.ts 新增 `NotificationPriority` 类型;data-access.ts 新增 `archiveNotification` / `unarchiveNotification` 函数,`getNotifications` 支持归档和优先级筛选(默认仅返回未归档),`createNotification` 支持 priority;actions.ts 新增 `archiveNotificationAction`(含 trackEvent 埋点 notification.archived);NotificationList 组件支持优先级 Badge 显示和归档按钮;i18n 新增 priority/actions.archive/messages.archiveFailed 翻译键
|
||||
- ⚠️ P1:发送日志仅 console,无 `notification_logs` 表
|
||||
- ✅ 渠道抽象优秀(接口 + 工厂 + Mock 实现)
|
||||
|
||||
@@ -1170,20 +1189,20 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
| 文件 | 行数 | 职责 |
|
||||
|------|------|------|
|
||||
| `dispatcher.ts` | 152 | 渠道选择 + 并行分发 |
|
||||
| `data-access.ts` | 212 | 站内通知 CRUD + 用户联系方式 + 发送日志持久化(notification_logs 表;P0-4 / P1-5 修复后新增通知 CRUD) |
|
||||
| `data-access.ts` | ~250 | 站内通知 CRUD + 用户联系方式 + 发送日志持久化(notification_logs 表;P0-4 / P1-5 修复后新增通知 CRUD;✅ V2-P2-13b:新增归档函数 + 优先级/归档筛选) |
|
||||
| `preferences.ts` | 166 | 通知偏好 CRUD(P0-4 / P1-5 修复后从 messaging 迁移) |
|
||||
| `actions.ts` | ~260 | 6 个 Server Action(✅ P1-4:新增 4 个通知 CRUD Action) |
|
||||
| `types.ts` | 120 | 通知负载 + 渠道配置 + 通知记录 + 偏好类型(P0-4 / P1-5 修复后扩充) |
|
||||
| `index.ts` | ~75 | 对外导出入口(✅ P1-4:新增组件和 CRUD Action 导出) |
|
||||
| `actions.ts` | ~300 | 7 个 Server Action(✅ P1-4:新增 4 个通知 CRUD Action;✅ V2-P2-13b:新增 archiveNotificationAction) |
|
||||
| `types.ts` | ~130 | 通知负载 + 渠道配置 + 通知记录 + 偏好类型(P0-4 / P1-5 修复后扩充;✅ V2-P2-13b:新增 NotificationPriority 类型 + priority/isArchived 字段) |
|
||||
| `index.ts` | ~80 | 对外导出入口(✅ P1-4:新增组件和 CRUD Action 导出;✅ V2-P2-13b:新增归档函数/Action/类型导出) |
|
||||
| `channels/*` | 5 文件 | 4 个渠道实现 |
|
||||
| `components/notification-list.tsx` | ~140 | ✅ P1-4 新增(从 messaging 迁移):通知列表组件 |
|
||||
| `components/notification-list.tsx` | ~170 | ✅ P1-4 新增(从 messaging 迁移):通知列表组件;✅ V2-P2-13b:支持优先级 Badge 显示和归档操作 |
|
||||
| `components/notification-dropdown.tsx` | ~150 | ✅ P1-4 新增(从 messaging 迁移):通知下拉菜单组件;✅ V2-P3:改用 SSE 实时推送 + 轮询降级 |
|
||||
| `hooks/use-notification-stream.ts` | ~195 | ✅ V2-P3 新增:SSE 实时推送 Hook(EventSource + 轮询降级) |
|
||||
|
||||
**组件清单**:
|
||||
| 组件 | 职责 |
|
||||
|------|------|
|
||||
| `components/notification-list.tsx` | 通知列表(消息页底部,展示所有通知,支持标记已读;✅ V2-P0-1:useTranslations 命名空间从 "messages" 切换到 "notifications") |
|
||||
| `components/notification-list.tsx` | 通知列表(消息页底部,展示所有通知,支持标记已读;✅ V2-P0-1:useTranslations 命名空间从 "messages" 切换到 "notifications";✅ V2-P2-13b:支持优先级 Badge 显示和归档操作) |
|
||||
| `components/notification-dropdown.tsx` | 通知下拉菜单(站点头部,✅ V2-P3:改用 SSE 实时推送 `/api/notifications/stream` + 轮询降级;✅ V2-P0-1:useTranslations 命名空间切换;✅ V2-P2-1:POLL_INTERVAL_MS 常量) |
|
||||
|
||||
**客户端行为**:
|
||||
@@ -1389,7 +1408,9 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
- ✅ P2 已修复:~~`buildHomeworkSummary` 中 `[...assignments].sort()` 不必要拷贝~~ 改为 `toSorted()`
|
||||
- ✅ P2 已修复:~~`in7Days` 死代码~~ 已删除
|
||||
- ⚠️ v4 保留:`/parent/leave` 为占位页,待后端实现请假审批流后接入
|
||||
- ⚠️ v4 保留:`ParentExportButton` 为占位,待后端实现成绩导出 Server Action 后接入
|
||||
- ✅ v4-P1-5 改进(2026-06-23):新增 `getParentIdsByStudentIds` data-access 函数,批量查询多个学生的家长 userId(去重),供 diagnostic/grades 模块通知场景调用
|
||||
- ✅ v4-P1-9 改进(2026-06-23):parent/diagnostic/page.tsx 新增错误卡片展示子女诊断查询失败原因
|
||||
- ✅ v4-P1-12 改进(2026-06-23):`ParentExportButton` 接入 `exportGradesAction`,支持按 studentId 导出单个子女成绩;parent/grades/page.tsx 传 studentId 到 ParentExportButton
|
||||
- ⚠️ v4 保留:详情页 Attendance/Diagnostic Tab 为占位提示,待对应功能实现后填充
|
||||
- ✅ v3-P2 改进(2026-06-23):parent/grades/page.tsx 为每个子女并行查询 `getClassAverageTrend`,渲染 GradeTrendCard;parent/diagnostic/page.tsx 传入 `practiceHrefBase={null}` 隐藏练习按钮
|
||||
- ✅ 职责单一,正确复用其他模块 data-access
|
||||
@@ -1404,7 +1425,7 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
| `components/parent-attendance-warning.tsx` | 89 | v4 新增:考勤异常预警 |
|
||||
| `components/parent-attendance-rate-card.tsx` | 105 | v4 新增:考勤出勤率汇总卡片 |
|
||||
| `components/parent-attendance-calendar.tsx` | 175 | v4 新增:考勤月历视图(use client) |
|
||||
| `components/parent-export-button.tsx` | 50 | v4 新增:成绩导出按钮(占位) |
|
||||
| `components/parent-export-button.tsx` | 50 | v4 新增:成绩导出按钮(v4-P1-12 已接入 exportGradesAction,支持按 studentId 导出单个子女成绩) |
|
||||
| `components/child-card.tsx` | 148 | 子女卡片(v4 增强:异常突出 + 趋势图标) |
|
||||
| `components/child-detail-header.tsx` | 78 | 详情页头部(v4 增强:面包屑) |
|
||||
| `components/child-detail-panel.tsx` | 200+ | 详情页 Tab 面板 + SiblingSwitcher(v4 重写,集成 Homework/Grade Detail;V3-11 新增 exams Tab) |
|
||||
@@ -1434,17 +1455,27 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
**职责**:选修课程管理 + 学生选课 + 抽签。
|
||||
|
||||
**导出函数**:
|
||||
- Actions(11 个):`getElectiveCoursesAction` / `createElectiveCourseAction` / `updateElectiveCourseAction` / `deleteElectiveCourseAction` / `getStudentSelectionsAction` / `selectCourseAction` / `dropCourseAction` / `runLotteryAction` / `getAvailableCoursesForStudentAction` / `openSelectionAction` / `closeSelectionAction`
|
||||
- Data-access:`getElectiveCourses` / `getElectiveCourseById` / `createElectiveCourse` / `updateElectiveCourse` / `deleteElectiveCourse` / `openSelection` / `closeSelection` / `buildCourseSelect` / `mapCourseRow` / `resolveCourseDisplayNames` / `CourseCoreRow`(P3 新增导出,供 data-access-selections 复用)
|
||||
- Data-access-operations:`selectCourse` / `dropCourse` / `runLottery` / `buildLotteryRankCase`(⚠️ 未导出,无法单测)
|
||||
- Data-access-selections:`getCourseSelections` / `getStudentSelections` / `getStudentGradeId` / `getAvailableCoursesForStudent`
|
||||
- Components:`ElectiveCourseList`(课程卡片网格 + 管理操作)/ `ElectiveCourseForm`(课程创建/编辑表单)/ `ElectiveFilters`(nuqs 筛选栏)/ `StudentSelectionView`(学生选课视图)
|
||||
- Actions(11 个):`getElectiveCoursesAction` / `createElectiveCourseAction` / `updateElectiveCourseAction` / `deleteElectiveCourseAction` / `getStudentSelectionsAction` / `selectCourseAction` / `dropCourseAction` / `runLotteryAction` / `getAvailableCoursesForStudentAction` / `openSelectionAction` / `closeSelectionAction`(✅ P2-2:8 个写 Action 错误消息改用 `getTranslations("elective")` 国际化)
|
||||
- Data-access:`getElectiveCourses` / `getElectiveCourseById` / `createElectiveCourse` / `updateElectiveCourse` / `deleteElectiveCourse` / `openSelection` / `closeSelection` / `buildCourseSelect` / `mapCourseRow` / `resolveCourseDisplayNames`(✅ P2-7:使用 React `cache()` 包装 subject/grade options 请求级去重;✅ P2-8:通过 `resolvers.ts` 接口抽象跨模块依赖)/ `CourseCoreRow`
|
||||
- Data-access-operations:`selectCourse`(✅ P2-9:新增 `checkScheduleConflict` 时间冲突检测;✅ P2-10:新增 `checkCreditLimit` 学分上限校验)/ `dropCourse` / `runLottery` / `buildLotteryRankCase`(⚠️ 未导出,无法单测)/ `checkScheduleConflict`(P2-9 新增)/ `checkCreditLimit`(P2-10 新增)
|
||||
- Data-access-selections:`getCourseSelections` / `getStudentSelections` / `getStudentGradeId`(✅ P2-8:通过 `resolvers.ts` StudentGradeResolver 接口抽象)/ `getAvailableCoursesForStudent` / `resolveStudentDisplayNames`(✅ P2-8:通过 `resolvers.ts` CourseDisplayResolver 接口抽象)
|
||||
- Resolvers(✅ P2-8 新增):`CourseDisplayResolver` / `StudentGradeResolver`(接口)/ `getCourseDisplayResolver` / `getStudentGradeResolver` / `setCourseDisplayResolver` / `setStudentGradeResolver` / `resetResolvers`(可注入测试 mock)
|
||||
- Lib 纯函数(✅ P2-9 新增):`parseSchedule`(解析时间段字符串)/ `isScheduleConflict`(判断两个时间段是否冲突)
|
||||
- Import-export(✅ P2-11 新增):`exportElectiveCoursesToExcel`(课程列表导出)/ `exportCourseSelectionsToExcel`(选课名单导出)
|
||||
- Components:`ElectiveCourseList`(课程卡片网格 + 管理操作)/ `ElectiveCourseForm`(课程创建/编辑表单)/ `ElectiveFilters`(nuqs 筛选栏)/ `StudentSelectionView`(学生选课视图)/ `ElectivePageLayout`(✅ P2-4 新增:页面布局骨架,admin/teacher 选课页复用)
|
||||
|
||||
**依赖关系**:
|
||||
- 依赖:`shared/*`、`@/auth`、`school`(✅ P3 已修复:通过 school data-access.getSubjectOptions/getGradeOptions 获取科目/年级名称,不再直查 subjects/grades 表)、`users`(✅ P3 已修复:通过 users data-access.getUserNamesByIds 获取教师姓名,不再直查 users 表)、`classes`(通过 classes data-access.getStudentActiveGradeId 获取学生年级)
|
||||
- 被依赖:无
|
||||
- 依赖:`shared/*`、`@/auth`、`school`(✅ P3 已修复:通过 school data-access.getSubjectOptions/getGradeOptions 获取科目/年级名称;✅ P2-8:通过 resolvers.ts 接口抽象)、`users`(✅ P3 已修复:通过 users data-access.getUserNamesByIds;✅ P2-8:通过 resolvers.ts 接口抽象)、`classes`(通过 classes data-access.getStudentActiveGradeId;✅ P2-8:通过 resolvers.ts 接口抽象)、`next-intl`(✅ P2-2:Server Action 错误消息 i18n)
|
||||
- 被依赖:`app/api/export`(✅ P2-11:通过 `exportElectiveCoursesToExcel` / `exportCourseSelectionsToExcel`)
|
||||
|
||||
**已知问题**(详见 `docs/architecture/audit/attendance-elective-audit-report.md`):
|
||||
- ✅ P2-2 已修复:8 个写 Action 错误消息改用 `getTranslations("elective")` 国际化
|
||||
- ✅ P2-4 已修复:新增 `ElectivePageLayout` 组件,admin/teacher 选课页复用布局
|
||||
- ✅ P2-7 已修复:`resolveCourseDisplayNames` 使用 React `cache()` 包装 subject/grade options 请求级去重
|
||||
- ✅ P2-8 已修复:新增 `resolvers.ts`,跨模块依赖(users/school/classes)通过接口抽象,支持测试注入 mock
|
||||
- ✅ P2-9 已修复:`selectCourse` 新增时间冲突检测(`parseSchedule` + `isScheduleConflict` 纯函数 + `checkScheduleConflict` 异步查询)
|
||||
- ✅ P2-10 已修复:`selectCourse` 新增学分上限校验(`checkCreditLimit`,MAX_CREDIT_PER_TERM=10)
|
||||
- ✅ P2-11 已修复:新增 `export.ts`,课程列表/选课名单可导出 Excel
|
||||
- ❌ P0:3 个读 Action 无调用方(`getElectiveCoursesAction`/`getStudentSelectionsAction`/`getAvailableCoursesForStudentAction`),页面绕过 Action 直接调用 data-access
|
||||
- ❌ P0:update/delete/select/drop/lottery Action 缺资源归属校验(教师 A 可操作教师 B 的课程,学生可退选他人课程)
|
||||
- ❌ P0:i18n 完全缺失(4 组标签/颜色常量硬编码英文,组件中硬编码中文)
|
||||
@@ -1464,16 +1495,19 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
**文件清单**:
|
||||
| 文件 | 行数 | 职责 |
|
||||
|------|------|------|
|
||||
| `actions.ts` | 304 | 11 个 Server Action |
|
||||
| `data-access.ts` | 250 | 课程 CRUD + scope 过滤 + 共享映射函数(P3 重构:移除跨模块 join,通过 school/users data-access 获取显示名称) |
|
||||
| `data-access-operations.ts` | 245 | 选课操作(select/drop/lottery,P3 重构:事务包裹 + FOR UPDATE 锁 + Fisher-Yates 洗牌) |
|
||||
| `data-access-selections.ts` | 149 | 选课记录查询 + 学生可选课程 |
|
||||
| `actions.ts` | 304 | 11 个 Server Action(P2-2:错误消息 i18n 化) |
|
||||
| `data-access.ts` | 250 | 课程 CRUD + scope 过滤 + 共享映射函数(P2-7:cache 包装;P2-8:resolvers 接口抽象) |
|
||||
| `data-access-operations.ts` | 370 | 选课操作(P2-9:时间冲突检测;P2-10:学分上限校验;P3:事务 + FOR UPDATE 锁 + Fisher-Yates 洗牌) |
|
||||
| `data-access-selections.ts` | 149 | 选课记录查询 + 学生可选课程(P2-8:resolvers 接口抽象) |
|
||||
| `resolvers.ts` | 83 | 跨模块依赖接口抽象(P2-8 新增:CourseDisplayResolver/StudentGradeResolver + 注入/重置函数) |
|
||||
| `export.ts` | 102 | Excel 导出(P2-11 新增:课程列表 + 选课名单双函数) |
|
||||
| `schema.ts` | 132 | Zod 校验 |
|
||||
| `types.ts` | 108 | 类型定义 + 4 组标签/颜色常量(硬编码英文) |
|
||||
| `components/elective-course-list.tsx` | 233 | 课程卡片网格 + 管理操作 |
|
||||
| `components/elective-course-form.tsx` | 293 | 课程创建/编辑表单 |
|
||||
| `components/elective-filters.tsx` | 49 | nuqs 筛选栏(搜索 + 模式) |
|
||||
| `components/student-selection-view.tsx` | 250 | 学生选课视图(已选 + 可选) |
|
||||
| `components/elective-page-layout.tsx` | 30 | 页面布局骨架(P2-4 新增:header/children 插槽) |
|
||||
|
||||
---
|
||||
|
||||
@@ -1490,7 +1524,8 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
- 被依赖:无
|
||||
|
||||
**已知问题**:
|
||||
- ❌ P0:`exam-mode-config.tsx` 未集成到考试表单(死代码,监考功能无法启用)
|
||||
- ✅ P1-2 已修复:`exam-mode-config.tsx` 已集成到考试表单(`exam-form.tsx` 调用 `<ExamModeConfig />`),移除全部 10 处 `as` 类型断言,改用 `useFormContext` 替代 `Control` prop 避免 `Control<T>` 不变型问题
|
||||
- ✅ P1-3 已修复:`proctoring-dashboard.tsx` 用类型守卫函数 `isProctoringEventType` + `toProctoringEventTypes` 替代 `Object.keys(...) as ProctoringEventType[]` 断言
|
||||
- ✅ P0-6 已修复:~~事件上报存在 Server Action 与 REST API 双通道重复~~ 删除 `/api/proctoring/event` REST 路由(移至 deletes/),Server Action `recordProctoringEventAction` 为唯一规范路径
|
||||
- ✅ P1-1 已修复:~~跨模块直查 `exams`/`examSubmissions`/`users`~~ 改为通过 exams/users data-access 函数获取数据
|
||||
- ✅ P2 已修复:`actions.ts` 不再直接 import `db` 和 `examSubmissions`,submission 归属校验已下沉到 data-access;`recordProctoringEventAction` 改用 `requirePermission(EXAM_SUBMIT)` 并增加 `revalidatePath`
|
||||
@@ -1503,8 +1538,8 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
| `actions.ts` | 139 | 2 个 Server Action |
|
||||
| `types.ts` | 136 | 类型定义 + 标签常量 + 阈值常量 |
|
||||
| `components/anti-cheat-monitor.tsx` | - | 学生端防作弊监控 |
|
||||
| `components/exam-mode-config.tsx` | - | 考试模式配置(**未集成**) |
|
||||
| `components/proctoring-dashboard.tsx` | - | 教师监考面板 |
|
||||
| `components/exam-mode-config.tsx` | - | 考试模式配置(✅ P1-2 已修复:已集成到 exam-form,useFormContext 替代 Control prop,无 as 断言) |
|
||||
| `components/proctoring-dashboard.tsx` | - | 教师监考面板(✅ P1-3 已修复:类型守卫函数替代 as 断言) |
|
||||
|
||||
---
|
||||
|
||||
@@ -1513,9 +1548,9 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
**职责**:知识点掌握度查询 + 诊断报告生成。
|
||||
|
||||
**导出函数**:
|
||||
- Actions:`generateStudentReportAction` / `generateClassReportAction` / `publishReportAction` / `deleteReportAction`(v2-P2-3 修复:删除死代码 `getDiagnosticReportsAction` / `getDiagnosticReportByIdAction`,页面直接调用 data-access 并自行权限校验)
|
||||
- Actions:`generateStudentReportAction` / `generateClassReportAction` / `publishReportAction`(v4-P1-4 + v4-P1-5 增强:班级报告发布时通知全班学生 + 全班学生家长,个人报告通知学生本人 + 其家长,调用 `parent/data-access.getParentIdsByStudentIds` 批量查询家长 ID)/ `deleteReportAction`(v2-P2-3 修复:删除死代码 `getDiagnosticReportsAction` / `getDiagnosticReportByIdAction`,页面直接调用 data-access 并自行权限校验)
|
||||
- Data-access:`updateMasteryFromSubmission`(v2-P1-8 修复:累积模式;v2-P2-5 修复:db.transaction 包裹)/ `getStudentMastery`(P3-19 修复:移除 export,改为模块内部函数)/ `getStudentMasterySummary`(P3-18 修复:getUserNamesByIds 与 getStudentMastery 并行查询)/ `getClassMasterySummary`(v2-P2-4 修复:totalStudents 语义 + 班级平均掌握度按学生平均)/ `getKnowledgePointStats`(v2-P1-7 修复:页面先查班级再传参)
|
||||
- Data-access-reports:`generateDiagnosticReport` / `generateClassDiagnosticReport`(v2-P2-6 修复:校验掌握度数据;P3-27 修复:使用 DiagnosticReportError 结构化错误码)/ `getDiagnosticReports`(P3-15 修复:支持分页 limit/offset,返回 { reports, total } 结构)/ `getDiagnosticReportById` / `publishDiagnosticReport` / `deleteDiagnosticReport`(✅ P2 已修复:使用 `React.cache()` 包装实现请求级 memoization;P3-1 修复:toNumber 从 grades 模块导入)/ `DiagnosticReportError`(P3-27 新增:结构化错误码类)
|
||||
- Data-access-reports:`generateDiagnosticReport` / `generateClassDiagnosticReport`(v2-P2-6 修复:校验掌握度数据;P3-27 修复:使用 DiagnosticReportError 结构化错误码)/ `getDiagnosticReports`(P3-15 修复:支持分页 limit/offset,返回 { reports, total } 结构;v4-P1-1 增强:新增可选 `scope?: DataScope` 参数,支持 children/class_taught 行级权限过滤,class_taught 通过 `getStudentIdsByClassIds` 解析所教班级学生 ID)/ `getDiagnosticReportById` / `publishDiagnosticReport` / `deleteDiagnosticReport`(✅ P2 已修复:使用 `React.cache()` 包装实现请求级 memoization;P3-1 修复:toNumber 从 grades 模块导入)/ `DiagnosticReportError`(P3-27 新增:结构化错误码类)
|
||||
- Stats-service(✅ v2-P1-6 新增):`serializeMasteryWithKp` / `computeAverageMastery` / `classifyStrengthsWeaknesses`(P3-16 修复:弱项阈值从 <60 改为 <80,消除 60-79 盲区)/ `buildStudentMasterySummary` / `aggregateClassMastery` / `computeKpStats` / `computeClassAverageMastery` / `buildStudentsNeedingAttention` / `buildClassMasterySummary` / `buildStudentReportContent` / `buildClassReportContent` / `computeMasteryLevel` / `serializeMastery`(从 data-access / data-access-reports 抽取的纯统计函数)
|
||||
- Schema:`GenerateStudentReportSchema` / `GenerateClassReportSchema` / `PublishReportSchema` / `DeleteReportSchema`(v2-P2-3 修复:删除死代码 `GetDiagnosticReportsSchema` / `GetDiagnosticReportByIdSchema`)
|
||||
|
||||
@@ -1551,18 +1586,28 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
- ✅ P3-18 已修复(2026-06-23):~~`getStudentMasterySummary` 串行查询用户名和掌握度~~ 改为 Promise.all 并行查询
|
||||
- ✅ P3-19 已修复(2026-06-23):~~`getStudentMastery` 使用 export 但仅内部使用~~ 移除 export,改为模块内部函数
|
||||
- ✅ P3-27 已修复(2026-06-23):~~`generateDiagnosticReport` / `generateClassDiagnosticReport` 中 `throw new Error("...")` 直接暴露给用户~~ 改为使用 `DiagnosticReportError` 结构化错误码(继承 BusinessError)
|
||||
- ✅ P3-21 已修复(2026-06-23):`ClassDiagnosticView` View 按钮已有描述性 aria-label(`classDiagnostic.viewAriaLabel`,含学生名)
|
||||
- ✅ P3-22 已修复(2026-06-23):`StudentDiagnosticView` Practice 按钮添加 aria-label(`studentDiagnostic.practiceAriaLabel`,含知识点名)
|
||||
- ✅ v4-P3-6 已修复(2026-06-23):`MasteryRadarChart` 雷达图添加 `tabIndex={0}` 键盘可达性 + `focus-visible` 焦点样式(原有 `role="img"` + `aria-label` 保留)
|
||||
- ✅ v4-P1-1 改进(2026-06-23):`getDiagnosticReports` 新增可选 `scope?: DataScope` 参数,支持 children/class_taught 行级权限过滤;teacher/diagnostic/page.tsx 传入 dataScope;student/diagnostic/page.tsx 传 status:"published" + dataScope;parent/diagnostic/page.tsx 传 status:"published" + dataScope + 错误卡片
|
||||
- ✅ v4-P1-3 改进(2026-06-23):`student-diagnostic-view.tsx` 移除草稿回退逻辑(不再展示 draft 状态报告)
|
||||
- ✅ v4-P1-4 + v4-P1-5 改进(2026-06-23):`publishReportAction` 班级报告发布时通知全班学生 + 全班学生家长(通过 `getStudentIdsByClassId` 获取全班学生,通过 `parent/data-access.getParentIdsByStudentIds` 获取家长 ID);个人报告通知学生本人 + 其家长
|
||||
- ✅ v4-P1-8 + v4-P1-11 改进(2026-06-23):`class-diagnostic-view.tsx` 热力图添加图例 + 表格 `overflow-x-auto` 水平滚动
|
||||
- ✅ v4-P1-9 改进(2026-06-23):parent/diagnostic/page.tsx 新增错误卡片(Error Card)展示子女诊断查询失败原因
|
||||
- ✅ v4-P1 数据库变更(2026-06-23):`learningDiagnosticReports` 表新增 `classId` 字段(varchar(128), references classes.id, onDelete: set null)+ `diagnostic_class_idx` 索引;`DiagnosticReport` 接口新增 `classId: string | null` 字段(班级报告关联班级 ID,个人报告为 null)
|
||||
- ✅ v4-P1 师生关系校验(2026-06-23):teacher/diagnostic/student/[studentId]/page.tsx 新增 class_taught 师生关系校验
|
||||
|
||||
**文件清单**:
|
||||
| 文件 | 行数 | 职责 |
|
||||
|------|------|------|
|
||||
| `data-access.ts` | 179 | 知识点掌握度查询 + 更新(v2-P1-8 累积模式;v2-P2-5 事务;v2-P2-4 语义修正;v2-P1-6 改用 stats-service 纯函数) |
|
||||
| `data-access-reports.ts` | 160 | 诊断报告 CRUD(v2-P2-6 校验;v2-P1-6 改用 stats-service 纯函数) |
|
||||
| `data-access-reports.ts` | 183+ | 诊断报告 CRUD(v2-P2-6 校验;v2-P1-6 改用 stats-service 纯函数;v4-P1-1:getDiagnosticReports 新增 scope 参数支持行级权限过滤) |
|
||||
| `stats-service.ts` | 352 | 统计计算纯函数(v2-P1-6 新增:12 个纯函数 + 2 个常量 + 4 个接口) |
|
||||
| `actions.ts` | 111 | 4 个 Server Action(v2-P2-3 删除 2 个死代码读 Action) |
|
||||
| `actions.ts` | 165+ | 4 个 Server Action(v2-P2-3 删除 2 个死代码读 Action;v4-P1-4/v4-P1-5:publishReportAction 新增全班学生 + 家长通知) |
|
||||
| `schema.ts` | 23 | Zod 校验(4 个 schema,v2-P2-3 删除 2 个死代码 schema) |
|
||||
| `types.ts` | 87 | 类型定义 |
|
||||
| `components/class-diagnostic-view.tsx` | 266 | 班级诊断视图(v2-P1-6 热力图 a11y;v2-P1-4 i18n) |
|
||||
| `components/student-diagnostic-view.tsx` | 225+ | 学生诊断视图(v2-P1-4 i18n;v3-P2 新增:practiceHrefBase prop,null 时隐藏练习按钮) |
|
||||
| `components/class-diagnostic-view.tsx` | 266 | 班级诊断视图(v2-P1-6 热力图 a11y;v2-P1-4 i18n;v4-P1-8 热力图图例;v4-P1-11 表格 overflow-x-auto) |
|
||||
| `components/student-diagnostic-view.tsx` | 225+ | 学生诊断视图(v2-P1-4 i18n;v3-P2 新增:practiceHrefBase prop,null 时隐藏练习按钮;v4-P1-3 移除草稿回退逻辑) |
|
||||
| `components/mastery-radar-chart.tsx` | 72 | 雷达图(v2-P1-4 i18n) |
|
||||
| `components/report-list.tsx` | 265 | 报告列表(v2-P2-7 Label htmlFor;v2-P1-4 i18n) |
|
||||
|
||||
@@ -1940,9 +1985,9 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
|
||||
---
|
||||
|
||||
## 2.29 ai(AI 模块)— ✅ 新增 / V2 增强
|
||||
## 2.29 ai(AI 模块)— ✅ 新增 / V2 增强 / V3 安全加固+竞品对标
|
||||
|
||||
**职责**:统一 AI 能力封装,为备课、错题集、试卷、改题等业务模块提供 AI 服务。V2 增加流式响应、Markdown 渲染、全局助手、内容安全过滤、家长学情摘要、管理员使用统计、学生学习路径推荐。
|
||||
**职责**:统一 AI 能力封装,为备课、错题集、试卷、改题等业务模块提供 AI 服务。V2 增加流式响应、Markdown 渲染、全局助手、内容安全过滤、家长学情摘要、管理员使用统计、学生学习路径推荐。V3 安全加固(原子配额/苏格拉底校验/重试机制)+ 竞品对标(知识图谱集成/苏格拉底式辅导强化)。
|
||||
|
||||
**架构定位**:
|
||||
- 位于 `modules/` 层,通过 `shared/lib/ai` 调用底层 AI SDK
|
||||
@@ -1989,6 +2034,13 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|
||||
| **Safety** | `filterUserInput` | `modules/ai/services/content-safety.ts` | 输入安全过滤 — V2 新增 |
|
||||
| **Safety** | `filterAiOutput` | `modules/ai/services/content-safety.ts` | 输出安全过滤 — V2 新增 |
|
||||
| **Safety** | `checkDailyLimit` | `modules/ai/services/content-safety.ts` | 每日交互限制 — V2 新增 |
|
||||
| **Safety** | `tryConsumeDailyQuota` | `modules/ai/services/content-safety.ts` | 原子化每日限额(防 TOCTOU 竞态)— V3 新增 |
|
||||
| **Safety** | `refundDailyQuota` | `modules/ai/services/content-safety.ts` | 配额回退(过滤/失败时不扣配额)— V3 新增 |
|
||||
| **Safety** | `validateSocraticOutput` | `modules/ai/services/content-safety.ts` | 苏格拉底式辅导输出校验(问号结尾/连续陈述句限制)— V3 新增 |
|
||||
| **Data Access** | `recordAiEvent` | `modules/ai/data-access.ts` | AI 事件记录(内存存储,生产环境替换为 DB)— V3 新增 |
|
||||
| **Data Access** | `getAiUsageStats` | `modules/ai/data-access.ts` | AI 使用统计聚合(真实聚合,替代硬编码零)— V3 新增 |
|
||||
| **Prompt** | `SOCRATIC_TUTOR_SYSTEM_PROMPT` | `modules/ai/services/prompt-templates.ts` | 苏格拉底式辅导专用提示词(3 级提示升级/禁止直接给答案)— V3 新增 |
|
||||
| **Util** | `consumeSseStream` / `getStreamErrorKey` / `removeTrailingEmptyAssistant` | `modules/ai/hooks/stream-utils.ts` | SSE 流解析工具(从 hook 抽取)— V3 新增 |
|
||||
|
||||
**集成点**:
|
||||
|
||||
@@ -2184,7 +2236,7 @@ shared/lib/{audit-logger, change-logger, auth-guard} → @/auth → shared/lib/*
|
||||
- ✅ 各模块 data-access 暴露查询接口:
|
||||
- `classes/data-access`:~~`getClassGradeIdsByClassIds`~~ ✅ 已实现 / `getClassStudentsByClassId` / `getActiveClassStudents` / `getClassExists` / `getClassNameById` / `getClassNamesByIds` / `getActiveStudentIdsByClassId` / `getStudentActiveClassId` / `getClassesByGradeId` / `verifyTeacherOwnsClass` / `getTeacherIdForMutations`
|
||||
- `exams/data-access`:~~`getExamForHomeworkCreation`~~ ✅ 已实现(`getExamIdsByGradeIds` / `getExamSubjectIdMap` / `getExamWithQuestionsForHomework` / `getExamSubmissionWithAnswers` / `getExamForProctoringCrossModule` / `getExamSubmissionForProctoringCrossModule` / `getExamSubmissionsForExam` / `getExamTitleById`)
|
||||
- `school/data-access`:~~`getSubjectOptions` / `getGradeOptions`~~ ✅ 已实现
|
||||
- `school/data-access`:~~`getSubjectOptions` / `getGradeOptions`~~ ✅ 已实现(含 `getSubjectNameMapByIds` 批量科目名称映射,P1-1 新增供 homework/data-access-classes 调用)
|
||||
- `users/data-access`:~~`getUserNameByIds` / `getStudentInfo`~~ ✅ 已实现(`getUserNamesByIds` / `getUserWithRole` / `getUserBasicInfo` / `getUserIdsByGradeId` / `getCurrentStudentUser`)
|
||||
- `textbooks/data-access`:~~`getKnowledgePointOptions`~~ ✅ 已实现
|
||||
- `questions/data-access`:~~`insertQuestionWithRelations`~~ ✅ 已通过 `createQuestionWithRelations` 供 exams 调用 / `getKnowledgePointsForQuestions`
|
||||
|
||||
Reference in New Issue
Block a user