import React, { 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; } export const TusUploader = ({ value = [], onChange }: TusUploaderProps) => { const { handleFileUpload } = useTusUpload(); const [uploadingFiles, setUploadingFiles] = useState([]); const [completedFiles, setCompletedFiles] = useState(() => value?.map(fileId => ({ name: `File ${fileId}`, // We could fetch the actual filename if needed progress: 1, 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", files); // 验证文件对象 if (!files.every((f) => f instanceof File)) { message.error("Invalid file format"); return false; } const newFiles: UploadingFile[] = files.map((f) => ({ name: f.name, progress: 0, status: "uploading" as const, })); setUploadingFiles((prev) => [...prev, ...newFiles]); const newUploadResults: string[] = []; try { for (const [index, f] of files.entries()) { if (!f) { throw new Error(`File ${f.name} is invalid`); } const fileId = await new Promise( (resolve, reject) => { handleFileUpload( f as File, (result) => { console.log("Upload success:", result); const completedFile = { name: f.name, progress: 1, status: "done" as const, fileId: result.fileId, }; setCompletedFiles((prev) => [ ...prev, completedFile, ]); setUploadingFiles((prev) => prev.filter((_, i) => i !== index) ); resolve(result.fileId); }, (error) => { console.error("Upload error:", error); reject(error); } ); } ); newUploadResults.push(fileId); } // Update with all uploaded files const newValue = Array.from(new Set([...uploadResults, ...newUploadResults])); setUploadResults(newValue); onChange?.(newValue); message.success(`${files.length} files uploaded successfully`); } catch (error) { console.error("Upload error details:", error); message.error( `Upload failed: ${error instanceof Error ? error.message : "Unknown error"}` ); setUploadingFiles((prev) => prev.map((f) => ({ ...f, status: "error" })) ); } return false; }, [uploadResults, onChange, handleFileUpload] ); return (

Click or drag file to this area to upload

Support for a single or bulk upload of files

{/* Uploading Files */} {uploadingFiles.length > 0 && (
Uploading Files
{uploadingFiles.map((file, index) => (
{file.name}
))}
)} {/* Completed Files */} {completedFiles.length > 0 && (
Uploaded Files
{completedFiles.map((file, index) => (
{file.name}
))}
)}
); };