<template>
  <el-upload
    ref="uploadRef"
    style="width: 100%"
    :file-list="modelValue"
    :action="action"
    multiple
    :limit="limit"
    :list-type="listType"
    :auto-upload="autoUpload"
    :disabled="disabled"
    :accept="accept"
    :on-remove="onRemove"
    :before-remove="beforeRemove"
    :on-change="onChange"
    :on-exceed="onExceed"
    :on-preview="onPreview"
    :http-request="httpRequest"
    :show-file-list="showFileList"
    :class="{ hide: modelValue.length === limit }"
  >
    <el-icon v-if="listType === 'picture-card'" size="32"><plus /></el-icon>
    <el-button v-else type="primary">点击选择文件上传</el-button>
    <template #tip>
      <div class="mt-10 text-red">
        <slot name="tip">
          <div>{{ tip.join("，") }}。</div>
        </slot>
      </div>
    </template>
  </el-upload>
  <el-dialog v-model="visible" title="查看图片">
    <img :src="imageUrl" alt="Preview Image" style="width: 100%; object-fit: scale-down" />
  </el-dialog>
</template>

<script setup>
import { computed, ref, useTemplateRef } from "vue";
import { ElMessage, ElMessageBox, ElUpload, ElIcon, ElButton, ElDialog } from "element-plus";
import { Plus } from "@element-plus/icons-vue";
import "element-plus/es/components/upload/style/css";
import "element-plus/es/components/icon/style/css";
import "element-plus/es/components/button/style/css";
import "element-plus/es/components/dialog/style/css";

defineOptions({
  name: "AppUpload",
});
const props = defineProps({
  autoUpload: { type: Boolean, default: false },
  action: { type: String, default: "" },
  limit: { type: Number, default: 1 },
  listType: { type: String, default: "text" },
  accept: { type: String, default: "" },
  ratio: { type: String, default: "" },
  disabled: { type: Boolean, default: false },
  deleteToServer: { type: Boolean, default: false },
  showFileList: { type: Boolean, default: true },
  httpRequest: { type: Function },
  size: { type: Number, default: 0 },
  beforeRemove: { type: Function, default: () => {} },
});
const visible = ref(false);
const imageUrl = ref("");
const modelValue = defineModel({ type: Array, required: true });
const deleteFiles = defineModel("deleteFiles", {
  type: Array,
  default: () => [],
});
const emits = defineEmits(["preview", "delete"]);
const uploadRef = useTemplateRef("uploadRef");
const tip = computed(() =>
  [
    `最多上传${props.limit}个文件`,
    props.accept
      ? `并且只能上传${props.accept
          .replaceAll(".", "")
          .split(",")
          .join("、")}格式的文件`
      : "可以上传任意格式的文件",
    props.size ? `文件大小不能超过${props.size}M` : "",
    props.ratio ? `只能上传${props.ratio}分辨率的图片` : "",
  ].filter(Boolean)
);
const onExceed = () => {
  ElMessage.warning(`最多上传${props.limit}个文件`);
};
const beforeRemove = async (uploadFile) => {
  if (props.deleteToServer && uploadFile.imgFilesId) {
    await ElMessageBox.confirm("确定要删除吗？", {
      type: "warning",
    });
    await props.beforeRemove(uploadFile);
  }
};
const onRemove = (uploadFile, uploadFiles) => {
  modelValue.value = uploadFiles;
  deleteFiles.value.push(uploadFile);
  emits("delete", uploadFile);
};
const onChange = (uploadFile, uploadFiles) => {
  const accept = props.accept && props.accept.split(",");
  const ratio = props.ratio && props.ratio.split("*");
  const suffix = uploadFile.raw.name.substring(
    uploadFile.raw.name.lastIndexOf("."),
    uploadFile.raw.name.length
  );
  const size = props.size * 1024 * 1024;
  if (ratio) {
    const img = new Image();
    img.src = uploadFile.url;
    img.onload = () => {
      if (img.width !== +ratio[0] && img.height !== +ratio[1]) {
        ElMessage.warning(`只能上传${props.ratio}分辨率的图片`);
        uploadRef.value.handleRemove(uploadFile.raw);
      }
    };
  }
  if (size) {
    if (uploadFile.size > size) {
      ElMessage.warning(`文件大小不能超过${props.size}M`);
      uploadRef.value.handleRemove(uploadFile.raw);
    }
  }
  if (accept) {
    if (accept.includes(suffix)) {
      modelValue.value = uploadFiles;
    } else {
      ElMessage.warning(`只能上传${props.accept}格式的文件`);
      uploadRef.value.handleRemove(uploadFile.raw);
    }
  } else {
    modelValue.value = uploadFiles;
  }
};
const onPreview = (uploadFile) => {
  if (props.listType === "picture-card") {
    visible.value = true;
    imageUrl.value = uploadFile.url;
  } else {
    emits("preview", uploadFile);
  }
};
</script>

<style scoped lang="scss">
.hide :deep(.el-upload--picture-card) {
  display: none;
}
</style>
