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
028b6cc7
Commit
028b6cc7
authored
May 24, 2019
by
陈帅
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
auto insert pro code
parent
41ad482a
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
442 additions
and
249 deletions
+442
-249
scripts/fetch-blocks.js
scripts/fetch-blocks.js
+4
-0
scripts/insertCode.js
scripts/insertCode.js
+136
-0
scripts/repalceRouter.js
scripts/repalceRouter.js
+1
-1
src/components/CopyBlock/index.tsx
src/components/CopyBlock/index.tsx
+9
-2
src/components/GlobalHeader/AvatarDropdown.tsx
src/components/GlobalHeader/AvatarDropdown.tsx
+72
-0
src/components/GlobalHeader/NoticeIconView.tsx
src/components/GlobalHeader/NoticeIconView.tsx
+145
-0
src/components/GlobalHeader/RightContent.tsx
src/components/GlobalHeader/RightContent.tsx
+29
-190
src/layouts/BasicLayout.tsx
src/layouts/BasicLayout.tsx
+46
-56
No files found.
scripts/fetch-blocks.js
View file @
028b6cc7
...
...
@@ -5,6 +5,7 @@ const exec = require('child_process').exec;
const
getNewRouteCode
=
require
(
'
./repalceRouter
'
);
const
router
=
require
(
'
./router.config
'
);
const
chalk
=
require
(
'
chalk
'
);
const
insertCode
=
require
(
'
./insertCode
'
);
const
fetchGithubFiles
=
async
()
=>
{
const
ignoreFile
=
[
'
_scripts
'
];
...
...
@@ -123,3 +124,6 @@ const installBlock = async () => {
installGitFile
(
0
);
};
installBlock
();
// 插入 pro 需要的演示代码
insertCode
();
scripts/insertCode.js
0 → 100644
View file @
028b6cc7
const
parser
=
require
(
'
@babel/parser
'
);
const
traverse
=
require
(
'
@babel/traverse
'
);
const
generate
=
require
(
'
@babel/generator
'
);
const
t
=
require
(
'
@babel/types
'
);
const
fs
=
require
(
'
fs
'
);
const
path
=
require
(
'
path
'
);
const
prettier
=
require
(
'
prettier
'
);
const
chalk
=
require
(
'
chalk
'
);
const
parseCode
=
code
=>
{
return
parser
.
parse
(
code
,
{
sourceType
:
'
module
'
,
plugins
:
[
'
typescript
'
,
'
jsx
'
],
}).
program
.
body
[
0
];
};
/**
* 生成代码
* @param {*} ast
*/
function
generateCode
(
ast
)
{
const
newCode
=
generate
.
default
(
ast
,
{}).
code
;
return
prettier
.
format
(
newCode
,
{
// format same as ant-design-pro
singleQuote
:
true
,
trailingComma
:
'
es5
'
,
printWidth
:
100
,
parser
:
'
typescript
'
,
});
}
const
SettingCodeString
=
`
<SettingDrawer
settings={settings}
onSettingChange={config =>
dispatch!({
type: 'settings/changeSetting',
payload: config,
})
}
/>
`
;
const
mapAst
=
(
configPath
,
callBack
)
=>
{
const
ast
=
parser
.
parse
(
fs
.
readFileSync
(
configPath
,
'
utf-8
'
),
{
sourceType
:
'
module
'
,
plugins
:
[
'
typescript
'
,
'
jsx
'
],
});
// 查询当前配置文件是否导出 routes 属性
traverse
.
default
(
ast
,
{
Program
({
node
})
{
const
{
body
}
=
node
;
callBack
(
body
);
},
});
return
generateCode
(
ast
);
};
const
insertBasicLayout
=
configPath
=>
{
return
mapAst
(
configPath
,
body
=>
{
const
index
=
body
.
findIndex
(
item
=>
{
return
item
.
type
!==
'
ImportDeclaration
'
;
});
// 从组件中导入 CopyBlock
body
.
splice
(
index
,
0
,
parseCode
(
`import CopyBlock from '@/components/CopyBlock';
`
),
);
body
.
forEach
(
item
=>
{
// 从包中导出 SettingDrawer
if
(
item
.
type
===
'
ImportDeclaration
'
)
{
if
(
item
.
source
.
value
===
'
@ant-design/pro-layout
'
)
{
item
.
specifiers
.
push
(
parseCode
(
`SettingDrawer`
).
expression
);
}
}
if
(
item
.
type
===
'
VariableDeclaration
'
)
{
const
{
id
,
init
:
{
body
},
}
=
item
.
declarations
[
0
];
// 给 BasicLayout 中插入 button 和 设置抽屉
if
(
id
.
name
===
`BasicLayout`
)
{
body
.
body
.
forEach
(
node
=>
{
if
(
node
.
type
===
'
ReturnStatement
'
)
{
const
JSXFragment
=
parseCode
(
`<></>`
).
expression
;
JSXFragment
.
children
.
push
({
...
node
.
argument
});
JSXFragment
.
children
.
push
(
parseCode
(
SettingCodeString
).
expression
);
JSXFragment
.
children
.
push
(
parseCode
(
` <CopyBlock />`
).
expression
);
node
.
argument
=
JSXFragment
;
}
});
}
}
});
});
};
const
insertRightContent
=
configPath
=>
{
return
mapAst
(
configPath
,
body
=>
{
const
index
=
body
.
findIndex
(
item
=>
{
return
item
.
type
!==
'
ImportDeclaration
'
;
});
// 从组件中导入 CopyBlock
body
.
splice
(
index
,
0
,
parseCode
(
`import NoticeIconView from './NoticeIconView';`
));
body
.
forEach
(
item
=>
{
if
(
item
.
type
===
'
ClassDeclaration
'
)
{
const
classBody
=
item
.
body
.
body
[
0
].
body
;
classBody
.
body
.
forEach
(
node
=>
{
if
(
node
.
type
===
'
ReturnStatement
'
)
{
const
index
=
node
.
argument
.
children
.
findIndex
(
item
=>
{
if
(
item
.
type
===
'
JSXElement
'
)
{
if
(
item
.
openingElement
.
name
.
name
===
'
Avatar
'
)
{
return
true
;
}
}
});
node
.
argument
.
children
.
splice
(
index
,
1
,
parseCode
(
`<Avatar menu />`
).
expression
);
node
.
argument
.
children
.
splice
(
index
,
0
,
parseCode
(
`<NoticeIconView />`
).
expression
);
}
});
}
});
});
};
module
.
exports
=
()
=>
{
const
basicLayoutPath
=
path
.
join
(
__dirname
,
'
../src/layouts/BasicLayout.tsx
'
);
fs
.
writeFileSync
(
basicLayoutPath
,
insertBasicLayout
(
basicLayoutPath
));
console
.
log
(
`insert
${
chalk
.
hex
(
'
#1890ff
'
)(
'
BasicLayout
'
)}
success`
);
const
rightContentPath
=
path
.
join
(
__dirname
,
'
../src/components/GlobalHeader/RightContent.tsx
'
);
fs
.
writeFileSync
(
rightContentPath
,
insertRightContent
(
rightContentPath
));
console
.
log
(
`insert
${
chalk
.
hex
(
'
#1890ff
'
)(
'
RightContent
'
)}
success`
);
};
scripts/repalceRouter.js
View file @
028b6cc7
...
...
@@ -5,7 +5,7 @@ const t = require('@babel/types');
const
fs
=
require
(
'
fs
'
);
const
prettier
=
require
(
'
prettier
'
);
const
getNewRouteCode
=
(
configPath
,
newRoute
,
absSrcPath
)
=>
{
const
getNewRouteCode
=
(
configPath
,
newRoute
)
=>
{
const
ast
=
parser
.
parse
(
fs
.
readFileSync
(
configPath
,
'
utf-8
'
),
{
sourceType
:
'
module
'
,
plugins
:
[
'
typescript
'
],
...
...
src/components/CopyBlock/index.tsx
View file @
028b6cc7
import
React
from
'
react
'
;
import
{
Icon
,
Typography
,
Popover
}
from
'
antd
'
;
import
styles
from
'
./index.less
'
;
import
{
connect
}
from
'
dva
'
;
import
*
as
H
from
'
history
'
;
const
firstUpperCase
=
(
pathString
:
string
)
=>
{
return
pathString
.
replace
(
'
.
'
,
''
)
...
...
@@ -22,7 +24,12 @@ const BlockCodeView: React.SFC<{
);
};
export
default
({
url
}:
{
url
:
string
})
=>
{
type
RoutingType
=
{
location
:
H
.
Location
};
export
default
connect
(({
routing
}:
{
routing
:
RoutingType
})
=>
({
location
:
routing
.
location
,
}))(({
location
}:
RoutingType
)
=>
{
const
url
=
location
.
pathname
;
return
(
<
Popover
title
=
"下载此页面到本地项目"
...
...
@@ -35,4 +42,4 @@ export default ({ url }: { url: string }) => {
</
div
>
</
Popover
>
);
};
}
)
;
src/components/GlobalHeader/AvatarDropdown.tsx
0 → 100644
View file @
028b6cc7
import
React
from
'
react
'
;
import
{
Avatar
,
Menu
,
Spin
,
Icon
}
from
'
antd
'
;
import
{
FormattedMessage
}
from
'
umi-plugin-react/locale
'
;
import
{
ClickParam
}
from
'
antd/lib/menu
'
;
import
{
ConnectProps
,
ConnectState
}
from
'
@/models/connect
'
;
import
{
CurrentUser
}
from
'
@/models/user
'
;
import
{
connect
}
from
'
dva
'
;
import
router
from
'
umi/router
'
;
import
HeaderDropdown
from
'
../HeaderDropdown
'
;
import
styles
from
'
./index.less
'
;
export
interface
GlobalHeaderRightProps
extends
ConnectProps
{
currentUser
?:
CurrentUser
;
menu
?:
boolean
;
}
class
AvatarDropdown
extends
React
.
Component
<
GlobalHeaderRightProps
>
{
onMenuClick
=
(
event
:
ClickParam
)
=>
{
const
{
key
}
=
event
;
if
(
key
===
'
logout
'
)
{
const
{
dispatch
}
=
this
.
props
;
dispatch
!
({
type
:
'
login/logout
'
,
});
return
;
}
router
.
push
(
`/account/
${
key
}
`
);
};
render
()
{
const
{
currentUser
=
{},
menu
}
=
this
.
props
;
if
(
!
menu
)
{
return
(
<
span
className
=
{
`
${
styles
.
action
}
${
styles
.
account
}
`
}
>
<
Avatar
size
=
"small"
className
=
{
styles
.
avatar
}
src
=
{
currentUser
.
avatar
}
alt
=
"avatar"
/>
<
span
className
=
{
styles
.
name
}
>
{
currentUser
.
name
}
</
span
>
</
span
>
);
}
const
menuHeaderDropdown
=
(
<
Menu
className
=
{
styles
.
menu
}
selectedKeys
=
{
[]
}
onClick
=
{
this
.
onMenuClick
}
>
<
Menu
.
Item
key
=
"center"
>
<
Icon
type
=
"user"
/>
<
FormattedMessage
id
=
"menu.account.center"
defaultMessage
=
"account center"
/>
</
Menu
.
Item
>
<
Menu
.
Item
key
=
"settings"
>
<
Icon
type
=
"setting"
/>
<
FormattedMessage
id
=
"menu.account.settings"
defaultMessage
=
"account settings"
/>
</
Menu
.
Item
>
<
Menu
.
Divider
/>
<
Menu
.
Item
key
=
"logout"
>
<
Icon
type
=
"logout"
/>
<
FormattedMessage
id
=
"menu.account.logout"
defaultMessage
=
"logout"
/>
</
Menu
.
Item
>
</
Menu
>
);
return
currentUser
&&
currentUser
.
name
?
(
<
HeaderDropdown
overlay
=
{
menuHeaderDropdown
}
>
<
span
className
=
{
`
${
styles
.
action
}
${
styles
.
account
}
`
}
>
<
Avatar
size
=
"small"
className
=
{
styles
.
avatar
}
src
=
{
currentUser
.
avatar
}
alt
=
"avatar"
/>
<
span
className
=
{
styles
.
name
}
>
{
currentUser
.
name
}
</
span
>
</
span
>
</
HeaderDropdown
>
)
:
(
<
Spin
size
=
"small"
style
=
{
{
marginLeft
:
8
,
marginRight
:
8
}
}
/>
);
}
}
export
default
connect
(({
user
}:
ConnectState
)
=>
({
currentUser
:
user
.
currentUser
,
}))(
AvatarDropdown
);
src/components/GlobalHeader/NoticeIconView.tsx
0 → 100644
View file @
028b6cc7
import
{
ConnectProps
,
ConnectState
}
from
'
@/models/connect
'
;
import
{
NoticeItem
}
from
'
@/models/global
'
;
import
{
CurrentUser
}
from
'
@/models/user
'
;
import
React
,
{
Component
}
from
'
react
'
;
import
{
Tag
,
message
}
from
'
antd
'
;
import
{
formatMessage
}
from
'
umi-plugin-react/locale
'
;
import
moment
from
'
moment
'
;
import
groupBy
from
'
lodash/groupBy
'
;
import
NoticeIcon
from
'
../NoticeIcon
'
;
import
styles
from
'
./index.less
'
;
import
{
connect
}
from
'
dva
'
;
export
interface
GlobalHeaderRightProps
extends
ConnectProps
{
notices
?:
NoticeItem
[];
currentUser
?:
CurrentUser
;
fetchingNotices
?:
boolean
;
onNoticeVisibleChange
?:
(
visible
:
boolean
)
=>
void
;
onNoticeClear
?:
(
tabName
?:
string
)
=>
void
;
}
class
GlobalHeaderRight
extends
Component
<
GlobalHeaderRightProps
>
{
getNoticeData
=
():
{
[
key
:
string
]:
NoticeItem
[]
}
=>
{
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
as
string
).
fromNow
();
}
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
'
);
};
getUnreadData
=
(
noticeData
:
{
[
key
:
string
]:
NoticeItem
[]
})
=>
{
const
unreadMsg
:
{
[
key
:
string
]:
number
}
=
{};
Object
.
entries
(
noticeData
).
forEach
(([
key
,
value
])
=>
{
if
(
!
unreadMsg
[
key
])
{
unreadMsg
[
key
]
=
0
;
}
if
(
Array
.
isArray
(
value
))
{
unreadMsg
[
key
]
=
value
.
filter
(
item
=>
!
item
.
read
).
length
;
}
});
return
unreadMsg
;
};
changeReadState
=
(
clickedItem
:
NoticeItem
)
=>
{
const
{
id
}
=
clickedItem
;
const
{
dispatch
}
=
this
.
props
;
dispatch
!
({
type
:
'
global/changeNoticeReadState
'
,
payload
:
id
,
});
};
componentDidMount
()
{
const
{
dispatch
}
=
this
.
props
;
dispatch
!
({
type
:
'
global/fetchNotices
'
,
});
}
handleNoticeClear
=
(
title
:
string
,
key
:
string
)
=>
{
const
{
dispatch
}
=
this
.
props
;
message
.
success
(
`
${
formatMessage
({
id
:
'
component.noticeIcon.cleared
'
})}
${
title
}
`
);
if
(
dispatch
)
{
dispatch
({
type
:
'
global/clearNotices
'
,
payload
:
key
,
});
}
};
render
()
{
const
{
currentUser
,
fetchingNotices
,
onNoticeVisibleChange
}
=
this
.
props
;
const
noticeData
=
this
.
getNoticeData
();
const
unreadMsg
=
this
.
getUnreadData
(
noticeData
);
return
(
<
NoticeIcon
className
=
{
styles
.
action
}
count
=
{
currentUser
&&
currentUser
.
unreadCount
}
onItemClick
=
{
item
=>
{
this
.
changeReadState
(
item
as
NoticeItem
);
}
}
loading
=
{
fetchingNotices
}
clearText
=
{
formatMessage
({
id
:
'
component.noticeIcon.clear
'
})
}
viewMoreText
=
{
formatMessage
({
id
:
'
component.noticeIcon.view-more
'
})
}
onClear
=
{
this
.
handleNoticeClear
}
onPopupVisibleChange
=
{
onNoticeVisibleChange
}
onViewMore
=
{
()
=>
message
.
info
(
'
Click on view more
'
)
}
clearClose
>
<
NoticeIcon
.
Tab
tabKey
=
"notification"
count
=
{
unreadMsg
.
notification
}
list
=
{
noticeData
.
notification
}
title
=
{
formatMessage
({
id
:
'
component.globalHeader.notification
'
})
}
emptyText
=
{
formatMessage
({
id
:
'
component.globalHeader.notification.empty
'
})
}
showViewMore
/>
<
NoticeIcon
.
Tab
tabKey
=
"message"
count
=
{
unreadMsg
.
message
}
list
=
{
noticeData
.
message
}
title
=
{
formatMessage
({
id
:
'
component.globalHeader.message
'
})
}
emptyText
=
{
formatMessage
({
id
:
'
component.globalHeader.message.empty
'
})
}
showViewMore
/>
<
NoticeIcon
.
Tab
tabKey
=
"event"
title
=
{
formatMessage
({
id
:
'
component.globalHeader.event
'
})
}
emptyText
=
{
formatMessage
({
id
:
'
component.globalHeader.event.empty
'
})
}
count
=
{
unreadMsg
.
event
}
list
=
{
noticeData
.
event
}
showViewMore
/>
</
NoticeIcon
>
);
}
}
export
default
connect
(({
user
,
global
,
loading
}:
ConnectState
)
=>
({
currentUser
:
user
.
currentUser
,
collapsed
:
global
.
collapsed
,
fetchingMoreNotices
:
loading
.
effects
[
'
global/fetchMoreNotices
'
],
fetchingNotices
:
loading
.
effects
[
'
global/fetchNotices
'
],
notices
:
global
.
notices
,
}))(
GlobalHeaderRight
);
src/components/GlobalHeader/RightContent.tsx
View file @
028b6cc7
import
{
ConnectProps
,
ConnectState
}
from
'
@/models/connect
'
;
import
{
NoticeItem
}
from
'
@/models/global
'
;
import
{
CurrentUser
}
from
'
@/models/user
'
;
import
React
,
{
Component
}
from
'
react
'
;
import
{
Spin
,
Tag
,
Menu
,
Icon
,
Avatar
,
Tooltip
,
message
}
from
'
antd
'
;
import
{
ClickParam
}
from
'
antd/lib/menu
'
;
import
{
FormattedMessage
,
formatMessage
}
from
'
umi-plugin-react/locale
'
;
import
moment
from
'
moment
'
;
import
groupBy
from
'
lodash/groupBy
'
;
import
NoticeIcon
from
'
../NoticeIcon
'
;
import
{
Icon
,
Tooltip
}
from
'
antd
'
;
import
{
formatMessage
}
from
'
umi-plugin-react/locale
'
;
import
HeaderSearch
from
'
../HeaderSearch
'
;
import
HeaderDropdown
from
'
../HeaderDropdown
'
;
import
SelectLang
from
'
../SelectLang
'
;
import
styles
from
'
./index.less
'
;
import
Avatar
from
'
./AvatarDropdown
'
;
import
{
connect
}
from
'
dva
'
;
import
router
from
'
umi/router
'
;
export
type
SiderTheme
=
'
light
'
|
'
dark
'
;
export
interface
GlobalHeaderRightProps
extends
ConnectProps
{
notices
?:
NoticeItem
[];
currentUser
?:
CurrentUser
;
fetchingNotices
?:
boolean
;
onNoticeVisibleChange
?:
(
visible
:
boolean
)
=>
void
;
onMenuClick
?:
(
param
:
ClickParam
)
=>
void
;
onNoticeClear
?:
(
tabName
?:
string
)
=>
void
;
theme
?:
SiderTheme
;
layout
:
'
sidemenu
'
|
'
topmenu
'
;
}
class
GlobalHeaderRight
extends
Component
<
GlobalHeaderRightProps
>
{
getNoticeData
=
():
{
[
key
:
string
]:
NoticeItem
[]
}
=>
{
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
as
string
).
fromNow
();
}
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
'
);
};
getUnreadData
=
(
noticeData
:
{
[
key
:
string
]:
NoticeItem
[]
})
=>
{
const
unreadMsg
:
{
[
key
:
string
]:
number
}
=
{};
Object
.
entries
(
noticeData
).
forEach
(([
key
,
value
])
=>
{
if
(
!
unreadMsg
[
key
])
{
unreadMsg
[
key
]
=
0
;
}
if
(
Array
.
isArray
(
value
))
{
unreadMsg
[
key
]
=
value
.
filter
(
item
=>
!
item
.
read
).
length
;
}
});
return
unreadMsg
;
};
changeReadState
=
(
clickedItem
:
NoticeItem
)
=>
{
const
{
id
}
=
clickedItem
;
const
{
dispatch
}
=
this
.
props
;
dispatch
!
({
type
:
'
global/changeNoticeReadState
'
,
payload
:
id
,
});
};
componentDidMount
()
{
const
{
dispatch
}
=
this
.
props
;
dispatch
!
({
type
:
'
global/fetchNotices
'
,
});
}
handleNoticeClear
=
(
title
:
string
,
key
:
string
)
=>
{
const
{
dispatch
}
=
this
.
props
;
message
.
success
(
`
${
formatMessage
({
id
:
'
component.noticeIcon.cleared
'
})}
${
title
}
`
);
if
(
dispatch
)
{
dispatch
({
type
:
'
global/clearNotices
'
,
payload
:
key
,
});
}
};
onMenuClick
=
(
event
:
ClickParam
)
=>
{
const
{
onMenuClick
}
=
this
.
props
;
if
(
onMenuClick
)
{
onMenuClick
(
event
);
return
;
}
const
{
key
}
=
event
;
if
(
key
===
'
logout
'
)
{
const
{
dispatch
}
=
this
.
props
;
dispatch
!
({
type
:
'
login/logout
'
,
});
return
;
}
router
.
push
(
`/account/
${
key
}
`
);
};
render
()
{
const
{
currentUser
,
fetchingNotices
,
onNoticeVisibleChange
,
theme
}
=
this
.
props
;
const
menu
=
(
<
Menu
className
=
{
styles
.
menu
}
selectedKeys
=
{
[]
}
onClick
=
{
this
.
onMenuClick
}
>
<
Menu
.
Item
key
=
"center"
>
<
Icon
type
=
"user"
/>
<
FormattedMessage
id
=
"menu.account.center"
defaultMessage
=
"account center"
/>
</
Menu
.
Item
>
<
Menu
.
Item
key
=
"settings"
>
<
Icon
type
=
"setting"
/>
<
FormattedMessage
id
=
"menu.account.settings"
defaultMessage
=
"account settings"
/>
</
Menu
.
Item
>
<
Menu
.
Divider
/>
<
Menu
.
Item
key
=
"logout"
>
<
Icon
type
=
"logout"
/>
<
FormattedMessage
id
=
"menu.account.logout"
defaultMessage
=
"logout"
/>
</
Menu
.
Item
>
</
Menu
>
);
const
noticeData
=
this
.
getNoticeData
();
const
unreadMsg
=
this
.
getUnreadData
(
noticeData
);
const
{
theme
,
layout
}
=
this
.
props
;
let
className
=
styles
.
right
;
if
(
theme
===
'
dark
'
)
{
if
(
theme
===
'
dark
'
&&
layout
===
'
topmenu
'
)
{
className
=
`
${
styles
.
right
}
${
styles
.
dark
}
`
;
}
return
(
<
div
className
=
{
className
}
>
<
HeaderSearch
className
=
{
`
${
styles
.
action
}
${
styles
.
search
}
`
}
placeholder
=
{
formatMessage
({
id
:
'
component.globalHeader.search
'
})
}
placeholder
=
{
formatMessage
({
id
:
'
component.globalHeader.search
'
,
})
}
dataSource
=
{
[
formatMessage
({
id
:
'
component.globalHeader.search.example1
'
}),
formatMessage
({
id
:
'
component.globalHeader.search.example2
'
}),
formatMessage
({
id
:
'
component.globalHeader.search.example3
'
}),
formatMessage
({
id
:
'
component.globalHeader.search.example1
'
,
}),
formatMessage
({
id
:
'
component.globalHeader.search.example2
'
,
}),
formatMessage
({
id
:
'
component.globalHeader.search.example3
'
,
}),
]
}
onSearch
=
{
value
=>
{
console
.
log
(
'
input
'
,
value
);
// tslint:disable-line no-console
...
...
@@ -155,7 +47,11 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
console
.
log
(
'
enter
'
,
value
);
// tslint:disable-line no-console
}
}
/>
<
Tooltip
title
=
{
formatMessage
({
id
:
'
component.globalHeader.help
'
})
}
>
<
Tooltip
title
=
{
formatMessage
({
id
:
'
component.globalHeader.help
'
,
})
}
>
<
a
target
=
"_blank"
href
=
"https://pro.ant.design/docs/getting-started"
...
...
@@ -165,71 +61,14 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
<
Icon
type
=
"question-circle-o"
/>
</
a
>
</
Tooltip
>
<
NoticeIcon
className
=
{
styles
.
action
}
count
=
{
currentUser
&&
currentUser
.
unreadCount
}
onItemClick
=
{
item
=>
{
this
.
changeReadState
(
item
as
NoticeItem
);
}
}
loading
=
{
fetchingNotices
}
clearText
=
{
formatMessage
({
id
:
'
component.noticeIcon.clear
'
})
}
viewMoreText
=
{
formatMessage
({
id
:
'
component.noticeIcon.view-more
'
})
}
onClear
=
{
this
.
handleNoticeClear
}
onPopupVisibleChange
=
{
onNoticeVisibleChange
}
onViewMore
=
{
()
=>
message
.
info
(
'
Click on view more
'
)
}
clearClose
>
<
NoticeIcon
.
Tab
tabKey
=
"notification"
count
=
{
unreadMsg
.
notification
}
list
=
{
noticeData
.
notification
}
title
=
{
formatMessage
({
id
:
'
component.globalHeader.notification
'
})
}
emptyText
=
{
formatMessage
({
id
:
'
component.globalHeader.notification.empty
'
})
}
showViewMore
/>
<
NoticeIcon
.
Tab
tabKey
=
"message"
count
=
{
unreadMsg
.
message
}
list
=
{
noticeData
.
message
}
title
=
{
formatMessage
({
id
:
'
component.globalHeader.message
'
})
}
emptyText
=
{
formatMessage
({
id
:
'
component.globalHeader.message.empty
'
})
}
showViewMore
/>
<
NoticeIcon
.
Tab
tabKey
=
"event"
title
=
{
formatMessage
({
id
:
'
component.globalHeader.event
'
})
}
emptyText
=
{
formatMessage
({
id
:
'
component.globalHeader.event.empty
'
})
}
count
=
{
unreadMsg
.
event
}
list
=
{
noticeData
.
event
}
showViewMore
/>
</
NoticeIcon
>
{
currentUser
&&
currentUser
.
name
?
(
<
HeaderDropdown
overlay
=
{
menu
}
>
<
span
className
=
{
`
${
styles
.
action
}
${
styles
.
account
}
`
}
>
<
Avatar
size
=
"small"
className
=
{
styles
.
avatar
}
src
=
{
currentUser
.
avatar
}
alt
=
"avatar"
/>
<
span
className
=
{
styles
.
name
}
>
{
currentUser
.
name
}
</
span
>
</
span
>
</
HeaderDropdown
>
)
:
(
<
Spin
size
=
"small"
style
=
{
{
marginLeft
:
8
,
marginRight
:
8
}
}
/>
)
}
<
Avatar
/>
<
SelectLang
className
=
{
styles
.
action
}
/>
</
div
>
);
}
}
export
default
connect
(({
user
,
global
,
loading
}:
ConnectState
)
=>
({
currentUser
:
user
.
currentUser
,
collapsed
:
global
.
collapsed
,
fetchingMoreNotices
:
loading
.
effects
[
'
global/fetchMoreNotices
'
],
fetchingNotices
:
loading
.
effects
[
'
global/fetchNotices
'
],
notices
:
global
.
notices
,
export
default
connect
(({
settings
}:
ConnectState
)
=>
({
theme
:
settings
.
navTheme
,
layout
:
settings
.
layout
,
}))(
GlobalHeaderRight
);
src/layouts/BasicLayout.tsx
View file @
028b6cc7
import
{
ConnectState
,
ConnectProps
}
from
'
@/models/connect
'
;
import
RightContent
from
'
@/components/GlobalHeader/RightContent
'
;
import
CopyBlock
from
'
@/components/CopyBlock
'
;
import
{
connect
}
from
'
dva
'
;
import
React
,
{
useState
}
from
'
react
'
;
import
logo
from
'
../assets/logo.svg
'
;
...
...
@@ -11,30 +10,26 @@ import {
BasicLayoutProps
as
BasicLayoutComponentsProps
,
MenuDataItem
,
Settings
,
SettingDrawer
,
}
from
'
@ant-design/pro-layout
'
;
import
Link
from
'
umi/link
'
;
import
{
isAntDesignProOrDev
}
from
'
@/utils/utils
'
;
export
interface
BasicLayoutProps
extends
BasicLayoutComponentsProps
,
ConnectProps
{
breadcrumbNameMap
:
{
[
path
:
string
]:
MenuDataItem
};
breadcrumbNameMap
:
{
[
path
:
string
]:
MenuDataItem
;
};
settings
:
Settings
;
}
export
type
BasicLayoutContext
=
{
[
K
in
'
location
'
]:
BasicLayoutProps
[
K
]
}
&
{
breadcrumbNameMap
:
{
[
path
:
string
]:
MenuDataItem
};
breadcrumbNameMap
:
{
[
path
:
string
]:
MenuDataItem
;
};
};
/**
* use Authorized check all menu item
*/
const
menuDataRender
=
(
menuList
:
MenuDataItem
[]):
MenuDataItem
[]
=>
{
return
menuList
.
map
(
item
=>
{
const
localItem
=
{
...
item
,
children
:
item
.
children
?
menuDataRender
(
item
.
children
)
:
[],
};
const
localItem
=
{
...
item
,
children
:
item
.
children
?
menuDataRender
(
item
.
children
)
:
[]
};
return
Authorized
.
check
(
item
.
authority
,
localItem
,
null
)
as
MenuDataItem
;
});
};
...
...
@@ -44,57 +39,52 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
/**
* constructor
*/
useState
(()
=>
{
dispatch
!
({
type
:
'
user/fetchCurrent
'
});
dispatch
!
({
type
:
'
settings/getSetting
'
});
dispatch
!
({
type
:
'
user/fetchCurrent
'
,
});
dispatch
!
({
type
:
'
settings/getSetting
'
,
});
});
/**
* init variables
*/
const
handleMenuCollapse
=
(
payload
:
boolean
)
=>
dispatch
!
({
type
:
'
global/changeLayoutCollapsed
'
,
payload
});
dispatch
!
({
type
:
'
global/changeLayoutCollapsed
'
,
payload
,
});
return
(
<>
<
BasicLayoutComponents
logo
=
{
logo
}
onCollapse
=
{
handleMenuCollapse
}
menuItemRender
=
{
(
menuItemProps
,
defaultDom
)
=>
{
return
<
Link
to
=
{
menuItemProps
.
path
}
>
{
defaultDom
}
</
Link
>;
}
}
breadcrumbRender
=
{
(
routers
=
[])
=>
{
return
[
{
path
:
'
/
'
,
breadcrumbName
:
formatMessage
({
id
:
'
menu.home
'
,
defaultMessage
:
'
Home
'
,
}),
},
...
routers
,
];
}
}
menuDataRender
=
{
menuDataRender
}
formatMessage
=
{
formatMessage
}
rightContentRender
=
{
rightProps
=>
<
RightContent
{
...
rightProps
}
/>
}
{
...
props
}
{
...
settings
}
>
{
children
}
</
BasicLayoutComponents
>
{
isAntDesignProOrDev
()
&&
(
<
SettingDrawer
settings
=
{
settings
}
onSettingChange
=
{
config
=>
dispatch
!
({
type
:
'
settings/changeSetting
'
,
payload
:
config
,
})
}
/>
)
}
{
isAntDesignProOrDev
()
&&
<
CopyBlock
url
=
{
location
!
.
pathname
}
/>
}
</>
<
BasicLayoutComponents
logo
=
{
logo
}
onCollapse
=
{
handleMenuCollapse
}
menuItemRender
=
{
(
menuItemProps
,
defaultDom
)
=>
{
return
<
Link
to
=
{
menuItemProps
.
path
}
>
{
defaultDom
}
</
Link
>;
}
}
breadcrumbRender
=
{
(
routers
=
[])
=>
{
return
[
{
path
:
'
/
'
,
breadcrumbName
:
formatMessage
({
id
:
'
menu.home
'
,
defaultMessage
:
'
Home
'
,
}),
},
...
routers
,
];
}
}
menuDataRender
=
{
menuDataRender
}
formatMessage
=
{
formatMessage
}
rightContentRender
=
{
rightProps
=>
<
RightContent
{
...
rightProps
}
/>
}
{
...
props
}
{
...
settings
}
>
{
children
}
</
BasicLayoutComponents
>
);
};
...
...
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