From 4e46202c10dc894f7e3bb83326808571ff180f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 22 Sep 2026 17:00:13 +0800 Subject: [PATCH] =?UTF-8?q?3D=20=E6=8F=90=E4=BA=A4=E6=94=B6=E5=88=B0?= =?UTF-8?q?=E6=97=A0=E4=BB=BB=E5=8A=A1=E7=8A=B6=E6=80=81=E7=9A=84=E6=88=90?= =?UTF-8?q?=E5=8A=9F=E5=93=8D=E5=BA=94=E4=B8=8D=E5=86=8D=E9=9D=99=E9=BB=98?= =?UTF-8?q?=E5=A4=8D=E4=BD=8D=20-=20=E6=96=B0=E5=A2=9E=20MODEL3D=5FSUBMISS?= =?UTF-8?q?ION=5FMISSING=5FQUEUE=5FSTATE=5FMESSAGE=20=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E6=96=87=E6=A1=88=20-=20=E7=A9=BA=20body=20=E6=88=96=E7=BC=BA?= =?UTF-8?q?=20status=20=E7=9A=84=202xx=20=E5=93=8D=E5=BA=94=E6=94=B9?= =?UTF-8?q?=E5=88=A4=E5=A4=B1=E8=B4=A5=E6=80=81=E5=B9=B6=E4=BF=9D=E7=95=99?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=EF=BC=8C=E4=B8=8D=E5=86=8D=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E5=9B=9E=20idle=20-=20=E8=A1=A5=E7=94=A8=E4=BE=8B=E6=96=AD?= =?UTF-8?q?=E8=A8=80=E4=B8=8D=E5=86=8D=E8=A7=A6=E5=8F=91=E6=8E=92=E9=98=9F?= =?UTF-8?q?=E9=93=BE=E8=B7=AF=E4=B8=94=E5=AF=B9=E8=AF=9D=E6=A1=86=E8=BF=9B?= =?UTF-8?q?=E5=85=A5=E5=A4=B1=E8=B4=A5=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Model3dGenerationSubmission.ts | 2 ++ .../useModel3dGenerationTask.test.tsx | 21 +++++++++++++++++++ .../useModel3dGenerationTask.ts | 17 ++++++++++++--- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts b/src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts index 21f2c59c3..e2ee10ed7 100644 --- a/src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts +++ b/src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts @@ -27,6 +27,8 @@ export const MODEL3D_GENERATION_FAILURE_MESSAGE = '生成 3D 模型失败,请稍后重试。'; export const MODEL3D_GENERATION_TIMEOUT_MESSAGE = '3D 生成请求超时,请稍后重试。'; +export const MODEL3D_SUBMISSION_MISSING_QUEUE_STATE_MESSAGE = + '3D 生成任务已提交,但服务端没有返回任务状态,请稍后重试。'; export type Model3dSubmissionPlan = { endpoint: Model3dPricingEndpoint; diff --git a/src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx b/src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx index a67b977f9..b10b6b038 100644 --- a/src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx +++ b/src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx @@ -22,6 +22,7 @@ import { createModel3dGenerationDraftFields, MODEL3D_PRICING_UNAVAILABLE_REASON, } from './Model3dGenerationFormModel'; +import { MODEL3D_SUBMISSION_MISSING_QUEUE_STATE_MESSAGE } from './Model3dGenerationSubmission'; import { useModel3dGenerationTask } from './useModel3dGenerationTask'; const submitModel3dGenerationRequestMock = vi.hoisted(() => vi.fn()); @@ -218,6 +219,26 @@ describe('useModel3dGenerationTask', () => { expect(result.current.dialog.composerOpen).toBe(true); }); + it('2xx 但没有任务状态时给出失败提示,而不是静默复位', async () => { + // requestJson 在空 body 时返回 null,这里覆盖「成功但没有 status」的形态。 + submitModel3dGenerationRequestMock.mockResolvedValue(null); + const applyQueuedGeneration = vi.fn(async () => true); + const { result } = renderTask({ + dialog: createDialog(), + applyQueuedGeneration, + }); + + await act(async () => { + await result.current.submitModel3dGeneration(createDialog()); + }); + + expect(applyQueuedGeneration).not.toHaveBeenCalled(); + expect(result.current.dialog.status).toBe('failed'); + expect(result.current.dialog.errorMessage).toBe( + MODEL3D_SUBMISSION_MISSING_QUEUE_STATE_MESSAGE, + ); + }); + it('请求失败时留在面板上展示失败原因', async () => { submitModel3dGenerationRequestMock.mockRejectedValue( new Error('3D 模型生成失败,请稍后重试。'), diff --git a/src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts b/src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts index d19517121..666d00be8 100644 --- a/src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts +++ b/src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts @@ -14,6 +14,7 @@ import { readEditorModel3dPricingConfig } from '../ImageCanvasGenerationModel'; import { isModel3dGenerationMode } from './Model3dGenerationFormModel'; import { buildModel3dSubmissionPlan, + MODEL3D_SUBMISSION_MISSING_QUEUE_STATE_MESSAGE, model3dQueueStateFromResponse, resolveModel3dGenerationErrorMessage, resolveModel3dResultTitle, @@ -106,9 +107,19 @@ export function useModel3dGenerationTask({ idempotencyKey: planResult.plan.requestKey, }); const queueState = model3dQueueStateFromResponse(response); + if (!queueState) { + // 2xx 但没有任务状态(空 body 或缺 status 的 payload)不能当成功静默复位: + // 用户既看不到任务也没有任何提示,服务端细节被丢掉。 + updateCanvasGenerationDialogById(dialogId, (currentDialog) => ({ + ...currentDialog, + status: 'failed', + composerOpen: true, + errorMessage: MODEL3D_SUBMISSION_MISSING_QUEUE_STATE_MESSAGE, + })); + return; + } if ( - queueState && - (await applyQueuedGeneration( + await applyQueuedGeneration( { queueState }, projectId, applyProjectSnapshot, @@ -116,7 +127,7 @@ export function useModel3dGenerationTask({ onWalletBalanceMayHaveChanged, onGenerationWarning, dialogId, - )) + ) ) { return; }