From 3f3a6c4ab2e75cf04481fe690c17cb9b7ee39a98 Mon Sep 17 00:00:00 2001 From: kdletters Date: Wed, 15 Jul 2026 01:36:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=94=BB=E5=B8=83=E7=94=9F?= =?UTF-8?q?=E5=9B=BE=E4=BA=A4=E4=BB=98=E4=B8=8E=E7=B4=A0=E6=9D=90=E6=88=90?= =?UTF-8?q?=E6=9C=AC=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复 nanobanana 标量尺寸被误判为宽高的问题。 普通生图和快速编辑在内存完成尺寸变换后仅上传一次,变换失败保留 provider 原图。 移除快速编辑重复的原始输出素材,保留角色、图集和 UI 的独立中间产物。 后台将不重复计费的中间产物显示为不单独计费。 补充单次上传、降级交付和成本展示回归测试及相关文档。 --- .../pages/AdminEditorAssetQueryPage.test.tsx | 34 ++ .../src/pages/AdminEditorAssetQueryPage.tsx | 15 +- .../shared-memory/decision-log.md | 6 +- docs/project-memory/shared-memory/pitfalls.md | 8 + ...架构】图片画布编辑器MVP接入方案-2026-06-11.md | 4 +- ...】server-rs与SpacetimeDB数据契约-2026-05-15.md | 2 +- .../crates/api-server/src/editor_project.rs | 301 ++++++++++++------ 7 files changed, 272 insertions(+), 98 deletions(-) diff --git a/apps/admin-web/src/pages/AdminEditorAssetQueryPage.test.tsx b/apps/admin-web/src/pages/AdminEditorAssetQueryPage.test.tsx index c0cca000c..ddbc7a502 100644 --- a/apps/admin-web/src/pages/AdminEditorAssetQueryPage.test.tsx +++ b/apps/admin-web/src/pages/AdminEditorAssetQueryPage.test.tsx @@ -245,6 +245,40 @@ test('后台素材查询不展示分类筛选和分类列', async () => { expect(screen.queryByRole('columnheader', { name: '分类' })).toBeNull(); }); +test('后台素材查询将中间产物标记为不单独计费', async () => { + vi.mocked(listAdminEditorAssets).mockResolvedValueOnce({ + entries: [ + { + ...generatedAsset, + assetId: 'asset-source', + label: '角色形象原图', + assetKind: 'editor_green_screen_source', + generationCostMudPoints: 0, + }, + generatedAsset, + ], + nextCursor: null, + }); + + render( + , + ); + + const sourceRow = (await screen.findByText('角色形象原图')).closest('tr'); + const finalRow = screen.getByText('角色形象 1').closest('tr'); + expect(sourceRow).not.toBeNull(); + expect(finalRow).not.toBeNull(); + expect(within(sourceRow!).getByText('不单独计费')).toBeTruthy(); + expect(within(finalRow!).getByText('12 泥点')).toBeTruthy(); + + fireEvent.click(within(sourceRow!).getByRole('button', { name: '详情' })); + expect( + within(await screen.findByRole('dialog', { name: '素材详情' })).getByText( + '不单独计费', + ), + ).toBeTruthy(); +}); + test('后台素材查询缩略图使用 objectKey 换签后展示', async () => { render( , diff --git a/apps/admin-web/src/pages/AdminEditorAssetQueryPage.tsx b/apps/admin-web/src/pages/AdminEditorAssetQueryPage.tsx index 5bb5d25fa..d8276fe8f 100644 --- a/apps/admin-web/src/pages/AdminEditorAssetQueryPage.tsx +++ b/apps/admin-web/src/pages/AdminEditorAssetQueryPage.tsx @@ -24,6 +24,10 @@ const ADMIN_ASSET_READ_EXPIRE_SECONDS = 300; const ADMIN_ASSET_READ_DISPATCH_SPACING_MS = 40; const ADMIN_ASSET_READ_RETRY_DELAYS_MS = [400, 1_200, 3_000] as const; const ADMIN_ASSET_THUMBNAIL_ROOT_MARGIN = '240px 0px'; +const NON_BILLED_INTERMEDIATE_ASSET_KINDS = new Set([ + 'editor_green_screen_source', + 'editor_image_edit_source', +]); const AUDIO_ASSET_COVER_SRC = `${import.meta.env.DEV ? import.meta.env.BASE_URL : '/'}creation-home/audio-asset-cover.png`; let adminAssetReadDispatchTail = Promise.resolve(); @@ -217,7 +221,7 @@ export function AdminEditorAssetQueryPage({ {promptText} - {entry.generationCostMudPoints} 泥点 + {generationCostLabel(entry)}