优化 AI 设计任务失败提示
问题:客户端直接展示 policy_blocked 等内部错误码。 实现:统一转换为中文设计语言提示,并补充策略拦截场景回归测试。
This commit is contained in:
@@ -37,6 +37,19 @@ import type {
|
|||||||
} from '../../../shared/image-workspace';
|
} from '../../../shared/image-workspace';
|
||||||
|
|
||||||
const ACTIVE_TASK_STATUSES = new Set<DesignTaskStatus>(['queued', 'running']);
|
const ACTIVE_TASK_STATUSES = new Set<DesignTaskStatus>(['queued', 'running']);
|
||||||
|
const TASK_FAILURE_MESSAGES: Record<string, string> = {
|
||||||
|
policy_blocked: '内容可能涉及版权或安全风险,请调整设计后重试',
|
||||||
|
budget_denied: '当前设计点不足,无法开始生成',
|
||||||
|
quote_expired: '生成方案已过期,请重新确认',
|
||||||
|
asset_rejected: '生成结果未通过媒体检查,请调整设计后重试',
|
||||||
|
dependency_unavailable: '生成服务暂时不可用,请稍后重试',
|
||||||
|
submission_unknown: '正在确认生成请求状态,请稍后查看',
|
||||||
|
submission_not_accepted: '生成请求未被服务接受,请重新确认后再试',
|
||||||
|
generation_failed: '生成未完成,请调整设计或稍后重试',
|
||||||
|
result_persist_failed: '生成结果保存失败,请稍后重试',
|
||||||
|
cancelled: '生成任务已取消',
|
||||||
|
expired: '生成任务已过期,请重新确认',
|
||||||
|
};
|
||||||
const CONFIRMATION_UNAVAILABLE_MESSAGE = (
|
const CONFIRMATION_UNAVAILABLE_MESSAGE = (
|
||||||
'当前没有可确认的生成报价,请先让设计 Agent 完成方案与报价。'
|
'当前没有可确认的生成报价,请先让设计 Agent 完成方案与报价。'
|
||||||
);
|
);
|
||||||
@@ -61,6 +74,10 @@ function taskStatusLabel(status: DesignTaskStatus): string {
|
|||||||
return '失败';
|
return '失败';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function taskFailureMessage(code: string): string {
|
||||||
|
return TASK_FAILURE_MESSAGES[code] ?? '生成未完成,请稍后重试';
|
||||||
|
}
|
||||||
|
|
||||||
function mediumLabel(medium: 'image' | 'video'): string {
|
function mediumLabel(medium: 'image' | 'video'): string {
|
||||||
return medium === 'video' ? '视频' : '图片';
|
return medium === 'video' ? '视频' : '图片';
|
||||||
}
|
}
|
||||||
@@ -153,7 +170,7 @@ function TaskCard({ task }: { task: DesignGenerationTask }) {
|
|||||||
</p>
|
</p>
|
||||||
{task.failureCode ? (
|
{task.failureCode ? (
|
||||||
<p role="alert" className="mt-2 rounded-lg bg-destructive/10 px-2 py-1.5 text-[11px] font-semibold text-destructive">
|
<p role="alert" className="mt-2 rounded-lg bg-destructive/10 px-2 py-1.5 text-[11px] font-semibold text-destructive">
|
||||||
{task.failureCode}
|
{taskFailureMessage(task.failureCode)}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -482,6 +482,21 @@ describe('ImageCanvas Workspace-first design experience', () => {
|
|||||||
expect(confirmImageWorkspaceGenerationMock).not.toHaveBeenCalled();
|
expect(confirmImageWorkspaceGenerationMock).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders policy-blocked generation tasks with a user-facing design message', async () => {
|
||||||
|
fetchImageWorkspaceTasksMock.mockResolvedValue([{
|
||||||
|
...taskFixture,
|
||||||
|
status: 'failed',
|
||||||
|
failureCode: 'policy_blocked',
|
||||||
|
resultAssets: [],
|
||||||
|
}]);
|
||||||
|
|
||||||
|
render(<MemoryRouter><ImageCanvas /></MemoryRouter>);
|
||||||
|
|
||||||
|
const alert = await screen.findByRole('alert');
|
||||||
|
expect(alert).toHaveTextContent('内容可能涉及版权或安全风险,请调整设计后重试');
|
||||||
|
expect(alert).not.toHaveTextContent('policy_blocked');
|
||||||
|
});
|
||||||
|
|
||||||
it('renders a new task pushed by the design event stream without repeated polling', async () => {
|
it('renders a new task pushed by the design event stream without repeated polling', async () => {
|
||||||
const queuedTask = {
|
const queuedTask = {
|
||||||
...taskFixture,
|
...taskFixture,
|
||||||
|
|||||||
Reference in New Issue
Block a user