<template>
	<el-dialog title="选择文件" v-model="visible" :width="900" destroy-on-close @closed="$emit('closed')"
			   append-to-body>
		<div class="pi-file-select">
			<div class="pi-file-select__side" v-loading="menuLoading">
				<div class="pi-file-select__side-menu">
					<el-tree ref="menuRef" class="menu" :data="menu" :node-key="treeProps.key" :props="treeProps"
							 :expand-on-click-node="false" check-strictly show-checkbox
							 :current-node-key="menu.length>0?menu[0][treeProps.key]:''" highlight-current
							 @node-click="groupClick" :check-on-click-leaf="false">
						<template #default="{ node, data }">
							<span class="custom-tree-node el-tree-node__label">
								<span class="label">
									{{ node.label }}
								</span>
								<span class="do">
									<el-icon v-if="data.category_id != 0" @click.stop="editCategory(data)"><el-icon-edit/></el-icon>
								</span>
							</span>
						</template>
					</el-tree>
				</div>
				<div class="pi-file-select__side-msg">
					<el-button type="primary" size="small" icon="el-icon-plus" @click="addCategory"></el-button>
					<el-button type="danger" size="small" plain icon="el-icon-delete" @click="delCategory"></el-button>
				</div>
			</div>
			<div class="pi-file-select__files" v-loading="listLoading">
				<div class="pi-file-select__top">
					<div class="upload" v-if="!hideUpload">
						<el-upload class="pi-file-select__upload" action="" multiple :show-file-list="false"
								   :accept="accept" :on-change="uploadChange" :before-upload="uploadBefore"
								   :on-progress="uploadProcess" :on-success="uploadSuccess" :on-error="uploadError"
								   :http-request="uploadRequest">
							<el-button type="primary" icon="el-icon-upload">本地上传</el-button>
						</el-upload>
						<el-button type="danger" icon="el-icon-delete" @click="delFile">删除</el-button>
						<el-button type="primary" icon="el-icon-rank" @click="moveFile">移动</el-button>
					</div>
					<div class="keyword">
						<el-input v-model="file_name" style="width: 220px;" prefix-icon="el-icon-search"
								  placeholder="文件名搜索" clearable @keyup.enter="search" @input="search"
								  @clear="search"></el-input>
					</div>
				</div>
				<div class="pi-file-select__list">
					<el-scrollbar ref="scrollbarRef">
						<el-empty v-if="fileList.length==0 && data.length==0" description="无数据"
								  :image-size="80"></el-empty>
						<div v-for="(file, index) in fileList" :key="index" class="pi-file-select__item">
							<div class="pi-file-select__item__file">
								<div class="pi-file-select__item__upload">
									<el-progress type="circle" :percentage="file.progress" :width="70"></el-progress>
								</div>
								<el-image :src="file.tempImg" fit="contain"></el-image>
							</div>
							<p>{{ file.name }}</p>
						</div>
						<div v-for="item in data" :key="item[fileProps.id]" class="pi-file-select__item"
							 :class="{active: active(item) }" @click="select(item)">
							<div class="pi-file-select__item__file">
								<div class="pi-file-select__item__checkbox" v-if="multiple">
									<el-icon>
										<el-icon-check/>
									</el-icon>
								</div>
								<div class="pi-file-select__item__select" v-else>
									<el-icon>
										<el-icon-check/>
									</el-icon>
								</div>
								<div class="pi-file-select__item__box"></div>
								<el-image v-if="obj.isImg(item[fileProps.url])"
										  :src="config.API_URL + '/' + item[fileProps.url]" fit="contain"
										  lazy></el-image>
								<div v-else-if="obj.isVideo(item[fileProps.url])" class="item-video">
									<el-icon size="32px">
										<component :is="'pi-icon-video'"/>
									</el-icon>
								</div>
								<div v-else class="item-file item-file-doc">
									<el-icon size="32px">
										<component :is="'pi-icon-task'"/>
									</el-icon>
								</div>
							</div>
							<p :title="item[fileProps.fileName]">{{ item[fileProps.fileName] }}</p>
						</div>
					</el-scrollbar>
				</div>
				<div class="pi-file-select__pagination">
					<el-pagination size="small" background layout="prev, pager, next" :total="total"
								   :page-size="pageSize"
								   v-model:currentPage="currentPage" @current-change="reload"></el-pagination>
				</div>
				<div class="pi-file-select__do">
					<div><span v-if="multiple">已选择 <b>{{ value.length }}</b> / <b>{{ max }}</b> 项</span></div>
					<el-button type="primary" :disabled="value.length<=0" @click="submit">确 定</el-button>
				</div>
			</div>
		</div>
		<save-dialog v-if="dialog.save" ref="saveRef" @success="getMenu" @closed="dialog.save=false"></save-dialog>
		<move-dialog v-if="dialog.move" ref="moveRef" @success="moveSuccess"
					 @closed="dialog.move=false"></move-dialog>
	</el-dialog>
</template>

<script setup>
import assetConfig from "@/config/asset"
import saveDialog from "./save.vue";
import moveDialog from "./move.vue";
import * as imageConversion from 'image-conversion';
import {ref, onMounted, nextTick, getCurrentInstance} from "vue"
import tools from "@/utils/tools"
import config from "@/config"

defineExpose({
	open
})

const emit = defineEmits(['success', 'closed'])
const props = defineProps({
	hideUpload: {type: Boolean, default: false},
	multiple: {type: Boolean, default: false},
	max: {type: Number, default: assetConfig.max},
	maxSize: {type: Number, default: assetConfig.maxSize},
	type: {type: String, default: "image"}
})
const {proxy} = getCurrentInstance()
const saveRef = ref(null)
const moveRef = ref(null)
const scrollbarRef = ref(null)
const menuRef = ref(null)

let dialog = ref({
	save: false,
	move: false
})
let file_name = ref(null)
let pageSize = ref(20)
let total = ref(0)
let currentPage = ref(1)
let data = ref([])
let menu = ref([])
let category_id = ref(0)
let value = ref(props.multiple ? [] : '')
let fileList = ref([])
let accept = ref(assetConfig.fileType(props.type)['accept'])
let listLoading = ref(false)
let menuLoading = ref(false)
let treeProps = ref(assetConfig.menuProps)
let fileProps = ref(assetConfig.fileProps)
let visible = ref(false)
let obj = ref(assetConfig)

onMounted(() => {
	getMenu()
	getData()
})

async function open() {
	visible.value = true;
}

async function getMenu() {
	menuLoading.value = true
	const res = await assetConfig.menuListObj({type: props.type});
	menu.value = tools.makeTreeData(res.data, 0, "category_id")
	menu.value.unshift({
		'category_id': 0,
		'category_name': '未分类',
		'parent_id': 0
	})
	menuLoading.value = false
}

async function getData() {
	listLoading.value = true
	const reqData = {
		[assetConfig.request.menuKey]: category_id.value,
		[assetConfig.request.page]: currentPage.value,
		[assetConfig.request.pageSize]: pageSize.value,
	};
	reqData.type = props.type
	reqData.ori_name = file_name.value
	const res = await assetConfig.fileListObj(reqData);
	const parseData = assetConfig.listParseData(res);
	data.value = parseData.rows
	total.value = parseData.total
	listLoading.value = false
}

function groupClick(data) {
	category_id.value = data.category_id
	currentPage.value = 1
	file_name.value = null
	getData()
}

function reload() {
	getData()
}

function search() {
	currentPage.value = 1
	getData()
}

function active(item) {
	if (props.multiple) {
		let choice = false;
		value.value.forEach(i => {
			if (i[assetConfig.fileProps.id] === item[assetConfig.fileProps.id]) {
				choice = true
			}
		})
		return choice
	} else {
		return value.value[assetConfig.fileProps.id] === item[assetConfig.fileProps.id]
	}
}

function select(item) {
	if (props.multiple) {
		if (value.value.length >= props.max) {
			proxy.$message.error("选择文件过多")
			return;
		}
		if (active(item)) {
			value.value.splice(value.value.findIndex(f => f[assetConfig.fileProps.id] === item[assetConfig.fileProps.id]), 1)
		} else {
			value.value.push(item)
		}
	} else {
		if (value.value[assetConfig.fileProps.id] === item[assetConfig.fileProps.id]) {
			value.value = ''
		} else {
			value.value = item
		}
	}
}

function submit() {
	if (props.multiple) {
		emit('success', value.value.map(i => i[assetConfig.fileProps.url]));
	} else {
		emit('success', value.value[assetConfig.fileProps.url]);
	}
	visible.value = false
}

async function delFile() {
	const _value = JSON.parse(JSON.stringify(value.value))
	const ids = props.multiple ? _value.map(i => i[assetConfig.fileProps.id]) : [_value[assetConfig.fileProps.id]];
	if (!ids) return;
	const res = await assetConfig.delFileObj({ids: ids});
	// 删除文件成功，取消选择
	value.value = props.multiple ? [] : ''
	proxy.$message.success(res.msg)
	getData()
}

function moveFile() {
	dialog.value.move = true
	nextTick(() => {
		moveRef.value.open(menu.value)
	})
}

async function moveSuccess(category_id) {
	const _value = JSON.parse(JSON.stringify(value.value))
	const ids = props.multiple ? _value.map(i => i[assetConfig.fileProps.id]) : [_value[assetConfig.fileProps.id]];
	if (!ids) return;
	const res = await assetConfig.moveFileObj({ids: ids, category_id: category_id});
	proxy.$message.success(res.msg)
	// 清空选中值
	value.value = props.multiple ? [] : ''
	getData()
}

function uploadChange(file, _fileList) {
	file.tempImg = URL.createObjectURL(file.raw);
	fileList.value = _fileList
}

function uploadBefore(file) {
	const fileSize = file.size / 1024;
	if (assetConfig.isImg(file.name) && fileSize > 800) {
		return new Promise((resolve) => {
			imageConversion.compressAccurately(file, 800).then((res) => {
				resolve(res);
			});
		});
	} else {
		if (fileSize > props.maxSize * 1024) {
			proxy.$message.warning(`上传文件大小不能超过 ${props.maxSize}MB!`);
			return false;
		}
	}
}

function uploadRequest(param) {
	// 获取文件类型
	const _type = assetConfig.getType(param.file.name)
	if (props.type !== "" && proxy.type !== _type) {
		proxy.$message.warning(`不允许的文件类型!`);
		clearFiles(param.file)
		return false
	}
	const data = new FormData();
	data.append("file", param.file);
	if (category_id.value) {
		data.append(assetConfig.request.menuKey, category_id.value);
	}
	assetConfig.uploadObj(data, {
		onUploadProgress: e => {
			param.onProgress(e)
		}
	}).then(res => {
		param.onSuccess(res)
	}).catch(err => {
		param.onError(err)
	})
}

function uploadProcess(event, file) {
	file.progress = Number((event.loaded / event.total * 100).toFixed(2))
}

function clearFiles(file) {
	fileList.value.splice(fileList.value.findIndex(f => f.uid == file.uid), 1)
}

function uploadSuccess(res, file) {
	fileList.value.splice(fileList.value.findIndex(f => f.uid == file.uid), 1)
	var response = assetConfig.uploadParseData(res);
	data.value.unshift(response)
	if (!props.multiple) {
		value.value = response
	}
}

function uploadError(err) {
	proxy.$notify.error({
		title: '上传文件错误',
		message: err
	})
}

function editCategory(data) {
	dialog.value.save = true
	nextTick(() => {
		saveRef.value.setType(props.type).setMenu(menu.value).open('edit', data)
	})
}

function addCategory() {
	dialog.value.save = true
	nextTick(() => {
		saveRef.value.setType(props.type).setMenu(menu.value).open('add', null, menuRef.value.getCurrentKey())
	})
}

async function delCategory() {
	var CheckedNodes = menuRef.value.getCheckedNodes()
	if (CheckedNodes.length === 0) {
		proxy.$message.warning("请选择需要删除的项")
		return false;
	}
	var confirm = await proxy.$confirm('确认删除已选择的菜单吗？', '提示', {
		type: 'warning',
		confirmButtonText: '删除',
		cancelButtonText: '取消',
		confirmButtonClass: 'el-button--danger'
	}).catch(() => {
	})
	if (confirm !== 'confirm') {
		return false
	}
	menuLoading.value = true
	var res = await assetConfig.menuDelObj({ids: CheckedNodes.map(item => item.category_id)})
	menuLoading.value = false
	proxy.$message.success(res.msg)
	CheckedNodes.forEach(item => {
		var node = menuRef.value.getNode(item)
		if (node == null) {
			reload()
		}
		menuRef.value.remove(item)
	})
}

</script>


<style scoped>
.pi-file-select {
	display: flex;
}

.pi-file-select__files {
	flex: 1;
}

.pi-file-select__list {
	height: 400px;
}

.pi-file-select__item {
	display: inline-block;
	float: left;
	margin: 0 15px 25px 0;
	width: 110px;
	cursor: pointer;
}

.pi-file-select__item__file {
	width: 110px;
	height: 110px;
	position: relative;
}

.pi-file-select__item__file .el-image {
	width: 110px;
	height: 110px;
}

.pi-file-select__item__box {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	border: 2px solid var(--el-color-success);
	z-index: 1;
	display: none;
}

.pi-file-select__item__box::before {
	content: '';
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	background: var(--el-color-success);
	opacity: 0.2;
	display: none;
}

.pi-file-select__item:hover .pi-file-select__item__box {
	display: block;
}

.pi-file-select__item.active .pi-file-select__item__box {
	display: block;
}

.pi-file-select__item.active .pi-file-select__item__box::before {
	display: block;
}

.pi-file-select__item p {
	margin-top: 10px;
	white-space: nowrap;
	text-overflow: ellipsis;
	overflow: hidden;
	-webkit-text-overflow: ellipsis;
	text-align: center;
}

.pi-file-select__item__checkbox {
	position: absolute;
	width: 20px;
	height: 20px;
	top: 7px;
	right: 7px;
	z-index: 2;
	background: rgba(0, 0, 0, 0.2);
	border: 1px solid #fff;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.pi-file-select__item__checkbox i {
	font-size: 14px;
	color: #fff;
	font-weight: bold;
	display: none;
}

.pi-file-select__item__select {
	position: absolute;
	width: 20px;
	height: 20px;
	top: 0px;
	right: 0px;
	z-index: 2;
	background: var(--el-color-success);
	display: none;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.pi-file-select__item__select i {
	font-size: 14px;
	color: #fff;
	font-weight: bold;
}

.pi-file-select__item.active .pi-file-select__item__checkbox {
	background: var(--el-color-success);
}

.pi-file-select__item.active .pi-file-select__item__checkbox i {
	display: block;
}

.pi-file-select__item.active .pi-file-select__item__select {
	display: flex;
}

.pi-file-select__item__file .item-file {
	width: 110px;
	height: 110px;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.pi-file-select__item__file .item-file i {
	font-size: 40px;
}

.pi-file-select__item__file .item-file.item-file-doc {
	color: #409eff;
}

.pi-file-select__item .item-video {
	width: 110px;
	height: 110px;
	overflow: hidden;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.pi-file-select__item .item-video video {
	width: 110px;
	object-fit: cover;
}

.pi-file-select__item__upload {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 1;
	background: rgba(255, 255, 255, 0.7);
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.pi-file-select__side {
	width: 200px;
	margin-right: 15px;
	border-right: 1px solid rgba(128, 128, 128, 0.2);
	display: flex;
	flex-flow: column;
}

.pi-file-select__side-menu {
	flex: 1;
}

.pi-file-select__side-msg {
	height: 32px;
	line-height: 32px;
}

.pi-file-select__top {
	margin-bottom: 15px;
	display: flex;
	justify-content: space-between;
}

.pi-file-select__upload {
	display: inline-block;
}

.pi-file-select__top .tips {
	font-size: 12px;
	margin-left: 10px;
	color: #999;
}

.pi-file-select__top .tips i {
	font-size: 14px;
	margin-right: 5px;
	position: relative;
	bottom: -0.125em;
}

.pi-file-select__pagination {
	margin: 15px 0;
}

.pi-file-select__do {
	display: flex;
	justify-content: space-between;
	align-items: center;
}

.custom-tree-node {
	display: flex;
	flex: 1;
	align-items: center;
	justify-content: space-between;
	font-size: 14px;
	padding-right: 24px;
	height: 100%;
}

.custom-tree-node .label {
	display: flex;
	align-items: center;;
	height: 100%;
}

.custom-tree-node .label .el-tag {
	margin-left: 5px;
}

.custom-tree-node .do {
	display: none;
}

.custom-tree-node .do i {
	margin-left: 5px;
	color: #999;
}

.custom-tree-node .do i:hover {
	color: #333;
}

.custom-tree-node:hover .do {
	display: inline-block;
}

:deep(.el-upload) {
	display: block;
	margin-right: 12px;
}
</style>
