# 块编辑器架构设计 ## 1. 当前架构 AX 前端是 React + TypeScript + Vite 单页应用。应用采用左右双面板布局:左侧为聊天面板,右侧根据 UI 状态显示导出记录或文档编辑器。 ```text main.tsx -> App -> ErrorBoundary -> ResizableLayout -> ChatPanel -> ExportRecordList / EditorPanel -> EditorWithOutline -> DocumentOutline -> BlockEditor -> MainToolbar -> BlockCanvas -> BlockRenderer ``` `ChatPanel`、`EditorPanel`、`ExportRecordList` 和 `SessionList` 由 `React.lazy` 按需加载。会话抽屉关闭时不会挂载 `SessionList`。 ## 2. 组件职责 | 模块 | 主要职责 | | ------------------- | ----------------------------------------------- | | `App.tsx` | 组装布局、切换右侧视图、管理会话抽屉和网络状态 | | `ResizableLayout` | 左右面板布局、拖拽调整和宽度持久化 | | `EditorPanel` | 编辑器面板外壳,保持 App 的集成接口 | | `EditorWithOutline` | 组合编辑器与可折叠文档大纲 | | `BlockEditor` | 加载文档、连接 store、显示工具栏和画布 | | `BlockCanvas` | 按 `block_order` 排序并渲染 blocks | | `BlockRenderer` | 按 `block.type` 分发具体块组件 | | `RichTextEditor` | 基于 `contenteditable` 的富文本编辑和选区工具栏 | | `TableBlock` | 表格渲染、选择、结构操作和尺寸调整 | ## 3. Block 数据模型 核心类型位于 `src/types/editor.ts`,当前支持: ```ts type BlockType = 'heading' | 'paragraph' | 'table' | 'image' | 'toc'; ``` 每个 block 至少包含 `id`、`block_order`、`type`、`level`、`index`、`word_style`、`style` 和 `metadata`。标题和段落的 `content` 可以是字符串或 `RichText[]`;表格 content 包含行、单元格和可选列宽;图片 content 是图片 Data URL;目录块由标题数据生成。 ## 4. 数据流 ```text MessageItem / ExportRecordList -> uiStore.openDocumentPreview -> App 选择 EditorPanel -> editorStore.loadDocument -> blockService.getBlocks -> blocks 按 block_order 排序 -> BlockCanvas 渲染 -> 用户修改 -> editorStore.updateBlock -> dirtyBlocks / hasModified -> 自动保存或 MainToolbar.saveDocument -> blockService.updateBlock / createBlock / deleteBlock ``` `editorStore` 负责加载、脏块追踪、自动保存、并发限制、失败重试、哈希比较和请求取消。自动保存默认在停止编辑 3 秒后触发,最多同时保存 3 个块。 ## 5. 表格结构算法 表格不能只用数组下标理解。`getTableVisualCellPositions` 会根据 `rowspan`、`colspan` 和隐藏单元格计算视觉坐标。合并、拆分、插入和删除操作先在视觉网格中确定范围,再由重建函数重建行和单元格。 修改表格功能时应遵循: 1. 先规范化旧数据,再计算视觉坐标。 2. 用视觉范围验证选择区域是否连续。 3. 重建后同步 `metadata.cols`、`metadata.rows` 和宽度数组。 4. 用保存后的数据再次渲染,检查合并单元格没有重复插入。 表格样式面板和表格边框控制组件已经移除。当前保留的是结构工具栏、单元格文本格式和垂直对齐能力。 ## 6. 导出和大依赖 - Word:`exportService` 调用后端 `/api/v1/export/doc`,再下载导出记录。 - Markdown:`clientExportService` 根据 blocks 在浏览器生成 Blob。 - PDF:点击导出后动态加载 `html2canvas` 和 `jspdf`。 - Word 内容解析:`documentContentService` 在需要时动态加载 `mammoth`。 不要将这些可选依赖改成入口静态导入,否则会增加首屏 JavaScript 和 TBT。 ## 7. 安全边界 `richTextConverter` 在生成 HTML 前会转义文本,并限制颜色和字体值格式。富文本解析使用临时 DOM,不应直接将未过滤的用户 HTML 传给 `dangerouslySetInnerHTML`。 前端只读取 `VITE_AI_PROXY_URL` 和 `VITE_WORKFLOW_PROXY_URL`,AI 与工作流上游密钥必须由后端代理保存和使用。任何 `VITE_*_API_KEY` 都会被打包到浏览器,不能配置为秘密。 ## 8. 性能决策 - 面板和会话列表懒加载。 - 生产构建使用 Oxc 和 Lightning CSS 压缩,关闭 source map。 - 分栏拖动使用 `requestAnimationFrame`,结束时才写入 `localStorage`。 - 图片预留宽高比例,并使用 lazy loading 和 async decoding。 - 长聊天消息使用 `content-visibility: auto`。 - 可选导出库保持动态导入。 ## 9. 变更原则 - 优先修改拥有状态或数据变换职责的模块,不在渲染层复制保存逻辑。 - 保持 `EditorPanelProps` 兼容,避免无关修改 `App.tsx`。 - 新增 block 类型时同步更新类型、渲染器、插入菜单、保存接口和导出逻辑。 - 任何表格算法变更都应覆盖无合并、横向合并、纵向合并和混合合并场景。