You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
5.4 KiB
192 lines
5.4 KiB
import React from 'react';
|
|
import { Layout } from 'antd';
|
|
import DocumentTitle from 'react-document-title';
|
|
import { connect } from 'dva';
|
|
import { Route, Redirect, Switch } from 'dva/router';
|
|
import { ContainerQuery } from 'react-container-query';
|
|
import classNames from 'classnames';
|
|
import pathToRegexp from 'path-to-regexp';
|
|
import SiderMenu from '../components/SiderMenu';
|
|
import NotFound from '../routes/Exception/404';
|
|
import { getRoutes } from '../utils/utils';
|
|
import Authorized from '../utils/Authorized';
|
|
import SettingDarwer from '../components/SettingDarwer';
|
|
import logo from '../assets/logo.svg';
|
|
import Footer from './Footer';
|
|
import Header from './Header';
|
|
import Context from './MenuContext';
|
|
|
|
const { Content } = Layout;
|
|
const { AuthorizedRoute, check } = Authorized;
|
|
|
|
/**
|
|
* 获取面包屑映射
|
|
* @param {Object} menuData 菜单配置
|
|
* @param {Object} routerData 路由配置
|
|
*/
|
|
const getBreadcrumbNameMap = (menuData, routerData) => {
|
|
const result = {};
|
|
const childResult = {};
|
|
for (const i of menuData) {
|
|
if (!routerData[i.path]) {
|
|
result[i.path] = i;
|
|
}
|
|
if (i.children) {
|
|
Object.assign(childResult, getBreadcrumbNameMap(i.children, routerData));
|
|
}
|
|
}
|
|
return Object.assign({}, routerData, result, childResult);
|
|
};
|
|
|
|
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,
|
|
},
|
|
};
|
|
|
|
class BasicLayout extends React.PureComponent {
|
|
getContext() {
|
|
const { location, routerData, menuData } = this.props;
|
|
return {
|
|
location,
|
|
breadcrumbNameMap: getBreadcrumbNameMap(menuData, routerData),
|
|
};
|
|
}
|
|
getPageTitle() {
|
|
const { routerData, location } = this.props;
|
|
const { pathname } = location;
|
|
let title = 'Ant Design Pro';
|
|
let currRouterData = null;
|
|
// match params path
|
|
Object.keys(routerData).forEach(key => {
|
|
if (pathToRegexp(key).test(pathname)) {
|
|
currRouterData = routerData[key];
|
|
}
|
|
});
|
|
if (currRouterData && currRouterData.name) {
|
|
title = `${currRouterData.name} - Ant Design Pro`;
|
|
}
|
|
return title;
|
|
}
|
|
getLayoutStyle = () => {
|
|
const { fixSiderbar } = this.props;
|
|
if (fixSiderbar) {
|
|
return {
|
|
height: '100vh',
|
|
};
|
|
}
|
|
return null;
|
|
};
|
|
getContentStyle = () => {
|
|
const { fixedHeader } = this.props;
|
|
return {
|
|
margin: '24px 24px 0',
|
|
paddingTop: fixedHeader ? 64 : 0,
|
|
};
|
|
};
|
|
getBashRedirect = () => {
|
|
// According to the url parameter to redirect
|
|
// 这里是重定向的,重定向到 url 的 redirect 参数所示地址
|
|
const urlParams = new URL(window.location.href);
|
|
|
|
const redirect = urlParams.searchParams.get('redirect');
|
|
// Remove the parameters in the url
|
|
if (redirect) {
|
|
urlParams.searchParams.delete('redirect');
|
|
window.history.replaceState(null, 'redirect', urlParams.href);
|
|
} else {
|
|
const { routerData } = this.props;
|
|
// get the first authorized route path in routerData
|
|
const authorizedPath = Object.keys(routerData).find(
|
|
item => check(routerData[item].authority, item) && item !== '/'
|
|
);
|
|
return authorizedPath;
|
|
}
|
|
return redirect;
|
|
};
|
|
handleMenuCollapse = collapsed => {
|
|
this.props.dispatch({
|
|
type: 'global/changeLayoutCollapsed',
|
|
payload: collapsed,
|
|
});
|
|
};
|
|
|
|
render() {
|
|
const { isMobile, redirectData, routerData, match } = this.props;
|
|
const isTop = this.props.layout === 'topmenu';
|
|
const bashRedirect = this.getBashRedirect();
|
|
const myRedirectData = redirectData || [];
|
|
const layout = (
|
|
<Layout>
|
|
{isTop && !isMobile ? null : (
|
|
<SiderMenu
|
|
logo={logo}
|
|
Authorized={Authorized}
|
|
theme={this.props.silderTheme}
|
|
onCollapse={this.handleMenuCollapse}
|
|
{...this.props}
|
|
/>
|
|
)}
|
|
<Layout style={this.getLayoutStyle()}>
|
|
<Header handleMenuCollapse={this.handleMenuCollapse} logo={logo} {...this.props} />
|
|
<Content style={this.getContentStyle()}>
|
|
<Switch>
|
|
{myRedirectData.map(item => (
|
|
<Redirect key={item.from} exact from={item.from} to={item.to} />
|
|
))}
|
|
{getRoutes(match.path, routerData).map(item => (
|
|
<AuthorizedRoute
|
|
key={item.key}
|
|
path={item.path}
|
|
component={item.component}
|
|
exact={item.exact}
|
|
authority={item.authority}
|
|
redirectPath="/exception/403"
|
|
/>
|
|
))}
|
|
<Redirect exact from="/" to={bashRedirect} />
|
|
<Route render={NotFound} />
|
|
</Switch>
|
|
</Content>
|
|
<Footer />
|
|
</Layout>
|
|
</Layout>
|
|
);
|
|
|
|
return (
|
|
<DocumentTitle title={this.getPageTitle()}>
|
|
<ContainerQuery query={query}>
|
|
{params => (
|
|
<Context.Provider value={this.getContext()}>
|
|
<div className={classNames(params)}>
|
|
{layout}
|
|
<SettingDarwer />
|
|
</div>
|
|
</Context.Provider>
|
|
)}
|
|
</ContainerQuery>
|
|
</DocumentTitle>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default connect(({ global, setting }) => ({
|
|
collapsed: global.collapsed,
|
|
layout: setting.layout,
|
|
...setting,
|
|
}))(BasicLayout);
|
|
|