赞
踩
最近项目需求使用到大附件上传功能,图片最多5M,视频100M,结合查询到的资料决定使用webuploader上传组件,项目展示效果如下:
流程图:
1.上传前判断文件格式,项目只支持.png,.jpeg,.jpg,.mp4的视频和图片
2.图片最多5M,视频100M
3.图片可多选上传,视频每次上传一个
4.上传前获取uuid、文件名称和总文件md5判断是否重名和是否已上传过
5.已上传过时跳过上传直接进度显示99,并执行保存缩略图这一步
6.上传时显示上传进度,默认5M分片,大小超出自动分片,获取每个分片的md5
7.上传完成后执行合并操作,将所有分片md5和uuid提交与后端
8.后端验证分片个数和所有分片md5个数,合并后的文件md5和总文件md5,返回保存的附件地址url
9.获取url对应的缩略图并执行保存缩略图
template
<template> <el-row class="webUploader"> <el-col :span="24" class="mb20" :style="{ display: 'flex' }"> <div class="upload-area" :id="'drag'" v-show="is_upload"> <div class="upload" ref="selectFile" :id="'up_single'" > <div class="upload-icon"><i class="el-icon-upload"></i></div> <div class="upload-desc">将文件拖到此处,或<em>点击上传</em></div> <div class="upload-tip">支持上传jpg/png/jpeg/mp4格式文件,图片文件不能超过5M,视频文件不能超过100M。</div> </div> </div> <div class="upload-area" v-show="!is_upload"> <div class="upload" > 视频素材上传中请稍后...... </div> </div> <el-dialog title="提示" :visible.sync="dialogVisible" width="450px" :show-close="false" :before-close="handleClose"> <span class="model-title" slot="title"> <span class="title">上传失败</span> <span class="close" @click="dialogVisible = false"><i class="el-icon-close"></i></span> </span> <div class="model"> <div class="text">素材不符合上传要求!</div> <div class="text">支持上传jpg/png/jpeg/mp4格式文件,图片文件不能超过5M,视频文件不能超过100M。</div> </div> <span slot="footer" class="dialog-footer"> <el-button @click="dialogVisible = false" size="small">取 消</el-button> <el-button type="primary" @click="dialogVisible = false" size="small">确 定</el-button> </span> </el-dialog> <div class="upload-card" v-if="uploadLoading"> <div class="title">素材上传进度</div> <div class="card-wrap"> <div class="card-item" v-for="(item,index) in value" :key="index"> <div class="file-name"> <i :icon="item.type" class="uploader-file-icon"> </i> <div class="name"> {{item.fileName}}</div> </div> <div class="fileProgress"> <div class="bar-outer"> <div class="bar-inner" :style="{width:item.fileProgress+'%'}"></div> </div> {{ item.fileProgress+'%' }} </div> </div> </div> </div> </el-col> </el-row> </template>
script
<script> //引入webuploader import WebUploader from "webuploader"; import "webuploader/dist/webuploader.css"; import api from "@/http/api.js"; import BMF from 'browser-md5-file'; var chunkObj = {}; //用来记录文件的状态、上传中断的位置 var md5Obj = {};//记录文件分片后所有分片的md5 var GUID = WebUploader.Base.guid();//一个GUID export default { name: "uploaderList", components: {}, props: { accept: { type: [String, Object], default: null }, // 上传地址 url: { type: String, default: "/mtv_back/api/mtv-backend/sysMaterial/fileUpload",///mtv_back/api/mtv-backend/operate/upLoadFile }, // 上传最大数量 默认为100 fileNumLimit: { type: Number, default: 100 }, // 大小限制 默认2M fileSingleSizeLimit: { type: Number, default: 5120000 }, fileType: { type: String, default: "knowledge" }, // 上传时传给后端的参数,一般为token,key等 formData: { type: Object, default: () => { return { uuid: null, code: 9,md5:null }; } }, // 生成formData中文件的key,下面只是个例子,具体哪种形式和后端商议 keyGenerator: { type: Function, default: () => `${new Date().getTime()}` }, multiple: { type: Boolean, default: true }, // 上传按钮ID uploadButton: { type: String, default: "" }, value: { type: Array, default: () => [] }, disabled: { type: Boolean, default: () => false }, groupType:{ type: String, default: "" }, }, data() { return { uploader: null, dialogVisible:false, collapse:false, panelShow:true, uploadLoading:false, Filesize:0, file_type:'',//保存切换目录之前的type is_upload:true,//是否能继续上传,视频每次只能1个,图片可以多个 fileObj:{//上传的文件对象 } }; }, watch: { disabled(newVal) { if (newVal) { this.uploader.destroy(); return false; } this.initWebUpload(); }, groupType(newVal){ this.groupType = newVal; } }, mounted() { if (!this.disabled) { this.$nextTick(()=>{ console.log('初始化'); this.uploader = this.initWebUpload(); }) } }, methods: { handleClose(){ this.dialogVisible=false; }, initWebUpload() { console.log('初始化2'); // if (this.uploader) { // this.uploader.destroy(); // } let _this = this; WebUploader.Uploader.register({ "before-send-file":"beforeSendFile", "before-send": "beforeSend" }, { "beforeSendFile": function (file) { // var deferred = WebUploader.Deferred(); // this.$axios.post({ // url: "/PublicInfoManage/ResourceFile/isCheckFiles", // data: { // seq: seq, // fileMd5: $.md5(file.name + file.size + file.ext), // fileName:file.name // }, // dataType: "json", // success: function (data) { // console.log(data); // chunkObj = data; // chunkObj.type = data.type; // chunkObj.chunk == data.chunk; // if (data.type == 0) { // deferred.reject(); // //$("#" + file.id).find(".state").text("文件已上传"); // } else if (data.type == 1) { // if (data.chunk) { // deferred.resolve(); // } // } else { // deferred.resolve(); // } // }, // error: function () { // deferred.resolve(); // } // }) // deferred.resolve(); // return deferred.promise(); }, "beforeSend": function (block) {//分块对象 console.log('分块11',block); let _this = this; console.log('分块11',_this); if(_this.options.chunked){ var deferred = WebUploader.Deferred(); var curChunk = block.chunk;//第几个分片 var totalChunk = block.chunks;//总共几个分片 (new WebUploader.Uploader()).md5File(block.file, block.start, block.end) .progress(function(percentage) { console.log("正在读取文件"); }) .then(function(val) { //block.md5 = val; console.log("分块的md5",val); console.log('当前的md5',_this.options.formData.md5); // _this.options.formData.chunk = block.chunk; // _this.options.formData.fileSize = block.file.size;//分片大小 // if(block.file.name.indexOf('.jpg')!=-1 || block.file.name.indexOf('.jpeg')!=-1){ // }else{ // } if(md5Obj[block.file.name]){ md5Obj[block.file.name].md5List[block.chunk] = val; }else{ md5Obj[block.file.name] = { md5List:[], } md5Obj[block.file.name].md5List[block.chunk] = val; } //deferred.resolve(); if(chunkObj[block.file.name] && chunkObj[block.file.name].lackList){//如果重传只传失败的 if(chunkObj[block.file.name].lackList.indexOf(val)!=-1){ //_this.options.formData.md5 = val; _this.options.formData.chunk = block.chunk; _this.options.formData.fileSize = block.file.size;//分片大小 deferred.resolve(); }else{ deferred.reject();//跳过此分块 } }else{// //_this.options.formData.md5 = val; _this.options.formData.chunk = block.chunk; _this.options.formData.fileSize = block.file.size;//分片大小 deferred.resolve(); } }) return deferred.promise(); } } }); const uploader = (this.uploader = WebUploader.create({ auto: true, // 选完文件后,是否自动上传 server: this.url, // 文件接收服务端 // swf: '/static/lib/webuploader/Uploader.swf', // swf文件路径 dnd:`#drag`,//拖拽容器,不指定则不开启 pick: { id: `#up_single`, multiple: false }, // pick: { // //pick: { id: "#up_single", multiple: false }, // id: this.$refs.selectFile.$el, // 选择文件的按钮 // multiple: this.multiple // 是否多文件上传 默认false // }, //accept: this.getAccept(this.accept), // 允许选择文件格式。 threads: 3, fileNumLimit: this.fileNumLimit, // 限制上传个数 //fileSingleSizeLimit: this.fileSingleSizeLimit, // 限制单个上传图片的大小 formData: this.formData, // 上传所需参数 chunked: true, //分片上传 chunkRetry:3,//允许重传3次 //chunkSize: 2048000, //分片大小5120000,20M duplicate: true, // 重复上传 timeout: 0, //超时时间不设置超时限制 compress: false,//不启用压缩 resize: false,//尺寸不改变 //上传文件格式 // accept: { // extensions: "doc,docx,pdf,txt,xls,xlsx,jpg,png,mp4,avi", // mimeTypes: ".doc,.docx,.pdf,.txt,.xls,.xlsx,.jpg,.png,.mp4,.avi", // }, // accept: { // extensions: "zip,rar,ios,7z", // mimeTypes: ".zip,.rar,.ios,.7z,", // }, accept: { extensions: "jpg,png,jpeg,mp4", mimeTypes: ".jpg,.png,.jpeg,.mp4", }, })); const fun = [ "beforeFileQueued", "fileQueued", "uploadStart", "uploadProgress", "uploadSuccess", "error", "uploadError", "uploadBeforeSend" ]; for (const item of fun) { uploader.on(item, this[item]); } return uploader; }, beforeFileQueued(file){ this.file_type = this.groupType; this.Filesize = file.size console.log('filestart',file); console.log('uploader1',this.uploader); if(!this.coverString('.png',file.name) && !this.coverString('.jpg',file.name) && !this.coverString('.jpeg',file.name) && !this.coverString('.mp4',file.name)){ this.$message.error('文件格式不正确,请选择支持的图片或文件格式上传'); if (file) { // 取消并中断文件上传 this.uploader.cancelFile(file); // 在队列中移除文件 this.uploader.removeFile(file, true); //this.value = [];//上传前清空上传记录 this.uploadLoading = false; return; } } if(this.coverString('.jpg',file.name) || this.coverString('.png',file.name) || this.coverString('.jpeg',file.name)){//图片 if(file.size>(5*1024*1024)){//20M this.dialogVisible = true; this.$message.error('素材过大,请注意上传素材的大小不要超过规定限制'); if (file) { // 取消并中断文件上传 this.uploader.cancelFile(file); // 在队列中移除文件 this.uploader.removeFile(file, true); //this.value = [];//上传前清空上传记录 this.uploadLoading = false; return; } } } if(this.coverString('.mp4',file.name)){//视频 if(this.value.length>0){ this.uploader.cancelFile(file); // 在队列中移除文件 this.uploader.removeFile(file, true); this.$message.error('请等待图片上传完成后再上传视频'); return; } if(file.size>(100*1024*1024)){//20M this.dialogVisible = true; this.$message.error('视频文件不能超过100M'); // 取消并中断文件上传 this.uploader.cancelFile(file); // 在队列中移除文件 this.uploader.removeFile(file, true); //this.value = [];//上传前清空上传记录 this.uploadLoading = false; return; if (file) { } } } //this.value = [];//上传前清空上传记录 console.log('this.uploader',this.uploader); // //获取文件MD5 let _this = this; // const bmf = new BMF(); // bmf.md5( // file, // (err, md5) => { // console.log('err:', err); // console.log('md5 string:', md5); // 97027eb624f85892c69c4bcec8ab0f11 // //data.md5 = val; // }, // progress => { // console.log('progress number:', progress); // }, // ); this.uploader.removeFile(file, true); let md5 = {}; (new WebUploader.Uploader()).md5File(file, 0, file.size) .progress(function(percentage) { console.log("正在读取文件"); }) .then(function(val) { // this.uploader.md5File( file )// 及时显示进度 // .progress(function(percentage) { // console.log('读取文件:'+parseInt(percentage*100)+"%"); // }) // // 完成 // .then(function(val) { md5[file.id] = val; console.log('md5:',val); let params = { fileName:file.name, uuid:'', chunks:file.size>5242880?Math.ceil(file.size/5242880):1, fileSize:file.size, md5:val }; params.uuid = _this.keyGenerator(); //是否允许上传 _this.$axios.post(api + `/mtv-backend/sysMaterial/filePreCheck`,params) .then((res) => { console.log('res',res.data.data); if(res.data.data.allow){ console.log('允许上传'); _this.uploader.upload(file); // if(file.name.indexOf('.jpg')!=-1 || file.name.indexOf('.jpeg')!=-1){//jpg图片直接获取 // if(md5Obj[file.name]){ // md5Obj[file.name].md5List[0] = val; // }else{ // md5Obj[file.name] = { // md5List:[], // } // md5Obj[file.name].md5List[0] = val; // } // } _this.fileObj[file.name] = {//添加附件的md5记录 uuid:params.uuid, fileMd5List:[], count:1, } if(chunkObj[file.name]){ delete chunkObj[file.name] } const { name, size, id } = file; const obj = { id, fileName: name, fileSize: WebUploader.Base.formatSize(size), fileProgress: 0, fileStatus: "待上传", file, type:'', groupType:_this.file_type }; let text = '.doc,.docx,.pdf,.txt,.xls,.xlsx'; let image = '.jpg,.png,.jpeg'; let video = '.mp4'; let audio = '.avi' if(name.indexOf('.zip')!=-1){ obj.type='zip'; }else{ text.split(',').forEach(item=>{ if(_this.coverString(item,file.name)){ obj.type='text'; } }) image.split(',').forEach(item=>{ if(_this.coverString(item,file.name)){ obj.type='image'; } }) video.split(',').forEach(item=>{ if(_this.coverString(item,file.name)){ obj.type='video'; } }) audio.split(',').forEach(item=>{ if(_this.coverString(item,file.name)){ obj.type='audio'; } }) } //doc,docx,pdf,txt,xls,xlsx,jpg,png,mp4,avi _this.value.push(obj); _this.uploadLoading = true; if(obj.type=='video'){ _this.is_upload=false; }else{ _this.is_upload = true; } }else{ if(res.data.data.materialUrl && res.data.data.materialUrl!=''){//直接返回url保存 const { name, size, id } = file; const obj = { id, fileName: name, fileSize: WebUploader.Base.formatSize(size), fileProgress: 99, fileStatus: "待上传", file, type:'', groupType:_this.file_type }; let text = '.doc,.docx,.pdf,.txt,.xls,.xlsx'; let image = '.jpg,.png'; let video = '.mp4'; let audio = '.avi' if(name.indexOf('.zip')!=-1){ obj.type='zip'; }else{ text.split(',').forEach(item=>{ if(_this.coverString(item,file.name)){ obj.type='text'; } }) image.split(',').forEach(item=>{ if(_this.coverString(item,file.name)){ obj.type='image'; } }) video.split(',').forEach(item=>{ if(_this.coverString(item,file.name)){ obj.type='video'; } }) audio.split(',').forEach(item=>{ if(_this.coverString(item,file.name)){ obj.type='audio'; } }) } //doc,docx,pdf,txt,xls,xlsx,jpg,png,mp4,avi _this.value.push(obj); _this.uploadLoading = true; const params = { url:res.data.data.materialUrl, name:file.name, materialSize:file.size, file:null, groupType:_this.file_type }; _this.findVideoPoster(params);//获取视频第一帧并上传 }else{ _this.$message({ message: '名称不可重复', type: 'error' }); _this.panelShow = false; //this.uploadLoading = false; //this.value = [];//上传前清空上传记录 _this.uploader.cancelFile(file); // 在队列中移除文件 _this.uploader.removeFile(file, true); } } }) }); // const { name, size, id } = file; // const obj = { // id, // fileName: name, // fileSize: WebUploader.Base.formatSize(size), // fileProgress: 0, // fileStatus: "待上传", // file, // type:'', // groupType:_this.file_type // }; // let text = '.doc,.docx,.pdf,.txt,.xls,.xlsx'; // let image = '.jpg,.png'; // let video = '.mp4'; // let audio = '.avi' // if(name.indexOf('.zip')!=-1){ // obj.type='zip'; // }else{ // text.split(',').forEach(item=>{ // if(name.indexOf(item)!=-1){ // obj.type='text'; // } // }) // image.split(',').forEach(item=>{ // if(name.indexOf(item)!=-1){ // obj.type='image'; // } // }) // video.split(',').forEach(item=>{ // if(name.indexOf(item)!=-1){ // obj.type='video'; // } // }) // audio.split(',').forEach(item=>{ // if(name.indexOf(item)!=-1){ // obj.type='audio'; // } // }) // } // //doc,docx,pdf,txt,xls,xlsx,jpg,png,mp4,avi // _this.value.push(obj); // _this.uploadLoading = true; // if(obj.type=='video'){ // _this.is_upload=false; // }else{ // _this.is_upload = true; // } }, uploadBeforeSend(block,data){ console.log('block',block); var file = block.file; if(md5Obj[file.name]){ data.md5 = md5Obj[file.name].md5List[block.chunk]; } console.log("当前文件id", file.id); console.log("当前文件名", file.name); // 上传时添加自定义参数 console.log('获取当前块上传参数',data); if(this.fileObj[file.name]){ data.uuid = this.fileObj[file.name].uuid; if(this.fileObj[file.name].fileMd5List.indexOf(data.md5)==-1){ this.fileObj[file.name].fileMd5List.push(data.md5); } }else{ this.fileObj[file.name] = { uuid:data.uuid, fileMd5List:[], count:1 } this.fileObj[file.name].fileMd5List.push(data.md5); } //this.uploader.removeFile(file, true); //let _this = this; // this.uploader.md5File( file )// 及时显示进度 // .progress(function(percentage) { // console.log('读取文件:'+parseInt(percentage*100)+"%"); // }) // // 完成 // .then(function(val) { // data.md5 = val; // _this.uploader.upload(file); // }) }, // 当有文件被添加进队列的时候,添加到页面预览 fileQueued(file) { //this.value = [];//上传前清空上传记录 }, //获取视频第一帧做完封面 findVideoPoster(file) { let self = this return new Promise(function(resolve) { console.log('获取第一帧'); try{ let base64URL = '' let video = null; let eventName = ''; if(self.coverString('.png',file.name) || self.coverString('.jpg',file.name) || self.coverString('.jpeg',file.name)){ //video = document.createElement('image'); video = new Image(); eventName = 'load'; video.setAttribute('crossOrigin', 'anonymous') //处理跨域 console.log('获取第一帧001'); video.onload = (()=>{ console.log('获取第一帧003'); let canvas = document.createElement('canvas') //let canvas = document.getElementById('myCanvas'); //使用视频的宽高作为canvas、预览图的宽高 let width = 200; let height = 200; canvas.width = width canvas.height = height canvas.getContext('2d').drawImage(video, 0, 0, width, height) //绘制canvas base64URL = canvas.toDataURL('image/jpeg') //转换为base64,图片格式默认为png,这里修改为jpeg let fileName = String(new Date().getTime()) + parseInt(Math.random() * 100000) + '.jpeg' //const imgfile = self.data64toFile(base64URL) const imgfile = self.dataURLToFile(base64URL,fileName); file.file = imgfile; console.log('获取第一帧004'); self.postInfo(file); }) video.src = file.url; console.log('video',video); }else{ video = document.createElement('video'); eventName = 'loadeddata'; video.setAttribute('crossOrigin', 'anonymous') //处理跨域 video.setAttribute('src', file.url); video.currentTime = 1; video.addEventListener(eventName, function() { let canvas = document.createElement('canvas') //let canvas = document.getElementById('myCanvas'); //使用视频的宽高作为canvas、预览图的宽高 let width = 200; let height = 200; canvas.width = width canvas.height = height canvas.getContext('2d').drawImage(video, 0, 0, width, height) //绘制canvas base64URL = canvas.toDataURL('image/jpeg') //转换为base64,图片格式默认为png,这里修改为jpeg let fileName = String(new Date().getTime()) + parseInt(Math.random() * 100000) + '.jpeg' //const imgfile = self.data64toFile(base64URL) const imgfile = self.dataURLToFile(base64URL,fileName); file.file = imgfile; console.log('上传素材',file); console.log('获取第一帧003'); self.postInfo(file); }) } }catch(err){ console.log('err',err); } }) }, coverString(subStr,str){//判断字符串中是否存在子字符串,不区分大小写,处理素材大小写 let reg = eval("/"+subStr+"/ig"); return reg.test(str); }, dataURLToFile(file,filename){ const arr = file.split(','); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], filename, {type: mime}); }, data64toFile(base64URL) { const arr = base64URL.split(',') const mime = arr[0].match(/:(.*?);/)[1] const bstr = atob(arr[1]) let n = bstr.length const u8arr = new Uint8Array(n) while (n--) { u8arr[n] = bstr.charCodeAt(n) } return new Blob([u8arr], { type: mime }) }, postInfo(file){//上传素材信息 this.currentPage = 1; const formData = new FormData(); formData.append('materialUrl',file.url); formData.append('materialType',file.groupType); formData.append('materialName',file.name); formData.append('thumbnail',file.file); formData.append('materialSize',Number(this.Filesize)); this.$axios.post(api + "/mtv-backend/sysMaterial/saveSystemMaterial", formData, { headers:{ 'Content-Type': 'multipart/form-data', } }) .then((res) => { console.log('res',res); if(res.data.code==200){ this.$message({ message: file.name+'上传成功', type: 'success' }); let idx = -1; this.value.forEach((item,index)=>{ if(item.fileName==file.name){ idx = index } }) console.log(this.value,idx); if(this.value[idx]){//设置进度100 this.value[idx].fileProgress=100; } this.value.splice(idx,1);//删除上传记录 if(this.value.length==0){ this.uploadLoading = false; } this.is_upload = true; delete this.fileObj[file.name];//删除保存的md5记录 delete md5Obj[file.name] this.$emit("input"); }else{ this.$message({ message: file.name+'上传失败', type: 'error' }); let idx = -1; this.value.forEach((item,index)=>{ if(item.fileName==file.name){ idx = index } }) this.value.splice(idx,1); if(this.value.length==0){ this.uploadLoading = false; } this.is_upload = true; } }) }, // 在这里可以准备好formData的数据 uploadStart(file) { console.log('aa',file); this.uploader.options.formData.uuid = this.fileObj[file.name].uuid; }, // 文件上传过程中创建进度条实时显示。 uploadProgress(file, percentage) { const fileObj = this.value.find(obj => file.id == obj.id); fileObj.fileStatus = "上传中"; //console.log('percentage',percentage); fileObj.fileProgress = parseInt(percentage * 100); fileObj.file = file; if(fileObj.fileProgress==100){ fileObj.fileProgress = 99; } //this.$emit("input", this.value); }, // 文件上传成功 async uploadSuccess(file, res) { const fileObj = this.value.find(obj => file.id == obj.id); console.log('上传结果',file,res); if(res.code==200){ fileObj.fileId = file.id; fileObj.fileStatus = "上传成功"; //this.$emit("input", this.value); let form = this.fileObj[file.name]; //发起合并请求 this.$axios.post(api + "/mtv-backend/sysMaterial/fileMerge", form,{ timeout: 120000 }) .then((res) => { console.log('合并请求结果res',res); if(res.data.code==200){ if(!res.data.data.lackList){//分块丢失 if(res.data.data.materialUrl=='' || !res.data.data.materialUrl){//合并url出错 this.showError(file); return; } if(chunkObj[file.name]){//重传完成删除记录 delete chunkObj[file.name] } const params = { url:res.data.data.materialUrl, name:file.name, materialSize:res.data.data.fileSize, file:null, groupType:fileObj.groupType }; this.findVideoPoster(params);//获取视频第一帧并上传 }else{//重传分块 if(this.fileObj[file.name].count>=3){//重传3次依旧失败则不重传 this.showError(file); return; } chunkObj[file.name] = {//保存出错的分块 lackList:res.data.data.lackList, } this.fileObj[file.name].count++; this.uploader.upload(file); } }else{//合并出错 this.showError(file); } }) }else{//上传失败 this.showError(file); } }, showError(file){ this.$message({ message: file.name+'上传失败', type: 'error' }); let idx = -1; this.value.forEach((item,index)=>{ if(item.name==file.name){ idx = index } }) this.value.splice(idx,1); if(this.value.length==0){ this.uploadLoading = false; } this.is_upload = true; }, error(type) {//报错信息 console.log('error type',type); this.uploadLoading = false; let errorMessage = ""; if (type === "F_EXCEED_SIZE") { errorMessage = `文件大小不能超过${this.fileSingleSizeLimit / (1024 * 100)}M`; } else if (type === "Q_EXCEED_NUM_LIMIT") { errorMessage = "文件上传已达到最大上限数"; } else { errorMessage = `上传出错!请检查后重新上传!错误代码${type}`; } console.error(errorMessage); }, uploadError(file){ console.log('uploadError',file); this.$message({ message: file.name+'文件上传失败', type: 'error' }); let idx = -1; this.value.forEach((item,index)=>{ if(item.name==file.name){ idx = index } }) this.value.splice(idx,1); if(this.value.length==0){ this.uploadLoading = false; } this.is_upload = true; }, // 开始 resume(file) { this.uploader.upload(file); }, // 暂停 stop(file) { file.fileStatus = "暂停中"; this.uploader.stop(file); }, // 移除 async remove(row, idx) { const { fileId, file } = row; try { //if (fileId) await delFileApi(fileId); this.value.splice(idx, 1); if (file) { // 取消并中断文件上传 this.uploader.cancelFile(file); // 在队列中移除文件 this.uploader.removeFile(file, true); } //this.$emit("input", this.value); } catch (error) { console.log(error); } }, // 预览 imgLook(fileId) { if (!fileId) { return false; } lookImg(fileId).then(res => { const sourceImages = []; sourceImages.push({ thumbnail: process.env.VUE_APP_BASE_API + this.profile + res.data.thumbnailFile, source: process.env.VUE_APP_BASE_API + this.profile + res.data.thumbnailFile }); // console.log(sourceImages); this.$refs.viewer.show(sourceImages, 0); }); }, //上传文件格式 getAccept(accept) { switch (accept) { case "text": return { title: "Texts", exteensions: "doc,docx,xls,xlsx,ppt,pptx,pdf,txt", mimeTypes: ".doc,docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt" }; case "video": return { title: "Videos", exteensions: "mp4", mimeTypes: ".mp4" }; case "image": return { title: "Images", exteensions: "gif,jpg,jpeg,bmp,png,tif", mimeTypes: ".gif,.jpg,.jpeg,.bmp,.png,.tif" }; default: return accept; } }, submitFile() { this.uploader.upload(); }, // cancelFileUpload(){//取消上传,调取接口删除上传文件流 // const { fileId, file } = this.value[0]; // // 取消并中断文件上传 // this.uploader.cancelFile(file); // // 在队列中移除文件 // this.uploader.removeFile(file, true); // this.$axios.post(api + "/mtv-backend/sysMaterial/saveSystemMaterial", {fileName:file.name}) // .then((res) => { // console.log('res',res); // if(res.data.code==200){ // }else{ // } // }) // }, //文件大小单位换算 sizeConversion(size){ if (size < 1024) { size = size.toFixed(2) + "B"; }else if (size < 1048576) { size = (size / 1024).toFixed(2) + "K"; }else if (size < 1073741824) { size = (size / 1048576).toFixed(2) + "M"; }else { size = (size / 1073741824).toFixed(2) + "G"; } return size; }, close() { //this.uploader.destroy(); this.panelShow = false }, } }; </script>
style
<style lang="less" scoped> /deep/ .webuploader-pick{ background-color: #fff; } /deep/ .el-dialog{ border-radius: 4px; } /deep/ .el-dialog__header{ background-color: whitesmoke; padding: 15px 20px 15px; box-shadow: rgb(233 233 233) 0px 1px 1px; border-radius: 4px 4px 0 0; } /deep/ .el-dialog__footer{ box-shadow: rgb(233, 233, 233) 0px 1px 1px 0px inset; padding: 14px 20px 14px; } .upload-area{ background-color: #f9f9f9; border: 1px dashed #d9d9d9; border-radius: 6px; box-sizing: border-box; width: 500px; height: 184px; text-align: center; cursor: pointer; overflow: hidden; margin-bottom: 30px; display: flex; align-items: center; justify-content: center; &:hover{ border-color: #409EFF; background-color: #fff; .upload .upload-icon i{ color: #409EFF; } } .upload{ font-size: 14px; .upload-icon{ margin-bottom: 20px; i{ font-size: 67px; color: #C0C4CC; } } .upload-desc{ color: #606266; font-size: 14px; text-align: center; margin-bottom: 20px; } .upload-tip{ color: #999999; font-size: 14px; } } } .model-title{ color:#333; font-weight:bold; font-size: 13px; display: flex; align-items: center; justify-content: space-between; .title{ display: flex; align-items: center; } i{ font-size: 20px; } .close{ cursor: pointer; i{ font-weight: 700; font-size: 20px; color: #999; } } } .model{ margin-top: -20px; .tip{ margin-bottom:10px; color:#333; font-weight:bold; } .text{ line-height: 28px; font-size: 14px; color: #999; } } // .upload-list{ // position: fixed; // width: 600px; // bottom: 0px; // left: 0; // z-index: 1; // border-top: 1px solid #d9d9d9; // background-color: #fff; // border: 1px solid #e2e2e2; // border-radius: 7px 7px 0 0; // box-shadow: 0 0 10px rgb(0 0 0 / 20%); // .file-title { // display: flex; // height: 40px; // line-height: 40px; // padding: 0 15px; // border-bottom: 1px solid #ddd; // font-size: 14px; // .operate { // flex: 1; // text-align: right; // i{ // font-size: 18px; // } // .el-button { // display: inline-block; // line-height: 1; // white-space: nowrap; // cursor: pointer; // background: #FFF; // border: 1px solid #DCDFE6; // color: #606266; // -webkit-appearance: none; // text-align: center; // box-sizing: border-box; // outline: 0; // margin: 0; // transition: .1s; // font-weight: 500; // padding: 12px 20px; // font-size: 14px; // border-radius: 4px; // } // .el-button--text { // border-color: transparent; // color: #409EFF; // background: 0 0; // padding-left: 0; // padding-right: 0; // } // } // } // &.collapse { // .file-title { // background-color: #e7ecf2; // } // .file-list { // height: 0; // } // } // } .uploader-file-name{ .uploader-file-icon[icon=zip]{ background: url(../../assets/images/zip.png); } .uploader-file-icon[icon=text]{ background: url(../../assets/images/text-icon.png); } .uploader-file-icon[icon=image]{ background: url(../../assets/images/image-icon.png); } .uploader-file-icon[icon=video]{ background: url(../../assets/images/video-icon.png); } .uploader-file-icon[icon=audio]{ background: url(../../assets/images/audio-icon.png); } display: flex; .name{ flex: 1; word-break: break-all; } .uploader-file-icon { width: 24px; height: 24px; display: inline-block; vertical-align: top; // margin-top: 13px; // margin-right: 8px; } } .upload-card{ padding: 10px; border-radius: 4px; background-color: #fff; position: fixed; right: 60px; top: 60px; z-index: 99; box-shadow: 0 0 10px rgb(0 0 0 / 20%); color: #666; width: 300px; .title{ font-size: 14px; font-weight: bold; margin-bottom: 16px; } .card-wrap{ .card-item{ .file-name{ font-size: 12px; display: flex; .name{ flex: 1; word-break: break-all; } i{ width: 14px; height: 14px; margin-right: 4px; } .uploader-file-icon[icon=zip]{ background: url(../../assets/images/zip.png); background-size: contain; } .uploader-file-icon[icon=text]{ background: url(../../assets/images/text-icon.png); background-size: contain; } .uploader-file-icon[icon=image]{ background: url(../../assets/images/image-icon.png); background-size: contain; } .uploader-file-icon[icon=video]{ background: url(../../assets/images/video-icon.png); background-size: contain; } .uploader-file-icon[icon=audio]{ background: url(../../assets/images/audio-icon.png); background-size: contain; } } .fileProgress{ font-size: 12px; display: flex; align-items: center; .bar-outer{ display: flex; align-items: center; border-radius: 100px; background-color: #ebeef5; overflow: hidden; position: relative; vertical-align: middle; margin-right: 4px; height: 8px; //width: 200px; flex: 1; .bar-inner{ position: absolute; left: 0; top: 0; height: 100%; background-color: #409eff; text-align: right; border-radius: 100px; line-height: 1; white-space: nowrap; transition: width .6s ease; } } } } } } </style>
重点在于beforeSend获取到分片对象,WebUploader提供一个md5File函数获取文件流的md5,uploadBeforeSend函数自定义每个分片上传的参数,在WebUploader配置中记得加上compress:false,resize: false,否则组件在分片时会默认将分片压缩,导致总文件的md5与合并后的md5不一致
compress: false,//不启用压缩
resize: false,//尺寸不改变
(new WebUploader.Uploader()).md5File(block.file, block.start,
block.end)
.progress(function(percentage) {
console.log(“正在读取文件”);
})
.then(function(val) {
})
参考文档:
http://fex.baidu.com/webuploader/doc/#WebUploader_Uploader_md5File
http://t.zoukankan.com/hackerPJ-p-7563023.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。