29 changed files with 937 additions and 242 deletions
@ -0,0 +1,45 @@ |
|||||
|
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; |
||||
@ -0,0 +1,55 @@ |
|||||
|
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; |
||||
@ -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%); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 }) => ( |
||||
|
<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; |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
@ -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 <img src={url} alt={alt} />; |
||||
|
}; |
||||
|
|
||||
|
export default navState; |
||||
@ -1,31 +1,53 @@ |
|||||
.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; |
||||
|
} |
||||
|
} |
||||
|
|||||
@ -0,0 +1,38 @@ |
|||||
|
|
||||
|
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; |
||||
@ -0,0 +1,153 @@ |
|||||
|
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); |
||||
@ -0,0 +1,6 @@ |
|||||
|
.fixedHeader { |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
width: 100%; |
||||
|
z-index: 9; |
||||
|
} |
||||
@ -0,0 +1,94 @@ |
|||||
|
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); |
||||
@ -0,0 +1,32 @@ |
|||||
|
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, |
||||
|
}; |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
Loading…
Reference in new issue