diff --git a/src/layout/Sider.js b/src/layout/Sider.js index a2ce73d..b1a925e 100644 --- a/src/layout/Sider.js +++ b/src/layout/Sider.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useMemo, useRef } from "react"; +import React, { useState, useEffect, useMemo, useRef } from 'react'; import { AppstoreOutlined, CalendarOutlined, @@ -7,26 +7,20 @@ import { SettingOutlined, MenuUnfoldOutlined, MenuFoldOutlined, -} from "@ant-design/icons"; -import { Divider, Menu, Switch, Icon, Button, Modal } from "antd"; -import { connect } from "dva"; -import { withRouter, matchPath } from "dva/router"; -import { Scrollbars } from "react-custom-scrollbars"; -import EnergyIcon from "../utils/energyIcon"; -import { $consts } from "../plugins"; -import "./sider.less"; -import MenuItem from "antd/lib/menu/MenuItem"; -import SubMenu from "antd/lib/menu/SubMenu"; -import FullScreenPage from "./FullScreen"; -import { - requestFullScreenMethod, -} from "../utils/common"; - - - +} from '@ant-design/icons'; +import { Divider, Menu, Switch, Icon, Button, Modal } from 'antd'; +import { connect } from 'dva'; +import { withRouter, matchPath } from 'dva/router'; +import { Scrollbars } from 'react-custom-scrollbars'; +import EnergyIcon from '../utils/energyIcon'; +import { $consts } from '../plugins'; +import './sider.less'; +import MenuItem from 'antd/lib/menu/MenuItem'; +import SubMenu from 'antd/lib/menu/SubMenu'; +import FullScreenPage from './FullScreen'; +import { requestFullScreenMethod } from '../utils/common'; const Sider = (props) => { - /** 菜单页展开与收起 */ const timer = useRef(-1); const handleExpandMenuShow = () => { @@ -44,11 +38,11 @@ const Sider = (props) => { const [menuShrink, setMenuShrink] = useState({}); const handleMenuShrink = (menuId) => { const data = Object.assign({}, menuShrink); - data[menuId] ? (data[menuId] = "") : (data[menuId] = menuId); + data[menuId] ? (data[menuId] = '') : (data[menuId] = menuId); setMenuShrink(data); }; - const [showModal, setshowModal] = useState(false); - const escFunction = () => { + const [showModal, setshowModal] = useState(false); + const escFunction = () => { let isFull = !!( document.fullscreen || document.mozFullScreen || @@ -61,39 +55,30 @@ const Sider = (props) => { } else { // requestFullScreenMethod(document.body); setshowModal(false); - setActiveMenu(null); + setActiveMenu(null); } }; useEffect(() => { // 监听退出全屏事件 --- chrome 用 esc 退出全屏并不会触发 keyup 事件 - document.addEventListener( - "webkitfullscreenchange", - escFunction - ); /* Chrome, Safari and Opera */ - document.addEventListener("mozfullscreenchange", escFunction); /* Firefox */ - document.addEventListener( - "fullscreenchange", - escFunction - ); /* Standard syntax */ - document.addEventListener( - "msfullscreenchange", - escFunction - ); /* IE / Edge */ + document.addEventListener('webkitfullscreenchange', escFunction); /* Chrome, Safari and Opera */ + document.addEventListener('mozfullscreenchange', escFunction); /* Firefox */ + document.addEventListener('fullscreenchange', escFunction); /* Standard syntax */ + document.addEventListener('msfullscreenchange', escFunction); /* IE / Edge */ return () => { //销毁时清除监听 - document.removeEventListener("webkitfullscreenchange", escFunction); - document.removeEventListener("mozfullscreenchange", escFunction); - document.removeEventListener("fullscreenchange", escFunction); - document.removeEventListener("MSFullscreenChange", escFunction); + document.removeEventListener('webkitfullscreenchange', escFunction); + document.removeEventListener('mozfullscreenchange', escFunction); + document.removeEventListener('fullscreenchange', escFunction); + document.removeEventListener('MSFullscreenChange', escFunction); }; }, []); /** 回到首页 */ const navToHome = () => { setActiveMenu(null); - if (localStorage.getItem("webOrgId") == '00300000-0000-0000-0000-000000000000' ) { - props.history.replace('/grouphome') - }else{ - props.history.replace('/home') + if (localStorage.getItem('webOrgId') == '00300000-0000-0000-0000-000000000000') { + props.history.replace('/grouphome'); + } else { + props.history.replace('/home'); } // props.history.push({ pathname: "/home" }); }; @@ -101,12 +86,72 @@ const Sider = (props) => { setActiveMenu('largeScreen'); setshowModal(true); requestFullScreenMethod(document.body); - } + }; const clickMenu = () => { - collapsed === true ? setCollapsed(false) : setCollapsed(false) + collapsed === true ? setCollapsed(false) : setCollapsed(false); + }; + //ykx新增 + const [openKeys, setOpenKeys] = useState([]); + // 手风琴模式:只展开一个菜单 + const onOpenChange = (keys) => { + if (!keys || keys.length === 0) { + setOpenKeys([]); + return; + } - } + // 包含常用菜单 sub1 和所有一级菜单 key + const rootSubMenuKeys = ['sub1', ...topMenus.menus.map((menu, index) => `${menu.Node.ID}_${index}`)]; + + // 查找最新展开的 key(相对于当前 openKeys) + const latestOpenKey = keys.find((key) => !openKeys.includes(key)); + + const isRoot = (key) => rootSubMenuKeys.includes(key); + + // 根据二级 key 去找到它的一级父 key(通过匹配 topMenus 中的 Children.Node.ID) + const getParentKeyBySecondKey = (secondKey) => { + const secondId = String(secondKey).split('_')[0]; + for (let i = 0; i < topMenus.menus.length; i++) { + const top = topMenus.menus[i]; + if (top.Children && top.Children.some((c) => String(c.Node.ID) === secondId)) { + return `${top.Node.ID}_${i}`; + } + } + return null; + }; + + // 如果最新展开的是一级菜单,直接只保留该一级菜单(手风琴) + if (latestOpenKey && isRoot(latestOpenKey)) { + setOpenKeys([latestOpenKey]); + return; + } + + // 如果最新展开的是二级菜单,保留它的父级和它自己 + if (latestOpenKey) { + const parentKey = getParentKeyBySecondKey(latestOpenKey) || keys.find((k) => isRoot(k)); + if (parentKey) { + setOpenKeys([parentKey, latestOpenKey]); + return; + } + } + + // 兜底:保证每个父级只保留一个二级(取 keys 中最后一个属于该父级的二级) + const parentsInKeys = keys.filter((k) => isRoot(k)); + if (parentsInKeys.length) { + const parent = parentsInKeys[0]; + const secondsForParent = keys.filter((k) => !isRoot(k) && getParentKeyBySecondKey(k) === parent); + if (secondsForParent.length) { + setOpenKeys([parent, secondsForParent[secondsForParent.length - 1]]); + return; + } else { + setOpenKeys([parent]); + return; + } + } + + // 其他情况直接使用传入的 keys + setOpenKeys(keys); + }; /** 子菜单路由 */ const navToMenu = (menu) => { props.history.push({ pathname: `/main/${menu.ID}` }); @@ -135,7 +180,7 @@ const Sider = (props) => { useEffect(() => { const { pathname } = props.location; const mathHome = matchPath(pathname, { - path: $consts["ROUTE/HOME"], + path: $consts['ROUTE/HOME'], exact: true, strict: true, }); @@ -143,7 +188,7 @@ const Sider = (props) => { activeMenu && setActiveMenu(null); } const mathMain = matchPath(pathname, { - path: $consts["ROUTE/MAIN"], + path: $consts['ROUTE/MAIN'], exact: true, strict: true, }); @@ -153,7 +198,7 @@ const Sider = (props) => { const find = flatMenus.find((item) => item.ID === menuId); if (find) { props.dispatch({ - type: "app/updateActivatedMenu", + type: 'app/updateActivatedMenu', payload: { currActivatedTab: find.ID, currActivatedMenu: find, @@ -175,12 +220,9 @@ const Sider = (props) => { const topMenus = useMemo(() => { const menus = props.login.loginInfo?.Menus || []; // 菜单宽度 82 + margin 40 - const menuWidth = menus.length - ? menus.length * 82 + (menus.length - 1) * 40 - : 0; + const menuWidth = menus.length ? menus.length * 82 + (menus.length - 1) * 40 : 0; // 叶子菜单需要换行展示个数 - const leafMenuSections = - menus.length < 3 ? 1 : menus.length === 3 ? 2 : menus.length - 2; + const leafMenuSections = menus.length < 3 ? 1 : menus.length === 3 ? 2 : menus.length - 2; const result = { menus, width: menuWidth < 120 ? 120 : menuWidth, @@ -203,13 +245,7 @@ const Sider = (props) => { if (IS_MENU_SHRINK) { const { menus } = topMenus; const data = {}; - menus.forEach( - (menu) => - menu.Children && - menu.Children.forEach( - (child) => (data[child.Node.ID] = child.Node.ID) - ) - ); + menus.forEach((menu) => menu.Children && menu.Children.forEach((child) => (data[child.Node.ID] = child.Node.ID))); setMenuShrink(data); } }, [IS_MENU_SHRINK]); @@ -221,14 +257,14 @@ const Sider = (props) => { if (collapsed == false) { setCollapsed(true); } - }, [props.repost]) + }, [props.repost]); // console.log(props.repost,'21312313213213123') /** 登录页隐藏 */ if (props.matchLogin) return null; return ( -