优化Upload

master
LiuJiaNan 2026-02-24 11:42:08 +08:00
parent d6ada39fd0
commit ea129b523c
1 changed files with 84 additions and 48 deletions

View File

@ -1,6 +1,6 @@
import { PlusOutlined, UploadOutlined, VideoCameraAddOutlined } from "@ant-design/icons";
import { Upload as AntUpload, Button, message, Modal } from "antd";
import { useState } from "react";
import { useRef, useState } from "react";
/**
* 文件上传组件
@ -29,6 +29,9 @@ const Upload = (props) => {
const [previewVisible, setPreviewVisible] = useState(false);
const [previewImage, setPreviewImage] = useState("");
// 记录已经提示过错误的文件uid避免重复提示
const warnedFileUids = useRef(new Set());
// 预设的文件格式
const imageAccept = ".jpg,.jpeg,.png";
const documentAccept = ".pdf,.doc,.docx";
@ -137,66 +140,99 @@ const Upload = (props) => {
};
// 文件状态改变
const handleChange = ({ file, fileList }) => {
const handleChange = ({ fileList }) => {
console.log(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;
// 对整个fileList进行验证和过滤
const validateFiles = async (files) => {
const validFiles = [];
const invalidFiles = [];
for (const fileItem of files) {
const suffix = fileItem.name?.substring(
fileItem.name.lastIndexOf("."),
fileItem.name.length,
) || "";
// 验证文件格式
if (acceptList.length > 0 && !acceptList.includes(suffix)) {
message.warning(`只能上传${acceptTip}格式的文件`);
const filtered = fileList.filter(item => item.uid !== file.uid);
onChange?.(filtered);
return;
invalidFiles.push(fileItem);
// 只提示未提示过的文件
if (!warnedFileUids.current.has(fileItem.uid)) {
warnedFileUids.current.add(fileItem.uid);
message.warning(`${fileItem.name}:只能上传${acceptTip}格式的文件`);
}
continue;
}
// 验证文件大小
if (maxSize && file.size > maxSize) {
message.warning(`文件大小不能超过${size}M`);
const filtered = fileList.filter(item => item.uid !== file.uid);
onChange?.(filtered);
return;
if (maxSize && fileItem.size > maxSize) {
invalidFiles.push(fileItem);
// 只提示未提示过的文件
if (!warnedFileUids.current.has(fileItem.uid)) {
warnedFileUids.current.add(fileItem.uid);
message.warning(`${fileItem.name}:文件大小不能超过${size}M`);
}
continue;
}
// 验证图片分辨率
if (ratioArr.length === 2 && file.type?.startsWith("image/")) {
// 验证图片分辨率(异步)
if (ratioArr.length === 2 && fileItem.type?.startsWith("image/")) {
const validateImageResolution = (imageUrl) => {
return new Promise((resolve) => {
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;
const isValid = img.width === +ratioArr[0] && img.height === +ratioArr[1];
if (!isValid) {
// 只提示未提示过的文件
if (!warnedFileUids.current.has(fileItem.uid)) {
warnedFileUids.current.add(fileItem.uid);
message.warning(`${fileItem.name}:只能上传${ratio}分辨率的图片`);
}
onChange?.(fileList);
}
resolve(isValid);
};
img.onerror = () => resolve(false);
img.src = imageUrl;
});
};
// 如果有现成的URL则直接使用否则使用FileReader读取本地文件
if (file.url) {
validateImageResolution(file.url);
}
else {
const validResolution = fileItem.url
? await validateImageResolution(fileItem.url)
: await new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => {
validateImageResolution(e.target.result);
validateImageResolution(e.target.result).then(resolve);
};
reader.readAsDataURL(file);
reader.onerror = () => resolve(false);
reader.readAsDataURL(fileItem.originFileObj);
});
if (!validResolution) {
invalidFiles.push(fileItem);
continue;
}
}
else {
onChange?.(fileList);
validFiles.push(fileItem);
}
return { validFiles, invalidFiles };
};
// 执行验证并更新
validateFiles(fileList).then(({ validFiles }) => {
onChange?.(validFiles);
});
};
// 删除文件
const handleRemove = (file) => {
// 清理该文件的提示记录
warnedFileUids.current.delete(file.uid);
if (!file.originFileObj)
onGetRemoveFile?.(file);
return onRemove?.(file);