修复图片编辑器生图登录提示

调整编辑器 API 鉴权策略,允许通过 refresh cookie 静默补 access token

真实生图遇到未授权时显示登录提示,不再直接暴露 requestId

补充编辑器组件和客户端测试,并更新方案文档与跟踪记录
This commit is contained in:
2026-06-13 17:48:21 +08:00
parent 96c36f0b50
commit 3f4dba97ba
6 changed files with 68 additions and 13 deletions

View File

@@ -4,6 +4,7 @@ import { fireEvent, render, screen, waitFor, within } from '@testing-library/rea
import userEvent from '@testing-library/user-event';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { ApiClientError } from '../../services/apiClient';
import { ImageCanvasEditorView } from './ImageCanvasEditorView';
const generateEditorImageMock = vi.hoisted(() => vi.fn());
@@ -341,6 +342,30 @@ describe('ImageCanvasEditorView', () => {
expect(screen.queryByAltText(/画布图片:生成图片/)).toBeNull();
});
it('asks the user to log in when real generation is unauthorized', async () => {
generateEditorImageMock.mockRejectedValueOnce(
new ApiClientError({
message: '未授权访问requestId: web-login-required',
status: 401,
code: 'UNAUTHORIZED',
}),
);
render(<ImageCanvasEditorView />);
fireEvent.click(screen.getByRole('button', { name: '生成工具' }));
fireEvent.change(screen.getByLabelText('生成提示词'), {
target: { value: '一张需要登录生成的图' },
});
fireEvent.click(screen.getByRole('button', { name: '生成' }));
await waitFor(() => {
expect(screen.getByRole('alert').textContent).toBe(
'请先登录后再生成图片',
);
});
expect(screen.queryByText(/requestId/u)).toBeNull();
});
it('switches tools and restores the previous tool after holding Space', async () => {
const user = userEvent.setup();
render(<ImageCanvasEditorView />);

View File

@@ -43,6 +43,7 @@ import {
loadOrCreateRecentEditorProject,
saveEditorProjectLayout,
} from '../../services/image-editor/editorProjectClient';
import { ApiClientError } from '../../services/apiClient';
type EditorAsset = {
id: string;
@@ -427,6 +428,19 @@ function getPointerId(event: ReactPointerEvent<HTMLElement>) {
return Number.isFinite(nativeId) ? nativeId : -1;
}
function resolveImageGenerationErrorMessage(error: unknown) {
if (
error instanceof ApiClientError &&
(error.status === 401 || error.status === 403)
) {
return '请先登录后再生成图片';
}
return error instanceof Error && error.message.trim()
? error.message
: '生成图片失败';
}
export function ImageCanvasEditorView() {
const canvasViewportRef = useRef<HTMLDivElement | null>(null);
const uploadInputRef = useRef<HTMLInputElement | null>(null);
@@ -1016,10 +1030,7 @@ export function ImageCanvasEditorView() {
...dialog,
prompt: normalizedPrompt,
status: 'failed',
errorMessage:
error instanceof Error && error.message.trim()
? error.message
: '生成图片失败',
errorMessage: resolveImageGenerationErrorMessage(error),
});
}
};