<template>
  <div>
    <!-- 导入数据 -->
    <el-dialog v-model="upload.open" :title="upload.title" append-to-body width="400px">
      <el-upload
        ref="uploadRef"
        v-model:file-list="uploadFile"
        :action="upload.url"
        :auto-upload="false"
        :disabled="upload.isUploading || uploadHasFailed"
        :headers="upload.headers"
        :limit="1"
        accept=".xlsx, .xls"
        drag
        @change="handleFileChange"
      >
        <el-icon class="el-icon--upload">
          <i-ep-upload-filled />
        </el-icon>
        <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        <template #tip>
          <div class="text-center el-upload__tip">
            <span>仅允许导入xls、xlsx格式文件。</span>
            <div v-if="uploadHasFailed" class="error-tip">
              <el-icon><i-ep-warning /></el-icon>
              上传失败，请重新选择文件后再试
            </div>
          </div>
        </template>
      </el-upload>

      <!-- 上传失败后显示重新选择按钮 -->
      <div class="reselect-section" v-if="uploadHasFailed">
        <el-alert title="上传失败提示" type="warning" :closable="false" show-icon>
          <template #default>
            文件上传失败，可能是文件内容有误或网络问题。<br />
            请修改文件内容后，点击下方按钮重新选择文件。
          </template>
        </el-alert>

        <div class="reselect-buttons">
          <el-button type="primary" @click="reSelectFile" icon="Refresh"> 重新选择文件 </el-button>
        </div>
      </div>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitFileForm" :disabled="uploadFile.length === 0 || uploadHasFailed"> 确 定 </el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
      <show-batch-error-msg ref="batchErrorRef"></show-batch-error-msg>
    </el-dialog>
  </div>
</template>

<script lang="ts" setup>
import { globalHeaders, globalUploadHeaders } from '@/utils/request';
import { UploadUserFile } from 'element-plus';
import { importDataFile } from '@/api/common/syscommon';
import ShowBatchErrorMsg from '@/views/modules/common/ShowBatchErrorMsg.vue';

const { proxy } = getCurrentInstance() as ComponentInternalInstance;

//属性
const props = defineProps({
  //上传地址
  upUrl: { type: String, default: '' }
});

const uploadRef = ref<ElUploadInstance>();
//上付附件
const uploadFile = ref<UploadUserFile[]>([]);
//批量错误信息
const batchErrorRef = ref<InstanceType<typeof ShowBatchErrorMsg>>();
// 上传是否失败的标识
const uploadHasFailed = ref(false);

/*** 导入参数 */
const upload = reactive<ImportOption>({
  // 是否显示弹出层
  open: false,
  // 弹出层标题
  title: '',
  // 是否禁用上传
  isUploading: false,
  // 是否更新已经存在的用户数据
  updateSupport: 0,
  // 设置上传的请求头部
  headers: globalUploadHeaders(),
  // 上传的地址
  url: import.meta.env.VITE_APP_BASE_API + props.upUrl
});

const emit = defineEmits(['ok']);

/** 查询参数列表 */
const show = () => {
  upload.open = true;
  upload.title = '导入数据';
  // 重置所有状态
  resetUploadState();
};

/** 重置上传状态 */
const resetUploadState = () => {
  uploadHasFailed.value = false;
  uploadRef.value?.clearFiles();
  uploadFile.value = [];
};

/** 取消 */
const cancel = () => {
  upload.open = false;
  resetUploadState();
};

/** 文件选择变化处理 */
const handleFileChange = (file: any, fileList: any[]) => {
  // 文件变化时重置失败状态，允许重新上传
  if (uploadHasFailed.value) {
    uploadHasFailed.value = false;
  }
};

/** 重新选择文件 */
const reSelectFile = () => {
  // 清除当前文件
  uploadRef.value?.clearFiles();
  uploadFile.value = [];
  uploadHasFailed.value = false;

  // 创建一个隐藏的文件选择器
  const input = document.createElement('input');
  input.type = 'file';
  input.accept = '.xlsx, .xls';
  input.style.display = 'none';

  input.onchange = (e: any) => {
    const file = e.target.files[0];
    if (file) {
      // 手动添加文件到上传组件
      const fileObj = {
        name: file.name,
        raw: file,
        uid: Date.now(),
        size: file.size,
        status: 'ready' as const
      };
      uploadFile.value = [fileObj];

      // 也要更新Element Plus组件的内部文件列表
      if (uploadRef.value) {
        uploadRef.value.clearFiles();
        // 模拟文件添加
        setTimeout(() => {
          uploadFile.value = [fileObj];
        }, 10);
      }
    }
    // 清理临时元素
    document.body.removeChild(input);
  };

  // 添加到页面并触发点击
  document.body.appendChild(input);
  input.click();
};

/** 提交上传文件 */
const submitFileForm = async () => {
  // 检查是否有文件
  if (uploadFile.value?.length === 0) {
    proxy?.$modal.msgError('请选择要上传的文件!');
    return;
  }

  // 检查是否之前上传失败过
  if (uploadHasFailed.value) {
    proxy?.$modal.msgError('请重新选择文件后再试!');
    return;
  }

  const fileItem = uploadFile.value[0];

  if (fileItem.raw) {
    proxy?.$modal.loading('正在上传文件，请稍候...');
    upload.isUploading = true;

    try {
      const formData = new FormData();
      formData.append('file', fileItem.raw);
      await importDataFile(props.upUrl, formData);

      // 上传成功
      proxy?.$modal.closeLoading();
      proxy?.$modal.msgSuccess('导入成功');
      upload.isUploading = false;
      emit('ok');
      cancel();
    } catch (e) {
      // 上传失败
      proxy?.$modal.closeLoading();
      upload.isUploading = false;
      uploadHasFailed.value = true; // 设置失败状态，禁用确定按钮和上传区域
      if (e && typeof e === 'object' && 'code' in e) {
        // 这是批量错误（数据校验失败）
        proxy?.$modal.msgError('文件数据校验失败，请查看详细错误信息，修改文件后重新选择上传!');
        batchErrorRef.value?.show(e);
      } else {
        // 网络错误或其他错误
        proxy?.$modal.msgError('文件上传失败，请检查网络连接或文件格式，修改后重新选择文件上传!');
      }
    }
  }
};

//暴露方法
defineExpose({
  show
});
</script>

<style lang="scss" scoped>
.text-center {
  text-align: center;
}

.error-tip {
  color: #f56c6c;
  margin-top: 4px;
  font-size: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
}

.reselect-section {
  margin-top: 16px;

  .reselect-buttons {
    margin-top: 12px;
    text-align: center;
  }
}

// 上传失败时让上传区域显示为禁用状态
:deep(.el-upload.is-disabled) {
  cursor: not-allowed;

  .el-upload-dragger {
    background-color: #f5f7fa;
    border-color: #e4e7ed;
    cursor: not-allowed;
  }

  .el-upload-dragger:hover {
    border-color: #e4e7ed;
  }

  .el-upload__text {
    color: #c0c4cc;
  }
}
</style>
