# 教材(Textbooks)模块审计报告 v2
> 审计日期:2026-06-22
> 审计范围:`src/modules/textbooks/**`、`src/app/(dashboard)/teacher/textbooks/**`、`src/app/(dashboard)/student/learning/textbooks/**`
> 对比基准:[textbooks-audit-report.md](./textbooks-audit-report.md)(v1)
> 参照规则:`docs/architecture/004_architecture_impact_map.md`、`docs/architecture/005_architecture_data.json`、`.trae/rules/project_rules.md`
---
## 一、v1 改进项完成状态总览
### 1.1 完成度统计
| 优先级 | 总数 | 已完成 | 部分完成 | 未完成 |
|--------|------|--------|----------|--------|
| P0 | 4 | 3 | 1(P0-3 i18n) | 0 |
| P1 | 8 | 7 | 1(P1-6 类型断言) | 0 |
| P2 | 6 | 4 | 1(P2-5 架构图同步) | 1(图谱方向键导航) |
| **合计** | **18** | **14** | **3** | **1** |
### 1.2 各项状态明细
| 编号 | 标题 | 状态 | 关键证据 |
|------|------|------|----------|
| P0-1 | 跨模块 UI 依赖解耦 | ✅ 已完成 | `knowledge-point-dialogs.tsx` 改为 render prop,页面层注入 |
| P0-2 | 前端权限硬编码 canEdit | ✅ 已完成 | `textbook-reader.tsx` 使用 `usePermission().hasPermission()` |
| P0-3 | 全模块 i18n 改造 | ⚠️ 部分完成 | 约 85%,`chapter-sidebar-list.tsx`/`actions.ts`/`section-error-boundary.tsx` 未接入 |
| P0-4 | Server Action 资源归属校验 | ✅ 已完成 | `actions.ts` 全部写 Action 调用 `verify*` 函数 |
| P1-1 | data-access 数据范围过滤 | ✅ 已完成 | `getTextbooksWithScope` + 学生端按年级过滤 |
| P1-2 | Error Boundary | ✅ 已完成 | 4 个 `error.tsx` + `section-error-boundary.tsx` |
| P1-3 | 消除重复组件 | ✅ 已完成 | 删除 `knowledge-point-panel.tsx` 和 `create-knowledge-point-dialog.tsx` |
| P1-4 | 抽取学科/年级配置 | ✅ 已完成 | `constants.ts` 集中管理 `SUBJECTS`/`GRADES`/`SUBJECT_COLORS` |
| P1-5 | 导出纯函数并补单测 | ✅ 已完成 | `utils.ts` + `graph-layout.ts` + 两个测试文件 |
| P1-6 | 修复类型断言 | ⚠️ 部分完成 | v1 的 3 处已修复,残留 3 处 `as string` |
| P1-7 | 图谱 a11y | ✅ 已完成 | `role="img"`/`aria-label`/`
`/`aria-pressed` |
| P1-8 | 统一删除确认 | ✅ 已完成 | `textbook-settings-dialog.tsx` 用 `AlertDialog` |
| P2-1 | 统一空状态 | ✅ 已完成 | 全部使用 `EmptyState` |
| P2-2 | 知识点高亮性能优化 | ✅ 已完成 | 单遍 alternation 正则 + `useMemo` |
| P2-3 | 知识点懒加载 | ✅ 已完成 | 按章节懒加载 + 缓存 + 派生加载状态 |
| P2-4 | 移动端阅读优化 | ✅ 已完成 | `Sheet` 抽屉 + 桌面端内联复用 |
| P2-5 | 架构图同步 | ⚠️ 部分完成 | 005 JSON 新函数已加,`knownIssues`/`uiDeps`/`components` 过期 |
| P2-6 | 埋点接口预留 | ✅ 已完成 | `analytics.tsx` 定义接口 + Provider + Hook |
---
## 二、v2 新发现的问题
### 2.1 i18n 完整性(P0,v1 遗留)
#### 问题 v2-1 | `chapter-sidebar-list.tsx` 完全未接入 i18n(P0)
- **位置**:[chapter-sidebar-list.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/chapter-sidebar-list.tsx)
- **现象**:第 90 行 `"Toggle"`、第 118 行 `"Add Subchapter"`、第 130 行 `"Delete Chapter"`、第 258 行 `"Order updated"`、第 278 行 `"Cannot delete chapter with subchapters"`、第 332-341 行删除对话框文案全部硬编码英文
- **翻译键已存在**:`dialog.chapter.deleteTitle`/`delete`/`deleting`/`cannotDeleteWithSubchapters`/`addSubchapter` 等
- **影响**:中文用户看到英文文案,i18n 覆盖率不完整
#### 问题 v2-2 | `actions.ts` 错误消息全部硬编码英文(P0)
- **位置**:[actions.ts](file:///e:/Desktop/CICD/src/modules/textbooks/actions.ts)
- **现象**:约 20+ 条消息硬编码,如第 47 行 `"Chapter does not belong to this textbook"`、第 56 行 `"Failed to reorder chapters"`
- **影响**:用户看到的 toast 消息无法本地化
- **建议**:Server Action 内使用 `getTranslations("textbooks.action")` 获取翻译
#### 问题 v2-3 | `section-error-boundary.tsx` 默认文案硬编码中文(P1)
- **位置**:[section-error-boundary.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/section-error-boundary.tsx) 第 52/55/59 行
- **现象**:默认 fallback `"区块加载失败"` / `"请重试或刷新页面"` / `"重试"` 硬编码
- **影响**:英文用户看到中文默认值
### 2.2 学科/年级显示未本地化(P1)
#### 问题 v2-4 | `textbook-card.tsx` 学科显示未本地化(P1)
- **位置**:[textbook-card.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-card.tsx) 第 41 行
- **现象**:`{textbook.subject}` 直接显示原始值(如 "Mathematics"),未通过 `t(\`subject.${labelKey}\`)` 转换
#### 问题 v2-5 | 页面层学科/年级显示未本地化(P1)
- **位置**:
- [teacher/textbooks/[id]/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/teacher/textbooks/[id]/page.tsx) 第 64、66 行
- [student/learning/textbooks/[id]/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/student/learning/textbooks/[id]/page.tsx) 第 47、49 行
- **现象**:`{textbook.subject}` 和 `{textbook.grade}` 直接显示原始值
### 2.3 类型安全(P2)
#### 问题 v2-6 | 残留 `as string` 断言(P2)
- **位置**:
- [chapter-sidebar-list.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/chapter-sidebar-list.tsx) 第 226、257 行:`active.id as string`
- [graph-layout.ts](file:///e:/Desktop/CICD/src/modules/textbooks/graph-layout.ts) 第 123 行:`kp.parentId as string`
- **建议**:用类型守卫或 narrowing 替代
### 2.4 重复代码(P2)
#### 问题 v2-7 | `findParent` 与 `utils.ts` 的 `findChapterParent` 重复(P2)
- **位置**:[chapter-sidebar-list.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/chapter-sidebar-list.tsx) 第 215-224 行
- **现象**:内联 `findParent` 函数与 `utils.ts` 导出的 `findChapterParent` 功能完全相同
- **建议**:替换为 `import { findChapterParent } from "../utils"`
#### 问题 v2-8 | 4 个 `error.tsx` 文件几乎完全相同(P2)
- **位置**:4 个 `error.tsx` 文件
- **现象**:内容完全一致(仅函数名不同)
- **建议**:抽取为共享组件 `TextbookRouteError`
#### 问题 v2-9 | `student/learning/textbooks/page.tsx` 重复定义 `getParam`(P2)
- **位置**:[student/learning/textbooks/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/student/learning/textbooks/page.tsx) 第 13-18 行
- **现象**:本地定义 `getParam`,但 `@/shared/lib/search-params` 已导出
- **建议**:统一从 `@/shared/lib/search-params` 导入
### 2.5 a11y 改进(P2)
#### 问题 v2-10 | 拖拽手柄无 `aria-label`(P2)
- **位置**:[chapter-sidebar-list.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/chapter-sidebar-list.tsx) 第 71-73 行
- **现象**:`` 拖拽手柄仅含 `GripVertical` 图标,无 `aria-label`
#### 问题 v2-11 | 知识点高亮 span 无可交互语义(P2)
- **位置**:[textbook-content-panel.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-content-panel.tsx) 第 133-148 行
- **现象**:高亮的知识点 `` 仅 `data-kp-id` + `title`,无 `role="button"`/`aria-label`/`tabIndex`
#### 问题 v2-12 | 移动端抽屉触发按钮无 `aria-expanded`(P2)
- **位置**:[textbook-reader.tsx](file:///e:/Desktop/CICD/src/modules/textbooks/components/textbook-reader.tsx) 第 361-368 行
- **现象**:`