Files
NextEdu/docs/architecture/audit/lesson-preparation-audit-report-v2.md
SpecialX 97e59b95a1 refactor(lesson-preparation): V2 审计深度修复 — Server Actions i18n + 错误码模式 + 类型断言清零 + a11y 深度修复 + Tracker 埋点接入
V2-1: 12 个 Server Action 通过 getTranslations 翻译错误消息;Service/DataAccess 层抛出错误码异常(PublishServiceError/LessonPlanDataError),Actions 层通过 PUBLISH_ERROR_KEY_MAP 翻译为 i18n 消息
V2-2: SYSTEM_TEMPLATES name/title 改为 i18n 键,createLessonPlan 接受 translateTitle 函数在服务端翻译后存储到 DB
V2-3: 8 处 as unknown as 断言替换为显式类型映射函数(mapRowToLessonPlan/mapRowToListItem/mapRowToTemplate/mapRowToVersion)+ 类型守卫(isLessonPlanStatus/isTemplateType/isTemplateScope)
V2-4: MiniMap nodeColor 复用 lib/node-summary.ts 的 getNodeColor
V2-5: a11y 深度修复 — lesson-plan-filters/exercise-block/inline-question-editor 的 select 添加 label htmlFor 关联;exercise-block 题目列表改为 ul/li;node-editor 画布添加 role=application + 键盘导航配置
V2-6: Tracker 埋点接入 — 新增 useLessonPlanTrackerSafe hook,在 create/save/publish/revert/duplicate/archive 6 处调用 tracker.track

同步更新架构图 004 和 005 文档
2026-06-22 18:45:35 +08:00

10 KiB
Raw Permalink Blame History

备课模块审计报告 V2第二轮深度检查

审查日期2026-06-22第二轮 审查范围:基于 V1 审计报告的修复成果,对全模块进行深度复查 前置状态V1 审计报告中的 P0-1/P0-2/P0-3/P1-2/P1-3/P1-4/P1-5/P1-6/P1-7/P1-8/P2-1部分/P2-4接口已完成 本次目的:识别 V1 修复中遗留的未完成项,继续全量完整完成


一、V1 修复成果确认

状态 证据
P0-1 跨模块直查 已完成 publish-service.ts 使用 addExamQuestions/getStudentIdsByClassIds 跨模块接口
P0-2 i18n 接入 ⚠️ 部分完成 消息文件、request.ts、组件 useTranslations 已接入;但 actions 错误消息、constants SYSTEM_TEMPLATES 仍硬编码
P0-3 DataScope 已完成 buildScopeCondition 按 scope 类型精确过滤
P1-1 类型安全 ⚠️ 部分完成 as never 已修复;但 8 处 as unknown as 断言未修复
P1-2 错误边界 已完成 LessonPlanErrorBoundary 包裹 NodeEditPanel
P1-3 骨架屏 已完成 4 个 Skeleton 组件已创建
P1-4 阻塞式 UI 已完成 alert/confirm/window.location.reload 全部替换
P1-5 多实例 已完成 LessonPlanProvider + Context 注入
P1-6 纯函数抽取 ⚠️ 部分完成 lib/ 三个文件已抽取;但 node-editor.tsx MiniMap nodeColor 仍内联颜色映射
P1-7 角色配置 已完成 4 个角色配置 + ROLE_CONFIGS 注册表
P1-8 Block 注册表 已完成 BLOCK_REGISTRY 配置驱动渲染
P2-1 a11y ⚠️ 部分完成 5 个对话框 role/aria-label 已添加;但 select 无 label、题目列表非 ul/li、画布无键盘导航
P2-4 监控埋点 ⚠️ 部分完成 LessonPlanTracker 接口已定义;但未在关键操作处调用

二、V2 新发现的问题

V2-1actions 错误消息仍硬编码中文P0-2 遗留)

位置 问题 违反规则
actions.ts:53 "获取课案列表失败" i18n 规范
actions.ts:66 "课案不存在或无权访问" 同上
actions.ts:71 "获取课案失败" 同上
actions.ts:102 "创建课案失败" 同上
actions.ts:125 "保存失败" 同上
actions.ts:152 "保存版本失败" 同上
actions.ts:171 "获取版本失败" 同上
actions.ts:190 "版本不存在或无权操作" 同上
actions.ts:196 "回退失败" 同上
actions.ts:212 "删除失败" 同上
actions.ts:228 "复制失败" 同上
actions.ts:245 "获取模板失败" 同上
actions.ts:267 "保存模板失败" 同上
actions.ts:282 "删除模板失败" 同上
actions-ai.ts:29 "AI 推荐失败,请检查 AI Provider 配置" 同上
actions-kp.ts:37 "加载知识点失败" 同上
actions-publish.ts:48 "发布失败" 同上
publish-service.ts:39,55,60,62,64,70,103,128 8 处 throw new Error("中文") 同上
data-access.ts:183,243 "模板不存在"/"课案不存在或无权访问" 同上
data-access-templates.ts:61 "课案不存在或无权访问" 同上

修复方案Server Actions 使用 getTranslations("lessonPreparation") 获取翻译publish-service/data-access 的 throw new Error 改为抛出错误码(如 LESSON_PLAN_NOT_FOUND),由 actions 层捕获并翻译。

V2-2constants.ts SYSTEM_TEMPLATES 仍硬编码中文P0-2 遗留)

位置 问题
constants.ts:46-106 SYSTEM_TEMPLATES 的 name/title/hint 字段硬编码中文("常规课"/"教学目标"/"明确本课的知识、能力、情感目标"等)

修复方案:将 SYSTEM_TEMPLATES 的 name/title/hint 改为 i18n 键(如 template.names.tpl_regular/blockType.objective/template.hints.tpl_regular.objective),在 buildInitialContent 调用时由 actions 层传入翻译后的标题。

V2-38 处 as unknown as 断言未修复P1-1 遗留)

位置 代码
data-access.ts:146 rows as unknown as LessonPlanListItem[]
data-access.ts:166 row as unknown as LessonPlan
data-access.ts:288 rows[0] as unknown as LessonPlanTemplate
data-access-versions.ts:30 rows as unknown as LessonPlanVersion[]
data-access-knowledge.ts:25 rows.filter(...) as unknown as LessonPlanListItem[]
data-access-knowledge.ts:43 同上
data-access-templates.ts:40 personalRows as unknown as LessonPlanTemplate[]
publish-service.ts:40 rows[0] as unknown as {...}

修复方案:使用 Drizzle 的 inferSelect 类型推导,或定义显式类型映射函数替代断言。

V2-4node-editor.tsx MiniMap nodeColor 仍内联颜色映射P1-6 遗留)

位置 问题
node-editor.tsx:126-144 MiniMap nodeColor 内联 colors 对象,未使用 lib/node-summary.ts 的 NODE_COLORS/getNodeColor

修复方案:改为 import { getNodeColor } from "../lib/node-summary" 并在 nodeColor 回调中调用。

V2-5a11y 遗留问题P2-1 遗留)

位置 问题 违反规则
lesson-plan-filters.tsx:40-51 2 个 <select><label> 关联 "语义化标签、ARIA 属性"
exercise-block.tsx:56-65 purpose <select><label> 同上
exercise-block.tsx:72-92 题目列表用 <div> 而非 <ul>/<li> 语义化标签
node-editor.tsx React Flow 画布无键盘导航支持Tab/方向键无法聚焦/移动节点) 键盘导航
inline-question-editor.tsx:83-95 type <select><label> 但未通过 htmlFor/id 关联 label 关联

修复方案:为所有 <select> 添加 id<label htmlFor>;题目列表改为 <ul>/<li>node-editor 添加键盘事件处理(方向键移动节点)。

V2-6LessonPlanTracker 未在关键操作处调用P2-4 遗留)

位置 问题
providers/lesson-plan-provider.tsx LessonPlanTracker 接口已定义,但全模块无 tracker.track() 调用

修复方案:在以下关键操作处调用 tracker

  • createLessonPlanActioncreate
  • updateLessonPlanActionsave
  • publishLessonPlanHomeworkActionpublish
  • revertLessonPlanVersionActionrevert
  • duplicateLessonPlanActionduplicate
  • deleteLessonPlanActionarchive

由于 actions 是 server-sidetracker 应在客户端组件中调用(如 lesson-plan-editor 的 handleManualSave、lesson-plan-card 的 handleArchive/handleDuplicate、publish-homework-dialog 的 handlePublish、version-history-drawer 的 handleRevert


三、V2 改进优先级

# 问题 优先级 改进方向
V2-1 actions 错误消息硬编码 P0 Server Actions 使用 getTranslationspublish-service/data-access 抛错误码
V2-2 SYSTEM_TEMPLATES 硬编码 P0 改为 i18n 键actions 层传入翻译后标题
V2-3 8 处 as unknown as 断言 P1 使用 Drizzle inferSelect 或显式映射函数
V2-4 MiniMap nodeColor 内联 P1 使用 lib/node-summary.getNodeColor
V2-5 a11y 遗留 P2 select 加 label、题目列表改 ul/li、画布键盘导航
V2-6 Tracker 未调用 P2 6 个关键操作处调用 tracker.track

四、架构图同步说明

本次 V2 修复完成后需同步更新:

  • docs/architecture/004_architecture_impact_map.md §2.27(标注 V2 修复完成)
  • docs/architecture/005_architecture_data.json modules.lesson_preparation.auditFixes新增 V2-1~V2-6