<template>
  <div class="upload-box">
    <div v-for="(item, index) in fileList" class="items">
      <img v-if="item.filePath" :src="item.filePath" class="upload-image" />
      <div class="upload-handle" @click.stop>
        <div class="handle-icon" @click="handleEdit(index)" v-if="!self_disabled">
          <EditOutlined style="font-size: 20px" />
        </div>
        <div class="handle-icon" @click="onPreview(index)">
          <ZoomInOutlined style="font-size: 20px" />
        </div>
        <div class="handle-icon" @click="handleRemove(index)" v-if="!self_disabled">
          <DeleteOutlined style="font-size: 20px" />
        </div>
      </div>
    </div>
    <a-upload-dragger
      action="#"
      :id="uuid"
      class="upload-demo my-upload-images"
      :multiple="multiple"
      ref="uploadRef"
      :style="{ width: width, height: height }"
      :disabled="loading ? true : self_disabled || fileList.length >= props.limit"
      :custom-request="handleHttpUpload"
      :before-upload="beforeUpload"
      list-type="picture-card"
      :maxCount="limit"
      :file-list="fileList"
      :show-upload-list="false"
      v-if="!self_disabled"
      :on-exceed="onExceed"
      :accept="props.fileType"
    >
      <PlusOutlined v-if="!loading" />
      <a-progress type="circle" v-else :percentage="progress" />
    </a-upload-dragger>
  </div>
</template>

<script setup lang="ts">
  import { computed, ref } from 'vue';
  import { generateUUID } from '@/utils/auth';
  import {
    PlusOutlined,
    EditOutlined,
    DeleteOutlined,
    ZoomInOutlined,
  } from '@ant-design/icons-vue';
  import { notification } from 'ant-design-vue';
  import OSS from "ali-oss";
  const uploadRef = ref();
  import { upload,getOssConfig } from '@/api/common';

  // 接受父组件参数
  const props = defineProps({
    zIndex: {
      default: -1,
    },
    multiple: {
      type: Boolean,
      default: false,
    },
    btnTip: {
      type: String,
      default: '',
    },
    limit: {
      type: Number,
      default: undefined,
    },
    width: {
      type: String,
      default: '120px',
    },
    height: {
      type: String,
      default: '120px',
    },
    borderRadius: {
      type: String,
      default: '8px',
    },
    fileList: {
      type: Array,
      required: true,
      default: [],
    },
    disabled: {
      default: false,
    },
    fileSize: {
      default: 200,
    },
    orderNo: {
      default: '',
    },
    fileType: {
      default: '',
    },
    name: {
      default: '',
    },
  });
  // 生成组件唯一id
  const uuid = ref('id-' + generateUUID());

  // 判断是否禁用上传和删除
  const self_disabled = computed(() => {
    return props.disabled;
  });
  let editIndex = '';

  const emit = defineEmits(['upload']);
  const progress = ref(0);
  const loading = ref(false);

  //接口上传
  const handleHttpUpload = async (options) => {
    loading.value = true;
    try {
      const formData = new FormData();
      formData.append('file', options.file);
      formData.append('name', props.name);
      const res = await upload(formData);
      if (props.multiple) {
        let list = JSON.parse(JSON.stringify(props.fileList));
        if (editIndex !== '') {
          list.splice(editIndex, 1, {
            url: res.fileUrl,
            name: res.originalName,
            filePath: res.fileUrl,
            fileName: res.originalName,
          });
          editIndex = '';
        } else {
          list.push({
            url: res.fileUrl,
            name: res.originalName,
            filePath: res.fileUrl,
            fileName: res.originalName,
          });
        }
        emit('upload', list, props.zIndex);
      } else {
        emit('upload', res, props.zIndex);
      }
    } catch (error) {
      notification.error({
        message: '温馨提示',
        description: '上传文件失败！',
      });
      if (props.multiple) {
        emit('upload', props.fileList, props.zIndex);
      } else {
        uploadRef.value!.clearFiles();
        emit('upload', '', props.zIndex);
      }
      options.onError(error as any);
    } finally {
      progress.value = 0;
      loading.value = false;
    }
  };

   //oss上传
   const handleHttpUploads = async (options: UploadRequestOptions) => {
    const configData = await getOssConfig()
    let date = new Date();
    let year = date.getFullYear();
    let month: string | number = date.getMonth() + 1;
    month = month < 10 ? ("0" + month) : month;
    let day: string | number = date.getDate();
    day = day < 10 ? ("0" + day) : day;
    let h: string | number = date.getHours();
    h = h < 10 ? ("0" + h) : h;
    let minute: string | number = date.getMinutes();
    minute = minute < 10 ? ("0" + minute) : minute;
    let second: string | number = date.getSeconds();
    second = second < 10 ? ("0" + second) : second;
    let time = h + "" + minute + "" + second;
    let fileName = (props.orderNo ? (time + '-' + props.orderNo) : time) + "-" + options.file.name
    fileName = fileName.replace(/[\+\_\,\!\|\~\`\(\)\#\$\%\^\&\*\{\}\:\;\"\<\>\?]/g, '')
    let filePath = props.name + "/" + year + "/" + month + "/" + day + "/" + fileName;
    loading.value = true;
    try {
      const headers = {
        "Access-Control-Allow-Origin": "*"
      };
      const client = new OSS({
        // yourRegion填写Bucket所在地域。以华东1（杭州）为例，yourRegion填写为oss-cn-hangzhou。
        endpoint: configData.oss_endpoint,
        // 从STS服务获取的临时访问密钥（AccessKey ID和AccessKey Secret）。
        secure: true,
        region: configData.oss_region,
        accessKeyId: configData.oss_accessKeyId,
        accessKeySecret: configData.oss_accessKeySecret,
        // 填写Bucket名称。
        bucket: configData.oss_bucketName,
        timeout: 600000
      });
      const res = await client.multipartUpload(filePath, options.file, {
        headers: headers,
        // 获取分片上传进度、断点和返回值。
        progress: (p, cpt, res) => {
          progress.value = parseFloat(parseFloat(p * 100).toFixed(2))
          options.onProgress({ percent: parseFloat(parseFloat(p * 100).toFixed(2)) });
        },
        // 设置并发上传的分片数量。
        parallel: 4,
        // 设置分片大小。默认值为1 MB，最小值为100 KB。
        partSize: 1024 * 1024,
        // headers,
        mime: options.file.type
      });
      if (props.multiple) {
        let list = JSON.parse(JSON.stringify(props.fileList))
        if (editIndex !== '') {
          list.splice(editIndex, 1, {
            url:res.res.requestUrls[0],
            name: options.file.name,
            filePath: res.res.requestUrls[0],
            fileName: options.file.name
          })
          editIndex = ''
        } else {
          list.push({
            url: res.res.requestUrls[0],
            name: options.file.name,
            filePath: res.res.requestUrls[0],
            fileName: options.file.name
          })
        }
        emit('upload', list,props.zIndex)
      } else {
        emit("upload", res.res.requestUrls[0], options.file.name, props.zIndex);
      }
    } catch (error) {
      notification.error({
        message: '温馨提示',
        description: '上传文件失败！',
      });
      if (props.multiple) {
        emit('upload', props.fileList, props.zIndex);
      } else {
        uploadRef.value!.clearFiles();
        emit('upload', '', props.zIndex);
      }
      options.onError(error as any);
    } finally {
      progress.value = 0
      loading.value = false;
    }
};
  const onPreview = (index: any) => {
    window.open(props.fileList[index].filePath);
  };

  const handleEdit = (index: any) => {
    editIndex = index;
    const dom = document.querySelector(`.ant-upload #${uuid.value}`);
    dom && dom.dispatchEvent(new MouseEvent('click'));
  };
  const handleRemove = (index: any) => {
    editIndex = index;
    if (props.multiple) {
      emit(
        'upload',
        props.fileList.filter((f, i) => !(editIndex == i)),
        props.zIndex,
      );
    } else {
      uploadRef.value!.clearFiles();
      emit('upload', '', props.zIndex);
    }
  };

  const onExceed = () => {
    if (props.limit) {
      notification.warning({
        message: '温馨提示',
        description: `最多支持上传${props.limit}张`,
      });
    }
  };

  /**
   * @description 文件上传之前判断
   * @param rawFile 选择的文件
   * */
  const beforeUpload = (rawFile) => {
    const imgSize = rawFile.size / 1024 / 1024 < props.fileSize;
    if (!imgSize) {
      notification.warning({
        message: '温馨提示',
        description: `上传文件大小不能超过 ${props.fileSize}M！`,
      });
      return false;
    }
    if (props.fileType) {
      let fileType = props.fileType.replace(/\s/g, '');
      fileType.split('.').join('|');
      let fileIndex = rawFile.name.lastIndexOf('.');
      let substrName = rawFile.name.substr(fileIndex);
      if (fileType.indexOf(substrName) == -1) {
        notification.warning({
          message: '温馨提示',
          description: '上传文件不符合所需的格式！',
        });
        return false;
      }
    }
    return true;
  };
</script>
<style scoped lang="less">
  .upload-box {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    > div {
      margin-right: 10px;
      margin-bottom: 10px;
      position: relative;

      &.items {
        width: v-bind(width);
        height: v-bind(height);
        border: 1px dashed #d9d9d9;
        border-radius: 4px;
        padding: 5px;
      }

      &:hover {
        .upload-handle {
          opacity: 1;
        }
      }
    }
    :deep(.ant-upload) {
      position: relative;
      display: flex;
      align-items: center;
      justify-content: center;
      width: v-bind(width);
      height: v-bind(height);
      overflow: hidden;
      border-radius: 4px;
    }
    .upload-image {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }

    .upload-handle {
      position: absolute;
      top: 0;
      right: 0;
      box-sizing: border-box;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100%;
      height: 100%;
      cursor: pointer;
      background: rgb(0 0 0 / 60%);
      opacity: 0;

      .handle-icon {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 0 6%;
        color: aliceblue;
        span {
          font-size: 85%;
          line-height: 85%;
        }
      }
    }
  }
</style>
