feat: 完善画布管理与快捷键体验

修改历史:

- 为画布编辑器补齐节点复制粘贴、全选、追加选择、缩放、删除、生成等快捷键,并新增快捷键说明弹窗

- 支持粘贴剪贴板文本/图片为画布节点、拖入图片上传,以及多选节点复制时保留内部连接

- 在 /canvas 画布管理页新增编辑和删除操作,可编辑标题与说明,并支持删除当前画布

- 为画布项目新增 description 字段,补充数据库兼容迁移、列表展示、API 保存以及导入导出保留说明

- 优化画布节点、提示词引用、配置节点尺寸、生成任务状态与相关服务逻辑
This commit is contained in:
2026-06-23 01:10:25 +08:00
parent 3b8ce48c56
commit 4ff348e808
38 changed files with 2069 additions and 310 deletions
+55
View File
@@ -0,0 +1,55 @@
# 画布多人协作保存扩展需求
> 扩展需求:当前暂不实现。
## 背景
当前画布编辑器采用单人编辑模型。前端在画布数据变化后通过 debounce 触发保存,请求 `PATCH /api/canvas/projects/[id]`,服务端将画布数据作为整份 JSON 写入 `canvas_projects.data`
这个机制适合单人场景:用户新增节点、移动节点、编辑 prompt、删除连接等操作后,只需要可靠地把最新画布状态持久化即可。当前保存状态可以继续围绕 HTTP 请求结果展示,例如“保存中”“已同步”“保存失败”。
## 判断结论
单人保存不需要 WebSocket。现有 HTTP PATCH 自动保存已经能覆盖主要需求,后续更应该优先完善保存状态、错误提示和失败重试。
多人实时协作需要实时通道。WebSocket 适合承载协作者加入、在线状态、光标/选区、画布变更广播和冲突提示,但它只解决消息传输,不自动解决权限、身份、冲突合并和最终落库。
由于项目未来部署形态暂不确定,协作能力应通过 transport adapter 隔离。这样本机或内网 Node 部署可以使用自建 WebSocket serverServerless 部署可以替换为托管实时服务,而上层画布协作协议保持一致。
## 第一版目标
- 提供轻量实时协作,而不是严格无冲突协同编辑。
- 广播节点和连接的增删改结果,让其他已打开同一画布的客户端自动同步。
- 广播在线状态、光标位置和选中节点,帮助用户知道其他协作者正在查看或编辑的位置。
- 通过版本号检测基础冲突,避免旧客户端静默覆盖新状态。
- 保留现有 HTTP PATCH 作为最终落库和实时通道不可用时的回退路径。
## 非目标
- 当前不实现严格 CRDT 或操作日志合并。
- 当前不引入用户登录、权限模型或项目成员体系。
- 当前不改造图片生成任务的 SSE 监听机制。
- 当前不修改数据库 schema、前端画布组件或运行时配置。
## 未来方案草案
后续实现时,可以为画布项目引入版本字段,例如 `version: number`。客户端提交协作变更时携带 `baseVersion`,服务端仅接受基于当前版本的变更。服务端接受变更后递增版本、写入数据库,并向同一画布房间内的其他客户端广播新的画布状态。
建议的协作事件包括:
- `join_canvas`:客户端进入画布,携带 `projectId``clientId` 和显示名称。
- `presence`:广播在线协作者、光标位置和选中状态。
- `canvas_patch`:客户端提交画布变更,携带 `baseVersion` 和变更后的画布数据。
- `canvas_state`:服务端确认并广播最新 `version` 和画布数据。
- `conflict`:客户端基于旧版本提交时返回,提示客户端重新同步。
第一版冲突策略可以采用版本号加后写覆盖保护:服务端拒绝旧版本提交,客户端收到 `conflict` 后重新拉取或应用服务端状态。暂不尝试自动合并同一节点字段的并发修改。
## 测试场景
- 单人保存:新增节点、移动节点、编辑 prompt、删除连接后,保存状态从“保存中”回到“已同步”。
- 双窗口同步:两个窗口打开同一画布,窗口 A 新增节点后,窗口 B 无需刷新即可看到更新。
- 冲突处理:两个窗口基于同一旧版本同时修改,后提交方收到冲突提示,不能静默覆盖服务端状态。
- 断线回退:实时通道断开后,客户端显示离线或错误状态,并可通过 HTTP PATCH 回退保存。
- 生成任务回归:图片生成期间的 loading/result 节点仍能正确保存和同步,现有 SSE 任务监听保持不变。