diff --git a/src/components/GlobalHeader/RightContent.js b/src/components/GlobalHeader/RightContent.js new file mode 100644 index 0000000000000000000000000000000000000000..0b94093cae107696bf0a4a616fda6340d1f2851d --- /dev/null +++ b/src/components/GlobalHeader/RightContent.js @@ -0,0 +1,141 @@ +import React, { PureComponent } from 'react'; +import { Spin, Tag, Menu, Icon, Dropdown, Avatar, Tooltip } from 'antd'; +import moment from 'moment'; +import groupBy from 'lodash/groupBy'; +import NoticeIcon from '../NoticeIcon'; +import HeaderSearch from '../HeaderSearch'; +import styles from './index.less'; + +export default class GlobalHeaderRight extends PureComponent { + getNoticeData() { + const { notices = [] } = this.props; + if (notices.length === 0) { + return {}; + } + const newNotices = notices.map((notice) => { + const newNotice = { ...notice }; + if (newNotice.datetime) { + newNotice.datetime = moment(notice.datetime).fromNow(); + } + // transform id to item key + if (newNotice.id) { + newNotice.key = newNotice.id; + } + if (newNotice.extra && newNotice.status) { + const color = { + todo: '', + processing: 'blue', + urgent: 'red', + doing: 'gold', + }[newNotice.status]; + newNotice.extra = ( + + {newNotice.extra} + + ); + } + return newNotice; + }); + return groupBy(newNotices, 'type'); + } + render() { + const { + currentUser, + fetchingNotices, + onNoticeVisibleChange, + onMenuClick, + onNoticeClear, + } = this.props; + const menu = ( + + + 个人中心 + + + 设置 + + + 触发报错 + + + + 退出登录 + + + ); + const noticeData = this.getNoticeData(); + let className = styles.right; + if (this.props.theme === 'white') { + className = `${styles.right} ${styles.white}`; + } + return ( +
+ { + console.log('input', value); // eslint-disable-line + }} + onPressEnter={(value) => { + console.log('enter', value); // eslint-disable-line + }} + /> + + + + + + { + console.log(item, tabProps); // eslint-disable-line + }} + onClear={onNoticeClear} + onPopupVisibleChange={onNoticeVisibleChange} + loading={fetchingNotices} + popupAlign={{ offset: [20, -16] }} + > + + + + + {currentUser.name ? ( + + + + {currentUser.name} + + + ) : ( + + )} +
+ ); + } +} diff --git a/src/components/GlobalHeader/index.js b/src/components/GlobalHeader/index.js index a1a5614b325aa39f75c0f4e9d56bd7808491fce5..f6b7db5373534e5ab798bde4dc781a34e2f09bd5 100644 --- a/src/components/GlobalHeader/index.js +++ b/src/components/GlobalHeader/index.js @@ -1,148 +1,42 @@ import React, { PureComponent } from 'react'; -import { Menu, Icon, Spin, Tag, Dropdown, Avatar, Divider, Tooltip } from 'antd'; -import moment from 'moment'; -import groupBy from 'lodash/groupBy'; import Debounce from 'lodash-decorators/debounce'; +import { Icon, Divider } from 'antd'; import { Link } from 'dva/router'; -import NoticeIcon from '../NoticeIcon'; -import HeaderSearch from '../HeaderSearch'; import styles from './index.less'; +import RightContent from './RightContent'; export default class GlobalHeader extends PureComponent { componentWillUnmount() { this.triggerResizeEvent.cancel(); } - getNoticeData() { - const { notices = [] } = this.props; - if (notices.length === 0) { - return {}; - } - const newNotices = notices.map((notice) => { - const newNotice = { ...notice }; - if (newNotice.datetime) { - newNotice.datetime = moment(notice.datetime).fromNow(); - } - // transform id to item key - if (newNotice.id) { - newNotice.key = newNotice.id; - } - if (newNotice.extra && newNotice.status) { - const color = ({ - todo: '', - processing: 'blue', - urgent: 'red', - doing: 'gold', - })[newNotice.status]; - newNotice.extra = {newNotice.extra}; - } - return newNotice; - }); - return groupBy(newNotices, 'type'); - } - toggle = () => { - const { collapsed, onCollapse } = this.props; - onCollapse(!collapsed); - this.triggerResizeEvent(); - } @Debounce(600) - triggerResizeEvent() { // eslint-disable-line + triggerResizeEvent() { // eslint-disable-line const event = document.createEvent('HTMLEvents'); event.initEvent('resize', true, false); window.dispatchEvent(event); } + toggle = () => { + const { collapsed, onCollapse } = this.props; + onCollapse(!collapsed); + this.triggerResizeEvent(); + }; render() { - const { - currentUser, collapsed, fetchingNotices, isMobile, logo, - onNoticeVisibleChange, onMenuClick, onNoticeClear, - } = this.props; - const menu = ( - - 个人中心 - 设置 - 触发报错 - - 退出登录 - - ); - const noticeData = this.getNoticeData(); + const { collapsed, isMobile, logo } = this.props; return (
- {isMobile && ( - [ - ( - - logo - - ), - , - ] - )} + {isMobile && [ + + logo + , + , + ]} -
- { - console.log('input', value); // eslint-disable-line - }} - onPressEnter={(value) => { - console.log('enter', value); // eslint-disable-line - }} - /> - - - - - - { - console.log(item, tabProps); // eslint-disable-line - }} - onClear={onNoticeClear} - onPopupVisibleChange={onNoticeVisibleChange} - loading={fetchingNotices} - popupAlign={{ offset: [20, -16] }} - > - - - - - {currentUser.name ? ( - - - - {currentUser.name} - - - ) : } -
+ +
); } diff --git a/src/components/GlobalHeader/index.less b/src/components/GlobalHeader/index.less index a9e9d92f74e3e08fe35b06bc821f0094298f86cf..dfe717f9043ea914ef8605a743f25e549222540c 100644 --- a/src/components/GlobalHeader/index.less +++ b/src/components/GlobalHeader/index.less @@ -1,10 +1,10 @@ -@import "~antd/lib/style/themes/default.less"; +@import '~antd/lib/style/themes/default.less'; .header { height: 64px; padding: 0 12px 0 0; background: #fff; - box-shadow: 0 1px 4px rgba(0, 21, 41, .08); + box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); position: relative; } @@ -42,7 +42,7 @@ i.trigger { font-size: 20px; line-height: 64px; cursor: pointer; - transition: all .3s, padding 0s; + transition: all 0.3s, padding 0s; padding: 0 24px; &:hover { background: @primary-1; @@ -56,7 +56,7 @@ i.trigger { cursor: pointer; padding: 0 12px; display: inline-block; - transition: all .3s; + transition: all 0.3s; height: 100%; > i { font-size: 16px; @@ -69,8 +69,7 @@ i.trigger { } } .search { - padding: 0; - margin: 0 12px; + padding: 0 12px; &:hover { background: transparent; } @@ -79,12 +78,29 @@ i.trigger { .avatar { margin: 20px 8px 20px 0; color: @primary-color; - background: rgba(255, 255, 255, .85); + background: rgba(255, 255, 255, 0.85); vertical-align: middle; } } } +.white { + height: 64px; + .action { + color: rgba(255, 255, 255, 0.85); + > i { + color: rgba(255, 255, 255, 0.85); + } + &:hover, + &:global(.ant-popover-open) { + background: @primary-color; + } + :global(.ant-badge) { + color: rgba(255, 255, 255, 0.85); + } + } +} + @media only screen and (max-width: @screen-md) { .header { :global(.ant-divider-vertical) { diff --git a/src/components/SiderMenu/BaseMeun.js b/src/components/SiderMenu/BaseMeun.js new file mode 100644 index 0000000000000000000000000000000000000000..00c90e011e78491eadd93b6c5989b28331e02971 --- /dev/null +++ b/src/components/SiderMenu/BaseMeun.js @@ -0,0 +1,175 @@ +import React, { PureComponent } from 'react'; +import { Menu, Icon } from 'antd'; +import { Link } from 'dva/router'; +import pathToRegexp from 'path-to-regexp'; +import { urlToList } from '../utils/pathTools'; +import styles from './index.less'; + +const { SubMenu } = Menu; + +// Allow menu.js config icon as string or ReactNode +// icon: 'setting', +// icon: 'http://demo.com/icon.png', +// icon: , +const getIcon = (icon) => { + if (typeof icon === 'string' && icon.indexOf('http') === 0) { + return icon; + } + if (typeof icon === 'string') { + return ; + } + return icon; +}; + +export const getMeunMatcheys = (flatMenuKeys, path) => { + return flatMenuKeys.filter((item) => { + return pathToRegexp(item).test(path); + }); +}; + +export default class BaseMeun extends PureComponent { + constructor(props) { + super(props); + this.menus = props.menuData; + this.flatMenuKeys = this.getFlatMenuKeys(props.menuData); + } + /** + * Recursively flatten the data + * [{path:string},{path:string}] => {path,path2} + * @param menus + */ + getFlatMenuKeys(menus) { + let keys = []; + menus.forEach((item) => { + if (item.children) { + keys = keys.concat(this.getFlatMenuKeys(item.children)); + } + keys.push(item.path); + }); + return keys; + } + /** + * 获得菜单子节点 + * @memberof SiderMenu + */ + getNavMenuItems = (menusData) => { + if (!menusData) { + return []; + } + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item) => { + // make dom + const ItemDom = this.getSubMenuOrItem(item); + return this.checkPermissionItem(item.authority, ItemDom); + }) + .filter(item => item); + }; + // Get the currently selected menu + getSelectedMenuKeys = () => { + const { location: { pathname } } = this.props; + return urlToList(pathname).map(itemPath => + getMeunMatcheys(this.flatMenuKeys, itemPath).pop(), + ); + }; + /** + * get SubMenu or Item + */ + getSubMenuOrItem = (item) => { + if (item.children && item.children.some(child => child.name)) { + return ( + + {getIcon(item.icon)} + {item.name} + + ) : ( + item.name + ) + } + key={item.path} + > + {this.getNavMenuItems(item.children)} + + ); + } else { + return ( + {this.getMenuItemPath(item)} + ); + } + }; + /** + * 判断是否是http链接.返回 Link 或 a + * Judge whether it is http link.return a or Link + * @memberof SiderMenu + */ + getMenuItemPath = (item) => { + const itemPath = this.conversionPath(item.path); + const icon = getIcon(item.icon); + const { target, name } = item; + // Is it a http link + if (/^https?:\/\//.test(itemPath)) { + return ( + + {icon} + {name} + + ); + } + return ( + { + this.props.onCollapse(true); + } + : undefined + } + > + {icon} + {name} + + ); + }; + // permission to check + checkPermissionItem = (authority, ItemDom) => { + if (this.props.Authorized && this.props.Authorized.check) { + const { check } = this.props.Authorized; + return check(authority, ItemDom); + } + return ItemDom; + }; + conversionPath = (path) => { + if (path && path.indexOf('http') === 0) { + return path; + } else { + return `/${path || ''}`.replace(/\/+/g, '/'); + } + }; + render() { + const { openKeys } = this.props; + // if pathname can't match, use the nearest parent's key + let selectedKeys = this.getSelectedMenuKeys(); + if (!selectedKeys.length && openKeys) { + selectedKeys = [openKeys[openKeys.length - 1]]; + } + return ( + + {this.getNavMenuItems(this.menus)} + + ); + } +} diff --git a/src/components/SiderMenu/SiderMenu.js b/src/components/SiderMenu/SiderMenu.js index 072f5cea9eb4326ea3e0dafd0abde9c18a3311b2..5f5e17c150672fe5e6fc341b42f19b8dcd4d142d 100644 --- a/src/components/SiderMenu/SiderMenu.js +++ b/src/components/SiderMenu/SiderMenu.js @@ -1,32 +1,12 @@ import React, { PureComponent } from 'react'; -import { Layout, Menu, Icon } from 'antd'; -import pathToRegexp from 'path-to-regexp'; +import { Layout } from 'antd'; import { Link } from 'dva/router'; import styles from './index.less'; +import BaseMeun, { getMeunMatcheys } from './BaseMeun'; import { urlToList } from '../utils/pathTools'; -const { Sider } = Layout; -const { SubMenu } = Menu; - -// Allow menu.js config icon as string or ReactNode -// icon: 'setting', -// icon: 'http://demo.com/icon.png', -// icon: , -const getIcon = (icon) => { - if (typeof icon === 'string' && icon.indexOf('http') === 0) { - return icon; - } - if (typeof icon === 'string') { - return ; - } - return icon; -}; -export const getMeunMatcheys = (flatMenuKeys, path) => { - return flatMenuKeys.filter((item) => { - return pathToRegexp(item).test(path); - }); -}; +const { Sider } = Layout; export default class SiderMenu extends PureComponent { constructor(props) { @@ -44,19 +24,6 @@ export default class SiderMenu extends PureComponent { }); } } - /** - * Convert pathname to openKeys - * /list/search/articles = > ['list','/list/search'] - * @param props - */ - getDefaultCollapsedSubMenus(props) { - const { location: { pathname } } = props || this.props; - return urlToList(pathname) - .map((item) => { - return getMeunMatcheys(this.flatMenuKeys, item)[0]; - }) - .filter(item => item); - } /** * Recursively flatten the data * [{path:string},{path:string}] => {path,path2} @@ -73,115 +40,17 @@ export default class SiderMenu extends PureComponent { return keys; } /** - * 判断是否是http链接.返回 Link 或 a - * Judge whether it is http link.return a or Link - * @memberof SiderMenu - */ - getMenuItemPath = (item) => { - const itemPath = this.conversionPath(item.path); - const icon = getIcon(item.icon); - const { target, name } = item; - // Is it a http link - if (/^https?:\/\//.test(itemPath)) { - return ( - - {icon} - {name} - - ); - } - return ( - { - this.props.onCollapse(true); - } - : undefined - } - > - {icon} - {name} - - ); - }; - /** - * get SubMenu or Item - */ - getSubMenuOrItem = (item) => { - if (item.children && item.children.some(child => child.name)) { - return ( - - {getIcon(item.icon)} - {item.name} - - ) : ( - item.name - ) - } - key={item.path} - > - {this.getNavMenuItems(item.children)} - - ); - } else { - return ( - {this.getMenuItemPath(item)} - ); - } - }; - /** - * 获得菜单子节点 - * @memberof SiderMenu + * Convert pathname to openKeys + * /list/search/articles = > ['list','/list/search'] + * @param props */ - getNavMenuItems = (menusData) => { - if (!menusData) { - return []; - } - return menusData - .filter(item => item.name && !item.hideInMenu) + getDefaultCollapsedSubMenus(props) { + const { location: { pathname } } = props || this.props; + return urlToList(pathname) .map((item) => { - // make dom - const ItemDom = this.getSubMenuOrItem(item); - return this.checkPermissionItem(item.authority, ItemDom); + return getMeunMatcheys(this.flatMenuKeys, item)[0]; }) .filter(item => item); - }; - // Get the currently selected menu - getSelectedMenuKeys = () => { - const { location: { pathname } } = this.props; - return urlToList(pathname).map(itemPath => - getMeunMatcheys(this.flatMenuKeys, itemPath).pop(), - ); - }; - // conversion Path - // 转化路径 - conversionPath = (path) => { - if (path && path.indexOf('http') === 0) { - return path; - } else { - return `/${path || ''}`.replace(/\/+/g, '/'); - } - }; - // permission to check - checkPermissionItem = (authority, ItemDom) => { - if (this.props.Authorized && this.props.Authorized.check) { - const { check } = this.props.Authorized; - return check(authority, ItemDom); - } - return ItemDom; - }; - isMainMenu = (key) => { - return this.menus.some( - item => - key && (item.key === key || item.path === key), - ); } handleOpenChange = (openKeys) => { const lastOpenKey = openKeys[openKeys.length - 1]; @@ -193,17 +62,6 @@ export default class SiderMenu extends PureComponent { render() { const { logo, collapsed, onCollapse } = this.props; const { openKeys } = this.state; - // Don't show popup menu when it is been collapsed - const menuProps = collapsed - ? {} - : { - openKeys, - }; - // if pathname can't match, use the nearest parent's key - let selectedKeys = this.getSelectedMenuKeys(); - if (!selectedKeys.length) { - selectedKeys = [openKeys[openKeys.length - 1]]; - } return ( Ant Design Pro - - {this.getNavMenuItems(this.menus)} - + /> ); } diff --git a/src/components/SiderMenu/SilderMenu.test.js b/src/components/SiderMenu/SilderMenu.test.js index e6f1f55a8dc578a8ad156171e6b4be423b730abd..361f99378eee6f462d43cf398ec001054ed4aeed 100644 --- a/src/components/SiderMenu/SilderMenu.test.js +++ b/src/components/SiderMenu/SilderMenu.test.js @@ -1,4 +1,4 @@ -import { getMeunMatcheys } from './SiderMenu'; +import { getMeunMatcheys } from './BaseMeun'; const meun = [ '/dashboard', diff --git a/src/components/TopNavHeader/index.js b/src/components/TopNavHeader/index.js new file mode 100644 index 0000000000000000000000000000000000000000..83778649bfc2483c90bfe10c3478f73f1538afe0 --- /dev/null +++ b/src/components/TopNavHeader/index.js @@ -0,0 +1,26 @@ +import React, { PureComponent } from 'react'; +import { Link } from 'dva/router'; +import RightContent from '../GlobalHeader/RightContent'; +import BaseMeun from '../SiderMenu/BaseMeun'; +import styles from './index.less'; + +export default class TopNavHeader extends PureComponent { + render() { + return ( +
+
+
+ + logo +

Ant Design Pro

+ +
+ +
+
+ +
+
+ ); + } +} diff --git a/src/components/TopNavHeader/index.less b/src/components/TopNavHeader/index.less new file mode 100644 index 0000000000000000000000000000000000000000..037b12b0f7bb04a030166de0dcb9791e14dd1db7 --- /dev/null +++ b/src/components/TopNavHeader/index.less @@ -0,0 +1,31 @@ +.main { + display: flex; + height: 64px; + margin: auto; + max-width: 1200px; + .left { + flex: 1; + display: flex; + .logo { + width: 160px; + height: 64px; + position: relative; + line-height: 64px; + transition: all 0.3s; + overflow: hidden; + img { + display: inline-block; + vertical-align: middle; + height: 32px; + } + h1 { + color: #fff; + display: inline-block; + vertical-align: middle; + font-size: 16px; + margin: 0 0 0 12px; + font-weight: 400; + } + } + } +} diff --git a/src/layouts/BasicLayout.js b/src/layouts/BasicLayout.js index ab85895758ae98ab284eb2084a1765d4c19a8005..f6237e8e854674c07817be711034258999a396aa 100644 --- a/src/layouts/BasicLayout.js +++ b/src/layouts/BasicLayout.js @@ -9,6 +9,7 @@ import classNames from 'classnames'; import { enquireScreen } from 'enquire-js'; import GlobalHeader from '../components/GlobalHeader'; import GlobalFooter from '../components/GlobalFooter'; +import TopNavHeader from '../components/TopNavHeader'; import SiderMenu from '../components/SiderMenu'; import NotFound from '../routes/Exception/404'; import { getRoutes } from '../utils/utils'; @@ -153,26 +154,45 @@ class BasicLayout extends React.PureComponent { } } render() { + const isFluid = this.props.layout === 'fluid'; const { currentUser, collapsed, fetchingNotices, notices, routerData, match, location, } = this.props; const bashRedirect = this.getBashRedirect(); const layout = ( - + Authorized={Authorized} + menuData={getMenuData()} + collapsed={collapsed} + location={location} + isMobile={this.state.isMobile} + onCollapse={this.handleMenuCollapse} + /> + )}
+ {isFluid && !isMobile ? ( + + ) : ( + )}
@@ -253,6 +274,7 @@ class BasicLayout extends React.PureComponent { export default connect(({ user, global, loading }) => ({ currentUser: user.currentUser, collapsed: global.collapsed, + layout: global.layout, fetchingNotices: loading.effects['global/fetchNotices'], notices: global.notices, }))(BasicLayout); diff --git a/src/layouts/GridContent.js b/src/layouts/GridContent.js new file mode 100644 index 0000000000000000000000000000000000000000..60c22d5d24fc43917ebb3824f345a1642fa71a58 --- /dev/null +++ b/src/layouts/GridContent.js @@ -0,0 +1,17 @@ +import React, { PureComponent } from 'react'; +import { connect } from 'dva'; +import styles from './GridContent.less'; + +class GridContent extends PureComponent { + render() { + let className = `${styles.main}`; + if (this.props.layout === 'fluid') { + className = `${styles.main} ${styles.fluid}`; + } + return
{this.props.children}
; + } +} + +export default connect(({ global }) => ({ + layout: global.layout, +}))(GridContent); diff --git a/src/layouts/GridContent.less b/src/layouts/GridContent.less new file mode 100644 index 0000000000000000000000000000000000000000..b06ad0c6e28ba8819d35f0c326f2aad15427189b --- /dev/null +++ b/src/layouts/GridContent.less @@ -0,0 +1,9 @@ +.main { + width: 100%; + height: 100%; + min-height: 100%; + &.fluid { + max-width: 1200px; + margin: 0 auto; + } +} diff --git a/src/layouts/PageHeaderLayout.js b/src/layouts/PageHeaderLayout.js index 2c615e897db6549d9af9f13a1a4ad0994a7ab70d..7416127958c8a0a02fa9d6429d7c17f6a333b589 100644 --- a/src/layouts/PageHeaderLayout.js +++ b/src/layouts/PageHeaderLayout.js @@ -1,12 +1,17 @@ import React from 'react'; import { Link } from 'dva/router'; import PageHeader from '../components/PageHeader'; +import GridContent from './GridContent'; import styles from './PageHeaderLayout.less'; export default ({ children, wrapperClassName, top, ...restProps }) => (
{top} - {children ?
{children}
: null} + {children ? ( +
+ {children} +
+ ) : null}
); diff --git a/src/layouts/PageHeaderLayout.less b/src/layouts/PageHeaderLayout.less index a0c0a6efe6c5c8cbd606cadc143959bab71a275b..39a449657a98b039c29e6654fd117267cbb5283a 100644 --- a/src/layouts/PageHeaderLayout.less +++ b/src/layouts/PageHeaderLayout.less @@ -1,4 +1,4 @@ -@import "~antd/lib/style/themes/default.less"; +@import '~antd/lib/style/themes/default.less'; .content { margin: 24px 24px 0; diff --git a/src/models/global.js b/src/models/global.js index 55841e16d053db3bf4c92b94ce877cd6601d4965..64221aaad55adbb09f0ea73ec6ede75efe4b6c06 100644 --- a/src/models/global.js +++ b/src/models/global.js @@ -5,6 +5,7 @@ export default { state: { collapsed: false, + layout: 'fluid', notices: [], }, @@ -40,6 +41,12 @@ export default { collapsed: payload, }; }, + changeLayout(state, { payload }) { + return { + ...state, + layout: payload, + }; + }, saveNotices(state, { payload }) { return { ...state, diff --git a/src/routes/Dashboard/Analysis.js b/src/routes/Dashboard/Analysis.js index f6df44063c86b9cad082764c9a9b3a37438b8600..b1f3a435c43fd1ee003963e7b1f5260a15eb0699 100644 --- a/src/routes/Dashboard/Analysis.js +++ b/src/routes/Dashboard/Analysis.js @@ -1,4 +1,4 @@ -import React, { Component, Fragment } from 'react'; +import React, { Component } from 'react'; import { connect } from 'dva'; import { Row, @@ -14,6 +14,7 @@ import { Dropdown, } from 'antd'; import numeral from 'numeral'; +import GridContent from '../../layouts/GridContent'; import { ChartCard, yuan, @@ -241,7 +242,7 @@ export default class Analysis extends Component { }; return ( - + - + ); } } diff --git a/src/routes/Dashboard/Monitor.js b/src/routes/Dashboard/Monitor.js index 897dc9ce116573c4fd9a76f9c2309b141ff0bc2a..8332cc98b351a51009d4ad51ab9f508e7689f31b 100644 --- a/src/routes/Dashboard/Monitor.js +++ b/src/routes/Dashboard/Monitor.js @@ -1,7 +1,8 @@ -import React, { PureComponent, Fragment } from 'react'; +import React, { PureComponent } from 'react'; import { connect } from 'dva'; import { Row, Col, Card, Tooltip } from 'antd'; import numeral from 'numeral'; +import GridContent from '../../layouts/GridContent'; import Authorized from '../../utils/Authorized'; import { Pie, WaterWave, Gauge, TagCloud } from '../../components/Charts'; import NumberInfo from '../../components/NumberInfo'; @@ -35,7 +36,7 @@ export default class Monitor extends PureComponent { const { tags } = monitor; return ( - + @@ -164,7 +165,7 @@ export default class Monitor extends PureComponent { - + ); } } diff --git a/src/routes/UserProfile/UserCenter.js b/src/routes/UserProfile/UserCenter.js index b09d49270649dbdc3cc65cc0e381b8657bc03c9d..a1a603d3391e21e09cc209e0c110f7aa83f02516 100644 --- a/src/routes/UserProfile/UserCenter.js +++ b/src/routes/UserProfile/UserCenter.js @@ -3,14 +3,28 @@ import { connect } from 'dva'; import { Link } from 'dva/router'; import moment from 'moment'; import numeral from 'numeral'; -import { List, Card, Row, Col, Icon, Dropdown, - Menu, Avatar, Tag, Divider, Tooltip, Spin, Input } from 'antd'; +import { + List, + Card, + Row, + Col, + Icon, + Dropdown, + Menu, + Avatar, + Tag, + Divider, + Tooltip, + Spin, + Input, +} 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'; +import stylesArticles from './List/Articles.less'; +import stylesApplications from './List/Applications.less'; +import GridContent from '../layouts/GridContent'; @connect(({ list, loading, user, project }) => ({ list, @@ -26,7 +40,7 @@ export default class UserCenter extends PureComponent { newTags: [], inputVisible: false, inputValue: '', - } + }; componentDidMount() { const { dispatch } = this.props; @@ -46,33 +60,39 @@ export default class UserCenter extends PureComponent { onTabChange = (key) => { this.setState({ key }); - } + }; showInput = () => { this.setState({ inputVisible: true }, () => this.input.focus()); - } + }; saveInputRef = (input) => { this.input = input; - } + }; handleInputChange = (e) => { this.setState({ inputValue: e.target.value }); - } + }; handleInputConfirm = () => { const { state } = this; const { inputValue } = state; let { newTags } = state; - if (inputValue && newTags.filter(tag => tag.label === inputValue).length === 0) { - newTags = [...newTags, { key: `new-${newTags.length}`, label: inputValue }]; + if ( + inputValue && + newTags.filter(tag => tag.label === inputValue).length === 0 + ) { + newTags = [ + ...newTags, + { key: `new-${newTags.length}`, label: inputValue }, + ]; } this.setState({ newTags, inputVisible: false, inputValue: '', }); - } + }; renderArticles = (list, loading) => { const IconText = ({ type, text }) => ( @@ -81,11 +101,14 @@ export default class UserCenter extends PureComponent { {text} ); - const ListContent = ({ data: { content, updatedAt, avatar, owner, href } }) => ( + const ListContent = ({ + data: { content, updatedAt, avatar, owner, href }, + }) => (
{content}
- {owner} 发布在 {href} + + {owner} 发布在 {href} {moment(updatedAt).format('YYYY-MM-DD HH:mm')}
@@ -108,9 +131,14 @@ export default class UserCenter extends PureComponent { ]} > {item.title} - )} + title={ + + {item.title} + + } description={ Ant Design @@ -124,19 +152,37 @@ export default class UserCenter extends PureComponent { )} /> ); - } + }; renderApplications = (list, loading) => { const itemMenu = ( - 1st menu item + + 1st menu item + - 2nd menu item + + 2nd menu item + - 3d menu item + + 3d menu item + ); @@ -165,10 +211,18 @@ export default class UserCenter extends PureComponent { hoverable bodyStyle={{ paddingBottom: 20 }} actions={[ - , - , - , - , + + + , + + + , + + + , + + + , ]} > ); - } + }; renderProjects = (list, loading) => { return ( @@ -211,15 +265,13 @@ export default class UserCenter extends PureComponent { {moment(item.updatedAt).fromNow()}
- { - item.members.map(member => ( - - )) - } + {item.members.map(member => ( + + ))}
@@ -228,22 +280,137 @@ export default class UserCenter extends PureComponent { )} /> ); + }; + renderContent() { + const { newTags, inputVisible, inputValue } = this.state; + const { + currentUser, + project: { notice }, + projectLoading, + } = this.props; + return ( +
+
+ +
{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} + + ))} + + +
+ +
+
标签
+ {currentUser.tags + .concat(newTags) + .map(item => {item.label})} + {inputVisible && ( + + )} + {!inputVisible && ( + + + + )} +
+ +
+
团队
+ + + {notice.map(item => ( + + + + {item.member} + + + ))} + + +
+
+ ); } - render() { - const { key, newTags, inputVisible, inputValue } = this.state; - 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 { + list: { list }, + listLoading, + currentUser, + currentUserLoading, + } = 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), @@ -251,94 +418,33 @@ export default class UserCenter extends PureComponent { }; return ( -
- - - - { - currentUser && Object.keys(currentUser).length ? - ( -
-
- -
{currentUser.name}
-
{currentUser.signature}
-
-
-

{currentUser.title}

-

{currentUser.group}

-

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

-
- -
-
标签
- { - currentUser.tags.concat(newTags).map(item => - {item.label}) - } - {inputVisible && ( - - )} - {!inputVisible && ( - - - - )} -
- -
-
团队
- - - { - notice.map(item => ( - - - - {item.member} - - - )) - } - - -
-
- ) : 'loading...' - } -
- - - - {contentMap[key]} - - -
-
+ +
+ + + + {currentUser && Object.keys(currentUser).length + ? this.renderContent() + : 'loading...'} + + + + + {contentMap[this.state.key]} + + + +
+
); } } diff --git a/src/routes/UserProfile/Userinfo/Info.js b/src/routes/UserProfile/Userinfo/Info.js index ad6cdca52351503d0d385a27a7e1a91aef1a8463..4281fcb213dc2ecea0ea1d23f89126b7ef97ec7e 100644 --- a/src/routes/UserProfile/Userinfo/Info.js +++ b/src/routes/UserProfile/Userinfo/Info.js @@ -3,7 +3,8 @@ import { connect } from 'dva'; import { Route, routerRedux, Switch, Redirect } from 'dva/router'; import { Menu } from 'antd'; import styles from './Info.less'; -import { getRoutes } from '../../../utils/utils'; +import { getRoutes } from '../../utils/utils'; +import GridContent from '../../layouts/GridContent'; const { Item } = Menu; @@ -71,43 +72,36 @@ export default class Info extends Component { return ''; } return ( -
{ - this.main = ref; - }} - > -
- - {this.getmenu()} - + +
+
+ + {this.getmenu()} + +
+
+
{this.getRightTitle()}
+ + {getRoutes(match.path, routerData).map(item => ( + ( + + )} + exact={item.exact} + /> + ))} + + + +
-
-
{this.getRightTitle()}
- - {getRoutes(match.path, routerData).map(item => ( - ( - - )} - exact={item.exact} - /> - ))} - - - -
-
+ ); } }