<template>
  <div class="uploadWrapper">
    <div class="btnUpload">
      <div id="picker" class="form-control-focus">点击选择文件上传</div>
    </div>
    <div id="thelist" class="uploader-list">
      <ul>
        <li v-for="(item, index) in  fileList ">
          <a @click="removeFile(item, index)"><span title="点击移除">{{ item.name }}</span></a>
          <span
            :class="[item.state == 1 ? 'el-icon-loading' : item.state == 2 ? 'el-icon-success' : item.state == 3 ? 'el-icon-warning' : '']">{{
              item.description }}</span>
          <a @click="retry(item, index)" v-if="item.state == 3"><span title="点击重试"
              class="el-icon-refresh-right"></span></a>
          <el-progress :text-inside="true" :stroke-width="14" :percentage="item.percentage"
            status="success"></el-progress>
        </li>
      </ul>
    </div>
    <el-button class="startUpload" type="primary" @click="upload()">开始上传</el-button>
  </div>
</template>
<script>
import $ from "jquery";
import WebUploader from "webuploader";
import "webuploader/dist/webuploader.css";
import { ACCESS_TOKEN, ACCESS_USER, HTTP_STATUS } from "../../constant/user";
export default {
  props: {
    addFileInfo: {
      type: Function
    },
    checkFileExist: {
      type: Function
    }
  },
  data() {
    return {
      fileList: [],
      headers: { 'x-requested-with': 'XMLHttpRequest' }
    };
  },
  mounted() {
    this.headers[ACCESS_TOKEN] = sessionStorage.getItem("token");
    var _self = this;
    //必须先注销原来的，否则服务会执行多次
    WebUploader.Uploader.unRegister("uploadBigFile");
    //监听分块上存过程中的三个时间点
    WebUploader.Uploader.register(
      {
        "name": "uploadBigFile",
        // 在文件发送之前执行
        "before-send-file": "beforeSendFile",
        // 在文件分片（如果没有启用分片，整个文件被当成一个分片）后，上传之前执行
        "before-send": "beforeSend",
        // 在文件所有分片都上传完后，且服务端没有错误返回后执行
        "after-send-file": "afterSendFile",
      },
      {
        //时间点1:所有分块进行上存之前触发该方法,即当每个文件开始上传第一个分块前就调用该方法
        beforeSendFile: function (file) {
          //定义一个异步对象
          var deferred = WebUploader.Deferred();
          uploader
            .md5File(file, 0, 3 * 1024 * 1024)
            .progress((percentage) => {
              _self.getProgressBar(file, percentage);
            })
            .then((val) => {
              file.md5 = val;
              file.uid = WebUploader.Base.guid();
              Promise.resolve()
                .then(res => {
                  if (_self.checkFileExist) {
                    return _self.checkFileExist(val);
                  } else {
                    return Promise.resolve(false);
                  }
                }).then(res => {
                  if (res) {
                    return Promise.reject({ message: "文件已存在" });
                  } else {
                    return _self.post(`api/rest/file/bigFile/check?fileMd5=${val}`);
                  }
                }).then(res => {
                  //  文件已经上传过,忽略上传过程，直接标识上传成功；
                  if (res) {
                    uploader.skipFile(file);
                    file.pass = true;
                    _self.getProgressBar(file, 1);
                  } else {
                    //文件没有上传过，下标为0 文件上传中断过，返回当前已经上传到的下标
                    file.indexcode = 0;
                  }
                  deferred.resolve();
                }).catch(err => {
                  deferred.reject(err.message);//触发error事件
                });
            });
          return deferred.promise();
        },
        //时间点2：如果有分块上传，则每个分块上传之前调用此函数
        //用于文件的续传
        beforeSend: function (block) {
          var indexchunk = block.file.indexcode;
          var deferred = WebUploader.Deferred();
          if (indexchunk > 0) {
            if (block.chunk > indexchunk) {
              //分块不存在，重新发送该分块内容
              deferred.resolve();
            } else {
              //分块存在，跳过
              deferred.reject();
            }
          } else {
            //分块不存在，重新发送该分块内容
            deferred.resolve();
          }
          //返回Deferred的Promise对象。
          return deferred.promise();
        },
        //时间点3:一个文件的所有分片上传成功后，调用该方法,让后台合并所有分片
        //该方法的在uploader.on("success")方法前执行。
        afterSendFile: function (file) {
          var deferred = WebUploader.Deferred();
          Promise.resolve(file.pass)
            .then(res => {
              if (res) {
                return Promise.resolve();
              } else {
                return _self.post(`api/rest/file/bigFile/merge?fileName=${encodeURIComponent(file.name)}&fileMd5=${file.md5}`);
              }
            })
            .then(res => {
              if (_self.addFileInfo) {
                return _self.addFileInfo({
                  md5: file.md5,
                  file: {
                    name: file.name,
                    size: file.size,
                    type: file.ext,
                    uuid: file.uid + "." + file.ext,
                  }
                });
              } else {
                return Promise.resolve(res);
              }
            }).then(res => {
              deferred.resolve();
            }).catch(err => {
              deferred.reject(err.message);
            });
          return deferred.promise();
        },
      }
    );
    //创建实例
    var uploader = WebUploader.create({
      accept: {
        extensions: "pdf,doc,ppt,pptx,xls,xlsx,docx,txt,flv,mp4,avi,mvb,rmvb,rm",
        mimeTypes: ".pdf,.doc,.ppt,.pptx,.xls,.xlsx,.docx,.txt,.flv,.mp4,.avi,.mvb,.rmvb,.rm"
      },
      pick: {
        id: '#picker',
        label: '点击选择文件'
      },
      duplicate: true,//去重， 根据文件名字、文件大小和最后修改时间来生成hash Key
      swf: 'WebUploader/uploader.swf',
      chunked: true,
      chunkSize: 10 * 1024 * 1024, // 10M 每个分片的大小限制
      threads: 3,
      server: 'api/rest/file/bigFile/part',
      // auto: true,
      // 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候，把图片打开。
      disableGlobalDnd: true,
      fileNumLimit: 1024,
      fileSizeLimit: 50 * 1024 * 1024 * 1024,//50G 验证文件总大小是否超出限制, 超出则不允许加入队列
      fileSingleSizeLimit: 10 * 1024 * 1024 * 1024 //10G 验证单个文件大小是否超出限制, 超出则不允许加入队列
    });
    /**
     * 当某个文件的分块在发送前触发，主要用来询问是否要添加附带参数，大文件在开起分片上传的前提下此事件可能会触发多次。
     */
    uploader.onUploadBeforeSend = function (obj, data, headers) {
      //增加请求参数
      var file = obj.file;
      data.md5 = file.md5 || "";
      data.uid = file.uid;
      //增加请求token
      $.extend(headers, _self.headers);
    };
    // 当有文件被添加进队列的时候触发
    uploader.on("fileQueued", function (file) {
      _self.fileList.push({ name: file.name, id: file.id, percentage: 0, state: 0 });
    });
    //单个文件开始上传
    uploader.on("uploadStart", (file) => {
      _self.fileList.filter(e => e.id == file.id)[0].state = 1;
      console.log("uploadStart");
    });
    /**
     * 上传过程中，一直会执行该方法
     */
    uploader.on("uploadProgress", function (file, percentage) {
      _self.getProgressBar(file, percentage);
    });
    /**
     * 文件上传成功后，就在该文件对应的位置上，显示上传成功，file.id,作为上传文件位置标签的id,
     */
    uploader.on("uploadSuccess", (file, response) => {
      _self.fileList.filter(e => e.id == file.id)[0].state = 2;
      _self.fileList.filter(e => e.id == file.id)[0].percentage = 100;
      console.log("uploadSuccess");
    });
    /**
     * 发生错误时
     */
    uploader.on("uploadError", function (file, reason) {
      _self.fileList.filter(e => e.id == file.id)[0].state = 3;
      _self.fileList.filter(e => e.id == file.id)[0].description = reason;
      console.log("uploadError");
    });
    /**
     * 不管所有分片发送成功或者失败都会执行该方法
     */
    uploader.on("uploadComplete", function (file) {
      console.log("uploadComplete");
    });
    //所有文件上传结束
    uploader.on("uploadFinished", () => {
      _self.$emit("Finished", {});
      console.log("uploadFinished");
    });
    //设置全局变量
    this.uploader = uploader;
  },
  methods: {
    upload() {
      this.uploader.upload();
    },
    removeFile(item, index) {
      if (item.state == 1) {//上传中的文件无法删除
        return;
      }
      this.uploader.removeFile(item.id);
      this.fileList.splice(index, 1);
    },
    retry(item, index) {
      item.description = "";
      this.uploader.retry(this.fileList.filter(e => e.id == item.id)[0].id);
    },
    getProgressBar(file, percentage) {
      let item = this.fileList.find(e => e.id == file.id);
      //在分片合并之后在设置进度百分之百
      item && (item.percentage = percentage == 1 ? 99.9 : Math.floor(percentage * 100 * 100) / 100);
    },
    post(url) {
      return new Promise((resolve, reject) => {
        fetch(url, {
          method: "POST",
          headers: new Headers(this.headers)
        }).then(res => {
          if (res.status == 200) {
            return res.text();
          } else {
            console.log(res.statusText);
            reject(HTTP_STATUS);
          }
        }).then(res => {
          let result = JSON.parse(res);
          if (result.code == 9000) {
            resolve(result.data);
          } else {
            console.log(result);
            reject(result);
          }
        }).catch(err => reject(err));
      })
    }
  },
};
</script>
<style lang="scss" scope>
.uploadWrapper {
  height: 524px;
}

#picker>div:nth-child(2) {
  width: 126px !important;
  height: 40px !important;
}

.btnUpload {
  height: 50px;
}

#thelist {
  height: auto;
  overflow-y: auto;
  max-height: calc(100% - 130px);
}

#thelist a {
  // text-decoration: underline;
  cursor: pointer;
  font-size: 16px;
  color: white;
}

#thelist li {
  /* 去掉li前面的小圆点 */
  list-style: none;
  margin: 10px 0px;

  .el-progress {
    width: 95%;
    margin-top: 3px;

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

.startUpload {
  margin-top: 5px;
}

.el-icon-loading {
  color: white;
}

.el-icon-warning {
  color: red;
  font-size: 11px;
}

.el-icon-success {
  color: green
}
</style>
