diff --git a/docs/architecture/004_architecture_impact_map.md b/docs/architecture/004_architecture_impact_map.md index dd62db8..c876a12 100644 --- a/docs/architecture/004_architecture_impact_map.md +++ b/docs/architecture/004_architecture_impact_map.md @@ -2820,6 +2820,9 @@ src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions" > - **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 字符串偏移锚点) +> - **V2-1 复制节点**:`hooks/editor-slice.ts` 新增 `duplicateNode(id)` 方法(深拷贝 `BlockData` + 新 id + 标题加"副本" + order 置末,interaction 节点的 turns 重新生成 id 避免冲突);`components/paper-editor/paper-context-menu.tsx` 的 `copyNode` 从 toast 占位改为调用 `duplicateNode` 并 toast 成功提示;i18n 新增 `v4.contextMenu.copied`/`copyFailed` 键(zh-CN + en) +> - **V2-2 节点级 AI 协助 4 项**:`lib/ai-node-assist.ts` 新增 4 个服务函数(`generateNodeContent`/`optimizeNodeExpression`/`suggestNodeDifferentiation`/`generateLayeredQuestions`),全部纯服务端、Zod 校验、失败返回 null;`actions-ai.ts` 新增 4 个 Server Action,每个 action 校验 `LESSON_PLAN_READ + LESSON_PLAN_CREATE + AI_CHAT` 三个权限点;`hooks/use-node-ai-assist.ts` 新增客户端 hook;`components/paper-editor/paper-editor.tsx` 注入 `onAiAction` 回调;`components/detail-panel/detail-panel.tsx` 的 4 个 `AiButton` 接入真实 action;i18n 新增 `v4.contextMenu.aiRunning`/`aiSuccess`/`aiFailed`/`aiComingSoon` 键(zh-CN + en) +> - **V4-I18N-1 i18n 完整审查与修复**:对 lesson-preparation 模块 i18n 配置进行全量审查并修复——P0 修复运行时 MISSING_MESSAGE:`version.diff.*` 3 键(title/summary/noChanges)+ `schema.ts` 引用的 8 个 `error.*` 键(labelTooLong/versionNoInvalid/nameRequired/nameTooLong/queryTooLong/blockIdRequired/commentTooLong/reviewerRequired)+ `v4.contextMenu` 6 键(copied/copyFailed/aiComingSoon/aiRunning/aiSuccess/aiFailed)(zh-CN + en 同步);P1 修复 en locale 下大面积报错:en `calendar` 节键名对齐 zh-CN(weekView/monthView/loadFailed + prev/next/eventMeta/weekDays 子节),en `analytics` 节补齐 totalPublished/totalSubmitted/totalStandardsLinked/loadFailed;P2 修复 7 处硬编码中文(detail-props.tsx 的 stageLabel/differentiationLabel、inline-node.tsx 的 exerciseCount、inline-qa-dialog.tsx 的 expectedAnswer、qa-editor.tsx 的 turnContentPlaceholder、curriculum-map-view.tsx 的 legendTitle/noData)并新增对应 6 个 i18n 键(`v4.detail.stageLabel`/`differentiationLabel`/`exerciseCount`/`turnContentPlaceholder`、`v4.heatmap.legendTitle`/`noData`);清理 7 个 dead 节(review/comment/formative/substitute/evaluation/standards/gradeHead,analytics 因被 `app/(dashboard)/admin/curriculum-map` 引用而保留);`lib/i18n-errors.ts` 新增 `t.has(msg)` 运行时守卫,避免 `as` 断言绕过类型检查(键不存在时返回原消息而非抛出 MISSING_MESSAGE);zh-CN 与 en 顶层键集一致性验证通过(43 = 43);005_architecture_data.json 同步追加 `V4-I18N-1` auditFixes 条目;known-issues.md 追加 3 个 i18n 规则表(键缺失与中英文不同步 / dead 节清理规则 / 动态键翻译守卫) --- diff --git a/docs/architecture/005_architecture_data.json b/docs/architecture/005_architecture_data.json index 90ab252..8b350c8 100644 --- a/docs/architecture/005_architecture_data.json +++ b/docs/architecture/005_architecture_data.json @@ -6713,7 +6713,11 @@ ], "uiDeps": [], "uiDepsNote": "已通过 render prop 解耦,TeacherTextbookReader 已移至 app 层(src/app/(dashboard)/teacher/textbooks/[id]/_components/),textbooks 模块不再直接 import questions 模块组件", - "npmDeps": ["@xyflow/react", "@dagrejs/dagre", "react-force-graph-2d"], + "npmDeps": [ + "@xyflow/react", + "@dagrejs/dagre", + "react-force-graph-2d" + ], "npmDepsNote": "v4 新增 react-force-graph-2d(基于 d3-force + Canvas)实现 Obsidian 风格力导向图谱;通过 next/dynamic ssr:false 加载避免 SSR canvas/window 报错;@xyflow/react + @dagrejs/dagre 用于分层有向图布局", "knownIssues": [ "v4 新增(2026-07-03):知识点图谱新增 Obsidian 风格力导向布局(force 模式),与原分层有向图(hierarchical 模式)共存,工具栏可切换;新增组件 force-graph.tsx,新增类型 GraphLayoutMode;保留全部现有功能(掌握度视图/搜索高亮/邻居高亮/前置依赖增删)", @@ -20777,6 +20781,30 @@ "permission": "LESSON_PLAN_READ", "file": "actions-ai.ts", "purpose": "V5-21 A4 辅助新增:按 textbookId 获取知识点列表(仅 id+name),供课标核对 Tab 按需加载" + }, + { + "name": "generateNodeContentAction", + "permission": "LESSON_PLAN_READ + LESSON_PLAN_CREATE + AI_CHAT", + "file": "actions-ai.ts", + "purpose": "V4-N1 新增:节点级 AI 协助 - 根据节点 type 生成对应字段,返回 patch 由前端合并到 node.data" + }, + { + "name": "optimizeNodeExpressionAction", + "permission": "LESSON_PLAN_READ + LESSON_PLAN_CREATE + AI_CHAT", + "file": "actions-ai.ts", + "purpose": "V4-N2 新增:节点级 AI 协助 - 优化节点现有表达,保留结构仅修改字段值" + }, + { + "name": "suggestNodeDifferentiationAction", + "permission": "LESSON_PLAN_READ + LESSON_PLAN_CREATE + AI_CHAT", + "file": "actions-ai.ts", + "purpose": "V4-N3 新增:节点级 AI 协助 - 判定节点适合的差异化层次(basic/intermediate/advanced),前端据此设置 node.differentiation" + }, + { + "name": "generateLayeredQuestionsAction", + "permission": "LESSON_PLAN_READ + LESSON_PLAN_CREATE + AI_CHAT", + "file": "actions-ai.ts", + "purpose": "V4-N4 新增:节点级 AI 协助 - 为 interaction 节点生成分层提问,返回 QATurn[] 由前端追加到 turns" } ], "schemas": [ @@ -20876,6 +20904,7 @@ "lib/document-migration.ts", "lib/node-summary.ts", "lib/anchor-mark.ts", + "lib/ai-node-assist.ts", "lib/export.ts", "lib/scope-check.ts", "lib/document-diff.ts", @@ -20903,6 +20932,7 @@ "hooks/version-slice.ts", "hooks/history-slice.ts", "hooks/expanded-slice.ts", + "hooks/use-node-ai-assist.ts", "components/lesson-plan-list.tsx", "components/lesson-plan-card.tsx", "components/lesson-plan-filters.tsx", @@ -21059,7 +21089,10 @@ "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 升级为 4: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 字符串偏移锚点)" + "V4-PAPER-DOC": "documentVersion 升级为 4: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 字符串偏移锚点)", + "V4-PAPER-V2-1": "V2 复制节点功能完整实现:hooks/editor-slice.ts 新增 duplicateNode(id) 方法(深拷贝 BlockData + 新 id + 标题加'副本' + order 置末,interaction 节点的 turns 重新生成 id 避免冲突);components/paper-editor/paper-context-menu.tsx 的 copyNode 从 toast 占位改为调用 duplicateNode 并 toast 成功提示;i18n 新增 v4.contextMenu.copied/copyFailed 键(zh-CN + en)", + "V4-PAPER-V2-2": "V2 节点级 AI 协助 4 项完整实现:lib/ai-node-assist.ts 新增 4 个服务函数(generateNodeContent/optimizeNodeExpression/suggestNodeDifferentiation/generateLayeredQuestions),全部纯服务端、Zod 校验、失败返回 null;actions-ai.ts 新增 4 个 Server Action,每个 action 校验 LESSON_PLAN_READ + LESSON_PLAN_CREATE + AI_CHAT 三个权限点;hooks/use-node-ai-assist.ts 新增客户端 hook;components/paper-editor/paper-editor.tsx 注入 onAiAction 回调;components/detail-panel/detail-panel.tsx 的 4 个 AiButton 接入真实 action;i18n 新增 v4.contextMenu.aiRunning/aiSuccess/aiFailed/aiComingSoon 键", + "V4-I18N-1": "i18n 完整审查与修复:P0 修复 version.diff.* 3 键 + schema.ts 8 个 error.* 键 + contextMenu 6 键(zh-CN + en 同步);P1 修复 en calendar 节键名对齐 zh-CN;P2 修复 7 处硬编码中文 + 新增 6 个 i18n 键;清理 7 个 dead 节(review/comment/formative/substitute/evaluation/standards/gradeHead,analytics 因被 admin/curriculum-map 引用保留);lib/i18n-errors.ts 新增 t.has() 守卫" } }, "error-book": { @@ -26907,4 +26940,4 @@ } } } -} \ No newline at end of file +} diff --git a/docs/architecture/_update_004.cjs b/docs/architecture/_update_004.cjs deleted file mode 100644 index 78c8dc1..0000000 --- a/docs/architecture/_update_004.cjs +++ /dev/null @@ -1,101 +0,0 @@ -// 临时脚本:更新 004_architecture_impact_map.md -const fs = require('fs'); -const path = require('path'); - -const filePath = path.join(__dirname, '004_architecture_impact_map.md'); -const content = fs.readFileSync(filePath, 'utf8'); - -const oldString = [ - '| `components/blocks/reflection-block.tsx` | 反思 Block(V3 续:select onChange 使用 `isReflectionAspect` 类型守卫替代 `as` 断言) |', - '', - '---', - '', - '## 2.28 error-book(错题本模块)' -].join('\r\n'); - -const newLines = [ - '| `components/blocks/reflection-block.tsx` | 反思 Block(V3 续:select onChange 使用 `isReflectionAspect` 类型守卫替代 `as` 断言) |', - '| `components/calendar-view.tsx` | **M9 日历视图组件(2026-07-01 新增)**:客户端组件,支持周历/月历切换,6 种事件类型颜色映射 |', - '| `components/curriculum-map-view.tsx` | **M4 课程地图热力图组件(2026-07-01 新增)**:学科×年级矩阵表格,颜色编码覆盖率 |', - '| `data-access-calendar.ts` | **M9 日历事件数据访问层(2026-07-01 新增)** |', - '| `data-access-review.ts` | **M3 审核工作流数据访问层(2026-07-01 新增)** |', - '| `data-access-comments.ts` | **M2 协同备课评论数据访问层(2026-07-01 新增)** |', - '| `data-access-formative.ts` | **M5 形成性评价数据访问层(2026-07-01 新增)** |', - '| `data-access-attachments.ts` | **M6 资源附件库数据访问层(2026-07-01 新增)** |', - '| `data-access-substitutes.ts` | **M12 代课教师数据访问层(2026-07-01 新增)** |', - '| `data-access-ai-evaluation.ts` | **M8 AI 评估数据访问层(2026-07-01 新增)** |', - '| `data-access-analytics.ts` | **M10 备课分析仪表盘数据访问层(2026-07-01 新增)** |', - '| `actions-calendar.ts` | **M9 日历 Server Actions(2026-07-01 新增)** |', - '| `actions-review.ts` | **M3 审核工作流 Server Actions(2026-07-01 新增)** |', - '| `actions-comments.ts` | **M2 评论 Server Actions(2026-07-01 新增)** |', - '| `actions-formative.ts` | **M5 形成性评价 Server Actions(2026-07-01 新增)** |', - '| `actions-attachments.ts` | **M6 附件库 Server Actions(2026-07-01 新增)** |', - '| `actions-substitutes.ts` | **M12 代课教师 Server Actions(2026-07-01 新增)** |', - '| `actions-ai-evaluation.ts` | **M8 AI 评估 Server Actions(2026-07-01 新增)** |', - '| `actions-analytics.ts` | **M10 分析仪表盘 Server Actions(2026-07-01 新增)** |', - '', - '> 架构变更(2026-07-01,M1-M12 中长期计划完整实施):', - '> - **M1 课标对标体系**:新增 modules/standards/ 模块;新增 3 个 STANDARD_* 权限点;新增路由 /admin/curriculum-map', - '> - **M2 协同备课评论**:新增 data-access-comments.ts + actions-comments.ts,支持 Block 级评论、resolved 状态', - '> - **M3 审核工作流**:新增 data-access-review.ts + actions-review.ts,状态机 draft → submitted → approved/rejected → published', - '> - **M4 课程地图**:新增 admin/curriculum-map 路由 + curriculum-map-view.tsx 热力图组件', - '> - **M5 形成性评价闭环**:新增 data-access-formative.ts + actions-formative.ts,4 种互动类型', - '> - **M6 资源附件库**:新增 data-access-attachments.ts + actions-attachments.ts', - '> - **M7 移动端 PWA**:见 1.1.1 章节', - '> - **M8 AI 差异化生成 + 评估**:新增 data-access-ai-evaluation.ts + actions-ai-evaluation.ts', - '> - **M9 日历视图**:新增 data-access-calendar.ts + actions-calendar.ts + calendar-view.tsx + teacher/lesson-plans/calendar 路由', - '> - **M10 备课分析仪表盘**:新增 data-access-analytics.ts + actions-analytics.ts,3 个分析维度', - '> - **M11 版本 diff 预览**:data-access-versions.ts 的 getVersionContent 支持读取历史版本内容', - '> - **M12 代课教师**:新增 data-access-substitutes.ts + actions-substitutes.ts', - '> - **权限扩展**:新增 STANDARD_READ/MANAGE/LINK + LESSON_PLAN_SUBMIT/REVIEW/ANALYTICS_READ/SUBSTITUTE_MANAGE', - '> - **i18n 扩展**:zh-CN 新增 9 个命名空间;status 扩展为 6 状态', - '> - **数据库表**:新增 6 张表(lessonPlanComments/lessonPlanReviewRecords/lessonPlanFormativeItems/lessonPlanAttachments/lessonPlanAiEvaluations/lessonPlanSubstituteAssignments)', - '', - '---', - '', - '## 2.27b standards(课标模块,2026-07-01 新增)', - '', - '**职责**:K12 课标管理,支持课标树、按学科+年级筛选、课案与课标多对多关联。', - '', - '**导出函数**:', - '- Data-access:getStandards / getStandardsTree / getStandardById / createStandard / updateStandard / deactivateStandard / searchStandards / getStandardsByPlanId / linkPlanToStandard / unlinkPlanFromStandard', - '- Actions:10 个 Server Actions,全部使用 requirePermission() + ActionState', - '- Schema:createStandardSchema / updateStandardSchema / getStandardsParamsSchema / linkPlanToStandardSchema', - '- Types:Standard / StandardTreeNode / LessonPlanStandardLink', - '', - '**权限点**:', - '- STANDARD_READ(standard:read)', - '- STANDARD_MANAGE(standard:manage)', - '- STANDARD_LINK(standard:link)', - '', - '**依赖关系**:', - '- 依赖:shared/*、modules/lesson-preparation/lib/i18n-errors', - '- 被依赖:modules/lesson-preparation、app/(dashboard)/admin/curriculum-map', - '', - '**文件清单**:', - '| 文件 | 职责 |', - '|------|------|', - '| types.ts | 类型定义 |', - '| schema.ts | Zod 验证 |', - '| data-access.ts | 课标 CRUD + 树形查询 + 课案关联 |', - '| actions.ts | 10 个 Server Actions |', - '', - '---', - '', - '## 2.28 error-book(错题本模块)' -]; -const newString = newLines.join('\r\n'); - -if (!content.includes(oldString)) { - console.error('ERROR: old string not found'); - process.exit(1); -} -const occurrences = content.split(oldString).length - 1; -if (occurrences !== 1) { - console.error('ERROR: appears ' + occurrences + ' times'); - process.exit(1); -} - -const newContent = content.replace(oldString, newString); -fs.writeFileSync(filePath, newContent, 'utf8'); -console.log('SUCCESS 004 updated, before=' + content.length + ' after=' + newContent.length); diff --git a/docs/mockups/editor-layout-comparison.html b/docs/mockups/editor-layout-comparison.html new file mode 100644 index 0000000..2de3fa6 --- /dev/null +++ b/docs/mockups/editor-layout-comparison.html @@ -0,0 +1,637 @@ + + + + + +备课编辑器 · 正文节点布局对比 + + + +
+
+

备课编辑器 · 正文节点布局对比

+

三种交互形态对比。共同前提:正文节点变成真实的富文本编辑器(Tiptap),支持加粗/标题/列表/图片真实排版,锚点用 Mark 系统而非字符串偏移。三种方案只差在"正文和教学节点如何排布"。

+
+
教材正文
+
教学目标
+
新授
+
练习
+
总结
+
锚点标记
+
+
+ +
+ + +
+
+ 方案 A +

保留画布 · 正文节点变真实编辑器

+

最小改动。React Flow 画布不变,把中央那个 520px 假正文框换成真正的 Tiptap 富文本编辑器卡片,可拖拽缩放到更大。

+
+
+
+
+ + + 已保存 +
+
+
+ +
+ 教学目标 +
+
+ 新授 +
+ +
+
+ 📖 教材正文(可编辑副本) + 右键锚定 +
+
+ 第一章 · 走进大自然 + 春天的轻轻吹过田野, + 带来泥土的芬芳。 +
+ 观察要点: +
• 花朵的颜色变化 +
叶片的形状 +
• 气温的回升 +
+
+ BI + H1 + 🖼 +
+
+ +
+ 课堂练习 +
+
+ 总结 +
+ +
+
+
+
+
选中节点
+
+
+
+
+
+
+
+
+
✓ 优点
+
    +
  • 改动最小,画布交互不变
  • +
  • 保留"思维导图"式空间关系
  • +
  • 锚点系统改造可独立进行
  • +
+
+
+
✗ 缺点
+
    +
  • 长文档在画布上仍受限,需频繁缩放
  • +
  • 编辑器卡片和教学节点抢空间
  • +
  • 移动端几乎不可用
  • +
+
+
+
+
+ + +
+
+ 方案 B +

文档流为主(类 Notion)

+

正文和教学节点都在同一文档流里,按顺序拼成一篇完整教案。左侧大纲,中间文档,右侧选中节点详情。

+
+
+
+
+ + + 已保存 +
+
+
+
大纲
+
正文
+
目标
+
新授
+
练习
+
总结
+
+
+
+
+
📖 教材正文
+ 第一章 · 走进大自然
+ 春天的轻轻吹过田野,带来泥土的芬芳。 + 叶片的形状 +
+
+
🎯 教学目标
+ 认识春天的自然现象… +
+
+
📚 新授
+ 引导学生观察… +
+
+
✏ 课堂练习
+ 画一画你看到的春天… +
+
+
+
+
选中: 新授
+
+
+
+
+
+
+
+
+
✓ 优点
+
    +
  • 编辑体验最好,长文档自然滚动
  • +
  • 所见即所得,适合打印导出
  • +
  • 移动端友好
  • +
  • 教学节点和正文同流,关系清晰
  • +
+
+
+
✗ 缺点
+
    +
  • 失去"画布"的空间思维导图感
  • +
  • 需要重构数据模型(节点顺序流)
  • +
  • 锚点仍需跨"正文块"定位
  • +
+
+
+
+
+ + +
+
+ 方案 C +

双栏 · 正文编辑器 + 节点面板

+

正文富文本编辑器独占主区域(类 A4 文档页),教学节点在右侧面板编辑,左侧是节点树。正文与节点通过锚点关联,互不混排。

+
+
+
+
+ + + 已保存 +
+
+
+
节点树
+
📖 正文
+
🎯 目标
+
📚 新授
+
✏ 练习
+
📝 总结
+
+
+
+
第一章 · 走进大自然
+ 春天的轻轻吹过田野,带来泥土的芬芳。 +

+ 观察要点: +
• 花朵的颜色变化 +
叶片的形状 +
• 气温的回升 +
+ B + I + H1 + + 🖼 +
+
+
+
+
🎯 教学目标
+
+
+
+
+ AI 生成
+
+
+
+
+
+
✓ 优点
+
    +
  • 正文编辑区最大、最专注
  • +
  • 正文与节点分离,职责清晰
  • +
  • 锚点只在正文里,定位简单
  • +
  • 保留节点树导航,不丢结构
  • +
+
+
+
✗ 缺点
+
    +
  • 失去画布的连线/空间感
  • +
  • 节点间关系靠树而非图表达
  • +
  • 需要新增"节点树"组件
  • +
+
+
+
+ ★ 推荐:在"正文必须好编辑"这个核心诉求下,C 兼顾了编辑体验和结构清晰,改动量适中。 +
+
+
+ +
+ +
+

三种方案的正文节点都是真正的 Tiptap 富文本编辑器,区别只在布局。锚点系统统一从"字符串偏移"改为 Tiptap Mark,编辑时锚点自动跟随。

+
+
+ + diff --git a/docs/mockups/paper-detail-expanded.html b/docs/mockups/paper-detail-expanded.html new file mode 100644 index 0000000..bc77e75 --- /dev/null +++ b/docs/mockups/paper-detail-expanded.html @@ -0,0 +1,938 @@ + + + + + +备课编辑器 · 统一展开 + 详情面板 + + + + + + +
+ +
+ + 二年级 · 语文 + 人教版 · 上册 +
+ 已保存 · 14:32 + + + + + +
+ +
+ + + + + +
+
+ +
+ 教材正文 · 可编辑副本 + 3 节点已展开 +
+ +

1 走进大自然

+

—— 选自人教版二年级上册

+ +

春天的轻轻吹过田野,带来泥土的芬芳。柳枝抽出嫩芽,小草从泥土里探出头来,燕子也从南方飞回来了

+ + +
+
+ + 教学目标 + A · B + 收起 ▴ +
+

感受四季变化

+
+
    +
  • 认识"春、夏、秋、冬"四个生字,会写"风、燕、荷、稻"等 12 个字。
  • +
  • 正确、流利、有感情地朗读课文,背诵第一自然段。
  • +
  • 感受四季的美丽,培养观察自然的兴趣。
  • +
+
+
+ +

夏天,雷雨过后,天空中常常会出现一道美丽的彩虹。池塘里的荷花开了,青蛙在荷叶上1呱呱地唱歌。

+ + +
+
+ + 师生互动 + C · 1 + 收起 ▴ +
+

感受夏天的声音

+
+

围绕"雷雨后的夏天"展开问答,引导学生用感官词描述季节。

+
+
+
+
+ 课文中说"青蛙在荷叶上呱呱地唱歌",你还听过夏天有哪些声音? + [预期:蝉鸣、雷声、雨打芭蕉] +
+
+
+
+
+ 我听过知了在树上"知了知了"地叫,还有晚上蛐蛐的声音。 +
+
+
+
+
+ 说得真好!那这些声音给你什么样的感觉?能用一个词形容吗? + [预期:热闹、生机勃勃] +
+
+
+
+
+ +

观察要点

+ +
    +
  • 花朵的颜色变化:从早到晚,颜色会有什么不同?
  • +
  • 2 叶片的形状:心形、针形、掌状……
  • +
  • 气温的回升:用温度计记录一周的气温。
  • +
+ +

秋天,树叶变黄了,一片片飘落下来,像一封封金色的信。田野里,稻谷弯下了腰,3农民伯伯露出了丰收的喜悦。

+ + +
+
+ + 课堂练习 + D + 收起 ▴ +
+

仿写:金色的信

+
+

模仿"树叶变黄了,一片片飘落下来,像一封封金色的信",写一句自己观察到的秋天。

+
    +
  • 提示:可以用"像"字打比方
  • +
  • 时间:8 分钟
  • +
  • 分享:3 位同学朗读
  • +
+
+
+ +

冬天,雪花纷纷扬扬地飘落,大地披上了银装。孩子们在雪地里堆雪人、打雪仗。

+ +
+ + +
+
节点操作
+
+ + 展开到正文 + +
+
+ + 从正文收起 +
+
+ + 上移 / 下移 +
+
+
AI 协助
+
+ + 生成本节点内容 +
+
+ + 优化表达 +
+
+ + 差异化建议 +
+
+ ? + 生成分层提问 +
+
+
+ + 复制节点 +
+
+ × + 删除节点 + +
+
+ +
+ + + + +
+
+ + diff --git a/docs/mockups/paper-sticky-design.html b/docs/mockups/paper-sticky-design.html new file mode 100644 index 0000000..3c41b35 --- /dev/null +++ b/docs/mockups/paper-sticky-design.html @@ -0,0 +1,799 @@ + + + + + +备课编辑器 · 无边记纸感设计 + + + + + + +
+ + +
+ +
+ 二年级 · 语文 + 人教版 · 上册 +
+
+ 已保存 · 14:32 + + + + + + +
+ +
+ + + + + +
+
+ + +
+ + + + + + + + + + + +
+ +
+ 教材正文 · 可编辑副本 + 第 1 / 3 页 +
+ +

1 走进大自然

+

—— 选自人教版二年级上册

+ +

春天的轻轻吹过田野,带来泥土的芬芳。柳枝抽出嫩芽,小草从泥土里探出头来,燕子也从南方飞回来了

+ +

夏天,雷雨过后,天空中常常会出现一道美丽的彩虹。池塘里的荷花开了,青蛙在荷叶上1呱呱地唱歌。

+ +

观察要点

+ +
    +
  • 花朵的颜色变化:从早到晚,颜色会有什么不同?
  • +
  • 2 叶片的形状:心形、针形、掌状……
  • +
  • 气温的回升:用温度计记录一周的气温。
  • +
+ +

秋天,树叶变黄了,一片片飘落下来,像一封封金色的信。田野里,稻谷弯下了腰,3农民伯伯露出了丰收的喜悦。

+ +

冬天,雪花纷纷扬扬地飘落,大地披上了银装。孩子们在雪地里堆雪人、打雪仗,

+ +
+
+ + + + +
+
+ + diff --git a/docs/mockups/paper-sticky-expanded.html b/docs/mockups/paper-sticky-expanded.html new file mode 100644 index 0000000..82ba756 --- /dev/null +++ b/docs/mockups/paper-sticky-expanded.html @@ -0,0 +1,882 @@ + + + + + +备课编辑器 · 节点展开与师生交互 + + + + + + +
+ +
+ + 二年级 · 语文 + 人教版 · 上册 +
+ 已保存 · 14:32 + + + + + +
+ +
+ + + + + +
+
+ +
+ 教材正文 · 可编辑副本 + 2 个节点已展开到正文 +
+ +

1 走进大自然

+

—— 选自人教版二年级上册

+ +

春天的轻轻吹过田野,带来泥土的芬芳。柳枝抽出嫩芽,小草从泥土里探出头来,燕子也从南方飞回来了

+ +

夏天,雷雨过后,天空中常常会出现一道美丽的彩虹。池塘里的荷花开了,青蛙在荷叶上1呱呱地唱歌。

+ + +
+
+ + 师生互动 + C · 1 + 收起 ▴ +
+

感受夏天的声音

+
+

围绕"雷雨后的夏天"展开问答,引导学生用感官词描述季节。

+
+
+
+
+ 课文中说"青蛙在荷叶上呱呱地唱歌",你还听过夏天有哪些声音? + [预期:蝉鸣、雷声、雨打芭蕉] +
+
+
+
+
+ 我听过知了在树上"知了知了"地叫,还有晚上蛐蛐的声音。 +
+
+
+
+
+ 说得真好!那这些声音给你什么样的感觉?能用一个词形容吗? + [预期:热闹、生机勃勃、夏天的味道] +
+
+
+
+
+ +

观察要点

+ +
    +
  • 花朵的颜色变化:从早到晚,颜色会有什么不同?
  • +
  • 2 叶片的形状:心形、针形、掌状……
  • +
  • 气温的回升:用温度计记录一周的气温。
  • +
+ +

秋天,树叶变黄了,一片片飘落下来,像一封封金色的信。田野里,稻谷弯下了腰,3农民伯伯露出了丰收的喜悦。

+ + +
+
+ + 课堂练习 + D + 收起 ▴ +
+

仿写:金色的信

+
+

模仿"树叶变黄了,一片片飘落下来,像一封封金色的信",写一句自己观察到的秋天。

+
    +
  • 提示:可以用"像"字打比方
  • +
  • 时间:8 分钟
  • +
  • 分享:3 位同学朗读
  • +
+
+
+ +

冬天,雪花纷纷扬扬地飘落,大地披上了银装。孩子们在雪地里堆雪人、打雪仗。

+ +
+
+ + + + +
+
+ + diff --git a/docs/troubleshooting/known-issues.md b/docs/troubleshooting/known-issues.md index d162c32..96b1aa4 100644 --- a/docs/troubleshooting/known-issues.md +++ b/docs/troubleshooting/known-issues.md @@ -665,3 +665,32 @@ export function SubjectTabs({ subjects, currentSubjectId }: Props) { | 右键菜单触发对象区分 | inline-node 右键 = 节点菜单;正文右键 = 锚定菜单 | 任何右键都触发同一菜单 | | v3 锚点迁移失效提示 | ``(按 planId localStorage) | toast 一闪即逝 | + +### i18n 键缺失与中英文不同步 + +模块新增 t() 调用时,必须同步更新 zh-CN 和 en 两个语言文件,且键名必须完全一致(不能用 `week`/`weekView` 这种同义不同名的两套键)。 + +| 规则 | 正确写法 | 错误写法 | +|------|---------|---------| +| 嵌套路径不存在时需创建子对象 | JSON 中 `"version": { "diff": { "title": "..." } }` 对应 `t("version.diff.title")` | JSON 中 `"version"` 和 `"diff"` 是平级节,却调用 `t("version.diff.title")` → MISSING_MESSAGE | +| Zod schema 错误键必须存在于 JSON `error` 节 | `z.string().min(1, "error.labelTooLong")` + JSON `error.labelTooLong` 存在 | schema 引用 `error.labelTooLong` 但 JSON 中无此键 → 校验失败时显示键路径 | +| zh-CN 与 en 键名必须完全一致 | zh-CN `calendar.weekView` + en `calendar.weekView` | zh-CN `calendar.weekView` + en `calendar.week` → en locale 下 MISSING_MESSAGE | +| 禁止 JSX 中硬编码中文 | `label={t("v4.detail.stageLabel")}` | `label="教学阶段"` → en 用户看到中文 | +| 未启用 useTranslations 的组件如需展示文本,必须先引入 | `import { useTranslations } from "next-intl"; const t = useTranslations("lessonPreparation");` | 组件内直接写中文字面量 | + +### i18n dead 节清理规则 + +语言文件中未被任何 `t()` 调用引用的节(dead keys)应定期清理,避免 zh-CN 与 en 各持不同 schema 导致维护混乱。清理前必须全代码库搜索(含 `src/app/`),确认无引用。 + +| 规则 | 正确写法 | 错误写法 | +|------|---------|---------| +| 删除 dead 节前必须验证全代码库无引用 | `grep -r "t(\"review." src/` 无结果后删除 | 直接删除节,导致隐藏引用方 MISSING_MESSAGE | +| zh-CN 和 en 键集必须完全一致 | 两文件均保留 `analytics` 节且键名相同 | zh-CN 有 `analytics.totalPublished`,en 只有 `analytics.publishedPlans` | + +### i18n 动态键翻译守卫 + +Zod schema 中存储的 i18n 键(如 `"error.titleRequired"`)在服务端翻译时,必须先用 `t.has()` 守卫检查键是否存在,避免 schema 误写不存在的键时抛出 MISSING_MESSAGE。 + +| 规则 | 正确写法 | 错误写法 | +|------|---------|---------| +| 动态键翻译前必须用 t.has() 守卫 | `if (t.has(msg)) { return t(msg); } return msg;` | `return t(msg);` — 键不存在时抛 MISSING_MESSAGE |