diff --git a/src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts b/src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts index 669d8e48d..6f411f79a 100644 --- a/src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts +++ b/src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts @@ -36,6 +36,8 @@ export const MODEL3D_GENERATION_TIMEOUT_MESSAGE = '3D 生成请求超时,请稍后重试。'; export const MODEL3D_SUBMISSION_MISSING_QUEUE_STATE_MESSAGE = '3D 生成任务已提交,但服务端没有返回任务状态,请稍后重试。'; +export const MODEL3D_QUEUE_HANDOFF_FAILED_MESSAGE = + '3D 生成任务已提交,但画布没能接收任务状态,请刷新页面查看结果。'; /** * 提交计划按端点做成判别联合:`endpoint` 同时决定提交地址与提交体契约。 diff --git a/src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx b/src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx index c59097a23..1eec6fd16 100644 --- a/src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx +++ b/src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx @@ -23,7 +23,10 @@ import { createModel3dGenerationDraftFields, MODEL3D_PRICING_UNAVAILABLE_REASON, } from './Model3dGenerationFormModel'; -import { MODEL3D_SUBMISSION_MISSING_QUEUE_STATE_MESSAGE } from './Model3dGenerationSubmission'; +import { + MODEL3D_QUEUE_HANDOFF_FAILED_MESSAGE, + MODEL3D_SUBMISSION_MISSING_QUEUE_STATE_MESSAGE, +} from './Model3dGenerationSubmission'; import { useModel3dGenerationTask } from './useModel3dGenerationTask'; const submitModel3dTextToModelRequestMock = vi.hoisted(() => vi.fn()); @@ -218,7 +221,7 @@ describe('useModel3dGenerationTask', () => { expect(request.idempotencyKey.startsWith(`${persistedNonce}-`)).toBe(true); }); - it('排队链路没接手时回到可再次提交的空闲态', async () => { + it('排队链路没接手时不静默复位成空闲态', async () => { submitModel3dTextToModelRequestMock.mockResolvedValue({ operationId: 'task-1', jobKind: 'model3d_text_to_model', @@ -234,7 +237,10 @@ describe('useModel3dGenerationTask', () => { await result.current.submitModel3dGeneration(createDialog()); }); - expect(result.current.dialog.status).toBe('idle'); + expect(result.current.dialog.status).toBe('failed'); + expect(result.current.dialog.errorMessage).toBe( + MODEL3D_QUEUE_HANDOFF_FAILED_MESSAGE, + ); expect(result.current.dialog.composerOpen).toBe(true); }); diff --git a/src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts b/src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts index 00349e2e9..59987ce66 100644 --- a/src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts +++ b/src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts @@ -17,6 +17,7 @@ import { readEditorModel3dPricingConfig } from '../ImageCanvasGenerationModel'; import { isModel3dGenerationMode } from './Model3dGenerationFormModel'; import { buildModel3dSubmissionPlan, + MODEL3D_QUEUE_HANDOFF_FAILED_MESSAGE, MODEL3D_SUBMISSION_MISSING_QUEUE_STATE_MESSAGE, model3dQueueStateFromResponse, resolveModel3dGenerationErrorMessage, @@ -150,11 +151,13 @@ export function useModel3dGenerationTask({ ) { return; } + // 画布没接住这份任务状态时不能静默复位成 idle:用户会以为没提交过, + // 再点一次就是又一次外部生成(已经扣过费)。按失败收口,让用户先去看结果。 updateCanvasGenerationDialogById(dialogId, (currentDialog) => ({ ...currentDialog, - status: 'idle', + status: 'failed', composerOpen: true, - errorMessage: undefined, + errorMessage: MODEL3D_QUEUE_HANDOFF_FAILED_MESSAGE, })); } catch (error) { // 超时等失败也可能意味着服务端已经扣费(与其它生成链路的