Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
ant-design-pro
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
duanledexianxianxian
ant-design-pro
Commits
b021ef4d
Commit
b021ef4d
authored
Feb 22, 2018
by
jim
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add top nav layout
parent
2e59803f
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
782 additions
and
480 deletions
+782
-480
src/components/GlobalHeader/RightContent.js
src/components/GlobalHeader/RightContent.js
+141
-0
src/components/GlobalHeader/index.js
src/components/GlobalHeader/index.js
+17
-123
src/components/GlobalHeader/index.less
src/components/GlobalHeader/index.less
+23
-7
src/components/SiderMenu/BaseMeun.js
src/components/SiderMenu/BaseMeun.js
+175
-0
src/components/SiderMenu/SiderMenu.js
src/components/SiderMenu/SiderMenu.js
+15
-158
src/components/SiderMenu/SilderMenu.test.js
src/components/SiderMenu/SilderMenu.test.js
+1
-1
src/components/TopNavHeader/index.js
src/components/TopNavHeader/index.js
+26
-0
src/components/TopNavHeader/index.less
src/components/TopNavHeader/index.less
+31
-0
src/layouts/BasicLayout.js
src/layouts/BasicLayout.js
+31
-9
src/layouts/GridContent.js
src/layouts/GridContent.js
+17
-0
src/layouts/GridContent.less
src/layouts/GridContent.less
+9
-0
src/layouts/PageHeaderLayout.js
src/layouts/PageHeaderLayout.js
+6
-1
src/layouts/PageHeaderLayout.less
src/layouts/PageHeaderLayout.less
+1
-1
src/models/global.js
src/models/global.js
+7
-0
src/routes/Dashboard/Analysis.js
src/routes/Dashboard/Analysis.js
+4
-3
src/routes/Dashboard/Monitor.js
src/routes/Dashboard/Monitor.js
+4
-3
src/routes/UserProfile/UserCenter.js
src/routes/UserProfile/UserCenter.js
+243
-137
src/routes/UserProfile/Userinfo/Info.js
src/routes/UserProfile/Userinfo/Info.js
+31
-37
No files found.
src/components/GlobalHeader/RightContent.js
0 → 100644
View file @
b021ef4d
import
React
,
{
PureComponent
}
from
'
react
'
;
import
{
Spin
,
Tag
,
Menu
,
Icon
,
Dropdown
,
Avatar
,
Tooltip
}
from
'
antd
'
;
import
moment
from
'
moment
'
;
import
groupBy
from
'
lodash/groupBy
'
;
import
NoticeIcon
from
'
../NoticeIcon
'
;
import
HeaderSearch
from
'
../HeaderSearch
'
;
import
styles
from
'
./index.less
'
;
export
default
class
GlobalHeaderRight
extends
PureComponent
{
getNoticeData
()
{
const
{
notices
=
[]
}
=
this
.
props
;
if
(
notices
.
length
===
0
)
{
return
{};
}
const
newNotices
=
notices
.
map
((
notice
)
=>
{
const
newNotice
=
{
...
notice
};
if
(
newNotice
.
datetime
)
{
newNotice
.
datetime
=
moment
(
notice
.
datetime
).
fromNow
();
}
// transform id to item key
if
(
newNotice
.
id
)
{
newNotice
.
key
=
newNotice
.
id
;
}
if
(
newNotice
.
extra
&&
newNotice
.
status
)
{
const
color
=
{
todo
:
''
,
processing
:
'
blue
'
,
urgent
:
'
red
'
,
doing
:
'
gold
'
,
}[
newNotice
.
status
];
newNotice
.
extra
=
(
<
Tag
color
=
{
color
}
style
=
{{
marginRight
:
0
}}
>
{
newNotice
.
extra
}
<
/Tag
>
);
}
return
newNotice
;
});
return
groupBy
(
newNotices
,
'
type
'
);
}
render
()
{
const
{
currentUser
,
fetchingNotices
,
onNoticeVisibleChange
,
onMenuClick
,
onNoticeClear
,
}
=
this
.
props
;
const
menu
=
(
<
Menu
className
=
{
styles
.
menu
}
selectedKeys
=
{[]}
onClick
=
{
onMenuClick
}
>
<
Menu
.
Item
key
=
"
userCenter
"
>
<
Icon
type
=
"
user
"
/>
个人中心
<
/Menu.Item
>
<
Menu
.
Item
key
=
"
userinfo
"
>
<
Icon
type
=
"
setting
"
/>
设置
<
/Menu.Item
>
<
Menu
.
Item
key
=
"
triggerError
"
>
<
Icon
type
=
"
close-circle
"
/>
触发报错
<
/Menu.Item
>
<
Menu
.
Divider
/>
<
Menu
.
Item
key
=
"
logout
"
>
<
Icon
type
=
"
logout
"
/>
退出登录
<
/Menu.Item
>
<
/Menu
>
);
const
noticeData
=
this
.
getNoticeData
();
let
className
=
styles
.
right
;
if
(
this
.
props
.
theme
===
'
white
'
)
{
className
=
`
${
styles
.
right
}
${
styles
.
white
}
`
;
}
return
(
<
div
className
=
{
className
}
>
<
HeaderSearch
className
=
{
`
${
styles
.
action
}
${
styles
.
search
}
`
}
placeholder
=
"
站内搜索
"
dataSource
=
{[
'
搜索提示一
'
,
'
搜索提示二
'
,
'
搜索提示三
'
]}
onSearch
=
{(
value
)
=>
{
console
.
log
(
'
input
'
,
value
);
// eslint-disable-line
}}
onPressEnter
=
{(
value
)
=>
{
console
.
log
(
'
enter
'
,
value
);
// eslint-disable-line
}}
/
>
<
Tooltip
title
=
"
使用文档
"
>
<
a
target
=
"
_blank
"
href
=
"
http://pro.ant.design/docs/getting-started
"
rel
=
"
noopener noreferrer
"
className
=
{
styles
.
action
}
>
<
Icon
type
=
"
question-circle-o
"
/>
<
/a
>
<
/Tooltip
>
<
NoticeIcon
className
=
{
styles
.
action
}
count
=
{
currentUser
.
notifyCount
}
onItemClick
=
{(
item
,
tabProps
)
=>
{
console
.
log
(
item
,
tabProps
);
// eslint-disable-line
}}
onClear
=
{
onNoticeClear
}
onPopupVisibleChange
=
{
onNoticeVisibleChange
}
loading
=
{
fetchingNotices
}
popupAlign
=
{{
offset
:
[
20
,
-
16
]
}}
>
<
NoticeIcon
.
Tab
list
=
{
noticeData
[
'
通知
'
]}
title
=
"
通知
"
emptyText
=
"
你已查看所有通知
"
emptyImage
=
"
https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg
"
/>
<
NoticeIcon
.
Tab
list
=
{
noticeData
[
'
消息
'
]}
title
=
"
消息
"
emptyText
=
"
您已读完所有消息
"
emptyImage
=
"
https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg
"
/>
<
NoticeIcon
.
Tab
list
=
{
noticeData
[
'
待办
'
]}
title
=
"
待办
"
emptyText
=
"
你已完成所有待办
"
emptyImage
=
"
https://gw.alipayobjects.com/zos/rmsportal/HsIsxMZiWKrNUavQUXqx.svg
"
/>
<
/NoticeIcon
>
{
currentUser
.
name
?
(
<
Dropdown
overlay
=
{
menu
}
>
<
span
className
=
{
`
${
styles
.
action
}
${
styles
.
account
}
`
}
>
<
Avatar
size
=
"
small
"
className
=
{
styles
.
avatar
}
src
=
{
currentUser
.
avatar
}
/
>
<
span
className
=
{
styles
.
name
}
>
{
currentUser
.
name
}
<
/span
>
<
/span
>
<
/Dropdown
>
)
:
(
<
Spin
size
=
"
small
"
style
=
{{
marginLeft
:
8
}}
/
>
)}
<
/div
>
);
}
}
src/components/GlobalHeader/index.js
View file @
b021ef4d
import
React
,
{
PureComponent
}
from
'
react
'
;
import
{
Menu
,
Icon
,
Spin
,
Tag
,
Dropdown
,
Avatar
,
Divider
,
Tooltip
}
from
'
antd
'
;
import
moment
from
'
moment
'
;
import
groupBy
from
'
lodash/groupBy
'
;
import
Debounce
from
'
lodash-decorators/debounce
'
;
import
{
Icon
,
Divider
}
from
'
antd
'
;
import
{
Link
}
from
'
dva/router
'
;
import
NoticeIcon
from
'
../NoticeIcon
'
;
import
HeaderSearch
from
'
../HeaderSearch
'
;
import
styles
from
'
./index.less
'
;
import
RightContent
from
'
./RightContent
'
;
export
default
class
GlobalHeader
extends
PureComponent
{
componentWillUnmount
()
{
this
.
triggerResizeEvent
.
cancel
();
}
getNoticeData
()
{
const
{
notices
=
[]
}
=
this
.
props
;
if
(
notices
.
length
===
0
)
{
return
{};
}
const
newNotices
=
notices
.
map
((
notice
)
=>
{
const
newNotice
=
{
...
notice
};
if
(
newNotice
.
datetime
)
{
newNotice
.
datetime
=
moment
(
notice
.
datetime
).
fromNow
();
}
// transform id to item key
if
(
newNotice
.
id
)
{
newNotice
.
key
=
newNotice
.
id
;
}
if
(
newNotice
.
extra
&&
newNotice
.
status
)
{
const
color
=
({
todo
:
''
,
processing
:
'
blue
'
,
urgent
:
'
red
'
,
doing
:
'
gold
'
,
})[
newNotice
.
status
];
newNotice
.
extra
=
<
Tag
color
=
{
color
}
style
=
{{
marginRight
:
0
}}
>
{
newNotice
.
extra
}
<
/Tag>
;
}
return
newNotice
;
});
return
groupBy
(
newNotices
,
'
type
'
);
}
toggle
=
()
=>
{
const
{
collapsed
,
onCollapse
}
=
this
.
props
;
onCollapse
(
!
collapsed
);
this
.
triggerResizeEvent
();
}
@
Debounce
(
600
)
triggerResizeEvent
()
{
// eslint-disable-line
triggerResizeEvent
()
{
// eslint-disable-line
const
event
=
document
.
createEvent
(
'
HTMLEvents
'
);
event
.
initEvent
(
'
resize
'
,
true
,
false
);
window
.
dispatchEvent
(
event
);
}
toggle
=
()
=>
{
const
{
collapsed
,
onCollapse
}
=
this
.
props
;
onCollapse
(
!
collapsed
);
this
.
triggerResizeEvent
();
};
render
()
{
const
{
currentUser
,
collapsed
,
fetchingNotices
,
isMobile
,
logo
,
onNoticeVisibleChange
,
onMenuClick
,
onNoticeClear
,
}
=
this
.
props
;
const
menu
=
(
<
Menu
className
=
{
styles
.
menu
}
selectedKeys
=
{[]}
onClick
=
{
onMenuClick
}
>
<
Menu
.
Item
key
=
"
userCenter
"
><
Icon
type
=
"
user
"
/>
个人中心
<
/Menu.Item
>
<
Menu
.
Item
key
=
"
userinfo
"
><
Icon
type
=
"
setting
"
/>
设置
<
/Menu.Item
>
<
Menu
.
Item
key
=
"
triggerError
"
><
Icon
type
=
"
close-circle
"
/>
触发报错
<
/Menu.Item
>
<
Menu
.
Divider
/>
<
Menu
.
Item
key
=
"
logout
"
><
Icon
type
=
"
logout
"
/>
退出登录
<
/Menu.Item
>
<
/Menu
>
);
const
noticeData
=
this
.
getNoticeData
();
const
{
collapsed
,
isMobile
,
logo
}
=
this
.
props
;
return
(
<
div
className
=
{
styles
.
header
}
>
{
isMobile
&&
(
[
(
<
Link
to
=
"
/
"
className
=
{
styles
.
logo
}
key
=
"
logo
"
>
<
img
src
=
{
logo
}
alt
=
"
logo
"
width
=
"
32
"
/>
<
/Link
>
),
<
Divider
type
=
"
vertical
"
key
=
"
line
"
/>
,
]
)}
{
isMobile
&&
[
<
Link
to
=
"
/
"
className
=
{
styles
.
logo
}
key
=
"
logo
"
>
<
img
src
=
{
logo
}
alt
=
"
logo
"
width
=
"
32
"
/>
<
/Link>
,
<
Divider
type
=
"
vertical
"
key
=
"
line
"
/>
,
]}
<
Icon
className
=
{
styles
.
trigger
}
type
=
{
collapsed
?
'
menu-unfold
'
:
'
menu-fold
'
}
onClick
=
{
this
.
toggle
}
/
>
<
div
className
=
{
styles
.
right
}
>
<
HeaderSearch
className
=
{
`
${
styles
.
action
}
${
styles
.
search
}
`
}
placeholder
=
"
站内搜索
"
dataSource
=
{[
'
搜索提示一
'
,
'
搜索提示二
'
,
'
搜索提示三
'
]}
onSearch
=
{(
value
)
=>
{
console
.
log
(
'
input
'
,
value
);
// eslint-disable-line
}}
onPressEnter
=
{(
value
)
=>
{
console
.
log
(
'
enter
'
,
value
);
// eslint-disable-line
}}
/
>
<
Tooltip
title
=
"
使用文档
"
>
<
a
target
=
"
_blank
"
href
=
"
http://pro.ant.design/docs/getting-started
"
rel
=
"
noopener noreferrer
"
className
=
{
styles
.
action
}
>
<
Icon
type
=
"
question-circle-o
"
/>
<
/a
>
<
/Tooltip
>
<
NoticeIcon
className
=
{
styles
.
action
}
count
=
{
currentUser
.
notifyCount
}
onItemClick
=
{(
item
,
tabProps
)
=>
{
console
.
log
(
item
,
tabProps
);
// eslint-disable-line
}}
onClear
=
{
onNoticeClear
}
onPopupVisibleChange
=
{
onNoticeVisibleChange
}
loading
=
{
fetchingNotices
}
popupAlign
=
{{
offset
:
[
20
,
-
16
]
}}
>
<
NoticeIcon
.
Tab
list
=
{
noticeData
[
'
通知
'
]}
title
=
"
通知
"
emptyText
=
"
你已查看所有通知
"
emptyImage
=
"
https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg
"
/>
<
NoticeIcon
.
Tab
list
=
{
noticeData
[
'
消息
'
]}
title
=
"
消息
"
emptyText
=
"
您已读完所有消息
"
emptyImage
=
"
https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg
"
/>
<
NoticeIcon
.
Tab
list
=
{
noticeData
[
'
待办
'
]}
title
=
"
待办
"
emptyText
=
"
你已完成所有待办
"
emptyImage
=
"
https://gw.alipayobjects.com/zos/rmsportal/HsIsxMZiWKrNUavQUXqx.svg
"
/>
<
/NoticeIcon
>
{
currentUser
.
name
?
(
<
Dropdown
overlay
=
{
menu
}
>
<
span
className
=
{
`
${
styles
.
action
}
${
styles
.
account
}
`
}
>
<
Avatar
size
=
"
small
"
className
=
{
styles
.
avatar
}
src
=
{
currentUser
.
avatar
}
/
>
<
span
className
=
{
styles
.
name
}
>
{
currentUser
.
name
}
<
/span
>
<
/span
>
<
/Dropdown
>
)
:
<
Spin
size
=
"
small
"
style
=
{{
marginLeft
:
8
}}
/>
}
<
/div
>
<
RightContent
{...
this
.
props
}
/
>
<
/div
>
);
}
...
...
src/components/GlobalHeader/index.less
View file @
b021ef4d
@import
"~antd/lib/style/themes/default.less"
;
@import
'~antd/lib/style/themes/default.less'
;
.header {
height: 64px;
padding: 0 12px 0 0;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
box-shadow: 0 1px 4px rgba(0, 21, 41,
0
.08);
position: relative;
}
...
...
@@ -42,7 +42,7 @@ i.trigger {
font-size: 20px;
line-height: 64px;
cursor: pointer;
transition: all .3s, padding 0s;
transition: all
0
.3s, padding 0s;
padding: 0 24px;
&:hover {
background: @primary-1;
...
...
@@ -56,7 +56,7 @@ i.trigger {
cursor: pointer;
padding: 0 12px;
display: inline-block;
transition: all .3s;
transition: all
0
.3s;
height: 100%;
> i {
font-size: 16px;
...
...
@@ -69,8 +69,7 @@ i.trigger {
}
}
.search {
padding: 0;
margin: 0 12px;
padding: 0 12px;
&:hover {
background: transparent;
}
...
...
@@ -79,12 +78,29 @@ i.trigger {
.avatar {
margin: 20px 8px 20px 0;
color: @primary-color;
background: rgba(255, 255, 255, .85);
background: rgba(255, 255, 255,
0
.85);
vertical-align: middle;
}
}
}
.white {
height: 64px;
.action {
color: rgba(255, 255, 255, 0.85);
> i {
color: rgba(255, 255, 255, 0.85);
}
&:hover,
&:global(.ant-popover-open) {
background: @primary-color;
}
:global(.ant-badge) {
color: rgba(255, 255, 255, 0.85);
}
}
}
@media only screen and (max-width: @screen-md) {
.header {
:global(.ant-divider-vertical) {
...
...
src/components/SiderMenu/BaseMeun.js
0 → 100644
View file @
b021ef4d
import
React
,
{
PureComponent
}
from
'
react
'
;
import
{
Menu
,
Icon
}
from
'
antd
'
;
import
{
Link
}
from
'
dva/router
'
;
import
pathToRegexp
from
'
path-to-regexp
'
;
import
{
urlToList
}
from
'
../utils/pathTools
'
;
import
styles
from
'
./index.less
'
;
const
{
SubMenu
}
=
Menu
;
// Allow menu.js config icon as string or ReactNode
// icon: 'setting',
// icon: 'http://demo.com/icon.png',
// icon: <Icon type="setting" />,
const
getIcon
=
(
icon
)
=>
{
if
(
typeof
icon
===
'
string
'
&&
icon
.
indexOf
(
'
http
'
)
===
0
)
{
return
<
img
src
=
{
icon
}
alt
=
"
icon
"
className
=
{
styles
.
icon
}
/>
;
}
if
(
typeof
icon
===
'
string
'
)
{
return
<
Icon
type
=
{
icon
}
/>
;
}
return
icon
;
};
export
const
getMeunMatcheys
=
(
flatMenuKeys
,
path
)
=>
{
return
flatMenuKeys
.
filter
((
item
)
=>
{
return
pathToRegexp
(
item
).
test
(
path
);
});
};
export
default
class
BaseMeun
extends
PureComponent
{
constructor
(
props
)
{
super
(
props
);
this
.
menus
=
props
.
menuData
;
this
.
flatMenuKeys
=
this
.
getFlatMenuKeys
(
props
.
menuData
);
}
/**
* Recursively flatten the data
* [{path:string},{path:string}] => {path,path2}
* @param menus
*/
getFlatMenuKeys
(
menus
)
{
let
keys
=
[];
menus
.
forEach
((
item
)
=>
{
if
(
item
.
children
)
{
keys
=
keys
.
concat
(
this
.
getFlatMenuKeys
(
item
.
children
));
}
keys
.
push
(
item
.
path
);
});
return
keys
;
}
/**
* 获得菜单子节点
* @memberof SiderMenu
*/
getNavMenuItems
=
(
menusData
)
=>
{
if
(
!
menusData
)
{
return
[];
}
return
menusData
.
filter
(
item
=>
item
.
name
&&
!
item
.
hideInMenu
)
.
map
((
item
)
=>
{
// make dom
const
ItemDom
=
this
.
getSubMenuOrItem
(
item
);
return
this
.
checkPermissionItem
(
item
.
authority
,
ItemDom
);
})
.
filter
(
item
=>
item
);
};
// Get the currently selected menu
getSelectedMenuKeys
=
()
=>
{
const
{
location
:
{
pathname
}
}
=
this
.
props
;
return
urlToList
(
pathname
).
map
(
itemPath
=>
getMeunMatcheys
(
this
.
flatMenuKeys
,
itemPath
).
pop
(),
);
};
/**
* get SubMenu or Item
*/
getSubMenuOrItem
=
(
item
)
=>
{
if
(
item
.
children
&&
item
.
children
.
some
(
child
=>
child
.
name
))
{
return
(
<
SubMenu
title
=
{
item
.
icon
?
(
<
span
>
{
getIcon
(
item
.
icon
)}
<
span
>
{
item
.
name
}
<
/span
>
<
/span
>
)
:
(
item
.
name
)
}
key
=
{
item
.
path
}
>
{
this
.
getNavMenuItems
(
item
.
children
)}
<
/SubMenu
>
);
}
else
{
return
(
<
Menu
.
Item
key
=
{
item
.
path
}
>
{
this
.
getMenuItemPath
(
item
)}
<
/Menu.Item
>
);
}
};
/**
* 判断是否是http链接.返回 Link 或 a
* Judge whether it is http link.return a or Link
* @memberof SiderMenu
*/
getMenuItemPath
=
(
item
)
=>
{
const
itemPath
=
this
.
conversionPath
(
item
.
path
);
const
icon
=
getIcon
(
item
.
icon
);
const
{
target
,
name
}
=
item
;
// Is it a http link
if
(
/^https
?
:
\/\/
/
.
test
(
itemPath
))
{
return
(
<
a
href
=
{
itemPath
}
target
=
{
target
}
>
{
icon
}
<
span
>
{
name
}
<
/span
>
<
/a
>
);
}
return
(
<
Link
to
=
{
itemPath
}
target
=
{
target
}
replace
=
{
itemPath
===
this
.
props
.
location
.
pathname
}
onClick
=
{
this
.
props
.
isMobile
?
()
=>
{
this
.
props
.
onCollapse
(
true
);
}
:
undefined
}
>
{
icon
}
<
span
>
{
name
}
<
/span
>
<
/Link
>
);
};
// permission to check
checkPermissionItem
=
(
authority
,
ItemDom
)
=>
{
if
(
this
.
props
.
Authorized
&&
this
.
props
.
Authorized
.
check
)
{
const
{
check
}
=
this
.
props
.
Authorized
;
return
check
(
authority
,
ItemDom
);
}
return
ItemDom
;
};
conversionPath
=
(
path
)
=>
{
if
(
path
&&
path
.
indexOf
(
'
http
'
)
===
0
)
{
return
path
;
}
else
{
return
`/
${
path
||
''
}
`
.
replace
(
/
\/
+/g
,
'
/
'
);
}
};
render
()
{
const
{
openKeys
}
=
this
.
props
;
// if pathname can't match, use the nearest parent's key
let
selectedKeys
=
this
.
getSelectedMenuKeys
();
if
(
!
selectedKeys
.
length
&&
openKeys
)
{
selectedKeys
=
[
openKeys
[
openKeys
.
length
-
1
]];
}
return
(
<
Menu
key
=
"
Menu
"
theme
=
"
dark
"
mode
=
"
inline
"
onOpenChange
=
{
this
.
props
.
handleOpenChange
}
selectedKeys
=
{
selectedKeys
}
style
=
{
this
.
props
.
style
}
{...
this
.
props
}
>
{
this
.
getNavMenuItems
(
this
.
menus
)}
<
/Menu
>
);
}
}
src/components/SiderMenu/SiderMenu.js
View file @
b021ef4d
import
React
,
{
PureComponent
}
from
'
react
'
;
import
{
Layout
,
Menu
,
Icon
}
from
'
antd
'
;
import
pathToRegexp
from
'
path-to-regexp
'
;
import
{
Layout
}
from
'
antd
'
;
import
{
Link
}
from
'
dva/router
'
;
import
styles
from
'
./index.less
'
;
import
BaseMeun
,
{
getMeunMatcheys
}
from
'
./BaseMeun
'
;
import
{
urlToList
}
from
'
../utils/pathTools
'
;
const
{
Sider
}
=
Layout
;
const
{
SubMenu
}
=
Menu
;
// Allow menu.js config icon as string or ReactNode
// icon: 'setting',
// icon: 'http://demo.com/icon.png',
// icon: <Icon type="setting" />,
const
getIcon
=
(
icon
)
=>
{
if
(
typeof
icon
===
'
string
'
&&
icon
.
indexOf
(
'
http
'
)
===
0
)
{
return
<
img
src
=
{
icon
}
alt
=
"
icon
"
className
=
{
styles
.
icon
}
/>
;
}
if
(
typeof
icon
===
'
string
'
)
{
return
<
Icon
type
=
{
icon
}
/>
;
}
return
icon
;
};
export
const
getMeunMatcheys
=
(
flatMenuKeys
,
path
)
=>
{
return
flatMenuKeys
.
filter
((
item
)
=>
{
return
pathToRegexp
(
item
).
test
(
path
);
});
};
const
{
Sider
}
=
Layout
;
export
default
class
SiderMenu
extends
PureComponent
{
constructor
(
props
)
{
...
...
@@ -44,19 +24,6 @@ export default class SiderMenu extends PureComponent {
});
}
}
/**
* Convert pathname to openKeys
* /list/search/articles = > ['list','/list/search']
* @param props
*/
getDefaultCollapsedSubMenus
(
props
)
{
const
{
location
:
{
pathname
}
}
=
props
||
this
.
props
;
return
urlToList
(
pathname
)
.
map
((
item
)
=>
{
return
getMeunMatcheys
(
this
.
flatMenuKeys
,
item
)[
0
];
})
.
filter
(
item
=>
item
);
}
/**
* Recursively flatten the data
* [{path:string},{path:string}] => {path,path2}
...
...
@@ -73,115 +40,17 @@ export default class SiderMenu extends PureComponent {
return
keys
;
}
/**
* 判断是否是http链接.返回 Link 或 a
* Judge whether it is http link.return a or Link
* @memberof SiderMenu
*/
getMenuItemPath
=
(
item
)
=>
{
const
itemPath
=
this
.
conversionPath
(
item
.
path
);
const
icon
=
getIcon
(
item
.
icon
);
const
{
target
,
name
}
=
item
;
// Is it a http link
if
(
/^https
?
:
\/\/
/
.
test
(
itemPath
))
{
return
(
<
a
href
=
{
itemPath
}
target
=
{
target
}
>
{
icon
}
<
span
>
{
name
}
<
/span
>
<
/a
>
);
}
return
(
<
Link
to
=
{
itemPath
}
target
=
{
target
}
replace
=
{
itemPath
===
this
.
props
.
location
.
pathname
}
onClick
=
{
this
.
props
.
isMobile
?
()
=>
{
this
.
props
.
onCollapse
(
true
);
}
:
undefined
}
>
{
icon
}
<
span
>
{
name
}
<
/span
>
<
/Link
>
);
};
/**
* get SubMenu or Item
*/
getSubMenuOrItem
=
(
item
)
=>
{
if
(
item
.
children
&&
item
.
children
.
some
(
child
=>
child
.
name
))
{
return
(
<
SubMenu
title
=
{
item
.
icon
?
(
<
span
>
{
getIcon
(
item
.
icon
)}
<
span
>
{
item
.
name
}
<
/span
>
<
/span
>
)
:
(
item
.
name
)
}
key
=
{
item
.
path
}
>
{
this
.
getNavMenuItems
(
item
.
children
)}
<
/SubMenu
>
);
}
else
{
return
(
<
Menu
.
Item
key
=
{
item
.
path
}
>
{
this
.
getMenuItemPath
(
item
)}
<
/Menu.Item
>
);
}
};
/**
* 获得菜单子节点
* @memberof SiderMenu
* Convert pathname to openKeys
* /list/search/articles = > ['list','/list/search']
* @param props
*/
getNavMenuItems
=
(
menusData
)
=>
{
if
(
!
menusData
)
{
return
[];
}
return
menusData
.
filter
(
item
=>
item
.
name
&&
!
item
.
hideInMenu
)
getDefaultCollapsedSubMenus
(
props
)
{
const
{
location
:
{
pathname
}
}
=
props
||
this
.
props
;
return
urlToList
(
pathname
)
.
map
((
item
)
=>
{
// make dom
const
ItemDom
=
this
.
getSubMenuOrItem
(
item
);
return
this
.
checkPermissionItem
(
item
.
authority
,
ItemDom
);
return
getMeunMatcheys
(
this
.
flatMenuKeys
,
item
)[
0
];
})
.
filter
(
item
=>
item
);
};
// Get the currently selected menu
getSelectedMenuKeys
=
()
=>
{
const
{
location
:
{
pathname
}
}
=
this
.
props
;
return
urlToList
(
pathname
).
map
(
itemPath
=>
getMeunMatcheys
(
this
.
flatMenuKeys
,
itemPath
).
pop
(),
);
};
// conversion Path
// 转化路径
conversionPath
=
(
path
)
=>
{
if
(
path
&&
path
.
indexOf
(
'
http
'
)
===
0
)
{
return
path
;
}
else
{
return
`/
${
path
||
''
}
`
.
replace
(
/
\/
+/g
,
'
/
'
);
}
};
// permission to check
checkPermissionItem
=
(
authority
,
ItemDom
)
=>
{
if
(
this
.
props
.
Authorized
&&
this
.
props
.
Authorized
.
check
)
{
const
{
check
}
=
this
.
props
.
Authorized
;
return
check
(
authority
,
ItemDom
);
}
return
ItemDom
;
};
isMainMenu
=
(
key
)
=>
{
return
this
.
menus
.
some
(
item
=>
key
&&
(
item
.
key
===
key
||
item
.
path
===
key
),
);
}
handleOpenChange
=
(
openKeys
)
=>
{
const
lastOpenKey
=
openKeys
[
openKeys
.
length
-
1
];
...
...
@@ -193,17 +62,6 @@ export default class SiderMenu extends PureComponent {
render
()
{
const
{
logo
,
collapsed
,
onCollapse
}
=
this
.
props
;
const
{
openKeys
}
=
this
.
state
;
// Don't show popup menu when it is been collapsed
const
menuProps
=
collapsed
?
{}
:
{
openKeys
,
};
// if pathname can't match, use the nearest parent's key
let
selectedKeys
=
this
.
getSelectedMenuKeys
();
if
(
!
selectedKeys
.
length
)
{
selectedKeys
=
[
openKeys
[
openKeys
.
length
-
1
]];
}
return
(
<
Sider
trigger
=
{
null
}
...
...
@@ -220,17 +78,16 @@ export default class SiderMenu extends PureComponent {
<
h1
>
Ant
Design
Pro
<
/h1
>
<
/Link
>
<
/div
>
<
Menu
<
BaseMeun
{...
this
.
props
}
key
=
"
Menu
"
theme
=
"
dark
"
mode
=
"
inline
"
{...
menuProps
}
handleOpenChange
=
{
this
.
handleOpenChange
}
openKeys
=
{
collapsed
?
[]
:
openKeys
}
onOpenChange
=
{
this
.
handleOpenChange
}
selectedKeys
=
{
selectedKeys
}
style
=
{{
padding
:
'
16px 0
'
,
width
:
'
100%
'
}}
>
{
this
.
getNavMenuItems
(
this
.
menus
)}
<
/Menu
>
/
>
<
/Sider
>
);
}
...
...
src/components/SiderMenu/SilderMenu.test.js
View file @
b021ef4d
import
{
getMeunMatcheys
}
from
'
./
SiderMenu
'
;
import
{
getMeunMatcheys
}
from
'
./
BaseMeun
'
;
const
meun
=
[
'
/dashboard
'
,
...
...
src/components/TopNavHeader/index.js
0 → 100644
View file @
b021ef4d
import
React
,
{
PureComponent
}
from
'
react
'
;
import
{
Link
}
from
'
dva/router
'
;
import
RightContent
from
'
../GlobalHeader/RightContent
'
;
import
BaseMeun
from
'
../SiderMenu/BaseMeun
'
;
import
styles
from
'
./index.less
'
;
export
default
class
TopNavHeader
extends
PureComponent
{
render
()
{
return
(
<
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
>
<
BaseMeun
{...
this
.
props
}
style
=
{{
padding
:
'
9px 0
'
}}
/
>
<
/div
>
<
div
className
=
{
styles
.
right
}
>
<
RightContent
theme
=
"
white
"
{...
this
.
props
}
/
>
<
/div
>
<
/div
>
);
}
}
src/components/TopNavHeader/index.less
0 → 100644
View file @
b021ef4d
.main {
display: flex;
height: 64px;
margin: auto;
max-width: 1200px;
.left {
flex: 1;
display: flex;
.logo {
width: 160px;
height: 64px;
position: relative;
line-height: 64px;
transition: all 0.3s;
overflow: hidden;
img {
display: inline-block;
vertical-align: middle;
height: 32px;
}
h1 {
color: #fff;
display: inline-block;
vertical-align: middle;
font-size: 16px;
margin: 0 0 0 12px;
font-weight: 400;
}
}
}
}
src/layouts/BasicLayout.js
View file @
b021ef4d
...
...
@@ -9,6 +9,7 @@ import classNames from 'classnames';
import
{
enquireScreen
}
from
'
enquire-js
'
;
import
GlobalHeader
from
'
../components/GlobalHeader
'
;
import
GlobalFooter
from
'
../components/GlobalFooter
'
;
import
TopNavHeader
from
'
../components/TopNavHeader
'
;
import
SiderMenu
from
'
../components/SiderMenu
'
;
import
NotFound
from
'
../routes/Exception/404
'
;
import
{
getRoutes
}
from
'
../utils/utils
'
;
...
...
@@ -153,26 +154,45 @@ class BasicLayout extends React.PureComponent {
}
}
render
()
{
const
isFluid
=
this
.
props
.
layout
===
'
fluid
'
;
const
{
currentUser
,
collapsed
,
fetchingNotices
,
notices
,
routerData
,
match
,
location
,
}
=
this
.
props
;
const
bashRedirect
=
this
.
getBashRedirect
();
const
layout
=
(
<
Layout
>
<
SiderMenu
logo
=
{
logo
}
{
isFluid
&&
!
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
}
onCollapse
=
{
this
.
handleMenuCollapse
}
/
>
Authorized
=
{
Authorized
}
menuData
=
{
getMenuData
()}
collapsed
=
{
collapsed
}
location
=
{
location
}
isMobile
=
{
this
.
state
.
isMobile
}
onCollapse
=
{
this
.
handleMenuCollapse
}
/
>
)}
<
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
}
...
...
@@ -185,6 +205,7 @@ class BasicLayout extends React.PureComponent {
onMenuClick
=
{
this
.
handleMenuClick
}
onNoticeVisibleChange
=
{
this
.
handleNoticeVisibleChange
}
/
>
)}
<
/Header
>
<
Content
style
=
{{
margin
:
'
24px 24px 0
'
,
height
:
'
100%
'
}}
>
<
Switch
>
...
...
@@ -253,6 +274,7 @@ class BasicLayout extends React.PureComponent {
export
default
connect
(({
user
,
global
,
loading
})
=>
({
currentUser
:
user
.
currentUser
,
collapsed
:
global
.
collapsed
,
layout
:
global
.
layout
,
fetchingNotices
:
loading
.
effects
[
'
global/fetchNotices
'
],
notices
:
global
.
notices
,
}))(
BasicLayout
);
src/layouts/GridContent.js
0 → 100644
View file @
b021ef4d
import
React
,
{
PureComponent
}
from
'
react
'
;
import
{
connect
}
from
'
dva
'
;
import
styles
from
'
./GridContent.less
'
;
class
GridContent
extends
PureComponent
{
render
()
{
let
className
=
`
${
styles
.
main
}
`
;
if
(
this
.
props
.
layout
===
'
fluid
'
)
{
className
=
`
${
styles
.
main
}
${
styles
.
fluid
}
`
;
}
return
<
div
className
=
{
className
}
>
{
this
.
props
.
children
}
<
/div>
;
}
}
export
default
connect
(({
global
})
=>
({
layout
:
global
.
layout
,
}))(
GridContent
);
src/layouts/GridContent.less
0 → 100644
View file @
b021ef4d
.main {
width: 100%;
height: 100%;
min-height: 100%;
&.fluid {
max-width: 1200px;
margin: 0 auto;
}
}
src/layouts/PageHeaderLayout.js
View file @
b021ef4d
import
React
from
'
react
'
;
import
{
Link
}
from
'
dva/router
'
;
import
PageHeader
from
'
../components/PageHeader
'
;
import
GridContent
from
'
./GridContent
'
;
import
styles
from
'
./PageHeaderLayout.less
'
;
export
default
({
children
,
wrapperClassName
,
top
,
...
restProps
})
=>
(
<
div
style
=
{{
margin
:
'
-24px -24px 0
'
}}
className
=
{
wrapperClassName
}
>
{
top
}
<
PageHeader
key
=
"
pageheader
"
{...
restProps
}
linkElement
=
{
Link
}
/
>
{
children
?
<
div
className
=
{
styles
.
content
}
>
{
children
}
<
/div> : null
}
{
children
?
(
<
div
className
=
{
styles
.
content
}
>
<
GridContent
>
{
children
}
<
/GridContent
>
<
/div
>
)
:
null
}
<
/div
>
);
src/layouts/PageHeaderLayout.less
View file @
b021ef4d
@import
"~antd/lib/style/themes/default.less"
;
@import
'~antd/lib/style/themes/default.less'
;
.content {
margin: 24px 24px 0;
...
...
src/models/global.js
View file @
b021ef4d
...
...
@@ -5,6 +5,7 @@ export default {
state
:
{
collapsed
:
false
,
layout
:
'
fluid
'
,
notices
:
[],
},
...
...
@@ -40,6 +41,12 @@ export default {
collapsed
:
payload
,
};
},
changeLayout
(
state
,
{
payload
})
{
return
{
...
state
,
layout
:
payload
,
};
},
saveNotices
(
state
,
{
payload
})
{
return
{
...
state
,
...
...
src/routes/Dashboard/Analysis.js
View file @
b021ef4d
import
React
,
{
Component
,
Fragment
}
from
'
react
'
;
import
React
,
{
Component
}
from
'
react
'
;
import
{
connect
}
from
'
dva
'
;
import
{
Row
,
...
...
@@ -14,6 +14,7 @@ import {
Dropdown
,
}
from
'
antd
'
;
import
numeral
from
'
numeral
'
;
import
GridContent
from
'
../../layouts/GridContent
'
;
import
{
ChartCard
,
yuan
,
...
...
@@ -241,7 +242,7 @@ export default class Analysis extends Component {
};
return
(
<
Fragm
ent
>
<
GridCont
ent
>
<
Row
gutter
=
{
24
}
>
<
Col
{...
topColResponsiveProps
}
>
<
ChartCard
...
...
@@ -482,7 +483,7 @@ export default class Analysis extends Component {
))}
<
/Tabs
>
<
/Card
>
<
/
Fragm
ent
>
<
/
GridCont
ent
>
);
}
}
src/routes/Dashboard/Monitor.js
View file @
b021ef4d
import
React
,
{
PureComponent
,
Fragment
}
from
'
react
'
;
import
React
,
{
PureComponent
}
from
'
react
'
;
import
{
connect
}
from
'
dva
'
;
import
{
Row
,
Col
,
Card
,
Tooltip
}
from
'
antd
'
;
import
numeral
from
'
numeral
'
;
import
GridContent
from
'
../../layouts/GridContent
'
;
import
Authorized
from
'
../../utils/Authorized
'
;
import
{
Pie
,
WaterWave
,
Gauge
,
TagCloud
}
from
'
../../components/Charts
'
;
import
NumberInfo
from
'
../../components/NumberInfo
'
;
...
...
@@ -35,7 +36,7 @@ export default class Monitor extends PureComponent {
const
{
tags
}
=
monitor
;
return
(
<
Fragm
ent
>
<
GridCont
ent
>
<
Row
gutter
=
{
24
}
>
<
Col
xl
=
{
18
}
lg
=
{
24
}
md
=
{
24
}
sm
=
{
24
}
xs
=
{
24
}
style
=
{{
marginBottom
:
24
}}
>
<
Card
title
=
"
活动实时交易情况
"
bordered
=
{
false
}
>
...
...
@@ -164,7 +165,7 @@ export default class Monitor extends PureComponent {
<
/Card
>
<
/Col
>
<
/Row
>
<
/
Fragm
ent
>
<
/
GridCont
ent
>
);
}
}
src/routes/UserProfile/UserCenter.js
View file @
b021ef4d
...
...
@@ -3,14 +3,28 @@ import { connect } from 'dva';
import
{
Link
}
from
'
dva/router
'
;
import
moment
from
'
moment
'
;
import
numeral
from
'
numeral
'
;
import
{
List
,
Card
,
Row
,
Col
,
Icon
,
Dropdown
,
Menu
,
Avatar
,
Tag
,
Divider
,
Tooltip
,
Spin
,
Input
}
from
'
antd
'
;
import
{
List
,
Card
,
Row
,
Col
,
Icon
,
Dropdown
,
Menu
,
Avatar
,
Tag
,
Divider
,
Tooltip
,
Spin
,
Input
,
}
from
'
antd
'
;
import
AvatarList
from
'
../../components/AvatarList
'
;
import
{
formatWan
}
from
'
../../utils/utils
'
;
import
styles
from
'
./UserCenter.less
'
;
import
stylesArticles
from
'
../List/Articles.less
'
;
import
stylesApplications
from
'
../List/Applications.less
'
;
import
stylesProjects
from
'
../List/Projects.less
'
;
import
stylesArticles
from
'
./List/Articles.less
'
;
import
stylesApplications
from
'
./List/Applications.less
'
;
import
GridContent
from
'
../layouts/GridContent
'
;
@
connect
(({
list
,
loading
,
user
,
project
})
=>
({
list
,
...
...
@@ -26,7 +40,7 @@ export default class UserCenter extends PureComponent {
newTags
:
[],
inputVisible
:
false
,
inputValue
:
''
,
}
}
;
componentDidMount
()
{
const
{
dispatch
}
=
this
.
props
;
...
...
@@ -46,33 +60,39 @@ export default class UserCenter extends PureComponent {
onTabChange
=
(
key
)
=>
{
this
.
setState
({
key
});
}
}
;
showInput
=
()
=>
{
this
.
setState
({
inputVisible
:
true
},
()
=>
this
.
input
.
focus
());
}
}
;
saveInputRef
=
(
input
)
=>
{
this
.
input
=
input
;
}
}
;
handleInputChange
=
(
e
)
=>
{
this
.
setState
({
inputValue
:
e
.
target
.
value
});
}
}
;
handleInputConfirm
=
()
=>
{
const
{
state
}
=
this
;
const
{
inputValue
}
=
state
;
let
{
newTags
}
=
state
;
if
(
inputValue
&&
newTags
.
filter
(
tag
=>
tag
.
label
===
inputValue
).
length
===
0
)
{
newTags
=
[...
newTags
,
{
key
:
`new-
${
newTags
.
length
}
`
,
label
:
inputValue
}];
if
(
inputValue
&&
newTags
.
filter
(
tag
=>
tag
.
label
===
inputValue
).
length
===
0
)
{
newTags
=
[
...
newTags
,
{
key
:
`new-
${
newTags
.
length
}
`
,
label
:
inputValue
},
];
}
this
.
setState
({
newTags
,
inputVisible
:
false
,
inputValue
:
''
,
});
}
}
;
renderArticles
=
(
list
,
loading
)
=>
{
const
IconText
=
({
type
,
text
})
=>
(
...
...
@@ -81,11 +101,14 @@ export default class UserCenter extends PureComponent {
{
text
}
<
/span
>
);
const
ListContent
=
({
data
:
{
content
,
updatedAt
,
avatar
,
owner
,
href
}
})
=>
(
const
ListContent
=
({
data
:
{
content
,
updatedAt
,
avatar
,
owner
,
href
},
})
=>
(
<
div
className
=
{
stylesArticles
.
listContent
}
>
<
div
className
=
{
stylesArticles
.
description
}
>
{
content
}
<
/div
>
<
div
className
=
{
stylesArticles
.
extra
}
>
<
Avatar
src
=
{
avatar
}
size
=
"
small
"
/><
a
href
=
{
href
}
>
{
owner
}
<
/a> 发布在 <a href={href}>{href}</
a
>
<
Avatar
src
=
{
avatar
}
size
=
"
small
"
/>
<
a
href
=
{
href
}
>
{
owner
}
<
/a> 发布在 <a href={href}>{href}</
a
>
<
em
>
{
moment
(
updatedAt
).
format
(
'
YYYY-MM-DD HH:mm
'
)}
<
/em
>
<
/div
>
<
/div
>
...
...
@@ -108,9 +131,14 @@ export default class UserCenter extends PureComponent {
]}
>
<
List
.
Item
.
Meta
title
=
{(
<
a
className
=
{
stylesArticles
.
listItemMetaTitle
}
href
=
{
item
.
href
}
>
{
item
.
title
}
<
/a
>
)}
title
=
{
<
a
className
=
{
stylesArticles
.
listItemMetaTitle
}
href
=
{
item
.
href
}
>
{
item
.
title
}
<
/a
>
}
description
=
{
<
span
>
<
Tag
>
Ant
Design
<
/Tag
>
...
...
@@ -124,19 +152,37 @@ export default class UserCenter extends PureComponent {
)}
/
>
);
}
}
;
renderApplications
=
(
list
,
loading
)
=>
{
const
itemMenu
=
(
<
Menu
>
<
Menu
.
Item
>
<
a
target
=
"
_blank
"
rel
=
"
noopener noreferrer
"
href
=
"
http://www.alipay.com/
"
>
1
st
menu
item
<
/a
>
<
a
target
=
"
_blank
"
rel
=
"
noopener noreferrer
"
href
=
"
http://www.alipay.com/
"
>
1
st
menu
item
<
/a
>
<
/Menu.Item
>
<
Menu
.
Item
>
<
a
target
=
"
_blank
"
rel
=
"
noopener noreferrer
"
href
=
"
http://www.taobao.com/
"
>
2
nd
menu
item
<
/a
>
<
a
target
=
"
_blank
"
rel
=
"
noopener noreferrer
"
href
=
"
http://www.taobao.com/
"
>
2
nd
menu
item
<
/a
>
<
/Menu.Item
>
<
Menu
.
Item
>
<
a
target
=
"
_blank
"
rel
=
"
noopener noreferrer
"
href
=
"
http://www.tmall.com/
"
>
3
d
menu
item
<
/a
>
<
a
target
=
"
_blank
"
rel
=
"
noopener noreferrer
"
href
=
"
http://www.tmall.com/
"
>
3
d
menu
item
<
/a
>
<
/Menu.Item
>
<
/Menu
>
);
...
...
@@ -165,10 +211,18 @@ export default class UserCenter extends PureComponent {
hoverable
bodyStyle
=
{{
paddingBottom
:
20
}}
actions
=
{[
<
Tooltip
title
=
"
下载
"
><
Icon
type
=
"
download
"
/><
/Tooltip>
,
<
Tooltip
title
=
"
编辑
"
><
Icon
type
=
"
edit
"
/><
/Tooltip>
,
<
Tooltip
title
=
"
分享
"
><
Icon
type
=
"
share-alt
"
/><
/Tooltip>
,
<
Dropdown
overlay
=
{
itemMenu
}
><
Icon
type
=
"
ellipsis
"
/><
/Dropdown>
,
<
Tooltip
title
=
"
下载
"
>
<
Icon
type
=
"
download
"
/>
<
/Tooltip>
,
<
Tooltip
title
=
"
编辑
"
>
<
Icon
type
=
"
edit
"
/>
<
/Tooltip>
,
<
Tooltip
title
=
"
分享
"
>
<
Icon
type
=
"
share-alt
"
/>
<
/Tooltip>
,
<
Dropdown
overlay
=
{
itemMenu
}
>
<
Icon
type
=
"
ellipsis
"
/>
<
/Dropdown>
,
]}
>
<
Card
.
Meta
...
...
@@ -186,7 +240,7 @@ export default class UserCenter extends PureComponent {
)}
/
>
);
}
}
;
renderProjects
=
(
list
,
loading
)
=>
{
return
(
...
...
@@ -211,15 +265,13 @@ export default class UserCenter extends PureComponent {
<
span
>
{
moment
(
item
.
updatedAt
).
fromNow
()}
<
/span
>
<
div
className
=
{
stylesProjects
.
avatarList
}
>
<
AvatarList
size
=
"
mini
"
>
{
item
.
members
.
map
(
member
=>
(
<
AvatarList
.
Item
key
=
{
`
${
item
.
id
}
-avatar-
${
member
.
id
}
`
}
src
=
{
member
.
avatar
}
tips
=
{
member
.
name
}
/
>
))
}
{
item
.
members
.
map
(
member
=>
(
<
AvatarList
.
Item
key
=
{
`
${
item
.
id
}
-avatar-
${
member
.
id
}
`
}
src
=
{
member
.
avatar
}
tips
=
{
member
.
name
}
/
>
))}
<
/AvatarList
>
<
/div
>
<
/div
>
...
...
@@ -228,22 +280,137 @@ export default class UserCenter extends PureComponent {
)}
/
>
);
};
renderContent
()
{
const
{
newTags
,
inputVisible
,
inputValue
}
=
this
.
state
;
const
{
currentUser
,
project
:
{
notice
},
projectLoading
,
}
=
this
.
props
;
return
(
<
div
>
<
div
className
=
{
styles
.
avatarHolder
}
>
<
img
alt
=
""
src
=
{
currentUser
.
avatar
}
/
>
<
div
className
=
{
styles
.
name
}
>
{
currentUser
.
name
}
<
/div
>
<
div
>
{
currentUser
.
signature
}
<
/div
>
<
/div
>
<
div
className
=
{
styles
.
detail
}
>
<
p
>
<
i
className
=
{
styles
.
title
}
/
>
{
currentUser
.
title
}
<
/p
>
<
p
>
<
i
className
=
{
styles
.
group
}
/
>
{
currentUser
.
group
}
<
/p
>
<
p
>
<
i
className
=
{
styles
.
address
}
/
>
{
currentUser
.
geographic
.
province
.
label
}
{
currentUser
.
geographic
.
city
.
label
}
<
/p
>
<
/div
>
<
Divider
dashed
/>
<
div
className
=
{
styles
.
tags
}
>
<
div
className
=
{
styles
.
tagsTitle
}
>
标签
<
/div
>
{
currentUser
.
tags
.
map
(
item
=>
<
Tag
key
=
{
item
.
key
}
>
{
item
.
label
}
<
/Tag>
)
}
<
Tag
style
=
{{
background
:
'
#fff
'
,
borderStyle
:
'
dashed
'
}}
>
<
Icon
type
=
"
plus
"
/>
<
/Tag
>
<
/div
>
<
Divider
dashed
/>
<
div
className
=
{
styles
.
team
}
>
<
div
className
=
{
styles
.
teamTitle
}
>
团队
<
/div
>
<
Spin
spinning
=
{
projectLoading
}
>
<
Row
gutter
=
{
36
}
>
{
notice
.
map
(
item
=>
(
<
Col
key
=
{
item
.
id
}
className
=
{
styles
.
item
}
lg
=
{
24
}
xl
=
{
12
}
>
<
Avatar
size
=
"
small
"
src
=
{
item
.
logo
}
/
>
{
item
.
member
}
<
/Col
>
))}
<
/Row
>
<
/Spin
>
<
/div
>
<
Divider
dashed
/>
<
div
className
=
{
styles
.
tags
}
>
<
div
className
=
{
styles
.
tagsTitle
}
>
标签
<
/div
>
{
currentUser
.
tags
.
concat
(
newTags
)
.
map
(
item
=>
<
Tag
key
=
{
item
.
key
}
>
{
item
.
label
}
<
/Tag>
)
}
{
inputVisible
&&
(
<
Input
ref
=
{
this
.
saveInputRef
}
type
=
"
text
"
size
=
"
small
"
style
=
{{
width
:
78
}}
value
=
{
inputValue
}
onChange
=
{
this
.
handleInputChange
}
onBlur
=
{
this
.
handleInputConfirm
}
onPressEnter
=
{
this
.
handleInputConfirm
}
/
>
)}
{
!
inputVisible
&&
(
<
Tag
onClick
=
{
this
.
showInput
}
style
=
{{
background
:
'
#fff
'
,
borderStyle
:
'
dashed
'
}}
>
<
Icon
type
=
"
plus
"
/>
<
/Tag
>
)}
<
/div
>
<
Divider
style
=
{{
marginTop
:
16
}}
dashed
/>
<
div
className
=
{
styles
.
team
}
>
<
div
className
=
{
styles
.
teamTitle
}
>
团队
<
/div
>
<
Spin
spinning
=
{
projectLoading
}
>
<
Row
gutter
=
{
36
}
>
{
notice
.
map
(
item
=>
(
<
Col
key
=
{
item
.
id
}
lg
=
{
24
}
xl
=
{
12
}
>
<
Link
to
=
{
item
.
href
}
>
<
Avatar
size
=
"
small
"
src
=
{
item
.
logo
}
/
>
{
item
.
member
}
<
/Link
>
<
/Col
>
))}
<
/Row
>
<
/Spin
>
<
/div
>
<
/div
>
);
}
render
()
{
const
{
key
,
newTags
,
inputVisible
,
inputValue
}
=
this
.
state
;
const
{
list
:
{
list
},
listLoading
,
currentUser
,
currentUserLoading
,
project
:
{
notice
},
projectLoading
}
=
this
.
props
;
const
operationTabList
=
[{
key
:
'
article
'
,
tab
:
<
span
>
文章
<
span
style
=
{{
fontSize
:
14
}}
>
(
8
)
<
/span></
span
>
,
},
{
key
:
'
application
'
,
tab
:
<
span
>
应用
<
span
style
=
{{
fontSize
:
14
}}
>
(
8
)
<
/span></
span
>
,
},
{
key
:
'
project
'
,
tab
:
<
span
>
项目
<
span
style
=
{{
fontSize
:
14
}}
>
(
8
)
<
/span></
span
>
,
}];
const
{
list
:
{
list
},
listLoading
,
currentUser
,
currentUserLoading
,
}
=
this
.
props
;
const
operationTabList
=
[
{
key
:
'
article
'
,
tab
:
(
<
span
>
文章
<
span
style
=
{{
fontSize
:
14
}}
>
(
8
)
<
/span
>
<
/span
>
),
},
{
key
:
'
application
'
,
tab
:
(
<
span
>
应用
<
span
style
=
{{
fontSize
:
14
}}
>
(
8
)
<
/span
>
<
/span
>
),
},
{
key
:
'
project
'
,
tab
:
(
<
span
>
项目
<
span
style
=
{{
fontSize
:
14
}}
>
(
8
)
<
/span
>
<
/span
>
),
},
];
const
contentMap
=
{
article
:
this
.
renderArticles
(
list
,
listLoading
),
application
:
this
.
renderApplications
(
list
,
listLoading
),
...
...
@@ -251,94 +418,33 @@ export default class UserCenter extends PureComponent {
};
return
(
<
div
className
=
{
styles
.
userCenter
}
>
<
Row
gutter
=
{
24
}
>
<
Col
lg
=
{
7
}
md
=
{
24
}
>
<
Card
bordered
=
{
false
}
style
=
{{
marginBottom
:
24
}}
loading
=
{
currentUserLoading
}
>
{
currentUser
&&
Object
.
keys
(
currentUser
).
length
?
(
<
div
>
<
div
className
=
{
styles
.
avatarHolder
}
>
<
img
alt
=
""
src
=
{
currentUser
.
avatar
}
/
>
<
div
className
=
{
styles
.
name
}
>
{
currentUser
.
name
}
<
/div
>
<
div
>
{
currentUser
.
signature
}
<
/div
>
<
/div
>
<
div
className
=
{
styles
.
detail
}
>
<
p
><
i
className
=
{
styles
.
title
}
/>{currentUser.title}</
p
>
<
p
><
i
className
=
{
styles
.
group
}
/>{currentUser.group}</
p
>
<
p
><
i
className
=
{
styles
.
address
}
/
>
{
currentUser
.
geographic
.
province
.
label
}
{
currentUser
.
geographic
.
city
.
label
}
<
/p
>
<
/div
>
<
Divider
dashed
/>
<
div
className
=
{
styles
.
tags
}
>
<
div
className
=
{
styles
.
tagsTitle
}
>
标签
<
/div
>
{
currentUser
.
tags
.
concat
(
newTags
).
map
(
item
=>
<
Tag
key
=
{
item
.
key
}
>
{
item
.
label
}
<
/Tag>
)
}
{
inputVisible
&&
(
<
Input
ref
=
{
this
.
saveInputRef
}
type
=
"
text
"
size
=
"
small
"
style
=
{{
width
:
78
}}
value
=
{
inputValue
}
onChange
=
{
this
.
handleInputChange
}
onBlur
=
{
this
.
handleInputConfirm
}
onPressEnter
=
{
this
.
handleInputConfirm
}
/
>
)}
{
!
inputVisible
&&
(
<
Tag
onClick
=
{
this
.
showInput
}
style
=
{{
background
:
'
#fff
'
,
borderStyle
:
'
dashed
'
}}
>
<
Icon
type
=
"
plus
"
/>
<
/Tag
>
)}
<
/div
>
<
Divider
style
=
{{
marginTop
:
16
}}
dashed
/>
<
div
className
=
{
styles
.
team
}
>
<
div
className
=
{
styles
.
teamTitle
}
>
团队
<
/div
>
<
Spin
spinning
=
{
projectLoading
}
>
<
Row
gutter
=
{
36
}
>
{
notice
.
map
(
item
=>
(
<
Col
key
=
{
item
.
id
}
lg
=
{
24
}
xl
=
{
12
}
>
<
Link
to
=
{
item
.
href
}
>
<
Avatar
size
=
"
small
"
src
=
{
item
.
logo
}
/
>
{
item
.
member
}
<
/Link
>
<
/Col
>
))
}
<
/Row
>
<
/Spin
>
<
/div
>
<
/div
>
)
:
'
loading...
'
}
<
/Card
>
<
/Col
>
<
Col
lg
=
{
17
}
md
=
{
24
}
>
<
Card
className
=
{
styles
.
tabsCard
}
bordered
=
{
false
}
tabList
=
{
operationTabList
}
onTabChange
=
{
this
.
onTabChange
}
>
{
contentMap
[
key
]}
<
/Card
>
<
/Col
>
<
/Row
>
<
/div
>
<
GridContent
>
<
div
className
=
{
styles
.
userCenter
}
>
<
Row
gutter
=
{
24
}
>
<
Col
lg
=
{
7
}
md
=
{
24
}
>
<
Card
bordered
=
{
false
}
style
=
{{
marginBottom
:
24
}}
loading
=
{
currentUserLoading
}
>
{
currentUser
&&
Object
.
keys
(
currentUser
).
length
?
this
.
renderContent
()
:
'
loading...
'
}
<
/Card
>
<
/Col
>
<
Col
lg
=
{
17
}
md
=
{
24
}
>
<
Card
className
=
{
styles
.
tabsCard
}
bordered
=
{
false
}
tabList
=
{
operationTabList
}
onTabChange
=
{
this
.
onTabChange
}
>
{
contentMap
[
this
.
state
.
key
]}
<
/Card
>
<
/Col
>
<
/Row
>
<
/div
>
<
/GridContent
>
);
}
}
src/routes/UserProfile/Userinfo/Info.js
View file @
b021ef4d
...
...
@@ -3,7 +3,8 @@ import { connect } from 'dva';
import
{
Route
,
routerRedux
,
Switch
,
Redirect
}
from
'
dva/router
'
;
import
{
Menu
}
from
'
antd
'
;
import
styles
from
'
./Info.less
'
;
import
{
getRoutes
}
from
'
../../../utils/utils
'
;
import
{
getRoutes
}
from
'
../../utils/utils
'
;
import
GridContent
from
'
../../layouts/GridContent
'
;
const
{
Item
}
=
Menu
;
...
...
@@ -71,43 +72,36 @@ export default class Info extends Component {
return
''
;
}
return
(
<
div
className
=
{
styles
.
main
}
ref
=
{(
ref
)
=>
{
this
.
main
=
ref
;
}}
>
<
div
className
=
{
styles
.
leftmenu
}
>
<
Menu
mode
=
{
this
.
state
.
mode
}
selectedKeys
=
{[
this
.
state
.
selectKey
]}
onClick
=
{
this
.
selectKey
}
>
{
this
.
getmenu
()}
<
/Menu
>
<
GridContent
>
<
div
className
=
{
styles
.
main
}
>
<
div
className
=
{
styles
.
leftmenu
}
>
<
Menu
mode
=
{
this
.
state
.
mode
}
selectedKeys
=
{[
this
.
state
.
selectKey
]}
onClick
=
{
this
.
selectKey
}
>
{
this
.
getmenu
()}
<
/Menu
>
<
/div
>
<
div
className
=
{
styles
.
right
}
>
<
div
className
=
{
styles
.
title
}
>
{
this
.
getRightTitle
()}
<
/div
>
<
Switch
>
{
getRoutes
(
match
.
path
,
routerData
).
map
(
item
=>
(
<
Route
key
=
{
item
.
key
}
path
=
{
item
.
path
}
render
=
{
props
=>
(
<
item
.
component
{...
props
}
currentUser
=
{
currentUser
}
/
>
)}
exact
=
{
item
.
exact
}
/
>
))}
<
Redirect
exact
from
=
"
/userinfo
"
to
=
"
/userinfo/base
"
/>
<
Redirect
to
=
"
/exception/404
"
/>
<
/Switch
>
<
/div
>
<
/div
>
<
div
className
=
{
styles
.
right
}
>
<
div
className
=
{
styles
.
title
}
>
{
this
.
getRightTitle
()}
<
/div
>
<
Switch
>
{
getRoutes
(
match
.
path
,
routerData
).
map
(
item
=>
(
<
Route
key
=
{
item
.
key
}
path
=
{
item
.
path
}
render
=
{
props
=>
(
<
item
.
component
{...
props
}
currentUser
=
{
currentUser
}
/
>
)}
exact
=
{
item
.
exact
}
/
>
))}
<
Redirect
exact
from
=
"
/user-profile/userinfo
"
to
=
"
/user-profile/userinfo/base
"
/>
<
Redirect
to
=
"
/exception/404
"
/>
<
/Switch
>
<
/div
>
<
/div
>
<
/GridContent
>
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment