import { PlusOutlined, UploadOutlined, VideoCameraAddOutlined } from "@ant-design/icons"; import { Upload as AntUpload, Button, message, Modal } from "antd"; import { useState } from "react"; /** * 文件上传组件 */ const Upload = (props) => { const { value = [], onChange, onPreview, maxCount: externalMaxCount, listType: externalListType, accept: externalAccept, ratio = "", showTip = true, multiple = true, size: externalSize, tipContent, uploadButtonText: externalUploadButtonText, fileType: externalFileType, ...restProps } = props; const [previewVisible, setPreviewVisible] = useState(false); const [previewImage, setPreviewImage] = useState(""); // 预设的文件格式 const imageAccept = ".jpg,.jpeg,.png"; const documentAccept = ".pdf,.doc,.docx"; const videoAccept = ".mp4"; // 根据accept自动判断文件类型 const getAutoFileType = () => { if (externalAccept) { if (externalAccept === "*") return "document"; const acceptList = externalAccept.split(","); if (acceptList.some(format => videoAccept.split(",").includes(format))) return "video"; if (acceptList.some(format => documentAccept.split(",").includes(format))) return "document"; if (acceptList.some(format => imageAccept.split(",").includes(format))) return "image"; return "document"; } return "image"; }; const fileType = externalFileType || getAutoFileType(); // 文件类型判断 const isImageType = fileType === "image"; const isVideoType = fileType === "video"; const isDocumentType = fileType === "document"; // 获取listType const getListType = () => { if (externalListType) return externalListType; if (externalAccept === "*") return "text"; if (fileType === "image") return "picture-card"; return "text"; }; const listType = getListType(); // 获取文件格式 const getAccept = () => { if (externalAccept) return externalAccept === "*" ? "" : externalAccept; if (isImageType) return imageAccept; if (isVideoType) return videoAccept; if (isDocumentType) return documentAccept; return imageAccept; }; const accept = getAccept(); // 获取默认上传数量 const getMaxCount = () => { if (externalMaxCount) return externalMaxCount; if (isVideoType) return 1; if (isImageType) return 4; if (isDocumentType) return 4; return 1; }; const maxCount = getMaxCount(); // 获取默认文件大小 const getSize = () => { if (externalSize) return externalSize; if (isVideoType) return 100; return 0; }; const size = getSize(); // 上传按钮文字 const uploadButtonText = externalUploadButtonText || (isVideoType ? "上传视频" : "上传附件"); // 文件格式提示 const acceptTip = accept.replace(/\./g, "").split(",").join("、"); // 生成提示信息 const getTipText = () => { if (tipContent) return tipContent; const tips = [ `最多上传${maxCount}个文件`, accept ? `并且只能上传${acceptTip}格式的文件` : "可以上传任意格式的文件", size ? `文件大小不能超过${size}M` : "", ratio ? `只能上传${ratio}分辨率的图片` : "", ].filter(Boolean); return `${tips.join(",")}。`; }; const handleBeforeUpload = () => { return false; }; // 文件状态改变 const handleChange = ({ file, fileList }) => { const acceptList = accept ? accept.split(",") : []; const ratioArr = ratio ? ratio.split("*") : []; const suffix = file.name.substring( file.name.lastIndexOf("."), file.name.length, ); const maxSize = size * 1024 * 1024; // 验证文件格式 if (acceptList.length > 0 && !acceptList.includes(suffix)) { message.warning(`只能上传${acceptTip}格式的文件`); return; } // 验证文件大小 if (maxSize && file.size > maxSize) { message.warning(`文件大小不能超过${size}M`); return; } // 验证图片分辨率 if (ratioArr.length === 2 && file.type?.startsWith("image/")) { const validateImageResolution = (imageUrl) => { const img = new Image(); img.onload = () => { if (img.width !== +ratioArr[0] || img.height !== +ratioArr[1]) { message.warning(`只能上传${ratio}分辨率的图片`); const filtered = fileList.filter(item => item.uid !== file.uid); onChange?.(filtered); return; } onChange?.(fileList); }; img.src = imageUrl; }; // 如果有现成的URL则直接使用,否则使用FileReader读取本地文件 if (file.url) { validateImageResolution(file.url); } else { const reader = new FileReader(); reader.onload = (e) => { validateImageResolution(e.target.result); }; reader.readAsDataURL(file); } } else { onChange?.(fileList); } }; // 预览文件 const handlePreview = (file) => { if (isImageType) { setPreviewImage(file.url || file.thumbUrl); setPreviewVisible(true); } onPreview?.(file); }; // 关闭预览 const handleCancel = () => { setPreviewVisible(false); }; // 上传按钮 const uploadButton = isImageType ? (
) : ( ); return ( <> {value.length >= maxCount ? null : uploadButton} { showTip ? (getTipText()) && (
{getTipText()}
) : null } preview ); }; Upload.displayName = "Upload"; export default Upload;