<template>
  <el-dialog
    :class="prefixCls"
    :visible.sync="modalIsShow"
    :title="title"
    top="10vh"
    width="500px"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    append-to-body
    @opened="visibleChange"
  >
    <div :class="[`${prefixCls}-footer`]" v-if="downloadUrl">
      模板下载：
      <a :href="downloadUrl" :download="dfilename">{{ dfilename }}</a>
    </div>
    <div :class="[`${prefixCls}-footer`]" v-else-if="downloadHandle">
      模板下载：
      <el-button type="text" @click="downloadHandle">{{ dfilename }}</el-button>
    </div>
    <slot></slot>
    <div :class="[`${prefixCls}-body`]">
      <el-upload
        drag
        :action="uploadUrl"
        :headers="headers"
        :max-size="maxSize"
        :format="format"
        :accept="accept"
        :data="uploadDataDict"
        :before-upload="handleBeforeUpload"
        :on-error="handleError"
        :on-success="handleSuccess"
        :http-request="upload"
        :disabled="disabled || loading"
        :auto-upload="autoUpload"
        :show-file-list="true"
        :file-list="fileList"
        :on-change="handleFileChange"
        :on-remove="handleFileRemove"
        ref="UploadComp"
      >
        <i class="el-icon-upload"></i><br />
        <em class="el-upload__text">点击或将文件拖拽到这里上传</em>
        <p
          slot="tip"
          :class="[
            `${prefixCls}-tips`,
            {
              'cc-tips-success': res.success,
              'cc-tips-error': !res.success,
            },
          ]"
          v-if="res.message"
        >
          {{ res.message }}
        </p>
      </el-upload>
    </div>
    <slot name="bodyfoot"></slot>

    <div v-if="!autoUpload" slot="footer">
      <el-button
        type="primary"
        :disabled="loading || !canUpload"
        @click="submit"
        >确认</el-button
      >
      <el-button @click="cancel">取消</el-button>
    </div>
  </el-dialog>
</template>

<script>
/**
 * auto-upload为false时，手动调用ElUpload.Submit时会触发before-upload-handle
 */
import { fileMD5 } from "@/plugins/md5";
import { $post } from "@/plugins/axios";

const prefixCls = "cc-import-file";

export default {
  name: "import-file",
  props: {
    title: {
      type: String,
      default: "文件上传",
    },
    downloadHandle: {
      type: Function,
    },
    downloadUrl: {
      type: String,
      default: "",
    },
    downloadFilename: String,
    format: {
      type: Array,
      default() {
        return ["jpg", "jpeg", "png"];
      },
    },
    uploadUrl: {
      type: String,
      required: true,
    },
    uploadData: {
      type: Object,
      default() {
        return {};
      },
    },
    maxSize: {
      type: Number,
      default: 20 * 1024 * 1024,
    },
    addFilenameParam: {
      type: String,
      default: "filename",
    },
    autoUpload: {
      type: Boolean,
      default: true,
    },
    disabled: { type: Boolean, default: false },
    beforeSubmitHandle: {
      type: Function,
      default: null,
    },
  },
  data() {
    return {
      prefixCls,
      modalIsShow: false,
      headers: {
        md5: "",
      },
      selectFileName: "",
      loading: false,
      uploadDataDict: {},
      res: {
        success: true,
        message: "",
      },
      fileList: [],
    };
  },
  computed: {
    dfilename() {
      return this.downloadFilename || this.downloadUrl.split("/").pop();
    },
    accept() {
      return this.format.map((el) => `.${el}`).join();
    },
    canUpload() {
      return this.fileList.length > 0;
    },
  },
  methods: {
    visibleChange() {
      this.res = {
        success: true,
        message: "",
      };
      this.headers = { md5: "" };
      this.loading = false;
      this.uploadDataDict = {};
      this.$refs.UploadComp.clearFiles();
    },
    checkFileFormat(fileType) {
      const _file_format = fileType.split(".").pop().toLocaleLowerCase();
      return this.format.length
        ? this.format.some((item) => item.toLocaleLowerCase() === _file_format)
        : true;
    },
    handleFileChange(file) {
      if (file.status === "ready") {
        this.res = {
          success: true,
          message: "",
        };
      }

      this.fileList = [file];
    },
    handleFileRemove(file, fileList) {
      this.fileList = fileList;
    },
    async handleBeforeUpload(file) {
      this.uploadDataDict = {
        ...this.uploadData,
      };
      this.uploadDataDict[this.addFilenameParam] = file.name;

      if (file.size > this.maxSize) {
        this.handleExceededSize();
        return Promise.reject();
      }
      if (!this.checkFileFormat(file.name)) {
        this.handleFormatError();
        return Promise.reject();
      }

      const md5 = await fileMD5(file);
      this.headers["md5"] = md5;
      this.loading = true;

      return true;
    },
    upload(options) {
      let formData = new FormData();
      Object.entries(options.data).forEach(([k, v]) => {
        formData.append(k, v);
      });
      formData.append("file", options.file);
      this.$emit("uploading");

      return $post(options.action, formData, { headers: options.headers });
    },
    handleError(error) {
      this.loading = false;
      this.res = {
        success: false,
        message: error.message,
      };
      this.$emit("upload-error", error);
    },
    handleSuccess(responseData) {
      this.loading = false;
      this.res = {
        success: true,
        message: "导入成功！",
      };
      this.cancel();
      this.$emit("upload-success", {
        data: responseData,
        filename: this.uploadDataDict[this.addFilenameParam],
      });
    },
    handleFormatError() {
      const content = "只支持文件格式为" + this.format.join("/");
      this.res = {
        success: false,
        message: content,
      };
      this.$emit("valid-error", this.res);
      this.$refs.UploadComp.clearFiles();
    },
    handleExceededSize() {
      this.res = {
        success: false,
        message:
          "文件大小不能超过" + Math.floor(this.maxSize / (1024 * 1024)) + "M",
      };
      this.$emit("valid-error", this.res);
      this.$refs.UploadComp.clearFiles();
    },
    cancel() {
      this.modalIsShow = false;
    },
    open() {
      this.modalIsShow = true;
    },
    async submit() {
      if (this.beforeSubmitHandle) {
        let handleResult = true;
        await Promise.resolve(this.beforeSubmitHandle()).catch(() => {
          handleResult = false;
        });
        if (!handleResult) return;
      }
      this.$refs.UploadComp.submit();
    },
  },
};
</script>
