<template>
	<div v-if="flag" class="upload-box">
		<!-- 遮罩层 -->
		<div v-if="isShowPanel" :style="{ height: pageHeight, width: pageWidth, opacity: panelOpacity }" class="circle-mask-panel">
			<div v-if="uploadFile" class="circle-panel">
				<a-progress v-if="!isError && uploadFile.status !== 'done'" :percent="uploadFile.percent" type="circle">
					<template #format="percent">
						<span>{{ percent.toFixed(0) }}%</span>
					</template>
				</a-progress>
				<a-progress v-if="uploadFile.status === 'done'" :percent="100" strokeColor="#5cb85c" type="circle">
					<template>
						<check-outlined :style="{ fontSize: '60px', color: '#5cb85c' }" />
					</template>
				</a-progress>
				<a-progress v-if="isError" :percent="uploadFile.percent" strokeColor="#ff5500" type="circle">
					<template>
						<close-outlined :style="{ fontSize: '60px', color: '#ff5500' }" />
					</template>
				</a-progress>
				<div style="text-align: center; margin-top: 5px; font-size: 1.25rem">
					<span style="font-size: 0.875rem">已使用 {{ useTime?.time }} 秒</span>
					<br />
					{{ showText }} {{ ['.', '..', '...'][useTime?.time % 3] }}
				</div>
			</div>
		</div>
		<!-- 宫格图片上传 -->
		<div class="clearfix">
			<a-upload
				v-model:file-list="fileList"
				:accept="props.uploadAccept"
				:action="props.action"
				:before-upload="beforeUpload"
				:headers="headers"
				:list-type="props.uploadListType"
				:showUploadList="props.showUploadList"
				@change="handleChange"
				@preview="handlePreview"
			>
				<div v-if="fileList.length < props.uploadMaxSize">
					<plus-outlined v-if="props.uploadListType !== 'text'" />
					<div>
						<a-button
							:icon="props.btnIcon"
							:size="props.btnSize"
							:style="{ color: props.textColor, fontSize: props.btnTextSize }"
							:type="props.btnType"
							class="ant-upload-text"
							>{{ props.btnText }}
						</a-button>
					</div>
				</div>
			</a-upload>
			<a-modal :footer="null" :visible="previewVisible" :z-index="99999" @cancel="handleCancel">
				<img :src="previewImage" alt="预览图片" style="width: 100%" />
			</a-modal>
		</div>
	</div>
</template>
<script lang="ts" setup>
import { CheckOutlined, CloseOutlined, PlusOutlined } from '@ant-design/icons-vue'
import { computed, nextTick, onMounted, reactive, ref, watch, withDefaults } from 'vue'
import type { UploadChangeParam } from 'ant-design-vue'
import { messageMethod } from '../utils/message-util'
import { useSystemStore } from '../store/system'
import { TimeCountModel } from '../utils/datetime-util'
import { BaseUtil } from '../utils/base-util'
import { ResultModel } from '../http/result-model'
import { UploadFile } from './form-item/props'
import { LogFile } from '../entity/system-log/log-file'

interface FileUpload {
	id?: string
	url?: string
}

export interface BaseUploadProps {
	value?: Array<FileUpload>
	// 请求api
	action?: string
	// 按钮描述文字
	btnText?: string
	// 文字大小
	btnTextSize?: string
	// 按钮大小 large | middle | small
	btnSize?: string
	// 按钮图标
	btnIcon?: string
	// 按钮类型 primary | ghost | dashed | link | text | default
	btnType?: string
	// 文本颜色
	textColor?: string
	// 上传提示
	isMessage?: boolean
	// 上传列表类型 text ｜ picture ｜ picture-card
	uploadListType?: string
	// 接受上传的文件类型
	uploadAccept?: string
	// 文件上传大小限制（单位M）
	uploadFileSize?: number
	// 文件上传数量
	uploadMaxSize?: number
	// 是否支持多选文件
	isUploadMultiple?: boolean
	// 是否展示 uploadList
	showUploadList?: boolean | object
	// 已上传文件列表
	uploadList?: Array<UploadFile>
}

const props = withDefaults(defineProps<BaseUploadProps>(), {
	value: () => [],
	action: import.meta.env.VITE_APP_API_OSS || '/api/logFile/upload',
	btnText: '上传文件',
	btnSize: 'middle',
	btnType: 'link',
	isMessage: true,
	textColor: '#000',
	uploadListType: 'picture-card',
	// uploadAccept: '.docx',
	uploadFileSize: 10,
	uploadMaxSize: 9,
	isUploadMultiple: false,
	uploadList: () => [],
	showUploadList: true
})

// 请求头
const headers = reactive({
	authToken: '',
	submitKey: BaseUtil.uuid()
})
// 页面高度
const pageHeight = ref<string>(window.innerHeight + 'px')

// 页面宽度
const pageWidth = ref<string>(window.innerWidth + 'px')

// 透明程度
const panelOpacity = ref<number>(0)

// 使用时间
const useTime = ref<TimeCountModel | null>(null)

// 是否显示面板
const isShowPanel = ref<boolean>(false)

// 是否错误
const isError = ref<boolean>(false)

// 是否开启预览
const previewVisible = ref<boolean>(false)

// 预览图片的src
const previewImage = ref<string | undefined>('')

// 文件列表
const fileList = ref<Array<UploadFile>>([])

// 当前上传文件 文件状态 uploading ｜ done ｜ error ｜ removed
const uploadFile = ref<UploadFile>()

// 提示文本
const showText = computed<string>(() => {
	let memoText = ''
	if (isError.value) {
		memoText = '上传失败'
	}
	if (!uploadFile.value || uploadFile.value.percent === 0) {
		memoText = '上传准备中'
	}
	if (uploadFile.value && (uploadFile.value?.percent || 0) < 100) {
		memoText = '上传中'
	}
	if (uploadFile.value && (uploadFile.value?.percent || 0) === 100) {
		memoText = '处理中'
	}
	if ((uploadFile.value?.status || 'uploading') === 'done') {
		memoText = '上传成功'
	}
	return memoText
})

/**
 * 开始计时
 */
const startLoop = () => {
	isShowPanel.value = true
	isError.value = false
	panelOpacity.value = 1

	useTime.value = new TimeCountModel({ isCountdown: false })
	useTime.value.start()
}

/**
 * 关闭面板（延时500毫秒）
 * @param time
 */
const closePanel = (time = 500) => {
	setTimeout(() => {
		useTime.value?.finish()
		isShowPanel.value = false
		panelOpacity.value = 0
	}, time)
}

/**
 * 文件上传前
 * @param file 文件
 */
const beforeUpload = (file: UploadFile) => {
	// 处理文件大小限制
	const isFileSize = props.uploadFileSize * 1024 * 1024 * 1024 > (file.size || 0)
	if (!isFileSize) {
		privateExceededSize()
		return isFileSize
	}
	startLoop()
	return isFileSize
}

/**
 * 关闭弹出层
 */
const handleCancel = () => {
	previewVisible.value = false
}
/**
 * 预览图片的回调
 * @param file 当前文件对象
 */
const handlePreview = async (file: UploadFile) => {
	file.url = baseImageName(file)
	previewImage.value = file.url || file.preview
	previewVisible.value = true
}

const emit = defineEmits<{
	(e: 'upload-success', file: ResultModel<LogFile>, fileList: Array<UploadFile>, ids: Array<string>, paths: Array<string>): void
	(e: 'remove-success', file: ResultModel<LogFile>, fileList: Array<UploadFile>, ids: Array<string>, paths: Array<string>): void
}>()

/**
 * 文件上传状态改变
 * @param file 当前文件对象
 * @param newFileList 文件列表对象
 */
const handleChange = ({ file, fileList: newFileList }: UploadChangeParam<UploadFile>) => {
	uploadFile.value = file
	// 状态为完成
	if (file.status === 'done') {
		// isShowPanel.value = false
		// panelOpacity.value = 0
		closePanel(500)

		file.url = baseImageName(file)
		fileList.value = newFileList as Array<UploadFile>
		// 返回全部ids
		const ids = newFileList.map(item => (item.response !== undefined ? item?.response?.data?.id : (item as unknown as LogFile).id))
		// 返回全部paths
		const paths = newFileList.map(item => (item.response !== undefined ? item?.response?.data?.uploadPath : (item as unknown as LogFile).uploadPath))
		const fileListNew = fileList.value.map(item => (item.response !== undefined ? item?.response : item)) as Array<UploadFile>
		if (file.response?.code == '00000') {
			emit('upload-success', file.response, fileListNew, ids, paths)
		} else {
			messageMethod.error(file.response?.message)
		}
	}
	// 状态为失败
	if (file.status === 'error') {
		privateError()
	}
	if (file.status === 'removed') {
		// 返回全部ids
		const ids = newFileList?.map(item => (item.response !== undefined ? item?.response?.data.id : (item as unknown as LogFile).id))
		// 返回全部paths
		const paths = newFileList?.map(item => (item.response !== undefined ? item?.response?.data.uploadPath : (item as unknown as LogFile).uploadPath))
		const fileListNew = newFileList?.map(item => (item.response !== undefined ? item?.response : item))
		if (file.response) emit('remove-success', file.response, fileListNew, ids, paths)
	}
}

/**
 * 上传错误时触发
 */
function privateError() {
	isError.value = true
	closePanel(0)
	messageMethod.error('文件上传失败')
}

/**
 * 文件超出大小触发
 */
function privateExceededSize() {
	closePanel(0)
	messageMethod.error(`文件超出${props.uploadFileSize}MB!`)
}

//
// /**
//  * 文件类型错误
//  */
// function privateFormatError() {
// 	closePanel(0)
// 	messageMethod.error('文件类型错误')
// }
/**
 * 格式化返回的图片地址
 * @param file 当前文件对象
 */
function baseImageName(file: UploadFile): string {
	if (file.response) {
		if (file.response.data) {
			return (file.url = BaseUtil.getUploadPath(file?.response?.data?.uploadPath))
		} else {
			return ''
		}
	} else {
		const tempFile = file as unknown as LogFile
		return (file.url = BaseUtil.getUploadPath(tempFile.url || tempFile.uploadPath))
	}
}

const flag = ref<boolean>(false)

/**
 * 挂载
 */
onMounted(() => {
	const systemStore = useSystemStore()
	headers.authToken = systemStore.token
	// 处理图片回现
	props.uploadList.forEach(item => {
		item.url = BaseUtil.getUploadPath(item.url ?? '')
	})
	fileList.value = props.uploadList
	flag.value = true
})

const listLength = computed(() => props.uploadList.length)

watch(listLength, () => {
	props.uploadList.forEach(item => {
		item.url = BaseUtil.getUploadPath(item.url ?? '')
	})
	fileList.value = props.uploadList
	flag.value = false
	nextTick(() => {
		flag.value = true
	})
})
</script>

<style lang="scss" scoped>
.upload-box {
	//display: inline-block;
}

:deep(.ant-upload-list-picture-card-container) {
	height: 104px !important;
}

.circle-mask-panel {
	position: fixed;
	background-color: rgba(255, 255, 255, 0.8);
	width: 200px;
	top: 0;
	left: 0;
	z-index: 5000;
	opacity: 0;
	transition: opacity 0.2s;
}

.circle-panel {
	position: absolute;
	left: 50%;
	top: 50%;
	margin-left: -60px;
	margin-top: -95px;

	span {
		font-size: 1.5rem;
	}
}
</style>
