From 91bfd88ddcf444fdc23dc7409fa3b1a239fc5048 Mon Sep 17 00:00:00 2001 From: jim Date: Thu, 8 Mar 2018 12:20:51 +0800 Subject: [PATCH] add top_meun and siderbar --- src/common/menu.js | 2 +- src/common/router.js | 2 +- src/components/GlobalHeader/RightContent.js | 4 +- src/components/GlobalHeader/index.less | 2 +- src/components/NoticeIcon/index.js | 2 +- src/components/Sidebar/LayoutSetting.js | 45 ++++ src/components/Sidebar/ThemeColor.js | 55 +++++ src/components/Sidebar/ThemeColor.less | 26 +++ src/components/Sidebar/index.js | 218 +++++++++++++++++++ src/components/Sidebar/index.less | 62 ++++++ src/components/Sidebar/navState.js | 35 +++ src/components/SiderMenu/BaseMeun.js | 1 - src/components/SiderMenu/SiderMenu.js | 15 +- src/components/SiderMenu/index.js | 2 +- src/components/SiderMenu/index.less | 19 +- src/components/TopNavHeader/index.js | 35 ++- src/components/TopNavHeader/index.less | 74 ++++--- src/index.less | 1 + src/layouts/BasicLayout.js | 228 +++++--------------- src/layouts/Footer.js | 38 ++++ src/layouts/GridContent.js | 8 +- src/layouts/GridContent.less | 3 +- src/layouts/Header.js | 153 +++++++++++++ src/layouts/Header.less | 6 + src/layouts/LoadingPage.js | 94 ++++++++ src/models/global.js | 7 - src/models/setting.js | 32 +++ src/routes/UserProfile/UserCenter.js | 6 +- src/routes/UserProfile/Userinfo/Info.js | 4 +- 29 files changed, 937 insertions(+), 242 deletions(-) create mode 100644 src/components/Sidebar/LayoutSetting.js create mode 100644 src/components/Sidebar/ThemeColor.js create mode 100644 src/components/Sidebar/ThemeColor.less create mode 100644 src/components/Sidebar/index.js create mode 100644 src/components/Sidebar/index.less create mode 100644 src/components/Sidebar/navState.js create mode 100644 src/layouts/Footer.js create mode 100644 src/layouts/Header.js create mode 100644 src/layouts/Header.less create mode 100644 src/layouts/LoadingPage.js create mode 100644 src/models/setting.js diff --git a/src/common/menu.js b/src/common/menu.js index 6dd6911d..d71c86e2 100644 --- a/src/common/menu.js +++ b/src/common/menu.js @@ -122,7 +122,7 @@ const menuData = [{ path: 'user-center', }, { name: '个人设置', - path: 'userinfo', + path: 'userinfo/base', }], }]; diff --git a/src/common/router.js b/src/common/router.js index 6c9e54e1..9c3df8b1 100644 --- a/src/common/router.js +++ b/src/common/router.js @@ -71,7 +71,7 @@ function getFlatMenuData(menus) { export const getRouterData = (app) => { const routerConfig = { '/': { - component: dynamicWrapper(app, ['user', 'login'], () => import('../layouts/BasicLayout')), + component: dynamicWrapper(app, ['user', 'login', 'setting'], () => import('../layouts/LoadingPage')), }, '/dashboard/analysis': { component: dynamicWrapper(app, ['chart'], () => import('../routes/Dashboard/Analysis')), diff --git a/src/components/GlobalHeader/RightContent.js b/src/components/GlobalHeader/RightContent.js index 0b94093c..3998e407 100644 --- a/src/components/GlobalHeader/RightContent.js +++ b/src/components/GlobalHeader/RightContent.js @@ -65,8 +65,8 @@ export default class GlobalHeaderRight extends PureComponent { ); const noticeData = this.getNoticeData(); let className = styles.right; - if (this.props.theme === 'white') { - className = `${styles.right} ${styles.white}`; + if (this.props.theme === 'dark') { + className = `${styles.right} ${styles.dark}`; } return (
diff --git a/src/components/GlobalHeader/index.less b/src/components/GlobalHeader/index.less index dfe717f9..a9b11458 100644 --- a/src/components/GlobalHeader/index.less +++ b/src/components/GlobalHeader/index.less @@ -84,7 +84,7 @@ i.trigger { } } -.white { +.dark { height: 64px; .action { color: rgba(255, 255, 255, 0.85); diff --git a/src/components/NoticeIcon/index.js b/src/components/NoticeIcon/index.js index 3134aced..b30b204d 100644 --- a/src/components/NoticeIcon/index.js +++ b/src/components/NoticeIcon/index.js @@ -70,7 +70,7 @@ export default class NoticeIcon extends PureComponent { const notificationBox = this.getNotificationBox(); const trigger = ( - + diff --git a/src/components/Sidebar/LayoutSetting.js b/src/components/Sidebar/LayoutSetting.js new file mode 100644 index 00000000..7670480c --- /dev/null +++ b/src/components/Sidebar/LayoutSetting.js @@ -0,0 +1,45 @@ +import React from 'react'; +import NavSate from './navState'; + +const LayoutSetting = ({ value, onChange }) => { + return ( +
+ {['sidemenu', 'topmenu'].map(layout => ( +
onChange && onChange(layout)} + key={layout} + style={{ + width: 70, + height: 44, + textAlign: 'center', + margin: 8, + }} + > + +
+ ))} +
+ +
+
+ ); +}; + +export default LayoutSetting; diff --git a/src/components/Sidebar/ThemeColor.js b/src/components/Sidebar/ThemeColor.js new file mode 100644 index 00000000..78a63aae --- /dev/null +++ b/src/components/Sidebar/ThemeColor.js @@ -0,0 +1,55 @@ +import React from 'react'; +import styles from './ThemeColor.less'; + +const Tag = ({ color, ...rest }) => { + return ( +
+ ); +}; + +const ThemeColor = ({ colors, value, onChange }) => { + let colorList = colors; + if (!colors) { + colorList = [ + '#F5222D', + '#FA541C', + '#FA8C16', + '#FAAD14', + '#FADB14', + '#A0D911', + '#52C41A', + '#13C2C2', + '#1890FF', + '#2F54EB', + '#722ED1', + '#EB2F96', + ]; + } + + return ( +
+

主题颜色

+ {colorList.map((color) => { + const classname = + value === color + ? `${styles.colorBlock} ${styles.active}` + : styles.colorBlock; + return ( + onChange && onChange(color)} + /> + ); + })} +
+ ); +}; + +export default ThemeColor; diff --git a/src/components/Sidebar/ThemeColor.less b/src/components/Sidebar/ThemeColor.less new file mode 100644 index 00000000..9170eca3 --- /dev/null +++ b/src/components/Sidebar/ThemeColor.less @@ -0,0 +1,26 @@ +.themeColor { + overflow: hidden; + margin-top: 15px; + margin-left: -5px; + margin-right: -5px; + .title { + font-size: 14px; + color: rgba(0, 0, 0, 0.65); + line-height: 22px; + margin-bottom: 5px; + } + .colorBlock { + width: 16px; + height: 16px; + border-radius: 2px; + float: left; + margin: 5px; + &.active { + width: 18px; + height: 18px; + margin: 4px; + border: 2px solid hsl(90, 100%, 50%); + box-shadow: 0 0 4px 0 hsl(90, 100%, 50%); + } + } +} diff --git a/src/components/Sidebar/index.js b/src/components/Sidebar/index.js new file mode 100644 index 00000000..bfd893a8 --- /dev/null +++ b/src/components/Sidebar/index.js @@ -0,0 +1,218 @@ +import React, { PureComponent, Fragment } from 'react'; +import { Select, List, Switch, Divider, Radio } from 'antd'; +import styles from './index.less'; +import ThemeColor from './ThemeColor'; +import LayoutSeting from './LayoutSetting'; + +const RadioGroup = Radio.Group; + +const ColorBlock = ({ color, title }) => ( + +
+
{title}
+ +); + +const Body = ({ children, title, style }) => ( +
+

{title}

+ {children} +
+); + +class Sidebar extends PureComponent { + constructor(props) { + super(props); + this.defaultstate = { + collapse: false, + silderTheme: 'dark', + themeColor: '#1890FF', + layout: 'sidemenu', + grid: 'Fluid', + fixedHeader: false, + autoHideHeader: false, + fixSiderbar: false, + colorWeak: 'close', + }; + const propsState = this.propsToState(props); + this.state = { ...this.defaultstate, ...propsState }; + } + componentWillReceiveProps(props) { + this.setState(this.propsToState(props)); + } + getLayOutSetting = () => { + const { layout } = this.state; + return [ + { + title: '栅格模式', + isShow: true, + action: [ + , + ], + }, + { + title: 'Fixed Header', + isShow: true, + action: [ + this.changeSetting('fixedHeader', checked)} + />, + ], + }, + { + title: '↳ 下滑时隐藏 Header', + isShow: true, + action: [ + this.changeSetting('autoHideHeader', checked)} + />, + ], + }, + { + title: 'Fix Siderbar', + isShow: layout === 'sidemenu', + action: [ + , + ], + }, + ].filter(item => item.isShow); + }; + fixSiderbar = (checked) => { + this.changeSetting('fixSiderbar', checked); + }; + changeSetting = (key, value) => { + const nextState = {}; + nextState[key] = value; + if (key === 'layout') { + if (value === 'topmenu') { + nextState.grid = 'Wide'; + } else { + nextState.grid = 'Fluid'; + } + } + this.setState(nextState, () => { + if (this.props.onChange) { + this.props.onChange(this.state); + } + }); + }; + propsToState = (props) => { + const nextState = {}; + Object.keys(props).forEach((key) => { + if (props[key] && this.defaultstate[key] !== undefined) { + nextState[key] = props[key]; + } + }); + return nextState; + }; + togglerContent = () => { + this.changeSetting('collapse', !this.state.collapse); + }; + render() { + const radioStyle = { + display: 'block', + }; + return ( +
+
+ logo +
+
+ + + this.changeSetting('silderTheme', target.value) + } + value={this.state.silderTheme} + > + + + + + + + + this.changeSetting('themeColor', color)} + /> + + + + this.changeSetting('layout', layout)} + /> + ( + {item.title} + )} + /> + + + + this.changeSetting('colorWeak', value)} + style={{ width: 120 }} + > + 打开 + 关闭 + , + ], + }, + ]} + renderItem={item => ( + {item.title} + )} + /> + +
+
+ ); + } +} + +export default Sidebar; diff --git a/src/components/Sidebar/index.less b/src/components/Sidebar/index.less new file mode 100644 index 00000000..78a62183 --- /dev/null +++ b/src/components/Sidebar/index.less @@ -0,0 +1,62 @@ +.sidebar { + position: fixed; + right: -336px; + top: 150px; + transition: 0.3s; + display: flex; + z-index: 9; + &.show { + right: 0; + } + .mini_bar { + width: 50px; + height: 45px; + border-top-left-radius: 28px; + border-bottom-left-radius: 28px; + text-align: center; + font-size: 24px; + background: white; + box-shadow: 0 0 6px 0 rgba(0, 21, 41, 0.35); + img { + width: 28px; + height: 28px; + } + } + .content { + width: 336px; + background: white; + box-shadow: 0 0 6px 0 rgba(0, 21, 41, 0.35); + box-shadow: -3px 0 10px 3px rgba(183, 183, 183, 0.3); + :global { + .ant-switch-checked { + background-color: #87d068; + } + .ant-list-item { + padding-top: 7px; + padding-bottom: 7px; + } + } + } + .color_block { + width: 38px; + height: 22px; + margin: 4px; + margin-right: 12px; + display: inline-block; + vertical-align: middle; + background: #002140; + border-radius: 2px; + } + .color_block_title { + display: inline-block; + font-size: 14px; + color: rgba(0, 0, 0, 0.65); + line-height: 22px; + } + .bodyTitle { + font-size: 14px; + color: rgba(0, 0, 0, 0.85); + line-height: 22px; + margin-bottom: 10px; + } +} diff --git a/src/components/Sidebar/navState.js b/src/components/Sidebar/navState.js new file mode 100644 index 00000000..73cbeb6e --- /dev/null +++ b/src/components/Sidebar/navState.js @@ -0,0 +1,35 @@ +import React from 'react'; + +const UrlMap = { + sidemenu: { + active: + 'http://alipay-os.oss-cn-hangzhou-zmf.aliyuncs.com/rmsportal/YcoRFFREHxmXebXryzhC.svg', + default: + 'http://alipay-os.oss-cn-hangzhou-zmf.aliyuncs.com/rmsportal/FUcluUxklaHEgbCfosWO.svg', + disable: + 'http://alipay-os.oss-cn-hangzhou-zmf.aliyuncs.com/rmsportal/nnbGSviuREntXtWJEquJ.svg', + }, + topside: { + active: + 'http://alipay-os.oss-cn-hangzhou-zmf.aliyuncs.com/rmsportal/cRVYqCCkknDizjyHpjgR.svg', + default: + 'http://alipay-os.oss-cn-hangzhou-zmf.aliyuncs.com/rmsportal/ygeNiTUuhrHuNMjkVQkv.svg', + disable: + 'http://alipay-os.oss-cn-hangzhou-zmf.aliyuncs.com/rmsportal/KtcgueNbQdMSbxGDigdT.svg', + }, + topmenu: { + active: + 'http://alipay-os.oss-cn-hangzhou-zmf.aliyuncs.com/rmsportal/RCtKLhlMLWYKaWDzLsBC.svg', + default: + 'http://alipay-os.oss-cn-hangzhou-zmf.aliyuncs.com/rmsportal/pMRBYBPSKXgEGrglJsdl.svg', + disable: + 'http://alipay-os.oss-cn-hangzhou-zmf.aliyuncs.com/rmsportal/PvQhRIcAGTKewuOfJOSn.svg', + }, +}; + +const navState = ({ alt, type, state }) => { + const url = UrlMap[type][state]; + return {alt}; +}; + +export default navState; diff --git a/src/components/SiderMenu/BaseMeun.js b/src/components/SiderMenu/BaseMeun.js index 00c90e01..d3b9e402 100644 --- a/src/components/SiderMenu/BaseMeun.js +++ b/src/components/SiderMenu/BaseMeun.js @@ -161,7 +161,6 @@ export default class BaseMeun extends PureComponent { return ( item); } + isMainMenu = (key) => { + return this.menus.some( + item => + key && (item.key === key || item.path === key), + ); + } handleOpenChange = (openKeys) => { const lastOpenKey = openKeys[openKeys.length - 1]; const moreThanOne = openKeys.filter(openKey => this.isMainMenu(openKey)).length > 1; @@ -60,8 +65,9 @@ export default class SiderMenu extends PureComponent { }); }; render() { - const { logo, collapsed, onCollapse } = this.props; + const { logo, collapsed, onCollapse, theme } = this.props; const { openKeys } = this.state; + const defaultProps = collapsed ? {} : { openKeys }; return (
@@ -81,12 +87,11 @@ export default class SiderMenu extends PureComponent { ); diff --git a/src/components/SiderMenu/index.js b/src/components/SiderMenu/index.js index 70b3e474..3cdcedce 100644 --- a/src/components/SiderMenu/index.js +++ b/src/components/SiderMenu/index.js @@ -4,7 +4,7 @@ import DrawerMenu from 'rc-drawer-menu'; import SiderMenu from './SiderMenu'; export default props => ( - props.isMobile ? ( + props.isMobile || props.fixSiderbar ? ( -
-
- - logo -

Ant Design Pro

- +
+
+
+
+ + logo +

Ant Design Pro

+ +
+ +
+
+
- -
-
-
); diff --git a/src/components/TopNavHeader/index.less b/src/components/TopNavHeader/index.less index 037b12b0..456fc548 100644 --- a/src/components/TopNavHeader/index.less +++ b/src/components/TopNavHeader/index.less @@ -1,31 +1,53 @@ -.main { - display: flex; +.head { + width: 100%; + transition: background 0.3s, width 0.2s; height: 64px; - margin: auto; - max-width: 1200px; - .left { - flex: 1; + padding: 0 12px 0 0; + box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); + position: relative; + &.ligth { + background-color: #fff; + } + .main { 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; - } + height: 64px; + padding-left: 24px; + &.wide { + max-width: 1200px; + margin: auto; + padding-left: 4px; + } + .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; + } +} + +.ligth { + h1 { + color: #002140; + } +} diff --git a/src/index.less b/src/index.less index 5cfe914a..d8b1560f 100644 --- a/src/index.less +++ b/src/index.less @@ -2,6 +2,7 @@ html, body, :global(#root) { height: 100%; + overflow: auto; } :global(.ant-layout) { diff --git a/src/layouts/BasicLayout.js b/src/layouts/BasicLayout.js index f6237e8e..8ef41f61 100644 --- a/src/layouts/BasicLayout.js +++ b/src/layouts/BasicLayout.js @@ -1,43 +1,24 @@ -import React, { Fragment } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; -import { Layout, Icon, message } from 'antd'; +import { Layout } from 'antd'; import DocumentTitle from 'react-document-title'; import { connect } from 'dva'; -import { Route, Redirect, Switch, routerRedux } from 'dva/router'; +import { Route, Redirect, Switch } from 'dva/router'; import { ContainerQuery } from 'react-container-query'; 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'; import Authorized from '../utils/Authorized'; -import { getMenuData } from '../common/menu'; +import Sidebar from '../components/Sidebar'; import logo from '../assets/logo.svg'; +import Footer from './Footer'; +import Header from './Header'; -const { Content, Header, Footer } = Layout; +const { Content } = Layout; const { AuthorizedRoute } = Authorized; -/** - * 根据菜单取得重定向地址. - */ -const redirectData = []; -const getRedirect = (item) => { - if (item && item.children) { - if (item.children[0] && item.children[0].path) { - redirectData.push({ - from: `${item.path}`, - to: `${item.children[0].path}`, - }); - item.children.forEach((children) => { - getRedirect(children); - }); - } - } -}; -getMenuData().forEach(getRedirect); +const RightSidebar = connect(({ setting }) => ({ ...setting }))(Sidebar); const query = { 'screen-xs': { @@ -59,19 +40,10 @@ const query = { minWidth: 1200, }, }; - -let isMobile; -enquireScreen((b) => { - isMobile = b; -}); - class BasicLayout extends React.PureComponent { static childContextTypes = { location: PropTypes.object, breadcrumbNameMap: PropTypes.object, - } - state = { - isMobile, }; getChildContext() { const { location, routerData } = this.props; @@ -80,16 +52,6 @@ class BasicLayout extends React.PureComponent { breadcrumbNameMap: routerData, }; } - componentDidMount() { - enquireScreen((mobile) => { - this.setState({ - isMobile: mobile, - }); - }); - this.props.dispatch({ - type: 'user/fetchCurrent', - }); - } getPageTitle() { const { routerData, location } = this.props; const { pathname } = location; @@ -113,150 +75,73 @@ class BasicLayout extends React.PureComponent { return '/dashboard/analysis'; } return redirect; - } + }; handleMenuCollapse = (collapsed) => { this.props.dispatch({ type: 'global/changeLayoutCollapsed', payload: collapsed, }); - } - handleNoticeClear = (type) => { - message.success(`清空了${type}`); + }; + changeSetting = (setting) => { this.props.dispatch({ - type: 'global/clearNotices', - payload: type, + type: 'setting/changeSetting', + payload: setting, }); } - handleMenuClick = ({ key }) => { - if (key === 'userCenter') { - this.props.dispatch(routerRedux.push('/user-profile/user-center')); - return; - } - if (key === 'triggerError') { - this.props.dispatch(routerRedux.push('/exception/trigger')); - return; - } - if (key === 'userinfo') { - this.props.dispatch(routerRedux.push('/user-profile/userinfo/base')); - return; - } - if (key === 'logout') { - this.props.dispatch({ - type: 'login/logout', - }); - } - } - handleNoticeVisibleChange = (visible) => { - if (visible) { - this.props.dispatch({ - type: 'global/fetchNotices', - }); - } - } render() { - const isFluid = this.props.layout === 'fluid'; const { - currentUser, collapsed, fetchingNotices, notices, routerData, match, location, + isMobile, + redirectData, + routerData, + fixedHeader, + match, } = this.props; + const isTop = this.props.layout === 'topmenu'; const bashRedirect = this.getBashRedirect(); + const myRedirectData = redirectData || []; const layout = ( - {isFluid && !isMobile ? null : ( + {isTop && !isMobile ? null : ( )} -
- {isFluid && !isMobile ? ( - - ) : ( - - )} -
- +
+ - { - redirectData.map(item => - - ) - } - { - getRoutes(match.path, routerData).map(item => - ( - - ) - ) - } + {myRedirectData.map(item => ( + + ))} + {getRoutes(match.path, routerData).map(item => ( + + ))} -
- , - href: 'https://github.com/ant-design/ant-design-pro', - blankTarget: true, - }, { - key: 'Ant Design', - title: 'Ant Design', - href: 'http://ant.design', - blankTarget: true, - }]} - copyright={ - - Copyright 2018 蚂蚁金服体验技术部出品 - - } - /> -
+