<template>
  <el-dialog
    v-model="dialogVisible"
    :title="`导入${title}`"
    :width="500"
    center
    align-center
    :close-on-click-modal="false"
    @closed="closed"
    destroy-on-close
  >
    <div style="height: 300px">
      <el-result
        v-if="importResult"
        :icon="importResult.successNum > 0 ? 'success' : 'error'"
        :title="`导入${importResult.successNum > 0 ? '完成' : '失败'}`"
      >
        <template #sub-title>
          <div class="result-info mt10">
            <div>
              <span class="info-label">成功条数：</span>
              <span class="info-value" style="color: #228fff">{{ importResult.successNum }}</span>
            </div>
            <div>
              <span class="info-label">失败条数：</span>
              <span class="info-value">{{ importResult.failNum }}</span>
              <el-button v-if="failBolb" class="ml40" type="primary" @click="downloadFailedFiles" link>下载失败文件</el-button>
            </div>
          </div>
        </template>
      </el-result>
      <el-upload
        v-else
        ref="uploadRef"
        action="#"
        :limit="1"
        :accept="fileType.map(item => `.${item}`).join(',')"
        :multiple="false"
        :show-file-list="false"
        :http-request="handleHttpUpload"
        :before-upload="beforeUpload"
        :on-success="uploadSuccess"
        :on-error="uploadError"
        :drag="drag"
      >
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        <template #tip>
          <div class="mt10 el-upload__tip flex flex-space-between">
            <span>{{ uploadTip }}</span>
            <el-link
              v-if="tempPath"
              type="primary"
              :underline="false"
              style="font-size: 12px; vertical-align: baseline"
              :href="tempPath"
              :download="title ? `${title}导入模板.xlsx` : undefined"
            >
              下载模板
            </el-link>
          </div>
        </template>
      </el-upload>
    </div>
  </el-dialog>
</template>

<script lang="ts" setup>
import { ref, defineExpose, computed } from "vue";
import { ElNotification, ElMessage } from "element-plus";
import type { UploadProps, UploadRequestOptions } from "element-plus";
import { ResultEnum } from "@/enums/httpEnum";
import { downloadFile } from "@/utils";

interface UploadFileProps {
  title: string; // 标题 ==> 必传
  api: (params: any) => Promise<any>; // 上传文件的 api 方法，一般项目上传都是同一个 api 方法，在组件里直接引入即可 ==> 非必传
  drag?: boolean; // 是否支持拖拽上传 ==> 非必传（默认为 true）
  disabled?: boolean; // 是否禁用上传组件 ==> 非必传（默认为 false）
  fileSize?: number; // 文件大小限制 ==> 非必传（默认为 5M）
  fileType?: string[]; // 文件类型限制 ==> 非必传（默认为 ["image/jpeg", "image/png", "image/gif"]）
  tempPath?: string;
}

// 接受父组件参数
const props = withDefaults(defineProps<UploadFileProps>(), {
  title: "",
  drag: true,
  disabled: false,
  fileSize: 5,
  fileType: () => ["xls", "xlsx"]
});
// computed
const uploadTip = computed(() => {
  let tip = "";
  if (props.fileType.length > 0) {
    tip += `仅允许导入${props.fileType.join("、")}格式文件`;
  }
  if (props.fileSize > 0) {
    tip += `，最大限制${props.fileSize}M`;
  }
  return tip ? `${tip}。` : "";
});
// ref
const uploadRef = ref<any>(null);
const importResult = ref<{ successNum: number; failNum: number } | null>(null);
const failBolb = ref<Blob | null | boolean>(true);
const dialogVisible = ref(false);
const openPromise = ref<any>({});

// 发送上传请求
const handleHttpUpload = async (options: UploadRequestOptions) => {
  let formData = new FormData();
  formData.append("file", options.file);
  try {
    const res = await props.api(formData);
    if (res.data instanceof Blob) {
      if (res.data.type.includes("application/json")) {
        const resJsonStr = await res.data.text();
        const resJson = JSON.parse(resJsonStr);
        if (resJson.code !== ResultEnum.SUCCESS) {
          ElMessage.error(resJson.msg);
          options.onError(resJson.msg);
          return;
        }
        importResult.value = {
          successNum: resJson.data.successNum,
          failNum: 0
        };
        failBolb.value = null;
      } else {
        console.log(999, res.headers);
        importResult.value = {
          successNum: res.headers["success_num"],
          failNum: res.headers["fail_num"]
        };
        failBolb.value = res.data;
      }
      if (importResult.value && importResult.value.successNum > 0) {
        openPromise.value.resolve();
      }
    }
  } catch (error) {
    options.onError(error as any);
  }
};

/**
 * @description 文件上传之前判断
 * @param rawFile 选择的文件
 * */
const beforeUpload: UploadProps["beforeUpload"] = rawFile => {
  const fileSize = rawFile.size / 1024 / 1024 < props.fileSize;
  const fileType = props.fileType.some(type => rawFile.name.endsWith(`.${type}`));
  if (!fileType) {
    ElNotification({
      title: "温馨提示",
      message: "上传文件不符合所需的格式！",
      type: "warning"
    });
    return false;
  }

  if (!fileSize) {
    ElNotification({
      title: "温馨提示",
      message: `上传文件大小不能超过 ${props.fileSize}M！`,
      type: "warning"
    });
    return false;
  }
  return true;
};

/**
 * @description 导出失败文件
 * */
const downloadFailedFiles = () => {
  downloadFile(failBolb.value as Blob, `导入${props.title}失败文件_${Date.now()}.xlsx`);
};

/**
 * @description 上传成功
 * */
const uploadSuccess = () => {
  console.log(11);
};

/**
 * @description 文件上传错误
 * */
const uploadError = () => {
  uploadRef.value.clearFiles();
  ElNotification({
    title: "温馨提示",
    message: "上传失败，请您重新上传！",
    type: "error"
  });
};

// 弹窗关闭
function closed() {
  importResult.value = null;
  failBolb.value = null;
}

function open() {
  dialogVisible.value = true;
  return new Promise(resolve => {
    openPromise.value.resolve = resolve;
  });
}
defineExpose({
  open
});
</script>

<style lang="scss" scoped>
.result-info {
  text-align: left;
}
.info-label {
  font-size: 20px;
  color: #333333;
}
.info-value {
  font-size: 22px;
  font-weight: bold;
  color: var(--el-color-error);
}
</style>
