Files
NextEdu/docs/architecture/audit/archive/homework-audit-report.md

349 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 客观题自动识别