<template>
	<div class="pi-upload-multiple">
		<el-upload ref="uploaderRef" list-type="picture-card"
				   :auto-upload="autoUpload"
				   :disabled="disabled"
				   :action="action"
				   :name="name"
				   :data="data"
				   :http-request="request"
				   v-model:file-list="defaultFileList"
				   :show-file-list="showFileList"
				   :accept="accept"
				   :multiple="multiple"
				   :limit="limit"
				   :before-upload="before"
				   :on-success="success"
				   :on-error="error"
				   :on-preview="handlePreview"
				   :on-exceed="handleExceed">
			<slot>
				<el-icon><el-icon-plus/></el-icon>
			</slot>
			<template #tip>
				<div v-if="tip" class="el-upload__tip">{{tip}}</div>
			</template>
			<template #file="{ file }">
				<div class="pi-upload-list-item">
					<el-image class="el-upload-list__item-thumbnail" :src="file.url" fit="cover" :preview-src-list="preview" :initial-index="preview.findIndex(n=>n==file.url)" hide-on-click-modal append-to-body :z-index="9999">
						<template #placeholder>
							<div class="pi-upload-multiple-image-slot">
								Loading...
							</div>
						</template>
					</el-image>
					<div v-if="!disabled && file.status=='success'" class="pi-upload__item-actions">
						<span class="del" @click="handleRemove(file)"><el-icon><el-icon-delete /></el-icon></span>
					</div>
					<div v-if="file.status=='ready' || file.status=='uploading'" class="pi-upload__item-progress">
						<el-progress :percentage="file.percentage" :text-inside="true" :stroke-width="16"/>
					</div>
				</div>
			</template>
		</el-upload>
		<span style="display:none!important"><el-input v-model="value"></el-input></span>
	</div>
</template>

<script setup>
import config from "@/config/upload"
import Sortable from 'sortablejs'
import {ref, getCurrentInstance, watch, computed, onMounted} from "vue"

const emit = defineEmits(['update:modelValue'])
const {proxy} = getCurrentInstance()
const uploaderRef = ref(null)

const props = defineProps({
	modelValue: { type: [String, Array], default: "" },
	tip: { type: String, default: "" },
	action: { type: String, default: "" },
	apiObj: { type: Object, default: () => {} },
	name: { type: String, default: config.filename },
	data: { type: Object, default: () => {} },
	accept: { type: String, default: "image/gif, image/jpeg, image/png" },
	maxSize: { type: Number, default: config.maxSizeFile },
	limit: { type: Number, default: 0 },
	autoUpload: { type: Boolean, default: true },
	showFileList: { type: Boolean, default: true },
	multiple: { type: Boolean, default: true },
	disabled: { type: Boolean, default: false },
	draggable: { type: Boolean, default: false },
	onSuccess: { type: Function, default: () => { return true } }
})

let value = ref("")
let defaultFileList = ref([])

watch(() => props.modelValue, (val) => {
	if(Array.isArray(val)){
		if (JSON.stringify(val) != JSON.stringify(formatArr(defaultFileList.value))) {
			defaultFileList.value = val
			value.value = val
		}
	}else{
		if (val != toStr(defaultFileList.value)) {
			defaultFileList.value = toArr(val)
			value.value = val
		}
	}
})

watch(defaultFileList, (val) => {
	emit('update:modelValue', Array.isArray(props.modelValue) ? formatArr(val) : toStr(val))
	value.value = toStr(val)
}, {deep: true})

const preview = computed(() => {
	return defaultFileList.value.map(v => v.url)
})

onMounted(() => {
	if (props.modelValue) {
		defaultFileList.value = Array.isArray(props.modelValue) ? props.modelValue : toArr(props.modelValue)
	}
	value.value = props.modelValue
	if(!props.disabled && props.draggable){
		rowDrop()
	}
})

//默认值转换为数组
function toArr(str){
	var _arr = [];
	var arr = str.split(",");
	arr.forEach(item => {
		if(item){
			var urlArr = item.split('/');
			var fileName = urlArr[urlArr.length - 1]
			_arr.push({
				name: fileName,
				url: item
			})
		}
	})
	return _arr;
}

//数组转换为原始值
function toStr(arr){
	return arr.map(v => v.url).join(",")
}

//格式化数组值
function formatArr(arr){
	var _arr = []
	arr.forEach(item => {
		if(item){
			_arr.push({
				name: item.name,
				url: item.url
			})
		}
	})
	return _arr
}

//拖拽
function rowDrop(){
	const itemBox = uploaderRef.value.$el.querySelector('.el-upload-list')
	Sortable.create(itemBox, {
		handle: ".el-upload-list__item",
		animation: 200,
		ghostClass: "ghost",
		onEnd({ newIndex, oldIndex }) {
			const tableData = defaultFileList.value
			const currRow = tableData.splice(oldIndex, 1)[0]
			tableData.splice(newIndex, 0, currRow)
		}
	})
}

function before(file){
	if(!['image/jpeg','image/png','image/gif'].includes(file.type)){
		proxy.$message.warning(`选择的文件类型 ${file.type} 非图像类文件`);
		return false;
	}
	const maxSize = file.size / 1024 / 1024 < props.maxSize;
	if (!maxSize) {
		proxy.$message.warning(`上传文件大小不能超过 ${props.maxSize}MB!`);
		return false;
	}
}

function success(res, file){
	var os = props.onSuccess(res, file)
	if(os!=undefined && os==false){
		return false
	}
	var response = config.parseData(res)
	file.name = response.src
	file.url = response.src
}

function error(err){
	proxy.$notify.error({
		title: '上传文件未成功',
		message: err
	})
}

function beforeRemove(uploadFile){
	return proxy.$confirm(`是否移除 ${uploadFile.name} ?`, '提示', {
		type: 'warning',
	}).then(() => {
		return true
	}).catch(() => {
		return false
	})
}

function handleRemove(file){
	uploaderRef.value.handleRemove(file)
	//this.defaultFileList.splice(this.defaultFileList.findIndex(item => item.uid===file.uid), 1)
}

function handleExceed(){
	proxy.$message.warning(`当前设置最多上传 ${props.limit} 个文件，请移除后上传!`)
}

function handlePreview(uploadFile){
	window.open(uploadFile.url)
}

function request(param){
	var apiObj = config.apiObj;
	if(props.apiObj){
		apiObj = props.apiObj;
	}
	const data = new FormData();
	data.append(param.filename, param.file);
	for (const key in param.data) {
		data.append(key, param.data[key]);
	}
	apiObj(data, {
		onUploadProgress: e => {
			const complete = parseInt(((e.loaded / e.total) * 100) | 0, 10)
			param.onProgress({percent: complete})
		}
	}).then(res => {
		var response = config.parseData(res);
		if(response.code == config.successCode){
			param.onSuccess(res)
		}else{
			param.onError(response.msg || "未知错误")
		}
	}).catch(err => {
		param.onError(err)
	})
}
</script>

<style scoped>
.el-form-item.is-error .pi-upload-multiple:deep(.el-upload--picture-card) {border-color: var(--el-color-danger);}
:deep(.el-upload-list__item) {transition:none;border-radius: 0;}
.pi-upload-multiple:deep(.el-upload-list__item.el-list-leave-active) {position: static!important;}
.pi-upload-multiple:deep(.el-upload--picture-card) {border-radius: 0;}
.pi-upload-list-item {width: 100%;height: 100%;position: relative;}
.pi-upload-multiple .el-image {display: block;}
.pi-upload-multiple .el-image:deep(img) {-webkit-user-drag: none;}
.pi-upload-multiple-image-slot {display: flex;justify-content: center;align-items: center;width: 100%;height: 100%;font-size: 12px;}
.pi-upload-multiple .el-upload-list__item:hover .pi-upload__item-actions{display: block;}
.pi-upload__item-actions {position: absolute;top:0;right: 0;display: none;}
.pi-upload__item-actions span {display: flex;justify-content: center;align-items: center;;width: 25px;height:25px;cursor: pointer;color: #fff;}
.pi-upload__item-actions span i {font-size: 12px;}
.pi-upload__item-actions .del {background: #F56C6C;}
.pi-upload__item-progress {position: absolute;width: 100%;height: 100%;top: 0;left: 0;background-color: var(--el-overlay-color-lighter);}
</style>
