feat(web-client): add per-type file size validation on upload
Enforce Claude API file size limits at upload time with user-friendly error messages: - Images: max 5MB (Claude API hard limit) - PDF: max 25MB (32MB request limit minus headroom) - Other documents: max 50MB (general upload limit) Replaced duplicate ALLOWED_TYPES/MAX_FILE_SIZE in InputArea with shared validateFile() from fileService, showing alert() on rejection. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5338bdfc0f
commit
470ec9a64e
|
|
@ -2,6 +2,7 @@ import { useState, useRef, useEffect, KeyboardEvent, ChangeEvent, ClipboardEvent
|
|||
import { Send, Paperclip, X, Image, FileText, Loader2, Upload } from 'lucide-react';
|
||||
import { clsx } from 'clsx';
|
||||
import { FileAttachment } from '../stores/chatStore';
|
||||
import { validateFile, ALLOWED_FILE_TYPES } from '@/shared/services/fileService';
|
||||
|
||||
interface PendingFile {
|
||||
id: string;
|
||||
|
|
@ -20,25 +21,6 @@ interface InputAreaProps {
|
|||
uploadProgress?: Record<string, { progress: number; status: string }>;
|
||||
}
|
||||
|
||||
// 允许上传的文件类型
|
||||
const ALLOWED_TYPES = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'image/svg+xml',
|
||||
'application/pdf',
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'text/plain',
|
||||
'text/csv',
|
||||
'text/markdown',
|
||||
];
|
||||
|
||||
const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB
|
||||
|
||||
export function InputArea({
|
||||
onSend,
|
||||
disabled,
|
||||
|
|
@ -89,12 +71,9 @@ export function InputArea({
|
|||
|
||||
const validFiles: File[] = [];
|
||||
Array.from(files).forEach((file) => {
|
||||
if (!ALLOWED_TYPES.includes(file.type)) {
|
||||
console.warn(`不支持的文件类型: ${file.type}`);
|
||||
return;
|
||||
}
|
||||
if (file.size > MAX_FILE_SIZE) {
|
||||
console.warn(`文件过大: ${file.name}`);
|
||||
const result = validateFile(file);
|
||||
if (!result.valid) {
|
||||
alert(result.error);
|
||||
return;
|
||||
}
|
||||
validFiles.push(file);
|
||||
|
|
@ -116,12 +95,9 @@ export function InputArea({
|
|||
const processFiles = (files: File[]) => {
|
||||
const validFiles: File[] = [];
|
||||
files.forEach((file) => {
|
||||
if (!ALLOWED_TYPES.includes(file.type)) {
|
||||
console.warn(`不支持的文件类型: ${file.type}`);
|
||||
return;
|
||||
}
|
||||
if (file.size > MAX_FILE_SIZE) {
|
||||
console.warn(`文件过大: ${file.name}`);
|
||||
const result = validateFile(file);
|
||||
if (!result.valid) {
|
||||
alert(result.error);
|
||||
return;
|
||||
}
|
||||
validFiles.push(file);
|
||||
|
|
@ -301,7 +277,7 @@ export function InputArea({
|
|||
ref={fileInputRef}
|
||||
type="file"
|
||||
multiple
|
||||
accept={ALLOWED_TYPES.join(',')}
|
||||
accept={[...ALLOWED_FILE_TYPES.image, ...ALLOWED_FILE_TYPES.document].join(',')}
|
||||
onChange={handleFileSelect}
|
||||
className="hidden"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -45,9 +45,18 @@ export const ALLOWED_FILE_TYPES = {
|
|||
],
|
||||
};
|
||||
|
||||
export const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB
|
||||
export const MAX_DIRECT_UPLOAD_SIZE = 10 * 1024 * 1024; // 10MB
|
||||
|
||||
/** Claude API 文件大小限制(按类型区分) */
|
||||
export const FILE_SIZE_LIMITS = {
|
||||
/** 图片: Claude API 硬限制 5MB */
|
||||
image: 5 * 1024 * 1024,
|
||||
/** PDF: Claude API 整个请求 32MB 限制,单文件留 25MB */
|
||||
pdf: 25 * 1024 * 1024,
|
||||
/** 其他文档(Word/Excel/Text 等): 通用 50MB 上传限制 */
|
||||
document: 50 * 1024 * 1024,
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 验证文件类型和大小
|
||||
*/
|
||||
|
|
@ -61,10 +70,26 @@ export function validateFile(file: File): { valid: boolean; error?: string } {
|
|||
};
|
||||
}
|
||||
|
||||
if (file.size > MAX_FILE_SIZE) {
|
||||
// 按文件类型检查大小限制
|
||||
const fileType = getFileType(file.type);
|
||||
let maxSize: number;
|
||||
let typeLabel: string;
|
||||
|
||||
if (fileType === 'image') {
|
||||
maxSize = FILE_SIZE_LIMITS.image;
|
||||
typeLabel = '图片';
|
||||
} else if (file.type === 'application/pdf') {
|
||||
maxSize = FILE_SIZE_LIMITS.pdf;
|
||||
typeLabel = 'PDF';
|
||||
} else {
|
||||
maxSize = FILE_SIZE_LIMITS.document;
|
||||
typeLabel = '文档';
|
||||
}
|
||||
|
||||
if (file.size > maxSize) {
|
||||
return {
|
||||
valid: false,
|
||||
error: `文件大小超过限制。最大允许: ${MAX_FILE_SIZE / 1024 / 1024}MB`,
|
||||
error: `${typeLabel}大小超过限制 (${(file.size / 1024 / 1024).toFixed(1)}MB)。${typeLabel}最大允许: ${maxSize / 1024 / 1024}MB`,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue