需求
由于使用antd 上传图片,在某些情况下,例如token 失效,导致上传图片错误,但是antd 组件始终会走onChange 事件
导致上传路径为空情况
解决办法
使用自定义上传
// 自定义上传图片
const customRequest = params => {
const { file, onSuccess, onError } = params;
const formData = new FormData();
formData.append('upload_file', file);
Resource.handleUploadPicture(formData)
.then(ret => {
if (ret?.XCmdrCode === 0) {
if (typeof setPictureList === 'function') {
const temFile = {
...ret?.XCmdrResult,
};
onSuccess(ret); // 上传成功的图片会显示绿色的对勾
let newFiles = [...fileListRef.current, temFile];
if (!multiple) {
// 只保留最后一个文件
newFiles = newFiles.slice(-1);
}
setPictureList(_, newFiles);
}
} else {
message.error(`${ret?.XCmdrMessage}`);
}
})
.catch(ret => {
onError();
});
};
// 图片属性配置
const pictureProps = {
action: `https://admin-api.zhgcloud.com/attachments?token=${token}`,
name: 'upload_file',
// action: `https://admin-api.zhgcloud.com/images?token=${token}`,
// name: 'machine_image',
listType: 'picture-card',
fileList,
multiple,
...res,
beforeUpload: onBeforeUpload || defaultBeforeUpload,
onChange: ({ file, fileList, event }) => {
// let newFiles = [...fileList];
// if (!multiple) {
// // 只保留最后一个文件
// newFiles = newFiles.slice(-1);
// }
// if (typeof setPictureList === 'function') {
// setPictureList(file, newFiles);
// }
},
customRequest,
onRemove: file => {
const freshFiles = fileList?.filter(ele => ele.uid !== file.uid);
if (typeof onRemove === 'function') {
onRemove(file, freshFiles);
}
},
onPreview: async file => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
setUrl(file?.url || file?.response?.XCmdrResult?.url || file.previe);
},
onDownload: onDownload || defaultOnDownload,
};
完整组件逻辑
import React, { useEffect, useState, useRef, forwardRef, useImperativeHandle, onBeforeUpload } from 'react';
import { PlusOutlined } from '@ant-design/icons';
import { Upload, Modal, message } from 'antd';
import { saveAs } from 'file-saver';
import { useMount, useUnmount } from 'ahooks';
import FileViewer from '@/components/FileViewer';
import useToken from '@/hooks/useToken';
import Resource from '@/services/Resource';
const MAX_FILE_SIZE = 8;
const UNIT = 1024 * 1024;
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
const createFileObject = file => {
const fileObject = {
lastModified: file.lastModified,
lastModifiedDate: file.lastModifiedDate,
name: file.name,
size: file.size,
type: file.type,
uid: file.uid,
};
return fileObject;
};
const defaultOnDownload = file => {
// if (file?.url || file?.response?.XCmdrResult?.url) {
// window.open(file.url, '_blank');
// }
const url = file?.url || file?.response?.XCmdrResult?.url;
saveAs(url, `${file?.name || file?.url || ''}`);
};
const defaultBeforeUpload = file => {
const fileType = ['jpg', 'jpeg', 'png'];
// 文件显示
return new Promise((resolve, reject) => {
const curType = file.name.substr(file.name.lastIndexOf('.') + 1).toLowerCase();
if (!fileType.includes(curType)) {
Modal.warning({
maskClosable: true,
title: '图片格式须为jpg、jpeg、png!',
});
// reject(file);
return Upload.LIST_IGNORE;
} else if (file.size > MAX_FILE_SIZE * UNIT) {
Modal.warning({
maskClosable: true,
title: `单个图片大小不能超过${MAX_FILE_SIZE}M!`,
});
return Upload.LIST_IGNORE;
} else {
resolve(file);
}
});
};
const UploadPicture = ({
refChildPicture,
limit = 3,
action,
onRemove,
setPictureList = () => {},
onDownload,
pictures = [],
isPaste = false,
multiple = true,
outlinedName = '上传图片',
...res
}) => {
const [fileList, setFileList] = useState([]);
const [url, setUrl] = useState('');
const token = useToken();
const fileListRef = useRef([]);
useEffect(() => {
fileListRef.current = [...pictures];
setFileList([...pictures]);
}, [pictures]);
const saveFiles = (file, ret) => {
// // 图片转换成base64编码作为缩略图
const reader = new FileReader();
// 监听图片转换完成
reader.addEventListener(
'load',
() => {
// ...接入antd upload 的 filelist 中
const temFile = {
...file,
response: ret,
originFileObj: createFileObject(file),
id: new Date().getTime(),
status: 'done',
name: ret?.XCmdrResult?.path || file.name,
url: ret?.XCmdrResult?.url,
thumbUrl: reader.result,
};
if (typeof setPictureList === 'function') {
let newFiles = [...fileListRef.current, temFile];
if (!multiple) {
// 只保留最后一个文件
newFiles = newFiles.slice(-1);
}
setPictureList(_, newFiles);
}
},
false,
);
reader.readAsDataURL(file);
};
// 自定义上传图片
const customRequest = params => {
const { file, onSuccess, onError } = params;
const formData = new FormData();
formData.append('upload_file', file);
Resource.handleUploadPicture(formData)
.then(ret => {
if (ret?.XCmdrCode === 0) {
onSuccess();
saveFiles(file, ret);
} else {
message.error(`${ret?.XCmdrMessage}`);
}
})
.catch(ret => {
onError();
});
};
// 图片属性配置
const pictureProps = {
action: `https://admin-api.zhgcloud.com/attachments?token=${token}`,
name: 'upload_file',
// action: `https://admin-api.zhgcloud.com/images?token=${token}`,
// name: 'machine_image',
listType: 'picture-card',
fileList,
multiple,
...res,
beforeUpload: onBeforeUpload || defaultBeforeUpload,
onChange: ({ file, fileList, event }) => {
// let newFiles = [...fileList];
// if (!multiple) {
// // 只保留最后一个文件
// newFiles = newFiles.slice(-1);
// }
// if (typeof setPictureList === 'function') {
// setPictureList(file, newFiles);
// }
},
customRequest,
onRemove: file => {
const freshFiles = fileList?.filter(ele => ele.uid !== file.uid);
if (typeof onRemove === 'function') {
onRemove(file, freshFiles);
}
},
onPreview: async file => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
setUrl(file?.url || file?.response?.XCmdrResult?.url || file.previe);
},
onDownload: onDownload || defaultOnDownload,
};
useImperativeHandle(refChildPicture, () => {
// return返回的值就可以被父组件获取到
return {
getFileData() {
return {
fileList,
};
},
};
});
useMount(() => {
if (!isPaste) {
return;
}
const haoroomsbox = document.getElementById('ant-upload-picture-area-id');
haoroomsbox.addEventListener('paste', event => {
const data = event.clipboardData || window.clipboardData;
const items = data.items;
let tempFile = null; // 存储文件数据
if (items && items.length) {
// 检索剪切板items
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf('image') !== -1) {
tempFile = items[i].getAsFile();
break;
}
}
}
window.willUploadPictureList = tempFile;
event.preventDefault();
submitUpload(tempFile);
});
});
const submitUpload = file => {
if (!file) {
return;
}
if (fileListRef.current && fileListRef.current.length >= limit) {
message.error(`上传最大限制数量为${limit}`);
return;
}
const formData = new FormData();
formData.append('upload_file', file);
Resource.handleUploadPicture(formData)
.then(ret => {
if (ret?.XCmdrCode === 0) {
saveFiles(file, ret);
} else {
message.error(`${ret?.XCmdrMessage}`);
}
})
.catch(ret => {
message.error('上传失败');
});
};
useUnmount(() => {
const haoroomsbox = document.getElementById('ant-upload-picture-area-id');
if (haoroomsbox) {
// haoroomsbox.removeEventListener('paste', () => {});
}
});
return (
<div ref={refChildPicture} id="ant-upload-picture-area-id">
<Upload {...pictureProps}>
{fileList && fileList.length >= limit ? null : (
<div>
<PlusOutlined />
<div>{outlinedName}</div>
</div>
)}
</Upload>
<FileViewer url={url} onCancel={() => setUrl('')} />
</div>
);
};
export default forwardRef(UploadPicture);