zy-react-library/components/Upload/index.js

177 lines
4.5 KiB
JavaScript
Raw Normal View History

2025-10-22 14:43:42 +08:00
import { PlusOutlined } 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 = 1,
2025-10-30 11:27:04 +08:00
listType = "picture-card",
accept = ["picture-card", "picture-circle", "picture"].includes(listType) ? ".jpg,.jpeg,.png" : "",
2025-10-22 14:43:42 +08:00
ratio = "",
showTip = true,
multiple = true,
size = 0,
tipContent,
uploadButtonText = "点击选择文件上传",
formValues,
2025-10-22 14:43:42 +08:00
...restProps
} = props;
const [previewVisible, setPreviewVisible] = useState(false);
const [previewImage, setPreviewImage] = useState("");
// 生成提示信息
const getTipText = () => {
if (tipContent)
return tipContent;
const tips = [
`最多上传${maxCount}个文件`,
accept
? `并且只能上传${accept
.replace(/\./g, "")
.split(",")
.join("、")}格式的文件`
: "可以上传任意格式的文件",
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(`只能上传${accept}格式的文件`);
return;
}
// 验证文件大小
if (maxSize && file.size > maxSize) {
message.warning(`文件大小不能超过${size}M`);
return;
}
// 验证图片分辨率
if (ratioArr.length === 2 && file.type?.startsWith("image/")) {
2025-10-28 14:08:33 +08:00
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;
2025-10-22 14:43:42 +08:00
};
2025-10-28 14:08:33 +08:00
// 如果有现成的URL则直接使用否则使用FileReader读取本地文件
if (file.url) {
validateImageResolution(file.url);
}
else {
const reader = new FileReader();
reader.onload = (e) => {
validateImageResolution(e.target.result);
};
reader.readAsDataURL(file);
}
2025-10-22 14:43:42 +08:00
}
else {
onChange?.(fileList);
}
};
// 预览文件
const handlePreview = (file) => {
if (["picture-card", "picture-circle", "picture"].includes(listType)) {
setPreviewImage(file.url || file.thumbUrl);
setPreviewVisible(true);
}
onPreview?.(file);
};
// 关闭预览
const handleCancel = () => {
setPreviewVisible(false);
};
// 上传按钮
const uploadButton
= ["picture-card", "picture-circle", "picture"].includes(listType)
? (
<div>
<PlusOutlined style={{ fontSize: 32 }} />
</div>
)
: (
<Button type="primary">{uploadButtonText}</Button>
);
return (
<>
<AntUpload
fileList={value}
multiple={multiple}
maxCount={maxCount}
listType={listType}
accept={accept}
onChange={handleChange}
onPreview={handlePreview}
beforeUpload={handleBeforeUpload}
{...restProps}
>
{value.length >= maxCount ? null : uploadButton}
</AntUpload>
{
showTip
? (tipContent || getTipText()) && (
<div style={{ marginTop: 10, color: "#ff4d4f" }}>
{tipContent || getTipText()}
</div>
)
: null
}
<Modal
open={previewVisible}
title="查看图片"
footer={null}
onCancel={handleCancel}
>
<img
alt="preview"
style={{ width: "100%", objectFit: "scale-down" }}
src={previewImage}
/>
</Modal>
</>
);
};
Upload.displayName = "Upload";
export default Upload;