vue系列---【vue+webuploader实现文件分块上传】

html部分

<template>
  <div class="Upload">
    <div class="data-content" id="content">
      <div class="loanManagement_content">
        <h1 class="mb35">上传文件</h1>
        <div class="upload-file-flex mb35">
          <i>数据类型:</i>
          <el-radio-group
            v-model="uploadType"
            id="uploadFileType"
            @change="uploadTypeFn(uploadType)"
          >
            <el-radio :label="1">图片</el-radio>
            <el-radio :label="2">音频</el-radio>
            <el-radio :label="3">文本</el-radio>
            <el-radio :label="4">视频</el-radio>
            <el-radio :label="6">点云</el-radio>
          </el-radio-group>
        </div>
        <div class="upload-file-flex mb35">
          <i>限制扩展名:</i>
          <div v-html="limitType[uploadType].type"></div>
        </div>

        <div id="uploader">
          <div class="btns clearfix mgT20 mgB20">
            <div id="picker" class="disInline float-left mgR10"></div>
            <el-button
              class="disInline float-left"
              size="small"
              :disabled="isDisabled"
              type="primary"
              id="ctlBtn"
              @click="handleStartUpload"
              >开始上传</el-button
            >
          </div>
          <!--用来存放文件信息-->
          <div id="thelist" class="uploader-list">
            <div class="item" v-for="item in uploadFileList" :key="item.id">
              <div class="clearfix mgB10">
                <span class="info">{{ item.name }}</span>
                <span class="state">{{ processName }}</span>
                <p
                  class="remove-btn disInline el-icon-delete"
                  :class="{ removeBtn: removeBtn }"
                ></p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

js部分

<script>
import $ from "jquery";
// import WebUploader from "webuploader";
import XLSX from "xlsx";
import axios from "axios";
import Qs from "qs";
export default {
  name: "uploadFile",
  data() {
    return {
      removeBtn: false,
      uploadType: "2",
      limitType: {
        1: {
          type: ".csv、.xlsx、.xls",
          accept:
            ".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          checkType: "csv,xlsx,xls",
        },
        2: {
          type: ".csv、.xlsx、.xls",
          accept:
            ".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          checkType: "csv,xlsx,xls",
        },
        3: {
          type: ".txt",
          accept: "text/plain",
          checkType: "txt",
        },
        4: {
          type: ".csv、.xlsx、.xls",
          accept:
            ".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          checkType: "csv,xlsx,xls",
        },
        6: {
          type: ".csv、.xlsx、.xls",
          accept:
            ".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          checkType: "csv,xlsx,xls",
        },
      },
      acceptTypeObj: {
        title: "Files",
        extensions: "csv,xlsx,xls",
        mimeTypes:
          ".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      },
      uploadCheckType: "csv,xlsx,xls",
      uploadCheckMimeTypes: "",
      fileLists: [],
      getFiles: "", //队列文件个数
      fileName: "", //上传文件名称
      id: "", //start接口返回数据集id
      ossKey: "",
      fileSize: "",
      uploadStatus: "",
      isDisabled: false,
      uploadFileList: [],
      processName: "等待上传", //上传过程名称
      materialAmount: "", //数据量
      isCheckFlag: false, //是否检查过文件名标识
      uploader: null,
    };
  },
  mounted() {
    document.cookie = `pin=${this.getQueryString("user")};path=/;maxAge=${
      24 * 60 * 60 * 1000
    }`;
    this.uploadType = 1;
    this.uploadFile();
  },
  methods: {
    getQueryString(name) {
      var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
      var r = ('?' + window.location.href.split('?')[1]).substr(1).match(reg);
      if (r != null) return unescape(r[2]);
      return null;
    },
    uploadTypeFn(n) {
      this.uploadCheckType = this.limitType[n].checkType;
      this.uploadCheckMimeTypes = this.limitType[n].accept;

      this.acceptTypeObj = {
        title: "Files",
        extensions: this.uploadCheckType,
        mimeTypes: this.uploadCheckMimeTypes,
      };
      this.uploadFile();
    },
    handleStartUpload(file) {
      if (this.uploadStatus === 4) {
        //上传失败
        this.showProgress(file, "FILE");
        this.uploader.retry();
      } else {
        if (this.getFiles.length == 0) {
          this.$message({
            message: "请选择文件",
            type: "warning",
          });
          return false;
        }
        this.checkFileName(
          () => {
            this.processName = "上传中...";
            this.uploader.upload();
          },
          () => {
            this.closeUploader();
          },
        );
      }
    },
    //上传文件
    uploadFile() {
      let _this = this;
      var $btn = $("#ctlBtn");
      var $thelist = $("#thelist");
      var chunkSize = 5242880;
      //当前状态
      // var state = "pending";
      // HOOK 这个必须要再uploader实例化前面
      WebUploader.Uploader.register(
        {
          "before-send-file": "beforeSendFile",
          "before-send": "beforeSend",
        },
        {
          beforeSendFile: function (file) {
            // Deferred对象在钩子回掉函数中经常要用到,用来处理需要等待的异步操作。
            var task = new $.Deferred();
            // 根据文件内容来查询MD5
            if (file.md5 != null && file.md5 !== "") {
              // file.md5 = file.md5;
              file.uid = WebUploader.Base.guid();
              task.resolve();
            } else {
              _this.uploader
                .md5File(file)
                .progress(function () {
                  // 及时显示进度
                  if (file.md5 != null && file.md5 !== "") {
                    return;
                  }
                })
                .then(function (val) {
                  // 完成
                  file.md5 = val;
                  // 模拟用户id
                  file.uid = WebUploader.Base.guid();
                  task.resolve();
                });
            }

            return $.when(task);
          },
          beforeSend: function (block) {
            var task = new $.Deferred();
            var file = block.file;
            var missChunks = file.missChunks;
            var blockChunk = block.chunk;
            if (
              missChunks !== null &&
              missChunks !== undefined &&
              missChunks !== ""
            ) {
              var flag = true;
              for (var i = 0; i < missChunks.length; i++) {
                if (blockChunk == missChunks[i]) {
                  flag = false;
                  break;
                }
              }
              if (flag) {
                //是断点续传,但当前块不是缺少的块,不发送。
                task.reject();
              } else {
                task.resolve(); //是断点续传,当前块是缺少的块,发送
              }
            } else {
              task.resolve(); //不是断点续传,直接发送d当前数据块。
            }
            return $.when(task);
          },
        },
      );

      // 实例化
      this.uploader = WebUploader.create({
        //指定选择文件的按钮容器
        pick: {
          id: "#picker",
          innerHTML: "<div class='el-icon-upload2'>选择文件</div>",
          multiple: false,
        },
        //文件上传请求的参数表,每次发送都会发送此对象中的参数。
        formData: {
          uid: 0,
          md5: "",
          chunkSize: chunkSize,
        },
        accept: _this.acceptTypeObj,
        //dnd: '#dndArea',//此项实现拖拽的功能
        //paste: '#uploader',
        swf: "js/Uploader.swf",
        //是否要分片处理大文件上传
        chunked: true,
        // 如果要分片,分多大一片? 默认大小为5M.
        chunkSize: chunkSize,
        //上传并发数。允许同时最大上传进程数
        threads: 1,
        server: "/xxx/xxx/upload", // url
        //设置为 true 后,不需要手动调用上传,有文件选择即开始上传
        auto: false,
        // 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。
        disableGlobalDnd: true,
        //验证文件总数量, 超出则不允许加入队列(同时上传的文件数)B
        fileNumLimit: 1,
        //验证文件总大小是否超出限制, 超出则不允许加入队列B
        fileSizeLimit: 8 * 1024 * 1024 * 1024,
        //验证单个文件大小是否超出限制, 超出则不允许加入队列B
        fileSingleSizeLimit: 500 * 1024 * 1024,
        resize: false,
      });

      //文件被添加进队列前
      // this.uploader.on("beforeFileQueued", function (file) { });
      // 当有文件被添加进队列的时候
      this.uploader.on("fileQueued", function (file) {
        _this.getFiles = _this.uploader.getFiles().length;
        _this.fileName = file.name;
        _this.fileSize = file.size;
        _this.uploadStatus = 1;
        _this.uploadFileList.push(file);
        _this.getCSV(file.source.source, file.ext, file.id);
      });
      $thelist.on("click", ".remove-btn", function () {
        var fileItem = $(this).parent().parent();
        // var id = $(fileItem).attr("id");
        _this.uploader.removeFile(_this.uploadFileList, true);
        $(fileItem).fadeOut(function () {
          $(fileItem).remove();
        });
        _this.closeUploader();
      });
      //当某个文件的分块在发送前触发,主要用来询问是否要添加附带参数,大文件在开起分片上传的前提下此事件可能会触发多次。
      this.uploader.on("uploadBeforeSend", function (obj, data) {
        _this.uploadStatus = 0;
        var file = obj.file;
        data.md5 = file.md5 || "";
        data.uid = file.uid;
        data.relativepath = obj.file.source.source.webkitRelativePath
          ? obj.file.source.source.webkitRelativePath
          : "";
        data.fileType = "1";
        data.fileName = obj.file.source.source.webkitRelativePath
          ? obj.file.source.source.webkitRelativePath
          : "";
      });
      // 上传过程中触发,携带上传进度 percentage ,是一个数字
      this.uploader.on("uploadProgress", function (file, percentage) {
        _this.getProgressBar(file, percentage, "FILE", "上传进度");
      });
      // 上传返回结果
      this.uploader.on("uploadSuccess", (file, res) => {
        const { code, data } = res;
        if (code && code == 200) {
          if (data) {
            var ossKey = data.imageName;
            var md5 = data.ETag;
            var uploadId = "";
            if (data.uploadId) {
              uploadId = res.uploadId;
            }
            _this.uploadStatus = 3;
            _this.uploadComplete(ossKey, md5, file.id, uploadId);
          }
        }

        // if (res.result) {
        //   var ossKey = res.result.Key;
        //   var md5 = res.data.ETag;
        //   var uploadId = "";
        //   if (res.uploadId) {
        //     uploadId = res.uploadId;
        //   }
        //   _this.uploadStatus = 3;
        //   _this.uploadComplete(ossKey, md5, file.id, uploadId);
        // }

        this.processName = "上传成功";

        this.removeBtn = true;
        // $("#" + file.id)
        //   .find(".state")
        //   .text(this.processName);
        // $("#" + file.id)
        //   .find(".remove-btn")
        //   .remove();
      });
      this.uploader.on("uploadError", function (file) {
        _this.uploadStatus = 4;

        $("#" + file.id)
          .find(".state")
          .text("上传出错");
        $btn.html("重新上传");
        _this.handleStartUpload(file);
        // $btn.unbind('click');
        // $btn.on('click', function () {
        //     _this.showProgress(file, 'FILE');
        //     uploader.retry();
        // });
      });

      this.uploader.on("uploadComplete", function (file) {
        _this.fadeOutProgress(file, "FILE");
      });

      // 文件上传
      // $btn.on('click', function () {
      //     if (_this.getFiles.length == 0) {
      //         _this.$message({
      //             message: '请选择文件',
      //             type: 'warning'
      //         });
      //         return false;
      //     }
      //     _this.checkFileName(function () {
      //         _this.processName = '上传中...';
      //         uploader.upload();
      //     }, function () {
      //         closeUploader();
      //     });

      //     // _this.processName = '上传成功';
      // });
      //类型变换时
      $("#uploadFileType").on("change", function () {
        _this.closeUploader();
      });
    },
    //删除已上传队列
    closeUploader() {
      this.getFiles = "";
      this.fileName = "";
      this.isDisabled = false;

      // 移除所有缩略图并将上传文件移出上传序列
      for (var i = 0; i < this.uploader.getFiles().length; i++) {
        // 将图片从上传序列移除
        this.uploader.removeFile(this.uploadFileList);
        // 将图片从缩略图容器移除
        var $li = $("#" + this.uploadFileList.id);
        $li.off().remove();
      }

      // 重置文件总个数和总大小
      this.fileCount = 0;
      this.fileSize = 0;
      // 重置uploader,目前只重置了文件队列
      this.uploader.reset();
    },
    /**
     *  生成进度条封装方法
     * @param file 文件
     * @param percentage 进度值
     * @param id_Prefix id前缀
     * @param titleName 标题名
     */
    getProgressBar(file, percentage, id_Prefix, titleName) {
      var $li = $("#" + file.id),
        $percent = $li.find("#" + id_Prefix + "-progress-bar");
      // 避免重复创建
      if (!$percent.length) {
        $percent = $(
          '<div id="' +
            id_Prefix +
            '-progress" class="progress progress-striped active">' +
            '<div id="' +
            id_Prefix +
            '-progress-bar" class="progress-bar" role="progressbar" style="width: 0%">' +
            "</div>" +
            "</div>",
        )
          .appendTo($li)
          .find("#" + id_Prefix + "-progress-bar");
      }
      var progressPercentage = Math.round(percentage * 100) + "%";
      $percent.css("width", progressPercentage);
      $percent.html(titleName + ":" + progressPercentage);
    },

    /**
     * 隐藏进度条
     * @param file 文件对象
     * @param id_Prefix id前缀
     */
    fadeOutProgress(file, id_Prefix) {
      $("#" + file.id)
        .find("#" + id_Prefix + "-progress")
        .fadeOut();
    },
    showProgress(file, id_Prefix) {
      $("#" + file.id)
        .find("#" + id_Prefix + "-progress")
        .show();
    },
    //获取csv内容
    getCSV(file, ext, id) {
      // var _this = this;
      var sum = 0;
      if (ext === "csv" || ext === "CSV") {
        if (file) {
          var reader = new FileReader();
          if (typeof FileReader == "undefined") {
            this.$message({
              message: "你的浏览器暂不支持该功能",
              type: "warning",
            });
            return false;
          }
          reader.readAsText(file, "utf-8");
          reader.onload = function () {
            var relArr = this.result.split("\n");
            if (!$.isEmptyObject(relArr) && relArr.length > 1) {
              for (var key = 0; key < relArr.length; key++) {
                var values = relArr[key];
                if (!$.isEmptyObject(values)) {
                  sum++;
                }
              }
            }
            console.log("csv----->" + (sum - 1));

            $("#" + id).attr("data-num", sum - 1);
          };
        }
      } else if (ext === "xlsx" || ext === "XLSX" || ext === "xls") {
        var fileReader = new FileReader();
        fileReader.onload = function (ev) {
          try {
            var data = ev.target.result,
              workbook = XLSX.read(data, {
                type: "binary",
              }); // 以二进制流方式读取得到整份excel表格对象
          } catch (e) {
            this.$message({
              message: "文件类型不正确",
              type: "warning",
            });
            return;
          }

          // 表格的表格范围,可用于判断表头是否数量是否正确

          var fromTo = null;
          // 遍历每张表读取
          for (var sheet in workbook.Sheets) {
            // eslint-disable-next-line no-prototype-builtins
            if (workbook.Sheets.hasOwnProperty(sheet)) {
              fromTo = workbook.Sheets[sheet]["!ref"];
              sum = XLSX.utils.sheet_to_json(workbook.Sheets[sheet]).length;
              console.log("excel-----> " + sum);

              $("#" + id).attr("data-num", sum);
              break; // 如果只取第一张表,就取消注释这行
            }
          }
          console.log(fromTo);
        };
        // 以二进制方式打开文件
        fileReader.readAsBinaryString(file);
      }
    },
    //检查文件名称是否重复
    checkFileName(callback, callback2) {
      var url = "/xx/xxx/xxxx",
        data = {},
        _this = this;

      data.fileName = _this.fileName;
      axios({
        method: "post",
        url,
        data: Qs.stringify(data),
        headers: {
          "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        },
      }).then((res) => {
        if (res.data.code == 200 && res.data.data == 0) {
          if (typeof callback == "function") {
            callback();
          }
          if (!_this.isCheckFlag) {
            _this.uploadStart();
          }
          _this.isDisabled = false;
        } else {
          _this.$message({
            message: "文件名重复,请重新选择文件!",
            type: "error",
          });
          _this.isDisabled = true;
          if (typeof callback2 == "function") {
            callback2();
          }
          return false;
        }
      });
    },
    //开始上传调用后端接口
    uploadStart() {
      var url = "/xxx/xxx/start",
        data = {},
        _this = this;

      data.fileName = _this.fileName;
      data.fileType = _this.uploadType;
      data.dirFlag = 2; //文件夹标识:1,文件夹;2,文件
      data.extensionName = _this.uploadCheckType;
      axios({
        method: "post",
        url,
        data: Qs.stringify(data),
        headers: {
          "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        },
      }).then((res) => {
        if (res.data.code == 200) {
          _this.id = res.data.data;
          _this.isCheckFlag = true;
        } else {
          _this.$message({
            message: res.data.msg,
            type: "error",
          });
        }
      });
      // utils.promise(data, url, "post", "isAsync").done(function (res) {
      //   if (res.code == 200) {
      //     _this.id = res.data;
      //     _this.isCheckFlag = true;
      //   } else {
      //     _this.$message({
      //       message: res.msg,
      //       type: "error",
      //     });
      //   }
      // });
    },
    //上传完成
    uploadComplete(ossKey, md5, fileId, uploadId) {
      var url = "/xxx/xxx/uploadComplete",
        data = {},
        _this = this;

      data.id = _this.id;
      data.osskey = ossKey;
      data.fileSize = _this.fileSize;
      data.uploadStatus = _this.uploadStatus;
      data.md5 = md5;
      data.materialAmount = $("#" + fileId).attr("data-num");
      data.uploadId = uploadId;
      axios({
        method: "post",
        url,
        data: Qs.stringify(data),
        headers: {
          "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        },
      }).then((res) => {
        console.log(res,"res====");
        if (res.data.code == 200) {
          _this.$message({
            message: res.data.msg,
            type: "success",
          });
          //清除文件列表页面页码缓存
          sessionStorage.removeItem("/dataManage/data_lists/pageNo");
          sessionStorage.removeItem("/dataManage/data_lists/pageSize");
          setTimeout(() => {
            window.location.href = `${document.referrer}dataManage/data_lists#data`;
          }, 1000);
        } else {
          _this.$message({
            message: res.data.msg,
            type: "error",
          });
          //清除文件列表页面页码缓存
          sessionStorage.removeItem("/dataManage/data_lists/pageNo");
          sessionStorage.removeItem("/dataManage/data_lists/pageSize");
          setTimeout(() => {
            window.location.href = `${document.referrer}dataManage/data_lists#data`;
          }, 1000);
        }
      });
      // utils.promise(data, url, "post").done(function (res) {
      //   if (res.code == 200) {
      //     _this.$message({
      //       message: res.msg,
      //       type: "success",
      //     });
      //   } else {
      //     _this.$message({
      //       message: res.msg,
      //       type: "error",
      //     });
      //   }
      // });
    },
  },
};
</script>

css部分

<style lang="scss">
@import "../assets/scss/resetElement.css";

.uploadFile {
  .removeBtn {
    display: none;
  }
  .loanManagement_content {
    margin: 20px;
  }
  .data-content {
    width: 1200px;
    margin: 0 auto;
    min-height: 700px;
    overflow: auto;
    background: #fff;
    position: relative;
  }
  .data-lists-content {
    width: 100% !important;
    padding: 30px !important;
    margin-left: 0 !important;
  }
  .mb20 {
    margin-bottom: 20px;
  }
  .mb35 {
    margin-bottom: 35px;
  }
  .upload-file-flex {
    display: flex;
    align-items: center;
    justify-content: start;
  }

  .upload-file-flex i {
    flex: 0 0 100px;
    font-style: normal;
  }

  .el-upload-list {
    width: 500px;
  }

  .el-progress-bar__outer {
    height: 6px !important;
  }

  .el-upload-list__item .el-icon-upload-success {
    font-size: 18px;
  }

  .el-upload-list__item-status-label {
    top: 3px !important;
  }

  .btns .webuploader-pick {
    display: inline-block;
    padding: 8px 15px;
    font-size: 12px;
    vertical-align: middle;
    background: #ffffff;
    border: 1px solid #dcdfe6;
    color: #606266;
  }

  .uploader-list .item {
    overflow: hidden;
  }
  .uploader-list .item .info {
    float: left;
    margin-right: 20px;
    font-weight: normal;
    font-size: 14px;
  }
  .uploader-list .item .state {
    float: left;
    margin-right: 20px;
    color: #aaa;
  }
  .uploader-list .item .remove-btn {
    vertical-align: middle;
    cursor: pointer;
  }
}
</style>

 

posted on 2022-04-20 10:04  码农小小海  阅读(367)  评论(0编辑  收藏  举报

导航