feat: 优化聊天附件拖拽上传提示
- 不支持格式改用轻量提示并展示支持范围 - 扩展拖拽区域并增加全区上传覆盖层 - 补充文档和图片格式校验测试
This commit is contained in:
@@ -107,6 +107,21 @@ describe('useChatDocumentUploads', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects unsupported files without adding an error attachment', async () => {
|
||||
const uploads = useChatDocumentUploads();
|
||||
const result = await uploads.addFiles(
|
||||
[new File(['archive'], 'unsupported.zip', { type: 'application/zip' })],
|
||||
{ agentId: 'agent-1', mode: 'FORMAL', sessionId: 'session-1' },
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
rejectedCount: 0,
|
||||
unsupportedCount: 1,
|
||||
});
|
||||
expect(uploads.items.value).toEqual([]);
|
||||
expect(mediaApi.uploadAgentChatDocument).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('exposes a server read failure without continuing to poll', async () => {
|
||||
mediaApi.uploadAgentChatDocument.mockResolvedValue({
|
||||
data: {
|
||||
|
||||
@@ -59,4 +59,19 @@ describe('useChatImageUploads', () => {
|
||||
expect(observedStatuses.at(-1)).toBe('ready');
|
||||
expect(uploads.uploadIds.value).toEqual(['upload-1']);
|
||||
});
|
||||
|
||||
it('rejects unsupported images without adding an error attachment', async () => {
|
||||
const uploads = useChatImageUploads();
|
||||
const result = await uploads.addFiles(
|
||||
[new File(['vector'], 'unsupported.svg', { type: 'image/svg+xml' })],
|
||||
{ agentId: 'agent-1', mode: 'FORMAL', sessionId: 'session-1' },
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
rejectedCount: 0,
|
||||
unsupportedCount: 1,
|
||||
});
|
||||
expect(uploads.items.value).toEqual([]);
|
||||
expect(mediaApi.uploadAgentChatImage).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import type { AgentComposerMode, AgentMediaUpload } from './mediaApi';
|
||||
|
||||
const MAX_IMAGES = 5;
|
||||
const MAX_IMAGE_BYTES = 10 * 1024 * 1024;
|
||||
export const CHAT_IMAGE_SUPPORTED_FORMATS = 'PNG、JPG、JPEG、WebP、GIF、BMP';
|
||||
const ACCEPTED_EXTENSIONS = new Set([
|
||||
'bmp',
|
||||
'gif',
|
||||
@@ -26,6 +27,11 @@ interface LocalAttachment extends ChatImageAttachment {
|
||||
file?: File;
|
||||
}
|
||||
|
||||
interface ChatImageAddFilesResult {
|
||||
rejectedCount: number;
|
||||
unsupportedCount: number;
|
||||
}
|
||||
|
||||
function createLocalId() {
|
||||
return `agent-image-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
|
||||
}
|
||||
@@ -69,12 +75,20 @@ export function useChatImageUploads() {
|
||||
);
|
||||
|
||||
async function addFiles(files: File[], context: UploadContext) {
|
||||
const supportedFiles: File[] = [];
|
||||
let unsupportedCount = 0;
|
||||
for (const file of files) {
|
||||
if (ACCEPTED_EXTENSIONS.has(extensionOf(file))) {
|
||||
supportedFiles.push(file);
|
||||
} else {
|
||||
unsupportedCount++;
|
||||
}
|
||||
}
|
||||
const available = Math.max(0, MAX_IMAGES - items.value.length);
|
||||
const accepted = files.slice(0, available);
|
||||
const rejectedCount = Math.max(0, files.length - accepted.length);
|
||||
const accepted = supportedFiles.slice(0, available);
|
||||
const rejectedCount = Math.max(0, supportedFiles.length - accepted.length);
|
||||
const uploads: Promise<void>[] = [];
|
||||
for (const file of accepted) {
|
||||
const extension = extensionOf(file);
|
||||
const local: LocalAttachment = {
|
||||
file,
|
||||
localId: createLocalId(),
|
||||
@@ -85,11 +99,6 @@ export function useChatImageUploads() {
|
||||
status: 'uploading',
|
||||
};
|
||||
items.value.push(local);
|
||||
if (!ACCEPTED_EXTENSIONS.has(extension)) {
|
||||
local.status = 'error';
|
||||
local.error = '仅支持 PNG、JPG、JPEG、WebP、GIF、BMP';
|
||||
continue;
|
||||
}
|
||||
if (file.size > MAX_IMAGE_BYTES) {
|
||||
local.status = 'error';
|
||||
local.error = '单张图片不能超过 10 MiB';
|
||||
@@ -98,7 +107,10 @@ export function useChatImageUploads() {
|
||||
uploads.push(upload(local, context));
|
||||
}
|
||||
await Promise.all(uploads);
|
||||
return rejectedCount;
|
||||
return {
|
||||
rejectedCount,
|
||||
unsupportedCount,
|
||||
} satisfies ChatImageAddFilesResult;
|
||||
}
|
||||
|
||||
async function upload(item: LocalAttachment, context: UploadContext) {
|
||||
|
||||
Reference in New Issue
Block a user