BasicLayout.tsx 4.07 KB
Newer Older
何乐's avatar
何乐 committed
1 2
import SiderMenu, { MenuDataItem, SiderMenuProps } from '@/components/SiderMenu';
import { ConnectProps, ConnectState, SettingModelState } from '@/models/connect';
3 4 5 6 7 8 9 10 11 12 13
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
14
import Header, { HeaderViewProps } from './Header';
15 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
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
47 48 49 50 51 52
export interface BasicLayoutProps
  extends ConnectProps,
    SiderMenuProps,
    HeaderViewProps,
    Partial<SettingModelState> {
  breadcrumbNameMap: { [path: string]: MenuDataItem };
53 54
}

55
export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & {
何乐's avatar
何乐 committed
56
  breadcrumbNameMap: { [path: string]: MenuDataItem };
57
};
58

何乐's avatar
何乐 committed
59
const BasicLayout: React.FC<BasicLayoutProps> = props => {
60 61 62 63 64 65 66 67 68 69 70
  const {
    breadcrumbNameMap,
    dispatch,
    children,
    collapsed,
    fixedHeader,
    fixSiderbar,
    layout: PropsLayout,
    location,
    menuData,
    navTheme,
71
    route,
72
  } = props;
73
  const { routes, authority } = route!;
何乐's avatar
何乐 committed
74 75 76
  /**
   * constructor
   */
77
  useState(() => {
何乐's avatar
何乐 committed
78 79 80
    dispatch!({ type: 'user/fetchCurrent' });
    dispatch!({ type: 'setting/getSetting' });
    dispatch!({ type: 'menu/getMenuData', payload: { routes, authority } });
81
  });
何乐's avatar
何乐 committed
82 83 84
  /**
   * init variables
   */
85 86 87
  const isMobile = useMedia({ id: 'BasicLayout', query: '(max-width: 599px)' })[0];
  const hasLeftPadding = fixSiderbar && PropsLayout !== 'topmenu' && !isMobile;
  const handleMenuCollapse = (payload: boolean) =>
何乐's avatar
何乐 committed
88
    dispatch!({ type: 'global/changeLayoutCollapsed', payload });
89 90 91 92 93 94 95
  // 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
96
      {PropsLayout === 'topmenu' && !isMobile ? null : (
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
        <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
119
        <Content className={styles.content} style={!fixedHeader ? { paddingTop: 0 } : {}}>
120 121 122 123 124 125 126 127
          {children}
        </Content>
        <Footer />
      </Layout>
    </Layout>
  );
  return (
    <React.Fragment>
何乐's avatar
何乐 committed
128
      <DocumentTitle title={getPageTitle(location!.pathname, breadcrumbNameMap)}>
129 130
        <ContainerQuery query={query}>
          {params => (
131
            <Context.Provider value={{ location, breadcrumbNameMap }}>
132 133 134 135 136
              <div className={classNames(params)}>{layout}</div>
            </Context.Provider>
          )}
        </ContainerQuery>
      </DocumentTitle>
137
      <Suspense fallback={null}>{renderSettingDrawer()}</Suspense>
138 139 140 141
    </React.Fragment>
  );
};

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