fix: 修复 Chrome 90 智能体文档上传失败
- 复用兼容 UUID 生成逻辑,移除对 crypto.randomUUID 的依赖 - 补充旧浏览器缺失 randomUUID 时的上传回归测试
This commit is contained in:
@@ -16,6 +16,7 @@ vi.mock('./mediaApi', () => mediaApi);
|
|||||||
describe('useChatDocumentUploads', () => {
|
describe('useChatDocumentUploads', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
|
vi.unstubAllGlobals();
|
||||||
Object.values(mediaApi).forEach((mock) => mock.mockReset());
|
Object.values(mediaApi).forEach((mock) => mock.mockReset());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -68,6 +69,44 @@ describe('useChatDocumentUploads', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses getRandomValues when randomUUID is unavailable', async () => {
|
||||||
|
const getRandomValues = vi.fn((values: Uint8Array) => {
|
||||||
|
values.fill(171);
|
||||||
|
return values;
|
||||||
|
});
|
||||||
|
vi.stubGlobal('crypto', { getRandomValues });
|
||||||
|
mediaApi.uploadAgentChatDocument.mockImplementation(
|
||||||
|
async (file, _context, uploadId) => ({
|
||||||
|
data: {
|
||||||
|
attachmentRef: 'document:chrome-90',
|
||||||
|
mimeType: file.type,
|
||||||
|
name: file.name,
|
||||||
|
size: file.size,
|
||||||
|
status: 'READY',
|
||||||
|
uploadId,
|
||||||
|
},
|
||||||
|
errorCode: 0,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const uploads = useChatDocumentUploads();
|
||||||
|
await uploads.addFiles(
|
||||||
|
[new File(['document'], 'chrome-90.pdf', { type: 'application/pdf' })],
|
||||||
|
{ agentId: 'agent-1', mode: 'FORMAL', sessionId: 'session-1' },
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(getRandomValues).toHaveBeenCalled();
|
||||||
|
expect(mediaApi.uploadAgentChatDocument).toHaveBeenCalledWith(
|
||||||
|
expect.any(File),
|
||||||
|
{ agentId: 'agent-1', mode: 'FORMAL', sessionId: 'session-1' },
|
||||||
|
expect.stringMatching(/^[a-f0-9]{32}$/),
|
||||||
|
);
|
||||||
|
expect(uploads.items.value[0]).toMatchObject({
|
||||||
|
status: 'ready',
|
||||||
|
uploadId: expect.stringMatching(/^[a-f0-9]{32}$/),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('exposes a server read failure without continuing to poll', async () => {
|
it('exposes a server read failure without continuing to poll', async () => {
|
||||||
mediaApi.uploadAgentChatDocument.mockResolvedValue({
|
mediaApi.uploadAgentChatDocument.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
"@easyflow/icons": "workspace:*",
|
"@easyflow/icons": "workspace:*",
|
||||||
"@easyflow/locales": "workspace:*",
|
"@easyflow/locales": "workspace:*",
|
||||||
"@easyflow/types": "workspace:*",
|
"@easyflow/types": "workspace:*",
|
||||||
|
"@easyflow/utils": "workspace:*",
|
||||||
"@incremark/theme": "1.0.2",
|
"@incremark/theme": "1.0.2",
|
||||||
"@incremark/vue": "1.0.2",
|
"@incremark/vue": "1.0.2",
|
||||||
"@vueuse/core": "catalog:",
|
"@vueuse/core": "catalog:",
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import type { ChatDocumentAttachment } from './types';
|
|||||||
|
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
|
import { uuid } from '@easyflow/utils';
|
||||||
|
|
||||||
const MAX_DOCUMENTS = 3;
|
const MAX_DOCUMENTS = 3;
|
||||||
const MAX_TOTAL_BYTES = 30 * 1024 * 1024;
|
const MAX_TOTAL_BYTES = 30 * 1024 * 1024;
|
||||||
const MAX_OFFICE_BYTES = 20 * 1024 * 1024;
|
const MAX_OFFICE_BYTES = 20 * 1024 * 1024;
|
||||||
@@ -61,7 +63,7 @@ function createLocalId() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createUploadId() {
|
function createUploadId() {
|
||||||
return crypto.randomUUID().replaceAll('-', '');
|
return uuid().replaceAll('-', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function extensionOf(file: File) {
|
function extensionOf(file: File) {
|
||||||
@@ -170,11 +172,11 @@ export function createChatDocumentUploads(api: ChatDocumentUploadApi) {
|
|||||||
context: ChatDocumentUploadContext,
|
context: ChatDocumentUploadContext,
|
||||||
) {
|
) {
|
||||||
if (!item.file) return;
|
if (!item.file) return;
|
||||||
item.uploadId ||= createUploadId();
|
|
||||||
item.status = 'uploading';
|
item.status = 'uploading';
|
||||||
item.error = undefined;
|
item.error = undefined;
|
||||||
const currentLifecycle = lifecycle;
|
const currentLifecycle = lifecycle;
|
||||||
try {
|
try {
|
||||||
|
item.uploadId ||= createUploadId();
|
||||||
const response = await api.upload(item.file, context, item.uploadId);
|
const response = await api.upload(item.file, context, item.uploadId);
|
||||||
if (response.errorCode !== 0 || !response.data) {
|
if (response.errorCode !== 0 || !response.data) {
|
||||||
throw new Error(response.message || '文档上传失败');
|
throw new Error(response.message || '文档上传失败');
|
||||||
|
|||||||
3
easyflow-ui-admin/pnpm-lock.yaml
generated
3
easyflow-ui-admin/pnpm-lock.yaml
generated
@@ -1441,6 +1441,9 @@ importers:
|
|||||||
'@easyflow/types':
|
'@easyflow/types':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../types
|
version: link:../../types
|
||||||
|
'@easyflow/utils':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../utils
|
||||||
'@incremark/theme':
|
'@incremark/theme':
|
||||||
specifier: 1.0.2
|
specifier: 1.0.2
|
||||||
version: 1.0.2
|
version: 1.0.2
|
||||||
|
|||||||
Reference in New Issue
Block a user