# 错题本模块审计报告 > 审计日期:2026-06-24 > 审计范围:`src/modules/error-book/` 及 `src/app/(dashboard)/{student,teacher,parent,admin}/error-book/` > 审计依据:项目规则 `docs/standards/coding-standards.md`、架构影响地图 `004`/`005` --- ## 一、现有实现概要 ### 1.1 文件分布 错题本模块位于 `src/modules/error-book/`,包含以下文件: | 文件 | 行数 | 职责 | |------|------|------| | `actions.ts` | 341 | 9 个 Server Actions(列表/详情/统计/增删改/复习/采集) | | `data-access.ts` | **1029** | 数据访问层(学生 CRUD + 教师/管理员分析查询 + 跨模块接口) | | `data-access-collection.ts` | 170 | 自动采集逻辑(考试/作业错题采集) | | `schema.ts` | 51 | 4 个 Zod 验证 schema | | `types.ts` | 245 | 11 个类型定义 + 状态映射常量 | | `sm2-algorithm.ts` | 177 | SM-2 间隔重复算法(纯函数) | | `sm2-algorithm.test.ts` | - | 39 个单元测试 | | `components/` | 17 个文件 | UI 组件(学生卡片/列表/筛选/详情/图表等) | ### 1.2 路由分布 | 路由 | 角色 | 文件完整性 | |------|------|-----------| | `/student/error-book` | 学生 | page + loading + error ✅ | | `/teacher/error-book` | 教师 | page + loading + error ✅ | | `/parent/error-book` | 家长 | page + loading + error ✅ | | `/admin/error-book` | 管理员 | page + loading + error ✅ | ### 1.3 架构图覆盖情况 架构影响地图 `004_architecture_impact_map.md` 第 2.28 节已覆盖该模块,记录了: - 模块职责、导出函数、权限点、DataScope 行级权限 - SM-2 算法说明、自动采集机制 - 文件清单、路由清单、数据库表 **但存在以下不一致**: 1. `005_architecture_data.json` 的 `uses.shared` 仍列出 `examSubmissions`、`submissionAnswers`、`homeworkSubmissions` 等表,实际上这些已通过跨模块 data-access 接口访问(`data-access-collection.ts`),不再直接查询 2. JSON 未记录 `adaptive-practice` 依赖,但 `error-book-detail-dialog.tsx` 直接 import 了 `createPracticeSessionAction` 3. JSON 未记录 `ai` 模块依赖,但 `error-book-detail-dialog.tsx` 直接 import 了 `AiErrorBookAnalysis` 组件 --- ## 二、现存问题与原因分析 ### 2.1 【P0】跨模块直接依赖(违反三层架构规则) **项目规则**:「模块间只能通过对方 data-access 通信,禁止跨模块直接查询数据库表」「该模块必须作为独立功能单元」 | 位置 | 违规内容 | 原因 | 后果 | |------|---------|------|------| | [error-book-detail-dialog.tsx](file:///e:/Desktop/CICD/src/modules/error-book/components/error-book-detail-dialog.tsx#L40) | `import { AiErrorBookAnalysis } from "@/modules/ai/components/ai-error-book-analysis"` | error-book 组件直接 import ai 模块组件 | 模块强耦合,无法独立测试/部署 | | [error-book-detail-dialog.tsx](file:///e:/Desktop/CICD/src/modules/error-book/components/error-book-detail-dialog.tsx#L41) | `import { createPracticeSessionAction } from "@/modules/adaptive-practice/actions"` | error-book 组件直接 import adaptive-practice 的 Server Action | 模块强耦合,违反依赖注入原则 | | [add-error-book-dialog.tsx](file:///e:/Desktop/CICD/src/modules/error-book/components/add-error-book-dialog.tsx#L26) | `import { getQuestionsAction } from "@/modules/questions/actions"` | error-book 组件直接 import questions 模块的 Action | 应通过 data-access 或注入接口调用 | ### 2.2 【P0】i18n 国际化严重遗漏 **项目规则**:「所有用户可见文本必须适配 i18n(使用 next-intl),提取翻译键」 虽然 `error-book.json` 翻译文件已存在(123 行),但**大量组件仍使用硬编码中文**: | 组件 | 硬编码文本示例 | 行数 | |------|--------------|------| | `error-book-item-card.tsx` | "题目内容"、"难度"、"掌握度"、"复习 X 次"、"需复习"、"下次"、"未学习"、"入门"... | 10+ 处 | | `error-book-detail-dialog.tsx` | "题目"、"我的答案"、"正确答案"、"AI 智能分析"、"复习自评"、"学习笔记"、"错误原因标签"、"复习历史"、"归档"、"删除"、"添加于"... | 20+ 处 | | `error-book-filters.tsx` | "搜索笔记内容..."、"状态"、"来源"、"复习"、"全部状态"、"全部来源"... | 8+ 处 | | `add-error-book-dialog.tsx` | "手动添加"、"添加错题"、"选择题目"、"学习笔记(可选)"、"错误原因标签"、"取消"、"添加"... | 10+ 处 | | `review-buttons.tsx` | "重来"、"困难"、"良好"、"简单" 及描述文案(i18n 已有翻译但未使用) | 8 处 | | `error-book-stats-cards.tsx` | "错题总数"、"待学习"、"学习中"、"已掌握"、"待复习" 及描述 | 10 处 | | `analytics-stats-cards.tsx` | "覆盖学生"、"错题总数"、"平均掌握率"、"待复习"、"涉及知识点" 及子文案 | 10+ 处 | | `subject-tabs.tsx` | "全部学科"、"待复习" | 2 处 | | `class-filter.tsx` | "全部班级"、"错题"、"待复习" | 3 处 | | `top-wrong-questions.tsx` | "高频错题"、"高频错题 Top 10"、"暂无高频错题"、"人错"、"人已掌握"、"掌握率" | 8 处 | | `knowledge-point-weakness-chart.tsx` | "薄弱知识点 Top X"、"错题数"、"所属章节"、"错题数"、"已掌握"、"掌握率" | 8+ 处 | | `chapter-weakness-chart.tsx` | "章节错题分布(哪些课在错)"、"错题数"、"已掌握"、"掌握率"、"知识点数"、"薄弱知识点" | 10+ 处 | | `class-error-bar-chart.tsx` | "各班级错题数对比"、"错题总数"、"学生数"、"人均错题"、"平均掌握率"、"待复习" | 6+ 处 | | `subject-distribution-chart.tsx` | "各学科错题分布"、"错题数"、"已掌握"、"掌握率" | 4+ 处 | | `grouped-student-error-table.tsx` | "未分班"、"人"、"人有错题"、"错题总数"、"平均掌握率"、"学生" 及表头 | 15+ 处 | | `class-error-overview.tsx` | "覆盖学生"、"错题总数"、"平均掌握率"、"薄弱知识点"、"学科错题分布" 等 | 15+ 处 | | `error-book-list.tsx` | "错题本为空"、"查看详情" | 2 处 | | `teacher/error-book/page.tsx` | "错题分析"、"按学科、班级查看学生的错题统计与薄弱知识点" 等 | 8+ 处 | **总计约 150+ 处硬编码中文文本**,违反 i18n 规则。 ### 2.3 【P0】类型安全问题(违反 TypeScript 严格模式) **项目规则**:「禁止 `any`、禁止 `as` 断言(除类型收窄外)」 | 文件 | 行号 | 违规代码 | 类型 | |------|------|---------|------| | `data-access.ts` | 77 | `row.sourceType as ErrorBookItem["sourceType"]` | `as` 断言 | | `data-access.ts` | 82 | `row.knowledgePointIds as string[] \| null` | `as` 断言 | | `data-access.ts` | 90 | `row.errorTags as string[] \| null` | `as` 断言 | | `data-access.ts` | 133 | `or(...)!` | 非空断言 | | `data-access.ts` | 175 | `row as unknown as Parameters[0]` | 双重断言 | | `data-access.ts` | 222 | 同上 | 双重断言 | | `data-access.ts` | 657 | `row.knowledgePointIds as string[] \| null` | `as` 断言 | | `data-access.ts` | 792 | 同上 | `as` 断言 | | `actions.ts` | 63 | `params.status as "new" \| "learning" \| ...` | `as` 断言 | | `actions.ts` | 69 | `params.sourceType as "exam" \| "homework" \| ...` | `as` 断言 | | `error-book-item-card.tsx` | 31 | `node as Record` | `as` 断言 | | `error-book-detail-dialog.tsx` | 61 | `content as Record` | `as` 断言 | | `add-error-book-dialog.tsx` | 48 | `node as Record` | `as` 断言 | | `top-wrong-questions.tsx` | 26 | `node as Record` | `as` 断言 | | `knowledge-point-weakness-chart.tsx` | 77 | `payload as unknown as {...}` | 双重断言 | | `chapter-weakness-chart.tsx` | 74 | `payload as unknown as {...}` | 双重断言 | | `class-error-bar-chart.tsx` | 76 | `payload as unknown as {...}` | 双重断言 | | `subject-distribution-chart.tsx` | 77 | `payload as unknown as {...}` | 双重断言 | ### 2.4 【P1】data-access.ts 超过 1000 行硬性上限 **项目规则**:「硬性上限:任何文件不超过 1000 行,超过必须拆分」 `data-access.ts` 当前 **1029 行**,超出硬性上限。该文件混合了: - 学生端 CRUD(`getErrorBookItems`、`createErrorBookItem`、`recordReview` 等) - 教师/管理员分析查询(`getStudentErrorBookSummaries`、`getKnowledgePointWeakness`、`getChapterWeakness`、`getClassErrorOverviews`、`getSubjectErrorOverviews` 等) - 跨模块查询接口(`getStudentIdsByClassIdList`、`getAllStudentIds`) ### 2.5 【P1】性能问题:全量查询 + JS 端聚合 | 函数 | 问题 | 影响 | |------|------|------| | `getErrorBookStats` | 查询该学生**所有**错题行到内存,再 JS 循环统计 | 学生错题多时内存/CPU 浪费 | | `getStudentErrorBookSummaries` | 查询所有学生的所有错题行,再 JS 聚合 | 班级学生多时性能差 | | `getKnowledgePointWeakness` | 查询所有错题行,JS 展开知识点数组再统计 | 同上 | | `getChapterWeakness` | 同上 | 同上 | | `getSubjectErrorDistribution` | 同上 | 同上 | | `getClassErrorOverviews` | 同上 | 同上 | | `getSubjectErrorOverviews` | 同上 | 同上 | | `getTopWrongQuestionsByStudentIds` | 同上 | 同上 | | `admin/page.tsx` | `allStudentIds.slice(0, 500)` 硬编码限制,无分页 | 超过 500 学生时数据不完整 | **应使用 SQL `GROUP BY` + `COUNT` 聚合查询**,避免全量加载到内存。 ### 2.6 【P1】a11y 可访问性缺失 **项目规则**:「可访问性(a11y):语义化标签、ARIA 属性、键盘导航」 | 位置 | 问题 | |------|------| | `grouped-student-error-table.tsx:162` | 使用 `` 而非 Next.js ``(违反项目记忆中的 Link 规范) | | `subject-tabs.tsx` | `