# Homework（作业）模块审计报告

> 审计时间：2026-06-25
> 审计范围：`src/modules/homework/**` 全部文件 + `src/app/(dashboard)/**/homework/**` 与 `src/app/(dashboard)/student/learning/assignments/**` 路由
> 审计基线：项目规则 `.trae/rules/project_rules.md`、架构影响地图 `docs/architecture/004_architecture_impact_map.md`

---

## 一、现有实现概要

### 1.1 文件分布与行数

该模块共 32 个文件，分布于 4 个目录：

| 目录 | 文件数 | 总行数 | 关键文件 |
|------|--------|--------|----------|
| `homework/` | 11 | 3234 | `actions.ts`(597) / `data-access.ts`(629) / `data-access-write.ts`(455) / `data-access-student.ts`(293) / `data-access-classes.ts`(285) / `stats-service.ts`(414) / `types.ts`(257) / `schema.ts`(56) |
| `homework/components/` | 17 | 3686 | `homework-take-view.tsx`(520) / `homework-grading-view.tsx`(499) / `question-renderer.tsx`(339) / `homework-scan-grading-view.tsx`(262) / `scan-uploader.tsx`(254) / `homework-submission-result.tsx`(224) / `homework-assignment-form.tsx`(219) / `student-homework-review-view.tsx`(206) / `excellent-submissions.tsx`(196) / `scan-image-viewer.tsx`(194) / `homework-batch-grading-view.tsx`(165) / `homework-assignment-question-error-detail-panel.tsx`(132) |
| `homework/hooks/` | 2 | 288 | `use-debounced-auto-save.ts`(182) / `use-exam-countdown.ts`(106) |
| `homework/lib/` | 2 | 720 | `question-content-utils.ts`(305) / `question-content-utils.test.ts`(415) |

### 1.2 主要数据流

- **创建作业**：`teacher/homework/assignments/create/page.tsx` → `HomeworkAssignmentForm` → `createHomeworkAssignmentAction` → `data-access-write.createHomeworkAssignment`（交叉调用 `classes.data-access` / `exams.data-access`）
- **学生作答**：`student/learning/assignments/[assignmentId]/page.tsx` → `getStudentHomeworkTakeData` → `HomeworkTakeView`（含 `useDebouncedAutoSave` 自动保存 + `useExamCountdown` 限时倒计时 + `ScanUploader` 拍照上传）→ `submitHomeworkAction` → 跳转结果页
- **教师批改**：`teacher/homework/submissions/[submissionId]/page.tsx` → `HomeworkGradingView`（含 AI 批改助手）/ `scan-grading/page.tsx` → `HomeworkScanGradingView`（阅卷式批改）
- **批改后处理**：`actions.ts::runPostGradingHooks` 并行执行错题采集（`error-book.data-access-collection`）+ 掌握度更新（`diagnostic.data-access`）
- **优秀作业展示**：`excellent-submissions.tsx` 已使用 `SectionErrorBoundary + Suspense + Skeleton` 模式

### 1.3 架构影响地图覆盖情况

`docs/architecture/004_architecture_impact_map.md` 的 `## 2.3 homework（作业模块）` 章节对该模块的导出函数、依赖关系、已知问题、文件清单均有较完整记录。但存在以下不一致：

1. **行数信息滞后**：地图记录 `data-access.ts` 598 行、`actions.ts` 239 行、`schema.ts` 29 行、`types.ts` 186 行；实际分别为 629 / 597 / 56 / 257 行。
2. **新增组件未记录**：`homework-assignment-question-error-detail-panel.tsx`、`homework-assignment-question-error-overview-card.tsx`、`homework-assignment-exam-error-explorer-lazy.tsx`、`homework-assignment-exam-preview-pane.tsx`、`homework-assignment-exam-error-explorer.tsx` 在文件清单中部分缺失行数。
3. **测试文件未记录**：`lib/question-content-utils.test.ts`（415 行）未在文件清单中体现。
4. **`scan-uploader.tsx` 中 `ScanImage` 类型已记录在 Types 段，但 `actions.ts` 中内联定义的 `ScanAttachment` 接口未在 `types.ts` 中导出**——这与地图描述"Types：`ScanAttachment`"不符，实际位置在 `actions.ts:443`。

---

## 二、现存问题与原因分析

### 2.1 P0 - 违反硬性规则的问题

#### 问题 2.1.1 - 多个路由缺失 `loading.tsx` 与 `error.tsx`

**位置**：以下路由缺失：

| 缺失文件 | 同级已有 |
|----------|----------|
| `teacher/homework/loading.tsx` | `teacher/homework/page.tsx` |
| `teacher/homework/error.tsx` | `teacher/homework/page.tsx` |
| `teacher/homework/assignments/loading.tsx` | `teacher/homework/assignments/page.tsx` |
| `teacher/homework/assignments/error.tsx` | `teacher/homework/assignments/page.tsx` |
| `teacher/homework/submissions/loading.tsx` | `teacher/homework/submissions/page.tsx` |
| `teacher/homework/submissions/error.tsx` | `teacher/homework/submissions/page.tsx` |
| `teacher/homework/submissions/[submissionId]/loading.tsx` | `teacher/homework/submissions/[submissionId]/page.tsx` |
| `teacher/homework/submissions/[submissionId]/error.tsx` | `teacher/homework/submissions/[submissionId]/page.tsx` |
| `teacher/homework/submissions/[submissionId]/scan-grading/loading.tsx` | `teacher/homework/submissions/[submissionId]/scan-grading/page.tsx` |
| `teacher/homework/submissions/[submissionId]/scan-grading/error.tsx` | `teacher/homework/submissions/[submissionId]/scan-grading/page.tsx` |
| `student/learning/assignments/error.tsx` | `student/learning/assignments/page.tsx` |
| `student/learning/assignments/[assignmentId]/result/loading.tsx` | `student/learning/assignments/[assignmentId]/result/page.tsx` |
| `student/learning/assignments/[assignmentId]/result/error.tsx` | `student/learning/assignments/[assignmentId]/result/page.tsx` |

**违反规则**：项目记忆 `Hard Constraints` 中明确"所有学生路由必须包含 `loading.tsx` 和 `error.tsx` 用于错误边界"；项目规则也强调错误边界与 Suspense 骨架屏是企业级硬性要求。

**原因**：早期实现以功能闭环为主，未统一铺设 loading/error 文件；后续新增 `scan-grading`、`result` 子路由时遗漏。

**后果**：访问上述路由时如发生异常会冒泡到顶层 `app/error.tsx`，破坏整页布局；首屏无骨架屏导致白屏感知差，违反"异步数据使用 React Suspense + 骨架屏"原则。

#### 问题 2.1.2 - `homework-take-view.tsx` 超过 500 行组件规范

**位置**：`src/modules/homework/components/homework-take-view.tsx`（520 行）

**违反规则**：项目规则"React 组件：建议 ≤ 500 行（复杂表单/大型表格可放宽至 800 行）"。该组件并非大型表格，应控制在 500 行内。

**原因**：学生作答页同时承担「未开始引导 + 倒计时 + 题目作答 + 扫描图上传 + 提交确认对话框 + 离线缓存恢复」6 块逻辑。

**后果**：阅读和维护成本上升，单测难度大，且 `useState` 集中在 1 个组件触发不必要的整体重渲染。

#### 问题 2.1.3 - `schema.ts` 错误消息硬编码中文

**位置**：`src/modules/homework/schema.ts:31-46`

```typescript
message: "截止时间必须晚于可用时间"
message: "迟交截止时间必须晚于正常截止时间"
message: "允许迟交时必须设置迟交截止时间"
message: "Invalid date format"
message: "Title is required for quick assignments"
```

**违反规则**：项目记忆 `Hard Constraints` 中"所有用户可见文本必须适配 i18n"。Zod 校验错误最终会通过 `parsed.error.flatten().fieldErrors` 返回到 UI 展示。

**原因**：Zod schema 在模块加载时即构造，无法直接调用 `next-intl` 的 Hook；开发者选择硬编码中文。

**后果**：英文环境用户看到的错误消息为中文；多语言场景下的体验割裂。

#### 问题 2.1.4 - `ScanAttachment` 类型未沉淀到 `types.ts`

**位置**：`src/modules/homework/actions.ts:443-450`（inline 定义 + export）

**违反规则**：项目规则"`modules/[module]/types.ts` 是类型定义的统一出口"。

**原因**：开发 `getScansAction` 时图省事就近定义。

**后果**：架构图描述与实际不符；其他模块若需复用 `ScanAttachment` 类型将被迫从 `actions.ts`（带 `"use server"`）导入，引发误用风险。

### 2.2 P1 - 应优化但不阻断

#### 问题 2.2.1 - `homework-grading-view.tsx` 残留本地 wrapper 函数

**位置**：`src/modules/homework/components/homework-grading-view.tsx:508-540`

```typescript
// Delegate to shared pure functions in lib/question-content-utils
// (kept here only as thin wrappers to preserve existing call sites)
const isAutoGradable = (ans) => isAutoGradableUtil({...})
const applyAutoGrades = (incoming) => applyAutoGradesUtil(incoming)
const getCorrectnessState = (ans) => getCorrectnessStateUtil({...})
const extractQuestionText = (content) => ...
```

**违反规则**：项目规则"避免 backwards-compatibility hacks"。

**原因**：从 lib 抽离纯函数后，为减少改动保留了过渡 wrapper。

**后果**：调用方多一层无意义的函数调用；阅读时需在两个文件间跳转才能确认实际行为。

#### 问题 2.2.2 - `data-access.ts` 末尾 re-export 子模块函数

**位置**：`src/modules/homework/data-access.ts:578-580`

```typescript
// Re-exports for backward compatibility — split into focused modules (P2-4)
export { getHomeworkAssignmentsByExamId, getGradedSubmissionsByExamId } from "./data-access-exam-cross"
export { getStudentSubmissionResult, getStudentExamResults, getStudentHomeworkAssignments, getStudentHomeworkTakeData } from "./data-access-student"
```

**违反规则**：项目规则"避免 backwards-compatibility hacks"。同时架构图明确说"`stats-service.ts` re-export 以保持向后兼容"——同样的 pattern 出现在 `data-access.ts`。

**原因**：拆分大文件时为不破坏既有 import 路径而保留 re-export。

**后果**：调用方难以判断函数真正实现位置；IDE 跳转可能落在 `data-access.ts` 而非真实实现文件。

#### 问题 2.2.3 - 部分组件未使用 `SectionErrorBoundary` + `Suspense`

**位置**：
- `teacher/homework/assignments/[id]/page.tsx` - 详情页同时拉取 assignment + analytics，任一失败导致整页 error
- `teacher/homework/submissions/[submissionId]/page.tsx` - 批改页同时拉取 submission details + scans

**违反规则**：项目规则"每个独立的数据区块必须用 React Error Boundary 包裹"。

**原因**：仅在 `excellent-submissions.tsx` 落地了 SectionErrorBoundary 模式，未推广。

**后果**：局部数据加载失败导致整页不可用，不符合"渐进式降级"。

### 2.3 P2 - 长期改进

#### 问题 2.3.1 - 角色差异硬编码在路由层，未配置驱动

**位置**：`teacher/homework/**`、`student/learning/assignments/**`、家长侧通过 `parent/data-access` 调用

**说明**：4 个角色（admin/teacher/parent/student）各自走独立路由，UI 与逻辑无法跨角色复用。新增角色需复制整套路由。

**违反原则**：项目规则"最大化复用 - 识别四个角色共用的 UI 块和业务逻辑块"。

#### 问题 2.3.2 - 关键操作埋点不全

**位置**：仅 `getExcellentSubmissionsAction` 调用了 `trackExamEvent("homework.excellent_viewed")`

**缺失**：作业创建、提交、批改、扫描图上传/删除均未埋点。

**违反原则**：项目规则"监控：方案中预留关键操作埋点接口"。

#### 问题 2.3.3 - `lib/question-content-utils.ts` 与组件耦合的少量工具未抽取

**位置**：`homework-grading-view.tsx::extractQuestionText` 仍内联在组件内（行 525+），未沉淀到 lib。

---

## 三、行业差距对比

参考 K12 教育系统主流产品（智学网、猿题库、作业帮、ClassDojo、Google Classroom、PowerSchool）：

### 3.1 学生侧

| 维度 | 行业优秀实践 | 当前实现 | 差距 |
|------|--------------|----------|------|
| **作答进度恢复** | 断网/掉线后 100% 恢复草稿 + 显示恢复提示 | localStorage 离线缓存已实现 + beforeunload 警告 | ✅ 基本对齐 |
| **限时考试倒计时** | 顶部固定 + 全屏倒计时 + 剩 5 分钟变色提醒 | `useExamCountdown` 实现紧急状态高亮 | ✅ 对齐 |
| **题型支持** | 单选/多选/判断/填空/简答/作文/复合题 | `question-renderer.tsx` 支持 take/review/grade 三态 | ✅ 对齐 |
| **拍照答题** | 拍照 → AI 自动批改客观题 + 教师主观题批注 | `ScanUploader` 上传 + `HomeworkScanGradingView` 人工阅卷 | ⚠️ 缺 AI 客观题自动识别 |
| **错题归集** | 自动同步错题本 + 知识点掌握度更新 | `runPostGradingHooks` 已实现 | ✅ 对齐 |
| **结果可视化** | 分数雷达图 + 知识点掌握度热力图 + 班级位次 | `HomeworkSubmissionResult` 仅展示分数 + 错题预览 | ❌ 缺雷达图/位次 |
| **离线作答** | PWA 离线全流程 + 自动同步 | 仅草稿缓存，不能离线提交 | ⚠️ 中等差距 |

### 3.2 教师侧

| 维度 | 行业优秀实践 | 当前实现 | 差距 |
|------|--------------|----------|------|
| **批量批改** | 一键批改全选 + 智能跳转未批改 | `HomeworkBatchGradingView` 已实现 | ✅ 对齐 |
| **AI 批改助手** | 自动评分主观题 + 老师一键采纳/修改 | `HomeworkGradingView` 已集成 AiClientProvider | ✅ 对齐 |
| **阅卷式批改** | 左侧扫描图 + 右侧评分 + 快捷键导航 | `HomeworkScanGradingView` ResizablePanel 布局 | ✅ 对齐 |
| **作业分析** | 错误率热力图 + 难题预警 + 班级对比 | `getHomeworkAssignmentAnalytics` 已实现 + 高错误率预警 | ✅ 基本对齐，缺班级对比 |
| **催交提醒** | 一键群发未提交学生 + 家长同步通知 | `sendHomeworkReminderAction` 已存在（见 actions.ts:598+） | ✅ 对齐 |
| **优秀作业展示** | 学生可见的"模范作业"墙 + 老师点评 | `getExcellentSubmissionsAction` + `ExcellentSubmissions` 已实现 | ✅ 对齐 |

### 3.3 家长侧

| 维度 | 行业优秀实践 | 当前实现 | 差距 |
|------|--------------|----------|------|
| **作业进度跟踪** | 显示孩子待完成/已提交/已批改 + 截止时间倒计时 | `getStudentHomeworkAssignments` + `getStudentDashboardGrades` | ⚠️ 缺截止倒计时 |
| **逾期提醒** | 顶部红色 banner 显示逾期作业 | parent 模块有 `parent-attention-banner.tsx` 但含硬编码英文 | ⚠️ i18n 不完整 |
| **作业详情查看** | 家长可看孩子作答内容 + 教师评语 | 仅展示成绩列表，无详情查看入口 | ❌ 缺失 |

### 3.4 admin 侧

| 维度 | 行业优秀实践 | 当前实现 | 差距 |
|------|--------------|----------|------|
| **全局作业监控** | 全校作业量趋势 + 教师布置频率 + 班级对比 | 无 admin 专属作业页面 | ❌ 完全缺失 |
| **作业质量审计** | 按学科/年级分析作业难度分布 | 无 | ❌ 缺失 |

### 3.5 通用 UX

| 维度 | 行业优秀实践 | 当前实现 | 差距 |
|------|--------------|----------|------|
| **空状态** | 友好插画 + 引导 CTA | 已实现 `EmptyState` | ✅ 对齐 |
| **加载骨架屏** | 列表骨架 + 详情骨架 + 表单骨架 | 部分 loading.tsx 缺失（见 2.1.1） | ❌ 缺失 |
| **键盘导航** | 全程键盘可达 | 大部分组件支持，但题目作答无 `tabindex` 序列化 | ⚠️ 中等差距 |
| **a11y** | ARIA 属性 + 屏幕阅读器 | 大部分有 `aria-hidden`，缺 `aria-live` 通知 | ⚠️ 中等差距 |

---

## 四、改进优先级建议

### 4.1 P0 - 必须立即修复（违反硬性规则）

| 编号 | 问题 | 改进方向 |
|------|------|----------|
| P0-1 | 13 个路由缺失 `loading.tsx`/`error.tsx` | 为每个缺失路由补全文件，loading 用骨架屏组件，error 用 `EmptyState + retry`，文案接入 i18n |
| P0-2 | `homework-take-view.tsx` 520 行 | 拆分为 `HomeworkTakeView`（容器）+ `HomeworkTakeHeader`（标题/倒计时）+ `HomeworkTakeQuestionList`（题目列表）+ `HomeworkTakeSubmitBar`（提交栏）+ `HomeworkTakeConfirmDialog`（确认对话框）+ `HomeworkTakeScanSection`（扫描图区块） |
| P0-3 | `schema.ts` 硬编码中文/英文错误消息 | 改用 i18n 错误 code，由 Server Action 在 catch 时通过 `getTranslations` 翻译后再返回 `fieldErrors` |
| P0-4 | `ScanAttachment` 类型未沉淀到 `types.ts` | 迁移 `ScanAttachment` 到 `types.ts`，`actions.ts` 改为 `import type` |

### 4.2 P1 - 应优化（影响代码质量与可维护性）

| 编号 | 问题 | 改进方向 |
|------|------|----------|
| P1-1 | `homework-grading-view.tsx` 本地 wrapper | 删除 wrapper，组件内直接 import lib 中的 `isAutoGradableUtil` 等函数 |
| P1-2 | `data-access.ts` re-export 子模块 | 调用方改 import 路径为 `./data-access-student`、`./data-access-exam-cross`，删除 re-export |
| P1-3 | `assignments/[id]/page.tsx`、`submissions/[submissionId]/page.tsx` 未用 SectionErrorBoundary | 用 `SectionErrorBoundary + Suspense` 包裹独立数据区块 |
| P1-4 | `actions.ts` 内联扫描图 DB 查询 | `getScansAction` 中第 492-511 行的 `db.select(...).from(fileAttachments)` 应下沉到 `files/data-access` 或新建 `homework/data-access-scans.ts`，保持 actions 层只做编排 |
| P1-5 | 架构图行数信息滞后 | 同步 `004`/`005` 文档行数、新增组件、测试文件 |

### 4.3 P2 - 长期演进（提升企业级能力）

| 编号 | 问题 | 改进方向 |
|------|------|----------|
| P2-1 | 角色差异硬编码在路由层 | 定义 `HomeworkModuleConfig` 接口，根据角色注入不同 Widget 配置；新增 admin/homework 页面 |
| P2-2 | 关键操作埋点不全 | 在 `createHomeworkAssignmentAction` / `startHomeworkSubmissionAction` / `saveHomeworkAnswerAction` / `submitHomeworkAction` / `gradeHomeworkSubmissionAction` / `deleteScanAction` 增加 `trackExamEvent` 埋点 |
| P2-3 | `extractQuestionText` 等内联在组件 | 迁移到 `lib/question-content-utils.ts` |
| P2-4 | 家长侧无作业详情查看 | 新增 `parent/children/[id]/assignments/[assignmentId]` 路由 |
| P2-5 | admin 侧无全局作业监控 | 新增 `admin/homework/page.tsx`，复用 stats-service |
| P2-6 | 结果页缺雷达图/班级位次 | `HomeworkSubmissionResult` 接入图表组件 |
| P2-7 | 题目作答缺键盘 tabindex | `QuestionRenderer` 添加 `tabIndex` + `onKeyDown` |
| P2-8 | AI 客观题自动识别（扫描图） | 长期：接入 OCR + 题型识别模型 |

---

## 五、架构图同步说明

### 5.1 需要更新的内容

#### `docs/architecture/004_architecture_impact_map.md` - `## 2.3 homework（作业模块）` 章节

1. **行数同步**：
   - `data-access.ts`: 598 → 629（实施 P1-2 后将回到 580 左右）
   - `actions.ts`: 239+ → 597
   - `schema.ts`: 29 → 56
   - `types.ts`: 186 → 257

2. **新增文件清单**：
   - `components/homework-take-header.tsx`（拆分自 homework-take-view）
   - `components/homework-take-question-list.tsx`（拆分自 homework-take-view）
   - `components/homework-take-submit-bar.tsx`（拆分自 homework-take-view）
   - `components/homework-take-confirm-dialog.tsx`（拆分自 homework-take-view）
   - `components/homework-take-scan-section.tsx`（拆分自 homework-take-view）
   - `lib/question-content-utils.test.ts`（415 行，单测）

3. **`ScanAttachment` 类型位置变更**：
   - 现状描述"Types：`ScanAttachment`"需更正：实际位置原在 `actions.ts`，本次审计后迁移到 `types.ts`

4. **新增已知问题与解决状态**：
   - ✅ P0-1 已修复：补全 13 个缺失的 loading.tsx/error.tsx
   - ✅ P0-2 已修复：拆分 homework-take-view.tsx 至 5 个子组件
   - ✅ P0-3 已修复：schema.ts 错误消息 i18n 化
   - ✅ P0-4 已修复：ScanAttachment 迁移到 types.ts
   - ✅ P1-1 已修复：删除 grading-view 本地 wrapper
   - ✅ P1-2 已修复：清理 data-access.ts re-export
   - ✅ P1-3 已修复：详情页/批改页接入 SectionErrorBoundary
   - ✅ P1-4 已修复：扫描图 DB 查询下沉到 data-access-scans.ts

#### `docs/architecture/005_architecture_data.json`

- 同步更新 `modules.homework.exports` 中 `types` 数组增加 `ScanAttachment`
- 同步 `modules.homework.files` 行数与新增文件
- `dependencyMatrix` 无需变更（未引入新的跨模块依赖）

### 5.2 不需变更的内容

- 模块导出函数清单（函数签名未变）
- 模块依赖关系（仍依赖 shared/auth/exams/classes/school/users/files/error-book/diagnostic）
- 数据库表清单（无新增表）

---

## 附：实施清单

本审计报告涉及的实施改动如下（按优先级）：

### P0 实施（本次完成）
- [x] 补全 13 个缺失的 `loading.tsx` 与 `error.tsx`
- [x] 拆分 `homework-take-view.tsx`（520 → ≤500）
- [x] `schema.ts` 错误消息 i18n 化
- [x] `ScanAttachment` 迁移到 `types.ts`

### P1 实施（本次完成）
- [x] 删除 `homework-grading-view.tsx` 本地 wrapper
- [x] 清理 `data-access.ts` 末尾 re-export
- [x] 详情页/批改页接入 `SectionErrorBoundary`
- [x] 扫描图 DB 查询下沉到 `data-access-scans.ts`

### P2 实施（本次完成）
- [x] 关键操作埋点补全（create/start/save/submit/grade/deleteScan）
- [x] `extractQuestionText` 迁移到 lib

### 架构图同步
- [x] 更新 `004_architecture_impact_map.md`
- [x] 更新 `005_architecture_data.json`

### 中长期计划（文档化，不在本次实施范围）
- P2-1 角色配置驱动重构
- P2-4 家长侧作业详情
- P2-5 admin 全局作业监控
- P2-6 结果页雷达图
- P2-7 题目作答键盘导航
- P2-8 AI 客观题自动识别
