import { useCallback, useState } from "react"; import { UploadOutlined, CheckCircleOutlined, DeleteOutlined, } from "@ant-design/icons"; import { Upload, Progress, Button } from "antd"; import type { UploadFile } from "antd"; import { useTusUpload } from "@web/src/hooks/useTusUpload"; import toast from "react-hot-toast"; import { getCompressedImageUrl } from "@nice/utils"; export interface TusUploaderProps { value?: string[]; onChange?: (value: string[]) => void; multiple?: boolean; } interface UploadingFile { name: string; progress: number; status: "uploading" | "done" | "error"; fileId?: string; fileKey?: string; } export const TusUploader = ({ value = [], onChange, multiple = true, }: 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) ); setUploadResults((prev) => { const newValue = prev.filter((id) => id !== fileId); onChange?.(newValue); return newValue; }); }, [onChange] ); // 新增:处理删除上传中的失败文件 const handleRemoveUploadingFile = useCallback((fileKey: string) => { setUploadingFiles((prev) => prev.filter((f) => f.fileKey !== fileKey)); }, []); const handleBeforeUpload = useCallback( (file: File) => { const fileKey = `${file.name}-${Date.now()}`; setUploadingFiles((prev) => [ ...prev, { name: file.name, progress: 0, status: "uploading", fileKey, }, ]); handleFileUpload( file, (result) => { setCompletedFiles((prev) => [ ...prev, { name: file.name, progress: 100, status: "done", fileId: result.fileId, }, ]); setUploadingFiles((prev) => prev.filter((f) => f.fileKey !== fileKey) ); setUploadResults((prev) => { // 如果是单文件模式,则替换现有文件 const newValue = multiple ? [...prev, result.fileId] : [result.fileId]; onChange?.(newValue); return newValue; }); // 单文件模式下,清除之前的完成文件 if (!multiple) { setCompletedFiles([ { name: file.name, progress: 100, status: "done", fileId: result.fileId, }, ]); } }, (error) => { console.error("上传错误:", error); toast.error( `上传失败: ${error instanceof Error ? error.message : "未知错误"}` ); setUploadingFiles((prev) => prev.map((f) => f.fileKey === fileKey ? { ...f, status: "error" } : f ) ); }, fileKey ); return false; }, [handleFileUpload, onChange] ); return (

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

{multiple ? "支持单个或批量上传文件" : "仅支持上传单个文件"}

{uploadingFiles.map((file) => (
{file.name}
{file.status === "error" && (
))} {completedFiles.map((file) => (
{file.name}
))}
); };