Unverified Commit 577ded4b authored by ddcat1115's avatar ddcat1115 Committed by GitHub

Router config (#442)

* adjust menu and router config

* rebase master

* remove invalid breadcrumb item

* add nested layout

* Some improvements

* get name from menu.js

* - use HOC to pass routerData instead of context
parent 6e37a939
......@@ -53,6 +53,6 @@
}
},
"settings": {
"polyfills": ["fetch"]
"polyfills": ["fetch", "promises"]
}
}
const menuData = [{
name: 'dashborad',
icon: 'dashboard',
path: 'dashboard',
children: [{
name: '分析页',
path: 'analysis',
}, {
name: '监控页',
path: 'monitor',
}, {
name: '工作台',
path: 'workplace',
// hideInMenu: true,
}],
}, {
name: '表单页',
icon: 'form',
path: 'form',
children: [{
name: '基础表单',
path: 'basic-form',
}, {
name: '分步表单',
path: 'step-form',
}, {
name: '高级表单',
path: 'advanced-form',
}],
}, {
name: '列表页',
icon: 'table',
path: 'list',
children: [{
name: '搜索列表',
icon: 'search',
path: 'search',
children: [{
name: '搜索列表(项目)',
path: 'projects',
}, {
name: '搜索列表(应用)',
path: 'applications',
}, {
name: '搜索列表(文章)',
path: 'articles',
}],
}, {
name: '查询表格',
path: 'table-list',
}, {
name: '标准列表',
path: 'basic-list',
}, {
name: '卡片列表',
path: 'card-list',
}],
}, {
name: '详情页',
icon: 'profile',
path: 'profile',
children: [{
name: '基础详情页',
path: 'basic',
}, {
name: '高级详情页',
path: 'advanced',
}],
}, {
name: '结果页',
icon: 'check-circle-o',
path: 'result',
children: [{
name: '成功',
path: 'success',
}, {
name: '失败',
path: 'fail',
}],
}, {
name: '异常页',
icon: 'warning',
path: 'exception',
children: [{
name: '403',
path: '403',
}, {
name: '404',
path: '404',
}, {
name: '500',
path: '500',
}],
}, {
name: '账户',
icon: 'user',
path: 'user',
children: [{
name: '登录',
path: 'login',
}, {
name: '注册',
path: 'register',
}, {
name: '注册结果',
path: 'register-result',
}],
}, {
name: '使用文档',
icon: 'book',
path: 'http://pro.ant.design/docs/getting-started',
target: '_blank',
}];
function formatter(data, parentPath = '') {
const list = [];
data.forEach((item) => {
if (item.children) {
list.push({
...item,
path: `${parentPath}${item.path}`,
children: formatter(item.children, `${parentPath}${item.path}/`),
});
} else {
list.push({
...item,
path: `${parentPath}${item.path}`,
});
}
});
return list;
}
export const getMenuData = () => formatter(menuData);
import dynamic from 'dva/dynamic';
// wrapper of dynamic
const dynamicWrapper = (app, models, component) => dynamic({
app,
models: () => models.map(m => import(`../models/${m}.js`)),
component,
});
// nav data
export const getNavData = app => [
{
component: dynamicWrapper(app, ['user', 'login'], () => import('../layouts/BasicLayout')),
layout: 'BasicLayout',
name: '首页', // for breadcrumb
path: '/',
children: [
{
name: 'Dashboard',
icon: 'dashboard',
path: 'dashboard',
children: [
{
name: '分析页',
path: 'analysis',
component: dynamicWrapper(app, ['chart'], () => import('../routes/Dashboard/Analysis')),
},
{
name: '监控页',
path: 'monitor',
component: dynamicWrapper(app, ['monitor'], () => import('../routes/Dashboard/Monitor')),
},
{
name: '工作台',
path: 'workplace',
component: dynamicWrapper(app, ['project', 'activities', 'chart'], () => import('../routes/Dashboard/Workplace')),
},
],
},
{
name: '表单页',
path: 'form',
icon: 'form',
children: [
{
name: '基础表单',
path: 'basic-form',
component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/BasicForm')),
},
{
name: '分步表单',
path: 'step-form',
component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm')),
children: [
{
path: 'confirm',
component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm/Step2')),
},
{
path: 'result',
component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm/Step3')),
},
],
},
{
name: '高级表单',
path: 'advanced-form',
component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/AdvancedForm')),
},
],
},
{
name: '列表页',
path: 'list',
icon: 'table',
children: [
{
name: '查询表格',
path: 'table-list',
component: dynamicWrapper(app, ['rule'], () => import('../routes/List/TableList')),
},
{
name: '标准列表',
path: 'basic-list',
component: dynamicWrapper(app, ['list'], () => import('../routes/List/BasicList')),
},
{
name: '卡片列表',
path: 'card-list',
component: dynamicWrapper(app, ['list'], () => import('../routes/List/CardList')),
},
{
name: '搜索列表',
path: 'search',
component: dynamicWrapper(app, [], () => import('../routes/List/List')),
children: [{
name: '搜索列表(项目)',
path: 'projects',
component: dynamicWrapper(app, ['list'], () => import('../routes/List/Projects')),
}, {
name: '搜索列表(应用)',
path: 'applications',
component: dynamicWrapper(app, ['list'], () => import('../routes/List/Applications')),
}, {
name: '搜索列表(文章)',
path: 'articles',
component: dynamicWrapper(app, ['list'], () => import('../routes/List/Articles')),
}],
},
],
},
{
name: '详情页',
path: 'profile',
icon: 'profile',
children: [
{
name: '基础详情页',
path: 'basic',
component: dynamicWrapper(app, ['profile'], () => import('../routes/Profile/BasicProfile')),
},
{
name: '高级详情页',
path: 'advanced',
component: dynamicWrapper(app, ['profile'], () => import('../routes/Profile/AdvancedProfile')),
},
],
},
{
name: '结果',
path: 'result',
icon: 'check-circle-o',
children: [
{
name: '成功',
path: 'success',
component: dynamicWrapper(app, [], () => import('../routes/Result/Success')),
},
{
name: '失败',
path: 'fail',
component: dynamicWrapper(app, [], () => import('../routes/Result/Error')),
},
],
},
{
name: '异常',
path: 'exception',
icon: 'warning',
children: [
{
name: '403',
path: '403',
component: dynamicWrapper(app, [], () => import('../routes/Exception/403')),
},
{
name: '404',
path: '404',
component: dynamicWrapper(app, [], () => import('../routes/Exception/404')),
},
{
name: '500',
path: '500',
component: dynamicWrapper(app, [], () => import('../routes/Exception/500')),
},
],
},
],
},
{
component: dynamicWrapper(app, [], () => import('../layouts/UserLayout')),
path: '/user',
layout: 'UserLayout',
children: [
{
name: '帐户',
icon: 'user',
path: 'user',
children: [
{
name: '登录',
path: 'login',
component: dynamicWrapper(app, ['login'], () => import('../routes/User/Login')),
},
{
name: '注册',
path: 'register',
component: dynamicWrapper(app, ['register'], () => import('../routes/User/Register')),
},
{
name: '注册结果',
path: 'register-result',
component: dynamicWrapper(app, [], () => import('../routes/User/RegisterResult')),
},
],
},
],
},
{
component: dynamicWrapper(app, [], () => import('../layouts/BlankLayout')),
layout: 'BlankLayout',
children: {
name: '使用文档',
path: 'http://pro.ant.design/docs/getting-started',
target: '_blank',
icon: 'book',
},
},
];
import React from 'react';
import dynamic from 'dva/dynamic';
import { getMenuData } from './menu';
// wrapper of dynamic
const dynamicWrapper = (app, models, component) => dynamic({
app,
models: () => models.map(m => import(`../models/${m}.js`)),
// add routerData prop
component: () => {
const p = component();
return new Promise((resolve, reject) => {
p.then((Comp) => {
resolve(props => <Comp {...props} routerData={getRouterData(app)} />);
}).catch(err => reject(err));
});
},
});
function getFlatMenuData(menus) {
let keys = {};
menus.forEach((item) => {
if (item.children) {
keys[item.path] = item.name;
keys = { ...keys, ...getFlatMenuData(item.children) };
} else {
keys[item.path] = item.name;
}
});
return keys;
}
export const getRouterData = (app) => {
const routerData = {
'/': {
component: dynamicWrapper(app, ['user', 'login'], () => import('../layouts/BasicLayout')),
},
'/dashboard/analysis': {
component: dynamicWrapper(app, ['chart'], () => import('../routes/Dashboard/Analysis')),
},
'/dashboard/monitor': {
component: dynamicWrapper(app, ['monitor'], () => import('../routes/Dashboard/Monitor')),
},
'/dashboard/workplace': {
component: dynamicWrapper(app, ['project', 'activities', 'chart'], () => import('../routes/Dashboard/Workplace')),
// hideInBreadcrumb: true,
// name: '工作台',
},
'/form/basic-form': {
component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/BasicForm')),
},
'/form/step-form': {
component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm')),
},
'/form/step-form/confirm': {
component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm/Step2')),
},
'/form/step-form/result': {
component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/StepForm/Step3')),
},
'/form/advanced-form': {
component: dynamicWrapper(app, ['form'], () => import('../routes/Forms/AdvancedForm')),
},
'/list/table-list': {
component: dynamicWrapper(app, ['rule'], () => import('../routes/List/TableList')),
},
'/list/basic-list': {
component: dynamicWrapper(app, ['list'], () => import('../routes/List/BasicList')),
},
'/list/card-list': {
component: dynamicWrapper(app, ['list'], () => import('../routes/List/CardList')),
},
'/list/search': {
component: dynamicWrapper(app, ['list'], () => import('../routes/List/List')),
},
'/list/search/projects': {
component: dynamicWrapper(app, ['list'], () => import('../routes/List/Projects')),
},
'/list/search/applications': {
component: dynamicWrapper(app, ['list'], () => import('../routes/List/Applications')),
},
'/list/search/articles': {
component: dynamicWrapper(app, ['list'], () => import('../routes/List/Articles')),
},
'/profile/basic': {
component: dynamicWrapper(app, ['profile'], () => import('../routes/Profile/BasicProfile')),
},
'/profile/advanced': {
component: dynamicWrapper(app, ['profile'], () => import('../routes/Profile/AdvancedProfile')),
},
'/result/success': {
component: dynamicWrapper(app, [], () => import('../routes/Result/Success')),
},
'/result/fail': {
component: dynamicWrapper(app, [], () => import('../routes/Result/Error')),
},
'/exception/403': {
component: dynamicWrapper(app, [], () => import('../routes/Exception/403')),
},
'/exception/404': {
component: dynamicWrapper(app, [], () => import('../routes/Exception/404')),
},
'/exception/500': {
component: dynamicWrapper(app, [], () => import('../routes/Exception/500')),
},
'/user': {
component: dynamicWrapper(app, [], () => import('../layouts/UserLayout')),
},
'/user/login': {
component: dynamicWrapper(app, ['login'], () => import('../routes/User/Login')),
},
'/user/register': {
component: dynamicWrapper(app, ['register'], () => import('../routes/User/Register')),
},
'/user/register-result': {
component: dynamicWrapper(app, [], () => import('../routes/User/RegisterResult')),
},
// '/user/:id': {
// component: dynamicWrapper(app, [], () => import('../routes/User/SomeComponent')),
// },
};
// Get name from ./menu.js or just set it in the router data.
const menuData = getFlatMenuData(getMenuData());
const routerDataWithName = {};
Object.keys(routerData).forEach((item) => {
routerDataWithName[item] = {
...routerData[item],
name: routerData[item].name || menuData[item.replace(/^\//, '')],
};
});
return routerDataWithName;
};
......@@ -14,7 +14,7 @@ function getBreadcrumb(breadcrumbNameMap, url) {
if (breadcrumbNameMap[urlWithoutSplash]) {
return breadcrumbNameMap[urlWithoutSplash];
}
let breadcrumb = '';
let breadcrumb = {};
Object.keys(breadcrumbNameMap).forEach((item) => {
const itemRegExpStr = `^${item.replace(/:[\w-]+/g, '[\\w-]+')}$`;
const itemRegExp = new RegExp(itemRegExpStr);
......@@ -78,15 +78,15 @@ export default class PageHeader extends PureComponent {
const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;
const currentBreadcrumb = getBreadcrumb(breadcrumbNameMap, url);
const isLinkable = (index !== pathSnippets.length - 1) && currentBreadcrumb.component;
return (
return currentBreadcrumb.name && !currentBreadcrumb.hideInBreadcrumb ? (
<Breadcrumb.Item key={url}>
{createElement(
isLinkable ? linkElement : 'span',
{ [linkElement === 'a' ? 'href' : 'to']: url },
currentBreadcrumb.name || url,
currentBreadcrumb.name,
)}
</Breadcrumb.Item>
);
) : null;
});
const breadcrumbItems = [(
<Breadcrumb.Item key="home">
......
......@@ -3,6 +3,7 @@ import { Layout, Menu, Icon } from 'antd';
import { Link } from 'dva/router';
import logo from '../../assets/logo.svg';
import styles from './index.less';
import { getMenuData } from '../../common/menu';
const { Sider } = Layout;
const { SubMenu } = Menu;
......@@ -10,8 +11,7 @@ const { SubMenu } = Menu;
export default class SiderMenu extends PureComponent {
constructor(props) {
super(props);
// 把一级 Layout 的 children 作为菜单项
this.menus = props.navData.reduce((arr, current) => arr.concat(current.children), []);
this.menus = getMenuData();
this.state = {
openKeys: this.getDefaultCollapsedSubMenus(props),
};
......@@ -23,22 +23,49 @@ export default class SiderMenu extends PureComponent {
});
}
getDefaultCollapsedSubMenus(props) {
const currentMenuSelectedKeys = [...this.getCurrentMenuSelectedKeys(props)];
currentMenuSelectedKeys.splice(-1, 1);
const { location: { pathname } } = props || this.props;
const snippets = pathname.split('/').slice(1, -1);
const currentPathSnippets = snippets.map((item, index) => {
const arr = snippets.filter((_, i) => i <= index);
return arr.join('/');
});
let currentMenuSelectedKeys = [];
currentPathSnippets.forEach((item) => {
currentMenuSelectedKeys = currentMenuSelectedKeys.concat(this.getSelectedMenuKeys(item));
});
if (currentMenuSelectedKeys.length === 0) {
return ['dashboard'];
}
return currentMenuSelectedKeys;
}
getCurrentMenuSelectedKeys(props) {
const { location: { pathname } } = props || this.props;
const keys = pathname.split('/').slice(1);
if (keys.length === 1 && keys[0] === '') {
return [this.menus[0].key];
getFlatMenuKeys(menus) {
let keys = [];
menus.forEach((item) => {
if (item.children) {
keys.push(item.path);
keys = keys.concat(this.getFlatMenuKeys(item.children));
} else {
keys.push(item.path);
}
});
return keys;
}
getNavMenuItems(menusData, parentPath = '') {
getSelectedMenuKeys = (path) => {
const flatMenuKeys = this.getFlatMenuKeys(this.menus);
if (flatMenuKeys.indexOf(path.replace(/^\//, '')) > -1) {
return [path.replace(/^\//, '')];
}
if (flatMenuKeys.indexOf(path.replace(/^\//, '').replace(/\/$/, '')) > -1) {
return [path.replace(/^\//, '').replace(/\/$/, '')];
}
return flatMenuKeys.filter((item) => {
const itemRegExpStr = `^${item.replace(/:[\w-]+/g, '[\\w-]+')}$`;
const itemRegExp = new RegExp(itemRegExpStr);
return itemRegExp.test(path.replace(/^\//, ''));
});
}
getNavMenuItems(menusData) {
if (!menusData) {
return [];
}
......@@ -47,13 +74,14 @@ export default class SiderMenu extends PureComponent {
return null;
}
let itemPath;
if (item.path.indexOf('http') === 0) {
if (item.path && item.path.indexOf('http') === 0) {
itemPath = item.path;
} else {
itemPath = `${parentPath}/${item.path || ''}`.replace(/\/+/g, '/');
itemPath = `/${item.path || ''}`.replace(/\/+/g, '/');
}
if (item.children && item.children.some(child => child.name)) {
return (
return item.hideInMenu ? null :
(
<SubMenu
title={
item.icon ? (
......@@ -65,12 +93,13 @@ export default class SiderMenu extends PureComponent {
}
key={item.key || item.path}
>
{this.getNavMenuItems(item.children, itemPath)}
{this.getNavMenuItems(item.children)}
</SubMenu>
);
}
const icon = item.icon && <Icon type={item.icon} />;
return (
return item.hideInMenu ? null :
(
<Menu.Item key={item.key || item.path}>
{
/^https?:\/\//.test(itemPath) ? (
......@@ -101,8 +130,7 @@ export default class SiderMenu extends PureComponent {
});
}
render() {
const { collapsed } = this.props;
const { collapsed, location: { pathname } } = this.props;
// Don't show popup menu when it is been collapsed
const menuProps = collapsed ? {} : {
openKeys: this.state.openKeys,
......@@ -128,7 +156,7 @@ export default class SiderMenu extends PureComponent {
mode="inline"
{...menuProps}
onOpenChange={this.handleOpenChange}
selectedKeys={this.getCurrentMenuSelectedKeys()}
selectedKeys={this.getSelectedMenuKeys(pathname)}
style={{ padding: '16px 0', width: '100%' }}
>
{this.getNavMenuItems(this.menus)}
......
......@@ -10,6 +10,7 @@ import GlobalHeader from '../components/GlobalHeader';
import GlobalFooter from '../components/GlobalFooter';
import SiderMenu from '../components/SiderMenu';
import NotFound from '../routes/Exception/404';
import { getRoutes } from '../utils/utils';
const { Content } = Layout;
......@@ -38,56 +39,31 @@ class BasicLayout extends React.PureComponent {
static childContextTypes = {
location: PropTypes.object,
breadcrumbNameMap: PropTypes.object,
routeData: PropTypes.array,
}
getChildContext() {
const { location, navData, getRouteData } = this.props;
const routeData = getRouteData('BasicLayout');
const firstMenuData = navData.reduce((arr, current) => arr.concat(current.children), []);
const menuData = this.getMenuData(firstMenuData, '');
const breadcrumbNameMap = {};
routeData.concat(menuData).forEach((item) => {
breadcrumbNameMap[item.path] = {
name: item.name,
component: item.component,
const { location, routerData } = this.props;
return {
location,
breadcrumbNameMap: routerData,
};
});
return { location, breadcrumbNameMap, routeData };
}
getPageTitle() {
const { location, getRouteData } = this.props;
const { routerData, location } = this.props;
const { pathname } = location;
let title = 'Ant Design Pro';
getRouteData('BasicLayout').forEach((item) => {
if (item.path === pathname) {
title = `${item.name} - Ant Design Pro`;
if (routerData[pathname] && routerData[pathname].name) {
title = `${routerData[pathname].name} - Ant Design Pro`;
}
});
return title;
}
getMenuData = (data, parentPath) => {
let arr = [];
data.forEach((item) => {
if (item.name) {
arr.push({ path: `${parentPath}/${item.path}`, name: item.name });
}
if (item.children) {
arr = arr.concat(this.getMenuData(item.children, `${parentPath}/${item.path}`));
}
});
return arr;
}
render() {
const {
currentUser, collapsed, fetchingNotices, notices, getRouteData, navData, location, dispatch,
currentUser, collapsed, fetchingNotices, notices, routerData, match, location, dispatch,
} = this.props;
const layout = (
<Layout>
<SiderMenu
collapsed={collapsed}
navData={navData}
location={location}
dispatch={dispatch}
/>
......@@ -103,19 +79,19 @@ class BasicLayout extends React.PureComponent {
<div style={{ minHeight: 'calc(100vh - 260px)' }}>
<Switch>
{
getRouteData('BasicLayout').map(item =>
getRoutes(match.path, routerData).map(item =>
(
<Route
exact={item.exact}
key={item.path}
key={item.key}
path={item.path}
component={item.component}
exact={item.exact}
/>
)
)
}
<Redirect exact from="/" to="/dashboard/analysis" />
<Route component={NotFound} />
<Route render={NotFound} />
</Switch>
</div>
<GlobalFooter
......
import React from 'react';
import PropTypes from 'prop-types';
import { Link, Route } from 'dva/router';
import DocumentTitle from 'react-document-title';
import { Icon } from 'antd';
import GlobalFooter from '../components/GlobalFooter';
import styles from './UserLayout.less';
import logo from '../assets/logo.svg';
import { getRoutes } from '../utils/utils';
const links = [{
title: '帮助',
......@@ -21,27 +21,17 @@ const links = [{
const copyright = <div>Copyright <Icon type="copyright" /> 2017 蚂蚁金服体验技术部出品</div>;
class UserLayout extends React.PureComponent {
static childContextTypes = {
location: PropTypes.object,
}
getChildContext() {
const { location } = this.props;
return { location };
}
getPageTitle() {
const { getRouteData, location } = this.props;
const { routerData, location } = this.props;
const { pathname } = location;
let title = 'Ant Design Pro';
getRouteData('UserLayout').forEach((item) => {
if (item.path === pathname) {
title = `${item.name} - Ant Design Pro`;
if (routerData[pathname] && routerData[pathname].name) {
title = `${routerData[pathname].name} - Ant Design Pro`;
}
});
return title;
}
render() {
const { getRouteData } = this.props;
const { routerData, match } = this.props;
return (
<DocumentTitle title={this.getPageTitle()}>
<div className={styles.container}>
......@@ -55,13 +45,13 @@ class UserLayout extends React.PureComponent {
<div className={styles.desc}>Ant Design 是西湖区最具影响力的 Web 设计规范</div>
</div>
{
getRouteData('UserLayout').map(item =>
getRoutes(match.path, routerData).map(item =>
(
<Route
exact={item.exact}
key={item.path}
key={item.key}
path={item.path}
component={item.component}
exact={item.exact}
/>
)
)
......
......@@ -3,9 +3,7 @@ import { Router, Route, Switch } from 'dva/router';
import { LocaleProvider, Spin } from 'antd';
import zhCN from 'antd/lib/locale-provider/zh_CN';
import dynamic from 'dva/dynamic';
import cloneDeep from 'lodash/cloneDeep';
import { getNavData } from './common/nav';
import { getPlainNode } from './utils/utils';
import { getRouterData } from './common/router';
import styles from './index.less';
......@@ -13,49 +11,16 @@ dynamic.setDefaultLoadingComponent(() => {
return <Spin size="large" className={styles.globalSpin} />;
});
function getRouteData(navData, path) {
if (!navData.some(item => item.layout === path) ||
!(navData.filter(item => item.layout === path)[0].children)) {
return null;
}
const route = cloneDeep(navData.filter(item => item.layout === path)[0]);
const nodeList = getPlainNode(route.children);
return nodeList;
}
function getLayout(navData, path) {
if (!navData.some(item => item.layout === path) ||
!(navData.filter(item => item.layout === path)[0].children)) {
return null;
}
const route = navData.filter(item => item.layout === path)[0];
return {
component: route.component,
layout: route.layout,
name: route.name,
path: route.path,
};
}
function RouterConfig({ history, app }) {
const navData = getNavData(app);
const UserLayout = getLayout(navData, 'UserLayout').component;
const BasicLayout = getLayout(navData, 'BasicLayout').component;
const passProps = {
app,
navData,
getRouteData: (path) => {
return getRouteData(navData, path);
},
};
const routerData = getRouterData(app);
const UserLayout = routerData['/user'].component;
const BasicLayout = routerData['/'].component;
return (
<LocaleProvider locale={zhCN}>
<Router history={history}>
<Switch>
<Route path="/user" render={props => <UserLayout {...props} {...passProps} />} />
<Route path="/" render={props => <BasicLayout {...props} {...passProps} />} />
<Route path="/user" render={props => <UserLayout {...props} />} />
<Route path="/" render={props => <BasicLayout {...props} />} />
</Switch>
</Router>
</LocaleProvider>
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { routerRedux, Route, Switch } from 'dva/router';
import { routerRedux, Route, Switch, Redirect } from 'dva/router';
import { connect } from 'dva';
import { Input } from 'antd';
import PageHeaderLayout from '../../layouts/PageHeaderLayout';
import { getRoutes } from '../../utils/utils';
@connect()
export default class SearchList extends Component {
static contextTypes = {
routeData: PropTypes.array,
};
handleTabChange = (key) => {
const { dispatch, match } = this.props;
switch (key) {
......@@ -52,9 +48,8 @@ export default class SearchList extends Component {
</div>
);
const { match } = this.props;
const { routeData } = this.context;
const routes = routeData.filter(item => item.path === match.path)[0].children;
const { match, routerData } = this.props;
const routes = getRoutes(match.path, routerData);
return (
<PageHeaderLayout
......@@ -68,13 +63,15 @@ export default class SearchList extends Component {
routes.map(item =>
(
<Route
key={item.path}
path={`${match.path}/${item.path}`}
key={item.key}
path={item.path}
component={item.component}
exact={item.exact}
/>
)
)
}
<Redirect exact from={`${match.path}`} to={`${match.path}${routes[0]}`} />
</Switch>
</PageHeaderLayout>
);
......
......@@ -92,3 +92,43 @@ export function digitUppercase(n) {
return s.replace(/(零.)*零元/, '').replace(/(零.)+/g, '').replace(/^整$/, '零元整');
}
function getRelation(str1, str2) {
if (str1 === str2) {
console.warn('Two path are equal!');
}
const arr1 = str1.split('/');
const arr2 = str2.split('/');
if (arr2.every((item, index) => item === arr1[index])) {
return 1;
} else if (arr1.every((item, index) => item === arr2[index])) {
return 2;
}
return 3;
}
export function getRoutes(path, routerData) {
let routes = Object.keys(routerData).filter(routePath =>
routePath.indexOf(path) === 0 && routePath !== path);
routes = routes.map(item => item.replace(path, ''));
let renderArr = [];
renderArr.push(routes[0]);
for (let i = 1; i < routes.length; i += 1) {
let isAdd = false;
isAdd = renderArr.every(item => getRelation(item, routes[i]) === 3);
renderArr = renderArr.filter(item => getRelation(item, routes[i]) !== 1);
if (isAdd) {
renderArr.push(routes[i]);
}
}
const renderRoutes = renderArr.map((item) => {
const exact = !routes.some(route => route !== item && getRelation(route, item) === 1);
return {
key: `${path}${item}`,
path: `${path}${item}`,
component: routerData[`${path}${item}`].component,
exact,
};
});
return renderRoutes;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment