<!-- 文件上传组件 -->
<template>
  <div>
    <el-upload v-model:file-list="fileList" :style="props.style" :before-upload="handleBeforeUpload"
      :on-change="handleChange" :accept="accept" multiple drag :tip="'支持多个文件上传，单个文件不超过 ' + props.maxFileSize + 'MB'"
      :auto-upload="false">
      <!-- 拖拽上传区域 -->
      <div>
        <el-icon class="el-icon--upload">
          <UploadFilled />
        </el-icon>
        <div class="el-upload__text">
          将文件拖到此处，或 <em>点击上传</em>
          <br />
          <small>支持格式：{{ accept }}</small>
        </div>
      </div>
      <!-- 文件列表 -->
      <template #file="{ file }">
        <div class="el-upload-list__item-info">
          <a class="el-upload-list__item-name" @click="handleDownload(file)">
            <el-icon>
              <Document />
            </el-icon>
            <span class="el-upload-list__item-file-name">{{ file.name }}</span>
            <span class="el-icon--close" @click="handleRemove(file.url)">
              <el-icon>
                <Close />
              </el-icon>
            </span>
          </a>
        </div>
      </template>
    </el-upload>
  </div>
</template>
<script setup>
import { UploadFilled, Document, Close } from "@element-plus/icons-vue";

const emit = defineEmits({
  "file-selected": null,
});

const props = defineProps({
  /**
   * 文件上传数量限制
   */
  limit: {
    type: Number,
    default: 10,
  },
  /**
   * 单个文件上传大小限制(单位MB)
   */
  maxFileSize: {
    type: Number,
    default: 10,
  },
  /**
   * 上传文件类型
   */
  accept: {
    type: String,
    default: "*",
  },
  /**
   * 选择文件成功的回调函数
   */
  successCallback: {
    type: Function,
    default: null,
  },
  /**
   * 样式
   */
  style: {
    type: Object,
    default: () => {
      return {
        width: "100%",
      };
    },
  },
});

const fileList = defineModel({
  type: Array,
  default: () => [],
});

/**
 * 文件选择变化
 */
function handleChange(file, fileList) {
  if (file.status === 'ready') {
    // 如果限制为1个文件，移除之前的文件，只保留当前新文件
    if (props.limit === 1 && fileList.length > 1) {
      fileList.splice(0, fileList.length - 1);
    }
    const rawFile = file.raw;
    // 限制文件类型
    if (props.accept !== "*") {
      const acceptedTypes = props.accept.split(',').map(type => type.trim());
      const isAccepted = acceptedTypes.some(type => {
        let checkType = type;
        if (!type.startsWith('.') && !type.includes('/')) {
          checkType = '.' + type;
        }
        if (checkType.startsWith('.')) {
          return rawFile.name.toLowerCase().endsWith(checkType.toLowerCase());
        } else if (checkType.includes('*')) {
          const [main] = checkType.split('/');
          return rawFile.type.startsWith(main + '/');
        } else {
          return rawFile.type === checkType;
        }
      });
      if (!isAccepted) {
        ElMessage.warning("文件类型不符合要求");
        // 从 fileList 中移除不符合的文件
        fileList.splice(fileList.indexOf(file), 1);
        return;
      }
    }
    if (props.successCallback) {
      props.successCallback(rawFile);
    } else {
      emit("file-selected", rawFile);
    }
  }
}

/**
 * 上传前校验
 */
function handleBeforeUpload(file) {
  // 限制文件大小
  if (file.size > props.maxFileSize * 1024 * 1024) {
    ElMessage.warning("上传文件不能大于" + props.maxFileSize + "M");
    return false;
  }
  // 限制文件类型
  if (props.accept !== "*") {
    const acceptedTypes = props.accept.split(',').map(type => type.trim());
    const isAccepted = acceptedTypes.some(type => {
      if (type.startsWith('.')) {
        return file.name.toLowerCase().endsWith(type.toLowerCase());
      } else {
        return file.type === type;
      }
    });
    if (!isAccepted) {
      ElMessage.warning("文件类型不符合要求");
      return false;
    }
  }
  return true;
}

/**
 * 删除文件
 */
function handleRemove(fileUrl) {
  // 从 fileList 中移除
  fileList.value = fileList.value.filter(f => f.url !== fileUrl);
}

/**
 * 下载文件
 */
function handleDownload(file) {
  // 本地文件，不支持下载
}
</script>
<style lang="scss" scoped>
.el-upload-list__item .el-icon--close {
  position: absolute;
  top: 50%;
  right: 5px;
  color: var(--el-text-color-regular);
  cursor: pointer;
  opacity: 0.75;
  transition: opacity var(--el-transition-duration);
  transform: translateY(-50%);

  &:hover {
    opacity: 1;
    color: var(--el-color-danger);
  }
}

:deep(.el-upload-list) {
  margin: 10px 0 0 0;
}

:deep(.el-upload-list__item) {
  margin: 5px 0;
  background: #f5f5f5;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  padding: 8px 12px;
  display: flex;
  align-items: center;
  transition: all 0.3s ease;

  &:hover {
    background: #f0f0f0;
    border-color: var(--el-color-primary-light-3);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  }

  .el-upload-list__item-info {
    flex: 1;

    a {
      display: flex;
      align-items: center;
      text-decoration: none;
      color: var(--el-text-color-primary);

      &:hover {
        color: var(--el-color-primary);
      }

      .el-icon {
        margin-right: 8px;
        color: var(--el-color-primary);
      }

      .el-upload-list__item-file-name {
        flex: 1;
        font-size: 14px;
        font-weight: 500;
      }

      .el-icon--close {
        margin-left: 8px;
      }
    }
  }
}
</style>
