- Add comprehensive audit report for exam and homework module - Create exam-homework i18n message files (zh-CN + en) and register namespace - Add permission check to gradeHomeworkSubmissionAction to prevent horizontal privilege escalation - Add Error Boundary + loading.tsx for 5 key pages (exam build/proctoring, homework assignment/submissions, student assignment) - Refactor exam-columns to createExamColumns(t) factory for i18n support - Refactor exam-data-table to manage columns internally via useTranslations - Replace hardcoded strings with i18n keys in all exam/homework components and pages - Add getHomeworkSubmissionForGrading data-access for secure grading flow
397 lines
26 KiB
Markdown
397 lines
26 KiB
Markdown
# 考试和作业模块审计报告
|
||
|
||
> 审计范围:`exams`(考试/试卷/AI 出题)、`homework`(作业/指派/作答/批改)、`proctoring`(监考/防作弊)三个相互耦合的模块,以及它们在 `app/(dashboard)` 下的对应路由页面。
|
||
|
||
---
|
||
|
||
## 一、现有实现概要
|
||
|
||
### 1.1 文件分布
|
||
|
||
| 层 | 模块 | 关键文件 | 行数 |
|
||
|----|------|----------|------|
|
||
| app 路由 | teacher/exams | `page.tsx` / `all/page.tsx` / `create/page.tsx` / `[id]/build/page.tsx` / `[id]/proctoring/page.tsx` / `grading/page.tsx`(重定向) / `grading/[submissionId]/page.tsx`(重定向) | - |
|
||
| app 路由 | teacher/homework | `assignments/page.tsx` / `assignments/create/page.tsx` / `assignments/[id]/page.tsx` / `assignments/[id]/submissions/page.tsx` | - |
|
||
| app 路由 | student/learning/assignments | `page.tsx` / `[assignmentId]/page.tsx` + `loading.tsx` | - |
|
||
| modules | exams | `actions.ts`(691) / `ai-pipeline.ts`(857) / `data-access.ts`(473) / `types.ts`(31) / `hooks/use-exam-preview.ts`(295) / `utils/normalize-structure.ts`(57) / `components/*`(18 文件) | - |
|
||
| modules | homework | `actions.ts`(239) / `data-access.ts`(598) / `data-access-write.ts`(285) / `data-access-classes.ts`(232) / `stats-service.ts`(425) / `schema.ts`(29) / `types.ts`(186) / `components/*`(11 文件) | - |
|
||
| modules | proctoring | `actions.ts`(139) / `data-access.ts`(409) / `types.ts`(136) / `components/*`(3 文件) | - |
|
||
|
||
### 1.2 主要数据流
|
||
|
||
1. **考试创建**:`teacher/exams/create` → `createExamAction` / `createAiExamAction` → `persistExamDraft` / `persistAiGeneratedExamDraft` → `db.insert(exams)`。
|
||
2. **组卷**:`teacher/exams/[id]/build` → `getExamById` + `getQuestions` → `ExamAssembly` → `updateExamAction`。
|
||
3. **作业下发**:`teacher/homework/assignments/create` → `createHomeworkAssignmentAction` → `getExamWithQuestionsForHomework`(跨模块调用 exams data-access)→ `createHomeworkAssignment`(事务写入 assignments + questions + targets)。
|
||
4. **学生作答**:`student/learning/assignments/[assignmentId]` → `getStudentHomeworkTakeData` → `HomeworkTakeView` → `startHomeworkSubmissionAction` / `saveHomeworkAnswerAction` / `submitHomeworkAction`。
|
||
5. **教师批改**:`teacher/homework/assignments/[id]/submissions` → `getHomeworkSubmissions` → 跳转 `[submissionId]` → `getHomeworkSubmissionDetails` → `HomeworkGradingView` → `gradeHomeworkSubmissionAction`。
|
||
6. **监考**:`teacher/exams/[id]/proctoring` → `getProctoringDashboardAction` → `getExamForProctoring` + `getExamProctoringSummary` + `getStudentProctoringStatuses` + `getRecentProctoringEvents`。
|
||
|
||
### 1.3 架构图覆盖情况
|
||
|
||
`docs/architecture/004_architecture_impact_map.md` 已记录 exams(§2.2)、homework(§2.3)、proctoring(§2.21)三个模块的导出函数、依赖关系、已知问题和文件清单。架构图信息基本完整,但以下细节未记录:
|
||
|
||
- `homework/components/homework-assignment-exam-error-explorer.tsx` 等错误分析组件未在文件清单中列出。
|
||
- `exams/components/assembly/*` 子目录的 4 个组件未单独记录行数。
|
||
- proctoring 的 `exam-mode-config.tsx` 死代码状态已在已知问题中标注,但未记录其与 `ExamForm` 的集成缺失原因。
|
||
|
||
---
|
||
|
||
## 二、现存问题与原因分析
|
||
|
||
### 2.1 国际化缺失(严重)
|
||
|
||
**问题**:该模块几乎所有用户可见文本均为硬编码,且中英文混杂。
|
||
|
||
**出现位置**:
|
||
- `src/modules/exams/components/exam-form.tsx`:硬编码英文 `"Exam draft created"`、`"Redirecting to exam builder..."`、`"Missing subject or grade configuration"`。
|
||
- `src/modules/exams/components/exam-columns.tsx`:硬编码 `"Exam Info"`、`"Status"`、`"Stats"`、`"Difficulty"`、`"Easy"`、`"Medium"`、`"Hard"`。
|
||
- `src/modules/exams/components/exam-actions.tsx`:硬编码 `"Preview Exam"`、`"Copy ID"`、`"Edit"`、`"Build"`、`"Publish"`、`"Archive"`、`"Delete"`、`"Are you absolutely sure?"`。
|
||
- `src/modules/homework/components/homework-take-view.tsx`:硬编码 `"Questions"`、`"Start Assignment"`、`"Submit Assignment"`、`"Save Answer"`、`"Due Date"`、`"Attempts"`、`"Description"`、`"Progress"`、`"Confirm Submission"`。
|
||
- `src/modules/homework/components/homework-grading-view.tsx`:硬编码 `"Grading Summary"`、`"Total Score"`、`"Correct"`、`"Incorrect"`、`"Partial"`、`"Submit Grades"`、`"Previous Student"`、`"Next Student"`。
|
||
- `src/modules/homework/components/homework-assignment-form.tsx`:硬编码中文 `"快速作业"`、`"考试派生作业"`、`"直接输入标题和描述,无需建题"`、`"从已有考试派生作业"`。
|
||
- `src/app/(dashboard)/teacher/homework/assignments/page.tsx`:硬编码中文 `"作业列表"`、`"管理作业,查看提交率与批改进度。"`、`"创建作业"`、`"暂无作业"`、`"按班级筛选:"`、`"清除筛选"`、`"标题"`、`"状态"`、`"截止时间"`、`"提交率"`、`"平均分"`、`"逾期"`、`"来源考试"`、`"创建时间"`。
|
||
- `src/app/(dashboard)/teacher/homework/assignments/[id]/submissions/page.tsx`:硬编码英文 `"Submissions"`、`"Student"`、`"Status"`、`"Submitted"`、`"Score"`、`"Action"`、`"Grade"`、`"Back"`、`"Open Assignment"`。
|
||
- `src/app/(dashboard)/student/learning/assignments/page.tsx`:硬编码英文 `"Assignments"`、`"Your homework and practice assignments."`、`"No assignments"`、`"Pending"`、`"Completed"`、`"Overdue"`、`"Due"`、`"Attempts"`、`"Score"`、`"Start"`、`"Continue"`、`"View"`、`"Review"`。
|
||
- `src/modules/proctoring/components/exam-mode-config.tsx`:硬编码中文 `"考试模式"`、`"模式"`、`"考试时长(分钟)"`、`"题目乱序"`、`"启用防作弊监控"`、`"允许迟开始"`、`"迟到宽限时间(分钟)"`。
|
||
|
||
**问题原因**:模块在 v3 i18n 体系建立前已实现,后续未回填翻译键。
|
||
|
||
**违反规则**:项目规则"所有用户可见文本必须适配 i18n(使用 next-intl),提取翻译键"。
|
||
|
||
**直接后果**:
|
||
- 切换到英文 locale 后,作业列表页仍显示中文;考试列表页仍显示英文。多角色(admin/teacher/parent/student)无法获得一致的语言体验。
|
||
- 国际化交付阻塞,无法满足 K12 学校多语言场景。
|
||
|
||
### 2.2 类型安全问题
|
||
|
||
**问题**:多处使用 `as any` / `as unknown` 断言,违反 TypeScript 严格规范。
|
||
|
||
**出现位置**:
|
||
- `src/modules/exams/components/exam-form.tsx:38`:`resolver: zodResolver(formSchema) as any`(注释 `eslint-disable`)。
|
||
- `src/modules/exams/components/exam-form.tsx:163,168`:`form.handleSubmit(onSubmit as any)`(两处 `eslint-disable`)。
|
||
- `src/modules/exams/components/exam-actions.tsx:60`:`questionById.set(q.id, q as unknown as Question)`。
|
||
- `src/modules/exams/components/exam-actions.tsx:63`:`const hydrate = (nodes: any[]): ExamNode[]`(`eslint-disable`)。
|
||
- `src/modules/homework/components/homework-take-view.tsx:346-347`:`(prev[q.questionId]?.answer as string[])`。
|
||
- `src/modules/homework/components/homework-take-view.tsx:468`:`(answersByQuestionId[q.questionId]?.answer as unknown[])`。
|
||
- `src/modules/homework/components/homework-grading-view.tsx:199`:`(ans.questionContent.options as ChoiceOption[])`。
|
||
- `src/modules/homework/data-access.ts:484`:`structure: assignment.structure as unknown`。
|
||
|
||
**问题原因**:zodResolver 与 react-hook-form 类型不兼容时偷懒用 `as any`;题目内容为 `unknown` 时未做类型守卫直接断言。
|
||
|
||
**违反规则**:项目规则"禁止 `any`"、"禁止 `as` 断言(除非从 `unknown` 转换或测试中,需注释原因)"。
|
||
|
||
**直接后果**:类型系统形同虚设,运行时错误无法在编译期捕获;重构时易引入隐性 bug。
|
||
|
||
### 2.3 权限校验不完整
|
||
|
||
**问题**:`gradeHomeworkSubmissionAction` 未校验教师对该提交记录的访问权限。
|
||
|
||
**出现位置**:`src/modules/homework/actions.ts:249-292`。
|
||
|
||
**问题原因**:`gradeHomeworkSubmissionAction` 仅调用 `requirePermission(Permissions.HOMEWORK_GRADE)`,未校验当前教师是否为该作业的创建者、或该学生所在班级的任课教师。任意拥有 `HOMEWORK_GRADE` 权限的教师均可批改任意学生的任意作业。
|
||
|
||
**违反规则**:项目规则"所有敏感数据查询必须在 data-access 层结合当前用户权限过滤,Server Action 二次校验"。
|
||
|
||
**直接后果**:横向越权风险——教师 A 可批改教师 B 的学生作业,篡改成绩。
|
||
|
||
### 2.4 错误边界与加载状态缺失
|
||
|
||
**问题**:考试和作业模块的页面缺少 React Error Boundary 和 Suspense 骨架屏。
|
||
|
||
**出现位置**:
|
||
- `src/app/(dashboard)/teacher/exams/[id]/build/page.tsx`:无 `error.tsx`、无 `loading.tsx`,`getExamById` 失败时整页 500。
|
||
- `src/app/(dashboard)/teacher/exams/[id]/proctoring/page.tsx`:无 `error.tsx`、无 `loading.tsx`。
|
||
- `src/app/(dashboard)/teacher/homework/assignments/[id]/page.tsx`:无 `error.tsx`、无 `loading.tsx`。
|
||
- `src/app/(dashboard)/teacher/homework/assignments/[id]/submissions/page.tsx`:无 `error.tsx`、无 `loading.tsx`。
|
||
- `src/app/(dashboard)/teacher/homework/assignments/create/page.tsx`:无 `loading.tsx`。
|
||
- `src/app/(dashboard)/student/learning/assignments/[assignmentId]/page.tsx`:有 `loading.tsx` 但无 `error.tsx`。
|
||
- 仅 `exams/all` 和 `exams/create` 有 `loading.tsx`。
|
||
|
||
**问题原因**:页面开发时未配套错误边界;Suspense 仅在 `exams/all` 使用。
|
||
|
||
**违反规则**:项目规则"每个独立的数据区块必须用 React Error Boundary 包裹"、"异步数据使用 React Suspense + 骨架屏"、"明确处理空数据、无权限、网络异常等边界状态"。
|
||
|
||
**直接后果**:数据库连接抖动或单条记录缺失会导致整页崩溃,无法降级展示。
|
||
|
||
### 2.5 组件复用不足
|
||
|
||
**问题**:题目渲染逻辑在作答页、批改页、复习页三处重复实现。
|
||
|
||
**出现位置**:
|
||
- `src/modules/homework/components/homework-take-view.tsx:248-400`:渲染 `single_choice` / `multiple_choice` / `judgment` / `text` 四种题型。
|
||
- `src/modules/homework/components/homework-grading-view.tsx:155-328`:再次渲染同样四种题型(带正确答案高亮)。
|
||
- `src/modules/homework/components/student-homework-review-view.tsx`:第三次渲染同样四种题型(带批改反馈)。
|
||
- 三处都重复实现 `getQuestionText` / `getOptions` / `isRecord` 等工具函数。
|
||
|
||
**问题原因**:未抽象 `QuestionRenderer` / `QuestionAnswerInput` / `QuestionResultDisplay` 等复用组件。
|
||
|
||
**违反规则**:项目规则"最大化复用:识别四个角色共用的 UI 块和业务逻辑块,抽象为泛型组件和 hooks"、"组合优先:所有 UI 通过组件组合实现灵活性"。
|
||
|
||
**直接后果**:题型扩展(如填空、排序、拖拽)需改三处;样式不一致风险高;单测难以覆盖。
|
||
|
||
### 2.6 监考模块死代码
|
||
|
||
**问题**:`ExamModeConfig` 组件已实现但未集成到考试创建/编辑表单。
|
||
|
||
**出现位置**:`src/modules/proctoring/components/exam-mode-config.tsx`(230 行)从未被 import。
|
||
|
||
**问题原因**:架构图 §2.21 已标注"❌ P0:`exam-mode-config.tsx` 未集成到考试表单(死代码,监考功能无法启用)",但至今未修复。
|
||
|
||
**违反规则**:项目规则"如果架构图未覆盖该模块的任何部分,必须优先补全架构图再继续"——此处架构图已记录但代码未修复。
|
||
|
||
**直接后果**:监考功能(防作弊、限时、全屏强制)完全不可用;`proctoring` 模块的 `recordProctoringEventAction` 无前端触发路径。
|
||
|
||
### 2.7 文件行数超限
|
||
|
||
**问题**:`ai-pipeline.ts` 857 行,超过 800 行建议值。
|
||
|
||
**出现位置**:`src/modules/exams/ai-pipeline.ts`。
|
||
|
||
**问题原因**:混合了 AI 请求构造、响应解析、Zod 校验、题目归一化、结构生成 5 类职责。
|
||
|
||
**违反规则**:项目规则"Server Actions / Data Access 模块:建议 ≤ 800 行"、"超过建议行数时应考虑拆分"。
|
||
|
||
**直接后果**:维护困难;AI 供应商切换需改动整个文件。
|
||
|
||
### 2.8 可访问性缺陷
|
||
|
||
**问题**:交互元素缺少 ARIA 属性,颜色作为唯一信息载体。
|
||
|
||
**出现位置**:
|
||
- `src/modules/homework/components/homework-grading-view.tsx:156-158`:用 `border-l-emerald-500` / `border-l-red-500` 表示对错,无文本替代。
|
||
- `src/modules/exams/components/exam-columns.tsx:110-121`:难度仅用色块表示,`text-[10px]` 标签为英文缩写。
|
||
- `src/modules/homework/components/homework-take-view.tsx:471-486`:题目导航按钮 `aria-label` 为英文 `Jump to question ${i+1}`,未 i18n。
|
||
- 批改页 `Correct`/`Incorrect` 按钮仅靠颜色区分状态。
|
||
|
||
**违反规则**:项目规则"可访问性(a11y):语义化标签、ARIA 属性、键盘导航"。
|
||
|
||
**直接后果**:色盲教师无法区分对错;屏幕阅读器用户体验差。
|
||
|
||
### 2.9 性能问题
|
||
|
||
**问题**:`getHomeworkSubmissionDetails` 为获取前后导航 ID 拉取全部提交记录。
|
||
|
||
**出现位置**:`src/modules/homework/data-access.ts:540-548`。
|
||
|
||
```typescript
|
||
const allSubmissions = await db.query.homeworkSubmissions.findMany({
|
||
where: eq(homeworkSubmissions.assignmentId, submission.assignmentId),
|
||
orderBy: [desc(homeworkSubmissions.updatedAt)],
|
||
columns: { id: true },
|
||
})
|
||
const currentIndex = allSubmissions.findIndex((s) => s.id === submissionId)
|
||
```
|
||
|
||
**问题原因**:未用 SQL 窗口函数或 `OFFSET`/`LIMIT` 获取相邻记录。
|
||
|
||
**违反规则**:项目规则"性能:优先使用 React Server Components 获取初始数据"——此处为 data-access 层低效查询。
|
||
|
||
**直接后果**:班级 50 人作业批改时,每次打开详情都拉取 50 条记录的 ID。
|
||
|
||
### 2.10 答案保存无防抖与离线支持
|
||
|
||
**问题**:学生作答时每题手动点击"Save Answer",无自动保存、无离线缓存。
|
||
|
||
**出现位置**:`src/modules/homework/components/homework-take-view.tsx:139-151`。
|
||
|
||
**问题原因**:未实现自动保存(防抖)和 `localStorage` 离线缓存。
|
||
|
||
**违反规则**:项目规则"明确处理网络异常等边界状态"。
|
||
|
||
**直接后果**:网络抖动时学生答案丢失;刷新页面(尽管有 `beforeunload` 警告)仍可能丢失未保存答案。
|
||
|
||
---
|
||
|
||
## 三、行业差距对比
|
||
|
||
### 3.1 与主流 K12 考试系统对比
|
||
|
||
| 功能 | 行业主流(如智学网、猿题库、Google Classroom) | 当前实现 | 差距影响 |
|
||
|------|------|------|------|
|
||
| 限时考试 | 支持设定考试时长,到时自动提交 | `ExamModeConfig` 已实现但未集成 | 教师无法组织课堂限时测验 |
|
||
| 题目乱序 | 每位学生题目顺序随机 | `ExamModeConfig` 已实现但未集成 | 防作弊能力缺失 |
|
||
| 监考模式 | 切屏检测、强制全屏、AI 行为分析 | `proctoring` 模块后端已实现,前端无入口 | 远程考试无法防作弊 |
|
||
| 自动批改 | 选择题/判断题提交后即时出分 | `homework-grading-view` 有 `applyAutoGrades` 但仅在打开批改页时计算,不回写 | 学生提交后看不到即时成绩 |
|
||
| 批量批改 | 列表页勾选多份提交批量打分 | 仅支持逐份批改 | 50 人班级批改效率低 |
|
||
| 评分量规(Rubric) | 文本题按维度打分 | 仅支持单分数 | 主观题批改粗放 |
|
||
| 考试分析 | 题目难度、区分度、知识点掌握度 | `homework/stats-service` 有作业分析,考试无分析 | 考试后无法复盘教学质量 |
|
||
| 学生答案草稿 | 自动保存 + 离线缓存 | 手动保存,无离线 | 弱网环境答案易丢 |
|
||
| 部分分自动判分 | 多选题漏选得部分分 | 全对才得分 | 评分不够精细 |
|
||
| 重考与补考 | 支持重考流程与成绩记录 | `maxAttempts` 已支持但无补考入口 | 补考场景需手动创建新作业 |
|
||
|
||
### 3.2 多角色体验差距
|
||
|
||
| 角色 | 行业主流体验 | 当前实现 | 差距 |
|
||
|------|------|------|------|
|
||
| **教师** | 一站式工作台:创建→发布→监考→批改→分析 | 分散在 `/teacher/exams/*` 和 `/teacher/homework/*` 两个独立菜单 | 考试到作业的链路割裂 |
|
||
| **学生** | 统一"待办"入口:作业+考试+复习 | 仅 `/student/learning/assignments`,考试作答也走作业流程 | 考试与作业概念混淆 |
|
||
| **家长** | 查看孩子考试详情、错题本、趋势 | `parent` 模块仅有作业摘要,无考试详情 | 家长无法了解考试表现 |
|
||
| **管理员** | 全校考试统计、年级对比、教师工作量 | 无管理员视角的考试仪表盘 | 管理层无法宏观决策 |
|
||
|
||
### 3.3 UI/UX 差距
|
||
|
||
- **空状态**:`exams/all` 有空状态,但 `homework/assignments/[id]/submissions` 无空状态(无提交时显示空表格)。
|
||
- **加载骨架屏**:仅 `exams/all`、`exams/create`、`student/learning/assignments` 有;其余页面白屏加载。
|
||
- **错误降级**:全模块无 `error.tsx`,任何数据加载失败均导致整页 500。
|
||
- **移动端适配**:`homework-take-view` 和 `homework-grading-view` 使用 `lg:grid-cols-12`,移动端可正常显示但未优化触控体验(题目导航按钮过小)。
|
||
|
||
---
|
||
|
||
## 四、改进优先级建议
|
||
|
||
### P0(紧急,影响安全与核心功能)
|
||
|
||
1. **补全 `gradeHomeworkSubmissionAction` 权限校验**:在 data-access 层新增 `getHomeworkSubmissionForGrading(submissionId, teacherId, dataScope)`,校验教师对该作业的访问权(创建者或班级任课教师)。Server Action 二次校验。
|
||
2. **i18n 全量回填**:新建 `messages/zh-CN/exam-homework.json` 和 `messages/en/exam-homework.json`,提取该模块所有硬编码文本为翻译键;在 `i18n/request.ts` 注册新命名空间;组件改用 `useTranslations('examHomework')`。
|
||
3. **集成 `ExamModeConfig` 到考试表单**:在 `exam-form.tsx` 中引入 `ExamModeConfig`,将 `examMode` / `durationMinutes` / `shuffleQuestions` / `antiCheatEnabled` 等字段纳入 `ExamFormValues`,持久化到 `exams` 表;`proctoring` 模块读取这些配置启用监考。
|
||
|
||
### P1(重要,影响可维护性与体验)
|
||
|
||
4. **添加 Error Boundary 与 loading.tsx**:为 `exams/[id]/build`、`exams/[id]/proctoring`、`homework/assignments/[id]`、`homework/assignments/[id]/submissions`、`homework/assignments/create`、`student/learning/assignments/[assignmentId]` 配套 `error.tsx` + `loading.tsx`。
|
||
5. **抽象题目渲染组件**:新建 `homework/components/question-renderer.tsx`,导出 `QuestionRenderer`(只读展示)、`QuestionAnswerInput`(作答交互)、`QuestionGradingPanel`(批改面板),三处页面改用组合模式复用。
|
||
6. **清理类型断言**:`exam-form.tsx` 的 `as any` 改为正确泛型;`exam-actions.tsx` 的 `hydrate` 函数用类型守卫替代 `any[]`;`homework-take-view.tsx` / `homework-grading-view.tsx` 的 `as` 断言改为类型守卫。
|
||
7. **拆分 `ai-pipeline.ts`**:按职责拆为 `ai-pipeline/request.ts`(请求构造)、`ai-pipeline/parse.ts`(响应解析+校验)、`ai-pipeline/structure.ts`(结构生成),原文件作为 re-export 入口。
|
||
8. **优化 `getHomeworkSubmissionDetails` 相邻记录查询**:用 `LEAD`/`LAG` 窗口函数或两次 `LIMIT 1` 查询替代全量拉取。
|
||
|
||
### P2(增强,提升体验与可扩展性)
|
||
|
||
9. **学生答案自动保存 + 离线缓存**:`homework-take-view` 增加 `useDebouncedAutoSave` hook,答案变更后 3 秒自动保存;同时写入 `localStorage`,断网时队列化重试。
|
||
10. **考试分析仪表盘**:新增 `exams/components/exam-analytics-dashboard.tsx`,复用 `homework/stats-service` 模式,展示题目难度、区分度、知识点掌握度。
|
||
11. **批量批改 UI**:`homework/assignments/[id]/submissions` 增加多选 + 批量打分(全对/全错/自定义分数)。
|
||
12. **a11y 修复**:颜色指示器增加文本替代;题目导航按钮 `aria-label` i18n;批改页 `Correct`/`Incorrect` 按钮增加 `aria-pressed`。
|
||
13. **配置驱动的角色渲染**:定义 `ExamHomeworkRoleConfig` 接口,各角色模块仅组合复用单元,新增角色只改配置。
|
||
|
||
---
|
||
|
||
## 五、架构图同步说明
|
||
|
||
本次审计发现架构图需补充以下信息:
|
||
|
||
### 5.1 需补充的节点
|
||
|
||
1. **`004_architecture_impact_map.md` §2.2 exams 模块**:
|
||
- 文件清单补充 `components/assembly/exam-paper-preview.tsx`、`question-bank-list.tsx`、`selected-question-list.tsx`、`structure-editor.tsx` 四个组件的行数与职责。
|
||
- 已知问题补充:`exam-mode-config.tsx` 未集成(与 proctoring 模块联动缺失)。
|
||
|
||
2. **`004_architecture_impact_map.md` §2.3 homework 模块**:
|
||
- 文件清单补充 `components/homework-assignment-exam-content-card.tsx`、`homework-assignment-exam-error-explorer.tsx`、`homework-assignment-exam-error-explorer-lazy.tsx`、`homework-assignment-exam-preview-pane.tsx`、`homework-assignment-question-error-detail-panel.tsx`、`homework-assignment-question-error-overview-card.tsx`、`student-homework-review-view.tsx` 七个组件的行数与职责。
|
||
- 已知问题补充:`gradeHomeworkSubmissionAction` 权限校验不完整(P0 安全问题)。
|
||
|
||
3. **`004_architecture_impact_map.md` §2.21 proctoring 模块**:
|
||
- 已知问题补充:`ExamModeConfig` 未集成的根因是 `ExamFormValues` 未包含 `examMode` 字段,需扩展表单 schema。
|
||
|
||
4. **`005_architecture_data.json`**:
|
||
- `modules.exams.exports` 补充 `ExamModeConfig` 集成状态字段。
|
||
- `modules.homework.knownIssues` 新增 `gradeHomeworkPermissionGap` 节点。
|
||
- `dependencyMatrix` 补充 `proctoring → exams` 的 `examModeConfig` 依赖关系(当前仅记录 data-access 依赖,未记录 UI 集成依赖)。
|
||
|
||
### 5.2 无需修改的部分
|
||
|
||
- 三层架构依赖关系记录准确(`app → modules → shared`)。
|
||
- 跨模块 data-access 调用关系记录完整(exams ↔ homework ↔ proctoring)。
|
||
- 文件行数统计基本准确(`ai-pipeline.ts` 857 行已记录)。
|
||
|
||
---
|
||
|
||
## 六、重构方案设计(概要)
|
||
|
||
### 6.1 完全解耦
|
||
|
||
定义 `ExamHomeworkServicePort` 接口,抽象数据依赖:
|
||
|
||
```typescript
|
||
// modules/exam-homework/types/service-port.ts
|
||
export interface ExamHomeworkServicePort {
|
||
getExams(scope: DataScope): Promise<ExamListItem[]>
|
||
getExamById(id: string): Promise<ExamDetail | null>
|
||
getHomeworkAssignments(scope: DataScope): Promise<HomeworkAssignmentListItem[]>
|
||
getStudentHomeworkTakeData(assignmentId: string, studentId: string): Promise<StudentHomeworkTakeData | null>
|
||
// ... 其余数据访问方法
|
||
}
|
||
|
||
export interface ExamHomeworkPermissionPort {
|
||
canGradeSubmission(teacherId: string, submissionId: string): Promise<boolean>
|
||
canViewExam(userId: string, examId: string, scope: DataScope): Promise<boolean>
|
||
}
|
||
```
|
||
|
||
通过 `ExamHomeworkServiceProvider`(React Context)注入实现,模块内部组件绝不 import 其他业务模块的 actions。
|
||
|
||
### 6.2 组合优先
|
||
|
||
抽象题目渲染组件:
|
||
|
||
```typescript
|
||
// modules/exam-homework/components/question-renderer.tsx
|
||
export function QuestionRenderer({
|
||
question,
|
||
mode,
|
||
children,
|
||
}: {
|
||
question: QuestionData
|
||
mode: 'take' | 'grade' | 'review'
|
||
children?: React.ReactNode
|
||
}) { ... }
|
||
|
||
export function QuestionAnswerInput({ question, value, onChange, disabled }: TakeProps) { ... }
|
||
export function QuestionGradingPanel({ answer, onScoreChange, onFeedbackChange }: GradeProps) { ... }
|
||
```
|
||
|
||
### 6.3 国际化就绪
|
||
|
||
翻译文件结构示例:
|
||
|
||
```json
|
||
// messages/zh-CN/exam-homework.json
|
||
{
|
||
"exam": {
|
||
"list": { "title": "考试列表", "create": "创建考试", "empty": "暂无考试" },
|
||
"form": { "title": "考试标题", "subject": "科目", "grade": "年级", "difficulty": "难度" },
|
||
"status": { "draft": "草稿", "published": "已发布", "archived": "已归档" },
|
||
"actions": { "preview": "预览", "edit": "编辑", "build": "组卷", "publish": "发布", "duplicate": "复制", "delete": "删除" }
|
||
},
|
||
"homework": {
|
||
"list": { "title": "作业列表", "create": "创建作业", "submissionRate": "提交率", "averageScore": "平均分", "overdue": "逾期" },
|
||
"take": { "start": "开始作答", "submit": "提交作业", "saveAnswer": "保存答案", "confirmSubmit": "确认提交", "unansweredWarning": "您有 {{count}} 道题未作答" },
|
||
"grade": { "summary": "批改摘要", "totalScore": "总分", "correct": "正确", "incorrect": "错误", "partial": "部分正确", "submitGrades": "提交成绩" }
|
||
},
|
||
"proctoring": {
|
||
"mode": { "homework": "作业模式", "timed": "限时模式", "proctored": "监考模式" },
|
||
"config": { "duration": "考试时长(分钟)", "shuffleQuestions": "题目乱序", "antiCheat": "启用防作弊监控" }
|
||
}
|
||
}
|
||
```
|
||
|
||
### 6.4 错误与边界处理
|
||
|
||
- 每个页面配套 `error.tsx`(React Error Boundary)。
|
||
- 每个页面配套 `loading.tsx`(骨架屏)。
|
||
- `ExamHomeworkErrorBoundary` 组件区分 `NetworkError` / `PermissionDenied` / `NotFound` 三种状态。
|
||
|
||
### 6.5 可测试性
|
||
|
||
- 纯逻辑函数(`applyAutoGrades` / `computeIsCorrect` / `normalizeStructure`)已与 UI 分离,补充单测。
|
||
- 数据获取逻辑通过 `ServicePort` 接口可 mock。
|
||
- 新增 `__tests__/exam-homework-service.test.ts` 覆盖权限校验与数据流转。
|
||
|
||
### 6.6 可扩展性
|
||
|
||
配置驱动设计:
|
||
|
||
```typescript
|
||
// modules/exam-homework/config/role-config.ts
|
||
export const EXAM_HOMEWORK_ROLE_CONFIG: Record<Role, ExamHomeworkRoleConfig> = {
|
||
admin: { widgets: ['stats', 'all-exams', 'all-homework'], canGrade: false },
|
||
teacher: { widgets: ['my-exams', 'my-homework', 'grading-queue'], canGrade: true },
|
||
parent: { widgets: ['child-exam-results', 'child-homework-summary'], canGrade: false },
|
||
student: { widgets: ['pending-exams', 'pending-homework', 'results'], canGrade: false },
|
||
}
|
||
```
|
||
|
||
### 6.7 企业级补充
|
||
|
||
- **a11y**:颜色指示器增加 `sr-only` 文本;`aria-pressed` / `aria-label` 全覆盖。
|
||
- **性能**:RSC 获取初始数据(已实现);客户端组件仅负责交互(已实现);流式渲染(`Suspense` 已部分使用)。
|
||
- **安全**:data-access 层结合 `dataScope` 过滤(已实现);Server Action 二次校验(P0 待补全)。
|
||
- **监控**:预留 `trackExamEvent(eventName, payload)` 接口,关键操作(创建/提交/批改)埋点。
|