Commit 91bfd88d authored by jim's avatar jim

add top_meun and siderbar

parent b021ef4d
......@@ -122,7 +122,7 @@ const menuData = [{
path: 'user-center',
}, {
name: '个人设置',
path: 'userinfo',
path: 'userinfo/base',
}],
}];
......
......@@ -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')),
......
......@@ -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 (
<div className={className} >
......
......@@ -84,7 +84,7 @@ i.trigger {
}
}
.white {
.dark {
height: 64px;
.action {
color: rgba(255, 255, 255, 0.85);
......
......@@ -70,7 +70,7 @@ export default class NoticeIcon extends PureComponent {
const notificationBox = this.getNotificationBox();
const trigger = (
<span className={noticeButtonClass}>
<Badge count={count} className={styles.badge}>
<Badge count={count} style={{ boxShadow: 'none' }} className={styles.badge}>
<Icon type="bell" className={styles.icon} />
</Badge>
</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 {
return (
<Menu
key="Menu"
theme="dark"
mode="inline"
onOpenChange={this.props.handleOpenChange}
selectedKeys={selectedKeys}
......
......@@ -5,7 +5,6 @@ import styles from './index.less';
import BaseMeun, { getMeunMatcheys } from './BaseMeun';
import { urlToList } from '../utils/pathTools';
const { Sider } = Layout;
export default class SiderMenu extends PureComponent {
......@@ -52,6 +51,12 @@ export default class SiderMenu extends PureComponent {
})
.filter(item => 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 (
<Sider
trigger={null}
......@@ -70,7 +76,7 @@ export default class SiderMenu extends PureComponent {
breakpoint="lg"
onCollapse={onCollapse}
width={256}
className={styles.sider}
className={`${styles.sider} ${theme === 'ligth' ? styles.ligth : ''}`}
>
<div className={styles.logo} key="logo">
<Link to="/">
......@@ -81,12 +87,11 @@ export default class SiderMenu extends PureComponent {
<BaseMeun
{...this.props}
key="Menu"
theme="dark"
mode="inline"
handleOpenChange={this.handleOpenChange}
openKeys={collapsed ? [] : openKeys}
onOpenChange={this.handleOpenChange}
style={{ padding: '16px 0', width: '100%' }}
{...defaultProps}
/>
</Sider>
);
......
......@@ -4,7 +4,7 @@ import DrawerMenu from 'rc-drawer-menu';
import SiderMenu from './SiderMenu';
export default props => (
props.isMobile ? (
props.isMobile || props.fixSiderbar ? (
<DrawerMenu
parent={null}
level={null}
......
@import "~antd/lib/style/themes/default.less";
@ease-in-out-circ: cubic-bezier(.78, .14, .15, .86);
@import '~antd/lib/style/themes/default.less';
@ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86);
.logo {
height: 64px;
position: relative;
line-height: 64px;
padding-left: (@menu-collapsed-width - 32px) / 2;
transition: all .3s;
transition: all 0.3s;
background: #002140;
overflow: hidden;
img {
......@@ -14,7 +14,7 @@
height: 32px;
}
h1 {
color: #fff;
color: white;
display: inline-block;
vertical-align: middle;
font-size: 20px;
......@@ -26,9 +26,18 @@
.sider {
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;
z-index: 10;
&.ligth {
background-color: white;
.logo {
background: white;
h1 {
color: #002140;
}
}
}
}
.icon {
......
......@@ -7,18 +7,31 @@ import styles from './index.less';
export default class TopNavHeader extends PureComponent {
render() {
return (
<div className={styles.main}>
<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
className={`${styles.head} ${
this.props.theme === 'ligth' ? styles.ligth : ''
}`}
>
<div
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>
<BaseMeun {...this.props} style={{ padding: '9px 0' }} />
</div>
<div className={styles.right}>
<RightContent theme="white" {...this.props} />
</div>
</div>
);
......
.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;
}
}
......@@ -2,6 +2,7 @@ html,
body,
:global(#root) {
height: 100%;
overflow: auto;
}
:global(.ant-layout) {
......
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 = (
<Layout>
{isFluid && !isMobile ? null : (
{isTop && !isMobile ? null : (
<SiderMenu
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}
menuData={getMenuData()}
collapsed={collapsed}
location={location}
isMobile={this.state.isMobile}
theme={this.props.silderTheme}
onCollapse={this.handleMenuCollapse}
{...this.props}
/>
)}
<Layout>
<Header style={{ padding: 0 }}>
{isFluid && !isMobile ? (
<TopNavHeader
logo={logo}
mode="horizontal"
location={location}
menuData={getMenuData()}
isMobile={this.state.isMobile}
onNoticeClear={this.handleNoticeClear}
onCollapse={this.handleMenuCollapse}
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%' }}>
<Header
handleMenuCollapse={this.handleMenuCollapse}
logo={logo}
{...this.props}
/>
<Content
style={{
margin: '24px 24px 0',
height: '100%',
paddingTop: fixedHeader ? 64 : 0,
}}
>
<Switch>
{
redirectData.map(item =>
<Redirect key={item.from} exact from={item.from} to={item.to} />
)
}
{
getRoutes(match.path, routerData).map(item =>
(
<AuthorizedRoute
key={item.key}
path={item.path}
component={item.component}
exact={item.exact}
authority={item.authority}
redirectPath="/exception/403"
/>
)
)
}
{myRedirectData.map(item => (
<Redirect key={item.from} exact from={item.from} to={item.to} />
))}
{getRoutes(match.path, routerData).map(item => (
<AuthorizedRoute
key={item.key}
path={item.path}
component={item.component}
exact={item.exact}
authority={item.authority}
redirectPath="/exception/403"
/>
))}
<Redirect exact from="/" to={bashRedirect} />
<Route render={NotFound} />
</Switch>
</Content>
<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>
<Footer />
</Layout>
</Layout>
);
......@@ -264,17 +149,20 @@ class BasicLayout extends React.PureComponent {
return (
<DocumentTitle title={this.getPageTitle()}>
<ContainerQuery query={query}>
{params => <div className={classNames(params)}>{layout}</div>}
{params => (
<div className={classNames(params)}>
{layout}
<RightSidebar onChange={this.changeSetting} />
</div>
)}
</ContainerQuery>
</DocumentTitle>
);
}
}
export default connect(({ user, global, loading }) => ({
currentUser: user.currentUser,
export default connect(({ global, setting }) => ({
collapsed: global.collapsed,
layout: global.layout,
fetchingNotices: loading.effects['global/fetchNotices'],
notices: global.notices,
layout: setting.layout,
...setting,
}))(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';
class GridContent extends PureComponent {
render() {
let className = `${styles.main}`;
if (this.props.layout === 'fluid') {
className = `${styles.main} ${styles.fluid}`;
if (this.props.grid === 'Wide') {
className = `${styles.main} ${styles.wide}`;
}
return <div className={className}>{this.props.children}</div>;
}
}
export default connect(({ global }) => ({
layout: global.layout,
export default connect(({ setting }) => ({
grid: setting.grid,
}))(GridContent);
......@@ -2,7 +2,8 @@
width: 100%;
height: 100%;
min-height: 100%;
&.fluid {
transition: 0.3s;
&.wide {
max-width: 1200px;
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 {
state: {
collapsed: false,
layout: 'fluid',
notices: [],
},
......@@ -41,12 +40,6 @@ export default {
collapsed: payload,
};
},
changeLayout(state, { payload }) {
return {
...state,
layout: payload,
};
},
saveNotices(state, { payload }) {
return {
...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';
import { formatWan } from '../../utils/utils';
import styles from './UserCenter.less';
import stylesProjects from '../List/Projects.less';
import stylesArticles from './List/Articles.less';
import stylesApplications from './List/Applications.less';
import GridContent from '../layouts/GridContent';
import stylesArticles from '../List/Articles.less';
import stylesApplications from '../List/Applications.less';
import GridContent from '../../layouts/GridContent';
@connect(({ list, loading, user, project }) => ({
list,
......
......@@ -3,8 +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 GridContent from '../../layouts/GridContent';
import { getRoutes } from '../../../utils/utils';
import GridContent from '../../../layouts/GridContent';
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