177 lines
4.4 KiB
JavaScript
177 lines
4.4 KiB
JavaScript
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,
|
||
listType = "text",
|
||
accept = "",
|
||
ratio = "",
|
||
showTip = true,
|
||
multiple = true,
|
||
size = 0,
|
||
tipContent,
|
||
uploadButtonText = "点击选择文件上传",
|
||
formValues,
|
||
...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/")) {
|
||
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 (["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;
|