修正图标素材只生成透明图集
后端图标素材生成只持久化扣绿后的 spritesheet 图集。 响应兼容保留 iconImageSrcs 但图标生成固定返回空数组。 前端测试改为验证只回填图集且不生成独立图标层。 同步 OpenAPI、编辑器文档和项目记忆中的图标素材生成约定。
This commit is contained in:
@@ -70,6 +70,16 @@ vi.mock('./ImageCanvasUiAssetExtractionRasterModel', () => ({
|
||||
renderUiDesignAssetExtractionMarkedImageMock,
|
||||
}));
|
||||
|
||||
vi.mock('./ImageCanvasProjectCoverSnapshotModel', async () => {
|
||||
const actual = await vi.importActual<
|
||||
typeof import('./ImageCanvasProjectCoverSnapshotModel')
|
||||
>('./ImageCanvasProjectCoverSnapshotModel');
|
||||
return {
|
||||
...actual,
|
||||
createProjectCoverSnapshotBlob: vi.fn(async () => null),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ImageCanvasEditorView generation integration', () => {
|
||||
setupImageCanvasEditorViewTestLifecycle({
|
||||
generateEditorImageMock,
|
||||
@@ -1488,14 +1498,7 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
spritesheetImageSrc: 'data:image/png;base64,sheet-gpt-model',
|
||||
spritesheetWidth: 1024,
|
||||
spritesheetHeight: 1024,
|
||||
iconImageSrcs: [
|
||||
{
|
||||
name: '返回按钮',
|
||||
imageSrc: 'data:image/png;base64,back',
|
||||
width: 128,
|
||||
height: 128,
|
||||
},
|
||||
],
|
||||
iconImageSrcs: [],
|
||||
prompt: '图标 prompt',
|
||||
actualPrompt: '图标 prompt',
|
||||
model: 'gpt-image-2',
|
||||
@@ -2241,7 +2244,7 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
expect(screen.getByAltText('画布图片:拼图素材')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('opens icon asset generation panel, only picks icon specs, and lays generated icons on canvas', async () => {
|
||||
it('opens icon asset generation panel, only picks icon specs, and lays only the generated spritesheet on canvas', async () => {
|
||||
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
|
||||
projectId: 'editor-project-icons',
|
||||
title: '图标素材画布',
|
||||
@@ -2284,20 +2287,7 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
spritesheetImageSrc: 'data:image/png;base64,sheet',
|
||||
spritesheetWidth: 512,
|
||||
spritesheetHeight: 512,
|
||||
iconImageSrcs: [
|
||||
{
|
||||
name: '返回按钮',
|
||||
imageSrc: 'data:image/png;base64,back-icon',
|
||||
width: 96,
|
||||
height: 96,
|
||||
},
|
||||
{
|
||||
name: '设置按钮',
|
||||
imageSrc: 'data:image/png;base64,setting-icon',
|
||||
width: 96,
|
||||
height: 96,
|
||||
},
|
||||
],
|
||||
iconImageSrcs: [],
|
||||
prompt: '图标 prompt',
|
||||
actualPrompt: '图标 prompt',
|
||||
model: 'gemini-3.1-flash-image-preview',
|
||||
@@ -2324,7 +2314,7 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
name: '素材描述',
|
||||
}) as HTMLTextAreaElement
|
||||
).value,
|
||||
).toBe('返回按钮\n设置按钮\n下一关按钮\n提示按钮\n原图按钮\n冻结按钮');
|
||||
).toBe('');
|
||||
|
||||
fireEvent.click(
|
||||
within(iconPanel).getByRole('button', { name: '图标规范' }),
|
||||
@@ -2371,34 +2361,37 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
);
|
||||
fireEvent.click(within(iconPanel).getByRole('button', { name: '生成' }));
|
||||
|
||||
expect(generateEditorIconSpritesheetMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
referenceImageSrc: 'data:image/png;base64,icon-spec',
|
||||
iconDescriptions: ['返回按钮', '设置按钮'],
|
||||
model: 'gemini-3.1-flash-image-preview',
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '1K',
|
||||
projectId: 'editor-project-icons',
|
||||
assetFolderId: 'project',
|
||||
generationInputs: expect.objectContaining({
|
||||
fields: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
title: '素材描述',
|
||||
value: '返回按钮\n设置按钮',
|
||||
}),
|
||||
]),
|
||||
await waitFor(() => {
|
||||
expect(generateEditorIconSpritesheetMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
referenceImageSrc: 'data:image/png;base64,icon-spec',
|
||||
iconDescriptions: ['返回按钮', '设置按钮'],
|
||||
model: 'gemini-3.1-flash-image-preview',
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '1K',
|
||||
projectId: 'editor-project-icons',
|
||||
assetFolderId: 'project',
|
||||
generationInputs: expect.objectContaining({
|
||||
fields: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
title: '素材描述',
|
||||
value: '返回按钮\n设置按钮',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByAltText('画布图片:返回按钮')).toBeTruthy();
|
||||
expect(screen.getByAltText('画布图片:设置按钮')).toBeTruthy();
|
||||
expect(screen.getByAltText(/图层缩略图:图标素材图集/u)).toBeTruthy();
|
||||
});
|
||||
expect(screen.queryByAltText('画布图片:返回按钮')).toBeNull();
|
||||
expect(screen.queryByAltText('画布图片:设置按钮')).toBeNull();
|
||||
expect(screen.queryByLabelText('图标素材生成占位图')).toBeNull();
|
||||
expect(screen.getAllByText('图标')).toHaveLength(2);
|
||||
expect(screen.getByText('图集')).toBeTruthy();
|
||||
fireEvent.click(
|
||||
screen.getAllByRole('button', { name: '查看返回按钮图片信息' })[0]!,
|
||||
screen.getByRole('button', { name: /查看图标素材图集.*图片信息/u }),
|
||||
);
|
||||
const iconInfoPanel = screen.getByRole('dialog', { name: '图片信息' });
|
||||
expect(within(iconInfoPanel).queryByText('Prompt')).toBeNull();
|
||||
@@ -2573,14 +2566,7 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
spritesheetImageSrc: 'data:image/png;base64,cmVuYW1lZC1zaGVldA==',
|
||||
spritesheetWidth: 512,
|
||||
spritesheetHeight: 512,
|
||||
iconImageSrcs: [
|
||||
{
|
||||
name: '背包按钮',
|
||||
imageSrc: 'data:image/png;base64,YmFncGFjay1pY29u',
|
||||
width: 96,
|
||||
height: 96,
|
||||
},
|
||||
],
|
||||
iconImageSrcs: [],
|
||||
prompt: '图标 prompt',
|
||||
actualPrompt: '图标 prompt',
|
||||
model: 'gemini-3.1-flash-image-preview',
|
||||
@@ -2651,20 +2637,23 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
);
|
||||
fireEvent.click(within(iconPanel).getByRole('button', { name: '生成' }));
|
||||
|
||||
expect(generateEditorIconSpritesheetMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
referenceImageSrc: 'data:image/png;base64,cmVuYW1lZC1pY29uLXNwZWM=',
|
||||
iconDescriptions: ['背包按钮'],
|
||||
model: 'gemini-3.1-flash-image-preview',
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '1K',
|
||||
projectId: 'editor-project-default',
|
||||
assetFolderId: 'project',
|
||||
}),
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByAltText('画布图片:背包按钮')).toBeTruthy();
|
||||
expect(generateEditorIconSpritesheetMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
referenceImageSrc: 'data:image/png;base64,cmVuYW1lZC1pY29uLXNwZWM=',
|
||||
iconDescriptions: ['背包按钮'],
|
||||
model: 'gemini-3.1-flash-image-preview',
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '1K',
|
||||
projectId: 'editor-project-default',
|
||||
assetFolderId: 'project',
|
||||
}),
|
||||
);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByAltText(/图层缩略图:图标素材图集/u)).toBeTruthy();
|
||||
});
|
||||
expect(screen.queryByAltText('画布图片:背包按钮')).toBeNull();
|
||||
});
|
||||
|
||||
it('exits character generation canvas picking with Escape', () => {
|
||||
|
||||
@@ -1537,10 +1537,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
model: 'gpt-image-2',
|
||||
provider: 'VectorEngine',
|
||||
taskId: 'task-icons',
|
||||
iconImageSrcs: [
|
||||
createIconResult('返回按钮', 'data:image/png;base64,back'),
|
||||
createIconResult('设置按钮', 'data:image/png;base64,setting'),
|
||||
],
|
||||
iconImageSrcs: [],
|
||||
});
|
||||
render(
|
||||
<SubmissionWorkflowHarness
|
||||
@@ -1586,11 +1583,8 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
'layer-icon-spritesheet-1:图标素材图集 1:-:icon-spritesheet',
|
||||
);
|
||||
});
|
||||
expect(screen.getByTestId('layers').textContent).toContain(
|
||||
'layer-icon-2:返回按钮:-:icon',
|
||||
);
|
||||
expect(screen.getByTestId('layers').textContent).toContain(
|
||||
'layer-icon-3:设置按钮:-:icon',
|
||||
expect(screen.getByTestId('layers').textContent).not.toContain(
|
||||
'layer-icon-2',
|
||||
);
|
||||
expect(screen.getByTestId('selected').textContent).toBe(
|
||||
'layer-icon-spritesheet-1',
|
||||
@@ -1616,9 +1610,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
model: 'gpt-image-2',
|
||||
provider: 'VectorEngine',
|
||||
taskId: 'task-icons',
|
||||
iconImageSrcs: [
|
||||
createIconResult('返回按钮', 'data:image/png;base64,back'),
|
||||
],
|
||||
iconImageSrcs: [],
|
||||
});
|
||||
render(
|
||||
<SubmissionWorkflowHarness
|
||||
|
||||
@@ -780,14 +780,7 @@ describe('editorProjectClient', () => {
|
||||
spritesheetImageSrc: 'data:image/png;base64,sheet',
|
||||
spritesheetWidth: 512,
|
||||
spritesheetHeight: 512,
|
||||
iconImageSrcs: [
|
||||
{
|
||||
name: '返回按钮',
|
||||
imageSrc: 'data:image/png;base64,back',
|
||||
width: 96,
|
||||
height: 96,
|
||||
},
|
||||
],
|
||||
iconImageSrcs: [],
|
||||
prompt: '图标素材 prompt',
|
||||
actualPrompt: '图标素材 prompt',
|
||||
model: 'gemini-3.1-flash-image-preview',
|
||||
|
||||
Reference in New Issue
Block a user