diff --git a/src/layouts/base-layout/MenuProvider.tsx b/src/layouts/base-layout/MenuProvider.tsx index e24fff3..3cc9b09 100644 --- a/src/layouts/base-layout/MenuProvider.tsx +++ b/src/layouts/base-layout/MenuProvider.tsx @@ -2,6 +2,7 @@ import type { FC, ReactNode } from 'react'; import { useMemo } from 'react'; import { getSortRoutes } from '@/store/slice/route'; import { selectActiveFirstLevelMenuKey, setActiveFirstLevelMenuKey } from '@/store/slice/tab'; +import { getActiveFirstLevelMenuKey } from '@/store/slice/tab/shared'; import { MixMenuContext } from '../context'; import { getGlobalMenusByAuthRoutes } from './MenuUtil'; @@ -11,12 +12,35 @@ interface Props { const MenuProvider: FC = ({ children }) => { const sortRoutes = useAppSelector(getSortRoutes); + + const menus = getGlobalMenusByAuthRoutes(sortRoutes); + const activeFirstLevelMenuKey = useAppSelector(selectActiveFirstLevelMenuKey); + const dispatch = useAppDispatch(); - const changeActiveFirstLevelMenuKey = (key: string) => dispatch(setActiveFirstLevelMenuKey(key)); + const route = useRoute(); - const menus = getGlobalMenusByAuthRoutes(sortRoutes); + const selectKey = useMemo(() => { + const { hideInMenu, activeMenu } = route.meta; + + const name = route.name as string; + + const routeName = (hideInMenu ? activeMenu : name) || name; + + return [routeName]; + }, [route]); + + /** - 可以手动指定菜单或者是默认当前路由的一级菜单 */ + function changeActiveFirstLevelMenuKey(key?: string) { + let routeKey = key; + + if (!routeKey) { + routeKey = getActiveFirstLevelMenuKey(route); + } + + dispatch(setActiveFirstLevelMenuKey(routeKey)); + } const firstLevelMenu = useMemo( () => @@ -37,8 +61,10 @@ const MenuProvider: FC = ({ children }) => { activeFirstLevelMenuKey, setActiveFirstLevelMenuKey: changeActiveFirstLevelMenuKey, firstLevelMenu, + selectKey, isActiveFirstLevelMenuHasChildren: activeFirstLevelMenuKey ? Boolean(childLevelMenus) : false, - childLevelMenus: childLevelMenus || [] + childLevelMenus: childLevelMenus || [], + route }; return {children}; diff --git a/src/layouts/base-layout/MenuUtil.tsx b/src/layouts/base-layout/MenuUtil.tsx index 17934cc..7e992ba 100644 --- a/src/layouts/base-layout/MenuUtil.tsx +++ b/src/layouts/base-layout/MenuUtil.tsx @@ -50,16 +50,3 @@ export function getGlobalMenuByBaseRoute(route: ElegantConstRoute): App.Global.M return menu; } - -export function getActiveFirstLevelMenuKey(route: App.Global.TabRoute) { - const { hideInMenu, activeMenu } = route.meta; - const name = route.name; - - const routeName = (hideInMenu ? activeMenu : name) || name; - - if (!routeName) return ''; - - const [firstLevelRouteName] = routeName.split('_'); - - return firstLevelRouteName; -} diff --git a/src/layouts/context/index.ts b/src/layouts/context/index.ts index 2020501..df5a74e 100644 --- a/src/layouts/context/index.ts +++ b/src/layouts/context/index.ts @@ -1,12 +1,15 @@ import { createContext } from 'react'; +import type { Route } from '@sa/simple-router'; export interface MixMenuContextProps { activeFirstLevelMenuKey: string; - setActiveFirstLevelMenuKey: (key: string) => void; + setActiveFirstLevelMenuKey: (key?: string) => void; firstLevelMenu: App.Global.Menu[]; allMenus: App.Global.Menu[]; childLevelMenus: App.Global.Menu[]; isActiveFirstLevelMenuHasChildren: boolean; + selectKey: string[]; + route: Route; } function voidFunc() {} @@ -17,5 +20,7 @@ export const MixMenuContext = createContext({ firstLevelMenu: [], allMenus: [], childLevelMenus: [], - isActiveFirstLevelMenuHasChildren: false + isActiveFirstLevelMenuHasChildren: false, + selectKey: [], + route: {} as Route }); diff --git a/src/layouts/modules/global-menu/components/FirstLevelMenu.tsx b/src/layouts/modules/global-menu/components/FirstLevelMenu.tsx index f13ccda..ebb06e4 100644 --- a/src/layouts/modules/global-menu/components/FirstLevelMenu.tsx +++ b/src/layouts/modules/global-menu/components/FirstLevelMenu.tsx @@ -37,6 +37,7 @@ function MixMenuItem(Props: MixMenuItemProps) { function handleSelectMixMenu() { setActiveFirstLevelMenuKey(key); + if (children?.length) { onClick && onClick(); } else { diff --git a/src/layouts/modules/global-menu/components/HorizontalMenu.tsx b/src/layouts/modules/global-menu/components/HorizontalMenu.tsx index c8a2038..b13ce5e 100644 --- a/src/layouts/modules/global-menu/components/HorizontalMenu.tsx +++ b/src/layouts/modules/global-menu/components/HorizontalMenu.tsx @@ -1,39 +1,35 @@ -import type { Route } from '@sa/simple-router'; import type { MenuInfo } from 'rc-menu/lib/interface'; import type { FC } from 'react'; import { useRouterPush } from '@/hooks/common/routerPush'; +import { getThemeSettings } from '@/store/slice/theme'; interface Props { mode: '1' | '2' | '3'; } -function getSelectKey(route: Route) { - const { hideInMenu, activeMenu } = route.meta; - - const name = route.name as string; - - const routeName = (hideInMenu ? activeMenu : name) || name; - - return [routeName]; +function isHasChildren(menus: App.Global.Menu[], key: string) { + return menus.some(item => item.key === key && item.children?.length); } const HorizontalMenu: FC = memo(({ mode }) => { - const route = useRoute(); + const themeSettings = useAppSelector(getThemeSettings); - const { allMenus, childLevelMenus, firstLevelMenu } = useMixMenuContext(); + const { allMenus, childLevelMenus, firstLevelMenu, selectKey, setActiveFirstLevelMenuKey } = useMixMenuContext(); - const menus = new Map([ - ['1', allMenus as any], + const menus = new Map([ + ['1', allMenus], ['2', childLevelMenus], ['3', firstLevelMenu] ]); const router = useRouterPush(); - const selectKey = getSelectKey(route); - function handleClickMenu(menuInfo: MenuInfo) { - router.menuPush(menuInfo.key); + if (mode === '3' && isHasChildren(allMenus, menuInfo.key)) { + setActiveFirstLevelMenuKey(menuInfo.key); + } else { + router.menuPush(menuInfo.key); + } } return ( @@ -42,6 +38,7 @@ const HorizontalMenu: FC = memo(({ mode }) => { items={menus.get(mode)} inlineIndent={18} onSelect={handleClickMenu} + style={{ lineHeight: `${themeSettings.header.height}px` }} className="size-full bg-container transition-400 border-0!" selectedKeys={selectKey} /> diff --git a/src/layouts/modules/global-menu/components/VerticalMenu.tsx b/src/layouts/modules/global-menu/components/VerticalMenu.tsx index 5e24ff0..2d81f9f 100644 --- a/src/layouts/modules/global-menu/components/VerticalMenu.tsx +++ b/src/layouts/modules/global-menu/components/VerticalMenu.tsx @@ -1,5 +1,5 @@ import { SimpleScrollbar } from '@sa/materials'; -import type { Route, RouteRecordNormalized } from '@sa/simple-router'; +import type { RouteRecordNormalized } from '@sa/simple-router'; import type { MenuInfo } from 'rc-menu/lib/interface'; import type { MenuProps } from 'antd'; import { getSiderCollapse } from '@/store/slice/app'; @@ -26,16 +26,6 @@ const getLevelKeys = (items1: LevelKeysProps[]) => { return key; }; -function getSelectKey(route: Route) { - const { hideInMenu, activeMenu } = route.meta; - - const name = route.name as string; - - const routeName = (hideInMenu ? activeMenu : name) || name; - - return [routeName]; -} - const getSelectedMenuKeyPath = (matches: RouteRecordNormalized[]) => { const result = matches.reduce((acc: string[], match, index) => { if (index < matches.length - 1 && match.name) { @@ -48,25 +38,19 @@ const getSelectedMenuKeyPath = (matches: RouteRecordNormalized[]) => { }; const VerticalMenu = memo(() => { - const route = useRoute(); + const { allMenus, childLevelMenus, selectKey, route } = useMixMenuContext(); - const { allMenus, childLevelMenus } = useMixMenuContext(); - - const levelKeys = getLevelKeys(allMenus as LevelKeysProps[]); + const levelKeys = useMemo(() => getLevelKeys(allMenus), [allMenus]); const themeSettings = useAppSelector(getThemeSettings); - const selectedKeys = getSelectKey(route); - const router = useRouterPush(); - const matches = route.matched; - const openKeys = () => { - return getSelectedMenuKeyPath(matches); - }; + + const openKeys = getSelectedMenuKeyPath(route.matched); const inlineCollapsed = useAppSelector(getSiderCollapse); - const [stateOpenKeys, setStateOpenKeys] = useState(openKeys()); + const [stateOpenKeys, setStateOpenKeys] = useState(openKeys); function handleClickMenu(menuInfo: MenuInfo) { router.menuPush(menuInfo.key); @@ -107,7 +91,7 @@ const VerticalMenu = memo(() => { inlineCollapsed={inlineCollapsed} openKeys={stateOpenKeys} onOpenChange={onOpenChange} - selectedKeys={selectedKeys} + selectedKeys={selectKey} onSelect={handleClickMenu} className="size-full bg-container transition-300 border-0!" inlineIndent={18} diff --git a/src/layouts/modules/global-menu/modules/VerticalMix.tsx b/src/layouts/modules/global-menu/modules/VerticalMix.tsx index 0e5aacd..6bac751 100644 --- a/src/layouts/modules/global-menu/modules/VerticalMix.tsx +++ b/src/layouts/modules/global-menu/modules/VerticalMix.tsx @@ -1,12 +1,10 @@ import classNames from 'classnames'; -import { useRouter } from '@sa/simple-router'; import { createPortal } from 'react-dom'; import { GLOBAL_SIDER_MENU_ID } from '@/constants/app'; import { getDarkMode, getThemeSettings } from '@/store/slice/theme'; import { getMixSiderFixed, toggleMixSiderFixed } from '@/store/slice/app'; import DarkModeContainer from '@/components/stateless/common/DarkModeContainer'; import PinToggler from '@/components/stateless/common/PinToggler'; -import { getActiveFirstLevelMenuKey } from '@/store/slice/tab/shared'; import FirstLevelMenu from '../components/FirstLevelMenu'; import GlobalLogo from '../../global-logo'; import VerticalMenu from '../components/VerticalMenu'; @@ -14,12 +12,13 @@ import { useGetElementById } from './hook'; const VerticalMix = memo(() => { const { t } = useTranslation(); - const router = useRouter(); + const { childLevelMenus, setActiveFirstLevelMenuKey } = useMixMenuContext(); const dispatch = useAppDispatch(); const darkMode = useAppSelector(getDarkMode); const themeSettings = useAppSelector(getThemeSettings); const mixSiderFixed = useAppSelector(getMixSiderFixed); + const [drawerVisible, setDrawerVisible] = useState(false); const siderInverted = !darkMode && themeSettings.sider.inverted; @@ -32,8 +31,8 @@ const VerticalMix = memo(() => { function handleResetActiveMenu() { setDrawerVisible(false); - const firstLevelRouteName = getActiveFirstLevelMenuKey(router.currentRoute); - setActiveFirstLevelMenuKey(firstLevelRouteName); + + setActiveFirstLevelMenuKey(); } return ( diff --git a/src/layouts/modules/global-menu/modules/shared.ts b/src/layouts/modules/global-menu/modules/shared.ts deleted file mode 100644 index 2e2c1b4..0000000 --- a/src/layouts/modules/global-menu/modules/shared.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { GLOBAL_HEADER_MENU_ID, GLOBAL_SIDER_MENU_ID } from '@/constants/app'; - -export const headerContainer = document.getElementById(GLOBAL_HEADER_MENU_ID); - -export const siderContainer = document.getElementById(GLOBAL_SIDER_MENU_ID);