<template>
	<div class="cl-user-select" @click="open()">
		<template v-if="!isEmpty(selection)">
			<template v-if="multiple">
				<cl-avatar
					v-for="(item, index) in selection"
					:key="index"
					:src="item.headImg"
					:size="24"
					class="mr-[5px]"
				/>
			</template>

			<template v-else>
				<cl-avatar :size="24" :src="selection[0]?.headImg"></cl-avatar>
				<span class="mr-auto ml-[6px]">{{ selection[0]?.[labelKey] }}</span>
			</template>

			<el-icon class="ml-auto" @click.stop="remove">
				<circle-close />
			</el-icon>
		</template>

		<span v-else class="placeholder">{{ placeholder || $t('请选择') }}</span>
	</div>

	<cl-dialog
		v-model="visible"
		:title="title || $t('选择成员')"
		:controls="['close']"
		width="600px"
	>
		<el-tabs v-model="tab.active" type="card">
			<el-tab-pane
				v-for="(item, index) in tab.list"
				:key="index"
				:label="item.label"
				:name="item.value"
			>
				<el-input
					:placeholder="$t('搜索名称')"
					v-model="keyWord"
					@input="onKeyWordChange"
				/>

				<el-scrollbar max-height="600px" class="scrollbar">
					<el-tree
						:ref="setRefs(`tree-${item.value}`)"
						node-key="id"
						:show-checkbox="multiple"
						:data="data[item.value]"
						:props="{
							label: 'name',
							class: data => {
								if (multiple) {
									return '';
								}

								if (!data.isUser) {
									return '';
								}

								return value.includes(data.id) ? 'is-selected' : '';
							}
						}"
						default-expand-all
						:filter-node-method="filterNode"
						@node-click="select"
					>
						<template #default="{ data }">
							<div class="cl-user-select__item">
								<cl-avatar
									class="mr-[6px]"
									:src="data.headImg"
									:size="24"
									v-if="data.isUser"
								/>

								<span class="select-none">{{ data.name }}</span>
							</div>
						</template>
					</el-tree>
				</el-scrollbar>
			</el-tab-pane>
		</el-tabs>

		<template #footer>
			<el-button @click="close">{{ $t('取消') }}</el-button>
			<el-button type="success" @click="confirm()">{{ $t('确定') }}</el-button>
		</template>
	</cl-dialog>
</template>

<script setup lang="ts">
defineOptions({
	name: 'cl-user-select'
});

import { computed, onMounted, reactive, ref, watch } from 'vue';
import { useCool } from '/@/cool';
import { deepTree } from '/@/cool/utils';
import { isEmpty, cloneDeep, isArray } from 'lodash-es';
import { ElMessage } from 'element-plus';
import { CircleClose } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
import { CrudProps } from '/#/crud';
import { useForm } from '@cool-vue/crud';

interface Item {
	name: string;
	isUser: boolean;
	[key: string]: any;
}

const props = defineProps({
	...CrudProps,
	modelValue: null,
	multiple: Boolean,
	placeholder: String,
	title: String,
	immediate: Boolean,
	labelKey: {
		type: String,
		default: 'nickName'
	},
	maxCollapse: {
		type: Number,
		default: 10
	}
});

const emit = defineEmits(['update:modelValue', 'change']);

const { service, refs, setRefs } = useCool();
const { t } = useI18n();
const Form = useForm();

// 绑定值
const value = ref<any[]>([]);

// 是否可见
const visible = ref(false);

// 搜索关键字
const keyWord = ref('');

// 选项
const tab = reactive({
	active: 'dept',

	list: [
		{
			label: t('按部门分组'),
			value: 'dept'
		},
		{
			label: t('按角色分组'),
			value: 'role'
		}
	]
});

// 数据
const data = reactive<{ [key: string]: Item[] }>({});

// 用户
const users = ref<Eps.BaseSysUserEntity[]>([]);

// 已选择
const selection = computed(() => {
	return users.value.filter(e => value.value.includes(e.id));
});

// 过滤节点
function filterNode(value: string, data: any) {
	if (!value) return true;
	return data.name.includes(value);
}

// 关键字改变
function onKeyWordChange() {
	refs[`tree-${tab.active}`].filter(keyWord.value);
}

// 获取用户
async function getUser() {
	return service.base.sys.user.page({ size: 10000 }).then(res => {
		users.value = res.list.map(e => {
			e.isUser = true;
			return e;
		});
	});
}

// 获取部门
async function getDept() {
	return service.base.sys.department.list().then(res => {
		res = deepTree(res);

		const deep = (arr: any[]) => {
			arr.forEach(e => {
				const list = users.value.filter(u => u.departmentId === e.id && u.id != 1);

				if (!e.children) {
					e.children = [];
				}

				e.children.push(...cloneDeep(list));

				if (e.children && !e.departmentId) {
					deep(e.children);
				}
			});
		};

		deep(res);

		data.dept = res as Item[];
	});
}

// 获取角色
async function getRole() {
	return service.base.sys.role.list().then(res => {
		res.forEach(e => {
			e.children = users.value.filter(u => u.roleIds.includes(e.id));
		});

		data.role = res as Item[];
	});
}

// 打开
async function open() {
	visible.value = true;
	keyWord.value = '';
	await refresh();

	tab.list.forEach(e => {
		refs[`tree-${e.value}`].setCheckedKeys(value.value);
	});
}

// 关闭
function close() {
	visible.value = false;
}

// 移除
function remove() {
	value.value = [];
	emit('update:modelValue', undefined);
	emit('change', undefined);
}

// 选择
function select(item: Item, node: any) {
	if (item.isUser) {
		if (props.multiple) {
			refs[`tree-${tab.active}`].setChecked(item, !node.checked, false);
		} else {
			value.value = [item.id];
			confirm();
		}
	}
}

// 确认
function confirm() {
	let v = value.value || [];

	if (props.multiple) {
		const tree = refs[`tree-${tab.active}`];
		const list: Eps.BaseSysUserEntity[] = tree.getCheckedNodes();
		v = list.filter(e => e.isUser).map(e => e.id!);
	}

	if (isEmpty(v)) {
		return ElMessage.warning(t('请选择成员'));
	}

	value.value = v;

	emit('update:modelValue', value.value);
	emit('change', selection.value);
	close();

	// 验证表单字段
	Form.value?.validateField(props.prop);
}

async function refresh() {
	await getUser();
	await getDept();
	await getRole();
}

onMounted(() => {
	if (props.immediate) {
		refresh();
	}

	watch(
		() => props.modelValue,
		val => {
			let v = val || [];

			if (!isArray(v)) {
				v = [v];
			}

			value.value = v;
		},
		{
			immediate: true
		}
	);
});

defineExpose({
	open,
	close
});
</script>

<style lang="scss" scoped>
.scrollbar {
	border: 1px solid var(--el-border-color);
	margin-top: 10px;
	border-radius: var(--el-border-radius-base);
	padding: 5px;

	:deep(.el-tree) {
		.el-tree-node {
			&.is-selected {
				.el-tree-node__content {
					background-color: var(--el-color-primary-light-9);
					color: var(--el-color-primary);
				}
			}
		}

		.el-tree-node__content {
			line-height: normal;
			height: 35px;
			border-radius: 6px;
		}
	}
}

.cl-user-select {
	display: flex;
	align-items: center;
	box-shadow: 0 0 0 1px var(--el-border-color) inset;
	border-radius: var(--el-border-radius-base);
	padding: 0 11px;
	min-height: 32px;
	cursor: pointer;
	position: relative;
	box-sizing: border-box;
	background-color: var(--el-bg-color);
	transition: var(--el-transition-duration);

	.placeholder {
		color: var(--el-text-color-placeholder);
	}

	&:hover {
		box-shadow: 0 0 0 1px var(--el-text-color-disabled) inset;
	}

	&__item {
		display: flex;
		align-items: center;
		width: 100%;

		.checked {
			color: var(--el-color-success);
			margin-left: auto;
			margin-right: 10px;
			font-size: 16px;
		}
	}
}
</style>
