修复画布快速编辑回写与原图元数据

快速编辑回到原图面板流程,避免新建生成器占位

提交快速编辑时传入目标图层并在后端成功后回写画布

快速编辑生成输入记录原图引用,图片信息可展示原图来源

同步前后端测试与图片画布文档记忆
This commit is contained in:
2026-07-02 23:05:38 +08:00
parent 7d954e0985
commit d707613a8b
27 changed files with 528 additions and 323 deletions
+23 -7
View File
@@ -66,8 +66,8 @@
- 现象:画板生成、快速编辑、图标素材或 UI 素材提取如果允许直接提交 generated objectKey,用户只要知道其他账号的私有 objectKey,就可能让 api-server 签名读取并送给外部生成供应商。
- 原因:Data URL 参考图可以直接解析,但 objectKey 是服务端私有对象引用;只校验 generated 前缀、mime 和大小不能证明它属于当前账号。
- 处理:所有编辑器参考图入口统一走 `parse_editor_reference_image(state, owner_user_id, source)`;objectKey 分支必须先在当前账号的项目资源、素材库资产或 `asset_object` 中匹配 owner / bucket / key,再读取 OSS。快速编辑和图标素材额外参考图也必须真实传到 provider,不只写 metadata。
- 验证:`cargo test -p api-server --manifest-path server-rs/Cargo.toml editor_reference`,并用前端 workflow 测试覆盖 `referenceImageSrcs` 进入快速编辑 / 图标生成请求。
- 处理:所有编辑器参考图入口统一走 `parse_editor_reference_image(state, owner_user_id, source)`;objectKey 分支必须先在当前账号的项目资源、素材库资产或 `asset_object` 中匹配 owner / bucket / key,再读取 OSS。图标素材等额外参考图必须真实传到 provider,不只写 metadata;图片快速编辑当前不开放额外参考图,若后续重开入口也必须沿用同一归属校验。
- 验证:`cargo test -p api-server --manifest-path server-rs/Cargo.toml editor_reference`,并用前端 workflow 测试覆盖 `referenceImageSrcs` 进入图标生成请求;若快速编辑重开额外参考图,再补对应请求覆盖。
- 关联:`server-rs/crates/api-server/src/editor_project.rs`、`server-rs/crates/spacetime-client/src/assets.rs`、`src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.ts`。
## 编辑器生成按钮显示泥点后仍要查真实钱包预扣
@@ -311,14 +311,30 @@
- 验证:`npm run test -- src/components/image-editor/ImageCanvasOverlayModel.test.ts src/components/image-editor/useImageCanvasGenerationSurface.test.tsx`。
- 关联:`src/components/image-editor/ImageCanvasOverlayModel.ts`、`src/components/image-editor/useImageCanvasGenerationSurface.tsx`、`docs/【编辑器】生成类面板Lovart统一改造方案-2026-06-17.md`。
## 图片画布图片改造也必须创建独立生成器占位
## 图片画布重绘创建独立占位,快速编辑不要新建生成器
- 现象:点击图片图层的“改造”后,输入框直接挂在原图上,提交时既不像其它生成入口一样有独立占位,也容易让用户误以为会覆盖源图。
- 原因:图片改造复用了旧 `QuickEditPanelState` / redraw 面板路径,只把源图选中并在原图附近打开快速编辑框,没有进入统一的 `CanvasGenerationDialogState` 占位链路。
- 处理:图片和用户快照图层的“改造”统一创建 `mode="quick-edit"` 的 generation dialog,占位仍走 `ImageCanvasGenerationPlacementModel`;源图作为隐式最后一张参考图提交,并把“当前图”提示词归一到对应参考图编号。音频改造继续走音频生成器路径,非图片 fallback 才保留旧面板。参考图 Data URL 提交前可压缩,但浏览器图片解码卡住时必须超时透传原图,不能阻塞生成请求。
- 验证:`npm run test -- src/components/image-editor/useImageCanvasGenerationWorkflow.test.tsx src/components/image-editor/ImageCanvasGenerationSubmissionModel.test.ts src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.test.tsx src/services/image-editor/editorImageReference.test.ts -- --runInBand`,以及 `npm run test -- src/components/image-editor/ImageCanvasEditorGenerationIntegration.test.tsx -t "hides quick edit and redraw panels|opens generated image info|shows the quick edit generator" -- --runInBand`。
- 现象:用户点击图片素材的“快速编辑”后,画布上额外出现 `Quick Edit Generator` 占位,像是新建了一个生成器;但用户预期是在原图下方框选区域、填写一个提示词和模型,然后直接修改当前图。
- 原因:快速编辑入口和提交链路误用了 `createQuickEditGenerationDialogDraft(...)` / `CanvasGenerationDialogState`,把“覆盖源图”的快速编辑伪装成会产出新图层的生成器占位。
- 处理:图片快速编辑必须走 `QuickEditPanelState`,打开时归档当前 active generation dialog 但不创建新的 `mode="quick-edit"` dialog;提交时调用 `/api/editor/images/edits`,把当前图片或带编号标注的图片作为 `sourceImageSrc`,成功后覆盖源图,失败时保留快速编辑面板。图片重绘、去背景、视频快速编辑等会产出新图层或异步占位的入口仍可走 generation dialog / placement 链路。
- 验证:`npm run test -- src/components/image-editor/useImageCanvasGenerationWorkflow.test.tsx src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.test.tsx src/components/image-editor/ImageCanvasQuickEditPanelView.test.tsx -- --runInBand`,以及按需运行 `npm run test -- src/components/image-editor/ImageCanvasEditorGenerationIntegration.test.tsx -t "快速编辑|quick edit" -- --runInBand`。
- 关联:`src/components/image-editor/useImageCanvasGenerationWorkflow.ts`、`src/components/image-editor/ImageCanvasGenerationSubmissionModel.ts`、`src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.ts`、`src/services/image-editor/editorImageReference.ts`。
## 图片画布快速编辑完成必须按目标图层回写
- 现象:图片快速编辑任务成功后,刷新页面素材库能看到新图,但画布上的源图没有替换。
- 原因:`/api/editor/images/edits` 只保存生成图、项目资源和素材;没有 `canvasCompletion` 时不会写 `editor_canvas.layers_json`。`sourceResourceId` 只能表示溯源,同一资源可出现在多个图层,不能用它来决定替换哪一层。
- 处理:图片快速编辑请求必须传 `targetLayerId`;后端在没有 `canvasCompletion` 的快速编辑完成分支里,用目标 layer id 和生成资源写回项目 layout。
- 验证:`npm run test -- src/services/image-editor/editorProjectClient.test.ts src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.test.tsx -- --runInBand`;后端验证至少覆盖 `editor_image_edit_request_omits_price_mud_points` 和 `editor_image_edit_can_complete_by_replacing_target_layer`。
- 关联:`src/services/image-editor/editorProjectClient.ts`、`src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.ts`、`server-rs/crates/api-server/src/editor_project.rs`。
## 图片画布快速编辑元数据必须记录原图引用
- 现象:快速编辑生成的新图可以替换画布,但打开图片信息时“生成输入”里看不到被修改的原图。
- 原因:信息面板直接渲染 `generationInputs.references`;快速编辑虽然把原图作为 `sourceImageSrc` 传给 provider,但如果 `buildQuickEditGenerationInputs(...)` 不把源图写成引用,后端资源和画布层都没有可展示的原图引用。
- 处理:快速编辑的 `generationInputs.references` 必须始终包含 `原图`,再追加用户额外参考图;关闭额外参考图入口时也不能删除这条源图引用。
- 验证:`npm run test -- src/components/image-editor/ImageCanvasGenerationModel.test.ts src/components/image-editor/ImageCanvasGenerationSubmissionModel.test.ts src/components/image-editor/useImageCanvasGenerationWorkflow.test.tsx -- --runInBand`。
- 关联:`src/components/image-editor/ImageCanvasGenerationModel.ts`、`src/components/image-editor/ImageCanvasMetadataModalView.tsx`、`src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.ts`。
## 图片画布生成完成应用项目快照后也要刷新素材库
- 现象:部分素材生成成功后画布上已经出现结果,但左侧素材库没有立刻出现新素材,刷新页面后才显示。
File diff suppressed because one or more lines are too long
@@ -202,7 +202,7 @@ npm run check:server-rs-ddd
2. 编辑器画板所有会调用外部生成 provider 的入口都不从前端请求接收 `priceMudPoints`;实际扣费真相以后端运行时模型定价配置为准,前端按钮泥点只作为展示。
3. 编辑器图片生成 / 图片修改 / 图标 spritesheet / UI 设计图提取素材 / 视频 / 角色动作 / 音效 / 背景音乐必须在后端计算模型价格后使用 `execute_billable_asset_operation_with_cost` 预扣泥点;预扣失败必须 fail-closed,不得继续提交 VectorEngine、Ark、Suno 或 Vidu 上游任务。
4. 音频生成的编辑器链路虽然任务提交和结果发布分离,仍必须把提交时后端计算出的模型价格写入 `AudioAssetBindingTarget.billing_points_cost`,最终发布落资产时按该价格扣费;创作音频目标未提供该字段时才使用旧的创作音频固定成本。
5. 编辑器图片生成、图片修改、图标 spritesheet 和 UI 设计图提取素材的参考图可以提交 Data URL 或已登记的 generated objectKey;objectKey 必须归属于当前账号的 `editor_project_resource`、`editor_asset` 或 `asset_object`,后端通过归属校验后才签名读取 OSS。快速编辑、图标素材和 UI 素材提取的额外参考图必须真正传入 provider,不得只写入 `generationInputs` 展示快照;UI 素材提取额外参考图上限为 5 张,普通图片生成上限 5 张,快速编辑 / 图标素材上限 8 张额外参考图。
5. 编辑器图片生成、图片修改、图标 spritesheet 和 UI 设计图提取素材的参考图可以提交 Data URL 或已登记的 generated objectKey;objectKey 必须归属于当前账号的 `editor_project_resource`、`editor_asset` 或 `asset_object`,后端通过归属校验后才签名读取 OSS。图标素材和 UI 素材提取的额外参考图必须真正传入 provider,不得只写入 `generationInputs` 展示快照;图片快速编辑当前不开放额外参考图,只提交原图或红框序号标注图作为 `sourceImageSrc`。UI 素材提取额外参考图上限为 5 张,普通图片生成上限 5 张,图标素材上限 8 张额外参考图。
## 外部服务与资产
@@ -18,7 +18,7 @@
- `快速编辑`
`角色动画生成面板` 同步纳入本次生成类面板交互统一:点击角色图只聚焦图层,不自动弹出底部重绘或角色动画面板;点击 `生成动画` 后像新建图片一样创建 `角色动作` 画布占位,面板跟随占位底部,参考图首行、单文本无边界、参数按钮向上弹出、生成按钮明确展示泥点。
`快速编辑` 由选中图片后的浮动工具栏显式打开,面板结构、参考图首行、提示词输入区和底部参数 / 生成区对齐其它生成类面板。
`快速编辑` 由选中图片后的浮动工具栏显式打开,图片类素材统一进入框选区域 + 单提示词 + 模型选择的修改面板,不再恢复原来源生成器,也不展示参考图或尺寸控件。
## 统一布局
@@ -40,7 +40,7 @@
- 生成视频:`你希望生成什么视频?`
8. 多输入框面板必须保留每个字段标题和输入框边界,例如生成规范。图标素材生成不再使用多描述列表,改为复用角色形象生成面板同款单文本输入框。
9. 生成规范下的角色规范、图标规范和自定义规范都使用同一生成类 shell:首行参考图区域、中央字段区、底部生成按钮区,不再出现缺首行参考区或单独 footer 样式。
10. 快速编辑最多允许额外绑定 8 张参考图;原图始终作为 `/api/editor/images/edits` 的 `sourceImageSrc` 直接提交,不占用额外参考图额度,也不在参考图条里固定展示 `图x`。
10. 图片快速编辑不展示额外参考图入口;原图或绘制了红框和序号的标注图始终作为 `/api/editor/images/edits` 的 `sourceImageSrc` 直接提交,不作为 `referenceImageSrcs`。
11. 快速编辑打开后,画布视口应调整到原图完整展示,且面板位于原图下方并不遮挡原图;原图右侧显示竖向框选工具,支持矩形、椭圆和画笔自由框选。快速编辑进入时不默认启用框选工具,点击工具后出现选中态并保持高亮,再点同一工具取消启用;红色圈选框使用细描边。每完成一次框选,红色圈选框按完成顺序标注 `1 / 2 / 3...`,并在快速编辑提示词中追加一行 `对N号红色圈选框里的内容做以下修改:`。
## 参数交互
@@ -68,7 +68,7 @@
- 生成图片和生成视频文本输入框紧贴参考图下方,取消旧网格预留导致的空白高度。
- 生成规范类图片固定使用 `16:9·2K · gpt-image-2`。这三个参数在面板底部沿用可编辑参数按钮的胶囊样式展示,但控件保持禁用不可点击,不提供比例、尺寸或模型修改入口。
- 宣发素材的 `游戏首图`、`详情五图`、`运营海报` 固定使用 `gpt-image-2`。面板底部只显示禁用态 `gpt-image-2` 模型胶囊和生成按钮,不出现 `nanobanana2` 选项;后端收到 `publication-material` 旧请求时也必须强制归一为 `gpt-image-2`。
- 快速编辑默认从原图分辨率和模型初始化比例、尺寸和模型,但底部胶囊必须可点击修改;左下角统一显示 `x:y·xK`,右下角模型胶囊紧贴生成按钮。
- 图片快速编辑只保留一个提示词输入框和模型选择;提示词 placeholder 为 `写下每个编号要怎么改`,提交按钮显示 `修改`,不展示比例 / 尺寸或参考图控件。
- 不再在底部常驻展开全部可选项。
## 泥点显示
@@ -98,7 +98,7 @@
- 图片类待生成占位尺寸必须与面板当前比例和尺寸同步:普通图片、角色形象、图标素材、UI 设计图按当前 `aspectRatio + imageSize` 计算像素尺寸;生成规范固定为 `16:9·2K`,占位为 `2048 x 1152`;宣发素材按 workflow 输出尺寸创建占位。
- 视频待生成占位必须与面板当前比例和清晰度同步:默认 `16:9 · 480p` 为 `854 x 480`,切换比例、`720p` 或 `1080p` 后按比例和清晰度重算偶数宽度;调整参数时保持占位中心点不变。
- 面板中用户修改比例、尺寸或清晰度后,已有空白待生成占位立即同步更新 `width / height / originalWidth / originalHeight`,且保持中心点不跳动。
- 快速编辑点击生成后不在原图上播放生成中遮罩,而是立即创建独立 `Quick Edit Generator` 画布生成占位并播放生成中动画;该占位必须复用新建图片的 placement 避让逻辑,和已有素材 / 生成占位至少保留 32px 画布间距,不允许固定放到原图右侧后压住其它素材;生成成功后结果落在该占位框位置,失败时占位标记失败并恢复快速编辑面板。
- 快速编辑点击修改后不创建独立 `Quick Edit Generator` 画布生成占位;当前快速编辑面板显示修改中,生成成功后结果直接覆盖源图,失败时保留当前面板并显示错误。需要新建占位的是生成图片、生成视频、重绘、去背景和角色动作等会产出新图层的入口。
- 任何会打开画布内 composer / 面板的入口,必须在面板渲染后通过统一 overlay 可见性校正检查真实 DOM 矩形;如果面板超出画布视口,或底部工具栏 / 左下 dock 会遮住面板,就只平移当前 viewport 让面板完整进入安全区域。新增生成类入口不要在按钮 handler 里手写单独的避让偏移。
## 画布悬浮信息
@@ -175,12 +175,12 @@
- `生成音乐` 选项面板出现在音乐按钮上方,不再固定在底栏中间。
- 规范面板比图片生成面板更紧凑,字段间距和输入高度更小,但外层 shell、首行参考图和底部按钮区必须继续对齐生成图片 / 生成角色 / 生成视频。
- 生成规范类图片底部展示禁用态参数按钮 `16:9·2K` 和 `gpt-image-2`,视觉对齐可编辑面板的比例 / 尺寸 / 模型按钮;提交参数也固定为这三项,不出现可展开选项。
- 快速编辑底部展示当前选择的比例 / 尺寸和模型,视觉对齐可编辑面板的比例 / 尺寸 / 模型按钮,并允许展开修改;额外参考图最多 8 张,原图作为 `sourceImageSrc` 直接编辑,不在参考图条里固定显示 `图x`。
- 图片快速编辑底部只展示模型选择和 `修改` 按钮;原图或红框序号标注图作为 `sourceImageSrc` 直接编辑,不展示参考图条或比例 / 尺寸控件。
- 快速编辑打开后画布自动缩放平移到原图完整展示,并让面板位于原图下方且不遮挡原图;原图右侧出现竖向矩形 / 椭圆 / 画笔自由框选按钮。进入快速编辑不默认启用框选,点击工具启用并保持高亮,再点同一工具取消;完成框选后画布红色细框显示连续序号,输入框同步追加 `对N号红色圈选框里的内容做以下修改:`。
- 快速编辑提交前保留提示词里对原图的 `原图`、`当前图片`、`当前图` 或 `图1` 引用,不再改写成 `图N`。
- 快速编辑提交给后端时只把原图或已绘制红框和序号的标注图作为 `sourceImageSrc`;额外参考图进入输入快照,并作为图片编辑请求的 `referenceImageSrcs` 一起提交。
- 快速编辑提交给后端时只把原图或已绘制红框和序号的标注图作为 `sourceImageSrc`,不提交隐藏的 `referenceImageSrcs`。
- 生成中的占位图聚焦后可用 `Delete` / `Backspace` 删除;删除后异步结果不再落回画布,也不显示额外删除 UI。
- 快速编辑生成中的占位图同样只支持键盘 `Delete` / `Backspace` 删除,不新增 UI 删除按钮;删除后异步结果不得再落回画布。
- 快速编辑不创建生成中占位图;提交后当前面板显示修改中,异步结果只允许回填到源图。
- 生成视频 / 角色形象 / 角色动作 / 音效 / 背景音乐新建后,画布占位空白样式和右上角标签均与对应生成类型一致,不再统一使用图片占位 icon。
- 新建空白待生成占位的尺寸必须和面板参数一致;图片类修改比例 / 尺寸、视频修改清晰度后,画布空白占位同步变更且保持中心点。
- 点击角色图只选中图层并显示工具栏,不自动弹出重绘、快速编辑或角色动画面板;点击工具栏或右键菜单中的 `生成动画` 才创建角色动作占位和面板。