docs: update architecture map and add lesson-preparation usage fixes design

- Update architecture impact map (004) and data (005) with new modules

- Add lesson-preparation usage fixes design spec

- Add teacher web test post-audit report
This commit is contained in:
SpecialX
2026-06-24 12:01:35 +08:00
parent 9d87388524
commit e4254f0f8e
5 changed files with 3139 additions and 107 deletions

View File

@@ -113,7 +113,7 @@
│ │ data-access │
┌─┴────────┐ │ │
│ grades │◀────┘ 仅外键引用(合理)
│ (成绩) │
│ (成绩) │◀──── exams data-access✅ 2026-06-24 新增getExamsForGradeEntry/getExamForGradeEntry 按试卷录入成绩)
└────┬─────┘
│ ✅ P1-1 已修复
│ 通过 classes/school/users data-access
@@ -499,7 +499,7 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
| `lib/ai.ts` | 9 | 向后兼容重导出P2-2 已拆分到 `ai/` 目录) |
| `lib/ai/payload-parser.ts` | 78 | 请求负载解析 |
| `lib/ai/api-key-crypto.ts` | 28 | API Key 加密/解密 |
| `lib/ai/provider-config.ts` | 61 | Provider 配置查询 |
| `lib/ai/provider-config.ts` | 132 | Provider 配置查询V3.1 增强:基于 session 用户的可见性/所有权校验public + own private 过滤) |
| `lib/ai/client.ts` | 58 | AI 客户端创建与调用 |
| `lib/ai/errors.ts` | 8 | 错误格式化 |
| `lib/ai/index.ts` | 5 | 聚合导出 |
@@ -541,15 +541,16 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
**导出函数**
- Actions`createExamAction` / `createAiExamAction` / `previewAiExamAction` / `regenerateAiQuestionAction` / `updateExamAction` / `deleteExamAction` / `duplicateExamAction` / `getExamPreviewAction` / `getSubjectsAction` / `getGradesAction` / `getExamsByGradeIdAction`(✅ v4-P2-7 新增年级仪表盘维度3按 gradeId 查询年级下所有考试 + 提交统计EXAM_READ 权限)(✅ P1-2 已修复actions 层不再直接访问 DB全部下沉到 data-access
- Data-access`getExams` / `getExamById` / `persistExamDraft` / `persistAiGeneratedExamDraft` / `buildExamDescription` / `resolveSubjectGradeNames` / `getExamCreatorId` / `updateExamWithQuestions` / `deleteExamById` / `duplicateExam` / `getExamPreview` / `getExamSubjects` / `getExamGrades` / `getExamsByGradeId`(✅ v4-P2-7 新增年级仪表盘维度3exams 表有直接 gradeId 字段,配合 examSubmissions 聚合提交数/已评分数/平均分,支持 scope 行级过滤)(后 8 个为 P1-2 新增)
- Data-access`getExams` / `getExamById` / `persistExamDraft` / `persistAiGeneratedExamDraft` / `buildExamDescription` / `resolveSubjectGradeNames` / `getExamCreatorId` / `updateExamWithQuestions` / `deleteExamById` / `duplicateExam` / `getExamPreview` / `getExamSubjects` / `getExamGrades` / `getExamsByGradeId`(✅ v4-P2-7 新增年级仪表盘维度3exams 表有直接 gradeId 字段,配合 examSubmissions 聚合提交数/已评分数/平均分,支持 scope 行级过滤)(后 8 个为 P1-2 新增)/ `getExamsForGradeEntry`(✅ 2026-06-24 新增:按 scope 过滤试卷列表,只返回有题目的试卷,供成绩录入页试卷选择器使用,返回 id/title/subjectName/gradeName/questionCount/totalScore/ `getExamForGradeEntry`(✅ 2026-06-24 新增获取单个试卷详情含题目列表innerJoin questions 获取 type含 scope 校验,返回 id/title/subjectId/gradeId/totalScore/questions[{id,order,score,type}],供 grades 模块按试卷录入成绩使用)
- AI Pipeline`generateAiCreateDraftFromSource` / `generateAiPreviewData` / `regenerateAiQuestionByInstruction`
- Utils`normalizeStructure`v3 新增:将持久化的 `exam.structure` unknown JSON 运行时校验并归一化为类型安全的 `ExamNode[]`,类型守卫模式无 `as` 断言,从 `teacher/exams/[id]/build/page.tsx` 提取)
- Stats-serviceV3-8 新增):`getExamAnalytics`cache 包装,聚合考试所有作业的已批改提交,计算平均分/及格率/分数段分布/逐题错误率与难度等级,对标智学网考试分析)+ `ExamAnalyticsSummary` 类型
- Types✅ 2026-06-24 新增成绩录入相关类型):`ExamQuestionItem`(试卷中单个题目的精简结构 { id, order, score, type }/ `ExamForGradeEntry`(成绩录入用的试卷详情,含题目列表)/ `ExamOptionForEntry`(成绩录入页试卷选择器选项 { id, title, subjectName, gradeName, questionCount, totalScore }
- ComponentsV3-8 新增):`ExamAnalyticsDashboard`(考试分析仪表盘:汇总卡片+分数段分布+逐题分析表)
**依赖关系**
- 依赖:`shared/*``@/auth``questions`(✅ P0-1 已修复:通过 data-access.createQuestionWithRelations`classes`(✅ P0-2 已修复:通过 data-access.getClassGradeIdsByClassIds`school`(✅ P1-1 已修复:通过 school data-access.getSubjectOptions/getGradeOptions`homework`V3-8 新增stats-service 通过 `homework/data-access.getHomeworkAssignmentsByExamId` / `getGradedSubmissionsByExamId` 获取作业与提交数据,合理跨模块调用)
- 被依赖:`homework`(通过 sourceExamId 外键,合理)、`dashboard`(通过 data-accessP0-4 已修复)、`proctoring`(✅ P1-1 已修复:通过 exams data-access`diagnostic`(✅ P1-1 已修复:通过 exams data-access
- 被依赖:`homework`(通过 sourceExamId 外键,合理)、`dashboard`(通过 data-accessP0-4 已修复)、`proctoring`(✅ P1-1 已修复:通过 exams data-access`diagnostic`(✅ P1-1 已修复:通过 exams data-access`grades`(✅ 2026-06-24 新增:通过 data-access.getExamsForGradeEntry/getExamForGradeEntry 获取试卷列表和详情供按试卷录入成绩使用)
**已知问题**
- ✅ P0-1 已修复:~~`persistAiGeneratedExamDraft` 直接 insert 到 `questions` 表~~ 改为调用 `questions/data-access.createQuestionWithRelations`,通过 ID 映射保持 structure 引用一致
@@ -565,9 +566,9 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
|------|------|------|
| `actions.ts` | 691 | 10 个 Server ActionP1-2 已修复,无直接 DB 操作) |
| `ai-pipeline.ts` | 857 | AI 出题管线(超限) |
| `data-access.ts` | 473 | 考试 CRUD含 P1-2 新增 7 个写/查询函数P0-1/P0-2 已修复:通过 questions/classes data-access 跨模块通信) |
| `data-access.ts` | 560+ | 考试 CRUD含 P1-2 新增 7 个写/查询函数P0-1/P0-2 已修复:通过 questions/classes data-access 跨模块通信v4-P2-7 新增 getExamsByGradeId2026-06-24 新增 getExamsForGradeEntry/getExamForGradeEntry 供 grades 模块按试卷录入成绩 |
| `stats-service.ts` | - | V3-8 新增:考试分析数据聚合(`getExamAnalytics` + `ExamAnalyticsSummary` 类型) |
| `types.ts` | 31 | 类型定义 |
| `types.ts` | 50+ | 类型定义2026-06-24 新增ExamQuestionItem/ExamForGradeEntry/ExamOptionForEntry 供成绩录入使用) |
| `hooks/use-exam-preview.ts` | 295 | 预览 Hook |
| `utils/normalize-structure.ts` | 57 | v3 新增exam.structure 运行时校验与归一化(从 build/page.tsx 提取) |
| `components/exam-analytics-dashboard.tsx` | - | V3-8 新增:考试分析仪表盘组件 |
@@ -725,16 +726,16 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
**职责**:成绩分析(录入/查询/统计/导出/趋势对比分析)。
**导出函数**
- Actions`getGradeRecordsAction` / `createGradeRecordAction`v4-P1-6 增强:成绩录入后通知学生和家长,调用 `notifyGradeEntered`/ `updateGradeRecordAction` / `deleteGradeRecordAction` / `exportGradesAction`v4-P1-12 增强:新增可选 `studentId` 参数,支持按学生导出,家长视角调用 `exportStudentGradeRecordsToExcel`,校验 studentId 属于家长子女)/ `getGradeTrendAction` / `getClassComparisonAction` / `getSubjectComparisonAction` / `getGradeDistributionAction` / `getGradeDistributionByGradeIdAction`(✅ v4-P2-7 新增年级仪表盘维度1按 gradeId 查询年级整体 + 按班级拆分的成绩分布GRADE_RECORD_READ 权限)/ `getClassRankingAction` / `getRankingTrendAction` / `getGradeRecordByIdAction` / `getClassGradeStatsAction` / `getStudentGradeSummaryAction` / `batchCreateGradeRecordsAction`v4-P1-6 增强:批量成绩录入后通知学生和家长)/ `saveGradeDraftAction` / `getGradeDraftAction` / `deleteGradeDraftAction`(✅ v3-P2 新增:成绩录入草稿 Server Actions分别使用 GRADE_RECORD_MANAGE/GRADE_RECORD_READ/GRADE_RECORD_MANAGE 权限)。注:`assertClassInScope` 原位于 actions.ts✅ P3 新增导出:班级 scope 校验工具,供 actions-analytics 复用),✅ v4-P2-6 修复:因 "use server" 文件要求所有 export 为 async`assertClassInScope` 是同步函数,已迁移至独立文件 `lib/scope-check.ts`actions.ts 与 actions-analytics.ts 均从 `./lib/scope-check` 导入
- Data-access`getGradeRecords` / `getStudentGradeSummary` / `getClassRanking` / `getClassStudentsForEntry` / `getClassGradeStats` / `getClassGradeStatsWithMeta` / `getGradeTrend` / `getClassComparison` / `getSubjectComparison` / `getGradeDistribution` / `getGradeDistributionByGradeId`(✅ v4-P2-7 新增年级仪表盘维度1通过 getClassesByGradeId 获取年级下所有班级inArray 查询成绩记录,复用 computeGradeDistribution/computeGradeStats 纯函数,返回整体分布 + 按班级拆分)/ `getRankingTrend` / `PaginatedGradeRecords`(✅ P3 新增:分页结果接口 `{ records, total }`/ `saveGradeDraft` / `getGradeDraft` / `deleteGradeDraft`(✅ v3-P2 新增:成绩录入草稿 CRUDupsert + 24 小时过期)/ `getExamOptionsForGrades` / `getSchoolWideGradeSummary`(✅ v3-P2 新增:考试选项查询 + 全校各年级成绩汇总,管理员视图按年级聚合平均分/及格率/优秀率/学生数/班级数,加权平均计算全校汇总)
- Types✅ v3-P2 新增,✅ v4-P2-7 新增年级分布类型):`SchoolWideGradeSummaryItem` / `SchoolWideGradeSummary` / `GradeDraftData`(草稿数据接口)/ `GradeDistributionByGradeResult`(✅ v4-P2-7 新增:年级维度成绩分布结果,含 overall 整体分布 + stats 统计 + byClass 按班级拆分数组)/ `GradeDistributionByGradeClassItem`(✅ v4-P2-7 新增按班级拆分的分布项classId/className/distribution/stats
- Actions`getGradeRecordsAction` / `createGradeRecordAction`v4-P1-6 增强:成绩录入后通知学生和家长,调用 `notifyGradeEntered`/ `updateGradeRecordAction` / `deleteGradeRecordAction` / `exportGradesAction`v4-P1-12 增强:新增可选 `studentId` 参数,支持按学生导出,家长视角调用 `exportStudentGradeRecordsToExcel`,校验 studentId 属于家长子女)/ `getGradeTrendAction` / `getClassComparisonAction` / `getSubjectComparisonAction` / `getGradeDistributionAction` / `getGradeDistributionByGradeIdAction`(✅ v4-P2-7 新增年级仪表盘维度1按 gradeId 查询年级整体 + 按班级拆分的成绩分布GRADE_RECORD_READ 权限)/ `getClassRankingAction` / `getRankingTrendAction` / `getGradeRecordByIdAction` / `getClassGradeStatsAction` / `getStudentGradeSummaryAction` / `batchCreateGradeRecordsAction`v4-P1-6 增强:批量成绩录入后通知学生和家长)/ `batchCreateGradeRecordsByExamAction`(✅ 2026-06-24 新增:按试卷批量录入每题得分,流程 requirePermission → getExamForGradeEntry scope 校验 → assertClassInScope → safeJsonParse → BatchGradeEntryByExamSchema 校验 → batchCreateGradeRecordsByExam 单事务写入 → updateMasteryFromExamScore → notifyGradeEntered → revalidatePath返回 gradeRecordId 列表供撤销)/ `saveGradeDraftAction` / `getGradeDraftAction` / `deleteGradeDraftAction`(✅ v3-P2 新增:成绩录入草稿 Server Actions分别使用 GRADE_RECORD_MANAGE/GRADE_RECORD_READ/GRADE_RECORD_MANAGE 权限)。注:`assertClassInScope` 原位于 actions.ts✅ P3 新增导出:班级 scope 校验工具,供 actions-analytics 复用),✅ v4-P2-6 修复:因 "use server" 文件要求所有 export 为 async`assertClassInScope` 是同步函数,已迁移至独立文件 `lib/scope-check.ts`actions.ts 与 actions-analytics.ts 均从 `./lib/scope-check` 导入
- Data-access`getGradeRecords` / `getStudentGradeSummary` / `getClassRanking` / `getClassStudentsForEntry` / `getClassGradeStats` / `getClassGradeStatsWithMeta` / `getGradeTrend` / `getClassComparison` / `getSubjectComparison` / `getGradeDistribution` / `getGradeDistributionByGradeId`(✅ v4-P2-7 新增年级仪表盘维度1通过 getClassesByGradeId 获取年级下所有班级inArray 查询成绩记录,复用 computeGradeDistribution/computeGradeStats 纯函数,返回整体分布 + 按班级拆分)/ `getRankingTrend` / `PaginatedGradeRecords`(✅ P3 新增:分页结果接口 `{ records, total }`/ `saveGradeDraft` / `getGradeDraft` / `deleteGradeDraft`(✅ v3-P2 新增:成绩录入草稿 CRUDupsert + 24 小时过期)/ `getExamOptionsForGrades` / `getSchoolWideGradeSummary`(✅ v3-P2 新增:考试选项查询 + 全校各年级成绩汇总,管理员视图按年级聚合平均分/及格率/优秀率/学生数/班级数,加权平均计算全校汇总)/ `batchCreateGradeRecordsByExam`(✅ 2026-06-24 新增:按试卷批量录入成绩,单事务写入 grade_records + grade_record_answers + 投影到 exam_submissions(status=graded) + submission_answers(answerContent=null),使错题集/成绩分析等下游模块无需改造即可读取教师录入的成绩,返回 gradeRecordId 列表供撤销)
- Types✅ v3-P2 新增,✅ v4-P2-7 新增年级分布类型,✅ 2026-06-24 新增按试卷录入类型`SchoolWideGradeSummaryItem` / `SchoolWideGradeSummary` / `GradeDraftData`(草稿数据接口)/ `GradeDistributionByGradeResult`(✅ v4-P2-7 新增:年级维度成绩分布结果,含 overall 整体分布 + stats 统计 + byClass 按班级拆分数组)/ `GradeDistributionByGradeClassItem`(✅ v4-P2-7 新增按班级拆分的分布项classId/className/distribution/stats/ `GradeRecordAnswer`(✅ 2026-06-24 新增:成绩记录-题目得分明细,对应 grade_record_answers 表)/ `BatchGradeEntryByExamQuestion`(✅ 2026-06-24 新增:按试卷录入时单个题目得分 { questionId, score }/ `BatchGradeEntryByExamItem`(✅ 2026-06-24 新增:按试卷录入时单个学生所有题目得分 { studentId, answers }
- Lib✅ P1-2 新增,✅ P3 更新签名,✅ P3-26 拆分,✅ v4-P2-6 新增 scope-check`toNumber` / `normalize`(位于 `lib/grade-utils.ts``buildScopeClassFilter(scope, currentUserId?)`P3-26 从 grade-utils.ts 迁移至 `lib/scope-filter.ts`P3 修复:`class_members` scope 内置 studentId 过滤,需传入 currentUserId 参数);`assertClassInScope(scope: DataScope, classId: string): string | null`(✅ v4-P2-6 从 actions.ts 迁移至 `lib/scope-check.ts`:校验 classId 是否在 scope 允许范围内,供 actions.ts 与 actions-analytics.ts 复用。迁移原因actions.ts 是 "use server" 文件要求所有 export 为 async而 assertClassInScope 是同步函数)
- Stats-service✅ P1-1 新增):`computeGradeStats` / `computeAverageScore` / `buildGradeTrendPoints` / `computeTrendAverage` / `computeClassComparisonStats` / `computeSubjectComparisonStats` / `computeGradeDistribution` / `buildRankingTrendPoints`(从 3 个 data-access 文件抽取的纯函数,使数据层专注 DB I/O统计逻辑可独立测试
- 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
- 依赖:`shared/*``@/auth``classes`(✅ P1-1 已修复:通过 classes data-access.getClassExists/getClassNameById/getClassNamesByIds/getActiveStudentIdsByClassId/getStudentActiveClassId/getClassesByGradeId/getClassGradeIdsByClassIds)、`school`(✅ P1-1 已修复:通过 school data-access.getSubjectOptions/getGradeOptions`users`(✅ P1-1 已修复:通过 users data-access.getUserNamesByIds`exams`(✅ 2026-06-24 新增:通过 exams data-access.getExamsForGradeEntry/getExamForGradeEntry 获取试卷列表和详情供按试卷录入成绩使用)
- 被依赖:`parent`(通过 data-access合理`dashboard`
**已知问题**
@@ -784,22 +785,23 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
- ✅ v3-P3-2 改进2026-06-23`grade-record-list.tsx` 新增多选复选框(全选/单选)+ 批量删除工具栏 + 批量删除确认对话框;新增 `bulkDeleteGradeRecords` data-access 函数(使用 inArray 一次性删除避免 N+1+ `bulkDeleteGradeRecordsAction` Server Action限制单次最多 500 条)
- ✅ v4-P3-2 改进2026-06-23`batch-grade-entry.tsx` 顶部新增可折叠新手引导提示框4 步使用说明),使用 localStorage 记住用户关闭状态避免重复显示
- ✅ v4-P2-6 修复2026-06-23~~`assertClassInScope` 是同步函数但位于 "use server" 文件 actions.ts 中~~ Next.js 要求 "use server" 文件中所有 export 必须为 async同步 export 会导致构建错误。修复:将 `assertClassInScope` 迁移至独立文件 `lib/scope-check.ts`(含 `import "server-only"`actions.ts 与 actions-analytics.ts 均从 `./lib/scope-check` 导入
- ✅ 2026-06-24 重新设计:批量录入从"只录总分"改为"按试卷录入每题得分"。新增 `grade_record_answers` 表存储每题得分明细(迁移 0010_grade_record_answers.sql`batchCreateGradeRecordsByExam` data-access 单事务写入 grade_records + grade_record_answers + 投影到 exam_submissions(status=graded) + submission_answers(answerContent=null),使错题集/成绩分析等下游模块无需改造即可读取教师录入的成绩(学生只看到对错,不知道学生答案)。`BatchGradeEntryByExam` 组件完全重写为 Excel 式表格(行=学生,列=题目,末列=总分自动计算支持多行多列粘贴、Enter 跳下一行、Tab 跳下一格、分数校验、撤销机制sessionStorage 5 分钟有效)。新增对 `exams` 模块的依赖getExamsForGradeEntry/getExamForGradeEntry。i18n 新增 batchByExam 章节zh-CN/en ~35 键)
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | 670+ | 19 个 Server Action含 Zod 校验,含 v2-P1-5 安全修复assertClassInScope + 行级 scope 校验P3 修复handleActionError + safeJsonParse + scope 传递 + DB 层分页v3-P2 新增saveGradeDraftAction/getGradeDraftAction/deleteGradeDraftActionv4-P1-6createGradeRecordAction/batchCreateGradeRecordsAction 新增通知v4-P1-12exportGradesAction 新增 studentId 参数v3-P3-2 新增bulkDeleteGradeRecordsAction 批量删除v4-P2-6assertClassInScope 迁移至 lib/scope-check.ts |
| `actions.ts` | 770+ | 20 个 Server Action含 Zod 校验,含 v2-P1-5 安全修复assertClassInScope + 行级 scope 校验P3 修复handleActionError + safeJsonParse + scope 传递 + DB 层分页v3-P2 新增saveGradeDraftAction/getGradeDraftAction/deleteGradeDraftActionv4-P1-6createGradeRecordAction/batchCreateGradeRecordsAction 新增通知v4-P1-12exportGradesAction 新增 studentId 参数v3-P3-2 新增bulkDeleteGradeRecordsAction 批量删除v4-P2-6assertClassInScope 迁移至 lib/scope-check.ts2026-06-24 新增batchCreateGradeRecordsByExamAction 按试卷录入每题得分 |
| `actions-analytics.ts` | 170 | 5 个分析 Action含 Zod 校验P3 修复handleActionError + assertClassInScope 校验v4-P2-6assertClassInScope 改从 ./lib/scope-check 导入) |
| `data-access.ts` | 450+ | 成绩 CRUD + 统计 + 草稿(含 v2-P2-9 修复recorderName 批量查询P3 修复PaginatedGradeRecords 接口 + DB 层分页 + 事务 + 存在性检查 + scope 过滤 + 并列排名v3-P2 新增saveGradeDraft/getGradeDraft/deleteGradeDraft + GradeDraftData 接口v3-P3-2 新增bulkDeleteGradeRecords 使用 inArray 批量删除) |
| `data-access.ts` | 600+ | 成绩 CRUD + 统计 + 草稿 + 按试卷录入(含 v2-P2-9 修复recorderName 批量查询P3 修复PaginatedGradeRecords 接口 + DB 层分页 + 事务 + 存在性检查 + scope 过滤 + 并列排名v3-P2 新增saveGradeDraft/getGradeDraft/deleteGradeDraft + GradeDraftData 接口v3-P3-2 新增bulkDeleteGradeRecords 使用 inArray 批量删除2026-06-24 新增batchCreateGradeRecordsByExam 单事务写入 grade_records + grade_record_answers + 投影到 exam_submissions/submission_answers |
| `data-access-analytics.ts` | 200+ | 趋势/对比分析P3 修复getClassComparison 应用 buildScopeClassFilterv3-P2 新增getExamOptionsForGrades/getSchoolWideGradeSummarygetGradeTrend/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-10createDefaultBuckets 改为内部函数P3-24buildGradeTrendPoints 使用 isGradeTrendType 类型守卫替代 as 断言) |
| `export.ts` | 290+ | Excel 导出v2-P1-5 修复:传递 currentUserId 到 data-accessP3 修复:适配 PaginatedGradeRecords 结构 + 传递 scopeP3-6复用 stats-service.computeAverageScore 替代局部 avgP3-7硬编码中文改用 next-intl getTranslationsv4-P1-12 新增exportStudentGradeRecordsToExcel 家长视角单学生导出) |
| `schema.ts` | 113+ | Zod 校验(含 12 个查询 schemaP3 修复score .max(1000) + records .max(500) + 补全查询字段v3-P2 新增grade_drafts 表定义第 1444-1469 行) |
| `schema.ts` | 130+ | Zod 校验(含 12 个查询 schemaP3 修复score .max(1000) + records .max(500) + 补全查询字段v3-P2 新增grade_drafts 表定义第 1444-1469 行2026-06-24 新增BatchGradeEntryByExamSchema 按试卷录入校验 + BatchGradeEntryByExamQuestionSchema/ItemSchema 子 schema导出 BatchGradeEntryByExamInput 类型 |
| `lib/grade-utils.ts` | 20 | 公共工具函数toNumber/normalizeP3-26buildScopeClassFilter 迁移至 scope-filter.ts |
| `lib/scope-filter.ts` | 56 | DB 行级权限过滤buildScopeClassFilterP3-26 从 grade-utils.ts 迁移v2-P2-2 修复:改用 classes data-access 子查询P3 修复:新增 currentUserId 参数) |
| `lib/scope-check.ts` | 34 | v4-P2-6 新增:班级 scope 校验工具assertClassInScope 同步函数,从 actions.ts 迁移至此独立文件以避开 "use server" 文件要求 export 必须为 async 的限制;含 `import "server-only"` |
| `types.ts` | 168+ | 类型定义v3-P2 新增SchoolWideGradeSummaryItem/SchoolWideGradeSummary |
| `types.ts` | 200+ | 类型定义v3-P2 新增SchoolWideGradeSummaryItem/SchoolWideGradeSummary2026-06-24 新增GradeRecordAnswer/BatchGradeEntryByExamQuestion/BatchGradeEntryByExamItem |
| `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 类名 |
@@ -810,7 +812,7 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
| `components/class-comparison-chart.tsx` | 194 | 班级对比图v2-P1-4i18nv3-P3-5 新增:显著性分析区域,基于极差和样本量的经验规则判断班级间差异,含可折叠详细分析) |
| `components/grade-trend-chart.tsx` | 59 | 趋势图v2-P1-4i18n |
| `components/grade-record-form.tsx` | 177 | 录入表单v2-P2-7 修复Label htmlForv2-P1-4i18nP3 修复safeActionCall 包装提交) |
| `components/batch-grade-entry.tsx` | 500+ | 批量录入(v2-P2-7 修复:Label htmlForv2-P1-4i18nP3 修复:safeActionCall + localStorage 安全检查 + 区分未录入与录入 0v3-P2 新增:接入服务端草稿 saveGradeDraftAction/getGradeDraftAction/deleteGradeDraftActionv3-P3-1 新增:下载 CSV 录入模板按钮含学生姓名列表v4-P3-2 新增可折叠新手引导提示框localStorage 记住关闭状态 |
| `components/batch-grade-entry.tsx` | 600+ | 2026-06-24 完全重写:导出名改为 BatchGradeEntryByExam按试卷录入每题得分。Excel 式表格(行=学生,列=题目,末列=总分自动计算)。交互:试卷选择器(按 scope 过滤)→ 班级选择器(按试卷 gradeId 过滤);多行多列 Excel 粘贴Tab 分隔Enter 跳下一行同一列Tab 跳下一格;实时统计(已录入/总数/均分/最高/最低分数校验超过题目满分标红撤销机制sessionStorage 5 分钟有效。Props: exams/classes/classGradeMap/exam/students/defaultExamId?/defaultClassId?(原 v2-P2-7 Label htmlForv2-P1-4 i18nP3 safeActionCall + localStorage 安全检查v3-P2 服务端草稿v3-P3-1 下载 CSV 模板v4-P3-2 新手引导均已替换 |
| `components/grade-filters.tsx` | 76 | 过滤器v2-P1-4i18n |
| `components/student-grade-summary.tsx` | 107 | 学生成绩摘要v2-P1-4i18n |
| `components/export-button.tsx` | 79 | 导出按钮v2-P1-4i18nP3 修复safeActionCall 包装导出操作) |
@@ -1632,21 +1634,21 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
## 2.23 settings设置模块— V3 AI 配置统一入口
**职责**:系统设置(学校信息/安全策略/文件上传/通知配置)+ AI Provider 管理 + 密码修改 + 个人资料 + 主题偏好 + 通知偏好 + 个人信息页(学生/教师概览。V3 将 AI Provider 配置统一到 `/admin/ai-settings` 独立页面,移除 `/settings?tab=ai` 标签页和考试页面内嵌弹窗。
**职责**:系统设置(学校信息/安全策略/文件上传/通知配置)+ AI Provider 管理 + 密码修改 + 个人资料 + 主题偏好 + 通知偏好 + 个人信息页(学生/教师概览。V3 将 AI Provider 配置统一到 `/admin/ai-settings` 独立页面,移除 `/settings?tab=ai` 标签页和考试页面内嵌弹窗。V3.1 新增 public/private 可见性模型:管理员发布 public Provider 全员可用,普通用户可创建 private Provider 仅本人可见。
**导出函数**
- Actions`getAiProviderSummaries` / `upsertAiProviderAction` / `testAiProviderAction` / `deleteAiProviderAction`V3 新增删除能力
- Actions`getAiProviderSummaries`V3.1 增强:按用户身份过滤 public + own private/ `upsertAiProviderAction`V3.1 增强visibility 字段,非管理员强制 private/ `testAiProviderAction` / `deleteAiProviderAction`V3 新增删除能力)/ `canConfigurePublicAiProvider`V3.1 新增:检查当前用户是否拥有 AI_CONFIGURE 权限
- Actions-password`changePasswordAction`(✅ P1 已修复:使用 `requirePermission(USER_PROFILE_UPDATE)` + Zod 校验 + DB 操作下沉到 data-access
- Actions-avatar`updateUserAvatarAction` / `removeUserAvatarAction`(✅ P2-8 新增:头像上传/删除,复用 `/api/upload` 路由)
- Actions-notifications`sendTestNotificationAction`(✅ P2-10 新增:发送测试通知,占位实现待接入真实通知服务)
- Actions-system-settings`getAdminSystemSettingsAction` / `saveAdminSystemSettingsAction`(✅ P0-3 新增:管理员系统设置 CRUD4 分类 Zod 校验)
- Actions-security`getSecurityCenterAction` / `toggleTwoFactorAction`(✅ P2-9 新增2FA 状态查询/切换 + 最近登录历史)
- Data-access`getAiProviderSummaries` / `countDefaultAiProviders` / `getAiProviderForUpdate` / `updateAiProvider` / `createAiProvider` / `deleteAiProvider`V3 新增:事务删除 + 自动转移默认)/ `getUserPasswordHash` / `getPasswordSecurityByUserId` / `updateUserPassword` / `upsertPasswordSecurityOnPasswordChange`P1 新增,从 actions 下沉)
- Data-access`getAiProviderSummaries`(管理员视图,返回全部)/ `getAiProviderSummariesForUser`V3.1 新增:用户视图,返回 public + own private/ `countDefaultAiProviders` / `getAiProviderForUpdate`V3.1 增强:可选 userId 做所有权校验)/ `updateAiProvider`V3.1 增强visibility 字段)/ `createAiProvider`V3.1 增强visibility 字段)/ `deleteAiProvider`V3 新增:事务删除 + 自动转移默认V3.1 增强:可选 userId 做所有权校验/ `getUserPasswordHash` / `getPasswordSecurityByUserId` / `updateUserPassword` / `upsertPasswordSecurityOnPasswordChange`P1 新增,从 actions 下沉)
- Data-access-system-settings`getSystemSettingsByCategory` / `getAllSystemSettings` / `getSystemSetting` / `upsertSystemSetting` / `upsertSystemSettings`(✅ P0-3 新增system_settings 表 CRUD键值对存储模式
- Components`SettingsView`统一设置页布局V3 移除 AI 标签页后为 4 标签页 General/Notifications/Appearance/Security角色差异通过 `resolveRoleSettingsConfig` 配置驱动 + `generalExtra` props 注入Tab URL 持久化;每个 TabsContent 包裹 `SettingsSectionErrorBoundary` + `Suspense` 骨架屏)、`SettingsServiceProvider` / `useSettingsService`Context 注入 `SettingsService` 接口,解耦组件对 users/messaging actions 的直接依赖)、`SettingsSectionErrorBoundary`(分区 Error Boundary局部失败不影响整页`QuickLinksCard`快捷链接卡片i18n 键驱动)、`ProfileStudentOverview` / `ProfileStudentOverviewSkeleton`(学生概览异步 Server Component + 骨架屏)、`ProfileTeacherOverview` / `ProfileTeacherOverviewSkeleton`(教师概览异步 Server Component + 骨架屏)、`AdminSettingsView`(✅ P0-3 已修复:从 mock 改为真实数据层,通过 Server Actions 加载/保存到 system_settings 表)、`AvatarUpload`(✅ P2-8 新增:头像上传/预览/删除客户端组件,文件验证 + i18n`SecurityCenterCard`(✅ P2-9 新增2FA 开关 + 最近登录历史卡片)、`ThemePreferencesCard`(✅ P2-11 已增强:集成 `LocaleSwitcher` 语言切换)、`AiProviderSettingsCard`V3 增强:新增删除按钮 + AlertDialog 确认,统一在 `/admin/ai-settings` 页面渲染
- Components`SettingsView`统一设置页布局V3 移除 AI 标签页后为 4 标签页 General/Notifications/Appearance/Security角色差异通过 `resolveRoleSettingsConfig` 配置驱动 + `generalExtra` props 注入Tab URL 持久化;每个 TabsContent 包裹 `SettingsSectionErrorBoundary` + `Suspense` 骨架屏)、`SettingsServiceProvider` / `useSettingsService`Context 注入 `SettingsService` 接口,解耦组件对 users/messaging actions 的直接依赖)、`SettingsSectionErrorBoundary`(分区 Error Boundary局部失败不影响整页`QuickLinksCard`快捷链接卡片i18n 键驱动)、`ProfileStudentOverview` / `ProfileStudentOverviewSkeleton`(学生概览异步 Server Component + 骨架屏)、`ProfileTeacherOverview` / `ProfileTeacherOverviewSkeleton`(教师概览异步 Server Component + 骨架屏)、`AdminSettingsView`(✅ P0-3 已修复:从 mock 改为真实数据层,通过 Server Actions 加载/保存到 system_settings 表)、`AvatarUpload`(✅ P2-8 新增:头像上传/预览/删除客户端组件,文件验证 + i18n`SecurityCenterCard`(✅ P2-9 新增2FA 开关 + 最近登录历史卡片)、`ThemePreferencesCard`(✅ P2-11 已增强:集成 `LocaleSwitcher` 语言切换)、`AiProviderSettingsCard`V3 增强:新增删除按钮 + AlertDialog 确认V3.1 增强visibility 选择器 + 可见性/归属 BadgeisAdmin prop 控制公开选项currentUserId prop 标识"我的"
- Config`ROLE_SETTINGS_CONFIG` / `resolveRoleSettingsConfig`(配置驱动角色 → 设置视图映射,新增角色只需添加条目)
- Lib`buildStudentOverviewData` / `computeStudentStats` / `sortUpcomingAssignments` / `filterTodaySchedule` / `toWeekday`(纯数据计算函数,与 UI 分离,便于单元测试)
- Types`AiProviderSummary` / `AiProviderName` / `AiProviderExisting` / `SettingsService` / `ProfileService` / `NotificationPreferenceService`(服务接口定义,用于依赖注入解耦)
- Types`AiProviderSummary`V3.1 增强:新增 visibility/createdBy 字段)/ `AiProviderName` / `AiProviderVisibility`V3.1 新增:'public' | 'private'/ `AiProviderExisting`V3.1 增强:新增 visibility/createdBy 字段)/ `SettingsService` / `ProfileService` / `NotificationPreferenceService`(服务接口定义,用于依赖注入解耦)
**依赖关系**
- 依赖:`shared/*`(含 `shared/lib/bcrypt-utils`)、`@/auth``messaging`(页面层通过 `SettingsService` 接口注入,组件层不直接 import`users`(页面层通过 `SettingsService` 接口注入)、`classes` / `homework` / `dashboard`ProfileStudentOverview 异步组件获取学生概览数据)、`notifications`(页面层获取通知偏好)
@@ -1821,7 +1823,7 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
- `FlowEdge`:流程连线(教学节点 → 教学节点)
**导出函数**
- Data-access`data-access.ts``getLessonPlans` / `getLessonPlanById` / `createLessonPlan` / `updateLessonPlanContent` / `softDeleteLessonPlan` / `duplicateLessonPlan` / `getTemplateById` / `buildInitialContent` / `migrateV1ToV2` / `normalizeDocument`v3 规范化,兼容 v1/v2 旧数据)/ `buildDefaultSkeleton`v3 默认 10 节点骨架)/ `getTextbooksForPicker` / `getChaptersForPicker` / `findChapterById` / `publishLessonPlan`V3 新增,设置 status=published/ `unpublishLessonPlan`V3 新增,设置 status=draft仅 published 课案)
- Data-access`data-access.ts``getLessonPlans`V4查询后按 textbookId+chapterId+creatorId 聚合版本,返回代表项 + versionCount + versions 摘要数组)/ `getLessonPlanById` / `createLessonPlan` / `updateLessonPlanContent` / `softDeleteLessonPlan` / `duplicateLessonPlan` / `getTemplateById` / `buildInitialContent` / `migrateV1ToV2` / `normalizeDocument`v3 规范化,兼容 v1/v2 旧数据)/ `buildDefaultSkeleton`v3 默认 10 节点骨架)/ `getTextbooksForPicker` / `getChaptersForPicker` / `findChapterById` / `publishLessonPlan`V3 新增,设置 status=published/ `unpublishLessonPlan`V3 新增,设置 status=draft仅 published 课案)
- Lib`lib/document-migration.ts``defaultDataForType` / `migrateV1ToV2` / `migrateV2ToV3` / `normalizeDocument` / `buildInitialContent` / `buildDefaultSkeleton` / `isTextbookContentNode` / `isAnchorEdge` / `getAnchorsForNode` / `getActiveAnchorIds` / `getAnchorEdges`
- Lib`lib/anchor-injector.ts``markdownToPlainText` / `injectPlaceholders` / `parseAnchoredText` / `toCircledNumber` / `getNextPointIndex` / `relocateAnchors` / `getAnchorColor`
- Lib`lib/node-summary.ts``getNodeSummary` / `getTextbookContentSummary` / `getNodeColor` / `NODE_COLORS`
@@ -1876,53 +1878,82 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
> - **V3-9 新增路由**`/student/lesson-plans`、`/student/lesson-plans/[planId]/view`、`/parent/lesson-plans`、`/parent/lesson-plans/[planId]/view`、`/admin/lesson-plans`、`/admin/lesson-plans/[planId]/view`
> - **V3-10 导航变更**admin 导航新增「课案管理」(/admin/lesson-plansstudent 导航新增「我的课案」(/student/lesson-plansparent 导航新增「孩子课案」(/parent/lesson-plans
> 架构变更2026-06-24V3 深度审计修复):
> - **P0-1 admin 直查 DB 修复**`admin/lesson-plans/page.tsx` 移除 `import { db }` 和 `import { lessonPlans }`,改用 data-access 新增的 `getLessonPlanStats()` 函数(返回 total/published/draft/archived 统计)
> - **P0-2 publish-service 硬编码中文 + as 断言修复**`publish-service.ts` 移除 `as ExerciseBlockData`/`as typeof validTypes[number]` 断言,改用 `lib/type-guards.ts` 的 `isExerciseBlockData`/`isValidQuestionType` 类型守卫;移除硬编码中文标题/描述,改为接受 `homeworkTitle`/`homeworkDescription` 参数由 actions 层 i18n 翻译后传入
> - **P0-3 duplicateLessonPlan 硬编码修复**`duplicateLessonPlan` 接受 `duplicateSuffix` 参数(默认 " - Copy"),由 actions 层传入 `t("error.duplicateSuffix")`
> - **P0-4 schema Zod 错误消息 i18n 化**`schema.ts` 所有错误消息从硬编码中文改为 i18n 键(如 `error.titleRequired`);新增 `lib/i18n-errors.ts``translateFieldErrors`/`safeParseWithI18n`)在 actions 层翻译 Zod 错误
> - **P0-5 loading/error 边界补全**:为 6 个路由新增 12 个 `loading.tsx` 和 `error.tsx` 文件teacher/lesson-plans、teacher/lesson-plans/new、teacher/lesson-plans/[planId]/edit、admin/lesson-plans、admin/lesson-plans/[planId]/view、student/lesson-plans、student/lesson-plans/[planId]/view、parent/lesson-plans、parent/lesson-plans/[planId]/view
> - **P1-2 组件完全通过 service 调用**`lesson-plan-card.tsx`/`lesson-plan-list.tsx`/`lesson-plan-editor.tsx` 移除所有直接 `import { xxxAction } from "../actions"`,改为通过 `useLessonPlanContextSafe()` 获取 service 调用;`LessonPlanDataService` 接口扩展 5 个方法getLessonPlanById/updateLessonPlan/saveLessonPlanVersion/publishLessonPlan/unpublishLessonPlan`default-data-service.ts` 实现扩展
> - **P1-3 as 断言修复**:新增 `lib/type-guards.ts` 集中类型守卫11 种 BlockData 类型守卫 + 节点/题目类型守卫);`block-registry.tsx` 所有 `as XxxBlockData` 替换为类型守卫;`node-edit-panel.tsx` 移除冗余 `as LessonPlanNode`TypeScript 判别联合自动收窄);`node-editor.tsx` MiniMap `nodeColor` 使用类型守卫替代 `as { node?: AnyLessonPlanNode }``rf-mappers.ts` 移除冗余 `as TextbookContentNode`/`as LessonPlanNode``use-lesson-plan-editor.ts` `updateNode` patch 类型改为 `Omit<Partial<Block>, "type">` 防止类型变更
> - **P1-4 MiniMap 颜色硬编码修复**`lesson-plan-readonly-view.tsx` MiniMap 移除硬编码 `#455a64`/`#1976d2`,改用 `getNodeColor(nodeData.type)` 与编辑器保持一致
> - **i18n 错误码扩展**`zh-CN/lesson-preparation.json` 和 `en/lesson-preparation.json` 新增 `publish.homeworkTitle`/`publish.homeworkDescription`/`error.invalidQuestionType`/`error.duplicateSuffix`/`error.titleRequired`/`error.titleTooLong`/`error.templateRequired`/`error.invalidDate`/`error.classRequired` 等键
> 架构变更2026-06-24V3 深度审计修复续):
> - **P0 硬编码中文修复6处**`actions.ts` 的 `getLessonPlanByIdAction`/`revertLessonPlanVersionAction` 错误消息改为 i18n 键(`t("error.notFound")`/`t("error.versionNotFound")``data-access-versions.ts` 的 `revertToVersion` 接受 `revertLabel` 参数替代硬编码 `` `回退到 v${versionNo}` ```lesson-plan-error-boundary.tsx` 重写为包装组件模式(内部类组件接受 `errorText`/`retryText` props外部函数组件通过 `useTranslations` 注入 i18n 文案);`lesson-plan-provider.tsx` 的 `useLessonPlanContext` 错误消息改为英文
> - **P1 组件完全通过 service 调用5个组件迁移**`version-history-drawer.tsx`/`template-picker.tsx`/`knowledge-point-picker.tsx`/`publish-homework-dialog.tsx`/`question-bank-picker.tsx` 移除所有直接 `import { xxxAction } from "../actions"`,改用 `useLessonPlanContextSafe()` 获取 service 调用;`LessonPlanDataService` 接口扩展 7 个方法createLessonPlan/getTextbooksForPicker/getChaptersForPicker/getLessonPlanTemplates/getKnowledgePointOptions/publishLessonPlanHomework/getQuestions+ 6 个导出类型TextbookPickerOption/ChapterPickerOption/KnowledgePointOption/PublishHomeworkInput/QuestionPickerParams/QuestionPickerItem`default-data-service.ts` 实现扩展;新增 `providers/lesson-plan-provider-setup.tsx`(页面层 Provider 设置包装组件自动注入默认数据服务和角色配置3 个页面teacher/lesson-plans/page、teacher/lesson-plans/new/page、teacher/lesson-plans/[planId]/edit/page用 `LessonPlanProviderSetup` 包裹;`question-bank-picker.tsx` 新增 `isQuestionType` 类型守卫替代 `as QuestionType` 断言
> - **P2 文件拆分**`textbook-content-node.tsx` 从 578 行拆分为 3 个文件——主文件471行+ `anchor-node-selector.tsx`AnchorNodeSelector 组件62行+ `textbook-segments.tsx`renderSegments 函数75行
> - **P3 as 断言修复8处**`textbook-content-node.tsx` 的 `as unknown as TextbookContentNodeProps` 替换为 `isTextbookContentNodePropsData` 类型守卫7 个 block 组件blackboard/import/exercise/objective/key-point/homework/reflection的 select onChange `as` 断言替换为类型守卫——`lib/type-guards.ts` 新增 7 个字段值类型守卫isBlackboardLayout/isImportMethod/isExercisePurpose/isObjectiveDimension/isKeyPointType/isHomeworkType/isReflectionAspect
**文件清单**
| 文件 | 职责 |
|------|------|
| `types.ts` | 类型定义(含 v1/v2/v3 文档类型、TextbookContentNode、LessonPlanNode、NodeAnchor、AnchorEdge、FlowEdge、11 种 BlockData 接口) |
| `constants.ts` | 常量定义 |
| `schema.ts` | Zod 验证 |
| `schema.ts` | Zod 验证V3错误消息改为 i18n 键,如 `error.titleRequired` |
| `lib/type-guards.ts` | **集中类型守卫V3 新增)**11 种 BlockData 类型守卫isRichTextBlockData/isTextStudyBlockData/isExerciseBlockData/isObjectiveBlockData/isKeyPointBlockData/isImportBlockData/isNewTeachingBlockData/isSummaryBlockData/isHomeworkBlockData/isBlackboardBlockData/isReflectionBlockData+ 节点类型守卫isTextbookContentNode/isLessonPlanNode+ 题目类型守卫isValidQuestionType+ 基础类型守卫isLessonPlanStatus/isTemplateType/isTemplateScope/isBlockType+ **Block 字段值类型守卫V3 续新增)**isBlackboardLayout/isImportMethod/isExercisePurpose/isObjectiveDimension/isKeyPointType/isHomeworkType/isReflectionAspect用于 select onChange 替代 `as` 断言) |
| `lib/i18n-errors.ts` | **Zod 错误 i18n 翻译辅助V3 新增)**`translateFieldErrors`(将 Zod fieldErrors 中的 i18n 键翻译为实际消息)/ `safeParseWithI18n`(安全解析 Zod 结果并返回带翻译的 ActionState 错误格式) |
| `lib/document-migration.ts` | **纯函数**v1→v2migrateV1ToV2/ v2→v3migrateV2ToV3/ 规范化normalizeDocument兼容 v1/v2/v3/ 初始内容buildInitialContent/ 默认骨架buildDefaultSkeleton10 节点 + 正文节点)/ defaultDataForType / 工具函数isTextbookContentNode/isAnchorEdge/getAnchorsForNode/getActiveAnchorIds/getAnchorEdges |
| `lib/anchor-injector.ts` | **纯函数**锚点注入算法markdownToPlainText/injectPlaceholders/parseAnchoredText/toCircledNumber/getNextPointIndex/relocateAnchors/getAnchorColor |
| `lib/node-summary.ts` | **纯函数**getNodeSummary支持 11 种节点类型)+ getTextbookContentSummary + NODE_COLORS + getNodeColor |
| `lib/rf-mappers.ts` | **纯函数**toRfNodes支持 textbook_content 节点 + 锚点回调V3ctx 新增 anchorableNodes/onCreateNewNode 字段)/ toRfEdges区分 anchor/flow 边透明度V3锚点边颜色使用 getNodeColor(anchor.nodeId) 替代硬编码anchorId 存入 edge.data/ fromRfEdgesV3从 e.data.anchorId 读取 anchorId回退到 className 判断) |
| `config/block-registry.tsx` | **配置驱动**BLOCK_REGISTRY 注册表 + BlockRendererswitch 渲染 11 种定制节点 + textbook_content |
| `providers/lesson-plan-provider.tsx` | **Provider + ContextP1-5/P1-7/P2-4/V2-6**LessonPlanProvider 注入数据服务/角色配置/埋点;定义 LessonPlanDataService 接口、4 个角色配置TEACHER/ADMIN/STUDENT/PARENT、ROLE_CONFIGS 注册表、LessonPlanTracker 接口 + noopTrackerhooksuseLessonPlanContextSafe(返回 null 不抛错)/useLessonPlanContext/useRoleConfig/useLessonPlanService/useLessonPlanTracker/useLessonPlanTrackerSafeV2-6 新增,返回 noopTracker 不抛错) |
| `services/default-data-service.ts` | **默认数据服务实现**createDefaultDataService() 包装 Server Actions 为 LessonPlanDataService 实现,测试可替换为 mock |
| `data-access.ts` | 课案 CRUD + 模板查询migrateV1ToV2/normalizeDocument/buildInitialContent 从 lib/ 导入并 re-export 保持向后兼容buildScopeCondition 按 scope 类型精确过滤 P0-3V2-1抛出 `LessonPlanDataError` 错误码V2-3mapRowToLessonPlan/mapRowToListItem/mapRowToTemplate 显式映射 + isLessonPlanStatus/isTemplateType/isTemplateScope 类型守卫V3新增 publishLessonPlan/unpublishLessonPlan 函数) |
| `data-access-versions.ts` | 版本管理(创建/查询/回滚/清理V2-3mapRowToVersion 显式映射 |
| `data-access-templates.ts` | 个人模板 CRUDV2-3mapRowToTemplate 显式映射 + 类型守卫 |
| `data-access-knowledge.ts` | 按知识点/题目反查课案V2-3显式字段映射替代 `as unknown as` |
| `actions.ts` | 课案 CRUD/版本/模板 Server ActionsV2-1getTranslations i18n + 错误码捕获V2-2createLessonPlanAction 传入 translateTitle 翻译 SYSTEM_TEMPLATES |
| `actions-publish.ts` | 发布作业 Server ActionV2-1getTranslations i18n + PUBLISH_ERROR_KEY_MAP 错误码映射V3新增 publishLessonPlanAction/unpublishLessonPlanActionrequirePermission(LESSON_PLAN_PUBLISH) |
| `actions-ai.ts` | AI 知识点建议 Server ActionV2-1i18n + 错误码) |
| `actions-kp.ts` | 知识点选项 Server ActionV2-1i18n + 错误码) |
| `publish-service.ts` | 发布作业服务(编排 homework/exams/classes通过对方 data-access 调用无直查跨模块表V2-1抛出 `PublishServiceError` 错误码V2-3显式字段映射替代 `as unknown as` |
| `lib/rf-mappers.ts` | **纯函数**toRfNodesV3移除冗余 `as` 断言TypeScript 判别联合自动收窄)/ toRfEdges / fromRfEdges |
| `config/block-registry.tsx` | **配置驱动**BLOCK_REGISTRY 注册表 + BlockRendererV3使用 `lib/type-guards.ts` 类型守卫替代所有 `as XxxBlockData` 断言 |
| `providers/lesson-plan-provider.tsx` | **Provider + Context**LessonPlanProvider 注入数据服务/角色配置/埋点;定义 LessonPlanDataService 接口V3扩展 5 个方法 getLessonPlanById/updateLessonPlan/saveLessonPlanVersion/publishLessonPlan/unpublishLessonPlan**V3 续扩展 7 个方法 createLessonPlan/getTextbooksForPicker/getChaptersForPicker/getLessonPlanTemplates/getKnowledgePointOptions/publishLessonPlanHomework/getQuestions + 6 个导出类型**、4 个角色配置、ROLE_CONFIGS 注册表、LessonPlanTracker 接口 + noopTrackerhooksuseLessonPlanContextSafe/useLessonPlanContext/useRoleConfig/useLessonPlanService/useLessonPlanTracker/useLessonPlanTrackerSafe |
| `providers/lesson-plan-provider-setup.tsx` | **页面层 Provider 设置包装组件V3 续新增)**LessonPlanProviderSetup 自动注入默认数据服务createDefaultDataService和角色配置TEACHER_ROLE_CONFIG3 个 teacher 页面用此组件包裹 |
| `services/default-data-service.ts` | **默认数据服务实现**createDefaultDataService() 包装 Server Actions 为 LessonPlanDataService 实现V3实现扩展的 5 个方法;**V3 续扩展 7 个方法 createLessonPlan/getTextbooksForPicker/getChaptersForPicker/getLessonPlanTemplates/getKnowledgePointOptions/publishLessonPlanHomework/getQuestions**),测试可替换为 mock |
| `data-access.ts` | 课案 CRUD + 模板查询V3新增 `getLessonPlanStats()` 统计函数 + `LessonPlanStats` 接口;`duplicateLessonPlan` 接受 `duplicateSuffix` 参数消除硬编码 |
| `data-access-versions.ts` | 版本管理(创建/查询/回滚/清理 |
| `data-access-templates.ts` | 个人模板 CRUD |
| `data-access-knowledge.ts` | 按知识点/题目反查课案 |
| `actions.ts` | 课案 CRUD/版本/模板 Server ActionsV3所有 action 使用 `translateFieldErrors` 翻译 Zod 错误;`duplicateLessonPlanAction` 传入 i18n 翻译的副本后缀;`getLessonPlanByIdAction` 返回类型改为 `ActionState<{ plan: LessonPlan }>` |
| `actions-publish.ts` | 发布作业 Server ActionV3actions 层注入 i18n 翻译的作业标题/描述/日期标签;新增 `INVALID_QUESTION_TYPE` 错误码映射 |
| `actions-ai.ts` | AI 知识点建议 Server Action |
| `actions-kp.ts` | 知识点选项 Server Action |
| `publish-service.ts` | 发布作业服务V3移除 `as` 断言改用类型守卫;移除硬编码中文,接受 `homeworkTitle`/`homeworkDescription` 参数;新增 `INVALID_QUESTION_TYPE` 错误码) |
| `ai-suggest.ts` | AI 知识点建议服务 |
| `seed-templates.ts` | 模板种子数据 |
| `hooks/use-lesson-plan-editor.ts` | 课案编辑器 Hook基于 zustand支持 nodes/edges/anchors 操作addNode/updateNode/updateNodePosition/removeNode/connect/disconnect/setEdges/selectNode + 锚点操作 addAnchor/removeAnchor/updateAnchor + 正文节点操作 updateTextbookContent/getTextbookContentNode实时拖动 |
| `components/lesson-plan-list.tsx` | 课案列表(i18n 已接入V3新增 viewMode prop支持 teacher/student/parent/admin/gradeHead 多角色视图 |
| `components/lesson-plan-card.tsx` | 课案卡片(i18n 已接入V2-6duplicate/archive 调用 tracker.trackV3新增 viewMode propteacher/student/parent/admin/gradeHead动态跳转链接 + 发布/撤回按钮 |
| `components/lesson-plan-filters.tsx` | 课案筛选器i18n 已接入V2-53 个表单元素 label htmlFor 关联) |
| `components/lesson-plan-editor.tsx` | 课案编辑器(编排 NodeEditor + NodeEditPaneli18n 已接入V2-6handleManualSave 调用 tracker.trackV3顶部工具栏显示教材/章节标题指示器V3新增 initialStatus prop + 发布/撤回按钮AlertDialog 确认) |
| `components/lesson-plan-readonly-view.tsx` | **只读画布组件**V3 新增):复用 React FlownodesDraggable=false, nodesConnectable=false供学生/家长/管理员/教研组长查看已发布课案 |
| `components/node-editor.tsx` | **节点图画布**React Flow使用 lib/rf-mappers + lib/node-summary 纯函数i18n 已接入V2-4MiniMap 复用 getNodeColorV2-5role=application + 键盘导航配置V3注册 textbook_content 节点类型 + 锚点回调 + 实时拖动 |
| `components/node-edit-panel.tsx` | **侧边内容编辑面板**配置驱动渲染 Block通过 BlockRenderer + LessonPlanErrorBoundary 包裹i18n 已接入V3处理 textbook_content 节点教学节点类型收窄V3选中 textbook_content 时显示操作提示 + 锚点列表(含删除功能) |
| `components/nodes/lesson-node.tsx` | **自定义教学节点组件**(使用 lib/node-summary 的 getNodeSummary/getNodeColori18n 已接入) |
| `components/nodes/textbook-content-node.tsx` | **正文节点组件**V3 新增ReactMarkdown 渲染正文 + 锚点注入 + 文本选择range 锚定)+ 点击位置point 锚定)+ 缩放控制 + 锚点浮动菜单V3新增 props `anchorableNodes`, `onCreateNewNode`AnchorNodeSelector 重写为节点列表+创建新节点选项 |
| `components/lesson-plan-error-boundary.tsx` | **错误边界**LessonPlanErrorBoundary 类组件,支持 fallback 和 onError 回调 |
| `hooks/use-lesson-plan-editor.ts` | 课案编辑器 HookV3`updateNode` patch 类型改为 `Omit<Partial<Block>, "type">` 防止类型变更 |
| `components/lesson-plan-list.tsx` | 课案列表(V3完全通过 service 调用,移除直接 import `getLessonPlansAction` |
| `components/lesson-plan-card.tsx` | 课案卡片(V3完全通过 service 调用,移除直接 import actions |
| `components/lesson-plan-filters.tsx` | 课案筛选器 |
| `components/lesson-plan-editor.tsx` | 课案编辑器(V3完全通过 service 调用,移除直接 import 5 个 actions所有操作改为 `service.updateLessonPlan`/`service.saveLessonPlanVersion`/`service.getLessonPlanById`/`service.publishLessonPlan`/`service.unpublishLessonPlan` |
| `components/lesson-plan-readonly-view.tsx` | **只读画布组件**V3MiniMap 使用 `getNodeColor` 替代硬编码颜色) |
| `components/node-editor.tsx` | **节点图画布**V3MiniMap `nodeColor` 使用类型守卫替代 `as { node?: AnyLessonPlanNode }` 断言 |
| `components/node-edit-panel.tsx` | **侧边内容编辑面板**V3移除冗余 `as LessonPlanNode` 断言TypeScript 判别联合自动收窄 |
| `components/nodes/lesson-node.tsx` | **自定义教学节点组件** |
| `components/nodes/textbook-content-node.tsx` | **正文节点组件**V3 续:拆分为 3 文件,主文件 471 行;`as unknown as` 替换为 `isTextbookContentNodePropsData` 类型守卫) |
| `components/nodes/anchor-node-selector.tsx` | **锚点节点选择器V3 续新增,从 textbook-content-node.tsx 抽取)**:渲染可锚定教学节点列表 + 关联到选中节点 + 创建新节点选项 |
| `components/nodes/textbook-segments.tsx` | **锚点段落渲染函数V3 续新增,从 textbook-content-node.tsx 抽取)**renderSegments 遍历 segments 数组渲染文本/区间锚点/点锚点 |
| `components/lesson-plan-error-boundary.tsx` | **错误边界**V3 续:重写为包装组件模式——内部类组件接受 `errorText`/`retryText` props外部函数组件通过 `useTranslations` 注入 i18n 文案) |
| `components/lesson-plan-skeleton.tsx` | **骨架屏**VersionListSkeleton/QuestionBankSkeleton/KnowledgePointSkeleton/LessonPlanListSkeleton |
| `components/block-renderer.tsx` | ⚠️ @deprecated Block 渲染器(已被 NodeEditor 替代,保留向后兼容) |
| `components/template-picker.tsx` | 模板选择器(i18n 已接入V2-6create 调用 tracker.trackV3加载并显示个人模板调用 getLessonPlanTemplatesAction分区显示系统/个人模板 |
| `components/version-history-drawer.tsx` | 版本历史抽屉(i18n 已接入V2-6revert 调用 tracker.track |
| `components/knowledge-point-picker.tsx` | 知识点选择器(i18n 已接入 |
| `components/question-bank-picker.tsx` | 题库选择器(i18n 已接入 |
| `components/inline-question-editor.tsx` | 内联题目编辑器i18n 已接入V2-5type/difficulty select label htmlFor 关联) |
| `components/publish-homework-dialog.tsx` | 发布作业对话框(i18n 已接入V2-6publish 调用 tracker.track |
| `components/blocks/rich-text-block.tsx` | 富文本 Block(被 NodeEditPanel 复用i18n 已接入) |
| `components/blocks/text-study-block.tsx` | 课文研读 Block(被 NodeEditPanel 复用i18n 已接入) |
| `components/blocks/exercise-block.tsx` | 练习 Block被 NodeEditPanel 复用,使用 router.refresh 替代 window.location.reloadi18n 已接入V2-5purpose select label 关联 + 题目列表 ul/li 语义化 |
| `components/blocks/reflection-block.tsx` | 反思 Block被 NodeEditPanel 复用i18n 已接入 |
| `components/template-picker.tsx` | 模板选择器(V3 续:完全通过 service 调用,移除直接 import 4 个 actions |
| `components/version-history-drawer.tsx` | 版本历史抽屉(V3 续:完全通过 service 调用,移除直接 import 2 个 actions |
| `components/knowledge-point-picker.tsx` | 知识点选择器(V3 续:完全通过 service 调用,移除直接 import actions-kp |
| `components/question-bank-picker.tsx` | 题库选择器(V3 续:完全通过 service 调用,移除跨模块直接 import `@/modules/questions/actions`;新增 `isQuestionType` 类型守卫替代 `as QuestionType` |
| `components/inline-question-editor.tsx` | 内联题目编辑器 |
| `components/publish-homework-dialog.tsx` | 发布作业对话框(V3 续:完全通过 service 调用,移除直接 import actions-publish |
| `components/blocks/rich-text-block.tsx` | 富文本 Block |
| `components/blocks/text-study-block.tsx` | 课文研读 Block |
| `components/blocks/objective-block.tsx` | 教学目标 BlockV3 续select onChange 使用 `isObjectiveDimension` 类型守卫替代 `as` 断言 |
| `components/blocks/key-point-block.tsx` | 重难点 BlockV3 续select onChange 使用 `isKeyPointType` 类型守卫替代 `as` 断言 |
| `components/blocks/import-block.tsx` | 导入 BlockV3 续select onChange 使用 `isImportMethod` 类型守卫替代 `as` 断言) |
| `components/blocks/new-teaching-block.tsx` | 新授 Block |
| `components/blocks/summary-block.tsx` | 总结 Block |
| `components/blocks/homework-block.tsx` | 作业 BlockV3 续select onChange 使用 `isHomeworkType` 类型守卫替代 `as` 断言) |
| `components/blocks/blackboard-block.tsx` | 板书 BlockV3 续select onChange 使用 `isBlackboardLayout` 类型守卫替代 `as` 断言) |
| `components/blocks/exercise-block.tsx` | 练习 BlockV3 续select onChange 使用 `isExercisePurpose` 类型守卫替代 `as` 断言) |
| `components/blocks/reflection-block.tsx` | 反思 BlockV3 续select onChange 使用 `isReflectionAspect` 类型守卫替代 `as` 断言) |
---
@@ -1977,28 +2008,36 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
| 文件 | 行数 | 职责 |
|------|------|------|
| `actions.ts` | ~180 | 9 个 Server Actions全部使用 `requirePermission()` + `ActionState<T>` |
| `data-access.ts` | ~960 | 16 个数据访问函数 + 自动采集逻辑SM-2 算法已提取到独立模块) |
| `data-access.ts` | ~1280 | 19 个数据访问函数 + 自动采集逻辑SM-2 算法已提取到独立模块,支持 subjectId 过滤、章节维度、班级分组、学科概览 |
| `sm2-algorithm.ts` | ~180 | SM-2 间隔重复算法(独立纯函数模块,可替换,支持时间注入测试) |
| `sm2-algorithm.test.ts` | ~280 | SM-2 算法单元测试39 个测试用例,覆盖所有函数和边界条件) |
| `schema.ts` | ~60 | 4 个 Zod 验证 schema |
| `types.ts` | ~120 | 6 个类型定义 + 状态映射常量 + 错误标签常量 |
| `types.ts` | ~245 | 11 个类型定义 + 状态映射常量 + 错误标签常量(新增 ChapterWeakness/ClassErrorOverview/SubjectErrorOverview |
| `components/error-book-stats-cards.tsx` | ~80 | 5 个统计卡片(总数/待学习/学习中/已掌握/待复习) |
| `components/analytics-stats-cards.tsx` | ~110 | 教师/管理员分析视图 5 个统计卡片(覆盖学生/错题总数/平均掌握率/待复习/知识点数) |
| `components/error-book-filters.tsx` | ~100 | 筛选栏(搜索/状态/来源/待复习),使用 nuqs |
| `components/error-book-item-card.tsx` | ~150 | 错题卡片(预览/标签/笔记/掌握度/操作) |
| `components/review-buttons.tsx` | ~80 | 4 按钮复习面板again/hard/good/easy |
| `components/error-book-detail-dialog.tsx` | ~250 | 详情对话框(题目/答案/复习/笔记/历史) |
| `components/error-book-list.tsx` | ~60 | 网格列表 |
| `components/add-error-book-dialog.tsx` | ~180 | 手动添加对话框(题库选择 + 标签) |
| `components/class-error-overview.tsx` | ~200 | 班级错题概览(教师/管理员视图 |
| `components/subject-tabs.tsx` | ~95 | 学科切换 Tab显示每个学科错题概览URL 参数持久化 |
| `components/class-filter.tsx` | ~85 | 班级筛选器显示每个班级错题数和待复习数URL 参数持久化) |
| `components/class-error-bar-chart.tsx` | ~115 | 班级错题数对比柱状图rechartstooltip 显示学生数/人均/掌握率) |
| `components/subject-distribution-chart.tsx` | ~110 | 学科错题分布柱状图管理员视图recharts |
| `components/knowledge-point-weakness-chart.tsx` | ~150 | 知识点薄弱度横向柱状图(按掌握率红/黄/绿着色,显示章节归属) |
| `components/chapter-weakness-chart.tsx` | ~165 | 章节错题分布横向柱状图(哪些课在错,含 Top 3 薄弱知识点) |
| `components/grouped-student-error-table.tsx` | ~180 | 按班级分组的学生错题表格(可展开/折叠,显示每个学生的错题详情) |
| `components/class-error-overview.tsx` | ~200 | 班级错题概览(旧版,保留兼容) |
| `components/top-wrong-questions.tsx` | ~80 | 高频错题列表Top 10 |
**路由清单**
| 路由 | 文件 | 说明 |
|------|------|------|
| `/student/error-book` | `page.tsx` + `loading.tsx` + `error.tsx` | 学生错题本(统计/筛选/列表/手动添加/详情复习) |
| `/teacher/error-book` | `page.tsx` + `loading.tsx` + `error.tsx` | 教师错题分析(班级概览/薄弱知识点/学科分布/高频错题) |
| `/teacher/error-book` | `page.tsx` + `loading.tsx` + `error.tsx` | 教师错题分析(学科Tab/班级筛选/统计卡片/班级对比图/章节错题图/知识点薄弱度图/按班级分组学生表/高频错题) |
| `/parent/error-book` | `page.tsx` + `loading.tsx` + `error.tsx` | 家长错题本(子女错题统计/薄弱知识点/高频错题) |
| `/admin/error-book` | `page.tsx` + `loading.tsx` + `error.tsx` | 管理员错题分析(全校错题统计/薄弱知识点/学科分布/高频错题) |
| `/admin/error-book` | `page.tsx` + `loading.tsx` + `error.tsx` | 管理员错题分析(学科Tab/统计卡片/学科分布图/章节错题图/知识点薄弱度图/按班级分组学生Top50/高频错题) |
**数据库表**
| 表 | 说明 |
@@ -2150,6 +2189,138 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
---
## 2.30 adaptive-practice专项练习模块— ✅ 新增(核心教学链路闭环)
**职责**:实现"错题集 → 知识点 → 专项出题 → 学生答题 → 自动判分 → 教师/年级主任宏观数据分析"的完整闭环。支持四种出题策略错题变式、知识点专项、薄弱章节、AI 推荐。提供教师端与年级主任端的宏观数据分析工作台。
**架构定位**
- 位于 `modules/` 层,严格遵循三层架构
- 通过 `data-access.ts` 提供 CRUD 操作,通过 `data-access-strategy.ts` 实现出题策略,通过 `data-access-analytics.ts` 提供教师/年级分析查询
- 跨模块通信:通过 `modules/error-book/data-access` 获取错题数据,通过 `modules/questions/data-access` 获取题目数据,通过 `modules/classes/data-access` 获取班级/学生数据,通过 `modules/users/data-access` 获取用户数据
- Server Actions 通过 `requirePermission()` 校验 `ADAPTIVE_PRACTICE_READ` / `ADAPTIVE_PRACTICE_MANAGE` 权限
**核心导出**
| 类型 | 名称 | 文件 | 说明 |
|------|------|------|------|
| **DB Schema** | `practiceSessions` | `shared/db/schema.ts` | 练习会话表(学生 ID/类型/状态/统计) |
| **DB Schema** | `practiceAnswers` | `shared/db/schema.ts` | 练习答题记录表(含变式题支持) |
| **Server Actions** | `getPracticeSessionsAction` | `modules/adaptive-practice/actions.ts` | 获取练习列表权限ADAPTIVE_PRACTICE_READ |
| **Server Actions** | `getPracticeSessionDetailAction` | `modules/adaptive-practice/actions.ts` | 获取练习详情权限ADAPTIVE_PRACTICE_READ |
| **Server Actions** | `getPracticeStatsAction` | `modules/adaptive-practice/actions.ts` | 获取练习统计权限ADAPTIVE_PRACTICE_READ |
| **Server Actions** | `createPracticeSessionAction` | `modules/adaptive-practice/actions.ts` | 创建练习会话权限ADAPTIVE_PRACTICE_MANAGE |
| **Server Actions** | `submitPracticeAnswerAction` | `modules/adaptive-practice/actions.ts` | 提交答案+自动判分权限ADAPTIVE_PRACTICE_MANAGE |
| **Server Actions** | `completePracticeSessionAction` | `modules/adaptive-practice/actions.ts` | 完成练习权限ADAPTIVE_PRACTICE_MANAGE |
| **Server Actions** | `abandonPracticeSessionAction` | `modules/adaptive-practice/actions.ts` | 放弃练习权限ADAPTIVE_PRACTICE_MANAGE |
| **Data Access** | `getPracticeSessions` / `getPracticeSessionById` | `data-access.ts` | 学生端 CRUD |
| **Data Access** | `createPracticeSession` | `data-access.ts` | 创建会话(事务:会话+答题记录) |
| **Data Access** | `submitPracticeAnswer` | `data-access.ts` | 提交答案+自动判分 |
| **Data Access** | `autoGradeAnswer` | `data-access.ts` | 自动判分逻辑(选择题/判断题自动,填空题返回 null |
| **Strategy** | `selectQuestionsForPractice` | `data-access-strategy.ts` | 出题策略主入口 |
| **Strategy** | `selectForErrorVariant` | `data-access-strategy.ts` | 错题变式策略 |
| **Strategy** | `selectForKnowledgePoint` | `data-access-strategy.ts` | 知识点专项策略 |
| **Strategy** | `selectForWeakChapter` | `data-access-strategy.ts` | 薄弱章节策略 |
| **Strategy** | `selectForAiRecommended` | `data-access-strategy.ts` | AI 推荐策略 |
| **Analytics** | `getClassPracticeStats` | `data-access-analytics.ts` | 班级练习统计 |
| **Analytics** | `getClassStudentPracticeSummaries` | `data-access-analytics.ts` | 班级学生练习摘要 |
| **Analytics** | `getGradePracticeStats` | `data-access-analytics.ts` | 年级练习统计 |
| **Analytics** | `getPracticeTypeBreakdown` | `data-access-analytics.ts` | 练习类型分布 |
| **Analytics** | `getStudentsWithoutPractice` | `data-access-analytics.ts` | 识别未参与练习学生 |
| **Analytics** | `getTeacherClassPracticeOverviews` | `data-access-analytics.ts` | 教师所教班级练习概览 |
| **Analytics** | `getClassKnowledgePointWeakness` | `data-access-analytics.ts` | 班级知识点薄弱度(基于练习答题) |
| **Analytics** | `getGradeClassPracticeComparison` | `data-access-analytics.ts` | 年级各班级练习对比 |
| **Analytics** | `getClassLearningProfile` | `data-access-analytics.ts` | 班级综合学习画像(跨模块整合) |
| **Analytics** | `getGradePracticeOverview` | `data-access-analytics.ts` | 年级综合练习统计 |
| **Component** | `PracticeStarter` | `components/practice-starter.tsx` | 练习发起器(四种模式选择) |
| **Component** | `PracticeSessionView` | `components/practice-session-view.tsx` | 答题界面(逐题作答+自动判分) |
| **Component** | `PracticeHistory` | `components/practice-history.tsx` | 练习历史列表 |
| **Component** | `PracticeStatsCards` | `components/practice-stats-cards.tsx` | 学生端统计卡片 |
| **Component** | `PracticeOverviewStatsCards` | `components/practice-overview-stats-cards.tsx` | 教师/年级端统计卡片 — 新增 |
| **Component** | `ClassPracticeComparisonTable` | `components/class-practice-comparison-table.tsx` | 班级练习对比表格 — 新增 |
| **Component** | `PracticeTypeBreakdownChart` | `components/practice-type-breakdown-chart.tsx` | 练习类型分布柱状图 — 新增 |
| **Component** | `ClassKnowledgePointWeaknessChart` | `components/class-knowledge-point-weakness-chart.tsx` | 知识点薄弱度柱状图 — 新增 |
| **Component** | `StudentPracticeRankingTable` | `components/student-practice-ranking-table.tsx` | 学生练习排名表格 — 新增 |
| **Component** | `InactiveStudentsAlert` | `components/inactive-students-alert.tsx` | 未参与练习学生提醒 — 新增 |
**集成点**
| 业务模块 | 集成组件 | 页面 | 说明 |
|---------|---------|------|------|
| error-book | `createPracticeSessionAction` | `student/error-book` 详情弹窗 | 错题详情页"发起变式练习"按钮 |
| student | `PracticeStarter` / `PracticeSessionView` | `student/practice` / `student/practice/[sessionId]` | 学生端练习入口与答题 |
| teacher | `PracticeOverviewStatsCards` 等 | `teacher/practice` | 教师端专项练习分析 — 新增 |
| management | `PracticeOverviewStatsCards` 等 | `management/grade/practice` | 年级主任宏观数据分析 — 新增 |
**依赖关系**
- `modules/adaptive-practice``shared/db`schema: practiceSessions/practiceAnswers/questions/knowledgePoints 等)
- `modules/adaptive-practice``shared/lib/auth-guard`(权限校验)
- `modules/adaptive-practice``shared/types/permissions`(权限常量)
- `modules/adaptive-practice``shared/types/action-state`(返回值类型)
- `modules/adaptive-practice``modules/classes/data-access`getActiveStudentIdsByClassId/getClassNameById/getClassesByGradeId/getClassIdsByGradeIds/getStudentIdsByClassIds
- `modules/adaptive-practice``modules/users/data-access`getUserIdsByGradeId/getUserNamesByIds
- `modules/adaptive-practice``modules/questions/data-access`(题目查询,出题策略使用)
- `modules/adaptive-practice``modules/error-book/data-access`(错题数据,错题变式策略使用)
- `app/(dashboard)/student/practice``modules/adaptive-practice`(学生端页面)
- `app/(dashboard)/teacher/practice``modules/adaptive-practice`(教师端分析页面)— 新增
- `app/(dashboard)/management/grade/practice``modules/adaptive-practice`(年级主任分析页面)— 新增
- `modules/error-book/components/error-book-detail-dialog``modules/adaptive-practice/actions`(变式练习入口)
**权限点**
- `ADAPTIVE_PRACTICE_READ`查看练习数据admin/teacher/student/parent/grade_head/teaching_head 均有)
- `ADAPTIVE_PRACTICE_MANAGE`:创建/提交/完成/放弃练习(仅 student 有)
**自动判分逻辑**
- `single_choice`:学生答案 ID 与正确答案 ID 完全匹配
- `multiple_choice`:学生答案 ID 集合与正确答案 ID 集合完全匹配(集合比对)
- `judgment`:学生布尔答案与正确布尔答案一致
- `text`(填空题):不自动判分,返回 `null`,待教师批阅
**出题策略**
- `error_variant`:按难度升序选取原题(确保 AI 不可用时也能练习)
- `knowledge_point`:按知识点+难度筛选,随机抽取
- `weak_chapter`:排除已答题目,避免重复
- `ai_recommended`:从 AI 推荐知识点抽题
**文件清单**
| 文件 | 行数 | 职责 |
|------|------|------|
| `modules/adaptive-practice/types.ts` | ~143 | 类型定义PracticeType/PracticeSourceMeta 联合类型等) |
| `modules/adaptive-practice/schema.ts` | ~75 | Zod 验证 schema |
| `modules/adaptive-practice/data-access.ts` | ~470 | CRUD 操作+自动判分逻辑 |
| `modules/adaptive-practice/data-access-strategy.ts` | ~310 | 四种出题策略实现 |
| `modules/adaptive-practice/data-access-analytics.ts` | ~630 | 教师/年级宏观数据分析查询 |
| `modules/adaptive-practice/actions.ts` | ~230 | 7 个 Server Actions含权限校验 |
| `modules/adaptive-practice/components/practice-starter.tsx` | ~270 | 练习发起器 |
| `modules/adaptive-practice/components/practice-session-view.tsx` | ~420 | 答题界面 |
| `modules/adaptive-practice/components/practice-history.tsx` | ~100 | 练习历史列表 |
| `modules/adaptive-practice/components/practice-stats-cards.tsx` | ~80 | 学生端统计卡片 |
| `modules/adaptive-practice/components/practice-overview-stats-cards.tsx` | ~95 | 教师/年级端统计卡片 — 新增 |
| `modules/adaptive-practice/components/class-practice-comparison-table.tsx` | ~95 | 班级练习对比表格 — 新增 |
| `modules/adaptive-practice/components/practice-type-breakdown-chart.tsx` | ~120 | 练习类型分布柱状图 — 新增 |
| `modules/adaptive-practice/components/class-knowledge-point-weakness-chart.tsx` | ~150 | 知识点薄弱度柱状图 — 新增 |
| `modules/adaptive-practice/components/student-practice-ranking-table.tsx` | ~130 | 学生练习排名表格 — 新增 |
| `modules/adaptive-practice/components/inactive-students-alert.tsx` | ~75 | 未参与练习学生提醒 — 新增 |
| `app/(dashboard)/student/practice/page.tsx` | - | 学生端练习列表页 |
| `app/(dashboard)/student/practice/[sessionId]/page.tsx` | - | 学生端答题页 |
| `app/(dashboard)/teacher/practice/page.tsx` | ~250 | 教师端专项练习分析页 — 新增 |
| `app/(dashboard)/teacher/practice/loading.tsx` | - | 教师端加载骨架 — 新增 |
| `app/(dashboard)/teacher/practice/error.tsx` | - | 教师端错误边界 — 新增 |
| `app/(dashboard)/management/grade/practice/page.tsx` | ~140 | 年级主任宏观数据分析页 — 新增 |
| `app/(dashboard)/management/grade/practice/loading.tsx` | - | 年级端加载骨架 — 新增 |
| `app/(dashboard)/management/grade/practice/error.tsx` | - | 年级端错误边界 — 新增 |
**i18n**
- 翻译文件:`shared/i18n/messages/{locale}/practice.json`
- 命名空间:`practice`
- 键:`starter.*``session.*``result.*``history.*``stats.*``types.*``status.*``teacher.*`(含 overview/classComparison/typeBreakdown/knowledgePointWeakness/studentRanking/inactiveStudents`grade.*`(含 overview/classComparison
**数据库表**
- `practice_sessions`练习会话表id/studentId/subjectId/practiceType/sourceMeta/status/totalQuestions/answeredQuestions/correctCount/startedAt/completedAt
- `practice_answers`练习答题记录表id/sessionId/studentId/questionId/variantContent/isVariant/orderIndex/status/studentAnswer/isCorrect/score/maxScore
---
# 第三部分:已知架构问题和技术债
## 3.1 P0 严重问题(必须立即修复)

File diff suppressed because one or more lines are too long