Commit 91bfd88d authored by jim's avatar jim

add top_meun and siderbar

parent b021ef4d
...@@ -122,7 +122,7 @@ const menuData = [{ ...@@ -122,7 +122,7 @@ const menuData = [{
path: 'user-center', path: 'user-center',
}, { }, {
name: '个人设置', name: '个人设置',
path: 'userinfo', path: 'userinfo/base',
}], }],
}]; }];
......
...@@ -71,7 +71,7 @@ function getFlatMenuData(menus) { ...@@ -71,7 +71,7 @@ function getFlatMenuData(menus) {
export const getRouterData = (app) => { export const getRouterData = (app) => {
const routerConfig = { const routerConfig = {
'/': { '/': {
component: dynamicWrapper(app, ['user', 'login'], () => import('../layouts/BasicLayout')), component: dynamicWrapper(app, ['user', 'login', 'setting'], () => import('../layouts/LoadingPage')),
}, },
'/dashboard/analysis': { '/dashboard/analysis': {
component: dynamicWrapper(app, ['chart'], () => import('../routes/Dashboard/Analysis')), component: dynamicWrapper(app, ['chart'], () => import('../routes/Dashboard/Analysis')),
......
...@@ -65,8 +65,8 @@ export default class GlobalHeaderRight extends PureComponent { ...@@ -65,8 +65,8 @@ export default class GlobalHeaderRight extends PureComponent {
); );
const noticeData = this.getNoticeData(); const noticeData = this.getNoticeData();
let className = styles.right; let className = styles.right;
if (this.props.theme === 'white') { if (this.props.theme === 'dark') {
className = `${styles.right} ${styles.white}`; className = `${styles.right} ${styles.dark}`;
} }
return ( return (
<div className={className} > <div className={className} >
......
...@@ -84,7 +84,7 @@ i.trigger { ...@@ -84,7 +84,7 @@ i.trigger {
} }
} }
.white { .dark {
height: 64px; height: 64px;
.action { .action {
color: rgba(255, 255, 255, 0.85); color: rgba(255, 255, 255, 0.85);
......
...@@ -70,7 +70,7 @@ export default class NoticeIcon extends PureComponent { ...@@ -70,7 +70,7 @@ export default class NoticeIcon extends PureComponent {
const notificationBox = this.getNotificationBox(); const notificationBox = this.getNotificationBox();
const trigger = ( const trigger = (
<span className={noticeButtonClass}> <span className={noticeButtonClass}>
<Badge count={count} className={styles.badge}> <Badge count={count} style={{ boxShadow: 'none' }} className={styles.badge}>
<Icon type="bell" className={styles.icon} /> <Icon type="bell" className={styles.icon} />
</Badge> </Badge>
</span> </span>
......
import React from 'react';
import NavSate from './navState';
const LayoutSetting = ({ value, onChange }) => {
return (
<div
style={{
margin: 5,
display: 'flex',
}}
>
{['sidemenu', 'topmenu'].map(layout => (
<div
onClick={() => onChange && onChange(layout)}
key={layout}
style={{
width: 70,
height: 44,
textAlign: 'center',
margin: 8,
}}
>
<NavSate
type={layout}
state={value === layout ? 'active' : 'default'}
alt={layout}
/>
</div>
))}
<div
key="topside"
style={{
width: 70,
height: 44,
textAlign: 'center',
margin: 8,
}}
>
<NavSate type="topside" state="disable" alt="topside" />
</div>
</div>
);
};
export default LayoutSetting;
import React from 'react';
import styles from './ThemeColor.less';
const Tag = ({ color, ...rest }) => {
return (
<div
{...rest}
style={{
backgroundColor: color,
}}
/>
);
};
const ThemeColor = ({ colors, value, onChange }) => {
let colorList = colors;
if (!colors) {
colorList = [
'#F5222D',
'#FA541C',
'#FA8C16',
'#FAAD14',
'#FADB14',
'#A0D911',
'#52C41A',
'#13C2C2',
'#1890FF',
'#2F54EB',
'#722ED1',
'#EB2F96',
];
}
return (
<div className={styles.themeColor}>
<h3 className={styles.title}>主题颜色</h3>
{colorList.map((color) => {
const classname =
value === color
? `${styles.colorBlock} ${styles.active}`
: styles.colorBlock;
return (
<Tag
className={classname}
key={color}
color={color}
onClick={() => onChange && onChange(color)}
/>
);
})}
</div>
);
};
export default ThemeColor;
.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%);
}
}
}
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 }) => (
<Fragment>
<div
className={styles.color_block}
style={{
backgroundColor: color,
}}
/>
<div className={styles.color_block_title}>{title}</div>
</Fragment>
);
const Body = ({ children, title, style }) => (
<div
style={{
padding: 15,
...style,
}}
>
<h3 className={styles.bodyTitle}>{title}</h3>
{children}
</div>
);
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: [
<Select
value={this.state.grid}
onSelect={value => this.changeSetting('grid', value)}
style={{ width: 120 }}
>
<Select.Option value="Wide">Wide</Select.Option>
<Select.Option value="Fluid">Fluid</Select.Option>
</Select>,
],
},
{
title: 'Fixed Header',
isShow: true,
action: [
<Switch
checked={!!this.state.fixedHeader}
onChange={checked => this.changeSetting('fixedHeader', checked)}
/>,
],
},
{
title: '↳ 下滑时隐藏 Header',
isShow: true,
action: [
<Switch
checked={!!this.state.autoHideHeader}
onChange={checked => this.changeSetting('autoHideHeader', checked)}
/>,
],
},
{
title: 'Fix Siderbar',
isShow: layout === 'sidemenu',
action: [
<Switch
checked={!!this.state.fixSiderbar}
onChange={this.fixSiderbar}
/>,
],
},
].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 (
<div
className={`${styles.sidebar} ${
this.state.collapse ? styles.show : ''
}`}
>
<div className={styles.mini_bar} onClick={this.togglerContent}>
<img
alt="logo"
src="https://gw.alipayobjects.com/zos/rmsportal/ApQgLmeZDNJMomKNvavq.svg"
/>
</div>
<div className={styles.content}>
<Body
title="整体风格设置"
style={{
paddingBottom: 10,
}}
>
<RadioGroup
onChange={({ target }) =>
this.changeSetting('silderTheme', target.value)
}
value={this.state.silderTheme}
>
<Radio style={radioStyle} value="dark">
<ColorBlock color="#002140" title="深色导航" />
</Radio>
<Radio style={radioStyle} value="ligth">
<ColorBlock color="#E9E9E9" title="浅色导航" />
</Radio>
</RadioGroup>
<ThemeColor
value={this.state.themeColor}
onChange={color => this.changeSetting('themeColor', color)}
/>
</Body>
<Divider style={{ margin: 0 }} />
<Body title="导航设置 ">
<LayoutSeting
value={this.state.layout}
onChange={layout => this.changeSetting('layout', layout)}
/>
<List
split={false}
dataSource={this.getLayOutSetting()}
renderItem={item => (
<List.Item actions={item.action}>{item.title}</List.Item>
)}
/>
</Body>
<Divider style={{ margin: 0 }} />
<Body title="其他设置">
<List
split={false}
dataSource={[
{
title: '色弱模式',
action: [
<Select
value={this.state.colorWeak}
onSelect={value => this.changeSetting('colorWeak', value)}
style={{ width: 120 }}
>
<Select.Option value="open">打开</Select.Option>
<Select.Option value="colse">关闭</Select.Option>
</Select>,
],
},
]}
renderItem={item => (
<List.Item actions={item.action}>{item.title}</List.Item>
)}
/>
</Body>
</div>
</div>
);
}
}
export default Sidebar;
.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;
}
}
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 <img src={url} alt={alt} />;
};
export default navState;
...@@ -161,7 +161,6 @@ export default class BaseMeun extends PureComponent { ...@@ -161,7 +161,6 @@ export default class BaseMeun extends PureComponent {
return ( return (
<Menu <Menu
key="Menu" key="Menu"
theme="dark"
mode="inline" mode="inline"
onOpenChange={this.props.handleOpenChange} onOpenChange={this.props.handleOpenChange}
selectedKeys={selectedKeys} selectedKeys={selectedKeys}
......
...@@ -5,7 +5,6 @@ import styles from './index.less'; ...@@ -5,7 +5,6 @@ import styles from './index.less';
import BaseMeun, { getMeunMatcheys } from './BaseMeun'; import BaseMeun, { getMeunMatcheys } from './BaseMeun';
import { urlToList } from '../utils/pathTools'; import { urlToList } from '../utils/pathTools';
const { Sider } = Layout; const { Sider } = Layout;
export default class SiderMenu extends PureComponent { export default class SiderMenu extends PureComponent {
...@@ -52,6 +51,12 @@ export default class SiderMenu extends PureComponent { ...@@ -52,6 +51,12 @@ export default class SiderMenu extends PureComponent {
}) })
.filter(item => item); .filter(item => item);
} }
isMainMenu = (key) => {
return this.menus.some(
item =>
key && (item.key === key || item.path === key),
);
}
handleOpenChange = (openKeys) => { handleOpenChange = (openKeys) => {
const lastOpenKey = openKeys[openKeys.length - 1]; const lastOpenKey = openKeys[openKeys.length - 1];
const moreThanOne = openKeys.filter(openKey => this.isMainMenu(openKey)).length > 1; const moreThanOne = openKeys.filter(openKey => this.isMainMenu(openKey)).length > 1;
...@@ -60,8 +65,9 @@ export default class SiderMenu extends PureComponent { ...@@ -60,8 +65,9 @@ export default class SiderMenu extends PureComponent {
}); });
}; };
render() { render() {
const { logo, collapsed, onCollapse } = this.props; const { logo, collapsed, onCollapse, theme } = this.props;
const { openKeys } = this.state; const { openKeys } = this.state;
const defaultProps = collapsed ? {} : { openKeys };
return ( return (
<Sider <Sider
trigger={null} trigger={null}
...@@ -70,7 +76,7 @@ export default class SiderMenu extends PureComponent { ...@@ -70,7 +76,7 @@ export default class SiderMenu extends PureComponent {
breakpoint="lg" breakpoint="lg"
onCollapse={onCollapse} onCollapse={onCollapse}
width={256} width={256}
className={styles.sider} className={`${styles.sider} ${theme === 'ligth' ? styles.ligth : ''}`}
> >
<div className={styles.logo} key="logo"> <div className={styles.logo} key="logo">
<Link to="/"> <Link to="/">
...@@ -81,12 +87,11 @@ export default class SiderMenu extends PureComponent { ...@@ -81,12 +87,11 @@ export default class SiderMenu extends PureComponent {
<BaseMeun <BaseMeun
{...this.props} {...this.props}
key="Menu" key="Menu"
theme="dark"
mode="inline" mode="inline"
handleOpenChange={this.handleOpenChange} handleOpenChange={this.handleOpenChange}
openKeys={collapsed ? [] : openKeys}
onOpenChange={this.handleOpenChange} onOpenChange={this.handleOpenChange}
style={{ padding: '16px 0', width: '100%' }} style={{ padding: '16px 0', width: '100%' }}
{...defaultProps}
/> />
</Sider> </Sider>
); );
......
...@@ -4,7 +4,7 @@ import DrawerMenu from 'rc-drawer-menu'; ...@@ -4,7 +4,7 @@ import DrawerMenu from 'rc-drawer-menu';
import SiderMenu from './SiderMenu'; import SiderMenu from './SiderMenu';
export default props => ( export default props => (
props.isMobile ? ( props.isMobile || props.fixSiderbar ? (
<DrawerMenu <DrawerMenu
parent={null} parent={null}
level={null} level={null}
......
@import "~antd/lib/style/themes/default.less"; @import '~antd/lib/style/themes/default.less';
@ease-in-out-circ: cubic-bezier(.78, .14, .15, .86); @ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86);
.logo { .logo {
height: 64px; height: 64px;
position: relative; position: relative;
line-height: 64px; line-height: 64px;
padding-left: (@menu-collapsed-width - 32px) / 2; padding-left: (@menu-collapsed-width - 32px) / 2;
transition: all .3s; transition: all 0.3s;
background: #002140; background: #002140;
overflow: hidden; overflow: hidden;
img { img {
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
height: 32px; height: 32px;
} }
h1 { h1 {
color: #fff; color: white;
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
font-size: 20px; font-size: 20px;
...@@ -26,9 +26,18 @@ ...@@ -26,9 +26,18 @@
.sider { .sider {
min-height: 100vh; min-height: 100vh;
box-shadow: 2px 0 6px rgba(0, 21, 41, .35); box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
position: relative; position: relative;
z-index: 10; z-index: 10;
&.ligth {
background-color: white;
.logo {
background: white;
h1 {
color: #002140;
}
}
}
} }
.icon { .icon {
......
...@@ -7,18 +7,31 @@ import styles from './index.less'; ...@@ -7,18 +7,31 @@ import styles from './index.less';
export default class TopNavHeader extends PureComponent { export default class TopNavHeader extends PureComponent {
render() { render() {
return ( return (
<div className={styles.main}> <div
<div className={styles.left}> className={`${styles.head} ${
<div className={styles.logo} key="logo"> this.props.theme === 'ligth' ? styles.ligth : ''
<Link to="/"> }`}
<img src={this.props.logo} alt="logo" /> >
<h1>Ant Design Pro</h1> <div
</Link> className={`${styles.main} ${
this.props.grid === 'Wide' ? styles.wide : ''
}`}
>
<div className={styles.left}>
<div className={styles.logo} key="logo">
<Link to="/">
<img src={this.props.logo} alt="logo" />
<h1>Ant Design Pro</h1>
</Link>
</div>
<BaseMeun
{...this.props}
style={{ padding: '9px 0', border: 'none' }}
/>
</div>
<div className={styles.right}>
<RightContent {...this.props} />
</div> </div>
<BaseMeun {...this.props} style={{ padding: '9px 0' }} />
</div>
<div className={styles.right}>
<RightContent theme="white" {...this.props} />
</div> </div>
</div> </div>
); );
......
.main { .head {
display: flex; width: 100%;
transition: background 0.3s, width 0.2s;
height: 64px; height: 64px;
margin: auto; padding: 0 12px 0 0;
max-width: 1200px; box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.left { position: relative;
flex: 1; &.ligth {
background-color: #fff;
}
.main {
display: flex; display: flex;
.logo { height: 64px;
width: 160px; padding-left: 24px;
height: 64px; &.wide {
position: relative; max-width: 1200px;
line-height: 64px; margin: auto;
transition: all 0.3s; padding-left: 4px;
overflow: hidden; }
img { .left {
display: inline-block; flex: 1;
vertical-align: middle; display: flex;
height: 32px;
}
h1 {
color: #fff;
display: inline-block;
vertical-align: middle;
font-size: 16px;
margin: 0 0 0 12px;
font-weight: 400;
}
} }
} }
} }
.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;
}
}
...@@ -2,6 +2,7 @@ html, ...@@ -2,6 +2,7 @@ html,
body, body,
:global(#root) { :global(#root) {
height: 100%; height: 100%;
overflow: auto;
} }
:global(.ant-layout) { :global(.ant-layout) {
......
import React, { Fragment } from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Layout, Icon, message } from 'antd'; import { Layout } from 'antd';
import DocumentTitle from 'react-document-title'; import DocumentTitle from 'react-document-title';
import { connect } from 'dva'; 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 { ContainerQuery } from 'react-container-query';
import classNames from 'classnames'; 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 SiderMenu from '../components/SiderMenu';
import NotFound from '../routes/Exception/404'; import NotFound from '../routes/Exception/404';
import { getRoutes } from '../utils/utils'; import { getRoutes } from '../utils/utils';
import Authorized from '../utils/Authorized'; import Authorized from '../utils/Authorized';
import { getMenuData } from '../common/menu'; import Sidebar from '../components/Sidebar';
import logo from '../assets/logo.svg'; 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 { AuthorizedRoute } = Authorized;
/** const RightSidebar = connect(({ setting }) => ({ ...setting }))(Sidebar);
* 根据菜单取得重定向地址.
*/
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 query = { const query = {
'screen-xs': { 'screen-xs': {
...@@ -59,19 +40,10 @@ const query = { ...@@ -59,19 +40,10 @@ const query = {
minWidth: 1200, minWidth: 1200,
}, },
}; };
let isMobile;
enquireScreen((b) => {
isMobile = b;
});
class BasicLayout extends React.PureComponent { class BasicLayout extends React.PureComponent {
static childContextTypes = { static childContextTypes = {
location: PropTypes.object, location: PropTypes.object,
breadcrumbNameMap: PropTypes.object, breadcrumbNameMap: PropTypes.object,
}
state = {
isMobile,
}; };
getChildContext() { getChildContext() {
const { location, routerData } = this.props; const { location, routerData } = this.props;
...@@ -80,16 +52,6 @@ class BasicLayout extends React.PureComponent { ...@@ -80,16 +52,6 @@ class BasicLayout extends React.PureComponent {
breadcrumbNameMap: routerData, breadcrumbNameMap: routerData,
}; };
} }
componentDidMount() {
enquireScreen((mobile) => {
this.setState({
isMobile: mobile,
});
});
this.props.dispatch({
type: 'user/fetchCurrent',
});
}
getPageTitle() { getPageTitle() {
const { routerData, location } = this.props; const { routerData, location } = this.props;
const { pathname } = location; const { pathname } = location;
...@@ -113,150 +75,73 @@ class BasicLayout extends React.PureComponent { ...@@ -113,150 +75,73 @@ class BasicLayout extends React.PureComponent {
return '/dashboard/analysis'; return '/dashboard/analysis';
} }
return redirect; return redirect;
} };
handleMenuCollapse = (collapsed) => { handleMenuCollapse = (collapsed) => {
this.props.dispatch({ this.props.dispatch({
type: 'global/changeLayoutCollapsed', type: 'global/changeLayoutCollapsed',
payload: collapsed, payload: collapsed,
}); });
} };
handleNoticeClear = (type) => { changeSetting = (setting) => {
message.success(`清空了${type}`);
this.props.dispatch({ this.props.dispatch({
type: 'global/clearNotices', type: 'setting/changeSetting',
payload: type, 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() { render() {
const isFluid = this.props.layout === 'fluid';
const { const {
currentUser, collapsed, fetchingNotices, notices, routerData, match, location, isMobile,
redirectData,
routerData,
fixedHeader,
match,
} = this.props; } = this.props;
const isTop = this.props.layout === 'topmenu';
const bashRedirect = this.getBashRedirect(); const bashRedirect = this.getBashRedirect();
const myRedirectData = redirectData || [];
const layout = ( const layout = (
<Layout> <Layout>
{isFluid && !isMobile ? null : ( {isTop && !isMobile ? null : (
<SiderMenu <SiderMenu
logo={logo} logo={logo}
// 不带Authorized参数的情况下如果没有权限,会强制跳到403界面
// If you do not have the Authorized parameter
// you will be forced to jump to the 403 interface without permission
Authorized={Authorized} Authorized={Authorized}
menuData={getMenuData()} theme={this.props.silderTheme}
collapsed={collapsed}
location={location}
isMobile={this.state.isMobile}
onCollapse={this.handleMenuCollapse} onCollapse={this.handleMenuCollapse}
{...this.props}
/> />
)} )}
<Layout> <Layout>
<Header style={{ padding: 0 }}> <Header
{isFluid && !isMobile ? ( handleMenuCollapse={this.handleMenuCollapse}
<TopNavHeader logo={logo}
logo={logo} {...this.props}
mode="horizontal" />
location={location} <Content
menuData={getMenuData()} style={{
isMobile={this.state.isMobile} margin: '24px 24px 0',
onNoticeClear={this.handleNoticeClear} height: '100%',
onCollapse={this.handleMenuCollapse} paddingTop: fixedHeader ? 64 : 0,
onMenuClick={this.handleMenuClick} }}
onNoticeVisibleChange={this.handleNoticeVisibleChange} >
notices={notices}
currentUser={currentUser}
fetchingNotices={fetchingNotices}
/>
) : (
<GlobalHeader
logo={logo}
currentUser={currentUser}
fetchingNotices={fetchingNotices}
notices={notices}
collapsed={collapsed}
isMobile={this.state.isMobile}
onNoticeClear={this.handleNoticeClear}
onCollapse={this.handleMenuCollapse}
onMenuClick={this.handleMenuClick}
onNoticeVisibleChange={this.handleNoticeVisibleChange}
/>
)}
</Header>
<Content style={{ margin: '24px 24px 0', height: '100%' }}>
<Switch> <Switch>
{ {myRedirectData.map(item => (
redirectData.map(item => <Redirect key={item.from} exact from={item.from} to={item.to} />
<Redirect key={item.from} exact from={item.from} to={item.to} /> ))}
) {getRoutes(match.path, routerData).map(item => (
} <AuthorizedRoute
{ key={item.key}
getRoutes(match.path, routerData).map(item => path={item.path}
( component={item.component}
<AuthorizedRoute exact={item.exact}
key={item.key} authority={item.authority}
path={item.path} redirectPath="/exception/403"
component={item.component} />
exact={item.exact} ))}
authority={item.authority}
redirectPath="/exception/403"
/>
)
)
}
<Redirect exact from="/" to={bashRedirect} /> <Redirect exact from="/" to={bashRedirect} />
<Route render={NotFound} /> <Route render={NotFound} />
</Switch> </Switch>
</Content> </Content>
<Footer style={{ padding: 0 }}> <Footer />
<GlobalFooter
links={[{
key: 'Pro 首页',
title: 'Pro 首页',
href: 'http://pro.ant.design',
blankTarget: true,
}, {
key: 'github',
title: <Icon type="github" />,
href: 'https://github.com/ant-design/ant-design-pro',
blankTarget: true,
}, {
key: 'Ant Design',
title: 'Ant Design',
href: 'http://ant.design',
blankTarget: true,
}]}
copyright={
<Fragment>
Copyright <Icon type="copyright" /> 2018 蚂蚁金服体验技术部出品
</Fragment>
}
/>
</Footer>
</Layout> </Layout>
</Layout> </Layout>
); );
...@@ -264,17 +149,20 @@ class BasicLayout extends React.PureComponent { ...@@ -264,17 +149,20 @@ class BasicLayout extends React.PureComponent {
return ( return (
<DocumentTitle title={this.getPageTitle()}> <DocumentTitle title={this.getPageTitle()}>
<ContainerQuery query={query}> <ContainerQuery query={query}>
{params => <div className={classNames(params)}>{layout}</div>} {params => (
<div className={classNames(params)}>
{layout}
<RightSidebar onChange={this.changeSetting} />
</div>
)}
</ContainerQuery> </ContainerQuery>
</DocumentTitle> </DocumentTitle>
); );
} }
} }
export default connect(({ user, global, loading }) => ({ export default connect(({ global, setting }) => ({
currentUser: user.currentUser,
collapsed: global.collapsed, collapsed: global.collapsed,
layout: global.layout, layout: setting.layout,
fetchingNotices: loading.effects['global/fetchNotices'], ...setting,
notices: global.notices,
}))(BasicLayout); }))(BasicLayout);
import React, { Fragment } from 'react';
import { Layout, Icon } from 'antd';
import GlobalFooter from '../components/GlobalFooter';
const { Footer } = Layout;
const FooterView = () => (
<Footer style={{ padding: 0 }}>
<GlobalFooter
links={[
{
key: 'Pro 首页',
title: 'Pro 首页',
href: 'http://pro.ant.design',
blankTarget: true,
},
{
key: 'github',
title: <Icon type="github" />,
href: 'https://github.com/ant-design/ant-design-pro',
blankTarget: true,
},
{
key: 'Ant Design',
title: 'Ant Design',
href: 'http://ant.design',
blankTarget: true,
},
]}
copyright={
<Fragment>
Copyright <Icon type="copyright" /> 2018 蚂蚁金服体验技术部出品
</Fragment>
}
/>
</Footer>
);
export default FooterView;
...@@ -5,13 +5,13 @@ import styles from './GridContent.less'; ...@@ -5,13 +5,13 @@ import styles from './GridContent.less';
class GridContent extends PureComponent { class GridContent extends PureComponent {
render() { render() {
let className = `${styles.main}`; let className = `${styles.main}`;
if (this.props.layout === 'fluid') { if (this.props.grid === 'Wide') {
className = `${styles.main} ${styles.fluid}`; className = `${styles.main} ${styles.wide}`;
} }
return <div className={className}>{this.props.children}</div>; return <div className={className}>{this.props.children}</div>;
} }
} }
export default connect(({ global }) => ({ export default connect(({ setting }) => ({
layout: global.layout, grid: setting.grid,
}))(GridContent); }))(GridContent);
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
min-height: 100%; min-height: 100%;
&.fluid { transition: 0.3s;
&.wide {
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
} }
......
import React, { PureComponent } from 'react';
import { Layout, message } from 'antd';
import Animate from 'rc-animate';
import { connect } from 'dva';
import { routerRedux } from 'dva/router';
import GlobalHeader from '../components/GlobalHeader';
import TopNavHeader from '../components/TopNavHeader';
import styles from './Header.less';
import Authorized from '../utils/Authorized';
const { Header } = Layout;
class HeaderView extends PureComponent {
state = {
visible: true,
};
componentDidMount() {
document.getElementById('root').addEventListener('scroll', this.handScroll);
}
componentWillUnmount() {
document
.getElementById('root')
.removeEventListener('scroll', this.handScroll);
}
getHeadWidth = () => {
if (
!this.props.fixedHeader ||
this.props.layout === 'topmenu' ||
this.props.fixSiderbar
) {
return '100%';
}
if (!this.props.collapsed) {
return 'calc(100% - 256px)';
}
if (this.props.collapsed) {
return 'calc(100% - 80px)';
}
};
handleNoticeClear = (type) => {
message.success(`清空了${type}`);
this.props.dispatch({
type: 'global/clearNotices',
payload: type,
});
};
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',
});
}
};
handScroll = () => {
if (!this.props.autoHideHeader) {
return;
}
const { scrollTop } = document.getElementById('root');
if (!this.ticking) {
this.ticking = false;
requestAnimationFrame(() => {
if (scrollTop > 400 && this.state.visible) {
this.setState({
visible: false,
});
}
if (scrollTop < 400 && !this.state.visible) {
this.setState({
visible: true,
});
}
this.ticking = false;
});
}
};
render() {
const {
logo,
isMobile,
handleMenuCollapse,
silderTheme,
layout,
fixedHeader,
} = this.props;
const isTop = layout === 'topmenu';
const HeaderDom = this.state.visible ? (
<Header
style={{ padding: 0, width: this.getHeadWidth() }}
className={fixedHeader ? styles.fixedHeader : ''}
>
{isTop && !isMobile ? (
<TopNavHeader
logo={logo}
theme={silderTheme}
mode="horizontal"
Authorized={Authorized}
isMobile={isMobile}
onNoticeClear={this.handleNoticeClear}
onCollapse={handleMenuCollapse}
onMenuClick={this.handleMenuClick}
onNoticeVisibleChange={this.handleNoticeVisibleChange}
{...this.props}
/>
) : (
<GlobalHeader
logo={logo}
onNoticeClear={this.handleNoticeClear}
onCollapse={handleMenuCollapse}
onMenuClick={this.handleMenuClick}
onNoticeVisibleChange={this.handleNoticeVisibleChange}
{...this.props}
/>
)}
</Header>
) : null;
return (
<Animate component="" transitionName="fade">
{HeaderDom}
</Animate>
);
}
}
export default connect(({ user, global, setting, loading }) => ({
currentUser: user.currentUser,
collapsed: global.collapsed,
fetchingNotices: loading.effects['global/fetchNotices'],
notices: global.notices,
layout: setting.layout,
silderTheme: setting.silderTheme,
fixedHeader: setting.fixedHeader,
fixSiderbar: setting.fixSiderbar,
autoHideHeader: setting.autoHideHeader,
}))(HeaderView);
.fixedHeader {
position: fixed;
top: 0;
width: 100%;
z-index: 9;
}
import React, { PureComponent } from 'react';
import { Spin } from 'antd';
import { enquireScreen } from 'enquire-js';
import { connect } from 'dva';
import BasicLayout from './BasicLayout';
import { getMenuData } from '../common/menu';
/**
* 根据菜单取得重定向地址.
*/
const MenuData = getMenuData();
const getRedirectData = () => {
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);
});
}
}
};
MenuData.forEach(getRedirect);
return redirectData;
};
const redirectData = getRedirectData();
class LodingPage extends PureComponent {
state = {
loading: true,
isMobile: false,
};
componentDidMount() {
enquireScreen((mobile) => {
this.setState({
isMobile: mobile,
});
});
this.props.dispatch({
type: 'user/fetchCurrent',
});
const urlParams = new URL(window.location.href);
const settingString = urlParams.searchParams.get('setting');
if (settingString) {
const setting = {};
settingString.split(';').forEach((keyValue) => {
const [key, value] = keyValue.split(':');
setting[key] = value;
});
this.props.dispatch({
type: 'setting/changeSetting',
payload: setting,
});
}
this.hideLoading();
}
hideLoading() {
this.setState({
loading: false,
});
}
render() {
if (this.state.loading) {
return (
<div
style={{
width: '100%',
height: '100%',
margin: 'auto',
paddingTop: 50,
textAlign: 'center',
}}
>
<Spin size="large" />
</div>
);
}
return (
<BasicLayout
isMobile={this.state.isMobile}
menuData={MenuData}
redirectData={redirectData}
{...this.props}
/>
);
}
}
export default connect()(LodingPage);
...@@ -5,7 +5,6 @@ export default { ...@@ -5,7 +5,6 @@ export default {
state: { state: {
collapsed: false, collapsed: false,
layout: 'fluid',
notices: [], notices: [],
}, },
...@@ -41,12 +40,6 @@ export default { ...@@ -41,12 +40,6 @@ export default {
collapsed: payload, collapsed: payload,
}; };
}, },
changeLayout(state, { payload }) {
return {
...state,
layout: payload,
};
},
saveNotices(state, { payload }) { saveNotices(state, { payload }) {
return { return {
...state, ...state,
......
export default {
namespace: 'setting',
state: {
collapse: false,
silderTheme: 'dark',
themeColor: '#1890FF',
layout: 'sidemenu',
grid: 'Fluid',
fixedHeader: false,
autoHideHeader: false,
fixSiderbar: false,
colorWeak: 'close',
},
reducers: {
changeSetting(state, { payload }) {
const urlParams = new URL(window.location.href);
let urlParamsString = '';
Object.keys(payload).forEach((key) => {
if (payload[key] && state[key] !== undefined && key !== 'collapse') {
urlParamsString += `${key}:${payload[key]};`;
}
});
urlParams.searchParams.set('setting', urlParamsString);
window.history.replaceState(null, 'setting', urlParams.href);
return {
...state,
...payload,
};
},
},
};
...@@ -22,9 +22,9 @@ import AvatarList from '../../components/AvatarList'; ...@@ -22,9 +22,9 @@ import AvatarList from '../../components/AvatarList';
import { formatWan } from '../../utils/utils'; import { formatWan } from '../../utils/utils';
import styles from './UserCenter.less'; import styles from './UserCenter.less';
import stylesProjects from '../List/Projects.less'; import stylesProjects from '../List/Projects.less';
import stylesArticles from './List/Articles.less'; import stylesArticles from '../List/Articles.less';
import stylesApplications from './List/Applications.less'; import stylesApplications from '../List/Applications.less';
import GridContent from '../layouts/GridContent'; import GridContent from '../../layouts/GridContent';
@connect(({ list, loading, user, project }) => ({ @connect(({ list, loading, user, project }) => ({
list, list,
......
...@@ -3,8 +3,8 @@ import { connect } from 'dva'; ...@@ -3,8 +3,8 @@ import { connect } from 'dva';
import { Route, routerRedux, Switch, Redirect } from 'dva/router'; import { Route, routerRedux, Switch, Redirect } from 'dva/router';
import { Menu } from 'antd'; import { Menu } from 'antd';
import styles from './Info.less'; import styles from './Info.less';
import { getRoutes } from '../../utils/utils'; import { getRoutes } from '../../../utils/utils';
import GridContent from '../../layouts/GridContent'; import GridContent from '../../../layouts/GridContent';
const { Item } = Menu; const { Item } = Menu;
......
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