import axios, { AxiosResponse } from 'axios'; import { message, Progress } from "antd"; import { RcFile } from "antd/lib/upload"; import { useEffect, useState } from "react"; import SparkMD5 from "spark-md5"; import { FileUploadParam } from "./upload-panel"; import React from 'react'; interface Iprops { file: RcFile, onComplete: () => void, callbackFn: (param: FileUploadParam) => Promise stopSignal: boolean checkFileExists: (md5: string, params?: {}) => Promise> getUploadUrl: (objectName: string, params?: {}) => Promise> } export default function UploadFilePanelItem(props: Iprops) { const [progress, setProgress] = useState(0); const [localProgress, setLocalProgress] = useState(0); const [msg, setMsg] = useState(''); const xhr = new XMLHttpRequest(); const reader = new FileReader(); const { file } = props; useEffect(() => { startUpload(); }, []) useEffect(() => { if (!!props.stopSignal) { xhr.abort(); reader.abort(); } }, [props.stopSignal]) const startUpload = () => { if (file == null) return; let filename: string = file.name; let suffix = filename.slice(filename?.lastIndexOf('.')) || ''; let originName = filename.slice(0, filename?.lastIndexOf('.')); setMsg(`正在读取本地文件 ${filename.slice(0, 50)}...`) let blobSlice = File.prototype.slice, chunkSize = 1024 * 1024 * 2, // Read in chunks of 2MB chunks = Math.ceil(file.size / chunkSize), currentChunk = 0, spark = new SparkMD5.ArrayBuffer(); const loadNext = () => { let start = currentChunk * chunkSize, end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize; reader.readAsArrayBuffer(blobSlice.call(file, start, end)); } reader.onprogress = (e) => { setLocalProgress(Math.round((e.loaded + currentChunk * chunkSize) / file.size * 100)) } reader.onerror = (e) => { console.log(e.target.error) message.error(`文件 ${filename} 读取失败 (${Math.round(file.size / 1024 / 1024)}MB)`, 3) setMsg(`文件 ${filename.slice(0, 50)}... 读取失败 (${file.size / 1024 / 2024}MB)`) setLocalProgress(0); props.onComplete(); } reader.onload = (e) => { spark.append(e.target.result as ArrayBuffer); // Append array buffer currentChunk++; if (currentChunk < chunks) { loadNext(); return; } let md5 = spark.end(); let objectName = `${md5}${suffix || ''}`; setLocalProgress(0); setMsg(`开始上传文件 ${filename}...`) let checkPromise = props.checkFileExists(md5); //通过md5值检查文件是否重复 let getObjectUploadUrlPromise = props.getUploadUrl(objectName); axios.all([checkPromise, getObjectUploadUrlPromise]).then(([res1, res2]) => { let fileExists = res1.data; let url = res2.data; let uploadFile: FileUploadParam = { md5: md5, suffix: suffix, filePath: objectName, name: originName, fileSize: file.size, } if (!!fileExists) { // 文件已存在 props.callbackFn(uploadFile).then(_ => { let p = Math.round(100); setProgress(p); setMsg(`${filename} 上传完成!`) props.onComplete(); }) } else { xhr.open('PUT', url, true) xhr.onload = () => { if (xhr.status === 200) { // resolve(xhr.response) props.callbackFn(uploadFile).then(_ => { setMsg(`${filename} 上传完成!`) props.onComplete(); }) } else { setMsg(`${filename} 上传完成!`) props.onComplete(); } } // xhr.send(new Blob([reader.result])) xhr.send(file) } }) } loadNext(); } xhr.upload.onprogress = (e) => { let p = Math.round(e.loaded / e.total * 100); setProgress(p); } return (
{`${msg}${localProgress ? `${localProgress}%` : ''}`}
) }