重构文件上传逻辑

This commit is contained in:
宇阳
2024-08-31 14:29:05 +08:00
parent f6cc17e339
commit 303e14b7a8
2 changed files with 67 additions and 71 deletions

View File

@@ -1,14 +1,10 @@
import { FileDir } from '@/types/app/file';
import { InboxOutlined } from '@ant-design/icons';
import type { UploadProps } from 'antd';
import { message, Modal, Radio, Select, Upload, Spin } from 'antd';
import { message, Modal, Radio, Select, Spin } from 'antd';
import { useUserStore } from '@/stores';
import { baseURL } from '@/utils/request';
import Compressor from 'compressorjs';
import { useState } from 'react';
import { UploadFile } from 'antd/es/upload';
const { Dragger } = Upload;
import { useRef, useState } from 'react';
interface UploadFileProps {
dir: FileDir,
@@ -19,81 +15,66 @@ interface UploadFileProps {
export default ({ dir, open, onCancel, onSuccess }: UploadFileProps) => {
const store = useUserStore();
const fileInputRef = useRef<HTMLInputElement>(null);
const [quality, setQuality] = useState(1000);
const [isCompressionUpload, setIsCompressionUpload] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [fileList, setFileList] = useState<UploadFile[]>([]);
const onUploadFile = async (e: React.ChangeEvent<HTMLInputElement>) => {
let files = [...e.target.files!];
const uploadProps: UploadProps = {
name: 'files',
multiple: true,
action: `${baseURL}/file`,
data: { dir },
headers: {
"Authorization": `Bearer ${store.token}`
},
showUploadList: true,
async onChange(info) {
const { status, response } = info.file;
setIsLoading(true);
if (status !== 'uploading' && response?.code === 400) return message.error(response.message);
setFileList(info.fileList);
if (status === 'done') {
message.success(`${info.file.name} 文件上传成功`);
} else if (status === 'error') {
message.error(`${info.file.name} 文件上传失败`);
setIsLoading(false);
return
}
// if (info.fileList.some(file => file.status === "error")) {
// message.error(`${info.file.name} 文件上传失败`);
// setIsLoading(false);
// return
// }
// 所有文件的状态都不为uploading就证明上传成功
if (info.fileList.every(file => file.status !== 'uploading')) {
// 等待所有请求完毕后再执行
const allResponses = await info.fileList.map(file => file.response?.data).filter(data => data);
const data = await allResponses.flat().join("\n");
// 把数据写入到剪贴板
await navigator.clipboard.writeText(data);
message.success(`🎉 文件上传成功URL链接已复制到剪贴板`);
onSuccess(data);
setIsLoading(false);
onCloseModel();
}
},
beforeUpload: async (file) => {
setIsLoading(true);
if (quality === 1000) return file;
return new Promise((resolve, reject) => {
// 上传前先压缩文件大小
const compressedFiles = await Promise.all(files.map(file => {
return new Promise<File>((resolve, reject) => {
new Compressor(file, {
quality,
success: (compressedFile) => {
resolve(compressedFile);
},
error: (err) => {
reject(err);
success: (blob) => {
// 将 Blob 转换为 File
const f = new File([blob], file.name, {
type: file.type,
lastModified: Date.now()
});
resolve(f);
},
error: (err) => reject(err)
});
});
},
className: "py-4"
}));
// 处理文件上传需要的格式
const formData = new FormData();
formData.append("dir", dir);
for (let i = 0; i < compressedFiles.length; i++) {
formData.append('files', compressedFiles[i]);
}
// 发起网络请求
const res = await fetch(`${baseURL}/file`, {
method: "POST",
body: formData,
headers: {
"Authorization": `Bearer ${store.token}`
}
});
const { code, message: msg, data } = await res.json();
if (code !== 200) return message.error("文件上传失败:" + msg);
// 把数据写入到剪贴板
await navigator.clipboard.writeText(data.join("\n"));
message.success(`🎉 文件上传成功URL链接已复制到剪贴板`);
onSuccess(data.join("\n"));
setIsLoading(false);
onCloseModel();
};
const onCloseModel = () => {
setIsCompressionUpload(false);
setQuality(1000);
setIsLoading(false);
setFileList([]);
onCancel();
};
@@ -129,13 +110,27 @@ export default ({ dir, open, onCancel, onSuccess }: UploadFileProps) => {
}
</div>
<Dragger {...uploadProps} fileList={fileList}>
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p className="ant-upload-text"></p>
<p className="ant-upload-hint"></p>
</Dragger>
<div className='mt-4'>
<div
onClick={() => fileInputRef?.current?.click()}
className='w-full h-40 p-4 border border-dashed border-[#D7D7D7] rounded-lg hover:border-primary bg-[#FAFAFA] space-y-2 cursor-pointer transition'
>
<div className='flex justify-center'>
<InboxOutlined className='text-5xl text-primary' />
</div>
<p className="text-base text-center"></p>
<p className="text-sm text-[#999] text-center"></p>
</div>
<input
multiple
type="file"
onChange={onUploadFile}
ref={fileInputRef}
className='hidden'
/>
</div>
</Spin>
</Modal>
</>

View File

@@ -134,6 +134,7 @@ export default () => {
<FileUpload
dir={dirName}
open={openUploadModalOpen}
// open={true}
onSuccess={() => getFileList(dirName)}
onCancel={() => setOpenUploadModalOpen(false)}
/>