diff --git a/package.json b/package.json index 6505ae9..62184ae 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "jsonp": "^0.2.1", "less-vars-to-js": "^1.1.2", "mockjs": "^1.0.1-beta3", + "path-to-regexp": "^1.7.0", "rc-tween-one": "^1.0.0", "redbox-react": "^1.2.10" }, diff --git a/src/components/Layout/Bread.js b/src/components/Layout/Bread.js index 25422ae..43003a7 100644 --- a/src/components/Layout/Bread.js +++ b/src/components/Layout/Bread.js @@ -3,46 +3,43 @@ import PropTypes from 'prop-types' import { Breadcrumb, Icon } from 'antd' import { Link } from 'dva/router' import styles from './Bread.less' -import { menu } from '../../utils' +import pathToRegexp from 'path-to-regexp' +import { queryArray } from '../../utils' -let pathSet = [] -const getPathSet = function (menuArray, parentPath) { - parentPath = parentPath || '/' - menuArray.forEach(item => { - pathSet[(parentPath + item.key).replace(/\//g, '-').hyphenToHump()] = { - path: parentPath + item.key, - name: item.name, - icon: item.icon || '', - clickable: item.clickable === undefined, +const Bread = ({ location, menu }) => { + // 匹配当前路由 + let pathArray = [] + let current + for (let index in menu) { + if (menu[index].router && pathToRegexp(menu[index].router).exec(location.pathname)) { + current = menu[index] + break } - if (item.child) { - getPathSet(item.child, `${parentPath}${item.key}/`) - } - }) -} -getPathSet(menu) + } -function Bread ({ location }) { - let pathNames = [] - location.pathname.substr(1).split('/').forEach((item, key) => { - if (key > 0) { - pathNames.push((`${pathNames[key - 1]}-${item}`).hyphenToHump()) - } else { - pathNames.push((`-${item}`).hyphenToHump()) - } - }) + if (!current) { + return (
首页
) + } - const breadsArray = pathNames.filter(item => (item in pathSet)) - const breads = breadsArray.map((item, key) => { + // 递归查找父级 + const getPathArray = (item) => { + pathArray.unshift(item) + if (item.bpid) { + getPathArray(queryArray(menu, item.bpid, 'id')) + } + } + getPathArray(current) + + const breads = pathArray.map((item, key) => { const content = ( - {pathSet[item].icon - ? - : ''}{pathSet[item].name} + {item.icon + ? + : ''}{item.name} ) return ( - {((breadsArray.length - 1) !== key && pathSet[item].clickable) - ? + {((pathArray.length - 1) !== key) + ? {content} : content} @@ -53,12 +50,6 @@ function Bread ({ location }) { return (
- - - - Home - - {breads}
@@ -66,6 +57,7 @@ function Bread ({ location }) { } Bread.propTypes = { + menu: PropTypes.array, location: PropTypes.object, } diff --git a/src/components/Layout/Header.js b/src/components/Layout/Header.js index 505eeb1..97ef337 100644 --- a/src/components/Layout/Header.js +++ b/src/components/Layout/Header.js @@ -6,9 +6,10 @@ import Menus from './Menu' const SubMenu = Menu.SubMenu -function Header ({ user, logout, switchSider, siderFold, isNavbar, menuPopoverVisible, location, switchMenuPopover, navOpenKeys, changeOpenKeys }) { +function Header ({ user, logout, switchSider, siderFold, isNavbar, menuPopoverVisible, location, switchMenuPopover, navOpenKeys, changeOpenKeys, menu }) { let handleClickMenu = e => e.key === 'logout' && logout() const menusProps = { + menu, siderFold: false, darkTheme: false, isNavbar, @@ -49,6 +50,7 @@ function Header ({ user, logout, switchSider, siderFold, isNavbar, menuPopoverVi } Header.propTypes = { + menu: PropTypes.array, user: PropTypes.object, logout: PropTypes.func, switchSider: PropTypes.func, diff --git a/src/components/Layout/Menu.js b/src/components/Layout/Menu.js index 353aeb1..520e305 100644 --- a/src/components/Layout/Menu.js +++ b/src/components/Layout/Menu.js @@ -2,33 +2,43 @@ import React from 'react' import PropTypes from 'prop-types' import { Menu, Icon } from 'antd' import { Link } from 'dva/router' -import { menu } from '../../utils' +import { arrayToTree } from '../../utils' -const topMenus = menu.map(item => item.key) -const getMenus = function (menuArray, siderFold, parentPath = '/') { - return menuArray.map(item => { - const linkTo = parentPath + item.key - if (item.child) { +const Menus = ({ siderFold, darkTheme, location, handleClickNavMenu, navOpenKeys, changeOpenKeys, menu }) => { + // 生成树状 + const menuTree = arrayToTree(menu.filter(_ => _.mpid !== -1), 'id', 'mpid') + + + // 递归生成菜单 + const getMenus = (menuTreeN, siderFoldN) => { + return menuTreeN.map(item => { + if (item.chindren) { + return ( + + {item.icon && } + {(!siderFoldN || menuTree.indexOf(item) < 0) && item.name} + } + > + {getMenus(item.chindren, siderFoldN)} + + ) + } return ( - {item.icon ? : ''}{siderFold && topMenus.indexOf(item.key) >= 0 ? '' : item.name}}> - {getMenus(item.child, siderFold, `${linkTo}/`)} - + + + {item.icon && } + {(!siderFoldN || menuTree.indexOf(item) < 0) && item.name} + + ) - } - return ( - - - {item.icon ? : ''} - {siderFold && topMenus.indexOf(item.key) >= 0 ? '' : item.name} - - - ) - }) -} + }) + } + const menuItems = getMenus(menuTree, siderFold) -function Menus ({ siderFold, darkTheme, location, handleClickNavMenu, navOpenKeys, changeOpenKeys }) { - const menuItems = getMenus(menu, siderFold) + // 保持选中 const getAncestorKeys = (key) => { const map = { '/navigation/navigation2': ['/navigation'], @@ -60,7 +70,7 @@ function Menus ({ siderFold, darkTheme, location, handleClickNavMenu, navOpenKey mode={siderFold ? 'vertical' : 'inline'} theme={darkTheme ? 'dark' : 'light'} onClick={handleClickNavMenu} - defaultSelectedKeys={[location.pathname !== '/' ? location.pathname : '/dashboard']} + defaultSelectedKeys={[location.pathname !== '/' ? location.pathname : menuTree[0].router]} > {menuItems} @@ -68,6 +78,7 @@ function Menus ({ siderFold, darkTheme, location, handleClickNavMenu, navOpenKey } Menus.propTypes = { + menu: PropTypes.array, siderFold: PropTypes.bool, darkTheme: PropTypes.bool, location: PropTypes.object, diff --git a/src/components/Layout/Sider.js b/src/components/Layout/Sider.js index 7fb1869..3184d40 100644 --- a/src/components/Layout/Sider.js +++ b/src/components/Layout/Sider.js @@ -5,8 +5,9 @@ import styles from './Layout.less' import { config } from '../../utils' import Menus from './Menu' -function Sider ({ siderFold, darkTheme, location, changeTheme, navOpenKeys, changeOpenKeys }) { +function Sider ({ siderFold, darkTheme, location, changeTheme, navOpenKeys, changeOpenKeys, menu }) { const menusProps = { + menu, siderFold, darkTheme, location, @@ -29,6 +30,7 @@ function Sider ({ siderFold, darkTheme, location, changeTheme, navOpenKeys, chan } Sider.propTypes = { + menu: PropTypes.array, siderFold: PropTypes.bool, darkTheme: PropTypes.bool, location: PropTypes.object, diff --git a/src/routes/app.js b/src/routes/app.js index 6d1bad9..c5857d3 100644 --- a/src/routes/app.js +++ b/src/routes/app.js @@ -2,17 +2,17 @@ import React from 'react' import PropTypes from 'prop-types' import { connect } from 'dva' import { Layout } from '../components' -import { classnames, config } from '../utils' +import { classnames, config, menu } from '../utils' import { Helmet } from 'react-helmet' import '../themes/index.less' const { Header, Bread, Footer, Sider, styles } = Layout -const App = ({ children, location, dispatch, app, loading }) => { - console.log(loading) +const App = ({ children, location, dispatch, app }) => { const { user, siderFold, darkTheme, isNavbar, menuPopoverVisible, navOpenKeys } = app const headerProps = { + menu, user, siderFold, location, @@ -34,6 +34,7 @@ const App = ({ children, location, dispatch, app, loading }) => { } const siderProps = { + menu, siderFold, darkTheme, location, @@ -47,6 +48,10 @@ const App = ({ children, location, dispatch, app, loading }) => { }, } + const breadProps = { + menu, + } + if (config.openPages && config.openPages.indexOf(location.pathname) > -1) { return
{children}
} @@ -65,7 +70,7 @@ const App = ({ children, location, dispatch, app, loading }) => { : ''}
- +
{children} @@ -83,7 +88,6 @@ App.propTypes = { location: PropTypes.object, dispatch: PropTypes.func, app: PropTypes.object, - loading: PropTypes.object, } export default connect(({ app, loading }) => ({ app, loading }))(App) diff --git a/src/utils/index.js b/src/utils/index.js index b124624..e1e812c 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -3,6 +3,7 @@ import menu from './menu' import request from './request' import classnames from 'classnames' import { color } from './theme' +import lodash from 'lodash' // 连字符转驼峰 String.prototype.hyphenToHump = function () { @@ -52,6 +53,52 @@ const queryURL = (name) => { return null } +/** + * 数组内查询 + * @param {array} array + * @param {String} id + * @param {String} keyAlias + * @return {Array} + */ +const queryArray = (array, key, keyAlias = 'key') => { + if (!(array instanceof Array)) { + return null + } + const item = array.filter(_ => _[keyAlias] === key) + if (item.length) { + return item[0] + } + return null +} + +/** + * 数组格式转树状结构 + * @param {array} array + * @param {String} id + * @param {String} pid + * @param {String} children + * @return {Array} + */ +const arrayToTree = (array, id = 'id', pid = 'pid', chindren = 'chindren') => { + let data = lodash.cloneDeep(array) + let result = [] + let hash = {} + data.forEach((item, index) => { + hash[data[index][id]] = data[index] + }) + + data.forEach((item) => { + let hashVP = hash[item[pid]] + if (hashVP) { + !hashVP[chindren] && (hashVP[chindren] = []) + hashVP[chindren].push(item) + } else { + result.push(item) + } + }) + return result +} + module.exports = { config, menu, @@ -59,4 +106,6 @@ module.exports = { color, classnames, queryURL, + queryArray, + arrayToTree, } diff --git a/src/utils/menu.js b/src/utils/menu.js index 3f815c7..9169872 100644 --- a/src/utils/menu.js +++ b/src/utils/menu.js @@ -1,102 +1,147 @@ module.exports = [ { - key: 'dashboard', - name: 'Dashboard', + id: 1, icon: 'laptop', + name: 'Dashboard', + router: '/dashboard', }, { - key: 'users', + id: 2, + bpid: 1, name: 'User Manage', icon: 'user', + router: '/users', }, { - key: 'request', + id: 3, + bpid: 1, name: 'Request', icon: 'api', + router: '/request', }, { - key: 'UIElement', + id: 4, + bpid: 1, name: 'UI Element', icon: 'camera-o', - clickable: false, - child: [ - { - key: 'iconfont', - name: 'IconFont', - icon: 'heart-o', - }, - { - key: 'dataTable', - name: 'DataTable', - icon: 'database', - }, - { - key: 'dropOption', - name: 'DropOption', - icon: 'bars', - }, - { - key: 'search', - name: 'Search', - icon: 'search', - }, - { - key: 'editor', - name: 'Editor', - icon: 'edit', - }, - { - key: 'layer', - name: 'layer (Function)', - icon: 'credit-card', - }, - ], }, { - key: 'chart', + id: 41, + bpid: 4, + mpid: 4, + name: 'IconFont', + icon: 'heart-o', + router: '/UIElement/iconfont', + }, + { + id: 42, + bpid: 4, + mpid: 4, + name: 'DataTable', + icon: 'database', + router: '/UIElement/dataTable', + }, + { + id: 43, + bpid: 4, + mpid: 4, + name: 'DropOption', + icon: 'bars', + router: '/UIElement/dropOption', + }, + { + id: 44, + bpid: 4, + mpid: 4, + name: 'Search', + icon: 'search', + router: '/UIElement/search', + }, + { + id: 45, + bpid: 4, + mpid: 4, + name: 'Editor', + icon: 'edit', + router: '/UIElement/editor', + }, + { + id: 46, + bpid: 4, + mpid: 4, + name: 'layer (Function)', + icon: 'credit-card', + router: '/UIElement/layer', + }, + { + id: 5, + bpid: 1, name: 'Recharts', icon: 'code-o', - child: [ - { - key: 'lineChart', - name: 'LineChart', - icon: 'line-chart', - }, - { - key: 'barChart', - name: 'BarChart', - icon: 'bar-chart', - }, - { - key: 'areaChart', - name: 'AreaChart', - icon: 'area-chart', - }, - ], }, { - key: 'navigation', + id: 51, + bpid: 5, + mpid: 5, + name: 'LineChart', + icon: 'line-chart', + router: '/chart/lineChart', + }, + { + id: 52, + bpid: 5, + mpid: 5, + name: 'BarChart', + icon: 'bar-chart', + router: '/chart/lineChart', + }, + { + id: 53, + bpid: 5, + mpid: 5, + name: 'AreaChart', + icon: 'area-chart', + router: '/chart/areaChart', + }, + { + id: 6, + bpid: 1, name: 'Test Navigation', icon: 'setting', - child: [ - { - key: 'navigation1', - name: 'Test Navigation1', - }, - { - key: 'navigation2', - name: 'Test Navigation2', - child: [ - { - key: 'navigation21', - name: 'Test Navigation21', - }, - { - key: 'navigation22', - name: 'Test Navigation22', - }, - ], - }, - ], + }, + { + id: 61, + bpid: 6, + mpid: 6, + name: 'Test Navigation1', + router: '/navigation/navigation1', + }, + { + id: 62, + bpid: 6, + mpid: 6, + name: 'Test Navigation2', + router: '/navigation/navigation2', + }, + { + id: 621, + bpid: 62, + mpid: 62, + name: 'Test Navigation21', + router: '/navigation/navigation2/navigation1', + }, + { + id: 621, + bpid: 62, + mpid: 62, + name: 'Test Navigation21', + router: '/navigation/navigation2/navigation1', + }, + { + id: 622, + bpid: 62, + mpid: 62, + name: 'Test Navigation22', + router: '/navigation/navigation2/navigation2', }, ]