diff --git a/.roadhogrc.mock.js b/.roadhogrc.mock.js index 4142c517d809e65cb7dbc257fa9c38eb9635ee95..da9321e4072cdd2bf2afe1bd4384d37e710f5253 100644 --- a/.roadhogrc.mock.js +++ b/.roadhogrc.mock.js @@ -30,6 +30,28 @@ const proxy = { userid: '00000001', email: 'antdesign@alipay.com', profile: '简单的介绍下自己', + signature: '海纳百川,有容乃大', + title: '交互专家', + group: '蚂蚁金服-平台数据技术事业群-基础平台部-用户体验技术部-UED', + tags: [{ + key: '0', + label: '很有想法的', + }, { + key: '1', + label: '专注设计', + }, { + key: '2', + label: '辣~', + }, { + key: '3', + label: '大长腿', + }, { + key: '4', + label: '川妹子', + }, { + key: '5', + label: '海纳百川', + }], notifyCount: 12, country: 'China', geographic: { diff --git a/mock/api.js b/mock/api.js index e596c755fc51a580c47974b454b52e2dea39361a..26141d942a39b0b8cba97e22cf6dbaf3d54009f4 100644 --- a/mock/api.js +++ b/mock/api.js @@ -88,14 +88,17 @@ export function fakeList(count) { { avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png', name: '曲丽丽', + id: 'member1', }, { avatar: 'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png', name: '王昭君', + id: 'member2', }, { avatar: 'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png', name: '董娜娜', + id: 'member3', }, ], }); diff --git a/src/common/router.js b/src/common/router.js index e0514c450ff6ac97ab7aaca0033341d5e828af44..aca4ead7d2959c318cfed598a81618d3614fcbb1 100644 --- a/src/common/router.js +++ b/src/common/router.js @@ -148,6 +148,9 @@ export const getRouterData = (app) => { '/exception/trigger': { component: dynamicWrapper(app, ['error'], () => import('../routes/Exception/triggerException')), }, + '/user-center': { + component: dynamicWrapper(app, ['list', 'user', 'project'], () => import('../routes/UserCenter')), + }, '/user': { component: dynamicWrapper(app, [], () => import('../layouts/UserLayout')), }, diff --git a/src/components/GlobalHeader/index.js b/src/components/GlobalHeader/index.js index bf22747b1608ae3e37ea96143de182d7284a85fc..1c4a567d934cc3ce04f943b343db9b8d22733c5e 100644 --- a/src/components/GlobalHeader/index.js +++ b/src/components/GlobalHeader/index.js @@ -57,7 +57,7 @@ export default class GlobalHeader extends PureComponent { } = this.props; const menu = ( - 个人中心 + 个人中心 设置 触发报错 diff --git a/src/layouts/BasicLayout.js b/src/layouts/BasicLayout.js index 90a5f56f66c0651cfa7ce4349a46f91f15aa140f..7bd774246d9102646dd8ecf83399257d6bce175d 100644 --- a/src/layouts/BasicLayout.js +++ b/src/layouts/BasicLayout.js @@ -127,6 +127,10 @@ class BasicLayout extends React.PureComponent { }); } handleMenuClick = ({ key }) => { + if (key === 'userCenter') { + this.props.dispatch(routerRedux.push('/user-center')); + return; + } if (key === 'triggerError') { this.props.dispatch(routerRedux.push('/exception/trigger')); return; diff --git a/src/routes/List/Applications.js b/src/routes/List/Applications.js index 83d1369ff0c31dfa952f0ac8a4a895e685390b4c..f65f13bde087110d2b8eb4eafeffaedbcbc7b86d 100644 --- a/src/routes/List/Applications.js +++ b/src/routes/List/Applications.js @@ -5,24 +5,13 @@ import { Row, Col, Form, Card, Select, Icon, Avatar, List, Tooltip, Dropdown, Me import StandardFormRow from '../../components/StandardFormRow'; import TagSelect from '../../components/TagSelect'; +import { formatWan } from '../../utils/utils'; import styles from './Applications.less'; const { Option } = Select; const FormItem = Form.Item; -const formatWan = (val) => { - const v = val * 1; - if (!v || isNaN(v)) return ''; - - let result = val; - if (val > 10000) { - result = Math.floor(val / 10000); - result = {result}; - } - return result; -}; - /* eslint react/no-array-index-key: 0 */ @Form.create() @connect(({ list, loading }) => ({ diff --git a/src/routes/List/Applications.less b/src/routes/List/Applications.less index 7c7747eaf2d2eb759b50c972de63b7a7f6efd507..ae1ace86981e8526984047da2682881041765385 100644 --- a/src/routes/List/Applications.less +++ b/src/routes/List/Applications.less @@ -38,12 +38,3 @@ } } } - -.wan { - position: relative; - top: -2px; - font-size: @font-size-base; - font-style: normal; - line-height: 20px; - margin-left: 2px; -} diff --git a/src/routes/UserCenter.js b/src/routes/UserCenter.js new file mode 100644 index 0000000000000000000000000000000000000000..c4f3ef8cf92b91fb42758c1261b09e8bce656574 --- /dev/null +++ b/src/routes/UserCenter.js @@ -0,0 +1,293 @@ +import React, { PureComponent } from 'react'; +import { connect } from 'dva'; +import moment from 'moment'; +import numeral from 'numeral'; +import { List, Card, Row, Col, Icon, Dropdown, + Menu, Avatar, Tag, Divider, Tooltip, Spin } from 'antd'; +import AvatarList from '../components/AvatarList'; +import { formatWan } from '../utils/utils'; +import styles from './UserCenter.less'; +import stylesArticles from './List/Articles.less'; +import stylesApplications from './List/Applications.less'; +import stylesProjects from './List/Projects.less'; + +@connect(({ list, loading, user, project }) => ({ + list, + listLoading: loading.effects['list/fetch'], + currentUser: user.currentUser, + currentUserLoading: loading.effects['user/fetchCurrent'], + project, + projectLoading: loading.effects['project/fetchNotice'], +})) +export default class UserCenter extends PureComponent { + state = { + key: 'article', + } + + componentDidMount() { + const { dispatch } = this.props; + this.props.dispatch({ + type: 'user/fetchCurrent', + }); + dispatch({ + type: 'list/fetch', + payload: { + count: 8, + }, + }); + dispatch({ + type: 'project/fetchNotice', + }); + } + + onTabChange = (key) => { + this.setState({ key }); + } + + renderArticles = (list, loading) => { + const IconText = ({ type, text }) => ( + + + {text} + + ); + const ListContent = ({ data: { content, updatedAt, avatar, owner, href } }) => ( +
+
{content}
+
+ {owner} 发布在 {href} + {moment(updatedAt).format('YYYY-MM-DD HH:mm')} +
+
+ ); + return ( + ( + , + , + , + ]} + > + {item.title} + )} + description={ + + Ant Design + 设计语言 + 蚂蚁金服 + + } + /> + + + )} + /> + ); + } + + renderApplications = (list, loading) => { + const itemMenu = ( + + + 1st menu item + + + 2nd menu item + + + 3d menu item + + + ); + const CardInfo = ({ activeUser, newUser }) => ( +
+
+

活跃用户

+

{activeUser}

+
+
+

新增用户

+

{newUser}

+
+
+ ); + return ( + ( + + , + , + , + , + ]} + > + } + title={item.title} + /> +
+ +
+
+
+ )} + /> + ); + } + + renderProjects = (list, loading) => { + return ( + ( + + } + > + {item.title}} + description={item.subDescription} + /> +
+ {moment(item.updatedAt).fromNow()} +
+ + { + item.members.map(member => ( + + )) + } + +
+
+
+
+ )} + /> + ); + } + + render() { + const { list: { list }, listLoading, currentUser, currentUserLoading, + project: { notice }, projectLoading } = this.props; + const operationTabList = [{ + key: 'article', + tab: '文章(8)', + }, { + key: 'application', + tab: '应用(8)', + }, { + key: 'project', + tab: '项目(8)', + }]; + const contentMap = { + article: this.renderArticles(list, listLoading), + application: this.renderApplications(list, listLoading), + project: this.renderProjects(list, listLoading), + }; + + return ( +
+ + + + { + currentUser && Object.keys(currentUser).length ? + ( +
+
+ +
{currentUser.name}
+
{currentUser.signature}
+
+
+

{currentUser.title}

+

{currentUser.group}

+

+ {currentUser.geographic.province.label} + {currentUser.geographic.city.label} +

+
+ +
+
标签
+ { + currentUser.tags.map(item => {item.label}) + } + + + +
+ +
+
团队
+ + + { + notice.map(item => ( + + + {item.member} + + )) + } + + +
+
+ ) : 'loading...' + } +
+ + + + {contentMap[this.state.key]} + + +
+
+ ); + } +} diff --git a/src/routes/UserCenter.less b/src/routes/UserCenter.less new file mode 100644 index 0000000000000000000000000000000000000000..4fe92ba4fc5e8bda407802325a1fff944f82a314 --- /dev/null +++ b/src/routes/UserCenter.less @@ -0,0 +1,98 @@ +@import '~antd/lib/style/themes/default.less'; + +.avatarHolder { + text-align: center; + margin-bottom: 24px; + + & > img { + width: 104px; + height: 104px; + margin-bottom: 20px; + } + + .name { + font-size: 20px; + line-height: 28px; + font-weight: 500; + color: @heading-color; + margin-bottom: 4px; + } +} + +.detail { + p { + margin-bottom: 8px; + padding-left: 26px; + position: relative; + + &:last-child { + margin-bottom: 0; + } + } + + i { + position: absolute; + height: 14px; + width: 14px; + left: 0; + top: 4px; + background: url(https://gw.alipayobjects.com/zos/rmsportal/pBjWzVAHnOOtAUvZmZfy.svg); + + &.title { + background-position: 0 0; + } + + &.group { + background-position: 0 -22px; + } + + &.address { + background-position: 0 -44px; + } + } +} + +.tagsTitle, .teamTitle { + font-weight: 500; + color: @heading-color; + margin-bottom: 12px; +} + +.tags { + :global { + .ant-tag { + margin-bottom: 8px; + } + } +} + +.team { + :global { + .ant-avatar { + margin-right: 12px; + } + } + + .item { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + margin-bottom: 24px; + } +} + +.tabsCard { + :global { + .ant-card-head { + padding: 0 16px; + } + } +} + +.articleList { + :global { + .ant-list-item:first-child { + padding-top: 0; + } + } +} diff --git a/src/utils/utils.js b/src/utils/utils.js index 93fb54f4a0bcff5dcc04f3cd639f34f86aaa6fcc..bbdf52355094a426cf3ed4f233b742837619b6f5 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -1,4 +1,5 @@ import moment from 'moment'; +import React from 'react'; export function fixedZero(val) { return val * 1 < 10 ? `0${val}` : val; @@ -157,3 +158,30 @@ const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[- export function isUrl(path) { return reg.test(path); } + +export function formatWan(val) { + const v = val * 1; + if (!v || isNaN(v)) return ''; + + let result = val; + if (val > 10000) { + result = Math.floor(val / 10000); + result = ( + + {result} + + 万 + + + ); + } + return result; +}