26 KiB
grades(成绩)模块审计报告
审计日期:2026-06-25 审计范围:
src/modules/grades/**+src/app/(dashboard)/**/grades/**共 50 个文件 架构图定位:004_architecture_impact_map.md§ 2.6 /005_architecture_data.jsonmodules.grades总体结论:该模块在架构图中被标记为"标杆模块(拆分范例)",三层架构、跨模块 data-access 通信、Server Action 权限校验、纯函数抽取、a11y 与 i18n 在主要文件中已落实。但仍存在 3 处 P0 i18n 严重缺陷、2 个文件超行数上限、多处英文错误消息未 i18n、若干as断言与缺返回值类型等问题,需按本报告优先级修复。
一、现有实现概要
1.1 文件分布
grades 模块共 50 个文件,按职责划分为四层:
| 层 | 文件数 | 路径 | 职责 |
|---|---|---|---|
| 类型/校验 | 2 | modules/grades/types.ts、schema.ts |
类型定义 + Zod 输入校验 |
| 数据访问 | 5 | data-access.ts、data-access-analytics.ts、data-access-ranking.ts、export.ts、stats-service.ts |
DB I/O + Excel 导出 + 统计纯函数 |
| Server Actions | 2 | actions.ts、actions-analytics.ts |
编排层(权限校验 → Zod → data-access → 通知 → revalidate) |
| Lib 工具 | 4 | lib/grade-utils.ts、scope-filter.ts、scope-check.ts、type-guards.ts |
纯工具函数 + 行级权限过滤 + 类型守卫 |
| 组件 | 19 | modules/grades/components/** |
RSC + 客户端组件混合 |
| 页面 | 18 | app/(dashboard)/**/grades/** |
四种角色页面 + loading/error |
1.2 主要数据流
teacher/grades/page.tsx
└─▶ requirePermission(GRADE_RECORD_READ)
└─▶ grades/data-access.getGradeRecords(scope, currentUserId, limit, offset)
└─▶ lib/scope-filter.buildScopeClassFilter → 行级过滤
└─▶ db.query.gradeRecords (DB 层分页)
└─▶ <GradeRecordList> + <GradeFilters> + <ExportButton>
teacher/grades/entry/page.tsx
└─▶ requirePermission(GRADE_RECORD_MANAGE)
└─▶ <BatchGradeEntryByExam>
└─▶ exams/data-access.getExamsForGradeEntry
└─▶ actions.batchCreateGradeRecordsByExamAction
└─▶ 单事务写入 grade_records + grade_record_answers
└─▶ 投影到 exam_submissions(status=graded) + submission_answers
└─▶ 并行:diagnostic.updateMasteryFromExamScore + error-book.collectFromExamSubmission
└─▶ notifyGradeEntered(批量通知学生 + 家长)
parent/grades/page.tsx
└─▶ requirePermission(GRADE_RECORD_READ)
└─▶ Promise.allSettled(为每个子女并行查询)
└─▶ grades/data-access.getStudentGradeSummary
└─▶ grades/data-access-analytics.getClassAverageTrend
└─▶ <StudentGradeSummary> + <GradeTrendCard> + <ParentExportButton>
1.3 架构图完整性核对
经核对 004_architecture_impact_map.md § 2.6 与 005_architecture_data.json modules.grades:
- 已记录且准确:
exports.dataAccess(15+ 函数)、exports.actions(17 个)、exports.types(7 类)、exports.lib(4 函数)、exports.statsService(8 纯函数)、exports.export(3 函数)、exports.components(WidgetBoundary/SchoolWideSummaryCard/ScoreCell)、dependencies(classes/school/users/exams/error-book/diagnostic/notifications/parent)、knownIssues(已修复 28 项)。 - 架构图遗漏:
components/widget-boundary.tsx在文件清单中标注为 136 行,但未在exports.components中列出(仅在 P1-5 修复记录中提及)。lib/scope-check.ts的assertClassInScope函数未在exports.lib节点中列出(仅在 v4-P2-6 修复记录中提及)。parent/grades/page.tsx调用的getClassAverageTrenddata-access 函数未在架构图exports.dataAccess中记录。
1.4 标杆特性
该模块作为项目标杆,已落实的实践:
- ✅ data-access 按职责拆分为 3 个文件(analytics/ranking/主)
- ✅ Server Actions 全部
requirePermission()+ Zod 校验 - ✅ 统计逻辑抽取为
stats-service.ts纯函数(8 个),可独立测试 - ✅ 行级权限过滤
buildScopeClassFilter(scope, currentUserId?) - ✅ DB 层分页(
PaginatedGradeRecords)而非内存分页 - ✅ 事务原子性(
db.transaction) - ✅ 跨模块全部通过 data-access 通信,无直查他模块表
- ✅ 类型守卫(
isGradeType/isSemester/isDistributionTooltipPayload)替代as断言 - ✅
handleActionError统一错误处理 +safeActionCall包装器 - ✅ a11y:4 图表
role="img"+aria-label、2 表格<caption>、色盲友好双重编码 - ✅ RSC 优先 + 客户端组件最小化
二、现存问题与原因分析
2.1 [P0] i18n 严重缺失 — 3 个 error.tsx 硬编码中文
| 文件 | 行号 | 硬编码文本 |
|---|---|---|
| parent/grades/error.tsx | 16-20 | "子女成绩页面加载失败" / "抱歉,页面加载时发生了意外错误..." / "重试" |
| admin/school/grades/insights/error.tsx | 17-21 | "成绩洞察页面加载失败" / "抱歉..." / "重试" |
| admin/school/grades/error.tsx | 12-16 | "页面加载失败" / "抱歉..." / "重试" |
- 违反规则:项目规则"所有用户可见文本必须适配 i18n(next-intl),提取翻译键"。
- 原因:这三个 error.tsx 与
teacher/grades/error.tsx(已 i18n)同期创建,但遗漏未接入useTranslations。 - 直接后果:非中文用户在页面出错时看到中文错误提示,国际化体验中断;与 teacher/grades/error.tsx 的良好实践形成明显不一致。
2.2 [P0] error.tsx 函数缺返回值类型标注
上述 3 个 error.tsx + student/grades/error.tsx + 所有 loading.tsx(共 7 个文件)的函数均未显式标注 : JSX.Element 返回值类型。
- 违反规则:项目规则"TypeScript 严格模式:函数返回值必须显式标注,特别是
Promise<T>"。 - 原因:loading/error 文件通常由脚手架生成,未补类型标注。
- 直接后果:tsc 严格模式下可能漏检类型错误;代码可读性下降。
2.3 [P1] actions.ts 超行数上限(856 行)
actions.ts 当前 856 行,超过 Server Actions 800 行建议上限 56 行。
- 违反规则:项目规则"Server Actions / Data Access 模块:建议 ≤ 800 行"。
- 原因:模块职责持续扩张(草稿 CRUD、按试卷录入、撤销、批量删除、通知),所有逻辑集中在单文件。
- 直接后果:接近 1000 行硬上限,后续新增 Action 将突破硬限;可读性、code review 成本上升。
2.4 [P1] data-access.ts 接近行数上限(816 行)
data-access.ts 当前 816 行,超过 800 行建议上限 16 行。
- 违反规则:同上。
- 原因:草稿 CRUD(
saveGradeDraft/getGradeDraft/deleteGradeDraft)、按试卷录入(batchCreateGradeRecordsByExam)混入主文件。 - 直接后果:与 analytics/ranking 已拆分形成不一致;新增数据访问函数将很快突破硬限。
2.5 [P1] actions.ts 多处英文错误消息未 i18n
| 行号 | 硬编码英文 |
|---|---|
| 148 | "Invalid form data" |
| 180 | "Grade record created" |
| 253 | "Failed to delete grade record" |
| 394-399 | "No records to undo" / "Cannot undo more than 500 records at once" |
| 483-487 | "No records to delete" / "Cannot delete more than 500 records at once" |
| 584-592 | "Can only view your own grades" / "Can only view your children's grades" |
| 654-669 | "Can only view your own grade record" / "Can only view your children's grade records" |
- 违反规则:项目规则"所有用户可见文本必须适配 i18n"。
- 原因:这些错误消息通过
ActionState.error返回前端展示,早期未统一接入翻译键。 - 直接后果:非中文用户看到英文错误提示。
2.6 [P1] lib/scope-check.ts 返回消息未 i18n
scope-check.ts 第 24/29/31 行返回 "You can only access classes you teach" 等英文,这些消息会通过 Action 层直接返回用户。
- 违反规则:同上。
- 原因:
assertClassInScope是同步函数,无法调用getTranslations(异步),因此返回原始错误消息交由 Action 层包装。 - 直接后果:Action 层目前未对返回消息做翻译包装,直接透传给用户。
2.7 [P1] actions-analytics.ts scope 校验消息未 i18n
actions-analytics.ts 第 176/183 行 "Can only view your own ranking trend" / "Can only view your children's ranking trend"。
- 同 2.5 原因与后果。
2.8 [P1] batch-grade-entry.tsx 超组件行数上限(604 行)
batch-grade-entry.tsx 604 行,超过组件 500 行建议上限 104 行(复杂表单可放宽至 800,但仍建议拆分)。
- 违反规则:项目规则"React 组件:建议 ≤ 500 行(复杂表单/大型表格可放宽至 800)"。
- 原因:Excel 式表格 + 试卷/班级选择器 + 统计栏 + 撤销机制 + AlertDialog 全部集中在单文件。
- 直接后果:可读性下降;子组件无法独立复用与测试;状态管理复杂度高,易引入 bug。
2.9 [P1] batch-grade-entry.tsx 第 341 行 as 断言无类型守卫
JSON.parse(raw) as { ids: string[]; timestamp: number }
- 违反规则:项目规则"禁止
as断言(除非从unknown转换或测试中,需注释原因)"。 - 原因:sessionStorage 撤销数据反序列化未做类型守卫。
- 直接后果:数据被篡改时可能运行时报错;类型安全缺失。
2.10 [P1] parent/grades/page.tsx 第 63 行 as 断言
summary as NonNullable<typeof r.value.summary>
- 违反规则:同 2.9。
- 原因:虽有前置
filter(r => r.value.summary)保证,但严格违反"禁止 as 断言"规则。 - 直接后果:类型系统对运行时假设依赖,filter 逻辑变更时可能失效。
2.11 [P2] student-grade-summary.tsx / grade-record-list.tsx 硬编码 "S" 前缀
两文件均使用 <TableCell>S{r.semester}</TableCell> 硬编码 "S1"/"S2" 前缀。
- 违反规则:i18n 规则。
- 原因:学期显示格式未抽象为翻译键。
- 直接后果:非英文/中文语境下学期标签不符合本地化习惯。
2.12 [P2] 多个组件函数缺返回值类型标注
| 文件 | 函数 |
|---|---|
grade-filters.tsx |
GradeFilters |
grade-query-filters.tsx |
GradeQueryFilters |
export-button.tsx |
handleExport |
grade-record-form.tsx |
handleSubmit |
| 所有 loading.tsx(7 个) | Loading |
- 违反规则:函数返回值必须显式标注。
- 原因:脚手架/早期代码遗漏。
- 直接后果:类型推导依赖,严格模式潜在漏检。
2.13 [P2] data-access.ts updateGradeRecord 类型安全性较弱
第 407 行使用 Record<string, unknown> 累积更新字段。
- 违反规则:TypeScript 严格模式精神(虽未直接违反禁止 any)。
- 原因:Drizzle 动态更新字段累积时类型推导困难。
- 直接后果:可能写入非法字段名;类型安全缺失。
2.14 [P2] getStudentGradeSummary 内部调用 getClassRanking 形成 data-access 层内部耦合
data-access.ts 第 564 行 getStudentGradeSummary 内部调用 getClassRanking,形成 data-access 层内部依赖。
- 原因:学生成绩摘要需要排名信息,直接复用排名查询。
- 直接后果:语义上
getStudentGradeSummary不应依赖getClassRanking;两者缓存参数不完全一致,可能导致重复查询;测试时需 mock 排名逻辑。
2.15 [P2] 组件复用抽象不足
| 现状 | 建议 |
|---|---|
GradeFilters(student,nuqs) 与 GradeQueryFilters(teacher,URLSearchParams) 两个独立过滤器 |
抽象为统一组件 + props 配置 |
ExportButton(teacher) 与 ParentExportButton(parent) |
可统一为带 variant prop 的单一组件 |
AnalyticsFilters(teacher RSC) 与 GradeInsightsFilters(school ChipNav) |
可考虑统一 |
- 违反规则:项目规则"识别四个角色共用的 UI 块和业务逻辑块,抽象为泛型组件和 hooks"。
- 原因:各角色过滤器实现差异较大(nuqs vs URLSearchParams vs ChipNav),未做抽象。
- 直接后果:新增角色需重写过滤器;维护成本上升。
2.16 [P2] 缺少 Error Boundary 包裹的独立数据区块
teacher/grades/page.tsx 列表与统计卡片未用 WidgetBoundary 包裹(仅 analytics 页面已包裹)。
- 违反规则:项目规则"每个独立的数据区块必须用 React Error Boundary 包裹"。
- 原因:主页面早期未应用 WidgetBoundary。
- 直接后果:单个数据区块失败会导致整个页面崩溃。
2.17 [P2] 撤销机制仅依赖 sessionStorage(5 分钟)
batch-grade-entry.tsx 撤销令牌存于 sessionStorage,刷新或跨设备后丢失;undoBatchCreateGradeRecordsAction 无时间窗口限制,理论上可撤销任意时间自己录入的记录。
- 违反规则:项目规则"错误与边界处理:明确处理空数据、无权限、网络异常等边界状态"(隐含)。
- 原因:撤销机制为 v4 新增,未考虑持久化与时效。
- 直接后果:误删风险;跨设备无法撤销。
2.18 [P2] 通知串行写入
notifyGradeEntered 对每个学生/家长串行调用 createNotification(actions.ts 第 88-117 行)。
- 违反规则:性能最佳实践。
- 原因:通知 data-access 未提供批量接口。
- 直接后果:批量录入 30+ 学生时通知耗时显著。
2.19 [P2] 图表 tooltip a11y 不足
图表组件有 role="img" + aria-label,但 tooltip(recharts tooltip)的 a11y 支持不足,屏幕阅读器无法读取悬停数据。
2.20 [P2] lib/type-guards.ts 第 8/12 行 as 断言
(GRADE_TYPES as readonly string[]).includes(v)
- 违反规则:禁止 as 断言(虽属类型收窄,但严格违规)。
- 改进:改用
Array.from(GRADE_TYPES).includes(v)或(GRADE_TYPES as readonly unknown[]).includes(v as unknown)后做类型守卫。
2.21 [P3] 架构图遗漏
components/widget-boundary.tsx未在exports.components节点列出lib/scope-check.ts的assertClassInScope未在exports.lib节点列出getClassAverageTrenddata-access 函数未记录
三、行业差距对比
对标 PowerSchool / Gradebook、Google Classroom、Canvas LMS、智学网、校宝在线等 K12 成绩管理产品,本模块差距如下:
3.1 缺失:成绩报告卡(Report Card)PDF 导出
- 行业实践:PowerSchool / Canvas 支持生成单生/班级 PDF 成绩报告卡,含学期汇总、排名、教师评语、签名区。
- 本模块现状:仅支持 Excel 导出(
exportGradeRecordsToExcel),无 PDF。 - 影响:家长会、学期末场景需手动排版打印,效率低。
3.2 缺失:成绩变化智能预警
- 行业实践:智学网提供"成绩大幅波动预警"(分数下降超过 10 分自动通知班主任 + 家长)。
- 本模块现状:无预警机制,仅静态统计。
- 影响:教师无法及时发现学习下滑学生,错过干预窗口。
3.3 缺失:知识点维度的成绩诊断
- 行业实践:Canvas LMS 的 MasteryGradebook 按知识点(competency)展示掌握度,而非仅按考试/科目。
- 本模块现状:成绩按科目/考试维度,虽
grade_record_answers已存储每题得分,但未提供知识点聚合视图(依赖 diagnostic 模块但未集成到 grades 页面)。 - 影响:教师无法在成绩页直接看到班级在哪个知识点薄弱。
3.4 缺失:学生纵向成长档案(Individual Growth Report)
- 行业实践:PowerSchool 提供单生多年纵向趋势图,含跨学期/跨年级对比。
- 本模块现状:
GradeTrendCard仅展示单学期/单科目趋势,无跨年级纵向档案。 - 影响:家长无法全面了解学生长期成长轨迹。
3.5 缺失:班级横向对比的统计显著性标注
- 行业实践:专业 BI 工具(如 Tableau 教育版)在班级对比时标注 p 值、效应量(Cohen's d)。
- 本模块现状:
ClassComparisonChart有"显著性分析区域"(v3-P3-5 新增),但仅基于极差经验规则,未使用统计检验。 - 影响:教师可能过度解读小样本差异。
3.6 缺失:成绩录入的草稿协同
- 行业实践:Google Classroom 支持多位教师协同录入,草稿云端同步,锁定机制防止冲突。
- 本模块现状:草稿仅单用户单设备(
grade_drafts表按 userId 唯一),无协同。 - 影响:多教师任教同一班级时无法分工录入。
3.7 缺失:成绩申诉与复核流程
- 行业实践:Canvas 支持学生对成绩提出申诉,教师复核后修改并留痕。
- 本模块现状:仅
updateGradeRecord,无申诉状态机与审计轨迹。 - 影响:成绩修改无留痕,合规性不足。
3.8 缺失:移动端适配深度优化
- 行业实践:校宝在线移动端针对家长提供"成绩单卡片"简化视图,大表格转为卡片堆叠。
- 本模块现状:
grade-record-list.tsx有overflow-x-auto,但未做卡片堆叠适配;图表在移动端可能过小。 - 影响:家长移动端查看体验一般。
3.9 缺失:成绩分布的隐私保护
- 行业实践:GDPR/FERPA 合规要求学生视角的分布图应隐藏其他学生身份,仅显示相对位置。
- 本模块现状:学生视角的
GradeDistributionChart显示全班分布,虽未暴露个人身份,但需明确"你在分布中的位置"标注。 - 影响:隐私合规风险(部分国家/地区)。
3.10 缺失:批量导入 Excel 成绩
- 行业实践:智学网支持下载模板 → 填写 → 上传 Excel 批量导入。
- 本模块现状:
batch-grade-entry.tsx支持下载 CSV 模板 + 粘贴录入,但无完整 Excel 上传解析。 - 影响:教师需手动粘贴,大批量场景效率低。
四、改进优先级建议
P0 — 立即修复(影响用户体验与合规)
| # | 问题 | 改进方向 |
|---|---|---|
| P0-1 | 3 个 error.tsx 硬编码中文(2.1) | 改为 useTranslations("grades") + 新增 error.* 翻译键(zh-CN/en 同步) |
| P0-2 | 7 个 loading/error.tsx 函数缺返回值类型(2.2) | 补全 : JSX.Element 返回值类型标注 |
P1 — 本周修复(架构规范与 i18n)
| # | 问题 | 改进方向 |
|---|---|---|
| P1-1 | actions.ts 超 800 行(2.3) |
拆分草稿相关 3 个 Action 到 actions-draft.ts;拆分通知逻辑到 lib/notify.ts |
| P1-2 | data-access.ts 超 800 行(2.4) |
拆分草稿 CRUD 到 data-access-drafts.ts;拆分按试卷录入到 data-access-exam-entry.ts |
| P1-3 | actions.ts 多处英文错误消息未 i18n(2.5) |
新增 action.error.* 翻译键,所有错误消息改用 t("action.error.*") |
| P1-4 | lib/scope-check.ts 返回消息未 i18n(2.6) |
改为返回错误码枚举,由 Action 层翻译;或返回 null + Action 层自行抛错 |
| P1-5 | actions-analytics.ts scope 消息未 i18n(2.7) |
同 P1-3 |
| P1-6 | batch-grade-entry.tsx 超 500 行(2.8) |
拆分为 BatchGradeEntryTable + BatchGradeEntryStats + BatchGradeEntryDialogs 子组件 |
| P1-7 | batch-grade-entry.tsx 第 341 行 as 断言(2.9) |
新增 isUndoData 类型守卫函数 |
| P1-8 | parent/grades/page.tsx 第 63 行 as 断言(2.10) |
改用类型守卫 isSummaryFulfilled 或非空检查 |
| P1-9 | teacher/grades/page.tsx 列表与统计未 WidgetBoundary 包裹(2.16) |
用 <WidgetBoundary> 包裹独立区块 |
P2 — 中期改进(质量与一致性)
| # | 问题 | 改进方向 |
|---|---|---|
| P2-1 | "S" 前缀硬编码(2.11) | 新增 semester.s1/semester.s2 翻译键 |
| P2-2 | 组件函数缺返回值类型(2.12) | 补全 : JSX.Element / : Promise<void> |
| P2-3 | updateGradeRecord 类型弱(2.13) |
改用 Partial<typeof gradeRecords.$inferInsert> |
| P2-4 | getStudentGradeSummary 内部耦合 getClassRanking(2.14) |
将排名计算抽取到 action 层或 stats-service |
| P2-5 | 过滤器组件未抽象(2.15) | 抽象 GradeFilterBar 统一组件 + props 配置 |
| P2-6 | 撤销机制 sessionStorage 依赖(2.17) | 服务端存储撤销令牌 + 24 小时时间窗口 |
| P2-7 | 通知串行写入(2.18) | 新增 notifications/data-access.bulkCreateNotification 批量接口 |
| P2-8 | 图表 tooltip a11y(2.19) | 添加 aria-describedby + 旁路数据表(sr-only) |
| P2-9 | lib/type-guards.ts as 断言(2.20) |
改用 Array.from(GRADE_TYPES).includes(v) |
P3 — 长期改进(行业对齐与企业级)
| # | 问题 | 改进方向 |
|---|---|---|
| P3-1 | 缺 PDF 成绩报告卡(3.1) | 新增 lib/report-card.ts,基于 @react-pdf/renderer 生成 PDF |
| P3-2 | 缺成绩变化预警(3.2) | 新增 stats-service.detectScoreAnomaly 纯函数 + 通知触发 |
| P3-3 | 缺知识点维度诊断集成(3.3) | 在 analytics 页面集成 diagnostic 模块的知识点掌握度视图 |
| P3-4 | 缺学生纵向档案(3.4) | 新增 getStudentGrowthArchive data-access + GrowthArchiveChart 组件 |
| P3-5 | 缺统计显著性标注(3.5) | 引入 simple-statistics 库计算 p 值 + Cohen's d |
| P3-6 | ✅ 缺协同录入(3.6) | grade_drafts 表新增 lockedBy/lockedAt/lockToken 字段 + classSubjectLockIdx 索引,支持锁机制(data-access-drafts.ts 5 个锁函数 + actions-lock.ts 4 个 Server Action + use-draft-lock Hook + DraftLockBanner 组件 + i18n) |
| P3-7 | ✅ 缺申诉流程(3.7) | 新增 grade_appeals 表(状态机枚举+4 个索引)+ data-access-appeals.ts(7 个函数)+ actions-appeal.ts(5 个 Server Action)+ schema.ts Zod 校验 + i18n |
| P3-8 | 缺移动端卡片堆叠(3.8) | 新增 GradeRecordCardList 移动端组件 |
| P3-9 | 缺隐私保护位置标注(3.9) | 学生视角分布图添加"你的位置"标注 |
| P3-10 | 缺 Excel 上传批量导入(3.10) | 集成 xlsx 库,新增 importGradesFromExcel Action |
| P3-11 | 单元测试覆盖(2.14 关联) | 为 stats-service.ts 纯函数 + lib/scope-check.ts 补充 vitest 测试 |
架构图同步
| # | 改进内容 | 架构图更新 |
|---|---|---|
| A-1 | P1-1 拆分 actions.ts | 004 文件清单 + 005 exports.actions 节点 |
| A-2 | P1-2 拆分 data-access.ts | 004 文件清单 + 005 exports.dataAccess 节点 |
| A-3 | P1-6 拆分 batch-grade-entry | 004 文件清单 + 005 exports.components 节点 |
| A-4 | 补全遗漏 | 004/005 补充 widget-boundary、scope-check.assertClassInScope、getClassAverageTrend |
五、架构图同步说明
5.1 本次审计发现的架构图遗漏(需补充)
components/widget-boundary.tsx— 在 004 § 2.6 文件清单中标注为 136 行,但未在exports.components节点中列出。需在 005modules.grades.exports.components数组中新增条目。lib/scope-check.ts的assertClassInScope— 仅在 v4-P2-6 修复记录中提及,未在exports.lib节点列出。需补充。getClassAverageTrenddata-access 函数 —parent/grades/page.tsx调用但架构图exports.dataAccess未记录。需确认其在data-access-analytics.ts中的位置并补充。
5.2 重构后需同步的节点
- 若执行 P1-1(拆分 actions.ts):004 文件清单更新为
actions.ts(barrel)+actions-draft.ts+actions-exam-entry.ts;005exports.actions按文件分组。 - 若执行 P1-2(拆分 data-access.ts):004 文件清单更新为
data-access.ts+data-access-drafts.ts+data-access-exam-entry.ts;005exports.dataAccess按文件分组。 - 若执行 P1-6(拆分 batch-grade-entry):004 文件清单新增 3 个子组件;005
exports.components补充。 - P0/P1 i18n 修复无需更新架构图(翻译键不影响模块导出结构)。
六、实施计划
本节为审计文档的实施清单,按优先级执行,每步完成后运行
npm run lint && npx tsc --noEmit验证零错误。
阶段 1:P0 立即修复(本次会话完成)
- P0-1: 3 个 error.tsx i18n(parent/grades、admin/school/grades、admin/school/grades/insights)
- P0-2: 7 个 loading/error.tsx 函数补全返回值类型
阶段 2:P1 本周修复(本次会话完成)
- P1-1: 拆分
actions.ts→actions-draft.ts+ 通知抽取到lib/notify.ts - P1-2: 拆分
data-access.ts→data-access-drafts.ts+data-access-exam-entry.ts - P1-3:
actions.ts错误消息 i18n(新增action.error.*翻译键) - P1-4:
lib/scope-check.ts改为返回错误码枚举 - P1-5:
actions-analytics.tsscope 消息 i18n - P1-6: 拆分
batch-grade-entry.tsx为子组件 - P1-7:
batch-grade-entry.tsx第 341 行 as 断言 → 类型守卫 - P1-8:
parent/grades/page.tsx第 63 行 as 断言 → 类型守卫 - P1-9:
teacher/grades/page.tsxWidgetBoundary 包裹
阶段 3:P2 中期改进(本次会话完成)
- P2-1: "S" 前缀 i18n
- P2-2: 组件函数返回值类型补全
- P2-3:
updateGradeRecord类型强化 - P2-4: 解耦
getStudentGradeSummary与getClassRanking - P2-5: 过滤器组件抽象(评估后决定是否实施)
- P2-6: 撤销机制服务端持久化(评估后决定)
- P2-7: 通知批量接口(依赖 notifications 模块改造,标注为后续)
- P2-8: 图表 tooltip a11y
- P2-9:
lib/type-guards.tsas 断言修复
阶段 4:P3 长期改进(记录待排期,不在本次会话实施)
- P3-1 ~ P3-10:行业差距对齐(需产品评估与设计)
- P3-11:单元测试覆盖
阶段 5:架构图同步(本次会话完成)
- A-1 ~ A-4:补充 004/005 遗漏节点 + 重构后节点更新