# antd 封装上传组件 FormUpload
import { UploadOutlined } from "@ant-design/icons";
import { Button, notification, Upload } from "antd";
import React, { useEffect, useRef } from "react";
// import { request } from 'umi';
import type { UploadProps } from "antd";
export const getExtension = (fileName: string) => {
return fileName.substring(fileName.lastIndexOf("."));
};
export const getSizeMb = (fileSize: number) => {
return fileSize / 1024 / 1024;
};
export const commonUpload = async (
serviceName: string,
file: File,
options = {}
) => {
const formData = new FormData();
formData.append("file", file);
try {
const res = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
success: true,
code: 200,
data: {
fileName: "xx.doc",
ossKey: "common/upload/12345/xx.doc",
},
});
}, 5000);
});
// request(serviceName, {
// method: 'POST',
// data: formData,
// params: options,
// });
return Promise.resolve(res);
} catch (e) {
return Promise.reject(e);
}
};
export interface FileItem {
name: string;
fileName: string;
ossKey: string;
}
export interface FormUploadProps
extends Omit<
UploadProps,
"accept" | "beforeUpload" | "onChange" | "customRequest"
> {
serviceName: string;
responseKey: string;
accepts?: string[];
limitSize?: number;
options?: any;
showBtn?: boolean;
children?: React.ReactDOM | React.ReactDOM[];
onChange?: (file: FileItem[]) => void;
onLoadUpload?: (file: File) => void;
onFinallyUpload?: () => void;
}
const ACCEPTS = [".doc", ".docx", ".pdf", ".xls", ".xlsx"];
const LIMIT_SIZE = 100; // 100M
const SHOW_BTN = true;
const LOADING = "loading";
/**
* @param serviceName 接口 - '/common/upload'
* @param responseKey 接口响应唯一标识字段 - ossFilePath
* @param accepts 接受文件类型 - ['.doc','.docx']
* @param limitSize 限制文件大小(单位: M) - 100
* @param options 自定义其他额外参数
* @param showBtn 是否显示上传按钮,用于查看时只显示列表
* @param children 子组件
* @param others 兼容Upload组件其他属性
* @callback onLoadUpload 每个附件上传前的回调
* @callback onFinallyUpload 全部附件上传成功或失败时的回调
* @use Form.Item 需要加 valuePropName = 'fileList' -
*/
const FormUpload: React.FC<FormUploadProps> = (props: FormUploadProps) => {
const {
onChange: propsOnchange,
disabled,
serviceName,
responseKey,
accepts = ACCEPTS,
limitSize = LIMIT_SIZE,
options = {},
showBtn = SHOW_BTN,
onLoadUpload,
onFinallyUpload,
...others
} = props;
const onLive = useRef(false); //保存当前组件是否已挂载
const uploadMap = useRef({}); //保存正在上传的附件uid
const onChange = (file: any) => {
const { fileList } = file;
const newFileList: FileItem[] = [];
fileList.forEach((item: any) => {
if (item.response && item.status === "done") {
newFileList.push({
name: item.name,
fileName: item.name,
ossKey: item.response[responseKey],
});
} else if (item.status !== "error" && item.status !== "removed") {
newFileList.push(item);
}
});
//调用Form传递下来的 onChange事件 把数据给Form实例保管
propsOnchange?.(newFileList);
};
const customRequest = async (params: any) => {
const currentFileId = params.file.uid;
try {
onLoadUpload?.(params.file);
uploadMap.current[currentFileId] = LOADING;
const res = await commonUpload(serviceName, params.file, options);
console.log(res, "res");
if (onLive.current) params.onSuccess(res?.data);
} catch (e) {
if (onLive.current) params.onError(e);
} finally {
const isLoading = uploadMap.current[currentFileId] === LOADING;
delete uploadMap.current[currentFileId];
if (
isLoading &&
onLive.current &&
Object.keys(uploadMap.current).length === 0
) {
onFinallyUpload?.();
}
}
};
const beforeUpload = (file: File) => {
if (!accepts.includes(getExtension(file.name))) {
notification.error({
message: `文件格式不支持!请上传格式为 ${accepts.join(",")} 的文件`,
});
return Upload.LIST_IGNORE;
}
if (getSizeMb(file.size) > limitSize) {
notification.error({
message: `文件过大!请上传大小不超过 ${limitSize}M 的文件`,
});
return Upload.LIST_IGNORE;
}
return file;
};
const onRemove = (file: any) => {
delete uploadMap.current[file.uid];
if (
file.originFileObj &&
onLive.current &&
Object.keys(uploadMap.current).length === 0
) {
//移除的是 正在上传的文件 并且 组件已挂载 并且没有正在上传的文件时
onFinallyUpload?.();
}
};
useEffect(() => {
onLive.current = true;
return () => {
onLive.current = false;
};
}, []);
return (
<Upload
disabled={disabled}
accept={accepts.join(",")}
onChange={onChange}
beforeUpload={beforeUpload}
customRequest={customRequest}
onRemove={onRemove}
{...others}
>
{props.children
? props.children
: showBtn && (
<Button disabled={disabled} icon={<UploadOutlined />}>
附件上传
</Button>
)}
</Upload>
);
};
export default FormUpload;
测试一下
import React from "react";
import { Form, Button } from "antd";
//使用
const App = () => {
const [form] = useForm();
return (
<div>
<Button
onClick={() => {
console.log(form.getFieldsValue());
}}
>
获取结果
</Button>
<Form form={form}>
<Form.Item name={"fileList"} valuePropName={"fileList"} label={"附件"}>
<FormUpload serviceName="/upload" responseKey="ossKeys" />
</Form.Item>
</Form>
</div>
);
};