<template>
    <div v-loading="spinShow" class="hc-uploads-box">
        <el-upload
            ref="uploadRef" v-model:file-list="fileListData" :accept="accept" :action="api + action"
            :before-upload="beforeUpload" :data="uploadData" :disabled="uploadDisabled"
            :headers="getTokenHeader()" :limit="limit" :multiple="limit > 1" :on-error="uploadError"
            :on-exceed="uploadExceed" :on-preview="uploadPreview" :on-progress="uploadprogress"
            :on-remove="uploadRemove" :on-success="uploadSuccess" list-type="picture-card"
        >
            <HcIcon class="hc-upload-icon" name="add" />
        </el-upload>
        <el-image-viewer
            v-if="showViewer" :initial-index="initialIndex" :url-list="previewFileList"
            @close="showViewerClose"
        />
    </div>
</template>

<script setup>
import { onMounted, ref, watch } from 'vue'
import { getTokenHeader } from '~src/api/request/header'
import { arrIndex, getObjVal, getObjValue, isFileSize } from 'js-fast-way'
import { genFileId } from 'element-plus'

const props = defineProps({
    fileList: {
        type: Array,
        default: () => ([]),
    },
    datas: {
        type: Object,
        default: () => ({}),
    },
    api: {
        type: String,
        default: '/api/blade-resource/oss/endpoint/',
    },
    action: {
        type: String,
        default: 'put-file',
    },
    accept: {
        type: String,
        default: 'image/png,image/jpg,image/jpeg',
    },
    limit: {
        type: Number,
        default: 1,
    },
    size: {
        type: Number,
        default: 30,
    },
    viewer: {
        type: Boolean,
        default: true,
    },
})

//事件
const emit = defineEmits(['change', 'progress', 'del', 'preview'])
//变量
const uploadRef = ref(null)
const uploadData = ref(props.datas)
const fileListData = ref(props.fileList)
const uploadDisabled = ref(false)

//监听
watch(() => [
    props.fileList,
    props.datas,
], ([fileList, datas]) => {
    uploadData.value = datas
    fileListData.value = fileList
})

//渲染完成
onMounted(() => {
    beforeFileNum.value = 0
    finishFileNum.value = 0
    errorFileNum.value = 0
})

const showViewerClose = () => {
    showViewer.value = false
}

//上传前
const spinShow = ref(false)
const beforeFileNum = ref(0)
const beforeUpload = async (file) => {
    if (isFileSize(file?.size, props.size)) {
        beforeFileNum.value++
        spinShow.value = true
        return true
    } else {
        window?.$message?.warning(`文件大小, 不能过${props.size}M!`)
        return false
    }
}

//超出限制时
const uploadExceed = (files) => {
    //上传一个文件时，重置
    if (props.limit === 1) {
        uploadRef.value?.clearFiles()
        const file = files[0]
        file.uid = genFileId()
        uploadRef.value?.handleStart(file)
    } else {
        window?.$message?.warning(`请上传 ${props.accept} 格式的文件，文件大小不超过${props.size}M`)
    }
}

//上传中
const uploadprogress = () => {
    uploadDisabled.value = true
    emit('progress', true)
}

//上传完成
const finishFileNum = ref(0)
const uploadSuccess = (response, uploadFile, uploadFiles) => {
    finishFileNum.value++
    if (beforeFileNum.value === finishFileNum.value) {
        let fileList = getUploadFileList(uploadFiles)
        uploadClearFiles()
        emit('change', { type: 'success', fileList })
        emit('progress', false)
    }
}

//上传失败
const errorFileNum = ref(0)
const uploadError = () => {
    errorFileNum.value++
    window?.$message?.error('上传失败')
    const num = finishFileNum.value + errorFileNum.value
    if (beforeFileNum.value === num) {
        let fileList = getUploadFileList(fileListData.value)
        uploadClearFiles()
        emit('change', { type: 'error', fileList })
        emit('progress', false)
    }
}

const uploadClearFiles = () => {
    finishFileNum.value = 0
    beforeFileNum.value = 0
    errorFileNum.value = 0
    spinShow.value = false
    uploadDisabled.value = false
}

//获取文件URL
const getUploadFileList = (fileListArr) => {
    let fileArr = [], fileList = fileListArr ?? []
    fileList.forEach(item => {
        if (getObjVal(item?.response)) {
            const data = getObjValue(item?.response?.data)
            fileArr.push({
                ...data,
                url: data['link'],
                name: data['originalName'],
            })
        } else {
            fileArr.push(item)
        }
    })
    return fileArr
}


//预览
const showViewer = ref(false)
const initialIndex = ref(-1)
const previewFileList = ref([])
const uploadPreview = (file) => {
    let fileArr = getUploadFileUrl()
    const fileList = fileListData.value ?? []
    const index = arrIndex(fileList, 'uid', file?.uid)
    if (props.viewer) {
        previewFileList.value = fileArr
        initialIndex.value = index
        showViewer.value = true
    } else {
        emit('preview', { index, fileArr, fileList })
    }
}

//获取文件URL
const getUploadFileUrl = () => {
    let fileArr = [], fileList = fileListData.value ?? []
    fileList.forEach(item => {
        if (getObjVal(item?.response)) {
            fileArr.push(item?.response?.data?.link)
        } else {
            fileArr.push(item?.url)
        }
    })
    return fileArr
}

//删除文件
const uploadRemove = (row) => {
    let link
    if (getObjVal(row?.response)) {
        link = row?.response?.data?.link
    } else {
        link = row?.url
    }
    emit('del', { link, row, fileList: fileListData.value })
}
</script>

<style lang="scss">
.hc-uploads-box .el-upload-list .el-upload-list__item {
    .el-upload-list__item-status-label, .el-icon--close-tip {
        display: none;
    }
}
</style>
