BasicLayout.tsx 4.13 KB
Newer Older
1
import PageLoading from '@/components/PageLoading';
何乐's avatar
何乐 committed
2 3
import SiderMenu, { MenuDataItem, SiderMenuProps } from '@/components/SiderMenu';
import { ConnectProps, ConnectState, SettingModelState } from '@/models/connect';
4 5 6 7 8 9 10 11 12 13 14
import getPageTitle from '@/utils/getPageTitle';
import { Layout } from 'antd';
import classNames from 'classnames';
import { connect } from 'dva';
import React, { Suspense, useState } from 'react';
import { ContainerQuery } from 'react-container-query';
import DocumentTitle from 'react-document-title';
import useMedia from 'react-media-hook2';
import logo from '../assets/logo.svg';
import styles from './BasicLayout.less';
import Footer from './Footer';
何乐's avatar
何乐 committed
15
import Header, { HeaderViewProps } from './Header';
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
import Context from './MenuContext';

// 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,
  },
};

何乐's avatar
何乐 committed
48 49 50 51 52 53 54
export interface BasicLayoutProps
  extends ConnectProps,
    SiderMenuProps,
    HeaderViewProps,
    Partial<SettingModelState> {
  breadcrumbNameMap: { [path: string]: MenuDataItem };
  route: MenuDataItem;
55 56
}

何乐's avatar
何乐 committed
57
export interface BasicLayoutContext {
58
  location: Location;
何乐's avatar
何乐 committed
59
  breadcrumbNameMap: { [path: string]: MenuDataItem };
60 61
}

何乐's avatar
何乐 committed
62
const BasicLayout: React.FC<BasicLayoutProps> = props => {
63 64 65 66 67 68 69 70 71 72 73 74 75
  const {
    breadcrumbNameMap,
    dispatch,
    children,
    collapsed,
    fixedHeader,
    fixSiderbar,
    layout: PropsLayout,
    location,
    menuData,
    navTheme,
    route: { routes, authority },
  } = props;
何乐's avatar
何乐 committed
76 77 78
  /**
   * constructor
   */
79
  useState(() => {
何乐's avatar
何乐 committed
80 81 82
    dispatch!({ type: 'user/fetchCurrent' });
    dispatch!({ type: 'setting/getSetting' });
    dispatch!({ type: 'menu/getMenuData', payload: { routes, authority } });
83
  });
何乐's avatar
何乐 committed
84 85 86
  /**
   * init variables
   */
87 88 89
  const isMobile = useMedia({ id: 'BasicLayout', query: '(max-width: 599px)' })[0];
  const hasLeftPadding = fixSiderbar && PropsLayout !== 'topmenu' && !isMobile;
  const handleMenuCollapse = (payload: boolean) =>
何乐's avatar
何乐 committed
90
    dispatch!({ type: 'global/changeLayoutCollapsed', payload });
91 92 93 94 95 96 97
  // Do not render SettingDrawer in production
  // unless it is deployed in preview.pro.ant.design as demo
  const renderSettingDrawer = () =>
    !(process.env.NODE_ENV === 'production' && APP_TYPE !== 'site') && <SettingDrawer />;

  const layout = (
    <Layout>
何乐's avatar
何乐 committed
98
      {PropsLayout === 'topmenu' && !isMobile ? null : (
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
        <SiderMenu
          logo={logo}
          theme={navTheme}
          onCollapse={handleMenuCollapse}
          menuData={menuData}
          isMobile={isMobile}
          {...props}
        />
      )}
      <Layout
        style={{
          paddingLeft: hasLeftPadding ? (collapsed ? 80 : 256) : void 0,
          minHeight: '100vh',
        }}
      >
        <Header
          menuData={menuData}
          handleMenuCollapse={handleMenuCollapse}
          logo={logo}
          isMobile={isMobile}
          {...props}
        />
何乐's avatar
何乐 committed
121
        <Content className={styles.content} style={!fixedHeader ? { paddingTop: 0 } : {}}>
122 123 124 125 126 127 128 129
          {children}
        </Content>
        <Footer />
      </Layout>
    </Layout>
  );
  return (
    <React.Fragment>
何乐's avatar
何乐 committed
130
      <DocumentTitle title={getPageTitle(location!.pathname, breadcrumbNameMap)}>
131 132
        <ContainerQuery query={query}>
          {params => (
何乐's avatar
何乐 committed
133
            <Context.Provider value={{ location: location!, breadcrumbNameMap }}>
134 135 136 137 138 139 140 141 142 143
              <div className={classNames(params)}>{layout}</div>
            </Context.Provider>
          )}
        </ContainerQuery>
      </DocumentTitle>
      <Suspense fallback={<PageLoading />}>{renderSettingDrawer()}</Suspense>
    </React.Fragment>
  );
};

何乐's avatar
何乐 committed
144
export default connect(({ global, setting, menu: menuModel }: ConnectState) => ({
145 146 147 148 149 150
  collapsed: global.collapsed,
  layout: setting.layout,
  menuData: menuModel.menuData,
  breadcrumbNameMap: menuModel.breadcrumbNameMap,
  ...setting,
}))(BasicLayout);