画布没接住任务状态时按失败收口

- src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts:applyQueuedGeneration 返回 false 时不再静默复位成 idle(用户会以为没提交过、再点一次就是又一次已扣费的外部生成),改为写回失败态与明确文案
- src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts:新增 MODEL3D_QUEUE_HANDOFF_FAILED_MESSAGE,与「服务端没返回任务状态」区分开
- src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx:原「回到空闲态」用例改为断言失败态
This commit is contained in:
2026-09-24 17:32:13 +08:00
parent 3455b7a00f
commit 946c101630
3 changed files with 16 additions and 5 deletions
@@ -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` 同时决定提交地址与提交体契约。
@@ -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);
});
@@ -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) {
// 超时等失败也可能意味着服务端已经扣费(与其它生成链路的