补齐画布多产物生成回填

将角色、图标图集和UI素材提取的原图登记为项目资源并随处理结果写入画布
保持后处理结果为生成器主锚点并将原图错开放置
新增原图标签、后端多产物布局测试和前端快照回归
同步更新图片画布方案与共享决策记录
This commit is contained in:
2026-07-13 18:28:54 +08:00
parent 55471e15de
commit 5536fba95e
10 changed files with 483 additions and 40 deletions
@@ -1145,6 +1145,7 @@ export function canvasAssetKindOrNull(value: unknown): CanvasAssetKind | null {
value === 'icon' ||
value === 'icon-spritesheet' ||
value === 'icon-spec' ||
value === 'editor_green_screen_source' ||
value === 'publication-material' ||
value === 'ui-design' ||
value === 'video' ||
@@ -20,6 +20,7 @@ export type CanvasAssetKind =
| 'icon'
| 'icon-spritesheet'
| 'icon-spec'
| 'editor_green_screen_source'
| 'publication-material'
| 'ui-design'
| 'video'
@@ -281,6 +281,12 @@ describe('ImageCanvasWorldView', () => {
title: '角色标签图层',
assetKind: 'character',
}),
createLayer({
id: 'layer-source',
resourceId: 'resource-source',
title: '角色原图',
assetKind: 'editor_green_screen_source',
}),
],
});
@@ -288,9 +294,11 @@ describe('ImageCanvasWorldView', () => {
const characterButton = screen.getByRole('button', {
name: '选择角色标签图层',
});
const sourceButton = screen.getByRole('button', { name: '选择角色原图' });
expect(within(layerButton).getByText('未知')).toBeTruthy();
expect(within(characterButton).getByText('角色')).toBeTruthy();
expect(within(sourceButton).getByText('原图')).toBeTruthy();
});
it('renders snap guides, marquee and floating generation status', () => {
@@ -205,6 +205,11 @@ const CANVAS_ASSET_KIND_TAG_OPTIONS: Array<{
{ value: 'icon', label: '图标', className: 'icon' },
{ value: 'icon-spritesheet', label: '图集', className: 'icon-spritesheet' },
{ value: 'icon-spec', label: '图标规范', className: 'icon-spec' },
{
value: 'editor_green_screen_source',
label: '原图',
className: 'source-image',
},
{
value: 'publication-material',
label: '宣发素材',
@@ -1307,8 +1307,32 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
layerId: 'layer-editor-resource-character',
resourceId: 'editor-resource-character',
},
{
layerId: 'layer-editor-resource-character-source',
resourceId: 'editor-resource-character-source',
},
],
resources: [
{
resourceId: 'editor-resource-character',
projectId: 'editor-project-1',
imageSrc: '/generated-character-drafts/editor/character.png',
width: 1024,
height: 1024,
sourceType: 'generated',
assetKind: 'character',
},
{
resourceId: 'editor-resource-character-source',
projectId: 'editor-project-1',
imageSrc:
'/generated-character-drafts/editor/character-green-screen-source.png',
width: 1024,
height: 1024,
sourceType: 'generated',
assetKind: 'editor_green_screen_source',
},
],
resources: [],
updatedAt: '2026-06-21T12:16:22.000Z',
},
});
@@ -1366,6 +1390,24 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
expect.objectContaining({
projectId: 'editor-project-1',
title: '角色项目',
layers: expect.arrayContaining([
expect.objectContaining({
resourceId: 'editor-resource-character',
}),
expect.objectContaining({
resourceId: 'editor-resource-character-source',
}),
]),
resources: expect.arrayContaining([
expect.objectContaining({
resourceId: 'editor-resource-character',
assetKind: 'character',
}),
expect.objectContaining({
resourceId: 'editor-resource-character-source',
assetKind: 'editor_green_screen_source',
}),
]),
}),
);
});
+5
View File
@@ -6335,6 +6335,11 @@ html[data-mobile-keyboard-open='true'] .platform-mobile-bottom-dock {
box-shadow: 0 8px 18px rgba(13, 148, 136, 0.24);
}
.image-canvas-editor__kind-badge--source-image {
background: rgba(71, 85, 105, 0.9);
box-shadow: 0 8px 18px rgba(71, 85, 105, 0.22);
}
.image-canvas-editor__kind-badge--ui-design {
background: rgba(245, 158, 11, 0.94);
box-shadow: 0 8px 18px rgba(245, 158, 11, 0.24);