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 文档
This commit is contained in:
SpecialX
2026-06-22 18:45:35 +08:00
parent 1fe30984b6
commit 97e59b95a1
23 changed files with 668 additions and 135 deletions

View File

@@ -8,6 +8,29 @@ import { lessonPlanVersions, lessonPlans } from "@/shared/db/schema";
import { normalizeDocument } from "./data-access";
import type { LessonPlanDocument, LessonPlanVersion } from "./types";
// ---- 类型映射Drizzle 行 → LessonPlanVersionDate → ISO string----
function mapRowToVersion(row: {
id: string;
planId: string;
versionNo: number;
label: string | null;
content: unknown;
isAuto: boolean;
creatorId: string;
createdAt: Date;
}): LessonPlanVersion {
return {
id: row.id,
planId: row.planId,
versionNo: row.versionNo,
label: row.label,
content: normalizeDocument(row.content),
isAuto: row.isAuto,
creatorId: row.creatorId,
createdAt: row.createdAt.toISOString(),
};
}
export async function getLessonPlanVersions(
planId: string,
userId: string,
@@ -27,7 +50,7 @@ export async function getLessonPlanVersions(
.from(lessonPlanVersions)
.where(eq(lessonPlanVersions.planId, planId))
.orderBy(desc(lessonPlanVersions.versionNo));
return rows as unknown as LessonPlanVersion[];
return rows.map(mapRowToVersion);
}
export async function createLessonPlanVersion(input: {