<template>
  <el-dialog
    :visible="visible"
    width="40%"
    style="height: 98%"
    :before-close="handleClose"
    top="5vh"
    lock-scroll
  >
    <div class="title" slot="title">
      <div class="divider"></div>
      <span class="label"> 上传文件</span>
      <span class="tips">
        <i class="el-icon-info"></i
        >提示：上传过程中请勿关闭此弹窗或刷新页面等操作
      </span>
    </div>
    <el-form
      :model="form"
      ref="form"
      :rules="rules"
      size="mini"
      label-width="80px"
    >
      <el-form-item label="标题" prop="uploadTitle">
        <el-input
          placeholder="请输入标题（必填）"
          v-model="form.uploadTitle"
          :disabled="isDisabledTitle"
        ></el-input>
      </el-form-item>
      <el-form-item label="文件">
        <el-upload
          ref="upload"
          class="upload-area"
          name="zipFile"
          action="#"
          :accept="fileType"
          :on-success="handleSuccess"
          :on-change="handleChange"
          :auto-upload="false"
          drag
        >
          <i class="el-icon-upload"></i>
          <div class="el-upload__text">
            将文件拖到此处，或<em>点击上传</em>, 只能上传{{
              fileType
            }}文件，一次只能传一个文件
          </div>
        </el-upload>
      </el-form-item>
      <el-form-item>
        <el-button size="mini" type="primary" @click="handleUpload"
          >确定上传</el-button
        >

        <el-button type="primary" size="mini" plain @click.native="handleClose"
          >关闭</el-button
        >
      </el-form-item>
    </el-form>

    <el-card
      class="upload-progress"
      shadow="never"
      v-if="displayList.length > 0"
    >
      <h3>上传列表</h3>
      <el-table :data="displayList" fit>
        <el-table-column prop="name" label="标题"> </el-table-column>
        <el-table-column prop="size" label="文件大小">
          <template slot-scope="scope">
            {{ getSize(scope.row.size) }}
          </template>
        </el-table-column>
        <el-table-column prop="progress" label="进度" width="300">
          <template slot-scope="scope">
            <el-progress
              :percentage="scope.row.percent"
              v-if="!isNaN(parseInt(scope.row.percent))"
              :status="scope.row.status"
              :text-inside="true"
              :stroke-width="16"
            ></el-progress>
          </template>
        </el-table-column>
        <el-table-column prop="operation" label="操作" width="100">
          <template slot-scope="scope">
            <el-button
              type="text"
              size="mini"
              @click.native="handleCancel(scope.$index)"
              v-if="scope.row.status == null"
              >取消</el-button
            >
            <!-- <el-button
              type="text"
              size="mini"
              @click.native="handleRestart(scope.$index)"
              v-if="scope.row.status == 'exception'"
              >重新上传</el-button
            > -->
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </el-dialog>
</template>

<script>
import { importZip } from "@/utils/file";
import { getToken } from "@/utils/auth";
export default {
  name: "UploadDialog",
  props: {
    // 抠图上传的对象（包含上传的文件类型、标题）
    options: {
      type: Object,
      default: () => ({
        recordsTitle: "", //上传时的记录标题,非必填
        bizType: "", //业务类型，文物、展览等biz_cultural_relic——文物，biz_exhibition——展览，如果是文物和展览批量上传必填，抠图不用填
        uploadUrl: "", //上传的地址，必填
        flowId: "", //流程ID,重传时需要，非必填
        compressFlag: "", //上传方式：0-单个图片文件；1-zip文件。抠图时需要，非必填
        uploadFileKey: "", //formData中文件的key
        uploadTitleKey: "", //formData中标题的key
      }),
    },
  },
  computed: {
    getSize(size) {
      return (size) => {
        return (size / 1024 / 1024).toFixed(2) + "M"; //1M=1024Kb=1024*1024byte
      };
    },
    fileType() {
      if (!this.options) {
        return;
      }
      if (this.options.compressFlag == 0) {
        return ".jpg,.png,jpeg";
      } else {
        return ".zip";
      }
    },
  },
  data() {
    return {
      dialogVisible: false,
      isUpLoading: false,
      percentState: 0,
      list: {
        records: [],
        current: 1,
        size: 10,
      },
      progressStatus: null,
      visible: false, //控制批量上传弹窗显示
      fileList: [], //上传当中的文件队列
      displayList: [], //用于显示下方的文件队列
      uploadCount: 0, //处于上传中的文件数量，当等于fileList的时候就关闭弹窗，请求完毕一个就++
      cancelUploadArr: [], //保存每个文件上传接口对应的取消请求的函数[fn,fn,fn...]，点叉叉关闭弹窗就遍历这个全部执行一遍就取消了所以请求
      headers: {
        authorization: getToken(),
      },
      form: {
        uploadTitle: "",
      },
      rules: {
        uploadTitle: [
          {
            required: true,
            message: "请输入上传标题",
            trigger: "change",
          },
        ],
      },
      isDisabledTitle: false,
    };
  },
  watch: {
    options: {
      handler(value) {
        if (value.recordsTitle) {
          this.form.uploadTitle = value.recordsTitle;
          this.isDisabledTitle = true;
        }
      },
      deep: true,
      immediate: true,
    },
  },

  methods: {
    // 取消编辑
    cancelForm() {
      this.handleClose();
    },
    // 提交上传
    handleUpload(file) {
      this.$refs.form.validate((valid) => {
        if (valid) {
          if (file && file instanceof File) {
            this.fileList = [file];
          } else {
            this.fileList = this.$refs.upload.uploadFiles;
          }
          // return
          for (let i = 0; i < this.fileList.length; i++) {
            this.uploadSelf(this.fileList[i].raw, i); //弹窗显示的时候，就根据文件队列的数量调用上传接口
          }
        }
      });
    },
    // 保证一次只能传一个，覆盖上一次
    handleChange(file, fileList) {
      if (fileList.length > 1) {
        fileList[0] = fileList[1];
        fileList.splice(1, 1);
      }
    },
    // 获取上传的表单
    getFormData(file) {
      let formData = new FormData();
      const { bizType, flowId, compressFlag, uploadFileKey, uploadTitleKey } =
        this.options;
      const { uploadTitle } = this.form;
      // 业务类型，文物和展览批量上传时需要
      if (bizType) {
        formData.append("type", bizType);
      }
      // 上传方式：0-单个图片文件；1-zip文件，抠图上传时需要
      if (compressFlag == "0" || compressFlag == "1") {
        formData.append("compressFlag", compressFlag);
      }
      // 流程Id
      if (flowId) {
        formData.append("flowId", flowId);
      }
      //文件上传的key
      const fileKey = uploadFileKey || "zipFile";
      const titleKey = uploadTitleKey || "flowTitle";
      formData.append(fileKey, file);
      formData.append(titleKey, uploadTitle);
      return formData;
    },
    // 判断文件是否符合规则校验
    getFileValid(file) {
      const { name } = file;
      const suffix = name.split(".")[1].toLowerCase();
      return suffix && this.fileType.includes(suffix);
    },
    // 上传函数实现逻辑
    uploadSelf(file, index) {
      const isValid = this.getFileValid(file);
      if (!isValid) {
        this.$message.error(`文件格式错误：请上传${this.fileType}格式的文件！`);
        return;
      }
      const loading = this.$loading({
        lock: true,
        text: "正在上传中...文件较大，请耐心等待，请勿刷新页面",
        spinner: "el-icon-loading",
        background: "rgba(0, 0, 0, 0.7)",
      });
      const formData = this.getFormData(file);
      importZip(
        this.options.uploadUrl,
        formData,
        (progressEvent) => this.uploadUnderWayCallback(progressEvent, index),
        (cancelCallback) => this.cancelCallBack(cancelCallback, index)
      )
        .then((res) => {
          loading.close();
          const { code, msg } = res.data;
          let status;
          let desc;
          if (code == 0) {
            status = "success";
            // 上传方式：0-单个图片文件；1-zip文件，抠图上传时需要
            const { compressFlag } = this.options;
            if (compressFlag == "0" || compressFlag == "1") {
              desc = "上传成功！请关闭弹窗并等待系统处理";
            } else {
              desc = "上传成功";
            }
            this.$set(this.fileList[index], "percent", 100);
            this.$message.success(desc);
          } else {
            status = "exception";
            desc = "上传失败" + msg;
            this.$message.error(desc);
          }
          this.$set(this.fileList[index], "status", status);
          this.$set(this.fileList[index], "desc", desc);
          this.$emit("update");
          //  删除已经上传成功的，并向display中新增一条
          this.displayList.push(this.fileList[index]);
          this.fileList.splice(index, 1);
          this.$refs.form.resetFields();
        })
        .catch((err) => {
          loading.close();
          console.log("err", err);
        });
    },

    // 文件上传进度回调
    uploadUnderWayCallback(progressEvent, index) {
      let completeVal =
        (progressEvent.loaded / progressEvent.total) * 100 - 1 || 0; //处理成组件库进度组件需要的格式
      this.$set(this.fileList[index], "percent", Math.floor(completeVal)); //直接改变数组某一项不是响应式的，因此我们需要用到这个api，将其响应式化，添加到数组中
    },

    // 文件取消回调
    cancelCallBack(cancelCallback, index) {
      this.$set(this.cancelUploadArr, index, cancelCallback); //添加取消队列中，关闭弹窗批量取消
      this.uploadCount = 0;
    },
    // 关闭弹窗回调
    handleClose() {
      // 文件列表中如果Status为null，则代表有仍在上传中
      let isUpLoading = false;
      this.fileList.map((item) => {
        if (item.status == null) {
          isUpLoading = true;
          return;
        }
      });
      let title = isUpLoading ? "当前有上传任务，是否取消上传" : "确认关闭？";
      let confirmButtonText = isUpLoading ? "关闭并取消上传" : "确定";
      let cancelButtonText = isUpLoading ? "否" : "取消";
      let that = this;
      this.$confirm(title, "提示", {
        confirmButtonText,
        cancelButtonText,
        type: "warning",
      })
        .then(() => {
          // 点击取消上传
          if (that.isUpLoading) {
            this.handleCancelAllUpLoad();
            this.$message.warning("已取消上传！");
          }
          this.visible = false; //最后关闭
        })
        .catch(() => {
          console.log("用户取消操作");
        });
    },
    // 取消单个上传任务
    handleCancel(index) {
      if (this.cancelUploadArr[index]) {
        this.cancelUploadArr[index](); //取消上传
        this.cancelUploadArr.splice(index, 1); //从取消队列中删除
      }
      if (this.displayList[index]) {
        this.displayList.splice(index, 1);
      }
      this.handleReset();
      this.$message.info("已取消上传！");
    },
    // // 重新上传
    // handleRestart(index) {
    //   // debugger
    //   const { name } = this.displayList[index];
    //   this.form.uploadTitle = name;
    //   this.handleUpload(this.displayList[index]);
    // },

    // 全部取消上传
    handleCancelAllUpLoad() {
      this.cancelUploadArr.forEach((cancelCallBack) => cancelCallBack()); //批量取消上传
    },
    // 上传成功的回调
    handleSuccess(res) {
      res.Success && this.$Message.success("上传成功"); //提示
      this.fileList = [];
    },
    // 恢复初始值
    handleReset() {
      this.fileList = [];
      this.uploadCount = 0;
      this.cancelUploadArr = [];
    },
  },
};
</script>

<style lang="scss" scoped>
.title {
  display: flex;
  align-items: center;
  .divider {
    width: 8px;
    height: 16px;
    border-left: 4px solid #409eff;
    margin-right: 8px;
  }
  .label {
    font-weight: bold;
  }
  .tips {
    font-size: 14px;
    color: #666;
    margin-left: 10px;
  }
}
.upload-area {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  margin-bottom: 30px;
  ::v-deep .el-upload,
  ::v-deep .el-upload-dragger {
    width: 100%;
  }
}
.upload-progress {
  margin-bottom: 30px;
}
.upload-records {
  margin-bottom: 30px;
}
.dialog-footer {
  margin-top: 30px;
  display: flex;
  justify-content: flex-end;
}
.el-dialog__body {
  padding: 0 20px 30px 20px;
}
::v-deep .el-upload-list {
  display: flex;
  justify-content: flex-start;
  width: 100%;
}
</style>
