webuploader大文件分片上传,md5验证附件上传

4 篇文章 0 订阅
1 篇文章 0 订阅

最近项目需求使用到大附件上传功能,图片最多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

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值