| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- import React, { Suspense } from 'react';
- import { Layout } from 'antd';
- import DocumentTitle from 'react-document-title';
- import isEqual from 'lodash/isEqual';
- import memoizeOne from 'memoize-one';
- import { connect } from 'dva';
- import { ContainerQuery } from 'react-container-query';
- import classNames from 'classnames';
- import pathToRegexp from 'path-to-regexp';
- import Media from 'react-media';
- import { formatMessage } from 'umi/locale';
- import Authorized from '@/utils/Authorized';
- import logo from '../assets/logo.svg';
- import Footer from './Footer';
- import Header from './Header';
- import Context from './MenuContext';
- import Exception403 from '../pages/Exception/403';
- import PageLoading from '@/components/PageLoading';
- import SiderMenu from '@/components/SiderMenu';
- // lazy load SettingDrawer
- const SettingDrawer = React.lazy(() => import('@/components/SettingDrawer'));
- const { Content } = Layout;
- const query = {
- 'screen-xs': {
- maxWidth: 575,
- },
- 'screen-sm': {
- minWidth: 576,
- maxWidth: 767,
- },
- 'screen-md': {
- minWidth: 768,
- maxWidth: 991,
- },
- 'screen-lg': {
- minWidth: 992,
- maxWidth: 1199,
- },
- 'screen-xl': {
- minWidth: 1200,
- maxWidth: 1599,
- },
- 'screen-xxl': {
- minWidth: 1600,
- },
- };
- class BasicLayout extends React.PureComponent {
- constructor(props) {
- super(props);
- this.getPageTitle = memoizeOne(this.getPageTitle);
- this.getBreadcrumbNameMap = memoizeOne(this.getBreadcrumbNameMap, isEqual);
- this.breadcrumbNameMap = this.getBreadcrumbNameMap();
- this.matchParamsPath = memoizeOne(this.matchParamsPath, isEqual);
- }
- componentDidMount() {
- const {
- dispatch,
- route: { routes, authority },
- } = this.props;
- dispatch({
- type: 'user/fetchCurrent',
- });
- dispatch({
- type: 'setting/getSetting',
- });
- dispatch({
- type: 'menu/getMenuData',
- payload: { routes, authority },
- });
- }
- componentDidUpdate(preProps) {
- // After changing to phone mode,
- // if collapsed is true, you need to click twice to display
- this.breadcrumbNameMap = this.getBreadcrumbNameMap();
- const { collapsed, isMobile } = this.props;
- if (isMobile && !preProps.isMobile && !collapsed) {
- this.handleMenuCollapse(false);
- }
- }
- getContext() {
- const { location } = this.props;
- return {
- location,
- breadcrumbNameMap: this.breadcrumbNameMap,
- };
- }
- /**
- * 获取面包屑映射
- * @param {Object} menuData 菜单配置
- */
- getBreadcrumbNameMap() {
- const routerMap = {};
- const { menuData } = this.props;
- const flattenMenuData = data => {
- data.forEach(menuItem => {
- if (menuItem.children) {
- flattenMenuData(menuItem.children);
- }
- // Reduce memory usage
- routerMap[menuItem.path] = menuItem;
- });
- };
- flattenMenuData(menuData);
- return routerMap;
- }
- matchParamsPath = pathname => {
- const pathKey = Object.keys(this.breadcrumbNameMap).find(key =>
- pathToRegexp(key).test(pathname)
- );
- return this.breadcrumbNameMap[pathKey];
- };
- getPageTitle = pathname => {
- const currRouterData = this.matchParamsPath(pathname);
- if (!currRouterData) {
- return 'Ant Design Pro';
- }
- const pageName = formatMessage({
- id: currRouterData.locale || currRouterData.name,
- defaultMessage: currRouterData.name,
- });
- return `${pageName} - Ant Design Pro`;
- };
- getLayoutStyle = () => {
- const { fixSiderbar, isMobile, collapsed, layout } = this.props;
- if (fixSiderbar && layout !== 'topmenu' && !isMobile) {
- return {
- paddingLeft: collapsed ? '80px' : '256px',
- };
- }
- return null;
- };
- getContentStyle = () => {
- const { fixedHeader } = this.props;
- return {
- margin: '24px 24px 0',
- paddingTop: fixedHeader ? 64 : 0,
- };
- };
- handleMenuCollapse = collapsed => {
- const { dispatch } = this.props;
- dispatch({
- type: 'global/changeLayoutCollapsed',
- payload: collapsed,
- });
- };
- renderSettingDrawer = () => {
- // Do not render SettingDrawer in production
- // unless it is deployed in preview.pro.ant.design as demo
- if (process.env.NODE_ENV === 'production' && APP_TYPE !== 'site') {
- return null;
- }
- return <SettingDrawer />;
- };
- render() {
- const {
- navTheme,
- layout: PropsLayout,
- children,
- location: { pathname },
- isMobile,
- menuData,
- } = this.props;
- const isTop = PropsLayout === 'topmenu';
- const routerConfig = this.matchParamsPath(pathname);
- const layout = (
- <Layout>
- {isTop && !isMobile ? null : (
- <SiderMenu
- logo={logo}
- theme={navTheme}
- onCollapse={this.handleMenuCollapse}
- menuData={menuData}
- isMobile={isMobile}
- {...this.props}
- />
- )}
- <Layout
- style={{
- ...this.getLayoutStyle(),
- minHeight: '100vh',
- }}
- >
- <Header
- menuData={menuData}
- handleMenuCollapse={this.handleMenuCollapse}
- logo={logo}
- isMobile={isMobile}
- {...this.props}
- />
- <Content style={this.getContentStyle()}>
- <Authorized
- authority={routerConfig && routerConfig.authority}
- noMatch={<Exception403 />}
- >
- {children}
- </Authorized>
- </Content>
- <Footer />
- </Layout>
- </Layout>
- );
- return (
- <React.Fragment>
- <DocumentTitle title={this.getPageTitle(pathname)}>
- <ContainerQuery query={query}>
- {params => (
- <Context.Provider value={this.getContext()}>
- <div className={classNames(params)}>{layout}</div>
- </Context.Provider>
- )}
- </ContainerQuery>
- </DocumentTitle>
- <Suspense fallback={<PageLoading />}>{this.renderSettingDrawer()}</Suspense>
- </React.Fragment>
- );
- }
- }
- export default connect(({ global, setting, menu }) => ({
- collapsed: global.collapsed,
- layout: setting.layout,
- menuData: menu.menuData,
- ...setting,
- }))(props => (
- <Media query="(max-width: 599px)">
- {isMobile => <BasicLayout {...props} isMobile={isMobile} />}
- </Media>
- ));
|