<template>
  <el-button plain size="small" @click="internalVisible = true">
    导出数据
  </el-button>
  <el-dialog
    v-model="internalVisible"
    center
    :close-on-click-modal="false"
    destroy-on-close
    :title="dialogTitle"
    width="480px"
    :before-close="handleClose"
  >
    <el-form ref="formRef" :model="form" :rules="rules" @submit.prevent>
      <el-row justify="center">
        <el-form-item prop="startPage">
          <el-input
            v-model="form.startPage"
            placeholder="请输入开始页码"
            clearable
            style="max-width: 120px"
            @keyup.enter="handleExport"
          />
        </el-form-item>

        <span style="margin: 5px 10px 0">至</span>

        <el-form-item prop="endPage">
          <el-input
            v-model="form.endPage"
            placeholder="请输入结束页码"
            clearable
            style="max-width: 120px"
            @keyup.enter="handleExport"
          />
        </el-form-item>
      </el-row>
    </el-form>

    <template #footer>
      <div class="dialog-footer">
        <el-button @click="handleClose">取消</el-button>
        <el-button type="primary" :loading="loading" @click="handleExport">
          导出
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { ref, reactive, computed } from "vue";
import type { FormInstance, FormRules } from "element-plus";
import { ElMessage } from "element-plus";
import dayjs from "dayjs";

import { http } from "@/utils/http";

// 定义接口
interface ExportForm {
  startPage: any;
  endPage: any;
}

// Props 定义
const props = withDefaults(
  defineProps<{
    title?: string;
    url: string;
    fileName: string;
    queryParams?: any;
    likeTable?: boolean;
  }>(),
  {
    title: "导出数据",
    likeTable: false
  }
);

// 响应式数据
const internalVisible = ref(false);
const loading = ref(false);
const formRef = ref<FormInstance>();

// 计算属性
const dialogTitle = computed(() => props.title);

// 表单数据
const form = reactive<ExportForm>({
  startPage: "1",
  endPage: "10"
});

/**
 * @description 从1开始正整数校验
 * @param val
 * @returns {boolean}
 */
const isNumbAvailable = (val: any): boolean => {
  let nubReg = /^[1-9]\d*$/;
  return nubReg.test(val);
};

// 自定义验证函数
const validatePageNumber = (rule: any, value: string, callback: any) => {
  if (!value) {
    callback(new Error("请输入页码"));
    return;
  }

  if (!isNumbAvailable(value)) {
    callback(new Error("请输入有效的正整数"));
    return;
  }

  callback();
};

const validateEndPage = (rule: any, value: string, callback: any) => {
  if (!value) {
    callback(new Error("请输入结束页码"));
    return;
  }

  if (!isNumbAvailable(value)) {
    callback(new Error("请输入有效的正整数"));
    return;
  }

  const startPageNum = parseInt(form.startPage);
  const endPageNum = parseInt(value);

  if (endPageNum < startPageNum) {
    callback(new Error("结束页不能小于开始页"));
    return;
  }

  callback();
};

// 表单验证规则
const rules = reactive<FormRules<ExportForm>>({
  startPage: [{ validator: validatePageNumber, trigger: "blur" }],
  endPage: [{ validator: validateEndPage, trigger: "blur" }]
});

/**
 * 下载文件
 * @param blob 文件blob对象
 * @param fileName 文件名
 */
const downloadFile = (blob: Blob, fileName: string) => {
  try {
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = fileName;
    link.style.display = "none";
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    window.URL.revokeObjectURL(url);
  } catch (error) {
    console.error("文件下载失败:", error);
    ElMessage.error("文件下载失败");
  }
};

/**
 * 生成文件名
 * @param baseName 基础文件名
 * @param extension 文件扩展名
 * @returns 完整文件名
 */
const generateFileName = (
  baseName: string,
  extension: string = "xlsx"
): string => {
  const timestamp = dayjs().format("YYYYMMDD_HHmmss");
  return `${baseName}_${timestamp}.${extension}`;
};

// 关闭对话框
const handleClose = () => {
  internalVisible.value = false;
  resetForm();
};

// 重置表单
const resetForm = () => {
  if (formRef.value) {
    formRef.value.resetFields();
  }
  form.startPage = "1";
  form.endPage = "10";
  loading.value = false;
};

const calculateNum = (param: any) => {
  if (!param.pageSize) {
    param.pageSize = 10;
    return true;
  }
  if (param.startPage < 0) {
    ElMessage.warning("行数必须大于0");
    return false;
  }
  if (Number(param.startPage) > Number(param.endPage)) {
    ElMessage.warning("结束行不能小于开始行");
    return false;
  }

  if ((param.endPage - param.startPage) * param.pageSize > 500000) {
    ElMessage.warning("导出行数不能超过5万");
    return false;
  }
  return true;
};

// 处理导出
const handleExport = async () => {
  if (!formRef.value) return;

  try {
    // 验证表单
    await formRef.value.validate();

    loading.value = true;

    let params = { ...props.queryParams };

    if (!props.likeTable) {
      params.endPage = form.endPage;
      params.startPage = form.startPage;
      if (!calculateNum(params)) {
        return;
      }
    } else {
      let rows =
        (form.endPage - form.startPage + 1) * props.queryParams.pageSize;
      params.pageNum = form.startPage;
      params.pageSize = Math.abs(rows);
    }

    if (params.reportDate) {
      // 将param.queryTime转为字符串,隔开
      params.reportDate = params.reportDate.join();
    }

    if (params.multipleDate) {
      params.multipleDate = params.multipleDate.join();
    }

    // 调用导出接口
    const blob = await http.postExport<Blob, any>(props.url, { data: params });

    // 生成文件名
    const fullFileName = generateFileName(props.fileName);

    // 下载文件
    downloadFile(blob, fullFileName);

    // 显示成功消息
    ElMessage.success(`导出成功！文件名：${fullFileName}`);

    // 关闭对话框
    handleClose();
  } catch (error) {
    console.error("导出失败:", error);

    // 根据错误类型显示不同的错误信息
    let errorMessage = "导出失败，请稍后重试";

    if (error?.response) {
      // HTTP错误
      const status = error.response.status;
      switch (status) {
        case 400:
          errorMessage = "请求参数错误";
          break;
        case 401:
          errorMessage = "未授权，请重新登录";
          break;
        case 403:
          errorMessage = "没有导出权限";
          break;
        case 404:
          errorMessage = "导出接口不存在";
          break;
        case 500:
          errorMessage = "服务器内部错误";
          break;
        default:
          errorMessage = `导出失败 (${status})`;
      }
    } else if (error?.code === "NETWORK_ERROR") {
      errorMessage = "网络连接失败，请检查网络";
    } else if (error?.message) {
      errorMessage = error.message;
    }

    ElMessage.error(errorMessage);
  } finally {
    loading.value = false;
  }
};
</script>

<style scoped>
.dialog-footer {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
}

:deep(.el-form-item__label) {
  font-weight: 500;
}

:deep(.el-input__inner) {
  text-align: center;
}
</style>
