提交 24bd6225 作者: 郁骅焌

菜单及顶部组件重写

上级 70352c9a
...@@ -8,6 +8,7 @@ module.exports = { ...@@ -8,6 +8,7 @@ module.exports = {
rules: { rules: {
'no-plusplus': 0, 'no-plusplus': 0,
'no-template-curly-in-string': 0, 'no-template-curly-in-string': 0,
'no-param-reassign': 0 'no-param-reassign': 0,
'no-unused-expressions': 0
} }
}; };
...@@ -23,7 +23,7 @@ export default defineConfig({ ...@@ -23,7 +23,7 @@ export default defineConfig({
targets: { targets: {
ie: 11, ie: 11,
}, },
plugins: ['@alitajs/keep-alive'], plugins: ['@heartrainy/keep-alive'],
// 缓存页面 // 缓存页面
keepalive: ['/demo/crud', '/system/role'], keepalive: ['/demo/crud', '/system/role'],
// umi routes: https://umijs.org/docs/routing // umi routes: https://umijs.org/docs/routing
...@@ -71,7 +71,7 @@ export default defineConfig({ ...@@ -71,7 +71,7 @@ export default defineConfig({
routes: [ routes: [
{ {
path: '/system/role', path: '/system/role',
name: '角色管理', name: 'role',
icon: 'SolutionOutlined', icon: 'SolutionOutlined',
component: './role', component: './role',
}, },
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
export default { export default {
dev: { dev: {
'/ebd/': { '/ebd/': {
target: 'http://47.103.50.109:9051', // target: 'http://47.103.50.109:9051',
target: 'http://47.103.50.109:9050',
changeOrigin: true, changeOrigin: true,
pathRewrite: { pathRewrite: {
'^/ebd': '', '^/ebd': '',
......
...@@ -50,10 +50,10 @@ ...@@ -50,10 +50,10 @@
"not ie <= 10" "not ie <= 10"
], ],
"dependencies": { "dependencies": {
"@alitajs/keep-alive": "^2.3.9",
"@ant-design/icons": "^4.0.0", "@ant-design/icons": "^4.0.0",
"@ant-design/pro-layout": "^5.0.8", "@ant-design/pro-layout": "^5.0.8",
"@ant-design/pro-table": "2.2.1", "@ant-design/pro-table": "2.2.1",
"@heartrainy/keep-alive": "^2.3.15",
"@umijs/hooks": "^1.9.2", "@umijs/hooks": "^1.9.2",
"antd": "^4.0.0", "antd": "^4.0.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
......
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
bottom: 0; bottom: 0;
width: 100%; width: 100%;
height: 40px; height: 40px;
margin-left: -24px; // margin-left: -24px;
padding-left: 10px; padding-left: 10px;
line-height: 40px; line-height: 40px;
background: #f0f2f5; background: #f0f2f5;
border-top: 1px solid #e7eaec; border-top: 1px solid #e7eaec;
z-index: 9;
} }
@import '~antd/es/style/themes/default.less'; @import '~antd/es/style/themes/default.less';
@pro-header-hover-bg: rgba(0, 0, 0, 0.025); @pro-header-hover-bg: rgba(0, 0, 0, 0.025);
@layout-header-height: 50px;
.menu { .menu {
:global(.anticon) { :global(.anticon) {
......
import React, { useState, useEffect, useImperativeHandle } from 'react'; import React, { useState, useEffect, useImperativeHandle } from 'react';
import { Tabs, Menu, Dropdown, Button } from 'antd'; import { Tabs, Menu, Dropdown, Button } from 'antd';
import { ReloadOutlined } from '@ant-design/icons'; import { ReloadOutlined } from '@ant-design/icons';
import { useLocation, history, dropByCacheKey } from 'umi'; import { useLocation, useIntl, history, dropByCacheKey } from 'umi';
import './style.less'; import './style.less';
const { TabPane } = Tabs; const { TabPane } = Tabs;
...@@ -10,7 +10,7 @@ const TabBar = (props, ref) => { ...@@ -10,7 +10,7 @@ const TabBar = (props, ref) => {
const location = useLocation(); const location = useLocation();
const { pathname } = location; const { pathname } = location;
const { const {
currentUser: { menuTree }, menuTree
} = props; } = props;
const [panes, setPanes] = useState([ const [panes, setPanes] = useState([
...@@ -32,6 +32,8 @@ const TabBar = (props, ref) => { ...@@ -32,6 +32,8 @@ const TabBar = (props, ref) => {
const [activeKey, setActiveKey] = useState(''); const [activeKey, setActiveKey] = useState('');
const [allPath, setAllPath] = useState([]); const [allPath, setAllPath] = useState([]);
const { formatMessage } = useIntl();
const checkPaneExist = (path) => { const checkPaneExist = (path) => {
let isExist = false; let isExist = false;
for (let i = 0; i < panes.length; i++) { for (let i = 0; i < panes.length; i++) {
...@@ -47,7 +49,7 @@ const TabBar = (props, ref) => { ...@@ -47,7 +49,7 @@ const TabBar = (props, ref) => {
if (p) { if (p) {
const newPanes = panes.slice(); const newPanes = panes.slice();
newPanes.push({ newPanes.push({
title: p.name, title: formatMessage({id: p.menuName}),
key: path, key: path,
}); });
setPanes(newPanes); setPanes(newPanes);
...@@ -61,13 +63,13 @@ const TabBar = (props, ref) => { ...@@ -61,13 +63,13 @@ const TabBar = (props, ref) => {
const loopPath = (arr) => { const loopPath = (arr) => {
arr.forEach((item) => { arr.forEach((item) => {
list.push(item); list.push(item);
if (item.hasSun) { if (item.hasSun || (item.children && item.children.length !== 0)) {
const clist = item.children.slice(); const clist = item.children.slice();
loopPath(clist); loopPath(clist);
} }
}); });
}; };
loopPath(menuTree); loopPath(menuTree || []);
setAllPath(list); setAllPath(list);
let isExist = false; let isExist = false;
...@@ -84,7 +86,7 @@ const TabBar = (props, ref) => { ...@@ -84,7 +86,7 @@ const TabBar = (props, ref) => {
if (p) { if (p) {
const newPanes = panes.slice(); const newPanes = panes.slice();
newPanes.push({ newPanes.push({
title: p.name, title: formatMessage({id: p.menuName}),
key: pathname, key: pathname,
}); });
setPanes(newPanes); setPanes(newPanes);
...@@ -100,6 +102,8 @@ const TabBar = (props, ref) => { ...@@ -100,6 +102,8 @@ const TabBar = (props, ref) => {
setActiveKey(activekey); setActiveKey(activekey);
// }, 200) // }, 200)
if (!fromMenu) { if (!fromMenu) {
props.setSelectedKeys([activekey])
props.checkMenuOpen(activekey)
history.push(activekey); history.push(activekey);
} else { } else {
checkPaneExist(activekey); checkPaneExist(activekey);
...@@ -129,6 +133,8 @@ const TabBar = (props, ref) => { ...@@ -129,6 +133,8 @@ const TabBar = (props, ref) => {
setActiveKey(lastActiveKey); setActiveKey(lastActiveKey);
// }, 200) // }, 200)
setPanes(lastPanes); setPanes(lastPanes);
props.setSelectedKeys([lastActiveKey])
props.checkMenuOpen(lastActiveKey)
history.push(lastActiveKey); history.push(lastActiveKey);
}; };
......
.sage-tabbar { .sage-tabbar {
position: fixed; // position: fixed;
z-index: 3; z-index: 3;
display: flex; display: flex;
width: calc(100% - 256px); width: 100%;
height: 40px; height: 40px;
margin: -24px -24px -4px; // margin: -24px -24px -4px;
background: #fff; background: #fff;
.sage-tabbar-left { .sage-tabbar-left {
flex: 1; flex: 1;
...@@ -12,10 +12,12 @@ ...@@ -12,10 +12,12 @@
.sage-tabbar-right { .sage-tabbar-right {
flex: 0 0 40px; flex: 0 0 40px;
.sage-tabbar-button { .sage-tabbar-button {
margin-top: 2px;
float: right; float: right;
width: 40px; width: 40px;
height: 100%; height: calc(100% - 2px);
border: none; border: none;
border-bottom: 1px solid #f0f0f0;
} }
} }
......
...@@ -50,7 +50,8 @@ ol { ...@@ -50,7 +50,8 @@ ol {
.ant-layout-header { .ant-layout-header {
position: fixed; position: fixed;
top: 0; top: 0;
width: calc(100% - 256px) !important; width: calc(100% - 256px);
transition: width 0.5s;
} }
.ant-pro-basicLayout-content { .ant-pro-basicLayout-content {
......
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
* https://github.com/ant-design/ant-design-pro-layout * https://github.com/ant-design/ant-design-pro-layout
*/ */
import ProLayout, { DefaultFooter } from '@ant-design/pro-layout'; import ProLayout, { DefaultFooter } from '@ant-design/pro-layout';
import React, { useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef, useMemo } from 'react';
import { Link, useIntl, connect, KeepAliveLayout } from 'umi'; import { Link, useIntl, connect, history, FormattedMessage, KeepAliveLayout } from 'umi';
import { GithubOutlined } from '@ant-design/icons'; import { GithubOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons';
import { Result, Button } from 'antd'; import { Result, Button, Menu } from 'antd';
import Authorized from '@/utils/Authorized'; import Authorized from '@/utils/Authorized';
import RightContent from '@/components/GlobalHeader/RightContent'; import RightContent from '@/components/GlobalHeader/RightContent';
import TabBar from '@/components/TabBar'; import TabBar from '@/components/TabBar';
...@@ -15,6 +15,10 @@ import GlobalFooter from '@/components/GlobalFooter'; ...@@ -15,6 +15,10 @@ import GlobalFooter from '@/components/GlobalFooter';
import { getAuthorityFromRouter } from '@/utils/utils'; import { getAuthorityFromRouter } from '@/utils/utils';
import logo from '../assets/logo.svg'; import logo from '../assets/logo.svg';
import './BasicLayout.less'
const { SubMenu } = Menu;
const noMatch = ( const noMatch = (
<Result <Result
status={403} status={403}
...@@ -72,24 +76,19 @@ const BasicLayout = (props) => { ...@@ -72,24 +76,19 @@ const BasicLayout = (props) => {
pathname: '/', pathname: '/',
}, },
currentUser, currentUser,
route,
collapsed
} = props; } = props;
const [selectedKeys, setSelectedKeys] = useState([location.pathname])
const [openKeys, setOpenKeys] = useState([])
/** /**
* constructor * constructor
*/ */
const tabBarRef = useRef(); const tabBarRef = useRef();
useEffect(() => {
if (dispatch) {
dispatch({
type: 'user/fetchCurrent',
});
}
}, []);
/**
* init variables
*/
const handleMenuCollapse = (payload) => { const handleMenuCollapse = (payload) => {
if (dispatch) { if (dispatch) {
dispatch({ dispatch({
...@@ -109,56 +108,204 @@ const BasicLayout = (props) => { ...@@ -109,56 +108,204 @@ const BasicLayout = (props) => {
authority: undefined, authority: undefined,
}; };
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
// 处理菜单数据
const disposeMenu = (list, pname, pitem) => {
list.forEach(item => {
const menuName = pname ? `${pname}.${item.name}` : `menu.${item.name}`
item.menuName = menuName
if (pname) {
item.parentPath = pitem.path
}
if (item.children) {
disposeMenu(item.children, menuName, item)
}
})
return list
}
// 获取菜单
const getMenuTree = () => {
const menuList = []
route.children.forEach(item => {
if (!item.redirect) {
menuList.push(item)
}
})
return disposeMenu(menuList)
}
// 递归显示菜单
const getMenuChildren = (menuChildren) => {
return menuChildren.map(item => {
if (item.children) {
return ( return (
<ProLayout <SubMenu key={item.path} icon={item.icon} title={<FormattedMessage id={item.menuName} />}>
logo={logo}
formatMessage={formatMessage}
menuHeaderRender={(logoDom, titleDom) => (
<Link to="/">
{logoDom}
{titleDom}
</Link>
)}
onCollapse={handleMenuCollapse}
onPageChange={handlePageChange}
menuItemRender={(menuItemProps, defaultDom) => {
if (menuItemProps.isUrl || menuItemProps.children || !menuItemProps.path) {
return defaultDom;
}
return <Link to={menuItemProps.path}>{defaultDom}</Link>;
}}
breadcrumbRender={(routers = []) => [
{ {
path: '/', getMenuChildren(item.children)
breadcrumbName: formatMessage({ }
id: 'menu.home', </SubMenu>
}), )
}, }
...routers, return (
]} <Menu.Item key={item.path} icon={item.icon}>
itemRender={(route, params, routes, paths) => { <FormattedMessage id={item.menuName} />
const first = routes.indexOf(route) === 0; </Menu.Item>
return first ? ( )
<Link to={paths.join('/')}>{route.breadcrumbName}</Link> })
) : ( }
<span>{route.breadcrumbName}</span>
); // 选中菜单
}} const handleSelectMenu = ({item, key}) => {
footerRender={() => defaultFooterDom} setSelectedKeys([key])
menuDataRender={menuDataRender} history.push(key)
rightContentRender={() => <RightContent />} if (tabBarRef.current) {
{...props} tabBarRef.current.onChange(key, true);
{...settings} }
}
const handleOpenChange = (_openKeys) => {
setOpenKeys(_openKeys.length > 1 ? [_openKeys.slice().pop()] : _openKeys)
}
const menuTree = useMemo(() => getMenuTree(), [])
// 判断菜单展开折叠
const checkMenuOpen = (key) => {
const loopMenuOpen = (list) => {
for (let i = 0; i < list.length; i++) {
if (list[i].path === key) {
if (list[i].parentPath) {
setOpenKeys([list[i].parentPath])
}
// setOpenKeys(list[i].parentPath ? [list[i].parentPath] : [])
break
}
if (list[i].children) {
loopMenuOpen(list[i].children)
}
}
}
loopMenuOpen(menuTree)
}
useEffect(() => {
checkMenuOpen(selectedKeys[0])
// if (dispatch) {
// dispatch({
// type: 'user/fetchCurrent',
// });
// }
// document.getElementsByClassName('ant-layout-header')[0].style.width = 'calc(100% - 256px)'
// document.getElementsByClassName('sage-tabbar')[0].style.width = 'calc(100% - 256px)'
}, []);
/**
* init variables
*/
return (
<div className={`sage-app-wrapper ${collapsed ? 'hideSidebar' : ''}`}>
<div className="sage-sidebar-container">
<div className="sidebar-logo-container">
<a href="/" className="sage-sidebar-logo-link">
<img src={logo} className="sage-sidebar-logo" />
<h1 className="sage-sidebar-title">Sage FrameWork</h1>
</a>
</div>
<div>
<Menu
style={{ width: '100%' }}
selectedKeys={selectedKeys}
openKeys={openKeys}
mode="inline"
theme="dark"
onSelect={handleSelectMenu}
onOpenChange={handleOpenChange}
inlineCollapsed={collapsed}
> >
<TabBar ref={tabBarRef} currentUser={currentUser} /> {
<Authorized authority={authorized.authority} noMatch={noMatch}> getMenuChildren(menuTree)
<div style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0 }}> }
</Menu>
</div>
</div>
<div className="sage-main-container">
<div className="sage-fixed-header">
<div className="sage-navbar">
<div className="sage-hamburger-container" style={{padding: '0 15px'}} onClick={() => handleMenuCollapse(!collapsed)}>
{
collapsed ? <MenuUnfoldOutlined style={{ fontSize: '20px' }} /> : <MenuFoldOutlined style={{ fontSize: '20px' }} />
}
</div>
<RightContent />
</div>
<TabBar ref={tabBarRef}
currentUser={currentUser}
menuTree={menuTree}
setSelectedKeys={setSelectedKeys}
checkMenuOpen={checkMenuOpen}
/>
</div>
<div className="sage-app-main">
<div className="sage-dashboard-container">
<KeepAliveLayout {...props}>{children}</KeepAliveLayout> <KeepAliveLayout {...props}>{children}</KeepAliveLayout>
</div> </div>
</Authorized>
<GlobalFooter /> <GlobalFooter />
</ProLayout> </div>
</div>
</div>
// <ProLayout
// logo={logo}
// formatMessage={formatMessage}
// menuHeaderRender={(logoDom, titleDom) => (
// <Link to="/">
// {logoDom}
// {titleDom}
// </Link>
// )}
// onCollapse={handleMenuCollapse}
// onPageChange={handlePageChange}
// menuItemRender={(menuItemProps, defaultDom) => {
// if (menuItemProps.isUrl || menuItemProps.children || !menuItemProps.path) {
// return defaultDom;
// }
// return <Link to={menuItemProps.path}>{defaultDom}</Link>;
// }}
// breadcrumbRender={(routers = []) => [
// {
// path: '/',
// breadcrumbName: formatMessage({
// id: 'menu.home',
// }),
// },
// ...routers,
// ]}
// itemRender={(route, params, routes, paths) => {
// const first = routes.indexOf(route) === 0;
// return first ? (
// <Link to={paths.join('/')}>{route.breadcrumbName}</Link>
// ) : (
// <span>{route.breadcrumbName}</span>
// );
// }}
// footerRender={() => defaultFooterDom}
// menuDataRender={menuDataRender}
// rightContentRender={() => <RightContent />}
// {...props}
// {...settings}
// >
// <TabBar ref={tabBarRef} currentUser={currentUser} />
// <Authorized authority={authorized.authority} noMatch={noMatch}>
// <div style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0 }}>
// <KeepAliveLayout {...props}>{children}</KeepAliveLayout>
// </div>
// </Authorized>
// <GlobalFooter />
// </ProLayout>
); );
}; };
......
.sage-app-wrapper {
position: relative;
height: 100%;
width: 100%;
}
.sage-sidebar-container {
transition: width .28s;
width: 205px!important;
background-color: #001529;
height: 100%;
position: fixed;
font-size: 0;
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
overflow: hidden;
}
.sage-main-container {
min-height: 100%;
transition: margin-left .28s;
margin-left: 205px;
position: relative;
}
.sidebar-logo-container {
position: relative;
width: 100%;
height: 50px;
line-height: 50px;
text-align: center;
overflow: hidden;
a {
display: inline-block;
width: 100%;
overflow: hidden;
}
.sage-sidebar-logo-link {
height: 100%;
width: 100%;
.sage-sidebar-logo {
width: 32px;
height: 32px;
vertical-align: middle;
margin-right: 6px;
}
.sage-sidebar-title {
display: inline-block;
margin: 0;
color: #fff;
font-weight: 600;
line-height: 50px;
font-size: 14px;
font-family: Avenir,Helvetica Neue,Arial,Helvetica,sans-serif;
vertical-align: middle;
}
}
}
.sage-fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - 205px);
-webkit-transition: width .28s;
transition: width .28s;
padding: 0;
}
.sage-navbar {
height: 50px;
overflow: hidden;
position: relative;
background: #fff;
-webkit-box-shadow: 0 1px 4px rgba(0,21,41,.08);
box-shadow: 0 1px 4px rgba(0,21,41,.08);
.sage-hamburger-container {
line-height: 50px;
height: 100%;
float: left;
cursor: pointer;
-webkit-transition: background .3s;
transition: background .3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0,0,0,.025);
}
}
}
.sage-app-main {
display: block;
padding-top: 90px;
width: 100%;
// min-height: calc(100vh - 90px);
min-height: 100vh;
position: relative;
overflow: hidden;
}
.sage-dashboard-container {
padding-bottom: 50px;
}
.hideSidebar {
.sage-sidebar-container {
width: 80px !important;
}
.sage-main-container {
margin-left: 80px;
}
.sage-fixed-header {
width: calc(100% - 80px);
}
.sage-sidebar-logo {
margin-right: 0 !important;
}
}
...@@ -19,17 +19,17 @@ const CreateForm = (props, ref) => { ...@@ -19,17 +19,17 @@ const CreateForm = (props, ref) => {
code: 'DEVICE_CONTROL_TYPE,DEVICE_FUNCTION_TYPE' code: 'DEVICE_CONTROL_TYPE,DEVICE_FUNCTION_TYPE'
}) })
if (res.isSuccess) { if (res.isSuccess) {
const { DEVICE_CONTROL_TYPE, DEVICE_FUNCTION_TYPE } = res.data const { DEVICE_CONTROL_TYPE = [], DEVICE_FUNCTION_TYPE = [] } = res.data
DEVICE_CONTROL_TYPE.forEach(item => { DEVICE_CONTROL_TYPE && DEVICE_CONTROL_TYPE.forEach(item => {
item.text = item.dictValue item.text = item.dictValue
item.value = item.dictKey item.value = item.dictKey
}) })
DEVICE_FUNCTION_TYPE.forEach(item => { DEVICE_FUNCTION_TYPE && DEVICE_FUNCTION_TYPE.forEach(item => {
item.text = item.dictValue item.text = item.dictValue
item.value = item.dictKey item.value = item.dictKey
}) })
setSelectOptions1(DEVICE_CONTROL_TYPE) setSelectOptions1(DEVICE_CONTROL_TYPE || [])
setSelectOptions2(DEVICE_FUNCTION_TYPE) setSelectOptions2(DEVICE_FUNCTION_TYPE || [])
} }
} }
......
...@@ -22,16 +22,16 @@ const UpdateForm = (props, ref) => { ...@@ -22,16 +22,16 @@ const UpdateForm = (props, ref) => {
}) })
if (res.isSuccess) { if (res.isSuccess) {
const { DEVICE_CONTROL_TYPE, DEVICE_FUNCTION_TYPE } = res.data const { DEVICE_CONTROL_TYPE, DEVICE_FUNCTION_TYPE } = res.data
DEVICE_CONTROL_TYPE.forEach(item => { DEVICE_CONTROL_TYPE && DEVICE_CONTROL_TYPE.forEach(item => {
item.text = item.dictValue item.text = item.dictValue
item.value = item.dictKey item.value = item.dictKey
}) })
DEVICE_FUNCTION_TYPE.forEach(item => { DEVICE_FUNCTION_TYPE && DEVICE_FUNCTION_TYPE.forEach(item => {
item.text = item.dictValue item.text = item.dictValue
item.value = item.dictKey item.value = item.dictKey
}) })
setSelectOptions1(DEVICE_CONTROL_TYPE) setSelectOptions1(DEVICE_CONTROL_TYPE || [])
setSelectOptions2(DEVICE_FUNCTION_TYPE) setSelectOptions2(DEVICE_FUNCTION_TYPE || [])
} }
} }
......
...@@ -34,16 +34,16 @@ const CrudList = () => { ...@@ -34,16 +34,16 @@ const CrudList = () => {
}) })
if (res.isSuccess) { if (res.isSuccess) {
const { DEVICE_CONTROL_TYPE, DEVICE_FUNCTION_TYPE } = res.data const { DEVICE_CONTROL_TYPE, DEVICE_FUNCTION_TYPE } = res.data
DEVICE_CONTROL_TYPE.forEach(item => { DEVICE_CONTROL_TYPE && DEVICE_CONTROL_TYPE.forEach(item => {
item.text = item.dictValue item.text = item.dictValue
item.value = item.dictKey item.value = item.dictKey
}) })
DEVICE_FUNCTION_TYPE.forEach(item => { DEVICE_FUNCTION_TYPE && DEVICE_FUNCTION_TYPE.forEach(item => {
item.text = item.dictValue item.text = item.dictValue
item.value = item.dictKey item.value = item.dictKey
}) })
setSelectOptions1(DEVICE_CONTROL_TYPE) setSelectOptions1(DEVICE_CONTROL_TYPE || [])
setSelectOptions2(DEVICE_FUNCTION_TYPE) setSelectOptions2(DEVICE_FUNCTION_TYPE || [])
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论