761 lines
27 KiB
Markdown
761 lines
27 KiB
Markdown
# MNOTE 当前架构梳理
|
||||
|
|
|
|||
|
|
本文只描述当前仓库中保留下来的主线结构,不再依赖已移动到 `/mnt/Data1T/mnote/recycle/` 的旧设计稿。
|
|||
|
|
|
|||
|
|
## 1. 当前保留的主线目录
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/`
|
|||
|
|
当前主前端,Next.js App Router,页面、编辑器、思维导图、OnlyOffice 页面都在这里。
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-backend/`
|
|||
|
|
当前辅助后端,FastAPI + Celery,主要提供补充服务能力。
|
|||
|
|
- `/mnt/Data1T/mnote/infra/convex/`
|
|||
|
|
Convex 自托管相关配置。
|
|||
|
|
- `/mnt/Data1T/mnote/src/components/onlyoffice/`
|
|||
|
|
根目录历史遗留,但当前仍保留,因为里面有 OnlyOffice 静态资源、插件和密钥数据。
|
|||
|
|
- `/mnt/Data1T/mnote/scripts/`
|
|||
|
|
启动与环境脚本。
|
|||
|
|
|
|||
|
|
## 2. 总体运行结构
|
|||
|
|
|
|||
|
|
当前主链路是:
|
|||
|
|
|
|||
|
|
1. 前端页面由 `/mnt/Data1T/mnote/wolai-frontend/src/app/**` 提供。
|
|||
|
|
2. 文档主页面进入 `DocumentShell -> DocumentContent -> BlockNoteEditor`,对应源码分别位于 `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-shell.tsx`、`/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx`、`/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx`。
|
|||
|
|
3. `BlockNoteEditor` 负责承载普通文档块、自定义块、思维导图块、在线表格块等。
|
|||
|
|
4. 思维导图有两种形态:
|
|||
|
|
- 作为 BlockNote 内嵌块存在于文档页面
|
|||
|
|
- 作为独立全屏页面存在于路由 `/mindmap/[docId]/[mindmapId]`,对应源码 `/mnt/Data1T/mnote/wolai-frontend/src/app/mindmap/[docId]/[mindmapId]/page.tsx`
|
|||
|
|
5. OnlyOffice 不嵌在 BlockNote 内部编辑,而是通过独立页面路由 `/onlyoffice` 打开,对应源码 `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/page.tsx`。
|
|||
|
|
6. 文档中的附件块如果识别为 Office 文档,会跳转到路由 `/onlyoffice` 页面进行编辑,对应页面实现 `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/OnlyOfficeClientPage.tsx`。
|
|||
|
|
|
|||
|
|
## 3. 前端主入口
|
|||
|
|
|
|||
|
|
### 3.1 根布局
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/layout.tsx`
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 注入运行时配置到 `window.__MNOTE_RUNTIME_CONFIG__`
|
|||
|
|
- 挂载 Convex Provider、Query Provider
|
|||
|
|
- 作为整个前端 App Router 的根布局
|
|||
|
|
|
|||
|
|
### 3.2 文档页面入口
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx`
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 根据文档 id 读取元数据
|
|||
|
|
- 组织只读、禁下载、禁复制等页面权限
|
|||
|
|
- 把文档上下文传给 `DocumentShell`,对应源码 `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-shell.tsx`
|
|||
|
|
|
|||
|
|
文档页真正的编辑器链路是:
|
|||
|
|
|
|||
|
|
`/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx` -> `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-shell.tsx` -> `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx` -> `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx`
|
|||
|
|
|
|||
|
|
## 4. BlockNote 位置与嵌入形式
|
|||
|
|
|
|||
|
|
### 4.1 BlockNote 主组件
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx`
|
|||
|
|
|
|||
|
|
这是当前文档编辑核心。
|
|||
|
|
|
|||
|
|
它负责:
|
|||
|
|
|
|||
|
|
- 创建 BlockNote 实例
|
|||
|
|
- 加载自定义 schema
|
|||
|
|
- 挂接 Slash Menu、Side Menu、TOC、评论、搜索引用、全屏表格桥接等
|
|||
|
|
- 承载普通文本块和自定义块
|
|||
|
|
|
|||
|
|
### 4.2 文档壳与内容层
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-shell.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx`
|
|||
|
|
|
|||
|
|
嵌入方式:
|
|||
|
|
|
|||
|
|
- `DocumentShell` 用动态导入方式挂载 `DocumentContent`
|
|||
|
|
- `DocumentContent` 再动态导入 `BlockNoteEditor`
|
|||
|
|
- 所以 BlockNote 是“文档页面中的主编辑器内核”,不是一个独立页面
|
|||
|
|
|
|||
|
|
### 4.3 BlockNote schema
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/schema.ts`
|
|||
|
|
|
|||
|
|
当前自定义 block 已明确注册在这里,包括:
|
|||
|
|
|
|||
|
|
- `mindmap`
|
|||
|
|
- `onlineTable`
|
|||
|
|
- `media`
|
|||
|
|
- `pageReference`
|
|||
|
|
- `blockReference`
|
|||
|
|
- `advancedTodo`
|
|||
|
|
- `progressMeter`
|
|||
|
|
|
|||
|
|
也就是说,思维导图和在线表格本质上都是 BlockNote 的自定义 block。
|
|||
|
|
|
|||
|
|
## 5. Mindmap 位置与嵌入形式
|
|||
|
|
|
|||
|
|
### 5.1 主组件
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapBlock.tsx`
|
|||
|
|
|
|||
|
|
这是思维导图前端主实现。
|
|||
|
|
|
|||
|
|
它同时承担:
|
|||
|
|
|
|||
|
|
- 内嵌块视图
|
|||
|
|
- 本地全屏视图
|
|||
|
|
- 独立页面全屏视图复用
|
|||
|
|
- 侧栏、工具栏、导航器、缩略图、计数器、右键菜单等整套 UI
|
|||
|
|
|
|||
|
|
### 5.2 作为 BlockNote 内嵌块
|
|||
|
|
|
|||
|
|
注册位置:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/schema.ts`
|
|||
|
|
|
|||
|
|
插入位置:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx`
|
|||
|
|
|
|||
|
|
嵌入方式:
|
|||
|
|
|
|||
|
|
- 在文档页面中,思维导图作为 `type: "mindmap"` 的 block 插入到 BlockNote 内容流里
|
|||
|
|
- 渲染时由 `mindmapBlock()` 对应到 `MindmapBlockView`
|
|||
|
|
- 这个块是“嵌在页面正文里的一大块交互式画布”
|
|||
|
|
|
|||
|
|
视觉与交互形态:
|
|||
|
|
|
|||
|
|
- 默认是页面中的内嵌卡片画布
|
|||
|
|
- 双击后可进入局部全屏模式
|
|||
|
|
|
|||
|
|
### 5.3 作为独立全屏页面
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/mindmap/[docId]/[mindmapId]/page.tsx`
|
|||
|
|
|
|||
|
|
嵌入方式:
|
|||
|
|
|
|||
|
|
- 这个页面不是重新实现一个思维导图编辑器
|
|||
|
|
- 而是直接复用 `MindmapBlockView`
|
|||
|
|
- 只用一个假的 `editorStub` 代替 BlockNote 编辑器上下文
|
|||
|
|
- 因此“文档内嵌思维导图”和“独立思维导图页”本质是同一套前端组件
|
|||
|
|
|
|||
|
|
### 5.4 Mindmap 相关子组件
|
|||
|
|
|
|||
|
|
主要都在:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/`
|
|||
|
|
|
|||
|
|
关键文件包括:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapToolbar.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapSidebar.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapNavigator.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapMiniMap.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapCount.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapContextMenu.tsx`
|
|||
|
|
|
|||
|
|
### 5.5 当前结论
|
|||
|
|
|
|||
|
|
Mindmap 的前端定位不是独立编辑器系统,而是:
|
|||
|
|
|
|||
|
|
- 以 BlockNote 自定义块为主形态
|
|||
|
|
- 以独立全屏页为辅助形态
|
|||
|
|
- 两者共用同一核心组件 `MindmapBlockView`
|
|||
|
|
|
|||
|
|
## 6. OnlyOffice 位置与嵌入形式
|
|||
|
|
|
|||
|
|
### 6.1 OnlyOffice 页面入口
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/page.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/OnlyOfficeClientPage.tsx`
|
|||
|
|
|
|||
|
|
当前 OnlyOffice 不是 BlockNote 内嵌编辑器,而是单独页面。
|
|||
|
|
|
|||
|
|
嵌入方式:
|
|||
|
|
|
|||
|
|
- 打开路由 `/onlyoffice`,对应入口文件 `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/page.tsx`
|
|||
|
|
- 页面内部加载 OnlyOffice 文档编辑器脚本
|
|||
|
|
- 通过 URL 参数和运行时配置决定打开哪个文档、哪种模式
|
|||
|
|
|
|||
|
|
### 6.2 页面职责
|
|||
|
|
|
|||
|
|
`page.tsx` 负责:
|
|||
|
|
|
|||
|
|
- 在最早阶段注入 DOM 补丁
|
|||
|
|
- 防止 OnlyOffice 某些 `NotFoundError` 导致整页白屏
|
|||
|
|
|
|||
|
|
`OnlyOfficeClientPage.tsx` 负责:
|
|||
|
|
|
|||
|
|
- 真正加载 OnlyOffice 编辑器
|
|||
|
|
- 改写内部请求
|
|||
|
|
- 处理代理地址
|
|||
|
|
- 配置 callback、签名、强制保存
|
|||
|
|
- 挂载 `OnlyOfficeAiAgentPanel`
|
|||
|
|
|
|||
|
|
### 6.3 与正文的关系
|
|||
|
|
|
|||
|
|
OnlyOffice 当前不是“BlockNote 中的一块可直接编辑的 Office 文档”。
|
|||
|
|
|
|||
|
|
当前模式是:
|
|||
|
|
|
|||
|
|
1. 文档正文里放的是附件块 `MediaBlock`
|
|||
|
|
2. 如果附件扩展名属于 Office 文档类型
|
|||
|
|
3. 点击后新开路由 `/onlyoffice` 页面,对应实现 `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/OnlyOfficeClientPage.tsx`
|
|||
|
|
4. 在独立页面内进行 OnlyOffice 编辑
|
|||
|
|
|
|||
|
|
对应主文件:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MediaBlock.tsx`
|
|||
|
|
|
|||
|
|
这意味着:
|
|||
|
|
|
|||
|
|
- BlockNote 中只嵌入“文件入口”
|
|||
|
|
- OnlyOffice 编辑器本身在独立页面运行
|
|||
|
|
|
|||
|
|
### 6.4 OnlyOffice 资源位置
|
|||
|
|
|
|||
|
|
当前仍保留的历史资源目录:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/src/components/onlyoffice/onlyoffice-web-apps`
|
|||
|
|
- `/mnt/Data1T/mnote/src/components/onlyoffice/onlyoffice-plugins`
|
|||
|
|
- `/mnt/Data1T/mnote/src/components/onlyoffice/onlyoffice-data`
|
|||
|
|
|
|||
|
|
这里不是主 React 页面代码,但对 OnlyOffice 运行仍有意义,因为里面保留了:
|
|||
|
|
|
|||
|
|
- web apps 静态资源
|
|||
|
|
- 插件
|
|||
|
|
- key / data
|
|||
|
|
|
|||
|
|
### 6.5 OnlyOffice 代理与 API
|
|||
|
|
|
|||
|
|
关键接口:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/proxy/route.ts`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/callback/route.ts`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/forcesave/route.ts`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/sign/route.ts`
|
|||
|
|
|
|||
|
|
当前角色分工:
|
|||
|
|
|
|||
|
|
- `proxy`
|
|||
|
|
负责把浏览器不可直达的 OnlyOffice / 文件回源 URL 包成同源代理,避免跨域、内网地址、token 参数冲突
|
|||
|
|
- `callback`
|
|||
|
|
接收 OnlyOffice 保存回调,再把内容写回存储
|
|||
|
|
- `forcesave`
|
|||
|
|
主动触发保存
|
|||
|
|
- `sign`
|
|||
|
|
提供签名能力
|
|||
|
|
|
|||
|
|
### 6.6 当前结论
|
|||
|
|
|
|||
|
|
OnlyOffice 的前端定位是:
|
|||
|
|
|
|||
|
|
- 独立页面型编辑器
|
|||
|
|
- 不直接嵌入 BlockNote 编辑画布
|
|||
|
|
- 通过附件块从文档页跳转进入
|
|||
|
|
|
|||
|
|
## 7. Online Table 的位置与嵌入形式
|
|||
|
|
|
|||
|
|
虽然你这次重点是 BlockNote / Mindmap / OnlyOffice,但当前结构里在线表格和它们关系紧密,也需要一起记住。
|
|||
|
|
|
|||
|
|
主文件:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/OnlineTableBlock.tsx`
|
|||
|
|
|
|||
|
|
嵌入方式:
|
|||
|
|
|
|||
|
|
- 在线表格是 BlockNote 的自定义 block
|
|||
|
|
- 在正文中显示的是紧凑预览块
|
|||
|
|
- 双击或操作按钮后,通过 editor bridge 打开全屏表格编辑器
|
|||
|
|
|
|||
|
|
所以它和 Mindmap 类似,都是:
|
|||
|
|
|
|||
|
|
- 正文里先以内嵌 block 形式出现
|
|||
|
|
- 再切换到更大编辑视图
|
|||
|
|
|
|||
|
|
但它和 OnlyOffice 不同:
|
|||
|
|
|
|||
|
|
- Online Table 仍然属于 BlockNote 自定义 block 体系
|
|||
|
|
- OnlyOffice 是独立页面体系
|
|||
|
|
|
|||
|
|
## 8. 四层结构图
|
|||
|
|
|
|||
|
|
下面用“组件层 / 页面层 / API 层 / 存储层”重新梳理一次当前主线。
|
|||
|
|
|
|||
|
|
### 8.1 组件层
|
|||
|
|
|
|||
|
|
组件层主要位于:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/`
|
|||
|
|
|
|||
|
|
其中本次最关键的组件分组是:
|
|||
|
|
|
|||
|
|
- 文档编辑核心
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-shell.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx`
|
|||
|
|
- BlockNote 自定义块
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapBlock.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/OnlineTableBlock.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MediaBlock.tsx`
|
|||
|
|
- OnlyOffice 页面侧组件
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/onlyoffice/OnlyOfficeAiAgentPanel.tsx`
|
|||
|
|
|
|||
|
|
这一层的职责是:
|
|||
|
|
|
|||
|
|
- 渲染交互界面
|
|||
|
|
- 承载编辑器实例
|
|||
|
|
- 把页面数据转成可操作 UI
|
|||
|
|
- 管理局部交互状态
|
|||
|
|
|
|||
|
|
### 8.2 页面层
|
|||
|
|
|
|||
|
|
页面层主要位于:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/`
|
|||
|
|
|
|||
|
|
关键页面关系是:
|
|||
|
|
|
|||
|
|
1. 文档页
|
|||
|
|
- 路由:`/documents/[id]`
|
|||
|
|
- 源码:`/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx`
|
|||
|
|
- 负责把文档元数据交给文档编辑器宿主
|
|||
|
|
2. 思维导图全屏页
|
|||
|
|
- 路由:`/mindmap/[docId]/[mindmapId]`
|
|||
|
|
- 源码:`/mnt/Data1T/mnote/wolai-frontend/src/app/mindmap/[docId]/[mindmapId]/page.tsx`
|
|||
|
|
- 负责把 MindmapBlock 复用为独立编辑页面
|
|||
|
|
3. OnlyOffice 页
|
|||
|
|
- 路由:`/onlyoffice`
|
|||
|
|
- 源码:`/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/page.tsx`
|
|||
|
|
- 客户端实现:`/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/OnlyOfficeClientPage.tsx`
|
|||
|
|
- 负责承载独立的文档编辑器
|
|||
|
|
|
|||
|
|
这一层的职责是:
|
|||
|
|
|
|||
|
|
- 定义访问路由
|
|||
|
|
- 组织页面级权限和参数
|
|||
|
|
- 决定使用哪套组件组合
|
|||
|
|
- 把独立编辑器和正文编辑器区分开
|
|||
|
|
|
|||
|
|
### 8.3 API 层
|
|||
|
|
|
|||
|
|
API 层主要位于:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/`
|
|||
|
|
|
|||
|
|
和本次主题最相关的 API 组是:
|
|||
|
|
|
|||
|
|
- 文档内容与页面数据
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/`
|
|||
|
|
- 思维导图
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/mindmap/`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/mindmap-ai/`
|
|||
|
|
- 媒体与附件
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/media/`
|
|||
|
|
- OnlyOffice
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/proxy/route.ts`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/callback/route.ts`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/forcesave/route.ts`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/sign/route.ts`
|
|||
|
|
|
|||
|
|
这一层的职责是:
|
|||
|
|
|
|||
|
|
- 做 BFF 转换
|
|||
|
|
- 统一权限校验
|
|||
|
|
- 代理前端和 Convex / 外部编辑器之间的请求
|
|||
|
|
- 处理 OnlyOffice 的保存回写与代理回源
|
|||
|
|
|
|||
|
|
### 8.4 存储层
|
|||
|
|
|
|||
|
|
存储层当前不是单一系统,而是三部分组合:
|
|||
|
|
|
|||
|
|
1. Convex 主数据层
|
|||
|
|
- 位置:`/mnt/Data1T/mnote/wolai-frontend/convex/`
|
|||
|
|
- 负责文档元数据、业务记录、任务编排等主链路数据
|
|||
|
|
2. 本地 / 历史文件资源层
|
|||
|
|
- 位置:`/mnt/Data1T/mnote/src/components/onlyoffice/`
|
|||
|
|
- 负责保留 OnlyOffice 相关静态资源、插件和密钥数据
|
|||
|
|
3. 辅助后端层
|
|||
|
|
- 位置:`/mnt/Data1T/mnote/wolai-backend/app/`
|
|||
|
|
- 负责补充服务能力与异步处理配合
|
|||
|
|
|
|||
|
|
这一层的职责是:
|
|||
|
|
|
|||
|
|
- 保存业务主数据
|
|||
|
|
- 保存编辑器所需静态资源
|
|||
|
|
- 承载需要服务端参与的补充逻辑
|
|||
|
|
|
|||
|
|
### 8.5 三个核心能力在四层中的落点
|
|||
|
|
|
|||
|
|
#### A. BlockNote
|
|||
|
|
|
|||
|
|
- 组件层:`/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx`
|
|||
|
|
- 页面层:`/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx`
|
|||
|
|
- API 层:`/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/`、`/mnt/Data1T/mnote/wolai-frontend/src/app/api/blocks/`
|
|||
|
|
- 存储层:`/mnt/Data1T/mnote/wolai-frontend/convex/`
|
|||
|
|
|
|||
|
|
#### B. Mindmap
|
|||
|
|
|
|||
|
|
- 组件层:`/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapBlock.tsx`
|
|||
|
|
- 页面层:
|
|||
|
|
- 文档内嵌页面宿主:`/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx`
|
|||
|
|
- 独立页:`/mnt/Data1T/mnote/wolai-frontend/src/app/mindmap/[docId]/[mindmapId]/page.tsx`
|
|||
|
|
- API 层:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/mindmap/`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/mindmap-ai/`
|
|||
|
|
- 存储层:
|
|||
|
|
- Convex 主数据:`/mnt/Data1T/mnote/wolai-frontend/convex/`
|
|||
|
|
- 本地 mindmap 辅助逻辑:`/mnt/Data1T/mnote/wolai-frontend/src/lib/mindmap/`
|
|||
|
|
|
|||
|
|
#### C. OnlyOffice
|
|||
|
|
|
|||
|
|
- 组件层:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/OnlyOfficeClientPage.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/onlyoffice/OnlyOfficeAiAgentPanel.tsx`
|
|||
|
|
- 页面层:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/page.tsx`
|
|||
|
|
- API 层:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/`
|
|||
|
|
- 存储层:
|
|||
|
|
- OnlyOffice 静态资源:`/mnt/Data1T/mnote/src/components/onlyoffice/`
|
|||
|
|
- 业务回写与数据协作:`/mnt/Data1T/mnote/wolai-frontend/convex/` 与 `/mnt/Data1T/mnote/wolai-backend/app/`
|
|||
|
|
|
|||
|
|
## 9. 页面树与文件树
|
|||
|
|
|
|||
|
|
这一部分专门说明当前左侧结构区里的两套树:页面树和文件树。
|
|||
|
|
|
|||
|
|
### 9.1 位置
|
|||
|
|
|
|||
|
|
它们当前都属于侧边栏系统,主要位于:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/sidebar.tsx`
|
|||
|
|
|
|||
|
|
其中:
|
|||
|
|
|
|||
|
|
- 页面树组件:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/private-tree.tsx`
|
|||
|
|
- 文件树组件:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/file-tree.tsx`
|
|||
|
|
|
|||
|
|
也就是说,两者都在“组件层”的侧边栏模块里,但不是同一个组件。
|
|||
|
|
|
|||
|
|
### 9.2 来源
|
|||
|
|
|
|||
|
|
当前两套树的数据源都先汇总到侧边栏数据模型,再做不同投影。
|
|||
|
|
|
|||
|
|
主要数据入口是:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/hooks/use-convex-sidebar-data.ts`
|
|||
|
|
|
|||
|
|
这个 hook 会从 Convex 拉取:
|
|||
|
|
|
|||
|
|
- 文档列表
|
|||
|
|
- 回收站文档
|
|||
|
|
- 思维导图记录
|
|||
|
|
- 媒体资产
|
|||
|
|
- 回收站媒体资产
|
|||
|
|
- 在线表格记录
|
|||
|
|
- 工作空间摘要
|
|||
|
|
|
|||
|
|
然后把这些数据组合成统一的 `SidebarInitialData` 形状,交给侧边栏 UI。
|
|||
|
|
|
|||
|
|
### 9.3 页面树
|
|||
|
|
|
|||
|
|
页面树的核心特点是:
|
|||
|
|
|
|||
|
|
- 只关心“文档节点”本身
|
|||
|
|
- 表示页面之间的父子结构
|
|||
|
|
- 不直接把附件、思维导图文件夹、在线表格文件作为树节点展开
|
|||
|
|
|
|||
|
|
主要实现链路:
|
|||
|
|
|
|||
|
|
1. `/mnt/Data1T/mnote/wolai-frontend/src/hooks/use-convex-sidebar-data.ts`
|
|||
|
|
提供文档数据源
|
|||
|
|
2. `/mnt/Data1T/mnote/wolai-frontend/src/lib/documents.ts`
|
|||
|
|
负责把文档记录构造成 `DocumentNode`
|
|||
|
|
3. `/mnt/Data1T/mnote/wolai-frontend/src/lib/sidebar-tree.ts`
|
|||
|
|
负责 `flattenDocumentTree` 和 section 投影
|
|||
|
|
4. `/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/private-tree.tsx`
|
|||
|
|
负责真正渲染页面树
|
|||
|
|
|
|||
|
|
页面树所在层次:
|
|||
|
|
|
|||
|
|
- 组件层:`/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/private-tree.tsx`
|
|||
|
|
- 页面层宿主:`/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/sidebar.tsx`
|
|||
|
|
- 数据来源:`/mnt/Data1T/mnote/wolai-frontend/src/hooks/use-convex-sidebar-data.ts`
|
|||
|
|
- 存储来源:`/mnt/Data1T/mnote/wolai-frontend/convex/`
|
|||
|
|
|
|||
|
|
页面树更像“文档导航树”。
|
|||
|
|
|
|||
|
|
### 9.4 文件树
|
|||
|
|
|
|||
|
|
文件树的核心特点是:
|
|||
|
|
|
|||
|
|
- 以文档为根
|
|||
|
|
- 但会把文档下的索引页、附件、思维导图资产、在线表格资产一起展开
|
|||
|
|
- 更像“资源管理器视图”
|
|||
|
|
|
|||
|
|
主要实现链路:
|
|||
|
|
|
|||
|
|
1. `/mnt/Data1T/mnote/wolai-frontend/src/hooks/use-convex-sidebar-data.ts`
|
|||
|
|
提供文档、媒体、思维导图、表格等混合数据
|
|||
|
|
2. `/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/sidebar.tsx`
|
|||
|
|
把多类资源整理到 file-tree 视图所需的输入结构
|
|||
|
|
3. `/mnt/Data1T/mnote/wolai-frontend/src/lib/file-tree/rows.ts`
|
|||
|
|
把文档节点 + 资产组合成 `FileTreeRow[]`
|
|||
|
|
4. `/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/file-tree.tsx`
|
|||
|
|
负责真正渲染文件树
|
|||
|
|
|
|||
|
|
文件树所在层次:
|
|||
|
|
|
|||
|
|
- 组件层:`/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/file-tree.tsx`
|
|||
|
|
- 页面层宿主:`/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/sidebar.tsx`
|
|||
|
|
- 数据来源:`/mnt/Data1T/mnote/wolai-frontend/src/hooks/use-convex-sidebar-data.ts`
|
|||
|
|
- 存储来源:`/mnt/Data1T/mnote/wolai-frontend/convex/`
|
|||
|
|
|
|||
|
|
文件树更像“页面 + 资源”的混合管理视图。
|
|||
|
|
|
|||
|
|
### 9.5 二者的关系
|
|||
|
|
|
|||
|
|
页面树和文件树不是两套独立后端数据模型,而是:
|
|||
|
|
|
|||
|
|
- 共用同一套侧边栏主数据源
|
|||
|
|
- 在前端侧做两种不同投影
|
|||
|
|
|
|||
|
|
区别可以简单记成:
|
|||
|
|
|
|||
|
|
- 页面树:只看页面层级
|
|||
|
|
- 文件树:看页面层级 + 页面下资源
|
|||
|
|
|
|||
|
|
### 9.6 当前结论
|
|||
|
|
|
|||
|
|
如果后续迁移到 `mnote-rust`,这两套树不应该混为一个组件重写,而应该拆成:
|
|||
|
|
|
|||
|
|
1. 统一侧边栏数据聚合层
|
|||
|
|
2. 页面树投影层
|
|||
|
|
3. 文件树投影层
|
|||
|
|
4. 各自独立渲染组件
|
|||
|
|
|
|||
|
|
这样最符合当前实现,也最容易保持行为一致。
|
|||
|
|
|
|||
|
|
## 10. 数据保存与读写入口
|
|||
|
|
|
|||
|
|
### 10.1 BlockNote
|
|||
|
|
|
|||
|
|
核心文件:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/save/route.ts`
|
|||
|
|
|
|||
|
|
保存位置:
|
|||
|
|
|
|||
|
|
- 主保存目标是 Convex 文档内容字段,对应后端 mutation 为 `api.documents.updateContent`
|
|||
|
|
- 实现入口位于 `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/save/route.ts`
|
|||
|
|
|
|||
|
|
保存格式:
|
|||
|
|
|
|||
|
|
- 前端提交字段为 `{ documentId, content }`
|
|||
|
|
- 其中 `content` 是 BlockNote 的 JSON 块数组
|
|||
|
|
- 如果初始值不是纯数组,也会在 `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx` 中先提取 `blocks`
|
|||
|
|
|
|||
|
|
读写入口:
|
|||
|
|
|
|||
|
|
- 读入口:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-shell.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx`
|
|||
|
|
- 写入口:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx`
|
|||
|
|
- 其中 `saveContent()` 会 `POST /api/documents/save`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/save/route.ts` 再调用 `api.documents.updateContent`
|
|||
|
|
|
|||
|
|
补充说明:
|
|||
|
|
|
|||
|
|
- BlockNote 主内容走 Convex 持久化
|
|||
|
|
- 同文件里还保留了 `HocuspocusProvider + Y.Doc` 协作接入,说明实时协作层与最终持久化层是分开的
|
|||
|
|
- 思维导图自动保存缓存也会临时写到浏览器 `localStorage`,但那不是文档主存储
|
|||
|
|
|
|||
|
|
### 10.2 Mindmap
|
|||
|
|
|
|||
|
|
核心文件:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapBlock.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/lib/mindmap/mindmapLocalStore.ts`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/lib/server/local-paths.ts`
|
|||
|
|
|
|||
|
|
保存位置:
|
|||
|
|
|
|||
|
|
- 首选目录由 `/mnt/Data1T/mnote/wolai-frontend/src/lib/server/local-paths.ts` 的 `getDocumentsBaseDir()` 决定
|
|||
|
|
- 如果设置了 `MNOTE_DATA_DIR`,目录是 `MNOTE_DATA_DIR/documents/<docId>/`
|
|||
|
|
- 否则回退到 `/mnt/Data1T/mnote/wolai-frontend/public/documents/<docId>/`
|
|||
|
|
- 兼容旧路径时,还会尝试 `getLegacyMindmapsBaseDir()`,即 `MNOTE_DATA_DIR/mindmaps/<docId>/` 或 `/mnt/Data1T/mnote/wolai-frontend/public/mindmaps/<docId>/`
|
|||
|
|
|
|||
|
|
保存格式:
|
|||
|
|
|
|||
|
|
- 保存为 JSON 文件
|
|||
|
|
- 文件名规则在 `/mnt/Data1T/mnote/wolai-frontend/src/lib/mindmap/mindmapLocalStore.ts`
|
|||
|
|
- `mindmap.json`
|
|||
|
|
- `mindmap-${mindmapId}.json`
|
|||
|
|
- 实际写入使用 `JSON.stringify(data, null, 2)`,即格式化 JSON 文本
|
|||
|
|
|
|||
|
|
读写入口:
|
|||
|
|
|
|||
|
|
- 读入口:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/lib/mindmap/mindmapLocalStore.ts` 的 `readMindmapLocal(docId, mindmapId)`
|
|||
|
|
- 写入口:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/lib/mindmap/mindmapLocalStore.ts` 的 `writeMindmapLocal(docId, mindmapId, data, docTitle)`
|
|||
|
|
- 相关服务侧复用:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/lib/ai-agent/tools/builtins/mindmap/mindmapServerTools.ts`
|
|||
|
|
|
|||
|
|
补充说明:
|
|||
|
|
|
|||
|
|
- Mindmap 当前不是像 BlockNote 正文那样直接持久化到 Convex 内容字段
|
|||
|
|
- 它更像“文档目录下的配套 JSON 资产”
|
|||
|
|
- 页面中的思维导图块与独立全屏思维导图页,共用同一份数据结构
|
|||
|
|
|
|||
|
|
### 10.3 OnlyOffice
|
|||
|
|
|
|||
|
|
核心文件:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/OnlyOfficeClientPage.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/callback/route.ts`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/sign/route.ts`
|
|||
|
|
|
|||
|
|
保存位置:
|
|||
|
|
|
|||
|
|
- 当前保存目标不是 BlockNote 内容,而是附件资产本身
|
|||
|
|
- Convex 模式下,OnlyOffice 回调会把编辑后的二进制文件重新上传到 Convex Files
|
|||
|
|
- 然后更新 `media_assets.storage_id / file_url` 之类的附件存储指针
|
|||
|
|
|
|||
|
|
保存格式:
|
|||
|
|
|
|||
|
|
- 保存内容是 Office 原始文件二进制,不是 BlockNote JSON
|
|||
|
|
- 文档格式取决于当前附件类型,例如 `docx / xlsx / pptx / pdf`
|
|||
|
|
- 前端传给 OnlyOffice 的 `document.url` 是可下载原文件的地址,OnlyOffice 保存后再通过回调传回新的下载地址
|
|||
|
|
|
|||
|
|
读写入口:
|
|||
|
|
|
|||
|
|
- 读入口:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MediaBlock.tsx` 负责从正文附件入口跳转
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/page.tsx`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/OnlyOfficeClientPage.tsx`
|
|||
|
|
- 写入口:
|
|||
|
|
- `OnlyOfficeClientPage.tsx` 里组装 `callbackUrl`
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/callback/route.ts` 接收 status `2/6`
|
|||
|
|
- 回调路由下载 OnlyOffice 生成的新文件,再上传到 Convex Files,并调用 `api.mediaAssets.replaceStorageFromUpload`
|
|||
|
|
|
|||
|
|
补充说明:
|
|||
|
|
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/forcesave/route.ts` 用于主动触发保存
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/proxy/route.ts` 用于同源代理与回源下载
|
|||
|
|
- 根目录 `/mnt/Data1T/mnote/src/components/onlyoffice/` 保留的是 OnlyOffice 静态资源、插件与历史数据,不是正文主数据存储
|
|||
|
|
|
|||
|
|
### 10.4 OnlyOffice key 生成规则
|
|||
|
|
|
|||
|
|
这里要区分两种“key / 密钥”。
|
|||
|
|
|
|||
|
|
第一种是前端传给 OnlyOffice 的 `document.key`:
|
|||
|
|
|
|||
|
|
- 定义位置:
|
|||
|
|
- `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/OnlyOfficeClientPage.tsx`
|
|||
|
|
- 生成规则:
|
|||
|
|
- 有 `assetId` 时,优先生成 `assetId + "_" + hashKey(assetStorageId)`
|
|||
|
|
- 如果还没拿到 `assetStorageId`,先退化为 `assetId`
|
|||
|
|
- 没有 `assetId` 时,回退为 `hashKey(\`${effectiveFileUrl}-${fileName}\`)`
|
|||
|
|
- 设计目的:
|
|||
|
|
- 让同一附件多次打开时 `document.key` 尽量稳定,提升 OnlyOffice 内部缓存命中
|
|||
|
|
- 当附件回写后 `storage_id` 变化,key 会自然变化,避免旧缓存污染新文件
|
|||
|
|
- 字符集限制:
|
|||
|
|
- 代码注释明确说明 OnlyOffice `document.key` 允许字符集接近 `[0-9a-zA-Z_.=-]`
|
|||
|
|
- 所以这里对 `storage_id` 做 hash,而不是直接原样拼接
|
|||
|
|
|
|||
|
|
第二种是服务端签名与回调校验所需的密钥:
|
|||
|
|
|
|||
|
|
- `ONLYOFFICE_JWT_SECRET`
|
|||
|
|
- 读取位置:`/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/sign/route.ts`
|
|||
|
|
- 用途:给整体 config、`document`、`editorConfig` 生成 HS256 JWT
|
|||
|
|
- 获得方式:这是你自己部署 OnlyOffice 时,在服务端环境变量里配置的一段共享密钥,不是前端算出来的值
|
|||
|
|
- 如果未配置,当前实现会返回 `token: null`,兼容“服务端未开启 JWT 校验”的场景
|
|||
|
|
|
|||
|
|
- `ONLYOFFICE_CALLBACK_SECRET`
|
|||
|
|
- 读取位置:`/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/callback/route.ts`
|
|||
|
|
- 用途:校验 OnlyOffice 文档服务器回调到 `/api/onlyoffice/callback` 时附带的共享密钥
|
|||
|
|
- 获得方式:同样是你在本项目环境变量和 OnlyOffice 侧约定的一段共享字符串,不是系统自动下发
|
|||
|
|
- 如果未配置,当前实现保持兼容,不强制校验
|
|||
|
|
|
|||
|
|
当前结论:
|
|||
|
|
|
|||
|
|
- 如果你问“OnlyOffice 的 key 如何获得”,前端运行期真正用来区分文档实例的 key,是代码按 `assetId / storage_id / fileUrl / fileName` 现场生成的
|
|||
|
|
- 如果你问“OnlyOffice 的密钥如何获得”,那指的是 `ONLYOFFICE_JWT_SECRET` 与 `ONLYOFFICE_CALLBACK_SECRET`,它们都应由部署者在环境变量中自行生成并在双方配置保持一致
|
|||
|
|
|
|||
|
|
## 11. 三者关系总结
|
|||
|
|
|
|||
|
|
### 11.1 BlockNote
|
|||
|
|
|
|||
|
|
定位:
|
|||
|
|
|
|||
|
|
- 主文档编辑器内核
|
|||
|
|
- 页面正文的承载容器
|
|||
|
|
|
|||
|
|
表现形式:
|
|||
|
|
|
|||
|
|
- 文档主页面核心区域
|
|||
|
|
- 挂载各种自定义 block
|
|||
|
|
|
|||
|
|
### 11.2 Mindmap
|
|||
|
|
|
|||
|
|
定位:
|
|||
|
|
|
|||
|
|
- BlockNote 内部的高级自定义块
|
|||
|
|
|
|||
|
|
表现形式:
|
|||
|
|
|
|||
|
|
- 文档页中可内嵌
|
|||
|
|
- 也可进入全屏
|
|||
|
|
- 独立路由 `/mindmap/[docId]/[mindmapId]` 页面与内嵌块共用同一核心组件,对应页面文件 `/mnt/Data1T/mnote/wolai-frontend/src/app/mindmap/[docId]/[mindmapId]/page.tsx`
|
|||
|
|
|
|||
|
|
### 11.3 OnlyOffice
|
|||
|
|
|
|||
|
|
定位:
|
|||
|
|
|
|||
|
|
- 独立页面型文档编辑器
|
|||
|
|
|
|||
|
|
表现形式:
|
|||
|
|
|
|||
|
|
- 从附件块跳转进入
|
|||
|
|
- 运行在路由 `/onlyoffice`,对应页面文件 `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/page.tsx`
|
|||
|
|
- 不直接嵌入 BlockNote 正文编辑画布
|
|||
|
|
|
|||
|
|
## 12. 一句话记忆版
|
|||
|
|
|
|||
|
|
可以把当前架构记成下面这三句:
|
|||
|
|
|
|||
|
|
- `BlockNote` 是主页面正文编辑器容器
|
|||
|
|
- `Mindmap` 是挂在 BlockNote 里的重交互 block,并可切到全屏
|
|||
|
|
- `OnlyOffice` 是通过附件入口跳转出去的独立编辑页面
|
|||
|
|
|
|||
|
|
## 13. 后续重构建议
|
|||
|
|
|
|||
|
|
如果后面你要把这套能力迁到 `mnote-rust`,最值得优先抽象的是三层:
|
|||
|
|
|
|||
|
|
1. 文档宿主层
|
|||
|
|
- 文档页面壳
|
|||
|
|
- 文档权限
|
|||
|
|
- 编辑器挂载流程
|
|||
|
|
2. Block 能力层
|
|||
|
|
- BlockNote schema
|
|||
|
|
- `mindmap` / `onlineTable` / `media` 的块协议
|
|||
|
|
3. 外部编辑器层
|
|||
|
|
- OnlyOffice 独立页面
|
|||
|
|
- 代理 / callback / sign / forcesave
|
|||
|
|
|
|||
|
|
这样拆之后会非常清楚:
|
|||
|
|
|
|||
|
|
- 哪些能力应继续做成“内嵌 block”
|
|||
|
|
- 哪些能力应继续保留为“独立页面编辑器”
|