<script lang="ts" setup>
import type { UploadProps, UploadUserFile } from 'element-plus'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import md5 from 'blueimp-md5'
import { getSignature } from '@/api/base'

interface Props {
  modelValue: string | { name: string; url: string }[]
  prefix?: string
  size?: number
  limit?: number
  beforeUpload?: (file: any) => void
}

const props = withDefaults(defineProps<Props>(), {
  prefix: 'upload/saas-lab/'
})

const emit = defineEmits(['update:modelValue', 'success'])

const uploadData = ref()

const fileList = ref<UploadUserFile[]>([])

watchEffect(() => {
  fileList.value = Array.isArray(props.modelValue) ? props.modelValue.map(item => ({ ...item })) : []
})

const showFileList = computed(() => {
  return Array.isArray(props.modelValue)
})

// 上传之前
const handleBeforeUpload = async (file: any) => {
  if (props.limit && fileList.value.length >= props.limit && props.limit > 1) {
    ElMessage.error(`只能上传${props.limit}个文件`)
    return false
  }
  if (props.size && file.size > props.size) {
    ElMessage.error(`文件大小不能超过${props.size / 1024 / 1024}M`)
    return false
  }
  const fileName = file.name
  const key = props.prefix + md5(fileName + new Date().getTime()) + '/' + fileName
  const response: Record<string, any> = await getSignature()
  uploadData.value = {
    key,
    host: response.host,
    OSSAccessKeyId: response.accessid,
    policy: response.policy,
    signature: response.signature,
    success_action_status: '200',
    url: `${response.host}/${key}`
  }
  file.url = `${response.host}/${key}`
  if (props.beforeUpload) {
    return props.beforeUpload(file)
  }
}

// 上传成功
const handleSuccess = (response: any, file: any, files: any) => {
  if (!files.every((item: any) => item.status === 'success')) return
  if (showFileList.value) {
    if (props.limit && props.limit === 1) {
      const last = files[files.length - 1]
      emit('update:modelValue', [
        {
          name: last.name,
          url: last.url || last.raw?.url,
          size: last.size || last.raw?.size,
          type: last.type || last.raw?.type
        }
      ])
    } else {
      emit(
        'update:modelValue',
        files.map((item: any) => {
          return {
            name: item.name,
            url: item.url || item.raw?.url,
            size: item.size || item.raw?.size,
            type: item.type || item.raw?.type
          }
        })
      )
    }
  } else {
    emit('update:modelValue', file.raw.url)
  }
  emit('success', file, files)
}

// 上传限制
const handleExceed: UploadProps['onExceed'] = () => {
  ElMessage.warning('文件超出个数限制')
}

// 删除
const handleRemove: UploadProps['onRemove'] = (file, files) => {
  if (showFileList.value) {
    emit(
      'update:modelValue',
      files.map((item: any) => {
        return { name: item.name, url: item.url || item.raw.url }
      })
    )
  } else {
    emit('update:modelValue', '')
  }
}

// 预览
const handlePreview: UploadProps['onPreview'] = uploadFile => {
  window.open(uploadFile.url)
}
</script>

<template>
  <el-upload
    :action="uploadData?.host"
    :data="uploadData"
    :show-file-list="showFileList"
    :before-upload="handleBeforeUpload"
    :on-exceed="handleExceed"
    :on-remove="handleRemove"
    :on-preview="handlePreview"
    :on-success="handleSuccess"
    :file-list="fileList"
    class="uploader">
    <slot>
      <template v-if="showFileList">
        <template v-if="$attrs['list-type'] === 'picture-card'">
          <el-icon><Plus /></el-icon>
        </template>
        <template v-else>
          <el-button type="primary" plain round>本地文件</el-button>
        </template>
      </template>
      <div class="avatar-uploader" v-else>
        <el-image :src="(modelValue as string)" fit="contain" v-if="modelValue" />
        <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
      </div>
    </slot>
    <template #tip>
      <div class="el-upload__tip"><slot name="tip"></slot></div>
    </template>
  </el-upload>
</template>

<style lang="scss">
.uploader {
  flex: 1;
  overflow: hidden;
}
.avatar-uploader {
  width: 178px;
  height: 178px;
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
  .el-image {
    width: 100%;
    height: 100%;
  }
}
.avatar-uploader:hover {
  border-color: var(--el-color-primary);
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 100%;
  height: 100%;
  text-align: center;
}
</style>
