功能实现
 
 
<template>
	<input ref="inputFile" type="file" hidden @change="checkFiles" />
	<van-button class="upBut" color="#BF234D" @click="onClick">点击上传文件</van-button>
</template>
 
<script setup lang='ts'>
import Apis from '@/utils/apis';
import FileReaderUpoad from "@/utils/upoad";
import { showLoadingToast, showSuccessToast, showFailToast } from 'vant';
const inputFile = ref<HTMLFieldSetElement | null>(null);
const data = reactive({
    loading: false,
});
const onClick = () => {
    
    inputFile.value && inputFile.value.click();
};
const checkFiles = (e: Event) => {
	
	if (data.loading) return;
    data.loading = true;
    
    let event: any = e.target as EventTarget;
    
    let file = event.files[0];
    
    let storageId = "";
    let fileName = "", suffix = "";
    if (file.name) {
        let arr = file.name.split('.');
        fileName = arr.filter((item: object, index: number) => arr.length - 1 != index).join(".");
        suffix = arr.filter((item: object, index: number) => arr.length - 1 == index).join(".");
    };
    
    showLoadingToast({
        message: `正在解析文件`,
        forbidClick: true,
        duration: 0,
        overlay: true,
    });
	
    let upoad = new FileReaderUpoad({
        file,
        maxNum: 4,
        size: 5242880,
        byteLength: file.size,
        singleFileSize: 209715200,
        
        once: () => {
            showLoadingToast({
                message: `正在上传中`,
                forbidClick: true,
                duration: 0,
                overlay: true,
            });
            
            let obj: any = {...};
            Apis.upLoad(obj).then((res: any) => {
                if (res.code == 200) {
                    data.loading = false;
                    showSuccessToast("上传成功");
                };
            }).catch((err) => {
                showFailToast("上传出现问题");
                data.loading = false;
            });
        },
        
        start: (data: any, next: Function) => {
            
            let obj: any = {
            	
                fileMd5: data.md5,
                
                sliceTotalChunks: data.total,
                
                ...
			};
            
            Apis.start(obj).then((res: any) => {
                if (res.code == 200) {
                	
                    storageId = res.obj.storageId;
                    
                    next();
                };
            }).catch(() => {
                showFailToast("创建上传信息失败");
                data.loading = false;
            });
        },
        
        upload: (val: any, next: Function) => {
        	
            let obj: any = {
            	
                name: fileName,
                
                chunk: val.page,
                
                chunks: val.total,
                
                md5: val.totalMd5,
                
                size: val.file.size,
                
                tenantId: storageId,
                
                currentFileMd5: val.md5,
                
                file: val.blob
            };
            
            Apis.burst(obj).then((res: any) => {
            	
                if (res.code == 200 && res.success) next();
                
                else next(val);
            }).catch(() => {
				
                next(val);
            });
        },
        
        loading: (val: string) => {
            showLoadingToast({
                message: `已上传${val}%`,
                forbidClick: true,
                duration: 0,
                overlay: true,
            });
        },
        
        end: (res: any) => {
        	
            Apis.end({ tenantId: storageId }).then((res: any) => {
                if (res.code == 200) {
                    showSuccessToast("上传成功");                    
                }
            }).catch(() => {
                showFailToast("上传失败");
                data.loading = false;
            })
        }
    });
    
    upoad.uploadStart();
};
</script>
 
 
import SparkMD5 from 'spark-md5';
interface FileType {
    file: File;              
    size: number;            
    once?: Function;         
    maxNum?: number;         
    start?: Function;        
    end?: Function;          
    upload?: Function;       
    loading?: Function;      
    byteLength: number;      
    singleFileSize: number;  
};
export default class FileReaderUpoad {
    private option: any = [];       
    private Setting: FileType;      
    private totalFilm!: number;     
    private result: string = "";    
    private current: number = 0;    
    private totalMd5: string = '';  
    private arrLength: number = 0;  
    constructor(Setting: FileType) {
        this.Setting = Setting;
    };
    
    public uploadStart = () => {
        let that = this;
        
        if (this.Setting.file.size >= this.Setting.singleFileSize) {
            
            let fileReader = new FileReader();
            fileReader.readAsBinaryString(this.Setting.file);
            fileReader.onload = function () {
                
                that.Setting.maxNum = that.Setting.maxNum || 1;
                
                that.result = fileReader.result as string;
                
                that.totalFilm = Math.ceil(that.Setting.byteLength / that.Setting.size);
                
                that.getDataMd5(that.result).then((res: any) => {
                    
                    that.totalMd5 = res;
                    if (typeof (that.Setting.start) === 'function') that.Setting.start({ md5: res, total: that.totalFilm }, () => {
                        that.current = 1;
                        that.option = [];
                        that.burstParam();
                    });
                });
            };
        } else {
            typeof this.Setting.once == 'function' && this.Setting.once();
        };
    };
    
    private burstParam() {
        
        if (this.current < this.totalFilm) {
            
            let start = (this.current - 1) * this.Setting.size;
            let end = this.current * this.Setting.size;
            
            this.fileSlice(start, end, (val: string) => {
                
                this.getDataMd5(val).then((res: unknown) => {
                    
                    this.option.push({
                        md5: res,
                        chunkFile: val,
                        size: val.length,
                        page: this.current -1,
                        total: this.totalFilm,
                        totalMd5: this.totalMd5,
                        file: this.Setting.file,
                        blob: this.Setting.file.slice(start, end),
                    });
                    
                    this.current++;
                    
                    this.burstParam();
                });
            });
        } else {
            
            let start = (this.current - 1) * this.Setting.size;
            let end = this.current * this.Setting.size;
            
            this.fileSlice(start, end, (val: string) => {
                
                this.getDataMd5(val).then((res: unknown) => {
                    
                    this.option.push({
                        md5: res,
                        chunkFile: val,
                        size: val.length,
                        page: this.current -1,
                        total: this.totalFilm,
                        totalMd5: this.totalMd5,
                        file: this.Setting.file,
                        blob: this.Setting.file.slice(start, this.Setting.byteLength),
                    });
                    
                    this.arrLength = this.option.length;
                    
                    if (this.Setting.maxNum && this.Setting.maxNum > 0) {
                        
                        this.multiRequest(this.option, this.Setting.maxNum).then((res: any) => {
                            
                            typeof this.Setting.end == 'function' && this.Setting.end(res);
                        });
                    } else {
                        
                        new Error("并发数不能为零!");
                    };
                });
            });
        };
    };
    
    private fileSlice = (start: number, end: number, callback: Function) => {
        callback(this.result.slice(start, end));
    };
    
    private getDataMd5 = (data: string) => {
        return new Promise((resolve, reject) => {
            if (data) resolve(new SparkMD5().appendBinary(data).end());
            else reject("计算失败");
        });
    };
    
    private multiRequest = (urls: any, maxNum: number) => {
        
        let queue: any = [];
        
        let urlsClone = [...urls];
        
        let result = new Array(urls.length);
        
        let isDoneArr = new Array(urls.length).fill(0);
        
        let queueLimit = Math.min(maxNum, urls.length);
        
        let index = 0;
        
        const request = (queue: any, url: any) => {
            
            if (typeof this.Setting.upload == 'function') this.Setting.upload(url, (val: object) => {
                
                let i = urlsClone.indexOf(url);
                result[i] = url;
                isDoneArr[i] = 1;
                
                if(val) {
                    
                    this.arrLength++;
                    
                    urls.push(val);
                    
                    isDoneArr.push(val);
                }
                
                outLine(queue, url);
            })
        };
        
        const EnterTheTeam = (queue: any = [], url: object) => {
            
            let len = queue.push(url);
            if (len == this.Setting.maxNum) {
                index++;
                
                let t = parseInt(String(index / this.arrLength * 100));
                
                typeof this.Setting.loading == 'function' && this.Setting.loading(t);
            };
            request(queue, url);
            return len;
        };
        
        while (EnterTheTeam(queue, urls.shift()) < queueLimit) {};
        
        
        let promise: any = {
            resolve: '',
            reject: '',
        };
        
        const outLine = (queue: any = [], url: object) => {
            
            queue.splice(queue.indexOf(url), 1);
            if (urls.length) EnterTheTeam(queue, urls.shift());
            else {
                
                if (isDoneArr.indexOf(0) === -1) {
                    promise.resolve(result);
                    typeof this.Setting.loading == 'function' && this.Setting.loading(100);
                };
            }
        };
        
        return new Promise((resolve, reject) => {
            return promise.resolve = resolve;
        });
    };
};