text-editor-feature-design.md 23 KB

文本编辑器功能设计文档

1. 项目概述

1.1 背景与目标

在 Axonix 平台中,添加类似豆包的富文本编辑器功能,服务于以下场景:

  1. mod-chat:用户在聊天过程中,可将 AI 生成的文档内容直接打开进行编辑、保存
  2. 工作流 + Word 模板:工作流中上传指定 Word 模板,系统根据模板生成文档,用户可在编辑器中打开、修改、下载,下载后的文档格式与原模板一致
  3. oil-agent 跨平台:同一套编辑器组件可在 oil-agent 平台通过免登录方式使用

1.2 核心价值

  • 无缝衔接工作流与编辑:工作流生成的文档可直接在编辑器中打开,无需下载再用 Word 打开
  • 格式保真:基于 Word 模板生成的文档,下载后字体、标题样式、页眉页脚等与模板完全一致
  • 跨平台复用:一套编辑器组件同时服务 mod-chat 和 oil-agent

1.3 技术栈概览

层次 技术
前端框架 React 18 + TypeScript + Vite + Ant Design
编辑器核心 Slate.js
状态管理 Zustand
后端框架 FastAPI(Python 3.10+)
ORM SQLAlchemy 2.0
数据库 PostgreSQL

2. 演进路线总览

阶段 0  打通基础链路(当前)
        mod-chat 中 AI 生成文档 → 编辑器打开 → 编辑 → 保存回 Chat
        约 1.5 周

阶段 1  Word 模板 + 工作流文档编辑(近期目标)
        上传 Word 模板 → 工作流生成文档 → 编辑器打开编辑 → 下载保持模板格式
        约 2 周

阶段 2  oil-agent 跨平台集成
        编辑器微前端化 → oil-agent 免登录接入 → 跨平台数据同步
        约 2 周

阶段 3  编辑器增强 + 协同编辑
        富文本增强、版本管理、实时多人协同
        约 4 周

3. 阶段 0:打通基础链路

3.1 目标

跑通 mod-chat 中"AI 生成文档 → 编辑器打开 → 编辑 → 保存回 Chat"的完整闭环。

3.2 功能范围

  1. 从 Chat 打开编辑器

    • 识别聊天消息中的 Markdown 内容
    • 点击消息右上角"编辑"按钮,弹出编辑器 Modal
    • 加载消息内容到编辑器
  2. 基础编辑器

    • Markdown 文本编辑(Slate.js)
    • 实时预览(分屏)
    • 防抖自动保存:小文件(< 200KB)防抖 3 秒直接推后端;大文件(≥ 200KB)写入 IndexedDB 缓存,手动保存时再同步
  3. 保存并下载

    • 点击"保存"按钮,弹出保存对话框
    • 对话框中填写文件名,选择文件格式(阶段 0 仅支持 .doc
    • 前端提交文件名、格式和文档内容到后端
    • 后端生成文件,返回下载链接
    • 前端根据下载链接自动触发浏览器下载
  4. 文档 API

    • 创建文档(POST /api/v1/documents)
    • 读取文档(GET /api/v1/documents/{id})
    • 更新文档(PUT /api/v1/documents/{id})
    • 导出下载(POST /api/v1/export/doc)

3.3 不做的事情

  • ❌ Word 模板处理(阶段 1)
  • ❌ 保持模板格式的 DOCX 导出(阶段 1)
  • ❌ oil-agent 集成 / Token 机制(阶段 2)
  • ❌ 版本管理 / 协同编辑(阶段 3)
  • ❌ Redis / S3 等外部存储(文档内容直接存 DB text 字段,上限 200KB)

3.4 架构

详见 技术架构文档 - 阶段 0

3.5 核心交互流程

用户在 Chat 中查看 AI 生成的文档
    ↓
点击"编辑"按钮
    ↓
POST /api/v1/documents  创建文档记录,获取 documentId
    ↓
打开编辑器 Modal,加载文档内容
    ↓
用户编辑 → 计算变动块(标题 level + index)→ 写入本地缓存
    ↓
判断文档大小
    ├── 小文件(< 200KB)→ 防抖 3s → PUT /api/v1/documents/{id}(局部块更新)
    └── 大文件(≥ 200KB)→ 仅写 IndexedDB,不自动推后端
    ↓
点击"保存"按钮 → 弹出保存对话框
    ↓
用户填写文件名,选择格式(.doc)→ 确认
    ↓
POST /api/v1/export/doc  提交文件名、格式、文档内容
    ↓
后端生成 .doc 文件,返回下载链接
    ↓
前端自动触发浏览器下载

3.6 保存对话框交互

┌─────────────────────────────────┐
│         保存文档                 │
├─────────────────────────────────┤
│  文件名  [季度报告_2026Q2      ] │
│  格式    [.doc            ▼   ] │
│          (目前仅支持 .doc)      │
├─────────────────────────────────┤
│              [取消]  [确认下载]  │
└─────────────────────────────────┘

3.7 前端组件结构

mod-chat/src/
  components/
    editor/
      DocumentEditor.tsx     // 编辑器 Modal 主组件
      EditorToolbar.tsx       // 工具栏(含保存按钮)
      EditorPreview.tsx       // Markdown 分屏预览
      SaveDialog.tsx          // 保存对话框(文件名 + 格式选择)
  store/
    editorStore.ts            // 编辑器 Zustand store
  api/
    documentApi.ts            // 文档 API 封装
    exportApi.ts              // 导出下载 API 封装

3.8 后端文件结构

backend/
  app/
    main.py                  // FastAPI 应用入口,注册路由
    config.py                // 环境变量配置(DB URL 等)
    core/
      database.py            // AsyncSession 连接池
      dependencies.py        // get_db 依赖注入
      exceptions.py          // 自定义异常 + 全局 handler
    models/
      document.py            // documents 表 ORM 模型
    schemas/
      document.py            // DocumentCreate / Update / Response
    services/
      document_service.py    // CRUD 业务逻辑
      export_service.py      // .doc 文件生成
    api/
      v1/
        documents.py         // CRUD 路由(5 个端点)
        export.py            // 导出下载路由(1 个端点)
  migrations/
    versions/
      001_init.py            // 建表迁移(Alembic)
  requirements.txt
  .env.example

3.9 排期

任务 预计工时
编辑器组件搭建(Slate.js 集成) 3 天
文档 CRUD API(FastAPI + PostgreSQL) 2 天
保存对话框 + 导出 .doc API 2 天
Chat 集成(打开编辑器) 1 天
联调测试 1 天
合计 约 1.5 周

4. 阶段 1:Word 模板 + 工作流文档编辑

4.1 目标

支持工作流上传 Word 模板,工作流根据模板生成文档后,用户可在编辑器中打开、修改,并下载,下载后的 DOCX 文件格式、字体、标题样式与原模板完全一致

4.2 功能范围

  1. Word 模板管理

    • 工作流上传 Word 模板(.docx)
    • 后端解析模板,提取样式表(标题级别、字体、页边距、页眉页脚等)
    • 模板与工作流关联存储
  2. 工作流生成文档

    • 工作流根据模板 + 业务数据生成文档内容,存入 documents 表
    • 文档记录关联对应的模板 ID
  3. 编辑器打开工作流文档

    • 从工作流入口打开编辑器,加载生成的文档内容
    • 编辑器渲染时应用模板样式(标题层级、字体显示)
    • 工具栏样式选项与模板中的样式对应
  4. 下载(保持模板格式)

    • 点击"下载",后端将编辑器内容 + 模板样式合并,生成 DOCX 文件
    • 下载的 DOCX 字体、段落格式、页眉页脚与原模板一致
    • 支持直接下载,不需要先上传到 CDN

4.3 不做的事情

  • ❌ PDF 导出(可在阶段 3 补充)
  • ❌ oil-agent 集成(阶段 2)
  • ❌ 版本管理(阶段 3)

4.4 架构

详见 技术架构文档 - 阶段 1

核心技术

  • python-docx:解析模板样式、生成最终 DOCX
  • docxtpl(可选):基于 Jinja2 模板语法填充变量,适合工作流场景

4.5 Word 模板处理流程

上传模板阶段:
  上传 .docx → 解析样式表(标题/正文/字体/间距)→ 存储元数据 + 原始文件

生成文档阶段:
  工作流触发 → 基于模板填充内容 → 生成文档记录(内容存 DB)

编辑器打开阶段:
  加载文档内容 → 查询关联模板样式 → 编辑器 UI 应用对应样式

下载阶段:
  读取编辑器最新内容 → 加载原始模板文件 → 用 python-docx 将内容写入模板 → 返回 DOCX 文件流

4.6 数据模型新增

// 模板表
interface DocumentTemplate {
  id: string;
  name: string;
  fileKey: string;          // 模板文件存储路径
  styles: {                 // 从模板解析出的样式元数据
    headings: HeadingStyle[];
    defaultFont: string;
    pageMargins: PageMargins;
    hasHeader: boolean;
    hasFooter: boolean;
  };
  createdAt: number;
}

// documents 表新增字段
interface Document {
  // ...原有字段
  templateId?: string;      // 关联模板 ID(工作流文档必填)
  source: 'chat' | 'workflow';
}

4.7 核心交互流程

工作流中上传 Word 模板
    ↓
后端解析模板样式,存储模板文件和元数据
    ↓
工作流根据业务数据 + 模板生成文档内容,POST /api/v1/documents(携带 templateId)
    ↓
用户点击"在编辑器中打开"
    ↓
编辑器加载文档内容,同时拉取模板样式,渲染时应用标题字体等样式
    ↓
用户修改内容 → 自动保存
    ↓
点击"下载" → POST /api/v1/export/docx
    ↓
后端:读取最新文档内容 + 加载原始模板 → python-docx 合并 → 返回 DOCX 文件流
    ↓
浏览器下载,文件格式与模板一致

4.8 前端文件结构(新增)

mod-chat/src/
  components/
    editor/
      TemplateStyleProvider.tsx  // 加载模板样式并注入 CSS 变量(新增)
      EditorToolbar.tsx           // 扩展:工具栏样式选项与模板标题级别对应
  api/
    templateApi.ts               // 模板信息查询 API 封装(新增)

4.9 后端文件结构(新增)

backend/app/
  models/
    document_template.py     // document_templates 表 ORM 模型(新增)
  schemas/
    template.py              // TemplateCreate / TemplateResponse(新增)
  services/
    template_service.py      // 模板上传、样式解析、文件存储(新增)
    export_service.py        // 扩展:新增 export_docx_with_template()
  api/
    v1/
      templates.py           // 模板管理路由(新增,2 个端点)
      export.py              // 扩展:新增 /export/docx 端点
  utils/
    docx_parser.py           // python-docx 样式解析工具函数(新增)

4.9 排期

任务 预计工时
模板上传 + 样式解析 API 2 天
工作流文档生成 API 1 天
编辑器应用模板样式(前端) 2 天
DOCX 下载导出(python-docx 合并) 2 天
联调测试 1 天
合计 约 2 周

5. 阶段 2:oil-agent 跨平台集成

5.1 目标

将编辑器组件微前端化,供 oil-agent 平台通过免登录 Token 接入,两个平台共用同一份文档数据。

5.2 功能范围

  1. 编辑器微前端化

    • 打包为 Module Federation 远程模块
    • 通过 Props 配置 API 端点、主题、权限
  2. 免登录 Token 机制

    • 生成临时访问 Token(JWT + Redis)
    • oil-agent 凭 Token 打开编辑器,访问指定文档
    • Token 有效期管理(默认 1 小时)
  3. 跨平台数据同步

    • 编辑完成后通过 Webhook 通知 oil-agent
    • oil-agent 接收事件后拉取最新文档

5.3 架构

详见 技术架构文档 - 阶段 2

5.4 核心交互流程

oil-agent 请求编辑某文档
    ↓
调用后端 POST /api/v1/edit-sessions,生成一次性 Token
    ↓
返回编辑器 URL(含 Token)
    ↓
oil-agent 打开新窗口,编辑器凭 Token 加载文档
    ↓
用户编辑保存 → 后端 Webhook 通知 oil-agent
    ↓
oil-agent 拉取最新文档内容

5.5 前端文件结构(新增)

mod-editor/src/                      // 新建独立微前端包
  components/
    editor/
      DocumentEditor.tsx             // 从 mod-chat 迁移,支持 platform prop
      EditorToolbar.tsx
      EditorPreview.tsx
      SaveDialog.tsx
  transport/
    EditorTransport.ts               // SSE / WebSocket 通信适配层(新增)
  store/
    editorStore.ts
  api/
    documentApi.ts
    exportApi.ts
    editSessionApi.ts                // Token 会话 API 封装(新增)
  vite.config.ts                     // Module Federation 打包配置(新增)

5.6 后端文件结构(新增)

backend/app/
  core/
    cache.py                 // Redis 连接池(新增)
  models/
    edit_session.py          // edit_sessions 表 ORM 模型(新增)
  schemas/
    edit_session.py          // CreateEditSessionRequest / Response(新增)
  services/
    token_service.py         // JWT 生成/验证/撤销 + Redis 双重校验(新增)
    webhook_service.py       // 触发 Webhook、签名、重试(新增)
  api/
    v1/
      edit_sessions.py       // Token 会话路由(新增,3 个端点)
      webhooks.py            // Webhook 配置路由(新增)

5.6 排期

任务 预计工时
Module Federation 打包配置 1 天
Token 服务(JWT + Redis) 2 天
编辑会话 API 1 天
Webhook 通知 1 天
oil-agent 接入联调 2 天
合计 约 2 周

6. 阶段 3:编辑器增强 + 协同编辑

6.1 目标

提升编辑器的编辑体验,并在有需要时支持多人实时协同。

6.2 功能范围

  1. 富文本增强

    • 完整格式工具栏(H1-H6、粗体、斜体、列表、代码块、引用块、表格)
    • 快捷键(Ctrl+B / Ctrl+I 等)
    • 撤销/重做、字数统计、查找替换
    • 图片上传插入
  2. PDF 导出

    • 导出为 PDF(weasyprint)
  3. 版本管理

    • 文档版本历史列表
    • 回滚到指定版本
    • 版本对比(Diff)
  4. 实时协同(可选,按需启用)

    • 多人同时编辑(Yjs CRDT + WebSocket)
    • 实时光标显示、在线用户列表
    • 冲突解决可视化

6.3 架构

阶段 3 完整架构图见 技术架构文档 - 阶段 3,新增依赖:Yjs、y-websocket、S3/MinIO(大文档迁移)、API Gateway。

6.4 前端文件结构(新增)

mod-editor/src/
  components/
    editor/
      CollabCursors.tsx            // 协同光标渲染(在线用户实时位置)(新增)
      OnlineUserList.tsx           // 在线用户列表展示(新增)
    toolbar/
      FormatToolbar.tsx            // 完整富文本工具栏(H1-H6、代码块、表格等)(新增)
      FindReplacePanel.tsx         // 查找替换面板(新增)
    version/
      VersionHistoryPanel.tsx      // 版本历史列表(新增)
      VersionDiffView.tsx          // 两版本对比 Diff 视图(新增)
  plugins/
    withCollaboration.ts           // Slate + Yjs 协同插件(新增)
    withHistory.ts                 // 撤销/重做扩展
    withImages.ts                  // 图片上传插入插件(新增)
  api/
    versionApi.ts                  // 版本历史 API 封装(新增)
    exportApi.ts                   // 扩展:新增 PDF 导出

6.5 后端文件结构(新增)

backend/app/
  models/
    document_version.py            // document_versions 表 ORM 模型(新增)
  schemas/
    version.py                     // VersionResponse / DiffResponse(新增)
  services/
    version_service.py             // 版本快照、回滚、Diff 逻辑(新增)
    collab_service.py              // y-websocket 会话管理(新增)
    export_service.py              // 扩展:新增 export_pdf()
  api/
    v1/
      versions.py                  // 版本管理路由(新增,3 个端点)
      export.py                    // 扩展:新增 /export/pdf 端点
      collab.py                    // WebSocket 协同端点(新增)

6.6 排期

任务 预计工时
富文本工具栏增强 3 天
PDF 导出 2 天
版本管理(DB 设计 + API + 前端) 3 天
实时协同(Yjs + WebSocket) 5 天
合计 约 3-4 周

7. 数据模型汇总

7.1 documents 表

字段 类型 说明
id string 文档唯一 ID
title string 标题
content text 文档内容(Markdown / JSON),上限 200KB
format string markdown(阶段 0/1);阶段 3 支持 json
template_id string 关联模板 ID,工作流文档必填(阶段 1 引入)
source string chat / workflow
session_id string 关联聊天会话 ID(可选)
created_by string 创建者
created_at timestamp
updated_at timestamp

7.2 document_templates 表(阶段 1 引入)

字段 类型 说明
id string 模板唯一 ID
name string 模板名称
file_key string 模板文件存储路径
styles jsonb 解析出的样式元数据
created_at timestamp

7.3 edit_sessions 表(阶段 2 引入)

字段 类型 说明
id string 会话 ID
document_id string 文档 ID
token_hash string Token 哈希(不存明文)
platform string mod-chat / oil-agent
status string active / closed
expires_at timestamp

8. API 汇总

接口 方法 引入阶段 说明
/api/v1/documents POST 阶段 0 创建文档
/api/v1/documents/{id} GET 阶段 0 获取文档
/api/v1/documents/{id} PUT 阶段 0 更新文档
/api/v1/documents/{id} DELETE 阶段 0 删除文档
/api/v1/export/doc POST 阶段 0 导出 .doc 并返回下载链接
/api/v1/templates POST 阶段 1 上传 Word 模板
/api/v1/templates/{id} GET 阶段 1 获取模板信息
/api/v1/export/docx POST 阶段 1 下载 DOCX(保持模板格式)
/api/v1/edit-sessions POST 阶段 2 创建编辑会话,返回 Token
/api/v1/edit-sessions/{id}/document GET 阶段 2 凭 Token 获取文档
/api/v1/edit-sessions/{id} DELETE 阶段 2 关闭会话
/api/v1/export/pdf POST 阶段 3 导出 PDF
/api/v1/documents/{id}/versions GET 阶段 3 版本历史

9. 前端本地存储与同步策略

9.1 大小文件判断与同步方向

200KB 为分界线:

文档大小 自动保存行为
小文件(< 200KB) 防抖 3 秒后直接 PUT 到后端,本地不做额外缓存
大文件(≥ 200KB) 写入前端 IndexedDB 缓存,不立即推后端;用户手动点"保存"时才同步到后端

9.2 存储分层

存储类型 用途 说明
Cookies 小型临时状态 存储编辑器 UI 状态(当前 documentId、预览模式开关等),TTL 与会话一致
localStorage 小文件草稿块缓存 按标题块存储变更内容,key 格式见 9.3,浏览器关闭后仍保留
IndexedDB 大文件内容缓存 存储 ≥ 200KB 的文档内容,异步读写,不阻塞主线程

9.3 局部更新策略(按标题等级)

不管文档大小,每次编辑都按标题等级定位到具体块做局部更新,而不是全量覆盖整个文档。

块的定义:以标题节点(H1/H2/H3...)为分割点,每个标题及其下属正文构成一个块,用"第 N 个 K 级标题"来唯一定位。

文档结构示例:
  # 第一章          ← H1[0]
    ## 1.1 背景     ← H2[0]
    ## 1.2 目标     ← H2[1]
  # 第二章          ← H1[1]
    ## 2.1 方案     ← H2[2]

用户只修改了"1.2 目标"下的正文
    ↓
定位到块:{ level: 2, index: 1 }  即"第 2 个 H2 标题"
    ↓
只更新该块,其余块不变

本地存储 key 格式

localStorage key:  doc:{documentId}:h{level}:{index}
示例:              doc:doc-abc123:h2:1

后端局部更新请求(见 API 文档 2.3):

{
  "blocks": [
    {
      "level": 2,
      "index": 1,
      "content": "更新后的内容..."
    }
  ]
}

9.4 自动保存完整流程

用户编辑内容
    ↓
计算变动块(level + index)
    ↓
写入 localStorage(小文件)或 IndexedDB(大文件)
    ↓
判断文档大小
    ├── 小文件(< 200KB)
    │     防抖 3 秒 → PUT /api/v1/documents/{id}(携带变动块)
    │     后端更新成功 → 清除对应本地缓存块
    │     后端更新失败 → 保留缓存,下次打开时提示"有未同步的草稿"
    │
    └── 大文件(≥ 200KB)
          只写 IndexedDB,不自动推后端
          用户手动点"保存" → 全量或按块同步到后端

9.5 打开编辑器时的恢复逻辑

打开编辑器,传入 documentId
    ↓
检查 localStorage / IndexedDB 是否有本地缓存块
    ├── 有缓存 → 对比本地 updatedAt 与服务端 updatedAt
    │           ├── 本地更新 → 提示"发现未同步的草稿,是否恢复?"
    │           │             用户确认 → 合并本地块覆盖服务端内容
    │           │             用户拒绝 → 丢弃本地缓存,加载服务端内容
    │           └── 服务端更新 → 直接加载服务端内容,清除本地缓存
    └── 无缓存 → 直接从服务端加载文档内容

10. 风险与应对

风险 影响 应对措施
Word 模板样式复杂,解析不完整 下载格式与模板不一致 阶段 1 先支持标题/正文/字体基础样式,复杂样式(表格边框、页眉图片等)逐步覆盖
编辑器富文本节点与 DOCX 样式映射困难 导出排版错乱 建立明确的节点类型 ↔ DOCX 样式映射表,作为开发规范
大文档(> 200KB)阶段 0 无法存储 工作流生成超长文档时失败 阶段 0 强制限制,阶段 1 引入文件存储后解除
oil-agent Token 安全 数据泄露 JWT + Redis 双重验证,Token 与文档 ID 绑定,默认 1 小时过期
协同编辑并发冲突 数据不一致 引入成熟 CRDT 库(Yjs),阶段 3 单独评估

11. 附录

相关文档

参考资料


文档版本: v4.0 最后更新: 2026-06-11 维护者: Axonix 前端团队