Commit cfc0aea5 authored by ddcat1115's avatar ddcat1115 Committed by GitHub

Dva@2 (#13)

* temp save

* upgrade to dva@2

* update

* fix ci

* remove useless Link & add missing `to` prop setting
parent 9e5bbe7a
......@@ -113,6 +113,8 @@ export const getNotice = [
description: '那是一种内在的东西, 他们到达不了,也无法触及的',
updatedAt: new Date(),
member: '科学搬砖组',
href: '',
memberLink: '',
},
{
id: 'xxx2',
......@@ -121,6 +123,8 @@ export const getNotice = [
description: '希望是一个好东西,也许是最好的,好东西是不会消亡的',
updatedAt: new Date('2017-07-24 11:00:00'),
member: '全组都是吴彦祖',
href: '',
memberLink: '',
},
{
id: 'xxx3',
......@@ -129,6 +133,8 @@ export const getNotice = [
description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
updatedAt: new Date(),
member: '中二少女团',
href: '',
memberLink: '',
},
{
id: 'xxx4',
......@@ -137,6 +143,8 @@ export const getNotice = [
description: '那时候我只会想自己想要什么,从不想自己拥有什么',
updatedAt: new Date('2017-07-23 06:23:00'),
member: '程序员日常',
href: '',
memberLink: '',
},
{
id: 'xxx5',
......@@ -145,6 +153,8 @@ export const getNotice = [
description: '凛冬将至',
updatedAt: new Date('2017-07-23 06:23:00'),
member: '高逼格设计天团',
href: '',
memberLink: '',
},
{
id: 'xxx6',
......@@ -153,6 +163,8 @@ export const getNotice = [
description: '生命就像一盒巧克力,结果往往出人意料',
updatedAt: new Date('2017-07-23 06:23:00'),
member: '骗你来学计算机',
href: '',
memberLink: '',
},
];
......
......@@ -17,15 +17,16 @@
},
"dependencies": {
"antd": "next",
"dva": "^2.0.3",
"classnames": "^2.2.5",
"dva": "^1.2.1",
"lodash": "^4.17.4",
"numeral": "^2.0.6",
"prop-types": "^15.5.10",
"qs": "^6.5.0",
"react": "^15.6.2",
"react-document-title": "^2.0.3",
"react-dom": "^15.6.2"
"react-dom": "^15.6.2",
"lodash.clonedeep": "^4.5.0"
},
"devDependencies": {
"babel-eslint": "^8.0.1",
......@@ -56,7 +57,7 @@
"nightmare": "^2.10.0",
"react-test-renderer": "^15.6.2",
"redbox-react": "^1.3.2",
"roadhog": "^1.0.2",
"roadhog": "^1.2.1",
"roadhog-api-doc": "^0.1.8",
"stylelint": "^8.1.0",
"stylelint-config-standard": "^17.0.0"
......
......@@ -34,6 +34,7 @@ import RegisterResult from '../routes/User/RegisterResult';
const data = [{
component: BasicLayout,
layout: 'BasicLayout',
name: '首页', // for breadcrumb
path: '',
children: [{
......@@ -152,6 +153,7 @@ const data = [{
}],
}, {
component: UserLayout,
layout: 'UserLayout',
children: [{
name: '帐户',
icon: 'user',
......
......@@ -18,6 +18,8 @@ export default class PageHeader extends PureComponent {
static contextTypes = {
routes: PropTypes.array,
params: PropTypes.object,
location: PropTypes.object,
breadcrumbNameMap: PropTypes.object,
};
onChange = (key) => {
if (this.props.onTabChange) {
......@@ -28,10 +30,12 @@ export default class PageHeader extends PureComponent {
return {
routes: this.props.routes || this.context.routes,
params: this.props.params || this.context.params,
location: this.props.location || this.context.location,
breadcrumbNameMap: this.props.breadcrumbNameMap || this.context.breadcrumbNameMap,
};
};
render() {
const { routes, params } = this.getBreadcrumbProps();
const { routes, params, location, breadcrumbNameMap } = this.getBreadcrumbProps();
const { title, logo, action, content, extraContent,
breadcrumbList, tabList, className } = this.props;
const clsString = classNames(styles.pageHeader, className);
......@@ -45,6 +49,28 @@ export default class PageHeader extends PureComponent {
itemRender={itemRender}
/>
);
} else if (location && location.pathname) {
const pathSnippets = location.pathname.split('/').filter(i => i);
const extraBreadcrumbItems = pathSnippets.map((_, index) => {
const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;
return (
<Breadcrumb.Item key={url}>
<Link to={url}>
{breadcrumbNameMap[url] || breadcrumbNameMap[url.replace('/', '')] || url}
</Link>
</Breadcrumb.Item>
);
});
const breadcrumbItems = [(
<Breadcrumb.Item key="home">
<Link to="/">Home</Link>
</Breadcrumb.Item>
)].concat(extraBreadcrumbItems);
breadcrumb = (
<Breadcrumb className={styles.breadcrumb}>
{breadcrumbItems}
</Breadcrumb>
);
} else if (breadcrumbList && breadcrumbList.length) {
breadcrumb = (
<Breadcrumb className={styles.breadcrumb}>
......
import dva from 'dva';
import G2 from 'g2';
// import { browserHistory } from 'dva/router';
import 'moment/locale/zh-cn';
import models from './models';
// import { browserHistory } from 'dva/router';
import './index.less';
G2.track(false);
......@@ -16,7 +15,7 @@ const app = dva({
// 2. Plugins
// app.use({});
// 3. Model
// 3. Model move to router
models.forEach((m) => {
app.model(m);
});
......
......@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Layout, Menu, Icon, Avatar, Dropdown, Tag, message, Spin } from 'antd';
import DocumentTitle from 'react-document-title';
import { connect } from 'dva';
import { Link, routerRedux } from 'dva/router';
import { Link, routerRedux, Route, Redirect, Switch } from 'dva/router';
import moment from 'moment';
import groupBy from 'lodash/groupBy';
import styles from './BasicLayout.less';
......@@ -11,14 +11,15 @@ import HeaderSearch from '../components/HeaderSearch';
import NoticeIcon from '../components/NoticeIcon';
import GlobalFooter from '../components/GlobalFooter';
import { getNavData } from '../common/nav';
import { getRouteData } from '../utils/utils';
const { Header, Sider, Content } = Layout;
const { SubMenu } = Menu;
class BasicLayout extends React.PureComponent {
static childContextTypes = {
routes: PropTypes.array,
params: PropTypes.object,
location: PropTypes.object,
breadcrumbNameMap: PropTypes.object,
}
constructor(props) {
super(props);
......@@ -29,8 +30,14 @@ class BasicLayout extends React.PureComponent {
};
}
getChildContext() {
const { routes, params } = this.props;
return { routes, params };
const { location } = this.props;
const routeData = getRouteData('BasicLayout');
const menuData = getNavData().reduce((arr, current) => arr.concat(current.children), []);
const breadcrumbNameMap = {};
routeData.concat(menuData).forEach((item) => {
breadcrumbNameMap[item.path] = item.name;
});
return { location, breadcrumbNameMap };
}
componentDidMount() {
this.props.dispatch({
......@@ -98,13 +105,15 @@ class BasicLayout extends React.PureComponent {
});
}
getPageTitle() {
const { routes } = this.props;
for (let i = routes.length - 1; i >= 0; i -= 1) {
if (routes[i].breadcrumbName) {
return `${routes[i].breadcrumbName} - Ant Design Pro`;
const { 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`;
}
}
return 'Ant Design Pro';
});
return title;
}
getNoticeData() {
const { notices = [] } = this.props;
......@@ -161,7 +170,7 @@ class BasicLayout extends React.PureComponent {
}
}
render() {
const { children, currentUser, collapsed, fetchingNotices } = this.props;
const { currentUser, collapsed, fetchingNotices } = this.props;
const menu = (
<Menu className={styles.menu} selectedKeys={[]} onClick={this.onMenuClick}>
......@@ -171,7 +180,6 @@ class BasicLayout extends React.PureComponent {
<Menu.Item key="logout"><Icon type="logout" />退出登录</Menu.Item>
</Menu>
);
const noticeData = this.getNoticeData();
// Don't show popup menu when it is been collapsed
......@@ -270,7 +278,21 @@ class BasicLayout extends React.PureComponent {
</div>
</Header>
<Content style={{ margin: '24px 24px 0', height: '100%' }}>
{children}
<Switch>
{
getRouteData('BasicLayout').map(item =>
(
<Route
exact={item.exact}
key={item.path}
path={item.path}
component={item.component}
/>
)
)
}
<Redirect to="/dashboard/analysis" />
</Switch>
<GlobalFooter
links={[{
title: '帮助',
......
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'dva/router';
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 { getRouteData } from '../utils/utils';
const links = [{
title: '帮助',
......@@ -21,25 +22,24 @@ const copyright = <div>Copyright <Icon type="copyright" /> 2017 蚂蚁金服体
class UserLayout extends React.PureComponent {
static childContextTypes = {
routes: PropTypes.array,
params: PropTypes.object,
location: PropTypes.object,
}
getChildContext() {
const { routes, params } = this.props;
return { routes, params };
const { location } = this.props;
return { location };
}
getPageTitle() {
const { routes } = this.props;
for (let i = routes.length - 1; i >= 0; i -= 1) {
if (routes[i].breadcrumbName) {
return `${routes[i].breadcrumbName} - Ant Design Pro`;
const { 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`;
}
}
return 'Ant Design Pro';
});
return title;
}
render() {
const { children } = this.props;
return (
<DocumentTitle title={this.getPageTitle()}>
<div className={styles.container}>
......@@ -52,7 +52,18 @@ class UserLayout extends React.PureComponent {
</div>
<p className={styles.desc}>Ant Design 是西湖区最具影响力的 Web 设计规范</p>
</div>
{children}
{
getRouteData('UserLayout').map(item =>
(
<Route
exact={item.exact}
key={item.path}
path={item.path}
component={item.component}
/>
)
)
}
<GlobalFooter className={styles.footer} links={links} copyright={copyright} />
</div>
</DocumentTitle>
......
import React from 'react';
import { Router, Route, Redirect } from 'dva/router';
import { Router, Route, Switch, Redirect } from 'dva/router';
import { LocaleProvider } from 'antd';
import zhCN from 'antd/lib/locale-provider/zh_CN';
import navData from './common/nav';
function getRoutes(data, level = 0) {
return data.map((item, i) => {
let children;
if (item.children) {
children = getRoutes(item.children, level + 1);
}
let homePageRedirect;
if (level === 1 && i === 0) {
let indexPath;
// First children router
if (item.children && item.children[0]) {
indexPath = `/${item.path}/${item.children[0].path}`;
} else {
indexPath = item.path;
}
homePageRedirect = <Redirect from="/" to={indexPath} />;
}
if (item.noRoute) {
return null;
}
return (
<Route
key={item.key || item.path || ''}
path={item.path}
breadcrumbName={item.name}
component={item.component}
>
{homePageRedirect}
{children}
</Route>
);
});
}
import BasicLayout from './layouts/BasicLayout';
import UserLayout from './layouts/UserLayout';
function RouterConfig({ history }) {
return (
<LocaleProvider locale={zhCN}>
<Router history={history}>
{getRoutes(navData)}
<Switch>
<Route path="/user" component={UserLayout} />
<Route path="/" component={BasicLayout} />
<Redirect to="/" />
</Switch>
</Router>
</LocaleProvider>
);
......
import React, { cloneElement, PureComponent } from 'react';
import React, { PureComponent } from 'react';
import { connect } from 'dva';
import { Card, Steps, Form } from 'antd';
import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
import Step1 from './Step1';
import Step2 from './Step2';
import Step3 from './Step3';
import styles from '../style.less';
const { Step } = Steps;
......@@ -10,16 +12,26 @@ const { Step } = Steps;
@Form.create()
class StepForm extends PureComponent {
getCurrentStep() {
const { routes } = this.props;
switch (routes[routes.length - 1].path) {
const { location } = this.props;
const { pathname } = location;
const pathList = pathname.split('/');
switch (pathList[pathList.length - 1]) {
case 'step-form': return 0;
case 'confirm': return 1;
case 'result': return 2;
default: return 0;
}
}
getCurrentComponent() {
const componentMap = {
0: Step1,
1: Step2,
2: Step3,
};
return componentMap[this.getCurrentStep()];
}
render() {
const { form, stepFormData, submitting, dispatch, children } = this.props;
const { form, stepFormData, submitting, dispatch } = this.props;
const formItemLayout = {
labelCol: {
span: 5,
......@@ -28,6 +40,7 @@ class StepForm extends PureComponent {
span: 19,
},
};
const CurrentComponent = this.getCurrentComponent();
return (
<PageHeaderLayout title="分步表单" content="将表单内容进行分步可以提高用户处理的专注度,降低页面复杂性。">
<Card bordered={false}>
......@@ -37,19 +50,13 @@ class StepForm extends PureComponent {
<Step title="确认转账信息" />
<Step title="完成" />
</Steps>
{children ? cloneElement(children, {
form,
formItemLayout,
data: stepFormData,
submitting,
dispatch,
}) : (
<Step1
formItemLayout={formItemLayout}
form={form}
dispatch={dispatch}
/>
)}
<CurrentComponent
formItemLayout={formItemLayout}
form={form}
dispatch={dispatch}
data={stepFormData}
submitting={submitting}
/>
</div>
</Card>
</PageHeaderLayout>
......
import React, { PureComponent } from 'react';
import moment from 'moment';
import { connect } from 'dva';
import { Link, routerRedux } from 'dva/router';
import { routerRedux } from 'dva/router';
import { Row, Col, Form, Card, Select, List, Input } from 'antd';
import PageHeaderLayout from '../../layouts/PageHeaderLayout';
......@@ -78,33 +78,31 @@ export default class CoverCardList extends PureComponent {
dataSource={list}
renderItem={item => (
<List.Item>
<Link>
<Card
hoverable
cover={<img alt={item.title} src={item.cover} />}
>
<Card.Meta
title={item.title}
description={item.subDescription}
/>
<div className={styles.cardItemContent}>
<span>{moment(item.updatedAt).fromNow()}</span>
<div className={styles.avatarList}>
<AvatarList size="mini">
{
item.members.map((member, i) => (
<AvatarList.Item
key={`${item.id}-avatar-${i}`}
src={member.avatar}
tips={member.name}
/>
))
}
</AvatarList>
</div>
<Card
hoverable
cover={<img alt={item.title} src={item.cover} />}
>
<Card.Meta
title={item.title}
description={item.subDescription}
/>
<div className={styles.cardItemContent}>
<span>{moment(item.updatedAt).fromNow()}</span>
<div className={styles.avatarList}>
<AvatarList size="mini">
{
item.members.map((member, i) => (
<AvatarList.Item
key={`${item.id}-avatar-${i}`}
src={member.avatar}
tips={member.name}
/>
))
}
</AvatarList>
</div>
</Card>
</Link>
</div>
</Card>
</List.Item>
)}
/>
......
import moment from 'moment';
import cloneDeep from 'lodash/cloneDeep';
import navData from '../common/nav';
export function fixedZero(val) {
return val * 1 < 10 ? `0${val}` : val;
......@@ -48,3 +51,31 @@ export function getTimeDistance(type) {
return [moment(`${year}-01-01 00:00:00`), moment(`${year}-12-31 23:59:59`)];
}
}
function getPlainNode(nodeList, parentPath = '') {
const arr = [];
nodeList.forEach((node) => {
const item = node;
item.path = `${parentPath}/${item.path || ''}`.replace(/\/+/g, '/');
item.exact = true;
if (item.children && !item.component) {
arr.push(...getPlainNode(item.children, item.path));
} else {
if (item.children && item.component) {
item.exact = false;
}
arr.push(item);
}
});
return arr;
}
export function getRouteData(path) {
if (!navData.some(item => item.layout === path) ||
!(navData.filter(item => item.layout === path)[0].children)) {
return null;
}
const dataList = cloneDeep(navData.filter(item => item.layout === path)[0]);
const nodeList = getPlainNode(dataList.children);
return nodeList;
}
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