<!--
 * @Author: xiejiang
 * @Date: 2024-11-05 10:14:56
 * @LastEditors: xiejiang
 * @LastEditTime: 2024-11-11 10:13:11
 * @Description: 上传图片组件
 * Copyright（c）2024 by 好老师教育科技有限公司 All right Reserved.
-->

<template>
  <div class="upload-box">
    <t-upload theme="image" :multiple="false" :disabled="disabled" :sizeLimit="{
      size: fileSize, unit: 'MB', message: `图片大小不超过${fileSize} MB`
    }" :requestMethod="handleHttpUpload" :onSuccess="uploadSuccess" :onFail="uploadError" :draggable="drag"
      :accept="fileType.join(',')">
    </t-upload>
  </div>
</template>

<script setup lang="ts" name="UploadImg">
import axios from 'axios'
import { generateUUID } from '@/utils'
import { signature } from '@/api/modules/upload'
import { NotifyPlugin } from 'tdesign-vue-next';
import type { UploadFile, RequestMethodResponse } from 'tdesign-vue-next'

interface UploadFileProps {
  imageUrl: string // 图片地址 ==> 必传
  drag?: boolean // 是否支持拖拽上传 ==> 非必传（默认为 true）
  disabled?: boolean // 是否禁用上传组件 ==> 非必传（默认为 false）
  fileSize?: number // 图片大小限制 ==> 非必传（默认为 5M）
  fileType?: File.ImageMimeType[] // 图片类型限制 ==> 非必传（默认为 ["image/jpeg", "image/png", "image/gif"]）
  height?: string // 组件高度 ==> 非必传（默认为 150px）
  width?: string // 组件宽度 ==> 非必传（默认为 150px）
  borderRadius?: string // 组件边框圆角 ==> 非必传（默认为 8px）
}

// 接受父组件参数
const props = withDefaults(defineProps<UploadFileProps>(), {
  imageUrl: '',
  drag: true,
  disabled: false,
  fileSize: 5,
  fileType: () => ['image/jpeg', 'image/png', 'image/gif'],
  height: '150px',
  width: '150px',
  borderRadius: '8px'
})

// 生成组件唯一id
const uuid = ref('id-' + generateUUID())

/**
 * @description 图片上传
 * @param options upload 所有配置项
 * */
interface UploadEmits {
  (e: 'update:imageUrl', value: string): void
}
const emit = defineEmits<UploadEmits>()
// 获取上传签名
const getSignature = (name: string) => {
  return signature(name)
}
interface SignatureData {
  accessId: string;
  policy: string;
  signature: string;
  dir: string;
  host: string;
}
const handleHttpUpload = async (file: UploadFile): Promise<RequestMethodResponse> => {
  let requestMethodResponse: RequestMethodResponse = { status: 'fail', error: '未知错误', response: {} }
  const fileName = uuid.value + file.name
  let signatureData = {} as SignatureData
  try {
    const { data } = await getSignature(fileName)
    signatureData = data
  } catch (error) {
    requestMethodResponse = { status: 'fail', error: '获取签名失败', response: {} }
  }

  const formData = new FormData()
  formData.append('OSSAccessKeyId', signatureData.accessId)
  formData.append('policy', signatureData.policy)
  formData.append('Signature', signatureData.signature)
  formData.append('success_action_status', '200')
  formData.append('key', signatureData.dir! + '/' + fileName)
  formData.append('file', file.raw!)
  try {
    await axios({
      url: signatureData.host,
      method: 'post',
      headers: {
        'Content-Type': 'multipart/form-data'
      },
      data: formData
    }).then(() => {
      const imageUrl = `${signatureData.host}/${signatureData.dir}/${fileName}`
      emit('update:imageUrl', imageUrl)
      requestMethodResponse = { status: 'success', response: { url: imageUrl, name: file.name } }
    })
  } catch (error) {
    requestMethodResponse = { status: 'fail', error: '上传失败', response: {} }
  }
  // 添加默认返回值
  return requestMethodResponse
}

/**
 * @description 图片上传成功
 * */
const uploadSuccess = () => {
  NotifyPlugin.success({
    title: '温馨提示',
    content: '图片上传成功！'
  })
}

/**
 * @description 图片上传错误
 * */
const uploadError = () => {
  NotifyPlugin('error', {
    title: '温馨提示',
    content: '图片上传失败，请您重新上传！'
  })
}
</script>

<style scoped lang="less"></style>
