diff --git a/.umirc.js b/.umirc.js index 7d8e013..5f35b26 100644 --- a/.umirc.js +++ b/.umirc.js @@ -26,6 +26,19 @@ export default { /chart\/Recharts\/.+Component\.js$/, /chart\/Recharts\/Container\.js$/, ], + update: routes => { + const newRoutes = [] + for (const item of routes[0].routes) { + newRoutes.push(item) + if(item.path){ + newRoutes.push( + Object.assign({}, item, { path: '/:lang(en|zh)' + item.path } ) + ) + } + } + routes[0].routes = newRoutes + return routes + }, }, dll: { include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch', 'antd/es'], diff --git a/src/layouts/BaseLayout.js b/src/layouts/BaseLayout.js new file mode 100644 index 0000000..2cd1e9f --- /dev/null +++ b/src/layouts/BaseLayout.js @@ -0,0 +1,99 @@ +import React, { PureComponent, Fragment } from 'react' +import pathToRegexp from 'path-to-regexp' +import PropTypes from 'prop-types' +import { connect } from 'dva' +import { Helmet } from 'react-helmet' +import { Loader } from 'components' +import NProgress from 'nprogress' +import config from 'utils/config' +import withRouter from 'umi/withRouter' + +import PublicLayout from './PublicLayout' +import PrimaryLayout from './PrimaryLayout' +import './BaseLayout.less' + +const LayoutMap = { + primary: PrimaryLayout, + public: PublicLayout, +} + +/** + * Query which layout should be used for the current path based on the configuration. + * @param {layouts} layouts Layout configuration. + * @param {pathname} pathname Path name to be queried. + * @return {string} Return frist object when query success. + */ +const queryLayout = (layouts, pathname) => { + let result = 'public' + + const isMatch = regepx => { + return regepx instanceof RegExp + ? regepx.test(pathname) + : pathToRegexp(regepx).exec(pathname) + } + + for (const item of layouts) { + let include = false + let exlude = false + if (item.include) { + for (const regepx of item.include) { + if (isMatch(regepx)) { + include = true + break + } + } + } + + if (include && item.exlude) { + for (const regepx of item.exlude) { + if (isMatch(regepx)) { + exlude = true + break + } + } + } + + if (include && !exlude) { + result = item.name + break + } + } + + return result +} + +@withRouter +@connect(({ loading }) => ({ loading })) +class BaseLayout extends PureComponent { + previousPath = '' + + render() { + const { loading, children, location } = this.props + const Container = LayoutMap[queryLayout(config.layouts, location.pathname)] + + const currentPath = location.pathname + location.search + if (currentPath !== this.previousPath) { + NProgress.start() + if (!loading.global) { + NProgress.done() + this.previousPath = currentPath + } + } + + return ( + + + {config.siteName} + + + {children} + + ) + } +} + +BaseLayout.propTypes = { + loading: PropTypes.object, +} + +export default BaseLayout diff --git a/src/layouts/app.less b/src/layouts/BaseLayout.less similarity index 95% rename from src/layouts/app.less rename to src/layouts/BaseLayout.less index 6c69dac..d958d75 100644 --- a/src/layouts/app.less +++ b/src/layouts/BaseLayout.less @@ -1,4 +1,5 @@ @import '~themes/vars.less'; +@import '~themes/index.less'; :global { #nprogress { @@ -7,7 +8,7 @@ .bar { background: @primary-color; position: fixed; - z-index: 1024; + z-index: 2048; top: 0; left: 0; right: 0; @@ -61,6 +62,7 @@ } } } + @keyframes nprogress-spinner { 0% { transform: rotate(0deg); diff --git a/src/layouts/PrimaryLayout.js b/src/layouts/PrimaryLayout.js new file mode 100644 index 0000000..db655bf --- /dev/null +++ b/src/layouts/PrimaryLayout.js @@ -0,0 +1,135 @@ +/* global window */ +/* global document */ +import React, { PureComponent, Fragment } from 'react' +import PropTypes from 'prop-types' +import pathToRegexp from 'path-to-regexp' +import withRouter from 'umi/withRouter' +import { connect } from 'dva' +import { MyLayout } from 'components' +import { BackTop, Layout } from 'antd' +import { classnames, config } from 'utils' +import Error from '../pages/404' + +const { Content, Footer, Sider } = Layout +const { Header, Bread, styles } = MyLayout +const { prefix } = config + +@withRouter +@connect(({ app, loading }) => ({ app, loading })) +class PrimaryLayout extends PureComponent { + render() { + const { children, dispatch, app, location } = this.props + const { + user, + siderFold, + darkTheme, + isNavbar, + menuPopoverVisible, + navOpenKeys, + menu, + permissions, + } = app + let { pathname } = location + pathname = pathname.startsWith('/') ? pathname : `/${pathname}` + const current = menu.filter(item => + pathToRegexp(item.route || '').exec(pathname) + ) + const hasPermission = current.length + ? permissions.visit.includes(current[0].id) + : false + + const headerProps = { + menu, + user, + location, + siderFold, + isNavbar, + menuPopoverVisible, + navOpenKeys, + switchMenuPopover() { + dispatch({ type: 'app/switchMenuPopver' }) + }, + logout() { + dispatch({ type: 'app/logout' }) + }, + switchSider() { + dispatch({ type: 'app/switchSider' }) + }, + changeOpenKeys(openKeys) { + dispatch({ + type: 'app/handleNavOpenKeys', + payload: { navOpenKeys: openKeys }, + }) + }, + } + + const siderProps = { + menu, + location, + siderFold, + darkTheme, + navOpenKeys, + changeTheme() { + dispatch({ type: 'app/switchTheme' }) + }, + changeOpenKeys(openKeys) { + window.localStorage.setItem( + `${prefix}navOpenKeys`, + JSON.stringify(openKeys) + ) + dispatch({ + type: 'app/handleNavOpenKeys', + payload: { navOpenKeys: openKeys }, + }) + }, + } + + const breadProps = { + menu, + location, + } + + return ( + + + {!isNavbar && ( + + {siderProps.menu.length === 0 ? null : ( + + )} + + )} + + document.getElementById('PrimaryLayoutContainer')} + /> +
+ + + {hasPermission ? children : } + +
{config.footerText}
+ + + + ) + } +} + +PrimaryLayout.propTypes = { + children: PropTypes.element.isRequired, + location: PropTypes.object, + dispatch: PropTypes.func, + app: PropTypes.object, + loading: PropTypes.object, +} + +export default PrimaryLayout diff --git a/src/layouts/PublicLayout.js b/src/layouts/PublicLayout.js new file mode 100644 index 0000000..caaaf5c --- /dev/null +++ b/src/layouts/PublicLayout.js @@ -0,0 +1,3 @@ +export default ({ children }) => { + return children +} diff --git a/src/layouts/app.js b/src/layouts/app.js deleted file mode 100644 index 9937c3a..0000000 --- a/src/layouts/app.js +++ /dev/null @@ -1,162 +0,0 @@ -/* global window */ -/* global document */ -import React from 'react' -import NProgress from 'nprogress' -import PropTypes from 'prop-types' -import pathToRegexp from 'path-to-regexp' -import { connect } from 'dva' -import { Loader, MyLayout } from 'components' -import { BackTop, Layout } from 'antd' -import { classnames, config } from 'utils' -import { Helmet } from 'react-helmet' -import { withRouter } from 'dva/router' -import Error from '../pages/404' -import '../themes/index.less' -import './app.less' - -const { Content, Footer, Sider } = Layout -const { Header, Bread, styles } = MyLayout -const { prefix, openPages } = config - -let lastHref - -const App = ({ children, dispatch, app, loading, location }) => { - const { - user, - siderFold, - darkTheme, - isNavbar, - menuPopoverVisible, - navOpenKeys, - menu, - permissions, - } = app - let { pathname } = location - pathname = pathname.startsWith('/') ? pathname : `/${pathname}` - const { logo } = config - const current = menu.filter(item => - pathToRegexp(item.route || '').exec(pathname) - ) - const hasPermission = current.length - ? permissions.visit.includes(current[0].id) - : false - const { href } = window.location - - if (lastHref !== href) { - NProgress.start() - if (!loading.global) { - NProgress.done() - lastHref = href - } - } - - const headerProps = { - menu, - user, - location, - siderFold, - isNavbar, - menuPopoverVisible, - navOpenKeys, - switchMenuPopover() { - dispatch({ type: 'app/switchMenuPopver' }) - }, - logout() { - dispatch({ type: 'app/logout' }) - }, - switchSider() { - dispatch({ type: 'app/switchSider' }) - }, - changeOpenKeys(openKeys) { - dispatch({ - type: 'app/handleNavOpenKeys', - payload: { navOpenKeys: openKeys }, - }) - }, - } - - const siderProps = { - menu, - location, - siderFold, - darkTheme, - navOpenKeys, - changeTheme() { - dispatch({ type: 'app/switchTheme' }) - }, - changeOpenKeys(openKeys) { - window.localStorage.setItem( - `${prefix}navOpenKeys`, - JSON.stringify(openKeys) - ) - dispatch({ - type: 'app/handleNavOpenKeys', - payload: { navOpenKeys: openKeys }, - }) - }, - } - - const breadProps = { - menu, - location, - } - - if (openPages && openPages.includes(pathname)) { - return ( -
- - {children} -
- ) - } - - return ( -
- - - ANTD ADMIN - - - - - - {!isNavbar && ( - - {siderProps.menu.length === 0 ? null : ( - - )} - - )} - - document.getElementById('mainContainer')} /> -
- - - {hasPermission ? children : } - -
{config.footerText}
- - -
- ) -} - -App.propTypes = { - children: PropTypes.element.isRequired, - location: PropTypes.object, - dispatch: PropTypes.func, - app: PropTypes.object, - loading: PropTypes.object, -} - -export default withRouter( - connect(({ app, loading }) => ({ app, loading }))(App) -) diff --git a/src/layouts/index.js b/src/layouts/index.js index 3a74af1..9634b06 100644 --- a/src/layouts/index.js +++ b/src/layouts/index.js @@ -1,13 +1,16 @@ -import React from 'react' +import React, { PureComponent } from 'react' import { LocaleProvider } from 'antd' import enUS from 'antd/lib/locale-provider/en_US' -import withRouter from 'umi/withRouter' -import App from './app' +import BaseLayout from './BaseLayout' -export default withRouter(props => { - return ( - - {props.children} - - ) -}) +class Layout extends PureComponent { + render() { + return ( + + {this.props.children} + + ) + } +} + +export default Layout diff --git a/src/models/app.js b/src/models/app.js index 507d86d..8dee83d 100644 --- a/src/models/app.js +++ b/src/models/app.js @@ -103,14 +103,14 @@ export default { config.openPages && config.openPages.indexOf(locationPathname) < 0 ) { - yield put( - routerRedux.push({ - pathname: '/login', - search: stringify({ - from: locationPathname, - }), - }) - ) + // yield put( + // routerRedux.push({ + // pathname: '/login', + // search: stringify({ + // from: locationPathname, + // }), + // }) + // ) } }, diff --git a/src/pages/document.ejs b/src/pages/document.ejs deleted file mode 100644 index de5e243..0000000 --- a/src/pages/document.ejs +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - antd admin - - - - -
- - - diff --git a/src/utils/config.js b/src/utils/config.js index 0c28063..e8d0310 100644 --- a/src/utils/config.js +++ b/src/utils/config.js @@ -5,4 +5,11 @@ module.exports = { logoPath: '/logo.svg', apiPrefix: '/api/v1', openPages: ['/login'], + layouts: [ + { + name: 'primary', + include: [/.*/], + exlude: [/(\/(en|zh))*\/login/], + }, + ], }