- A+
所属分类:Web前端
基本步骤
通过 antd 框架的 Upload 控件,采用手动上传的方式,先选择需要上传的文件(控制文件数量以及大小),再根据所选的文件列表,循环上传,期间通过 Spin 控件提示上传中。
效果展示
控件引用
Upload 控件配置:
1 props : { 2 multiple: true, 3 maxCount:20,//限制最多显示 20 个文件 4 onRemove: (file) => {//删除列表文件 5 let fileListbatch_curr=this.state.fileListbatch; 6 console.log("props-onRemove-fileListbatch_curr:",fileListbatch_curr); 7 let index = fileListbatch_curr.findIndex(item=>item.uid==file.uid); 8 console.log("props-onRemove-obj:",index,file.uid); 9 if(index==-1){ 10 //message.warning("未删除成功!") 11 return; 12 }else{ 13 const newFileList = fileListbatch_curr.slice(); 14 newFileList.splice(index, 1); 15 console.log("props-onRemove-newFileList:",newFileList); 16 this.setState({fileListbatch:newFileList}); 17 let uploadsuccesslist_curr=this.state.uploadsuccesslist; 18 let indexsuccess=uploadsuccesslist_curr.findIndex(item=>item.uid==file.uid);//根据唯一码 uid 查找目标文件的索引 19 if(indexsuccess!=-1){ 20 uploadsuccesslist_curr.splice(indexsuccess, 1);//删除 21 console.log("props-onRemove-uploadsuccesslist_curr:",uploadsuccesslist_curr); 22 this.setState({uploadsuccesslist:uploadsuccesslist_curr}); 23 } 24 } 25 }, 26 beforeUpload: (file) => {//添加文件,将文件加入临时列表,准备上传 27 let fileListbatch_curr=this.state.fileListbatch; 28 let ff=fileListbatch_curr.find((item)=>item.name==file.name); 29 if(ff==undefined){ 30 fileListbatch_curr.push(file); 31 this.setState({fileListbatch:fileListbatch_curr,uploadflag:false}); 32 return false; 33 } 34 else{ 35 message.warning("存在同名文件已选择,请确认!"); 36 return Upload.LIST_IGNORE;//列表中不显示 37 } 38 }, 39 fileListbatch_cc, 40 }
界面元素排列:
1 <Upload {...props}> 2 <Button icon={<UploadOutlined />}>选择文件(Max:20Pcs, Max:200MB)</Button> 3 </Upload> 4 <Button 5 type="primary" 6 onClick={this.batchUploadReports} 7 disabled={fileListbatch.length === 0} 8 //loading={uploading} 9 style={{ marginTop: 20,width:180 }} 10 > 11 {/* {uploading ? 'Uploading' : 'Start Upload'} */} 12 开始上传 13 </Button> 14 <label style={{ lineHeight: "0px", color: '#bfbfbf', fontSize: 10,float:'left',marginBottom:20 }}>支持扩展名:apk/exe/pdf/xls/doc/ppt等</label>
处理逻辑
根据文件列表,循环上传全部文件。
【后端采用 .Net 5.0 WebAPI 详见:大文件分片上传 中的“后端部分”】
1 //批量上传文件 2 batchUploadReports = () => { 3 this.setState({uploadsuccesslist:[]}) 4 let uploadsuccesslist_curr=[]; 5 this.formRef_upload.current.validateFields() 6 .then(formrefcurr => { 7 if(formrefcurr["baogaolb"]==0||formrefcurr["baogaolx"].length==0){ 8 message.warning("请检查必填项!"); 9 return null; 10 } 11 this.setState({fileuploading:true,uploadsuccesslist:[],tipContent:"报告文件上传中,请耐心等待..."}); 12 let fileListbatch_curr2=this.state.fileListbatch; 13 let filecount=fileListbatch_curr2.length; 14 let filecount_success=0; 15 if(filecount>20){//只取前 20 个文件 16 filecount=20; 17 fileListbatch_curr2=fileListbatch_curr2.splice(0,20); 18 } 19 try{//通过抛出异常,来中断 foreach 20 fileListbatch_curr2.forEach(element => {//文件 list 循环上传 21 if(element.size/(1024*1024)>200){ 22 this.setState({fileuploading:false,uploadsuccesslist:[],tipContent:"报告文件上传中,请耐心等待..."}) 23 message.warning("单个报告大小不允许超过 200MB,请检查后继续上传!"); 24 // fileListbatch_curr2.length=0; 25 throw new Error(element)//若有不符合条件的文件,抛出异常中断循环 26 } 27 else{ 28 let filename=element.name; 29 let chunklistcurr=this.createFileChunk(element).map(({ file, name }, index) => {//createFileChunk:创建文件切片,可处理大文件 30 return { 31 chunk: file, 32 size: file.size, 33 percent: 0, 34 //filename:file. 35 name: name,// + "-" + (index + 1), 36 index, 37 }; 38 }); 39 let filecountchunk=chunklistcurr.length; 40 let ii=0; 41 chunklistcurr.forEach(element => {//分片传输 42 const formData = new FormData() 43 formData.append('file', element.chunk); 44 formData.append('index', element.index); 45 formData.append('name', element.name); 46 formData.append('size', element.size); 47 //formData.append('filecount', filecount); 48 axios({ 49 method: 'post', 50 url: '/api/system/System/UploadFileAttachmentChunk?zhuti='+this.state.zhuti, 51 data: formData, 52 headers: { "Content-Type": "multipart/form-data"} 53 }).then(({data}) => { 54 if(data.code==200){ 55 ii++; 56 if(ii==filecountchunk){//分块全部上传完成 57 let indata={"name":chunklistcurr[0].name,"filecount":filecountchunk,"filename":filename 58 } 59 axios({//传输完成,通知拼接 60 method: 'post', 61 url: '/api/system/System/CombineChunkToFileBatch', 62 data: indata, 63 headers: { "Content-Type": "application/json"} 64 }).then(({data}) => { 65 if(data.code==200){ 66 let listbatchupload={} 67 uploadsuccesslist_curr.push(listbatchupload); 68 this.setState({uploadsuccesslist:uploadsuccesslist_curr}); 69 filecount_success++; 70 } 71 else if(data.code==202){ 72 window.location.href="/wellcome"; 73 } 74 else{ 75 message.error("上传失败,请稍后重试!详情:"+data.desc); 76 filecount_success++; 77 } 78 }).catch((err) =>{ 79 console.log(err); 80 message.error("上传失败,请稍后重试!"); 81 }).finally(() =>{ 82 if(filecount_success==filecount){ 83 this.setState({uploadflag:true}) 84 message.success("全部上传完成,请进一步确认上传是否全部成功"); 85 this.setState({fileuploading:false,tipContent:"加载中..."}); 86 } 87 }) 88 } 89 } 90 else if(data.code==202){ 91 window.location.href="/wellcome"; 92 } 93 else{ 94 message.error("上传失败,请稍后重试!详情:"+data.desc); 95 chunklistcurr.length=0; 96 return; 97 } 98 }).catch((err) =>{ 99 console.log(err); 100 message.error("上传失败,请稍后重试!"); 101 return; 102 }).finally(() =>{ }) 103 }) 104 } 105 }); 106 } 107 catch(e){ 108 console.log('catch-e:'+e) 109 } 110 }) 111 }
1 //创建文件切片 2 createFileChunk = (file, size = 20*1024*1024) => { 3 const fileChunkList = []; 4 let cur = 0; 5 while (cur < file.size) { 6 fileChunkList.push({ file: file.slice(cur, cur + size), name: file.uid });//uid:文件唯一标识 7 cur += size; 8 } 9 return fileChunkList; 10 };
注:本文代码已在项目中实用,有疑问欢迎指正。