BasicLayout.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import React, { Suspense } from 'react';
  2. import { Layout } from 'antd';
  3. import DocumentTitle from 'react-document-title';
  4. import isEqual from 'lodash/isEqual';
  5. import memoizeOne from 'memoize-one';
  6. import { connect } from 'dva';
  7. import { ContainerQuery } from 'react-container-query';
  8. import classNames from 'classnames';
  9. import pathToRegexp from 'path-to-regexp';
  10. import Media from 'react-media';
  11. import { formatMessage } from 'umi/locale';
  12. import Authorized from '@/utils/Authorized';
  13. import Footer from './Footer';
  14. import Header from './Header';
  15. import Context from './MenuContext';
  16. import Exception403 from '../pages/Exception/403';
  17. import PageLoading from '@/components/PageLoading';
  18. import SiderMenu from '@/components/SiderMenu';
  19. import styles from './BasicLayout.less';
  20. import Custom from '@/pages/Custom';
  21. // lazy load SettingDrawer
  22. const SettingDrawer = React.lazy(() => import('@/components/SettingDrawer'));
  23. const { Content } = Layout;
  24. const query = {
  25. 'screen-xs': {
  26. maxWidth: 575,
  27. },
  28. 'screen-sm': {
  29. minWidth: 576,
  30. maxWidth: 767,
  31. },
  32. 'screen-md': {
  33. minWidth: 768,
  34. maxWidth: 991,
  35. },
  36. 'screen-lg': {
  37. minWidth: 992,
  38. maxWidth: 1199,
  39. },
  40. 'screen-xl': {
  41. minWidth: 1200,
  42. maxWidth: 1599,
  43. },
  44. 'screen-xxl': {
  45. minWidth: 1600,
  46. },
  47. };
  48. class BasicLayout extends React.PureComponent {
  49. constructor(props) {
  50. super(props);
  51. this.getPageTitle = memoizeOne(this.getPageTitle);
  52. this.matchParamsPath = memoizeOne(this.matchParamsPath, isEqual);
  53. }
  54. componentDidMount() {
  55. const {
  56. dispatch,
  57. route: { routes, authority },
  58. } = this.props;
  59. // dispatch({ type: 'global/get_site_list_data' });
  60. dispatch({
  61. type: 'menu/getMenuData',
  62. payload: { routes, authority },
  63. });
  64. }
  65. componentDidUpdate(preProps) {
  66. // After changing to phone mode,
  67. // if collapsed is true, you need to click twice to display
  68. const { collapsed, isMobile } = this.props;
  69. if (isMobile && !preProps.isMobile && !collapsed) {
  70. this.handleMenuCollapse(false);
  71. }
  72. }
  73. getContext() {
  74. const { location, breadcrumbNameMap } = this.props;
  75. return {
  76. location,
  77. breadcrumbNameMap,
  78. };
  79. }
  80. matchParamsPath = (pathname, breadcrumbNameMap) => {
  81. const pathKey = Object.keys(breadcrumbNameMap).find(key => pathToRegexp(key).test(pathname));
  82. return breadcrumbNameMap[pathKey];
  83. };
  84. getRouterAuthority = (pathname, routeData) => {
  85. let routeAuthority = ['noAuthority'];
  86. const getAuthority = (key, routes) => {
  87. routes.map(route => {
  88. if (route.path && pathToRegexp(route.path).test(key)) {
  89. routeAuthority = route.authority;
  90. } else if (route.routes) {
  91. routeAuthority = getAuthority(key, route.routes);
  92. }
  93. return route;
  94. });
  95. return routeAuthority;
  96. };
  97. return getAuthority(pathname, routeData);
  98. };
  99. getPageTitle = (pathname, breadcrumbNameMap) => {
  100. const currRouterData = this.matchParamsPath(pathname, breadcrumbNameMap);
  101. if (!currRouterData) {
  102. return '商户后台';
  103. }
  104. const pageName = formatMessage({
  105. id: currRouterData.locale || currRouterData.name,
  106. defaultMessage: currRouterData.name,
  107. });
  108. return `${pageName} - 商户后台`;
  109. };
  110. getLayoutStyle = () => {
  111. const { fixSiderbar, isMobile, collapsed, layout } = this.props;
  112. if (fixSiderbar && layout !== 'topmenu' && !isMobile) {
  113. return {
  114. paddingLeft: collapsed ? '70px' : '150px',
  115. };
  116. }
  117. return null;
  118. };
  119. handleMenuCollapse = collapsed => {
  120. const { dispatch } = this.props;
  121. dispatch({
  122. type: 'global/changeLayoutCollapsed',
  123. payload: collapsed,
  124. });
  125. };
  126. renderSettingDrawer = () => {
  127. // Do not render SettingDrawer in production
  128. // unless it is deployed in preview.pro.ant.design as demo
  129. if (process.env.NODE_ENV === 'production' && APP_TYPE !== 'site') {
  130. return null;
  131. }
  132. return <SettingDrawer />;
  133. };
  134. render() {
  135. const {
  136. navTheme,
  137. layout: PropsLayout,
  138. children,
  139. location: { pathname },
  140. isMobile,
  141. menuData,
  142. breadcrumbNameMap,
  143. route: { routes },
  144. fixedHeader,
  145. collapsed,
  146. } = this.props;
  147. const isTop = PropsLayout === 'topmenu';
  148. const routerConfig = this.getRouterAuthority(pathname, routes);
  149. const contentStyle = !fixedHeader ? { paddingTop: 0,marginLeft:collapsed?20:0 } : {marginLeft:collapsed?20:10};
  150. const layout = (
  151. <Layout>
  152. <SiderMenu
  153. theme={navTheme}
  154. onCollapse={this.handleMenuCollapse}
  155. menuData={menuData}
  156. isMobile={isMobile}
  157. {...this.props}
  158. />
  159. <Layout
  160. style={{
  161. ...this.getLayoutStyle(),
  162. minHeight: '100vh',
  163. }}
  164. >
  165. <Header
  166. menuData={menuData}
  167. handleMenuCollapse={this.handleMenuCollapse}
  168. isMobile={isMobile}
  169. {...this.props}
  170. />
  171. <Content className={styles.show_long_desc} style={contentStyle}>
  172. <Authorized authority={routerConfig} noMatch={<Exception403 />}>
  173. {children}
  174. </Authorized>
  175. </Content>
  176. <Footer />
  177. </Layout>
  178. </Layout>
  179. );
  180. return (
  181. <React.Fragment>
  182. <DocumentTitle title={this.getPageTitle(pathname, breadcrumbNameMap)}>
  183. <ContainerQuery query={query}>
  184. {params => (
  185. <Context.Provider value={this.getContext()}>
  186. <div className={classNames(params)}>{layout}</div>
  187. </Context.Provider>
  188. )}
  189. </ContainerQuery>
  190. </DocumentTitle>
  191. <Custom />
  192. </React.Fragment>
  193. );
  194. }
  195. }
  196. export default connect(({ global, setting, menu }) => ({
  197. collapsed: global.collapsed,
  198. // currentSite: global.currentSite,
  199. layout: setting.layout,
  200. menuData: menu.menuData,
  201. breadcrumbNameMap: menu.breadcrumbNameMap,
  202. ...setting,
  203. }))(props => (
  204. <Media query="(max-width: 599px)">
  205. {isMobile => <BasicLayout {...props} isMobile={isMobile} />}
  206. </Media>
  207. ));