143 lines
4.1 KiB
TypeScript
143 lines
4.1 KiB
TypeScript
import { ElButton, ElIcon, ElMenu, ElMenuItem, ElMenuItemGroup, ElSubMenu, type MenuItemRegistered } from "element-plus";
|
|
import { elIcons } from "@/common/element/element.ts";
|
|
import AIcon from "@/components/a-icon/AIcon.tsx";
|
|
import type { IconName } from "@/components/a-icon/iconfont.ts";
|
|
import styles from "@/pages/a-frame/aaside.module.styl";
|
|
|
|
export interface Menu extends G.TreeNode {
|
|
// Id
|
|
id: string;
|
|
// 编码
|
|
sn: string;
|
|
// 上级 Id; 层级为 1 的节点值为 0
|
|
pid: string;
|
|
// 菜单名称
|
|
title: string;
|
|
// 图标
|
|
icon: string;
|
|
// 层级; >= 1
|
|
tier: number;
|
|
// 排序
|
|
sort: number;
|
|
// 路由名称
|
|
routeName: string;
|
|
// 面包路径
|
|
breadcrumb: string[];
|
|
// 类型
|
|
menuCategory: "Catalog" | "Group" | "Page" | "SubPage" | "Btn";
|
|
// 子菜单
|
|
children?: Menu[];
|
|
}
|
|
|
|
export default defineComponent(
|
|
(props, { emit }) => {
|
|
let defaultId = "";
|
|
let path: any = props.defaultPath.split("/");
|
|
path = path[path.length - 1];
|
|
props.menus.forEach((item) => {
|
|
if (item.routeName == path) {
|
|
defaultId = item.id;
|
|
} else if (item.children && item.children.length) {
|
|
item.children.forEach((item2) => {
|
|
if (item2.routeName == path) {
|
|
defaultId = item2.id;
|
|
} else if (item2.children && item2.children.length) {
|
|
item2.children.forEach((item3) => {
|
|
if (item3.routeName == path) {
|
|
defaultId = item3.id;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
const onMenuClick = (it: MenuItemRegistered) => emit("menuClick", it.index);
|
|
const renderMenu = (it: Menu) => {
|
|
let renderChildNode: (() => VNode[] | undefined) | undefined = undefined;
|
|
if (it.children != null && it.children.length > 0) {
|
|
renderChildNode = () => it.children?.map(renderMenu);
|
|
}
|
|
let currentNode: VNode;
|
|
switch (it.menuCategory) {
|
|
case "Catalog": {
|
|
currentNode = (
|
|
<ElSubMenu index={it.id}>
|
|
{{
|
|
title: () => (
|
|
<>
|
|
<AIcon class={styles.aIcon} name={it.icon as IconName} />
|
|
<span>{it.title}</span>
|
|
</>
|
|
),
|
|
default: renderChildNode,
|
|
}}
|
|
</ElSubMenu>
|
|
);
|
|
break;
|
|
}
|
|
case "Group": {
|
|
currentNode = (
|
|
<ElMenuItemGroup title={it.title}>
|
|
{{
|
|
default: renderChildNode,
|
|
}}
|
|
</ElMenuItemGroup>
|
|
);
|
|
break;
|
|
}
|
|
case "Page": {
|
|
currentNode = (
|
|
<ElMenuItem index={it.id} onClick={onMenuClick}>
|
|
{{
|
|
title: () => <span>{it.title}</span>,
|
|
default: () => <AIcon class={styles.aIcon} name={it.icon as IconName} />,
|
|
}}
|
|
</ElMenuItem>
|
|
);
|
|
break;
|
|
}
|
|
default:
|
|
currentNode = <></>;
|
|
}
|
|
return currentNode;
|
|
};
|
|
const isCollapse = ref(false);
|
|
|
|
return () => (
|
|
<>
|
|
<ElMenu default-active={defaultId} collapse={isCollapse.value} style={{ height: "100%", overflow: "auto", "--el-menu-base-level-padding": "10px" }} class={[styles.aMenus, "menus"]}>
|
|
{{
|
|
default: () => props.menus.map(renderMenu),
|
|
}}
|
|
</ElMenu>
|
|
<ElButton
|
|
style={{ position: "absolute", right: "6px", bottom: "6px", width: "32px", height: "32px" }}
|
|
onClick={() => {
|
|
isCollapse.value = !isCollapse.value;
|
|
}}
|
|
>
|
|
<ElIcon style={{ cursor: "pointer" }}>{isCollapse.value ? <elIcons.Fold /> : <elIcons.Expand />}</ElIcon>
|
|
</ElButton>
|
|
</>
|
|
);
|
|
},
|
|
{
|
|
props: {
|
|
menus: {
|
|
type: Object as PropType<Menu[]>,
|
|
required: true,
|
|
validator: (value: Menu[]) => value != null && value.length > 0,
|
|
},
|
|
defaultPath: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
},
|
|
emits: {
|
|
menuClick: (id: string) => id != null,
|
|
},
|
|
name: "AAside",
|
|
}
|
|
);
|