<template>
  <div class="sel-upload" :class="btnView==='plus'?'start':''">
    <el-button
      v-show="fileList.length<length"
      v-if="!btnView"
      :loading="loading&&useLoading"
      type="primary"
      @click="clickHandle"
    >
      <template v-if="loading">upload（{{ progressRatio }}%）</template>
      <template v-else>点击上传</template>
    </el-button>
    <span :class="fileList.length<length" />
    <div v-show="fileList.length<length" v-if="btnView==='plus'" class="plus" @click="clickHandle">
      <svg class="icon" aria-hidden="true">
        <use xlink:href="#icon-plus" />
      </svg>
    </div>
    <span v-if="view!=='image'" class="tips" v-html="tips"></span>
    <input
      style="display: none"
      ref="input"
      type="file"
      :accept="accept"
      :multiple="multiple"
      @change="handleChange"
    />
    <s-file-view
      v-if="fileList.length>0"
      v-model="model"
      :imageStyle="imageStyle"
      :upload="upload"
      :view="view"
      :remove="true"
      @change="changeHandle"
    />
    <div class="tips" v-if="view==='image'" v-html="tips"></div>
  </div>
</template>

<script setup lang="ts">
defineOptions({
  name: 'SUpload'
})
import { useUpload } from '../../../hooks/use-upload'
import { computed, inject, onMounted, provide, ref } from 'vue'
import { isFunction, isJsonString } from '../../../Utils'
import { useVModel } from '@vueuse/core'
// 打包依赖包
import './iconfont/iconfont.js'

// 打包文档
// onMounted(() => {
//   import('./iconfont/iconfont.js')
// })

interface Props {
  modelValue: string
  upload: any
  imageStyle: any
  size: number
  length: number
  tips: string
  remove: boolean
  accept: string
  btnProps: any
  view: string
  multiple: boolean
  loading: boolean
  btnView: string
  /*
  * 上传错误提示回调
  * */
  errorCallback: any
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: '',
  upload: () => {
    return {}
  },
  imageStyle: () => {
    return {}
  },
  size: 5,
  length: 10,
  tips: '',
  remove: false,
  accept: '.doc,.docx,.pdf,.xls,.xlsx,.jpg,.jpeg,.png,.ceb,.tiff,.txt,.otf',
  btnProps: () => {
    return {}
  },
  view: 'file',
  multiple: false,
  loading: false,
  btnView: ''
})
const emits = defineEmits(['update:modelValue', 'change'])
const { uploadHandler } = useUpload()
const input = ref()
const model = useVModel(props, 'modelValue', emits)
const setErrorMessage = inject('setErrorMessage')

function clickHandle () {
  input.value.click()
}

const useLoading = ref(false)
const progressRatio = ref(0)

function progress (progressEvent) {
  useLoading.value = true
  progressRatio.value = Math.round((progressEvent.loaded * 100) / progressEvent.total)
  if (progressRatio.value >= 100) {
    useLoading.value = false
  }
}

async function handleChange () {
  try {
    if (props.multiple) {
      const data = await uploadHandler(input.value.files, progress)
      input.value.value = null
      const fileList = files(props.modelValue)
      if (data.url) {
        fileList.push(data)
        model.value = JSON.stringify(fileList)
        emits('change', model.value)
      }
    } else {
      const data = await uploadHandler(input.value.files[0], progress)
      input.value.value = null
      const fileList = files(props.modelValue)
      if (data.url) {
        fileList.push(data)
        model.value = JSON.stringify(fileList)
        emits('change', model.value)
      }
    }
  } catch (message) {
    if (props.errorCallback && isFunction(props.errorCallback) && message) {
      props.errorCallback(message)
    } else if (message) {
      setErrorMessage && setErrorMessage(message)
    }
  }
}

function changeHandle (data) {
  const fileList = files(data)
  emits('change', fileList)
}

const fileList = computed(() => {
  return files(props.modelValue)
})

function files (value) {
  return value && isJsonString(value) ? JSON.parse(value) : []
}
</script>

<style lang="scss" scoped>
.sel-upload {
  &.start {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    flex-wrap: wrap;
  }

  .el-button {
    margin-right: 10px;
    margin-bottom: 10px;
  }

  .plus {
    display: flex;
    width: 98px;
    height: 98px;
    justify-content: center;
    align-items: center;
    margin-right: 10px;
    margin-bottom: 10px;
    border: 1px dashed #ddd;
  }

  input {
    display: none;
  }

  .tips {
    color: #999;
  }
}
</style>
