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
3b826259
Unverified
Commit
3b826259
authored
Feb 15, 2018
by
陈帅
Committed by
GitHub
Feb 15, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add meun test and Modify part of the logic (#917)
parent
bd391d7e
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
198 additions
and
143 deletions
+198
-143
src/common/menu.js
src/common/menu.js
+1
-1
src/components/PageHeader/index.js
src/components/PageHeader/index.js
+66
-49
src/components/PageHeader/index.test.js
src/components/PageHeader/index.test.js
+5
-23
src/components/SiderMenu/SiderMenu.js
src/components/SiderMenu/SiderMenu.js
+63
-70
src/components/SiderMenu/SilderMenu.test.js
src/components/SiderMenu/SilderMenu.test.js
+36
-0
src/components/utils/pathTools.js
src/components/utils/pathTools.js
+7
-0
src/components/utils/pathTools.test.js
src/components/utils/pathTools.test.js
+20
-0
No files found.
src/common/menu.js
View file @
3b826259
...
...
@@ -115,7 +115,7 @@ const menuData = [{
}],
}];
function
formatter
(
data
,
parentPath
=
''
,
parentAuthority
)
{
function
formatter
(
data
,
parentPath
=
'
/
'
,
parentAuthority
)
{
return
data
.
map
((
item
)
=>
{
let
{
path
}
=
item
;
if
(
!
isUrl
(
path
))
{
...
...
src/components/PageHeader/index.js
View file @
3b826259
...
...
@@ -4,7 +4,7 @@ import pathToRegexp from 'path-to-regexp';
import
{
Breadcrumb
,
Tabs
}
from
'
antd
'
;
import
classNames
from
'
classnames
'
;
import
styles
from
'
./index.less
'
;
import
{
urlToList
}
from
'
../utils/pathTools
'
;
const
{
TabPane
}
=
Tabs
;
export
function
getBreadcrumb
(
breadcrumbNameMap
,
url
)
{
...
...
@@ -19,14 +19,6 @@ export function getBreadcrumb(breadcrumbNameMap, url) {
return
breadcrumb
||
{};
}
// /userinfo/2144/id => ['/userinfo','/useinfo/2144,'/userindo/2144/id']
export
function
urlToList
(
url
)
{
const
urllist
=
url
.
split
(
'
/
'
).
filter
(
i
=>
i
);
return
urllist
.
map
((
urlItem
,
index
)
=>
{
return
`/
${
urllist
.
slice
(
0
,
index
+
1
).
join
(
'
/
'
)}
`
;
});
}
export
default
class
PageHeader
extends
PureComponent
{
static
contextTypes
=
{
routes
:
PropTypes
.
array
,
...
...
@@ -44,29 +36,35 @@ export default class PageHeader extends PureComponent {
routes
:
this
.
props
.
routes
||
this
.
context
.
routes
,
params
:
this
.
props
.
params
||
this
.
context
.
params
,
routerLocation
:
this
.
props
.
location
||
this
.
context
.
location
,
breadcrumbNameMap
:
this
.
props
.
breadcrumbNameMap
||
this
.
context
.
breadcrumbNameMap
,
breadcrumbNameMap
:
this
.
props
.
breadcrumbNameMap
||
this
.
context
.
breadcrumbNameMap
,
};
};
// Generated according to props
conversionFromProps
=
()
=>
{
conversionFromProps
=
()
=>
{
const
{
breadcrumbList
,
breadcrumbSeparator
,
linkElement
=
'
a
'
,
breadcrumbList
,
breadcrumbSeparator
,
linkElement
=
'
a
'
,
}
=
this
.
props
;
return
(
<
Breadcrumb
className
=
{
styles
.
breadcrumb
}
separator
=
{
breadcrumbSeparator
}
>
<
Breadcrumb
className
=
{
styles
.
breadcrumb
}
separator
=
{
breadcrumbSeparator
}
>
{
breadcrumbList
.
map
(
item
=>
(
<
Breadcrumb
.
Item
key
=
{
item
.
title
}
>
{
item
.
href
?
(
createElement
(
linkElement
,
{
{
item
.
href
?
createElement
(
linkElement
,
{
[
linkElement
===
'
a
'
?
'
href
'
:
'
to
'
]:
item
.
href
,
},
item
.
title
))
:
item
.
title
}
},
item
.
title
,
)
:
item
.
title
}
<
/Breadcrumb.Item
>
))}
<
/Breadcrumb
>
);
}
}
;
conversionFromLocation
=
(
routerLocation
,
breadcrumbNameMap
)
=>
{
const
{
breadcrumbSeparator
,
linkElement
=
'
a
'
}
=
this
.
props
;
// Convert the url to an array
...
...
@@ -74,7 +72,8 @@ export default class PageHeader extends PureComponent {
// Loop data mosaic routing
const
extraBreadcrumbItems
=
pathSnippets
.
map
((
url
,
index
)
=>
{
const
currentBreadcrumb
=
getBreadcrumb
(
breadcrumbNameMap
,
url
);
const
isLinkable
=
(
index
!==
pathSnippets
.
length
-
1
)
&&
currentBreadcrumb
.
component
;
const
isLinkable
=
index
!==
pathSnippets
.
length
-
1
&&
currentBreadcrumb
.
component
;
return
currentBreadcrumb
.
name
&&
!
currentBreadcrumb
.
hideInBreadcrumb
?
(
<
Breadcrumb
.
Item
key
=
{
url
}
>
{
createElement
(
...
...
@@ -88,26 +87,33 @@ export default class PageHeader extends PureComponent {
// Add home breadcrumbs to your head
extraBreadcrumbItems
.
unshift
(
<
Breadcrumb
.
Item
key
=
"
home
"
>
{
createElement
(
linkElement
,
{
[
linkElement
===
'
a
'
?
'
href
'
:
'
to
'
]:
'
/
'
},
'
首页
'
)}
<
/Breadcrumb.Item
>
{
createElement
(
linkElement
,
{
[
linkElement
===
'
a
'
?
'
href
'
:
'
to
'
]:
'
/
'
,
},
'
首页
'
,
)}
<
/Breadcrumb.Item>
,
);
return
(
<
Breadcrumb
className
=
{
styles
.
breadcrumb
}
separator
=
{
breadcrumbSeparator
}
>
<
Breadcrumb
className
=
{
styles
.
breadcrumb
}
separator
=
{
breadcrumbSeparator
}
>
{
extraBreadcrumbItems
}
<
/Breadcrumb
>
);
}
}
;
/**
* 将参数转化为面包屑
* Convert parameters into breadcrumbs
*/
conversionBreadcrumbList
=
()
=>
{
const
{
breadcrumbList
,
breadcrumbSeparator
}
=
this
.
props
;
const
{
routes
,
params
,
routerLocation
,
breadcrumbNameMap
}
=
this
.
getBreadcrumbProps
();
const
{
routes
,
params
,
routerLocation
,
breadcrumbNameMap
,
}
=
this
.
getBreadcrumbProps
();
if
(
breadcrumbList
&&
breadcrumbList
.
length
)
{
return
this
.
conversionFromProps
();
}
...
...
@@ -130,24 +136,37 @@ export default class PageHeader extends PureComponent {
return
this
.
conversionFromLocation
(
routerLocation
,
breadcrumbNameMap
);
}
return
null
;
}
}
;
// 渲染Breadcrumb 子节点
// Render the Breadcrumb child node
itemRender
=
(
route
,
params
,
routes
,
paths
)
=>
{
const
{
linkElement
=
'
a
'
}
=
this
.
props
;
const
last
=
routes
.
indexOf
(
route
)
===
routes
.
length
-
1
;
return
(
last
||
!
route
.
component
)
?
<
span
>
{
route
.
breadcrumbName
}
<
/span
>
:
createElement
(
linkElement
,
{
return
last
||
!
route
.
component
?
(
<
span
>
{
route
.
breadcrumbName
}
<
/span
>
)
:
(
createElement
(
linkElement
,
{
href
:
paths
.
join
(
'
/
'
)
||
'
/
'
,
to
:
paths
.
join
(
'
/
'
)
||
'
/
'
,
},
route
.
breadcrumbName
);
}
},
route
.
breadcrumbName
,
)
);
};
render
()
{
const
{
title
,
logo
,
action
,
content
,
extraContent
,
tabList
,
className
,
tabActiveKey
,
tabBarExtraContent
,
title
,
logo
,
action
,
content
,
extraContent
,
tabList
,
className
,
tabActiveKey
,
tabBarExtraContent
,
}
=
this
.
props
;
const
clsString
=
classNames
(
styles
.
pageHeader
,
className
);
...
...
@@ -175,12 +194,13 @@ export default class PageHeader extends PureComponent {
<
/div
>
<
div
className
=
{
styles
.
row
}
>
{
content
&&
<
div
className
=
{
styles
.
content
}
>
{
content
}
<
/div>
}
{
extraContent
&&
<
div
className
=
{
styles
.
extraContent
}
>
{
extraContent
}
<
/div>
}
{
extraContent
&&
(
<
div
className
=
{
styles
.
extraContent
}
>
{
extraContent
}
<
/div
>
)}
<
/div
>
<
/div
>
<
/div
>
{
tabList
&&
{
tabList
&&
tabList
.
length
&&
(
<
Tabs
className
=
{
styles
.
tabs
}
...
...
@@ -188,12 +208,9 @@ export default class PageHeader extends PureComponent {
onChange
=
{
this
.
onChange
}
tabBarExtraContent
=
{
tabBarExtraContent
}
>
{
tabList
.
map
(
item
=>
<
TabPane
tab
=
{
item
.
tab
}
key
=
{
item
.
key
}
/>
)
}
{
tabList
.
map
(
item
=>
<
TabPane
tab
=
{
item
.
tab
}
key
=
{
item
.
key
}
/>
)
}
<
/Tabs
>
)
}
)}
<
/div
>
);
}
...
...
src/components/PageHeader/index.test.js
View file @
3b826259
import
{
getBreadcrumb
,
urlToList
}
from
'
./index
'
;
describe
(
'
test urlToList
'
,
()
=>
{
it
(
'
A path
'
,
()
=>
{
expect
(
urlToList
(
'
/userinfo
'
)).
toEqual
([
'
/userinfo
'
]);
});
it
(
'
Secondary path
'
,
()
=>
{
expect
(
urlToList
(
'
/userinfo/2144
'
)).
toEqual
([
'
/userinfo
'
,
'
/userinfo/2144
'
,
]);
});
it
(
'
Three paths
'
,
()
=>
{
expect
(
urlToList
(
'
/userinfo/2144/addr
'
)).
toEqual
([
'
/userinfo
'
,
'
/userinfo/2144
'
,
'
/userinfo/2144/addr
'
,
]);
});
});
import
{
getBreadcrumb
}
from
'
./index
'
;
import
{
urlToList
}
from
'
../utils/pathTools
'
;
const
routerData
=
{
'
/dashboard/analysis
'
:
{
...
...
@@ -36,17 +18,17 @@ const routerData = {
describe
(
'
test getBreadcrumb
'
,
()
=>
{
it
(
'
Simple url
'
,
()
=>
{
expect
(
getBreadcrumb
(
routerData
,
'
/dashboard/analysis
'
).
name
).
toEqual
(
'
分析页
'
'
分析页
'
,
);
});
it
(
'
Parameters url
'
,
()
=>
{
expect
(
getBreadcrumb
(
routerData
,
'
/userinfo/2144
'
).
name
).
toEqual
(
'
用户信息
'
'
用户信息
'
,
);
});
it
(
'
The middle parameter url
'
,
()
=>
{
expect
(
getBreadcrumb
(
routerData
,
'
/userinfo/2144/addr
'
).
name
).
toEqual
(
'
收货订单
'
'
收货订单
'
,
);
});
it
(
'
Loop through the parameters
'
,
()
=>
{
...
...
src/components/SiderMenu/SiderMenu.js
View file @
3b826259
...
...
@@ -3,6 +3,7 @@ import { Layout, Menu, Icon } from 'antd';
import
pathToRegexp
from
'
path-to-regexp
'
;
import
{
Link
}
from
'
dva/router
'
;
import
styles
from
'
./index.less
'
;
import
{
urlToList
}
from
'
../utils/pathTools
'
;
const
{
Sider
}
=
Layout
;
const
{
SubMenu
}
=
Menu
;
...
...
@@ -21,10 +22,17 @@ const getIcon = (icon) => {
return
icon
;
};
export
const
getMeunMatcheys
=
(
flatMenuKeys
,
path
)
=>
{
return
flatMenuKeys
.
filter
((
item
)
=>
{
return
pathToRegexp
(
item
).
test
(
path
);
});
};
export
default
class
SiderMenu
extends
PureComponent
{
constructor
(
props
)
{
super
(
props
);
this
.
menus
=
props
.
menuData
;
this
.
flatMenuKeys
=
this
.
getFlatMenuKeys
(
props
.
menuData
);
this
.
state
=
{
openKeys
:
this
.
getDefaultCollapsedSubMenus
(
props
),
};
...
...
@@ -43,30 +51,11 @@ export default class SiderMenu extends PureComponent {
*/
getDefaultCollapsedSubMenus
(
props
)
{
const
{
location
:
{
pathname
}
}
=
props
||
this
.
props
;
// eg. /list/search/articles = > ['','list','search','articles']
let
snippets
=
pathname
.
split
(
'
/
'
);
// Delete the end
// eg. delete 'articles'
snippets
.
pop
();
// Delete the head
// eg. delete ''
snippets
.
shift
();
// eg. After the operation is completed, the array should be ['list','search']
// eg. Forward the array as ['list','list/search']
snippets
=
snippets
.
map
((
item
,
index
)
=>
{
// If the array length > 1
if
(
index
>
0
)
{
// eg. search => ['list','search'].join('/')
return
snippets
.
slice
(
0
,
index
+
1
).
join
(
'
/
'
);
}
// index 0 to not do anything
return
item
;
});
snippets
=
snippets
.
map
((
item
)
=>
{
return
this
.
getSelectedMenuKeys
(
`/
${
item
}
`
)[
0
];
});
// eg. ['list','list/search']
return
snippets
;
return
urlToList
(
pathname
)
.
map
((
item
)
=>
{
return
getMeunMatcheys
(
this
.
flatMenuKeys
,
item
)[
0
];
})
.
filter
(
item
=>
item
);
}
/**
* Recursively flatten the data
...
...
@@ -77,24 +66,12 @@ export default class SiderMenu extends PureComponent {
let
keys
=
[];
menus
.
forEach
((
item
)
=>
{
if
(
item
.
children
)
{
keys
.
push
(
item
.
path
);
keys
=
keys
.
concat
(
this
.
getFlatMenuKeys
(
item
.
children
));
}
else
{
keys
.
push
(
item
.
path
);
}
keys
.
push
(
item
.
path
);
});
return
keys
;
}
/**
* Get selected child nodes
* /user/chen => ['user','/user/:id']
*/
getSelectedMenuKeys
=
(
path
)
=>
{
const
flatMenuKeys
=
this
.
getFlatMenuKeys
(
this
.
menus
);
return
flatMenuKeys
.
filter
((
item
)
=>
{
return
pathToRegexp
(
`/
${
item
}
(.*)`
).
test
(
path
);
});
}
/**
* 判断是否是http链接.返回 Link 或 a
* Judge whether it is http link.return a or Link
...
...
@@ -108,7 +85,8 @@ export default class SiderMenu extends PureComponent {
if
(
/^https
?
:
\/\/
/
.
test
(
itemPath
))
{
return
(
<
a
href
=
{
itemPath
}
target
=
{
target
}
>
{
icon
}
<
span
>
{
name
}
<
/span
>
{
icon
}
<
span
>
{
name
}
<
/span
>
<
/a
>
);
}
...
...
@@ -117,16 +95,23 @@ export default class SiderMenu extends PureComponent {
to
=
{
itemPath
}
target
=
{
target
}
replace
=
{
itemPath
===
this
.
props
.
location
.
pathname
}
onClick
=
{
this
.
props
.
isMobile
?
()
=>
{
this
.
props
.
onCollapse
(
true
);
}
:
undefined
}
onClick
=
{
this
.
props
.
isMobile
?
()
=>
{
this
.
props
.
onCollapse
(
true
);
}
:
undefined
}
>
{
icon
}
<
span
>
{
name
}
<
/span
>
{
icon
}
<
span
>
{
name
}
<
/span
>
<
/Link
>
);
}
}
;
/**
* get SubMenu or Item
*/
getSubMenuOrItem
=
(
item
)
=>
{
getSubMenuOrItem
=
(
item
)
=>
{
if
(
item
.
children
&&
item
.
children
.
some
(
child
=>
child
.
name
))
{
return
(
<
SubMenu
...
...
@@ -136,7 +121,9 @@ export default class SiderMenu extends PureComponent {
{
getIcon
(
item
.
icon
)}
<
span
>
{
item
.
name
}
<
/span
>
<
/span
>
)
:
item
.
name
)
:
(
item
.
name
)
}
key
=
{
item
.
path
}
>
...
...
@@ -145,12 +132,10 @@ export default class SiderMenu extends PureComponent {
);
}
else
{
return
(
<
Menu
.
Item
key
=
{
item
.
path
}
>
{
this
.
getMenuItemPath
(
item
)}
<
/Menu.Item
>
<
Menu
.
Item
key
=
{
item
.
path
}
>
{
this
.
getMenuItemPath
(
item
)}
<
/Menu.Item
>
);
}
}
}
;
/**
* 获得菜单子节点
* @memberof SiderMenu
...
...
@@ -162,49 +147,57 @@ export default class SiderMenu extends PureComponent {
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
);
}
.
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
)
=>
{
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
check
(
authority
,
ItemDom
);
}
return
ItemDom
;
}
}
;
handleOpenChange
=
(
openKeys
)
=>
{
const
lastOpenKey
=
openKeys
[
openKeys
.
length
-
1
];
const
isMainMenu
=
this
.
menus
.
some
(
item
=>
lastOpenKey
&&
(
item
.
key
===
lastOpenKey
||
item
.
path
===
lastOpenKey
)
item
=>
lastOpenKey
&&
(
item
.
key
===
lastOpenKey
||
item
.
path
===
lastOpenKey
),
);
this
.
setState
({
openKeys
:
isMainMenu
?
[
lastOpenKey
]
:
[...
openKeys
],
});
}
}
;
render
()
{
const
{
logo
,
collapsed
,
location
:
{
pathname
},
onCollapse
}
=
this
.
props
;
const
{
logo
,
collapsed
,
onCollapse
}
=
this
.
props
;
const
{
openKeys
}
=
this
.
state
;
// Don't show popup menu when it is been collapsed
const
menuProps
=
collapsed
?
{}
:
{
const
menuProps
=
collapsed
?
{}
:
{
openKeys
,
};
// if pathname can't match, use the nearest parent's key
let
selectedKeys
=
this
.
getSelectedMenuKeys
(
pathname
);
let
selectedKeys
=
this
.
getSelectedMenuKeys
();
if
(
!
selectedKeys
.
length
)
{
selectedKeys
=
[
openKeys
[
openKeys
.
length
-
1
]];
}
...
...
src/components/SiderMenu/SilderMenu.test.js
0 → 100644
View file @
3b826259
import
{
getMeunMatcheys
}
from
'
./SiderMenu
'
;
const
meun
=
[
'
/dashboard
'
,
'
/userinfo
'
,
'
/dashboard/name
'
,
'
/userinfo/:id
'
,
'
/userinfo/:id/info
'
,
];
describe
(
'
test meun match
'
,
()
=>
{
it
(
'
simple path
'
,
()
=>
{
expect
(
getMeunMatcheys
(
meun
,
'
/dashboard
'
)).
toEqual
([
'
/dashboard
'
]);
});
it
(
'
error path
'
,
()
=>
{
expect
(
getMeunMatcheys
(
meun
,
'
/dashboardname
'
)).
toEqual
([]);
});
it
(
'
Secondary path
'
,
()
=>
{
expect
(
getMeunMatcheys
(
meun
,
'
/dashboard/name
'
)).
toEqual
([
'
/dashboard/name
'
,
]);
});
it
(
'
Parameter path
'
,
()
=>
{
expect
(
getMeunMatcheys
(
meun
,
'
/userinfo/2144
'
)).
toEqual
([
'
/userinfo/:id
'
,
]);
});
it
(
'
three parameter path
'
,
()
=>
{
expect
(
getMeunMatcheys
(
meun
,
'
/userinfo/2144/info
'
)).
toEqual
([
'
/userinfo/:id/info
'
,
]);
});
});
src/components/utils/pathTools.js
0 → 100644
View file @
3b826259
// /userinfo/2144/id => ['/userinfo','/useinfo/2144,'/userindo/2144/id']
export
function
urlToList
(
url
)
{
const
urllist
=
url
.
split
(
'
/
'
).
filter
(
i
=>
i
);
return
urllist
.
map
((
urlItem
,
index
)
=>
{
return
`/
${
urllist
.
slice
(
0
,
index
+
1
).
join
(
'
/
'
)}
`
;
});
}
src/components/utils/pathTools.test.js
0 → 100644
View file @
3b826259
import
{
urlToList
}
from
'
./pathTools
'
;
describe
(
'
test urlToList
'
,
()
=>
{
it
(
'
A path
'
,
()
=>
{
expect
(
urlToList
(
'
/userinfo
'
)).
toEqual
([
'
/userinfo
'
]);
});
it
(
'
Secondary path
'
,
()
=>
{
expect
(
urlToList
(
'
/userinfo/2144
'
)).
toEqual
([
'
/userinfo
'
,
'
/userinfo/2144
'
,
]);
});
it
(
'
Three paths
'
,
()
=>
{
expect
(
urlToList
(
'
/userinfo/2144/addr
'
)).
toEqual
([
'
/userinfo
'
,
'
/userinfo/2144
'
,
'
/userinfo/2144/addr
'
,
]);
});
});
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