<template>
  <div class="oss-filed">
    <n-upload
      action="#"
      :max="limit"
      :file-list="fileList"
      :default-upload="false"
      list-type="image-card"
      @change="handleChange"
      @before-upload="beforeUpload"
    >
      <div class="oss-upload-text" />
    </n-upload>
  </div>
</template>

<script>
import OSS from 'ali-oss'
import { getOssAuth } from '@/api/common/upload.js'
import { defineComponent, reactive, onMounted, watch, toRefs } from 'vue'
export default defineComponent({
  name: 'UploadOss',
  props: {
    limit: {
      type: Number,
      default: 1
    },
    defaultList: {
      type: String,
      default: ''
    }
  },
  emits: ['uploadStatus'],
  setup(props, { emit }) {
    const data = reactive({
      ...props,
      client: null,
      fileList: [],
      hasUploadInfo: {},
      limit: props.limit
    })
    onMounted(() => {
      if (props.defaultList) {
        const list = props.defaultList.split(',')
        const fileList = list.map((item) => {
          const objectName = item.split('/').slice(3).join('/')
          const obj = {
            name: objectName,
            id: objectName,
            type: 'image/png',
            url: item,
            objectName: objectName,
            status: 'finished'
          }
          data.hasUploadInfo[obj.id] = {
            id: objectName,
            objectName: objectName
          }
          return obj
        })
        data.fileList = fileList
        emit('uploadStatus', 'upload')
      } else {
        data.fileList = []
      }
    })
    /* 监听默认文件列表 */
    watch(() => props.defaultList, (value) => {
      if (value.length) {
        const list = value.split(',')
        const fileList = list.map((item) => {
          const objectName = item.split('/').slice(3).join('/')
          const obj = {
            name: objectName,
            id: objectName,
            type: 'image/png',
            url: item,
            objectName: objectName
          }
          data.hasUploadInfo[obj.id] = {
            id: objectName,
            objectName: objectName
          }
          return obj
        })
        data.fileList = fileList
        emit('uploadStatus', 'upload')
      } else {
        data.fileList = []
      }
    })

    /**
     * @description: 上传文件
     * @return {*}
     */
    function startUpload() {
      return new Promise((resolve, reject) => {
        /* 定义要上传文件 */
        const uploads = []
        /* 从待文件列表中获取没有上传过的文件 */
        const uloadList = data.fileList.filter((item) => {
          return !item.url
        })
        /* 如果待上传列表长度为0，则返回，否则获取上传鉴权 */
        if (!uloadList.length) {
          /* 如果没有要上传的文件信息则返回oss的文件名 */
          /* 不存在objectName的文件表示上传失败 */
          const objectList = data.fileList.map((item) => item.objectName || 'error')
          resolve(objectList)
        } else {
          getOssAuth()
            .then(res => {
              /* 初始化oss上传客户端 */
              data.client = new OSS({
                region: 'oss-cn-shanghai',
                secure: true,
                accessKeyId: res.data.accessKeyId,
                accessKeySecret: res.data.accessKeySecret,
                stsToken: res.data.securityToken,
                bucket: 'ta-tech-image'
              })
              /* promise上传要上传的文件 */
              uloadList.forEach(item => {
                uploads.push(uploadOss(item))
              })
              Promise.all(uploads)
                .then((response) => {
                  /* 获取fileList内的文件存储名称 */
                  data.fileList.forEach((item) => {
                  })
                  const objectList = data.fileList.map((item) => item.objectName || 'error')
                  resolve(objectList)
                })
                .catch((error) => {
                  console.log('error', error)
                  resolve(error)
                })
            })
        }
      })
    }

    function uploadOss(files) {
      const file = files.file
      return new Promise((resolve, reject) => {
        /* 生成随机文件名称 */
        const randomString = Math.random().toString(36).slice(2)
        const suffix = /\.[^\.]+/.exec(file.name)
        const timestamp = new Date().getTime()
        const objectName = `imagedir/${randomString}_${timestamp}${suffix}`
        /* 上传文件至oss */
        data.client.put(objectName, file)
          .then((res) => {
            const index = data.fileList.findIndex(list => list.id === files.id)
            data.fileList[index].url = res.url
            data.fileList[index].objectName = objectName
            const id = data.fileList[index].id
            data.hasUploadInfo[id] = {
              id: objectName,
              objectName: objectName
            }
            resolve(objectName)
          })
          .catch((err) => {
            console.log('err', err)
            resolve('error')
            console.log(err)
          })
      })
    }

    /**
     * @description: 上传前的判断文件类型
     * @param {*} file 当前选择的文件
     * @return {*}
     */
    async function beforeUpload({ file }) {
      if (!file.type.match('image.*')) {
        $message.error('请选择正确的图片类型')
        /* 中断流程 */
        return false
      }
    }
    /**
     * @description: 文件发生变化时
     * @param {Array} fileList
     * @return {*}
     */
    function handleChange({ fileList }) {
      data.fileList = fileList.map((item) => {
        if (Object.keys(data.hasUploadInfo).includes(item.id)) {
          item.objectName = data.hasUploadInfo[item.id].objectName
        }
        return item
      })
      /* 判断是否存在文件 */
      const status = fileList.length ? 'ready' : 'no-file'
      emit('uploadStatus', status)
    }

    return {
      ...toRefs(data),
      beforeUpload,
      handleChange,
      startUpload,
      uploadOss
    }
  }
})
</script>

<style lang="scss" scoped>
.oss-filed{
  width: 100%;
}
.oss-upload-picture-card-wrapper{
  min-height: 122px;
  padding: 10px 0 0 10px;
}
.oss-upload-text {
  // width: 100px;
  // height: 100px;
  // cursor: pointer;
  // border: 1px solid #e1e1e1;
  // margin: 10px 0 0 10px;
  position: relative;
}
.oss-upload-text::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 30px;
  transform:translate(-50%, -50%);
  border-top: 2px solid #e1e1e1;
}

.oss-upload-text::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  height: 30px;
  transform: translate(-50%,-50%);
  border-left: 2px solid #e1e1e1;
}

.n-image{
  img{
    overflow: hidden;
  }
}
</style>
