|
@@ -1,86 +1,112 @@
|
|
-import { Menu, MenuProps } from "antd";
|
|
|
|
-import { FC, memo, useCallback, useMemo } from "react";
|
|
|
|
-import { useLocation, useNavigate } from "react-router-dom";
|
|
|
|
-import { DageRouteItem } from "@/router";
|
|
|
|
-import { findRouteByPath } from "../../utils";
|
|
|
|
-
|
|
|
|
-export interface LayoutMenuProps extends Omit<MenuProps, "mode" | "items"> {
|
|
|
|
- /** 菜单内容 */
|
|
|
|
- menuData: DageRouteItem[];
|
|
|
|
- /**
|
|
|
|
- * 最大可展示层级
|
|
|
|
- * @default 2
|
|
|
|
- */
|
|
|
|
- maxShowLevel?: number;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-export const LayoutMenu: FC<LayoutMenuProps> = memo(
|
|
|
|
- ({ menuData, maxShowLevel = 2, ...rest }) => {
|
|
|
|
- const location = useLocation();
|
|
|
|
- const navigate = useNavigate();
|
|
|
|
- const defaultOpenKeys = useMemo(() => {
|
|
|
|
- let currentPath = "";
|
|
|
|
- const stack: string[] = [];
|
|
|
|
- const paths = location.pathname.split("/").filter((path) => path !== "");
|
|
|
|
- for (let i = 0; i < paths.length; i++) {
|
|
|
|
- currentPath += `/${paths[i]}`;
|
|
|
|
- const item = findRouteByPath(menuData, currentPath);
|
|
|
|
- if (item) {
|
|
|
|
- stack.push(item.path);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return stack;
|
|
|
|
- }, [menuData, location]);
|
|
|
|
-
|
|
|
|
- const renderMenuItems = useCallback(
|
|
|
|
- (list: DageRouteItem[], level = 1): any[] => {
|
|
|
|
- const stack: DageRouteItem[] = [];
|
|
|
|
-
|
|
|
|
- list.forEach((item) => {
|
|
|
|
- let child: DageRouteItem[] = [];
|
|
|
|
- const { title, path, icon, children, hide } = item;
|
|
|
|
- const params = {
|
|
|
|
- key: path,
|
|
|
|
- icon: icon,
|
|
|
|
- label: title,
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- if (hide) return null;
|
|
|
|
-
|
|
|
|
- if (level <= maxShowLevel - 1 && children) {
|
|
|
|
- child = renderMenuItems(children, level + 1);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (child.length) {
|
|
|
|
- // @ts-ignore
|
|
|
|
- params.children = child;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // @ts-ignore
|
|
|
|
- stack.push(params);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- return stack;
|
|
|
|
- },
|
|
|
|
- [maxShowLevel]
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- const handleMenu = useCallback(
|
|
|
|
- (item: any) => {
|
|
|
|
- navigate(item.key);
|
|
|
|
- },
|
|
|
|
- [navigate]
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- return menuData.length ? (
|
|
|
|
- <Menu
|
|
|
|
- mode="inline"
|
|
|
|
- items={renderMenuItems(menuData)}
|
|
|
|
- selectedKeys={location.pathname.split("/").map((i) => `/${i}`)}
|
|
|
|
- defaultOpenKeys={defaultOpenKeys}
|
|
|
|
- onClick={handleMenu}
|
|
|
|
- {...rest}
|
|
|
|
- />
|
|
|
|
- ) : null;
|
|
|
|
- }
|
|
|
|
-);
|
|
|
|
|
|
+import { Menu, MenuProps } from "antd";
|
|
|
|
+import { FC, memo, useCallback, useMemo } from "react";
|
|
|
|
+import { useLocation, useNavigate } from "react-router-dom";
|
|
|
|
+import { DageRouteItem } from "@/router";
|
|
|
|
+import { findRouteByPath, findVisibleRouteParent } from "../../utils";
|
|
|
|
+
|
|
|
|
+export interface LayoutMenuProps extends Omit<MenuProps, "mode" | "items"> {
|
|
|
|
+ /** 菜单内容 */
|
|
|
|
+ menuData: DageRouteItem[];
|
|
|
|
+ /**
|
|
|
|
+ * 最大可展示层级
|
|
|
|
+ * @default 2
|
|
|
|
+ */
|
|
|
|
+ maxShowLevel?: number;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const findSelectedKey = (
|
|
|
|
+ menuData: DageRouteItem[],
|
|
|
|
+ item: DageRouteItem
|
|
|
|
+): string | null => {
|
|
|
|
+ if (!item?.hide) {
|
|
|
|
+ return item.path;
|
|
|
|
+ } else {
|
|
|
|
+ const parent = findVisibleRouteParent(menuData, item.path);
|
|
|
|
+
|
|
|
|
+ return parent ? findSelectedKey(menuData, parent) : null;
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+export const LayoutMenu: FC<LayoutMenuProps> = memo(
|
|
|
|
+ ({ menuData, maxShowLevel = 2, ...rest }) => {
|
|
|
|
+ const location = useLocation();
|
|
|
|
+ const navigate = useNavigate();
|
|
|
|
+ const defaultOpenKeys = useMemo(() => {
|
|
|
|
+ let currentPath = "";
|
|
|
|
+ const stack: string[] = [];
|
|
|
|
+ const paths = location.pathname.split("/").filter((path) => path !== "");
|
|
|
|
+ for (let i = 0; i < paths.length; i++) {
|
|
|
|
+ currentPath += `/${paths[i]}`;
|
|
|
|
+ const item = findRouteByPath(menuData, currentPath);
|
|
|
|
+ if (item) {
|
|
|
|
+ stack.push(item.path);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return stack;
|
|
|
|
+ }, [menuData, location]);
|
|
|
|
+
|
|
|
|
+ const selectedKeys = useMemo(() => {
|
|
|
|
+ const stack = [];
|
|
|
|
+ const item = findRouteByPath(menuData, location.pathname);
|
|
|
|
+
|
|
|
|
+ if (item) {
|
|
|
|
+ const target = findSelectedKey(menuData, item);
|
|
|
|
+ target && stack.push(target);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return stack;
|
|
|
|
+ }, [menuData, location]);
|
|
|
|
+
|
|
|
|
+ const renderMenuItems = useCallback(
|
|
|
|
+ (list: DageRouteItem[], level = 1): any[] => {
|
|
|
|
+ const stack: DageRouteItem[] = [];
|
|
|
|
+
|
|
|
|
+ list.forEach((item) => {
|
|
|
|
+ let child: DageRouteItem[] = [];
|
|
|
|
+ const { title, path, icon, children, hide } = item;
|
|
|
|
+ const params = {
|
|
|
|
+ key: path,
|
|
|
|
+ icon: icon,
|
|
|
|
+ label: title,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ if (hide) return null;
|
|
|
|
+
|
|
|
|
+ if (level <= maxShowLevel - 1 && children) {
|
|
|
|
+ child = renderMenuItems(children, level + 1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (child.length) {
|
|
|
|
+ // @ts-ignore
|
|
|
|
+ params.children = child;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // @ts-ignore
|
|
|
|
+ stack.push(params);
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ return stack;
|
|
|
|
+ },
|
|
|
|
+ [maxShowLevel]
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ const handleMenu = useCallback(
|
|
|
|
+ (item: any) => {
|
|
|
|
+ navigate(item.key);
|
|
|
|
+ },
|
|
|
|
+ [navigate]
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ return menuData.length ? (
|
|
|
|
+ <Menu
|
|
|
|
+ key={menuData.length}
|
|
|
|
+ mode="inline"
|
|
|
|
+ items={renderMenuItems(menuData)}
|
|
|
|
+ selectedKeys={selectedKeys}
|
|
|
|
+ defaultOpenKeys={defaultOpenKeys}
|
|
|
|
+ onClick={handleMenu}
|
|
|
|
+ {...rest}
|
|
|
|
+ />
|
|
|
|
+ ) : null;
|
|
|
|
+ }
|
|
|
|
+);
|