<template>
	<div class="menu-form-com">
		<div class="menu-form-alert">
			1.红色星号表示必填;<br />
			2.添加菜单，如果是目录，组件地址为空即可;<br />
			3.添加根节点菜单，父级菜单为空即可;
		</div>
		<el-form ref="formRef" :rules="rules" :model="menuFormData" label-width="80px" label-position="right">
			<el-form-item label="菜单名称" prop="name">
				<el-input v-model="menuFormData.name" placeholder="请输入菜单名称" />
			</el-form-item>
			<el-form-item label="父级菜单" prop="parent">
				<el-tree-select v-model="menuFormData.parent" :props="defaultTreeProps" :data="deptDefaultList"
					:cache-data="props.cacheData" lazy check-strictly clearable :load="handleTreeLoad"
					placeholder="请选择父级菜单" style="width: 100%" />
			</el-form-item>

			<el-form-item label="路由地址" prop="web_path">
				<el-input v-model="menuFormData.web_path" placeholder="请输入路由地址，请以/开头" />
			</el-form-item>

			<el-form-item label="图标" prop="icon">
				<IconSelector clearable v-model="menuFormData.icon" />
			</el-form-item>

			<el-row>
				<el-col :span="12">
					<el-form-item required label="状态">
						<el-switch v-model="menuFormData.status" width="60" inline-prompt active-text="启用"
							inactive-text="禁用" />
					</el-form-item>
				</el-col>
				<el-col :span="12">
					<el-form-item v-if="menuFormData.status" required label="侧边显示">
						<el-switch v-model="menuFormData.visible" width="60" inline-prompt active-text="显示"
							inactive-text="隐藏" />
					</el-form-item>
				</el-col>
			</el-row>

			<el-row>
				<el-col :span="12">
					<el-form-item required label="是否目录">
						<el-switch v-model="menuFormData.is_catalog" width="60" inline-prompt active-text="是"
							inactive-text="否" />
					</el-form-item>
				</el-col>
				<el-col :span="12">
					<el-form-item v-if="!menuFormData.is_catalog" required label="外链接">
						<el-switch v-model="menuFormData.is_link" width="60" inline-prompt active-text="是"
							inactive-text="否" />
					</el-form-item>
				</el-col>
				<el-col :span="12">
					<el-form-item required v-if="!menuFormData.is_catalog" label="是否固定">
						<el-switch v-model="menuFormData.is_affix" width="60" inline-prompt active-text="是"
							inactive-text="否" />
					</el-form-item>
				</el-col>
				<el-col :span="12">
					<el-form-item v-if="!menuFormData.is_catalog && menuFormData.is_link" required label="是否内嵌">
						<el-switch v-model="menuFormData.is_iframe" width="60" inline-prompt active-text="是"
							inactive-text="否" />
					</el-form-item>
				</el-col>
			</el-row>

			<el-form-item label="备注">
				<el-input v-model="menuFormData.description" maxlength="200" show-word-limit type="textarea"
					placeholder="请输入备注" />
			</el-form-item>

			<el-divider></el-divider>

			<div style="min-height: 184px">
				<el-form-item v-if="!menuFormData.is_catalog && !menuFormData.is_link" label="组件地址" prop="component">
					<el-autocomplete class="w-full" v-model="menuFormData.component" :fetch-suggestions="querySearch"
						:trigger-on-focus="false" clearable :debounce="100" placeholder="输入组件地址" />
				</el-form-item>

				<el-form-item v-if="!menuFormData.is_catalog && !menuFormData.is_link" label="组件名称"
					prop="component_name">
					<el-input v-model="menuFormData.component_name" placeholder="请输入组件名称" />
				</el-form-item>

				<el-form-item v-if="!menuFormData.is_catalog && menuFormData.is_link" label="外链接" prop="link_url">
					<el-input v-model="menuFormData.link_url" placeholder="请输入外链接地址" />
				</el-form-item>

				<el-form-item v-if="!menuFormData.is_catalog" label="缓存">
					<el-switch v-model="menuFormData.cache" width="60" inline-prompt active-text="启用"
						inactive-text="禁用" />
				</el-form-item>
			</div>

			<el-divider></el-divider>
		</el-form>

		<div class="menu-form-btns">
			<el-button @click="handleSubmit" type="primary" :loading="menuBtnLoading">保存</el-button>
			<el-button @click="handleCancel">取消</el-button>
		</div>
	</div>
</template>

<script lang="ts" setup>
import XEUtils from 'xe-utils';
import { ref, onMounted, reactive } from 'vue';
import { ElForm, FormRules } from 'element-plus';
import IconSelector from '/@/components/iconSelector/index.vue';
import { lazyLoadMenu, AddObj, UpdateObj } from '../../api';
import { successNotification } from '/@/utils/message';
import { MenuFormDataType, MenuTreeItemType, ComponentFileItem, APIResponseData } from '../../types';
import type Node from 'element-plus/es/components/tree/src/model/node';

interface IProps {
	initFormData: Partial<MenuTreeItemType> | null;
	treeData: MenuTreeItemType[];
	cacheData: MenuTreeItemType[];
}

const defaultTreeProps: any = {
	children: 'children',
	label: 'name',
	value: 'id',
	isLeaf: (data: MenuTreeItemType[], node: Node) => {
		if (node?.data.hasChild) {
			return false;
		} else {
			return true;
		}
	},
};
const validateWebPath = (rule: any, value: string, callback: Function) => {
	let pattern = /^\/.*?/;
	const reg = pattern.test(value);
	if (reg) {
		callback();
	} else {
		callback(new Error('请输入正确的地址'));
	}
};

const validateLinkUrl = (rule: any, value: string, callback: Function) => {
	let pattern = /^\/.*?/;
	let patternUrl = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/;
	const reg = pattern.test(value) || patternUrl.test(value)
	if (reg) {
		callback();
	} else {
		callback(new Error('请输入正确的地址'));
	}
};

const props = withDefaults(defineProps<IProps>(), {
	initFormData: () => null,
	treeData: () => [],
	cacheData: () => [],
});
const emit = defineEmits(['drawerClose']);

const formRef = ref<InstanceType<typeof ElForm>>();

const rules = reactive<FormRules>({
	web_path: [{ required: true, message: '请输入正确的地址', validator: validateWebPath, trigger: 'blur' }],
	name: [{ required: true, message: '菜单名称必填', trigger: 'blur' }],
	component: [{ required: true, message: '请输入组件地址', trigger: 'blur' }],
	component_name: [{ required: true, message: '请输入组件名称', trigger: 'blur' }],
	link_url: [{ required: true, message: '请输入外链接地址', validator: validateLinkUrl, trigger: 'blur' }],
});

let deptDefaultList = ref<MenuTreeItemType[]>([]);
let menuFormData = reactive<MenuFormDataType>({
	parent: '',
	name: '',
	component: '',
	web_path: '',
	icon: '',
	cache: true,
	status: true,
	visible: true,
	component_name: '',
	description: '',
	is_catalog: false,
	is_link: false,
	is_iframe: false,
	is_affix: false,
	link_url: ''
});
let menuBtnLoading = ref(false);

const setMenuFormData = () => {
	if (props.initFormData?.id) {
		menuFormData.id = props.initFormData?.id || '';
		menuFormData.name = props.initFormData?.name || '';
		menuFormData.parent = props.initFormData?.parent || '';
		menuFormData.component = props.initFormData?.component || '';
		menuFormData.web_path = props.initFormData?.web_path || '';
		menuFormData.icon = props.initFormData?.icon || '';
		menuFormData.status = !!props.initFormData.status;
		menuFormData.visible = !!props.initFormData.visible;
		menuFormData.cache = !!props.initFormData.cache;
		menuFormData.component_name = props.initFormData?.component_name || '';
		menuFormData.description = props.initFormData?.description || '';
		menuFormData.is_catalog = !!props.initFormData.is_catalog;
		menuFormData.is_link = !!props.initFormData.is_link;
		menuFormData.is_iframe = !!props.initFormData.is_iframe;
		menuFormData.is_affix = !!props.initFormData.is_affix;
		menuFormData.link_url = props.initFormData.link_url;
	}
};

const querySearch = (queryString: string, cb: any) => {
	const files: any = import.meta.glob('@views/**/*.vue');
	let fileLists: Array<any> = [];
	Object.keys(files).forEach((queryString: string) => {
		fileLists.push({
			label: queryString.replace(/(\.\/|\.vue)/g, ''),
			value: queryString.replace(/(\.\/|\.vue)/g, ''),
		});
	});
	const results = queryString ? fileLists.filter(createFilter(queryString)) : fileLists;
	// 统一去掉/src/views/前缀
	results.forEach((val) => {
		val.label = val.label.replace('/src/views/', '');
		val.value = val.value.replace('/src/views/', '');
	});
	cb(results);
};

const createFilter = (queryString: string) => {
	return (file: ComponentFileItem) => {
		return file.value.toLowerCase().indexOf(queryString.toLowerCase()) !== -1;
	};
};

/**
 * 树的懒加载
 */
const handleTreeLoad = (node: Node, resolve: Function) => {
	if (node.level !== 0) {
		lazyLoadMenu({ parent: node.data.id }).then((res: APIResponseData) => {
			resolve(XEUtils.filter(res.data, (i: MenuTreeItemType) => i.is_catalog));
		});
	}
};

const handleSubmit = () => {
	if (!formRef.value) return;
	formRef.value.validate(async (valid) => {
		if (!valid) return;
		try {
			let res;
			menuBtnLoading.value = true;
			if (menuFormData.id) {
				res = await UpdateObj(menuFormData);
			} else {
				res = await AddObj(menuFormData);
			}
			if (res?.code === 2000) {
				successNotification(res.msg as string);
				handleCancel('submit');
			}
		} finally {
			menuBtnLoading.value = false;
		}
	});
};

const handleCancel = (type: string = '') => {
	emit('drawerClose', type);
	formRef.value?.resetFields();
};

/**
 * 初始化
 */
onMounted(async () => {
	props.treeData.map((item) => {
		if (item.is_catalog) {
			deptDefaultList.value.push(item);
		}
	});
	setMenuFormData();
});
</script>

<style lang="scss" scoped>
.menu-form-com {
	margin: 10px;
	overflow-y: auto;

	.menu-form-alert {
		color: #fff;
		line-height: 24px;
		padding: 8px 16px;
		margin-bottom: 20px;
		border-radius: 4px;
		background-color: var(--el-color-primary);
	}

	.menu-form-btns {
		padding-bottom: 10px;
		box-sizing: border-box;
	}
}
</style>
