菜单优化
This commit is contained in:
parent
b96f742a52
commit
e184b009f9
@ -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 (
|
||||
<div className={`sider ${"shortMenuShow"}`}>
|
||||
<div className={`sider ${'shortMenuShow'}`}>
|
||||
<Modal
|
||||
title="功能导航"
|
||||
visible={showModal}
|
||||
@ -244,16 +280,18 @@ const Sider = (props) => {
|
||||
>
|
||||
<FullScreenPage />
|
||||
</Modal>
|
||||
<div className={`sider ${"shortMenuShow_overflow"}`}>
|
||||
<div className={`sider ${'shortMenuShow_overflow'}`}>
|
||||
<Menu
|
||||
mode="inline"
|
||||
inlineCollapsed={collapsed}
|
||||
style={{
|
||||
// marginTop: 24,
|
||||
// paddingRight: 10,
|
||||
paddingTop: '21px'
|
||||
paddingTop: '21px',
|
||||
}}
|
||||
// defaultOpenKeys={['sub1']}
|
||||
openKeys={openKeys}
|
||||
onOpenChange={onOpenChange}
|
||||
inlineIndent="16"
|
||||
onClick={clickMenu}
|
||||
>
|
||||
@ -266,16 +304,17 @@ const Sider = (props) => {
|
||||
<Icon type="home"></Icon>
|
||||
<span>首页</span>
|
||||
</MenuItem>
|
||||
{localStorage.getItem("webOrgId") == '00300000-0000-0000-0000-000000000000'?
|
||||
<MenuItem key="largeScreen" onClick={navToLarge} title={'可视化大屏'} >
|
||||
{/* <img
|
||||
{localStorage.getItem('webOrgId') == '00300000-0000-0000-0000-000000000000' ? (
|
||||
<MenuItem key="largeScreen" onClick={navToLarge} title={'可视化大屏'}>
|
||||
{/* <img
|
||||
src={require("../assets/layout/menu-all.png")}
|
||||
alt=""
|
||||
className="sider__menuAll-icon"
|
||||
/> */}
|
||||
<Icon type="alert"></Icon>
|
||||
<span>可视化大屏</span>
|
||||
</MenuItem>:null}
|
||||
<Icon type="alert"></Icon>
|
||||
<span>可视化大屏</span>
|
||||
</MenuItem>
|
||||
) : null}
|
||||
<SubMenu
|
||||
key="sub1"
|
||||
title={
|
||||
@ -283,18 +322,13 @@ const Sider = (props) => {
|
||||
<Icon type="profile" title="常用菜单"></Icon>
|
||||
<span>常用菜单</span>
|
||||
</span>
|
||||
|
||||
}
|
||||
onTitleClick={clickMenu}
|
||||
>
|
||||
{favorMenus.map((menu2, index2) => {
|
||||
return (
|
||||
<MenuItem
|
||||
key={`${menu2.ID}_${index2}`}
|
||||
onClick={() => handleActiveMenu(menu2)}
|
||||
title={menu2.NAME}
|
||||
>
|
||||
<Icon type={menu2.ICON ? menu2.ICON : "file-text"} />
|
||||
<MenuItem key={`${menu2.ID}_${index2}`} onClick={() => handleActiveMenu(menu2)} title={menu2.NAME}>
|
||||
<Icon type={menu2.ICON ? menu2.ICON : 'file-text'} />
|
||||
|
||||
<span>{menu2.NAME}</span>
|
||||
</MenuItem>
|
||||
@ -308,47 +342,38 @@ const Sider = (props) => {
|
||||
key={`${menu.Node.ID}_${index}`}
|
||||
title={
|
||||
<span>
|
||||
<Icon type={menu.Node.ICON ? menu.Node.ICON : "reconciliation"} title={menu.Node.NAME}></Icon>
|
||||
<Icon type={menu.Node.ICON ? menu.Node.ICON : 'reconciliation'} title={menu.Node.NAME}></Icon>
|
||||
<span>{menu.Node.NAME}</span>
|
||||
</span>
|
||||
|
||||
}
|
||||
onTitleClick={() => {
|
||||
setCurrMenu(menu.Node);
|
||||
clickMenu()
|
||||
clickMenu();
|
||||
}}
|
||||
|
||||
>
|
||||
{/* 二级 */}
|
||||
{menu.Children.map((menu1, index1) => {
|
||||
const isLevel4Menu = menu1.Children?.find(
|
||||
(mc) => mc.Children?.length
|
||||
);
|
||||
const childMenus = isLevel4Menu
|
||||
? [menu]
|
||||
: menu.Children || [];
|
||||
const isLevel4Menu = menu1.Children?.find((mc) => mc.Children?.length);
|
||||
const childMenus = isLevel4Menu ? [menu] : menu.Children || [];
|
||||
return (
|
||||
<SubMenu
|
||||
key={`${menu1.Node.ID}_${index1}`}
|
||||
title={
|
||||
<span>
|
||||
<Icon type={menu1.Node.ICON ? menu1.Node.ICON : "reconciliation"}></Icon>
|
||||
<Icon type={menu1.Node.ICON ? menu1.Node.ICON : 'reconciliation'}></Icon>
|
||||
<span>{menu1.Node.NAME}</span>
|
||||
</span>
|
||||
|
||||
}
|
||||
>
|
||||
{/* 三级 */}
|
||||
{menu1.Children.map((menu3, index3) => {
|
||||
return (
|
||||
<MenuItem key={`${menu3.Node.ID}_${index3}`} onClick={() =>
|
||||
isLevel4Menu
|
||||
? navToBackend(menu3.Node)
|
||||
: handleActiveMenu(menu3.Node)
|
||||
}
|
||||
<MenuItem
|
||||
key={`${menu3.Node.ID}_${index3}`}
|
||||
onClick={() => (isLevel4Menu ? navToBackend(menu3.Node) : handleActiveMenu(menu3.Node))}
|
||||
title={menu3.Node.NAME}
|
||||
>
|
||||
<Icon type={menu3.Node.ICON ? menu3.Node.ICON : "file-text"} />
|
||||
<Icon type={menu3.Node.ICON ? menu3.Node.ICON : 'file-text'} />
|
||||
|
||||
<span>{menu3.Node.NAME}</span>
|
||||
</MenuItem>
|
||||
@ -361,9 +386,9 @@ const Sider = (props) => {
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
|
||||
</div>
|
||||
<div onClick={toggleCollapsed}
|
||||
<div
|
||||
onClick={toggleCollapsed}
|
||||
style={{
|
||||
marginBottom: 16,
|
||||
display: 'flex',
|
||||
@ -375,17 +400,18 @@ const Sider = (props) => {
|
||||
backgroundColor: '#DEE0E8',
|
||||
borderRadius: '6px',
|
||||
margin: '0px 0px 0px 0px',
|
||||
|
||||
}}>
|
||||
<Icon type={collapsed ? 'right' : 'left'} style={{
|
||||
fontSize: '12px',
|
||||
display: 'flex',
|
||||
// alignItems:'right',
|
||||
// justifyContent:'flex-end'
|
||||
}} />
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
type={collapsed ? 'right' : 'left'}
|
||||
style={{
|
||||
fontSize: '12px',
|
||||
display: 'flex',
|
||||
// alignItems:'right',
|
||||
// justifyContent:'flex-end'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user