docs(architecture): V4 纸感重构架构图同步

004_architecture_impact_map.md: 更新 lesson-preparation 章节描述(V4 三栏布局)、新增 V4 纸感重构架构变更章节(H1/I1/J1/J2/J3/J4/J5 + 数据模型 v4)、更新文件清单(移除 9 个废弃文件,新增 paper-editor/structure-tree/detail-panel/interaction-block/anchor-migration-banner 等组件 + anchor-mark/export lib + history/expanded slices)。

005_architecture_data.json: 更新 lesson_preparation 节点——description 改为 V4 描述、dependencies 移除 @xyflow/react 改为 @tiptap/* 包、files 数组移除 9 个废弃文件并新增 V4 组件、auditFixes 新增 V4-PAPER-1~8 + V4-PAPER-DOC 条目。JSON 语法验证通过。
This commit is contained in:
SpecialX
2026-07-04 11:59:39 +08:00
parent 0e4eccec21
commit 5ca2a76e3a
2 changed files with 112 additions and 40 deletions

View File

@@ -2544,44 +2544,47 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
## 2.27 lesson-preparation备课模块
**职责**:教师备课,基于教材章节创建课案(**节点图编辑器 React Flow**),支持模板、版本管理、知识点标注、题目创建/拉取、作业发布。
**职责**:教师备课,基于教材章节创建课案(**V4 纸感重构:三栏布局 StructureTree + PaperEditor + DetailPanel**),正文采用 Tiptap 富文本编辑器AnchorMark/AnchorPoint 内联锚点),支持模板、版本管理、知识点标注、题目创建/拉取、作业发布、撤销/重做、AI 反馈/差异化、一致性校验、课时安排
> 架构变更2026-06-21编辑器从列表式BlockRenderer + @dnd-kit升级为节点图式NodeEditor + @xyflow/react。数据结构从 v1blocks 数组)升级到 v2nodes + edges 节点图),旧数据通过 `migrateV1ToV2()` 自动迁移。
> 架构变更2026-06-23数据结构从 v2 升级到 v3课文锚点画布格式。正文节点textbook_content作为画布中央核心教学节点围绕正文组织。新增锚点系统range/point 两种锚定方式、占位符注入算法、11 种定制节点类型。旧数据通过 `migrateV2ToV3()` 自动迁移。
> 架构变更2026-07-04V4 纸感重构):抛弃 React Flow 画布改用三栏布局260px 结构树 + 1fr 纸感编辑器 + 380px 详情面板)。正文采用 Tiptap 富文本编辑器,锚点从字符串偏移升级为 Tiptap MarkAnchorMark 区间锚/AnchorPoint 点锚v3 旧锚点通过 AnchorMigrationBanner 提示失效。doc.version=4editor-slice 移除 updateNodePosition/connect/setEdges/autoLayout。新增 interaction block师生交互对话回合。结构树支持节点展开到正文流expanded-slice。PrintView 改为按 nodes.order 排序渲染。删除 8 个 React Flow 画布和字符串锚点相关文件node-editor/nodes/*/anchor-injector/rf-mappers/auto-layout
**数据结构**
- v1已废弃仅向后兼容读取`{ version: 1, blocks: Block[] }`
- v2已废弃仅向后兼容读取`{ version: 2, nodes: LessonPlanNode[]; edges: LessonPlanEdge[] }`
- v3当前`{ version: 3, textbookContentNodeId: string; nodes: AnyLessonPlanNode[]; edges: AnyLessonPlanEdge[]; anchors: NodeAnchor[] }`
- `TextbookContentNode`:正文节点(`draggable: false`,画布中央,可缩放)
- `LessonPlanNode`:教学节点(`Block` + `position`,可拖动可连线)
- `NodeAnchor`:锚点(`{ id, nodeId, type: "range"|"point", start, end?, textPreview?, invalid? }`
- `AnchorEdge`:锚点连线(教学节点 → 正文节点,默认 10% 透明度
- `FlowEdge`:流程连线(教学节点 → 教学节点
- v3已废弃,仅向后兼容读取`{ version: 3, textbookContentNodeId: string; nodes: AnyLessonPlanNode[]; edges: AnyLessonPlanEdge[]; anchors: NodeAnchor[] }`
- `NodeAnchor`v3 字符串偏移锚点(`{ id, nodeId, type: "range"|"point", start, end?, textPreview?, invalid? }`V4 中通过 `AnchorMigrationBanner` 提示失效
- v4当前`{ version: 4, textbookContentNodeId: string; nodes: AnyLessonPlanNode[]; edges: AnyLessonPlanEdge[]; anchors: NodeAnchor[] }`
- 锚点改为 Tiptap Mark`AnchorMark`(区间锚)+ `AnchorPoint`(点锚),存储在正文富文本 doc 中
- `nodes` 新增 `order` 字段,按顺序渲染(替代画布 position
- `InteractionBlockData`:师生交互对话回合(`{ designIntent, turns: QATurn[], expectedAnswer? }`
**导出函数**
- Data-access`data-access.ts``getLessonPlans`V4查询后按 textbookId+chapterId+creatorId 聚合版本,返回代表项 + versionCount + versions 摘要数组)/ `getLessonPlanById` / `createLessonPlan` / `updateLessonPlanContent` / `softDeleteLessonPlan` / `duplicateLessonPlan` / `getTemplateById` / `buildInitialContent` / `migrateV1ToV2` / `normalizeDocument`v3 规范化,兼容 v1/v2 旧数据)/ `buildDefaultSkeleton`v3 默认 10 节点骨架)/ `getTextbooksForPicker` / `getChaptersForPicker` / `findChapterById` / `publishLessonPlan`V3 新增,设置 status=published/ `unpublishLessonPlan`V3 新增,设置 status=draft仅 published 课案)
- Data-access`data-access.ts``getLessonPlans`V4查询后按 textbookId+chapterId+creatorId 聚合版本,返回代表项 + versionCount + versions 摘要数组)/ `getLessonPlanById` / `createLessonPlan` / `updateLessonPlanContent` / `softDeleteLessonPlan` / `duplicateLessonPlan` / `getTemplateById` / `buildInitialContent` / `migrateV1ToV2` / `normalizeDocument`v4 规范化,兼容 v1/v2/v3 旧数据)/ `buildDefaultSkeleton`默认骨架)/ `getTextbooksForPicker` / `getChaptersForPicker` / `findChapterById` / `publishLessonPlan` / `unpublishLessonPlan`
- Lib`lib/document-migration.ts``defaultDataForType` / `migrateV1ToV2` / `migrateV2ToV3` / `normalizeDocument` / `buildInitialContent` / `buildDefaultSkeleton` / `isTextbookContentNode` / `isAnchorEdge` / `getAnchorsForNode` / `getActiveAnchorIds` / `getAnchorEdges`
- Lib`lib/anchor-injector.ts``markdownToPlainText` / `injectPlaceholders` / `parseAnchoredText` / `toCircledNumber` / `getNextPointIndex` / `relocateAnchors` / `getAnchorColor`
- Lib`lib/anchor-mark.ts`V4 新增)Tiptap `AnchorMark` 扩展(区间锚)+ `AnchorPoint` 扩展(点锚),替代 v3 字符串偏移锚点
- Lib`lib/node-summary.ts``getNodeSummary` / `getTextbookContentSummary` / `getNodeColor` / `NODE_COLORS`
- Lib`lib/rf-mappers.ts``toRfNodes`(支持 textbook_content 节点V3ctx 新增 `anchorableNodes``onCreateNewNode` 字段)/ `toRfEdges`(区分 anchor/flow 边透明度V3锚点边颜色使用 `getNodeColor(anchor.nodeId)` 替代硬编码anchorId 存入 edge.data/ `fromRfEdges`V3`e.data.anchorId` 读取 anchorId回退到 className 判断)
- Lib`lib/export.ts`V5-4 新增 + V4 增强):`flattenLessonPlanForPrint` / `flattenBlockData`V4新增 `interaction` case + `flattenInteraction` 函数)/ `PrintableLessonPlan` 类型
- Data-access-versions`data-access-versions.ts``getLessonPlanVersions` / `createLessonPlanVersion` / `getVersionContent` / `revertToVersion` / `pruneAutoVersions`
- Data-access-templates`data-access-templates.ts``getLessonPlanTemplates` / `saveAsTemplate` / `deletePersonalTemplate`
- Data-access-knowledge`data-access-knowledge.ts``getLessonPlansByKnowledgePoint`V3增加 userId 参数,按 creatorId 过滤 + 排除 archived/ `getLessonPlansByQuestion`V3增加 userId 参数,按 creatorId 过滤 + 排除 archived
- Data-access-knowledge`data-access-knowledge.ts``getLessonPlansByKnowledgePoint` / `getLessonPlansByQuestion`
- Publish-service`publish-service.ts``publishLessonPlanHomework`
- AI-suggest`ai-suggest.ts``suggestKnowledgePoints`
- Actions`getLessonPlansAction` / `getLessonPlanByIdAction` / `createLessonPlanAction` / `updateLessonPlanAction` / `saveLessonPlanVersionAction` / `getLessonPlanVersionsAction` / `revertLessonPlanVersionAction` / `deleteLessonPlanAction` / `duplicateLessonPlanAction` / `getLessonPlanTemplatesAction` / `saveAsTemplateAction` / `deleteTemplateAction` / `suggestKnowledgePointsAction` / `publishLessonPlanHomeworkAction` / `getKnowledgePointOptionsAction` / `getTextbooksForPickerAction` / `getChaptersForPickerAction` / `publishLessonPlanAction`V3 新增requirePermission(LESSON_PLAN_PUBLISH)/ `unpublishLessonPlanAction`V3 新增requirePermission(LESSON_PLAN_PUBLISH)
- Actions`getLessonPlansAction` / `getLessonPlanByIdAction` / `createLessonPlanAction` / `updateLessonPlanAction` / `saveLessonPlanVersionAction` / `getLessonPlanVersionsAction` / `revertLessonPlanVersionAction` / `deleteLessonPlanAction` / `duplicateLessonPlanAction` / `getLessonPlanTemplatesAction` / `saveAsTemplateAction` / `deleteTemplateAction` / `suggestKnowledgePointsAction` / `publishLessonPlanHomeworkAction` / `getKnowledgePointOptionsAction` / `getTextbooksForPickerAction` / `getChaptersForPickerAction` / `publishLessonPlanAction` / `unpublishLessonPlanAction`
**依赖关系**
- 依赖:`shared/*``@/auth``shared/lib/ai``@xyflow/react`(节点图编辑器)、`textbooks`(只读章节/知识点树)、`questions`(创建/查询题目)、`exams`(创建 exam 草稿)、`homework`(创建作业下发)、`classes`(查询教师班级)、`files`(附件)
- 依赖:`shared/*``@/auth``shared/lib/ai``@tiptap/react``@tiptap/starter-kit``@tiptap/pm``@tiptap/extension-image`V4Tiptap 富文本编辑器)、`textbooks`(只读章节/知识点树)、`questions`(创建/查询题目)、`exams`(创建 exam 草稿)、`homework`(创建作业下发)、`classes`(查询教师班级)、`files`(附件)
- 被依赖:无
**已知问题**
- ✅ 通过对方 data-access 调用跨模块数据,无直查跨模块表
- ✅ data-access 按职责拆分为 4 个文件data-access/data-access-versions/data-access-templates/data-access-knowledge
- ✅ actions 按职责拆分为 4 个文件actions/actions-publish/actions-ai/actions-kp
-编辑器架构升级NodeEditorReact Flow 画布)+ NodeEditPanel侧边内容编辑面板+ LessonNode自定义节点组件支持节点拖拽、连线、画布缩放
-V4 纸感重构:三栏布局 StructureTree + PaperEditor + DetailPanel正文采用 Tiptap 富文本编辑器,锚点升级为 Tiptap MarkAnchorMark/AnchorPoint
- ✅ V4删除 8 个 React Flow 画布和字符串锚点相关文件node-editor/nodes/*/anchor-injector/rf-mappers/auto-layout无残留引用
- ✅ V4`block-renderer.tsx`@deprecated)已删除,无残留引用
> 架构变更2026-06-22本次审计修复
@@ -2671,10 +2674,10 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
| `schema.ts` | Zod 验证V3错误消息改为 i18n 键,如 `error.titleRequired` |
| `lib/type-guards.ts` | **集中类型守卫V3 新增)**11 种 BlockData 类型守卫isRichTextBlockData/isTextStudyBlockData/isExerciseBlockData/isObjectiveBlockData/isKeyPointBlockData/isImportBlockData/isNewTeachingBlockData/isSummaryBlockData/isHomeworkBlockData/isBlackboardBlockData/isReflectionBlockData+ 节点类型守卫isTextbookContentNode/isLessonPlanNode+ 题目类型守卫isValidQuestionType + **V4 导出 `VALID_QUESTION_TYPES` 常量 + `ValidQuestionType` 类型**+ 基础类型守卫isLessonPlanStatus/isTemplateType/isTemplateScope/isBlockType+ **Block 字段值类型守卫V3 续新增)**isBlackboardLayout/isImportMethod/isExercisePurpose/isObjectiveDimension/isKeyPointType/isHomeworkType/isReflectionAspect用于 select onChange 替代 `as` 断言)+ **normalizeTemplateBlocks 规范化函数V3 续审计新增)**:从 DB `unknown` 安全转换为 `TemplateBlockSkeleton[]`,替代 `as LessonPlanTemplate["blocks"]` 断言 |
| `lib/i18n-errors.ts` | **Zod 错误 i18n 翻译辅助V3 新增)**`translateFieldErrors`(将 Zod fieldErrors 中的 i18n 键翻译为实际消息)/ `safeParseWithI18n`(安全解析 Zod 结果并返回带翻译的 ActionState 错误格式) |
| `lib/document-migration.ts` | **纯函数**v1→v2migrateV1ToV2/ v2→v3migrateV2ToV3/ 规范化normalizeDocument兼容 v1/v2/v3/ 初始内容buildInitialContent/ 默认骨架buildDefaultSkeleton10 节点 + 正文节点/ defaultDataForType / 工具函数isTextbookContentNode/isAnchorEdge/getAnchorsForNode/getActiveAnchorIds/getAnchorEdges |
| `lib/anchor-injector.ts` | **纯函数**锚点注入算法markdownToPlainText/injectPlaceholders/parseAnchoredText/toCircledNumber/getNextPointIndex/relocateAnchors/getAnchorColor**V4`markdownToPlainText` 引用去除 regex 与 `skipPatterns` 一致化为 `/^\s*>\s+/gm`5 个 skipPatterns 统一添加 `g` 标志** |
| `lib/node-summary.ts` | **纯函数**getNodeSummary支持 11 种节点类型)+ getTextbookContentSummary + NODE_COLORS + getNodeColorV3 续审计:移除 `as { html?: string; ... }` 断言,改用 isRecord/getArrayLength/getString/getNumber 安全字段提取从 `unknown` 收窄) |
| `lib/rf-mappers.ts` | **纯函数**toRfNodesV3:移除冗余 `as` 断言TypeScript 判别联合自动收窄)/ toRfEdges / fromRfEdges |
| `lib/document-migration.ts` | **纯函数**v1→v2migrateV1ToV2/ v2→v3migrateV2ToV3/ 规范化normalizeDocument兼容 v1/v2/v3/v4/ 初始内容buildInitialContent/ 默认骨架buildDefaultSkeleton/ defaultDataForType / 工具函数isTextbookContentNode/isAnchorEdge/getAnchorsForNode/getActiveAnchorIds/getAnchorEdges |
| `lib/anchor-mark.ts` | **V4 新增**Tiptap `AnchorMark` 扩展(区间锚)+ `AnchorPoint` 扩展(点锚),替代 v3 字符串偏移锚点;存储在正文富文本 doc 中 |
| `lib/export.ts` | **V5-4 新增 + V4 增强**`flattenLessonPlanForPrint`(按 `nodes.order` 排序扁平化为 `PrintableLessonPlan`+ `flattenBlockData`V4新增 `interaction` case + `flattenInteraction` 函数)+ `PrintableLessonPlan` 类型;支持 detailed/concise 两种 variant |
| `lib/node-summary.ts` | **纯函数**getNodeSummary支持 12 种节点类型,含 V4 interaction+ getTextbookContentSummary + NODE_COLORS + getNodeColorV3 续审计:移除 `as { html?: string; ... }` 断言,改用 isRecord/getArrayLength/getString/getNumber 安全字段提取从 `unknown` 收窄) |
| `config/block-registry.tsx` | **配置驱动**BLOCK_REGISTRY 注册表 + BlockRendererV3使用 `lib/type-guards.ts` 类型守卫替代所有 `as XxxBlockData` 断言) |
| `providers/lesson-plan-provider.tsx` | **Provider + Context**LessonPlanProvider 注入数据服务/角色配置/埋点;定义 LessonPlanDataService 接口V3扩展 5 个方法 getLessonPlanById/updateLessonPlan/saveLessonPlanVersion/publishLessonPlan/unpublishLessonPlan**V3 续扩展 7 个方法 createLessonPlan/getTextbooksForPicker/getChaptersForPicker/getLessonPlanTemplates/getKnowledgePointOptions/publishLessonPlanHomework/getQuestions + 6 个导出类型**、4 个角色配置、ROLE_CONFIGS 注册表、LessonPlanTracker 接口 + noopTrackerhooksuseLessonPlanContextSafe/useLessonPlanContext/useRoleConfig/useLessonPlanService/useLessonPlanTracker/useLessonPlanTrackerSafe |
| `providers/lesson-plan-provider-setup.tsx` | **页面层 Provider 设置包装组件V3 续新增)**LessonPlanProviderSetup 自动注入默认数据服务createDefaultDataService和角色配置TEACHER_ROLE_CONFIG3 个 teacher 页面用此组件包裹 |
@@ -2691,20 +2694,39 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
| `ai-suggest.ts` | AI 知识点建议服务V3 续审计:移除 `as Record<string, unknown>` 断言改用 `isRecord` 类型守卫AI prompt 提取为 `AI_SUGGEST_PROMPT_TEMPLATE` 模块常量) |
| `seed-templates.ts` | 模板种子数据 |
| `hooks/use-lesson-plan-editor.ts` | **课案编辑器 Zustand store 主文件V4从 303 行单体 store 重写为 25 行薄层,组合 3 个 slice 并导出 `EditorState` 类型)**V3`updateNode` patch 类型改为 `Omit<Partial<Block>, "type">` 防止类型变更) |
| `hooks/editor-slice.ts` | **编辑器 sliceV4 P2-6 新增)**Zustand `StateCreator`,包含 planId/title/doc 状态及所有文档操作方法addNode/updateNode/updateNodePosition/removeNode/updateTextbookContent/getTextbookContentNode/addAnchor/removeAnchor/updateAnchor/connect/disconnect/setEdges/setTitle/setPlanId |
| `hooks/editor-slice.ts` | **编辑器 sliceV4 P2-6 新增 + V4 纸感重构**Zustand `StateCreator`,包含 planId/title/doc 状态及所有文档操作方法addNode/updateNode/removeNode/updateTextbookContent/getTextbookContentNode/addAnchor/removeAnchor/updateAnchor/setTitle/setPlanId**V4 移除**updateNodePosition/connect/disconnect/setEdges/autoLayout画布相关方法 |
| `hooks/selection-slice.ts` | **选中状态 sliceV4 P2-6 新增)**Zustand `StateCreator`,包含 selectedNodeId 状态 + selectNode 方法 |
| `hooks/version-slice.ts` | **版本与保存状态 sliceV4 P2-6 新增)**Zustand `StateCreator`,包含 isDirty/isSaving/lastSavedAt 状态 + hydrate/markSaved/setSaving/replaceDoc 方法 |
| `hooks/version-slice.ts` | **版本与保存状态 sliceV4 P2-6 新增)**Zustand `StateCreator`,包含 isDirty/isSaving/lastSavedAt/saveError/isOnline 状态 + hydrate/markSaved/setSaving/replaceDoc/setSaveError/setOnline 方法 |
| `hooks/history-slice.ts` | **撤销/重做 sliceV5-2 新增)**Zustand `StateCreator`past/future 栈50 步上限)+ canUndo/canRedo/pushHistory/undo/redo/clearHistory 方法 |
| `hooks/expanded-slice.ts` | **V4 纸感重构新增**Zustand `StateCreator`节点展开到正文流状态expandedNodeIds/toggleExpand/setExpanded |
| `components/lesson-plan-list.tsx` | 课案列表V3完全通过 service 调用,移除直接 import `getLessonPlansAction`V3 续审计:新增 `isLoading` 状态,加载时显示加载文本,传递给 `LessonPlanFilters` |
| `components/lesson-plan-card.tsx` | 课案卡片V3完全通过 service 调用,移除直接 import actionsV3 续审计4 个异步处理函数用 `useCallback` 包裹性能优化) |
| `components/lesson-plan-filters.tsx` | 课案筛选器V3 续审计:新增 `isLoading` prop加载时禁用输入并设置 `aria-busy` |
| `components/lesson-plan-editor.tsx` | 课案编辑器V3完全通过 service 调用,移除直接 import 5 个 actions所有操作改为 `service.updateLessonPlan`/`service.saveLessonPlanVersion`/`service.getLessonPlanById`/`service.publishLessonPlan`/`service.unpublishLessonPlan` |
| `components/lesson-plan-readonly-view.tsx` | **只读画布组件**V3MiniMap 使用 `getNodeColor` 替代硬编码颜色) |
| `components/node-editor.tsx` | **节点图画布**V3MiniMap `nodeColor` 使用类型守卫替代 `as { node?: AnyLessonPlanNode }` 断言) |
| `components/node-edit-panel.tsx` | **侧边内容编辑面板**V3移除冗余 `as LessonPlanNode` 断言TypeScript 判别联合自动收窄) |
| `components/nodes/lesson-node.tsx` | **自定义教学节点组件**V3 续审计:使用 `isLessonNodeData` 类型守卫替代 `as { node: LessonPlanNode }` 断言 + 空状态回退) |
| `components/nodes/textbook-content-node.tsx` | **正文节点组件**V3 续:拆分为 3 文件,主文件 471 行;`as unknown as` 替换为 `isTextbookContentNodePropsData` 类型守卫) |
| `components/nodes/anchor-node-selector.tsx` | **锚点节点选择器V3 续新增,从 textbook-content-node.tsx 抽取)**:渲染可锚定教学节点列表 + 关联到选中节点 + 创建新节点选项 |
| `components/nodes/textbook-segments.tsx` | **锚点段落渲染函数V3 续新增,从 textbook-content-node.tsx 抽取)**renderSegments 遍历 segments 数组渲染文本/区间锚点/点锚点 |
| `components/lesson-plan-editor.tsx` | 课案编辑器V3完全通过 service 调用**V4 纸感重构**:移除 NodeEditor/NodeEditPanel改用三栏布局 StructureTree + PaperEditor + DetailPanel保留顶部工具栏 + 5 个对话框 |
| `components/lesson-plan-readonly-view.tsx` | **只读视图**V3MiniMap 使用 `getNodeColor` 替代硬编码颜色**V4**:移除 React Flow 依赖,委托 `LessonPlanMobileView` 线性卡片视图渲染所有视口 |
| `components/anchor-migration-banner.tsx` | **V4 新增**v3 锚点失效提示 banner检测 `doc.anchors` `invalid:true` 或含 `start` 字段的旧锚点;通过 `key={planId}` 重新挂载 + lazy initial state 读取 localStorage 避免 setState in effect |
| `components/print-view.tsx` | **V5-4 新增 + V4 适配**:打印视图组件,按 `nodes.order` 排序渲染,详细版/简洁版切换 + `window.print()` |
| `components/schedule-dialog.tsx` | **V5-7 新增**:课案绑定课时对话框 |
| `components/consistency-check-dialog.tsx` | **V5-19 新增**:目标-评价一致性校验对话框 |
| `components/ai-feedback-dialog.tsx` | **V5-17 新增**AI 反馈闭环对话框4 维度 strengths/improvements/alignment/differentiation |
| `components/ai-differentiation-dialog.tsx` | **V5-21 新增**AI 差异化教学对话框3 Tab差异化建议/课标核对/可解释评估) |
| `components/curriculum-heatmap.tsx` | **V5-20 新增**:课标覆盖热力图组件 |
| `components/version-diff-view.tsx` | **V5-16 新增**:版本对比视图组件 |
| `components/lesson-plan-mobile-view.tsx` | **V5-13 新增**:移动端只读视图(按教学阶段分组线性卡片视图);**V4**:被 `lesson-plan-readonly-view.tsx` 委托渲染所有视口 |
| `components/attachment-picker.tsx` | **V5-5 新增**:素材库 picker复用 use-file-upload + M6 附件表 data-access |
| `components/paper-editor/paper-editor.tsx` | **V4 新增**:纸感编辑器容器(中栏),承载 Tiptap 富文本编辑器 |
| `components/paper-editor/paper-toolbar.tsx` | **V4 新增**:纸感编辑器工具栏 |
| `components/paper-editor/paper-context-menu.tsx` | **V4 新增**:纸感编辑器右键菜单 |
| `components/paper-editor/textbook-tiptap-editor.tsx` | **V4 新增**:教材正文 Tiptap 编辑器(集成 AnchorMark/AnchorPoint 扩展) |
| `components/paper-editor/inline-node.tsx` | **V4 新增**:内联节点渲染组件 |
| `components/paper-editor/inline-qa-dialog.tsx` | **V4 新增**:内联问答对话框 |
| `components/structure-tree/structure-tree.tsx` | **V4 新增**:结构树容器(左栏 260px支持节点展开到正文流 |
| `components/structure-tree/tree-node-row.tsx` | **V4 新增**:结构树节点行组件 |
| `components/detail-panel/detail-panel.tsx` | **V4 新增**:详情面板容器(右栏 380px |
| `components/detail-panel/detail-head.tsx` | **V4 新增**:详情面板头部 |
| `components/detail-panel/detail-props.tsx` | **V4 新增**:详情面板属性编辑 |
| `components/detail-panel/qa-editor.tsx` | **V4 新增**师生问答编辑器interaction block 配套) |
| `components/blocks/interaction-block.tsx` | **V4 新增**:师生交互 BlockdesignIntent + turns[] + expectedAnswer |
| `components/lesson-plan-error-boundary.tsx` | **错误边界**V3 续:重写为包装组件模式——内部类组件接受 `errorText`/`retryText` props外部函数组件通过 `useTranslations` 注入 i18n 文案) |
| `components/lesson-plan-skeleton.tsx` | **骨架屏**VersionListSkeleton/QuestionBankSkeleton/KnowledgePointSkeleton/LessonPlanListSkeleton |
| `components/template-picker.tsx` | 模板选择器V3 续:完全通过 service 调用,移除直接 import 4 个 actionsV3 续审计:通过 `ChapterPickerOption.children` 递归类型消除 `as ChapterPickerOption[]` 断言) |
@@ -2788,6 +2810,17 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions"
> - **i18n 扩展**zh-CN/en 同步新增 editor.stage*/editor.differentiation*/editor.consistency*/consistency.*/diff.*/library.*/feedback.*/heatmap.*/aiDifferentiation.*/blackboard.editMode/previewMode/editHint/previewEmpty/untitled
> - **V5-11 R3 协同编辑**需引入新依赖Yjs/Liveblocks或采用轻量协作方案评论+@提醒+版本对比),暂标记为待规划,待用户决策
> 架构变更2026-07-04V4 纸感重构 — 抛弃 React Flow 画布,改用三栏布局 + Tiptap 富文本编辑器):
> - **H1 interaction block 注册**`config/block-registry.tsx` 新增 `interaction` case导入 `InteractionBlock` 组件 + `isInteractionBlockData` 类型守卫BLOCK_REGISTRY 支持 12 种 Block 类型(含 V4 interaction
> - **H2 三栏布局重构**`lesson-plan-editor.tsx` 移除 `NodeEditor`/`NodeEditPanel` 导入与 JSX改用 `StructureTree + PaperEditor + DetailPanel` 三栏布局(`grid-template-columns: 260px 1fr 380px`),保留顶部工具栏(标题/保存/撤销重做/发布/导出/安排课时/一致性校验/AI 反馈/AI 差异化)+ 5 个对话框VersionHistoryDrawer/ConsistencyCheckDialog/AiFeedbackDialog/AiDifferentiationDialog/PrintView/ScheduleDialog删除 `components/node-edit-panel.tsx` + `app/(dashboard)/teacher/lesson-plans/[planId]/edit/ai-content-generator-slot.tsx`(依赖 NodeEditPanel 类型)
> - **I1 v3 锚点失效 banner**:新增 `components/anchor-migration-banner.tsx`,检测 `doc.anchors` 中 `invalid:true` 或含 `start` 字段的旧锚点并提示用户;通过 `key={planId}` 实现 planId 变化时重新挂载内部组件,使用 lazy initial state 读取 localStoragedismiss 状态按 planId 隔离),避免 useEffect 中 setState符合 V4 `react-hooks/set-state-in-effect` lint 规则)
> - **J1 删除废弃文件**:删除 8 个 React Flow 画布和字符串锚点相关文件——`components/node-editor.tsx`、`components/nodes/lesson-node.tsx`、`components/nodes/textbook-content-node.tsx`、`components/nodes/textbook-segments.tsx`、`components/nodes/anchor-node-selector.tsx`、`lib/anchor-injector.ts`、`lib/rf-mappers.ts`、`lib/auto-layout.ts``lesson-plan-readonly-view.tsx` 重写为委托 `LessonPlanMobileView`(线性卡片视图)渲染所有视口,移除 React Flow 依赖
> - **J2 PrintView 适配 V4**`lib/export.ts` 的 `flattenBlockData` switch 新增 `interaction` case + `flattenInteraction` 函数(输出设计意图 + 师生对话回合 + 预期回答export.ts 已使用 `nodes.sort((a, b) => a.order - b.order)` 按顺序扁平化无画布依赖docstring 更新为 12 种 Block含 V4 interaction
> - **J3 lint + tsc 零错误验证**tsc --noEmit 0 错误lint 中 V4 引入的 `react-hooks/set-state-in-effect` 错误已通过 `anchor-migration-banner.tsx` 的 key-based remount + lazy initial state 模式修复;剩余 6 个 lint 错误为预存无关模块问题exams/use-exam-preview-tasks react-hooks/refs 3 个、template-picker V5-9 set-state-in-effect 1 个),按计划要求记录不修复
> - **J4 架构图同步**004_architecture_impact_map.md 新增 V4 纸感重构章节005_architecture_data.json 更新 lesson_preparation 节点——description 改为 V4 描述、dependencies 移除 `@xyflow/react` 改为 `@tiptap/*` 包、files 数组移除 9 个废弃文件并新增 V4 组件、auditFixes 新增 V4-PAPER-1~8 + V4-PAPER-DOC 条目
> - **J5 known-issues V4 规则**`docs/troubleshooting/known-issues.md` 新增 V4 纸感重构规则表,记录 8 条规则——React Flow 弃用、Tiptap Mark 锚点替代字符串偏移、setState in effect 禁用、doc.version=4、editor-slice 移除画布相关方法、interaction block 注册、PrintView 按 order 排序、AnchorMigrationBanner 失效提示
> - **数据模型 v4**`types.ts` `LessonPlanDocument.version = 4``lib/document-migration.ts` `normalizeDocument` 兼容 v1/v2/v3/v4 链式迁移;`editor-slice.ts` 移除 `updateNodePosition`/`connect`/`setEdges`/`autoLayout` 画布相关方法;`hooks/expanded-slice.ts` 新增 `expandedNodeIds`/`toggleExpand`/`setExpanded` 状态(节点展开到正文流);`lib/anchor-mark.ts` 新增 Tiptap `AnchorMark` + `AnchorPoint` 扩展(替代 v3 字符串偏移锚点)
---
## 2.27b standards课标模块2026-07-01 新增)

View File

@@ -20330,7 +20330,7 @@
},
"lesson_preparation": {
"path": "src/modules/lesson-preparation",
"description": "教师备课模块(v3 锚点画布以课文正文为核心主体textbook_content 节点置于画布中央draggable=false 可缩放),教学目标/重难点等 11 种定制节点围绕正文组织。两种锚定机制range选择一段文本关联节点未选中 opacity:0+ point插入带圈数字占位符未选中 opacity:0.3)。锚点连线默认 10% 透明度,选中时完整显示。数据模型 v3LessonPlanDocument 含 textbookContentNodeId、nodes、edges、anchors 数组。anchor-injector 实现 Markdown 纯文本偏移映射与占位符注入。实时拖动onNodeDrag 替代 onNodeDragStop。v1→v2→v3 链式迁移。强制选定教材+章节才能备课template-picker 四步流程)。保留模板、版本管理、知识点标注、题目创建/拉取、作业发布能力",
"description": "教师备课模块(V4 纸感重构):抛弃 React Flow 画布改用三栏布局260px 结构树 + 1fr 纸感编辑器 + 380px 详情面板)。正文采用 Tiptap 富文本编辑器,锚点从字符串偏移升级为 Tiptap MarkAnchorMark 区间锚/AnchorPoint 点锚v3 旧锚点通过 AnchorMigrationBanner 提示失效。doc.version=4editor-slice 移除 updateNodePosition/connect/setEdges/autoLayout。新增 interaction block师生交互对话回合含 designIntent/turns[]/expectedAnswer。结构树支持节点展开到正文流expanded-slice。PrintView 改为按 nodes.order 排序渲染,不再依赖画布。v1→v2→v3→v4 链式迁移。保留模板、版本管理、知识点标注、题目创建/拉取、作业发布、撤销/重做、AI 反馈/差异化、一致性校验、课时安排等能力",
"exports": {
"dataAccess": [
{
@@ -20862,7 +20862,10 @@
"classes",
"files",
"shared/lib/ai",
"@xyflow/react"
"@tiptap/react",
"@tiptap/starter-kit",
"@tiptap/pm",
"@tiptap/extension-image"
],
"files": [
"types.ts",
@@ -20871,13 +20874,17 @@
"lib/type-guards.ts",
"lib/i18n-errors.ts",
"lib/document-migration.ts",
"lib/anchor-injector.ts",
"lib/node-summary.ts",
"lib/rf-mappers.ts",
"lib/anchor-mark.ts",
"lib/export.ts",
"lib/scope-check.ts",
"lib/document-diff.ts",
"config/block-registry.tsx",
"providers/lesson-plan-provider.tsx",
"providers/lesson-plan-provider-setup.tsx",
"services/default-data-service.ts",
"services/default-question-service.ts",
"services/external-questions-bridge.ts",
"data-access.ts",
"data-access-versions.ts",
"data-access-templates.ts",
@@ -20886,6 +20893,7 @@
"actions-publish.ts",
"actions-ai.ts",
"actions-kp.ts",
"actions-questions.ts",
"publish-service.ts",
"ai-suggest.ts",
"seed-templates.ts",
@@ -20893,17 +20901,13 @@
"hooks/editor-slice.ts",
"hooks/selection-slice.ts",
"hooks/version-slice.ts",
"hooks/history-slice.ts",
"hooks/expanded-slice.ts",
"components/lesson-plan-list.tsx",
"components/lesson-plan-card.tsx",
"components/lesson-plan-filters.tsx",
"components/lesson-plan-editor.tsx",
"components/lesson-plan-readonly-view.tsx",
"components/node-editor.tsx",
"components/node-edit-panel.tsx",
"components/nodes/lesson-node.tsx",
"components/nodes/textbook-content-node.tsx",
"components/nodes/anchor-node-selector.tsx",
"components/nodes/textbook-segments.tsx",
"components/lesson-plan-error-boundary.tsx",
"components/lesson-plan-skeleton.tsx",
"components/template-picker.tsx",
@@ -20912,6 +20916,29 @@
"components/question-bank-picker.tsx",
"components/inline-question-editor.tsx",
"components/publish-homework-dialog.tsx",
"components/anchor-migration-banner.tsx",
"components/print-view.tsx",
"components/schedule-dialog.tsx",
"components/consistency-check-dialog.tsx",
"components/ai-feedback-dialog.tsx",
"components/ai-differentiation-dialog.tsx",
"components/curriculum-heatmap.tsx",
"components/version-diff-view.tsx",
"components/version-diff-viewer.tsx",
"components/lesson-plan-mobile-view.tsx",
"components/attachment-picker.tsx",
"components/paper-editor/paper-editor.tsx",
"components/paper-editor/paper-toolbar.tsx",
"components/paper-editor/paper-context-menu.tsx",
"components/paper-editor/textbook-tiptap-editor.tsx",
"components/paper-editor/inline-node.tsx",
"components/paper-editor/inline-qa-dialog.tsx",
"components/structure-tree/structure-tree.tsx",
"components/structure-tree/tree-node-row.tsx",
"components/detail-panel/detail-panel.tsx",
"components/detail-panel/detail-head.tsx",
"components/detail-panel/detail-props.tsx",
"components/detail-panel/qa-editor.tsx",
"components/blocks/rich-text-block.tsx",
"components/blocks/text-study-block.tsx",
"components/blocks/exercise-block.tsx",
@@ -20923,6 +20950,7 @@
"components/blocks/summary-block.tsx",
"components/blocks/homework-block.tsx",
"components/blocks/blackboard-block.tsx",
"components/blocks/interaction-block.tsx",
"components/calendar-view.tsx",
"components/curriculum-map-view.tsx",
"data-access-calendar.ts",
@@ -20933,6 +20961,7 @@
"data-access-substitutes.ts",
"data-access-ai-evaluation.ts",
"data-access-analytics.ts",
"data-access-schedules.ts",
"actions-calendar.ts",
"actions-review.ts",
"actions-comments.ts",
@@ -20940,7 +20969,8 @@
"actions-attachments.ts",
"actions-substitutes.ts",
"actions-ai-evaluation.ts",
"actions-analytics.ts"
"actions-analytics.ts",
"actions-schedules.ts"
],
"i18n": {
"namespace": "lessonPreparation",
@@ -21020,7 +21050,16 @@
"V5-2": "撤销/重做:新增 hooks/history-slice.tspast/future 栈50 步上限canUndo/canRedo/pushHistory/undo/redo/clearHistory 方法editor-slice.ts 所有 mutation 方法setTitle/addNode/updateNode/removeNode/updateTextbookContent/addAnchor/removeAnchor/updateAnchor/connect/disconnect/setEdges包装 pushHistoryupdateNodePosition 除外(拖拽过程中由调用方在 onDragStart 时推入version-slice hydrate/replaceDoc 调用 clearHistorylesson-plan-editor.tsx 顶部新增 Undo/Redo 按钮 + Ctrl/Cmd+Z 撤销 + Ctrl/Cmd+Shift+Z 或 Ctrl/Cmd+Y 重做快捷键",
"V5-3": "发布前作业单预览publish-homework-dialog.tsx 改为 3 步流程step=select 选班级+时间 → step=preview 预览题目+总分+班级数 → step=confirm 确认发布),第二步显示题目列表(题型/来源/题干预览/分值)+汇总信息(班级数/题目数/总分),第三步显示最终确认信息+警告文案exercise-block.tsx 调用 PublishHomeworkDialog 时传入 items={data.items}",
"V5-4": "导出/打印:新增 lib/export.tsflattenLessonPlanForPrint 函数,将画布式 LessonPlanDocument 扁平化为 PrintableLessonPlan 线性结构,支持 detailed/concise 两种 variantconcise 仅含 objective/new_teaching/exercise/homework+ components/print-view.tsx打印视图组件详细版/简洁版切换 + 调用 window.print() 通过浏览器原生能力保存为 PDF + print: CSS 媒体查询隐藏工具栏 + 页眉含教材/教师/班级/教学时长/最后保存时间 + break-inside-avoid 防止段落跨页lesson-plan-editor.tsx 新增 printablePlan useMemo 构造 + 导出按钮 + PrintView 渲染",
"V5-5": "多媒体嵌入 + 我的素材库types.ts RichTextBlockData 新增 attachments?: RichTextAttachment[] 字段 + RichTextAttachment 类型attachmentId/fileId/displayName/kind: image|audio|video|file/url/mimeType?rich-text-block.tsx 集成 @tiptap/extension-imageImage.configure inline:false allowBase64:false+ 新增附件入口按钮 + 已嵌入附件列表渲染(非图片附件列表 + 图片附件缩略图,含删除按钮)+ 图片附件通过 editor.commands.setImage 直接插入富文本;新增 components/attachment-picker.tsx素材库 picker复用 use-file-upload hook 调用 /api/upload + 调用 service.createLessonPlanAttachment 落库到 M6 lessonPlanAttachments 表 + 列出 service.getLessonPlanAttachments + 删除 service.deleteLessonPlanAttachment + inferAttachmentKind 工具函数LessonPlanDataService 接口新增 getLessonPlanAttachments/createLessonPlanAttachment/deleteLessonPlanAttachment 三个方法 + LessonPlanAttachmentOption 导出类型default-data-service.ts 实现三个方法DB 层 Date 转 ISO string 以匹配接口类型BlockRenderProps 新增 planId? 字段NodeEditPanel 新增 planId prop 透传lesson-plan-editor.tsx NodeEditPanel 调用传入 planId新增依赖 @tiptap/extension-imagefiles/types.ts FileTargetType 新增 'lesson_plan' 类型"
"V5-5": "多媒体嵌入 + 我的素材库types.ts RichTextBlockData 新增 attachments?: RichTextAttachment[] 字段 + RichTextAttachment 类型attachmentId/fileId/displayName/kind: image|audio|video|file/url/mimeType?rich-text-block.tsx 集成 @tiptap/extension-imageImage.configure inline:false allowBase64:false+ 新增附件入口按钮 + 已嵌入附件列表渲染(非图片附件列表 + 图片附件缩略图,含删除按钮)+ 图片附件通过 editor.commands.setImage 直接插入富文本;新增 components/attachment-picker.tsx素材库 picker复用 use-file-upload hook 调用 /api/upload + 调用 service.createLessonPlanAttachment 落库到 M6 lessonPlanAttachments 表 + 列出 service.getLessonPlanAttachments + 删除 service.deleteLessonPlanAttachment + inferAttachmentKind 工具函数LessonPlanDataService 接口新增 getLessonPlanAttachments/createLessonPlanAttachment/deleteLessonPlanAttachment 三个方法 + LessonPlanAttachmentOption 导出类型default-data-service.ts 实现三个方法DB 层 Date 转 ISO string 以匹配接口类型BlockRenderProps 新增 planId? 字段NodeEditPanel 新增 planId prop 透传lesson-plan-editor.tsx NodeEditPanel 调用传入 planId新增依赖 @tiptap/extension-imagefiles/types.ts FileTargetType 新增 'lesson_plan' 类型",
"V4-PAPER-1": "H1 注册 interaction blockconfig/block-registry.tsx 新增 interaction case导入 InteractionBlock 组件 + isInteractionBlockData 类型守卫BLOCK_REGISTRY 支持 12 种 Block 类型(含 V4 interaction",
"V4-PAPER-2": "H2 三栏布局重构lesson-plan-editor.tsx 移除 NodeEditor/NodeEditPanel 导入与 JSX改用 StructureTree + PaperEditor + DetailPanel 三栏布局grid-template-columns: 260px 1fr 380px保留顶部工具栏标题/保存/撤销重做/发布/导出/安排课时/一致性校验/AI 反馈/AI 差异化)+ 5 个对话框VersionHistoryDrawer/ConsistencyCheckDialog/AiFeedbackDialog/AiDifferentiationDialog/PrintView/ScheduleDialog删除 components/node-edit-panel.tsx + app/(dashboard)/teacher/lesson-plans/[planId]/edit/ai-content-generator-slot.tsx依赖 NodeEditPanel 类型)",
"V4-PAPER-3": "I1 v3 锚点失效 banner新增 components/anchor-migration-banner.tsx检测 doc.anchors 中 invalid:true 或含 start 字段的旧锚点并提示用户;通过 key={planId} 实现 planId 变化时重新挂载内部组件,使用 lazy initial state 读取 localStoragedismiss 状态按 planId 隔离),避免 useEffect 中 setState符合 V4 react-hooks/set-state-in-effect lint 规则)",
"V4-PAPER-4": "J1 删除废弃文件:删除 8 个 React Flow 画布和字符串锚点相关文件——components/node-editor.tsx、components/nodes/lesson-node.tsx、components/nodes/textbook-content-node.tsx、components/nodes/textbook-segments.tsx、components/nodes/anchor-node-selector.tsx、lib/anchor-injector.ts、lib/rf-mappers.ts、lib/auto-layout.tslesson-plan-readonly-view.tsx 重写为委托 LessonPlanMobileView线性卡片视图渲染所有视口移除 React Flow 依赖",
"V4-PAPER-5": "J2 PrintView 适配 V4lib/export.ts 的 flattenBlockData switch 新增 interaction case + flattenInteraction 函数(输出设计意图 + 师生对话回合 + 预期回答export.ts 已使用 nodes.sort((a, b) => a.order - b.order) 按顺序扁平化无画布依赖docstring 更新为 12 种 Block含 V4 interaction",
"V4-PAPER-6": "J3 lint + tsc 零错误验证tsc --noEmit 0 错误lint 中 V4 引入的 react-hooks/set-state-in-effect 错误已通过 anchor-migration-banner.tsx 的 key-based remount + lazy initial state 模式修复;剩余 6 个 lint 错误为预存无关模块问题exams/use-exam-preview-tasks react-hooks/refs 3 个、template-picker V5-9 set-state-in-effect 1 个),按计划要求记录不修复",
"V4-PAPER-7": "J4 架构图同步004_architecture_impact_map.md 新增 V4 纸感重构章节005_architecture_data.json 更新 lesson_preparation 节点——description 改为 V4 描述、dependencies 移除 @xyflow/react 改为 @tiptap/* 包、files 数组移除 9 个废弃文件并新增 V4 组件paper-editor/structure-tree/detail-panel/interaction-block/anchor-migration-banner/print-view/schedule-dialog/consistency-check-dialog/ai-feedback-dialog/ai-differentiation-dialog/expanded-slice/history-slice/anchor-mark/export/scope-check/document-diff 等、auditFixes 新增 V4-PAPER-1~7 条目",
"V4-PAPER-8": "J5 known-issues V4 规则docs/troubleshooting/known-issues.md 新增 V4 纸感重构规则表,记录 8 条规则——React Flow 弃用、Tiptap Mark 锚点替代字符串偏移、setState in effect 禁用(用 key-based remount + lazy initial state 替代、doc.version=4、editor-slice 移除画布相关方法、interaction block 注册、PrintView 按 order 排序、AnchorMigrationBanner 失效提示",
"V4-PAPER-DOC": "documentVersion 升级为 4types.ts LessonPlanDocument.version = 4lib/document-migration.ts normalizeDocument 兼容 v1/v2/v3/v4 链式迁移editor-slice.ts 移除 updateNodePosition/connect/setEdges/autoLayout 画布相关方法hooks/expanded-slice.ts 新增 expandedNodeIds/toggleExpand/setExpanded 状态节点展开到正文流lib/anchor-mark.ts 新增 Tiptap AnchorMark + AnchorPoint 扩展(替代 v3 字符串偏移锚点)"
}
},
"error-book": {