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:
@@ -19,6 +19,7 @@ import "@xyflow/react/dist/style.css";
|
||||
import { useLessonPlanEditor } from "../hooks/use-lesson-plan-editor";
|
||||
import { LessonNode } from "./nodes/lesson-node";
|
||||
import { toRfNodes, toRfEdges } from "../lib/rf-mappers";
|
||||
import { getNodeColor } from "../lib/node-summary";
|
||||
import type { LessonPlanNode } from "../types";
|
||||
|
||||
const nodeTypes = { lesson: LessonNode };
|
||||
@@ -87,7 +88,7 @@ export function NodeEditor({}: Props) {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="w-full h-full relative">
|
||||
<div className="w-full h-full relative" role="application" aria-label={t("editor.canvasLabel")}>
|
||||
{doc.nodes.length === 0 && (
|
||||
<div className="absolute inset-0 flex items-center justify-center pointer-events-none z-10">
|
||||
<div className="text-center text-on-surface-variant">
|
||||
@@ -107,6 +108,12 @@ export function NodeEditor({}: Props) {
|
||||
onPaneClick={() => selectNode(null)}
|
||||
fitView
|
||||
fitViewOptions={{ padding: 0.2, maxZoom: 1.2 }}
|
||||
nodesFocusable
|
||||
nodesDraggable
|
||||
edgesFocusable
|
||||
elementsSelectable
|
||||
deleteKeyCode={["Backspace", "Delete"]}
|
||||
multiSelectionKeyCode={["Shift", "Meta", "Control"]}
|
||||
defaultEdgeOptions={{
|
||||
animated: true,
|
||||
style: { stroke: "#1976d2", strokeWidth: 2 },
|
||||
@@ -126,21 +133,7 @@ export function NodeEditor({}: Props) {
|
||||
nodeColor={(n) => {
|
||||
const nodeData = (n.data as { node?: LessonPlanNode }).node;
|
||||
if (!nodeData) return "#9e9e9e";
|
||||
const colors: Record<string, string> = {
|
||||
objective: "#4caf50",
|
||||
key_point: "#f44336",
|
||||
import: "#2196f3",
|
||||
new_teaching: "#9c27b0",
|
||||
consolidation: "#ff9800",
|
||||
summary: "#607d8b",
|
||||
homework: "#795548",
|
||||
blackboard: "#009688",
|
||||
text_study: "#3f51b5",
|
||||
exercise: "#e91e63",
|
||||
rich_text: "#9e9e9e",
|
||||
reflection: "#cddc39",
|
||||
};
|
||||
return colors[nodeData.type] ?? "#9e9e9e";
|
||||
return getNodeColor(nodeData.type);
|
||||
}}
|
||||
/>
|
||||
</ReactFlow>
|
||||
|
||||
Reference in New Issue
Block a user