<template>
  <div>
    <el-upload class="upload-demo" ref="upload" action="#"
               :before-upload="beforeUpload"
               :on-change="onChange"
               :on-remove="handleRemove"
               :multiple="isMultiple"
               :on-exceed="handleExceed"
               :accept="acceptType"
               :limit="limit"
               :file-list="fileList"
               :auto-upload="true"
               :http-request="uploadFile"
               show-file-list>
      <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
      <el-button size="small" type="primary" @click="handleUploadFile">
        上传文件夹
      </el-button>
      <!--    上传-->
      <input v-show="false" ref="fileRef" id="fileFolder" type="file" @change="handleFolderUpload" webkitdirectory
             multiple="multiple" />

<!--      <input v-show="false" type="file" ref="fileRef" webkitdirectory @change="handleFolderUpload">
      <el-button slot="trigger" size="small" type="primary">选取文件夹</el-button>-->
    </el-upload>
    <div slot="tip" class="el-upload__tip">只能上传{{acceptType}}文件</div>
    <div v-show="progressFlag" class="head-img">
      <el-progress :text-inside="true" :stroke-width="14" :percentage="progressPercent" status="success"></el-progress>
    </div>
  </div>
</template>

<script>
import axios from 'axios'
import {
  getToken
} from "@/utils/auth";
import JSZip from 'jszip'

export default {
  props: {
    uploadUrl: {
      type: String,
      required: true
    },
    // 是否多选
    isMultiple: {
      type: Boolean,
      default() {
        return false
      }
    },
    // 文件类型
    type: {
      type: Array,
      default() {
        return []
      }
    },
    //上传类型
    acceptType: {
      type: String,
      required: true
    },
    // 上传数量
    limit: {
      type: Number,
      default() {
        return 1
      }
    },
    // 文件
    dataFile: {
      type: [Object, Array, String],
      default() {
        return ''
      }
    },
  },
  data() {
    return {
      fileList: [],
      progress: 0,
      isUploading: false,
      progressFlag: false, //进度条初始值隐藏
      progressPercent: 0, //进度条初始值
      partSize: 5 * 1024 * 1024,
    };
  },
  watch: {
    dataFile: {
      handler(newValue, oldValue) {
        if (newValue) {
          this.fileList = Array.isArray(newValue) ? newValue : [newValue]
        } else {
          this.fileList = []
        }
      },
      immediate: true
    }
  },
  methods: {
    // 上传前
    beforeUpload(file) {
      /* const fileType = file.type.toLowerCase()
       console.info("fileType=======", fileType)
       const typeFlag = this.type.some(item => {
         return fileType.indexOf(item) != -1
       })
       if (!typeFlag) {
         this.$message.error('上传类型有误，请重新上传')
         return false
       }*/
    },
    //文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
    onChange(file, fileList) {
      this.fileList = fileList;
    },
    handleRemove(file, fileList) {
      this.fileList = fileList;
    },
    handleExceed(files, fileList) {
      this.$message.warning(
        "最多之能上传"+ this.limit +"个附件"
      );
    },
    async uploadFile({ data, file }) {
      let self = this
      //初始化参数
      if (file.size < this.partSize) {
        let formData = new FormData()
        formData.append("file", file)
        self.progressFlag = true;
        axios({
          url: self.uploadUrl,
          method: 'post',
          data: formData,
          headers: {
            'Authorization': 'Bearer ' + getToken(),
            'Content-Type': 'multipart/form-data'
          },
          onUploadProgress: progressEvent => {
            // progressEvent.loaded:已上传文件大小
            // progressEvent.total:被上传文件的总大小
            //进度条
            self.progressPercent = ((progressEvent.loaded / progressEvent.total) * 100) | 0;
          }
        }).then(res => {
          setTimeout(() => {
            if (res.data.code == 200 && self.progressPercent === 100) {
              setTimeout(function () {
                self.$message({
                  message: '上传成功！',
                  type: 'success',
                  duration: '2000'
                });
                self.progressFlag = false;
                self.progressPercent = 0
                self.handleResult(res,file);
              }, 500);
            } else {
              self.$message({
                message: '上传失败！',
                type: 'error',
                duration: '2000'
              });
            }
          }, 1000);

        }).catch(error => {
          console.error(error)
          self.progressFlag = false;
          self.progressPercent = 0
          self.$refs.upload.clearFiles();
          self.$message({
            message: '上传失败！',
            type: 'error',
            duration: '2000'
          });
        })
      } else {
        file._shardCount = Math.ceil(file.size / this.partSize) //总片数
        file.uploaded = 0
        let formData = new FormData()
        formData.append('fileName', file.name)
        let self = this
        //大文件上传初始化,返回uploadId  initUpload(formData)
        axios({
          url: process.env.VUE_APP_BASE_API + "/common/initUpload",
          method: 'post',
          data: formData,
          headers: {
            'Authorization': 'Bearer ' + getToken(),
            'Content-Type': 'multipart/form-data'
          },
        }).then(function (res) {
          if (res.status == 200) {
            //从第0块开始上传
            file.uploadId = res.data.uploadId
            file.objectKey = res.data
            file.chunkId = 0
            self.uploadByChunk(file)
          } else {
            this.progress--
            self.$message.error(res.msg)
          }
        }).catch(error => {
          self.progressPercent = 0
          self.progressFlag = false;
          console.error(error)
        })
      }

    },
    //分片上传大文件
    uploadByChunk(file) {
      this._start = file.chunkId * this.partSize
      this._end = Math.min(file.size, this._start + this.partSize)//结束时总大小，和 开始的大小+之前的大小比较

      let self = this
      let fileData = file.slice(this._start, this._end)
      //获取文件块MD5
      let reader = new FileReader()
      reader.readAsBinaryString(fileData)
      let form1 = new FormData()//new一个form的实例，可以进行键值对的添加，
      form1.append('chunkFile', fileData) //slice方法用于切出文件的一部分
      form1.append('uploadId', file.uploadId)
      form1.append('chunkId', (file.chunkId + 1).toString())
      form1.append('shardCount', file._shardCount.toString()) //是否最后一片
      self.progressFlag = true;
      //上传大文件的Chunk 返回chunk的MD5 uploadChunk(form1)
      axios({
        url: process.env.VUE_APP_BASE_API + "/common/uploadChunk",
        method: 'post',
        data: form1,
        headers: {
          'Authorization': 'Bearer ' + getToken(),
          'Content-Type': 'multipart/form-data'
        },
        onUploadProgress: progressEvent => {
          // progressEvent.loaded:已上传文件大小
          // progressEvent.total:被上传文件的总大小
          //进度条
          self.progressPercent = ((progressEvent.loaded / progressEvent.total) * 100) | 0;
        }
      }).then(response => {
        if (response.status == 200) {
          //判断返回的MD5值是否一致，一致继续传下一块，否则重传本块（这里目前前后端MD5一直不一致，暂时先注释掉，有时间了我再研究一下）
          // self.md5Str[index] === response.msg ||
          if (true) {
            // this.$message.success('第' + (index + 1).toString() + '块文件上传成功')
            file.uploaded++
            self.percentageSend(file)
            //如果没上传完成，继续上传一下块
            file.chunkId++
            if (file.chunkId < file._shardCount) {
              this.uploadByChunk(file)
            }
          } else {
            //不一致，重新传本块
            this.$message.success('第' + (file.chunkId + 1).toString() + '块文件上传不成功，重新上传')
            this.uploadByChunk(file.chunkId)
          }
        } else {
          //出错，跳出循环显示错误
          this.progress--
          this.$message.error(response.msg)
        }
      })
    },
    //接收上传的百分值回调
    percentageSend(file) {
      let self = this
      let perNum = Math.floor((file.uploaded / file._shardCount) * 100)
      this.progressPercent = perNum
      //如果上传完成，合并文件
      if (perNum === 100) {
        let form2 = new FormData()//new一个form的实例，可以进行键值对的添加，
        form2.append('uploadId', file.uploadId)
        form2.append('fileName', file.name)
        // 大文件上传完成后合并
        // 返回文件访问的URL
        axios({
          url: process.env.VUE_APP_BASE_API + "/common/mergeFile",
          method: 'post',
          data: form2,
          headers: {
            'Authorization': 'Bearer ' + getToken(),
            'Content-Type': 'multipart/form-data'
          },
        }).then(res => {
          if (res.status == 200) {
            setTimeout(function () {
              self.$message({
                message: '上传成功！',
                type: 'success',
                duration: '2000'
              });
              self.progressFlag = false;
              self.progressPercent = 0
              self.handleResult(res,file);
            }, 500);
          } else {
            self.$message({
              message: '上传失败！',
              type: 'error',
              duration: '2000'
            });
          }
        })
      }
    },
    resetData() {
      this.progress = 0;
    },
    handleResult(res, file) {
      let self = this
      const data = {
        fileName: file.name,
        fileSize: file.size,
        fileUrl: res.data.url,
        filePath: res.data.filePath,
        fileOldName: res.data.originalFilename,
        fileNewName: res.data.newFileName,
        suffixType: res.data.suffixType
      }
      console.info("data===========", data)
      self.$emit("handleSuccess", data)
    },
    /** 清空文件 **/
    clearFile(){
      this.$refs.upload.clearFiles();
      this.fileList = []
    },
    handleUploadFile() {
      document.getElementById("fileFolder").value = null;
      this.$refs.fileRef.dispatchEvent(new MouseEvent("click"));
    },
    async handleFolderUpload(event) {
      let self = this;
      const files = event.target.files;
      this.fileslength = files.length;

      // 获取文件夹名称
      let folderName = "";
      if (files.length > 0) {
        let relativePath = files[0].webkitRelativePath;
        folderName = relativePath.split("/")[0];
      }

      const zip = new JSZip();

      // 将文件夹及其内容添加到 ZIP 中
      Array.from(files).forEach(file => {
        zip.file(file.webkitRelativePath, file);
      });

      // 生成 ZIP 文件
      const zipBlob = await zip.generateAsync({ type: "blob" });

      // 创建 FormData 对象
     /* const formData = new FormData();
      formData.append("file", zipBlob, folderName + ".zip");*/
      let formData = new FormData()
      formData.append('fileName', folderName + ".zip")

      // 计算 shardCount
      const _shardCount = Math.ceil(zipBlob.size / this.partSize);
      const fileObj = {
        _shardCount,
        size: zipBlob.size,
        file: zipBlob              // 将 zipBlob 添加到 fileObj 中
      };
      self.$set(fileObj.file, '_shardCount', _shardCount);
      self.$set(fileObj.file, 'uploaded', 0);
      self.$set(fileObj.file, 'name', folderName + ".zip");
      self.fileList.push(fileObj.file)

      if (zipBlob.size < this.partSize) {
        let formDataSign = new FormData()
        formDataSign.append("file", zipBlob, folderName + ".zip")
        self.progressFlag = true;
        axios({
          url: self.uploadUrl,
          method: 'post',
          data: formDataSign,
          headers: {
            'Authorization': 'Bearer ' + getToken(),
            'Content-Type': 'multipart/form-data'
          },
          onUploadProgress: progressEvent => {
            // progressEvent.loaded:已上传文件大小
            // progressEvent.total:被上传文件的总大小
            //进度条
            self.progressPercent = ((progressEvent.loaded / progressEvent.total) * 100) | 0;
          }
        }).then(res => {
          setTimeout(() => {
            if (res.data.code == 200 && self.progressPercent === 100) {
              setTimeout(function () {
                self.$message({
                  message: '上传成功！',
                  type: 'success',
                  duration: '2000'
                });
                self.progressFlag = false;
                self.progressPercent = 0
                self.handleResult(res,fileObj.file);
              }, 500);
            } else {
              self.$message({
                message: '上传失败！',
                type: 'error',
                duration: '2000'
              });
            }
          }, 1000);

        }).catch(error => {
          console.error(error)
          self.progressFlag = false;
          self.progressPercent = 0
          self.$refs.upload.clearFiles();
          self.$message({
            message: '上传失败！',
            type: 'error',
            duration: '2000'
          });
        })
      } else {
        // 初始化上传，获取 uploadId
        axios({
          url: process.env.VUE_APP_BASE_API + "/common/initUpload",
          method: 'post',
          data: formData,
          headers: {
            'Authorization': 'Bearer ' + getToken(),
            'Content-Type': 'multipart/form-data'
          },
        }).then(function (res) {
          if (res.status === 200) {
            self.$set(fileObj.file, 'uploadId', res.data.uploadId);
            self.$set(fileObj.file, 'chunkId', 0);
            self.$set(fileObj.file, 'objectKey', res.data);

            /*//从第0块开始上传
            fileObj.uploadId = res.data.uploadId;
            fileObj.chunkId = 0;
            fileObj.objectKey = res.data*/
            self.uploadByChunk(fileObj.file);
          } else {
            self.progress--;
            self.$message.error(res.msg);
          }
        }).catch(error => {
          self.progressPercent = 0;
          self.progressFlag = false;
          console.error(error);
        });
      }
    },
  }
};
</script>
