import { useCallback, useState } from "react"; import { UploadOutlined, CheckCircleOutlined, DeleteOutlined, } from "@ant-design/icons"; import { Upload, message, Progress, Button } from "antd"; import type { UploadFile } from "antd"; import { useTusUpload } from "@web/src/hooks/useTusUpload"; export interface TusUploaderProps { value?: string[]; onChange?: (value: string[]) => void; } interface UploadingFile { name: string; progress: number; status: "uploading" | "done" | "error"; fileId?: string; fileKey?: string; } export const TusUploader = ({ value = [], onChange }: TusUploaderProps) => { const { handleFileUpload, uploadProgress } = useTusUpload(); const [uploadingFiles, setUploadingFiles] = useState([]); const [completedFiles, setCompletedFiles] = useState( () => value?.map((fileId) => ({ name: `文件 ${fileId}`, progress: 100, status: "done" as const, fileId, })) || [] ); const [uploadResults, setUploadResults] = useState(value || []); const handleRemoveFile = useCallback( (fileId: string) => { setCompletedFiles((prev) => prev.filter((f) => f.fileId !== fileId) ); const newResults = uploadResults.filter((id) => id !== fileId); setUploadResults(newResults); onChange?.(newResults); }, [uploadResults, onChange] ); const handleChange = useCallback( async (fileList: UploadFile | UploadFile[]) => { const files = Array.isArray(fileList) ? fileList : [fileList]; console.log("文件", files); if (!files.every((f) => f instanceof File)) { message.error("无效的文件格式"); return false; } const newFiles: UploadingFile[] = files.map((f) => ({ name: f.name, progress: 0, status: "uploading" as const, fileKey: `${f.name}-${Date.now()}`, // 为每个文件创建唯一标识 })); setUploadingFiles((prev) => [...prev, ...newFiles]); const newUploadResults: string[] = []; try { for (const [index, f] of files.entries()) { if (!f) { throw new Error(`文件 ${f.name} 无效`); } const fileKey = newFiles[index].fileKey!; const fileId = await new Promise( (resolve, reject) => { handleFileUpload( f as File, (result) => { console.log("上传成功:", result); const completedFile = { name: f.name, progress: 100, status: "done" as const, fileId: result.fileId, }; setCompletedFiles((prev) => [ ...prev, completedFile, ]); setUploadingFiles((prev) => prev.filter( (file) => file.fileKey !== fileKey ) ); resolve(result.fileId); }, (error) => { console.error("上传错误:", error); reject(error); }, fileKey ); } ); newUploadResults.push(fileId); } const newValue = Array.from( new Set([...uploadResults, ...newUploadResults]) ); setUploadResults(newValue); onChange?.(newValue); message.success(`${files.length} 个文件上传成功`); } catch (error) { console.error("上传错误详情:", error); message.error( `上传失败: ${error instanceof Error ? error.message : "未知错误"}` ); setUploadingFiles((prev) => prev.map((f) => ({ ...f, status: "error" })) ); } return false; }, [uploadResults, onChange, handleFileUpload] ); return (

点击或拖拽文件到此区域进行上传

支持单个或批量上传文件

{/* 正在上传的文件 */} {(uploadingFiles.length > 0 || completedFiles.length > 0) && (
{uploadingFiles.map((file) => (
{file.name}
))} {completedFiles.length > 0 && completedFiles.map((file, index) => (
{file.name}
))}
)}
); };