mirror of https://github.com/chillzhuang/Sword
238 lines
6.1 KiB
JavaScript
238 lines
6.1 KiB
JavaScript
import React, { Suspense } from 'react';
|
|
import { Layout } from 'antd';
|
|
import 'moment/locale/zh-cn';
|
|
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';
|
|
|
|
import { menu, title } from '../defaultSettings';
|
|
import styles from './BasicLayout.less';
|
|
|
|
// 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.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.getPageTitle = memoizeOne(this.getPageTitle);
|
|
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/fetchMenuData',
|
|
payload: { routes, authority },
|
|
});
|
|
}
|
|
|
|
getContext() {
|
|
const { location, breadcrumbNameMap } = this.props;
|
|
return {
|
|
location,
|
|
breadcrumbNameMap,
|
|
};
|
|
}
|
|
|
|
matchParamsPath = (pathname, breadcrumbNameMap) => {
|
|
const pathKey = Object.keys(breadcrumbNameMap).find(key => pathToRegexp(key).test(pathname));
|
|
return breadcrumbNameMap[pathKey];
|
|
};
|
|
|
|
getRouteAuthority = (pathname, routeData) => {
|
|
const routes = routeData.slice(); // clone
|
|
let authorities;
|
|
|
|
while (routes.length > 0) {
|
|
const route = routes.shift();
|
|
// check partial route
|
|
if (pathToRegexp(`${route.path}(.*)`).test(pathname)) {
|
|
if (route.authority) {
|
|
authorities = route.authority;
|
|
}
|
|
// is exact route?
|
|
if (pathToRegexp(route.path).test(pathname)) {
|
|
break;
|
|
}
|
|
|
|
if (route.routes) {
|
|
route.routes.forEach(r => routes.push(r));
|
|
}
|
|
}
|
|
}
|
|
return authorities;
|
|
};
|
|
|
|
getPageTitle = (pathname, breadcrumbNameMap) => {
|
|
const currRouterData = this.matchParamsPath(pathname, breadcrumbNameMap);
|
|
|
|
if (!currRouterData) {
|
|
return title;
|
|
}
|
|
|
|
const pageName = menu.disableLocal
|
|
? currRouterData.name
|
|
: formatMessage({
|
|
id: currRouterData.locale || currRouterData.name,
|
|
defaultMessage: currRouterData.name,
|
|
});
|
|
|
|
return `${pageName} - ${title}`;
|
|
};
|
|
|
|
getLayoutStyle = () => {
|
|
const { fixSiderbar, isMobile, collapsed, layout } = this.props;
|
|
if (fixSiderbar && layout !== 'topmenu' && !isMobile) {
|
|
return {
|
|
paddingLeft: collapsed ? '80px' : '256px',
|
|
};
|
|
}
|
|
return null;
|
|
};
|
|
|
|
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' && process.env.APP_TYPE !== 'site') {
|
|
return null;
|
|
}
|
|
return <SettingDrawer />;
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
navTheme,
|
|
layout: PropsLayout,
|
|
children,
|
|
location: { pathname },
|
|
isMobile,
|
|
menuData,
|
|
breadcrumbNameMap,
|
|
route: { routes },
|
|
fixedHeader,
|
|
} = this.props;
|
|
|
|
const isTop = PropsLayout === 'topmenu';
|
|
const routerConfig = this.getRouteAuthority(pathname, routes);
|
|
const contentStyle = !fixedHeader ? { paddingTop: 0 } : {};
|
|
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 className={styles.content} style={contentStyle}>
|
|
<Authorized authority={routerConfig} noMatch={<Exception403 />}>
|
|
{children}
|
|
</Authorized>
|
|
</Content>
|
|
<Footer />
|
|
</Layout>
|
|
</Layout>
|
|
);
|
|
return (
|
|
<React.Fragment>
|
|
<DocumentTitle title={this.getPageTitle(pathname, breadcrumbNameMap)}>
|
|
<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: menuModel }) => ({
|
|
collapsed: global.collapsed,
|
|
layout: setting.layout,
|
|
menuData: menuModel.menuData,
|
|
breadcrumbNameMap: menuModel.breadcrumbNameMap,
|
|
...setting,
|
|
}))(props => (
|
|
<Media query="(max-width: 599px)">
|
|
{isMobile => <BasicLayout {...props} isMobile={isMobile} />}
|
|
</Media>
|
|
));
|