kn-cli 1.0.44 → 1.0.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/readme.md +3 -0
- package/src/utils/index.js +1 -1
- package/templates/template_admin/.gitignore +6 -0
- package/templates/template_admin/build.sh +2 -0
- package/templates/template_admin/cli.config.js +21 -0
- package/templates/template_admin/dev.sh +89 -0
- package/templates/template_admin/frontend_build.sh +83 -0
- package/templates/template_admin/init/prepare-commit-msg +5 -0
- package/templates/template_admin/init.sh +33 -0
- package/templates/template_admin/package.json +23 -0
- package/templates/template_admin/public/404.html +26 -0
- package/templates/template_admin/public/favicon.ico +0 -0
- package/templates/template_admin/public/favicon.png +0 -0
- package/templates/template_admin/public/index.html +43 -0
- package/templates/template_admin/public/src/_antd.less +4 -0
- package/templates/template_admin/public/src/_reset.less +128 -0
- package/templates/template_admin/public/src/_variable.less +80 -0
- package/templates/template_admin/public/src/assets/iconfont/iconfont.eot +0 -0
- package/templates/template_admin/public/src/assets/iconfont/iconfont.less +57 -0
- package/templates/template_admin/public/src/assets/iconfont/iconfont.svg +36 -0
- package/templates/template_admin/public/src/assets/iconfont/iconfont.ttf +0 -0
- package/templates/template_admin/public/src/assets/iconfont/iconfont.woff +0 -0
- package/templates/template_admin/public/src/assets/iconfont/iconfont.woff2 +0 -0
- package/templates/template_admin/public/src/assets/images/avatar.png +0 -0
- package/templates/template_admin/public/src/assets/images/loading.svg +40 -0
- package/templates/template_admin/public/src/components/Alert/index.jsx +0 -0
- package/templates/template_admin/public/src/components/Alert/index.less +0 -0
- package/templates/template_admin/public/src/components/Auth/index.jsx +44 -0
- package/templates/template_admin/public/src/components/Header/index.jsx +57 -0
- package/templates/template_admin/public/src/components/Header/index.less +57 -0
- package/templates/template_admin/public/src/components/IconFont/index.jsx +10 -0
- package/templates/template_admin/public/src/components/IconFont/index.less +5 -0
- package/templates/template_admin/public/src/components/Layout/Basic/index.jsx +26 -0
- package/templates/template_admin/public/src/components/Layout/Basic/index.less +37 -0
- package/templates/template_admin/public/src/components/Layout/CenterBody/index.jsx +15 -0
- package/templates/template_admin/public/src/components/Layout/CenterBody/index.less +30 -0
- package/templates/template_admin/public/src/components/Layout/Provider/index.jsx +12 -0
- package/templates/template_admin/public/src/components/Layout/index.jsx +27 -0
- package/templates/template_admin/public/src/components/Layout/index.less +63 -0
- package/templates/template_admin/public/src/components/Link/index.jsx +24 -0
- package/templates/template_admin/public/src/components/Link/index.less +11 -0
- package/templates/template_admin/public/src/components/Loading/index.jsx +14 -0
- package/templates/template_admin/public/src/components/Loading/index.less +85 -0
- package/templates/template_admin/public/src/components/Menu/index.jsx +126 -0
- package/templates/template_admin/public/src/components/Menu/index.less +19 -0
- package/templates/template_admin/public/src/components/Page/PageLoading/index.jsx +30 -0
- package/templates/template_admin/public/src/components/Page/PageLoading/index.less +29 -0
- package/templates/template_admin/public/src/components/Popup/index.jsx +22 -0
- package/templates/template_admin/public/src/components/Popup/index.less +18 -0
- package/templates/template_admin/public/src/components/Toast/index.jsx +60 -0
- package/templates/template_admin/public/src/components/Toast/index.less +43 -0
- package/templates/template_admin/public/src/components/TopMenu/index.jsx +228 -0
- package/templates/template_admin/public/src/components/TopMenu/index.less +105 -0
- package/templates/template_admin/public/src/components/mask/index.jsx +47 -0
- package/templates/template_admin/public/src/components/mask/index.less +32 -0
- package/templates/template_admin/public/src/dictionary/index.js +103 -0
- package/templates/template_admin/public/src/hooks/index.jsx +18 -0
- package/templates/template_admin/public/src/hooks/useDelay.jsx +29 -0
- package/templates/template_admin/public/src/hooks/useImageLoader.jsx +27 -0
- package/templates/template_admin/public/src/hooks/useLoading.jsx +42 -0
- package/templates/template_admin/public/src/hooks/useLogin.jsx +33 -0
- package/templates/template_admin/public/src/hooks/useNextPage.jsx +89 -0
- package/templates/template_admin/public/src/hooks/usePreload.jsx +66 -0
- package/templates/template_admin/public/src/hooks/useScrollTop.jsx +32 -0
- package/templates/template_admin/public/src/hooks/useSearch.jsx +137 -0
- package/templates/template_admin/public/src/hooks/useUpdate.jsx +11 -0
- package/templates/template_admin/public/src/index.jsx +50 -0
- package/templates/template_admin/public/src/mock/auth.js +91 -0
- package/templates/template_admin/public/src/mock/index.js +63 -0
- package/templates/template_admin/public/src/mock/user.js +70 -0
- package/templates/template_admin/public/src/mock/utils.js +33 -0
- package/templates/template_admin/public/src/pages/checkLogin/index.jsx +13 -0
- package/templates/template_admin/public/src/pages/index.jsx +23 -0
- package/templates/template_admin/public/src/pages/index.less +22 -0
- package/templates/template_admin/public/src/pages/login/index.jsx +27 -0
- package/templates/template_admin/public/src/pages/login/index.less +44 -0
- package/templates/template_admin/public/src/pages/material/index.jsx +12 -0
- package/templates/template_admin/public/src/pages/order/index.jsx +12 -0
- package/templates/template_admin/public/src/pages/permission/index.jsx +12 -0
- package/templates/template_admin/public/src/pages/subHome/index.jsx +12 -0
- package/templates/template_admin/public/src/pages/subHome2/index.jsx +12 -0
- package/templates/template_admin/public/src/pages/subHome3/index.jsx +12 -0
- package/templates/template_admin/public/src/pages/suggest/index.jsx +12 -0
- package/templates/template_admin/public/src/pages/superAdminLogin/index.jsx +57 -0
- package/templates/template_admin/public/src/pages/superAdminLogin/index.less +44 -0
- package/templates/template_admin/public/src/pages/user/index.jsx +13 -0
- package/templates/template_admin/public/src/pages/userData/index.jsx +12 -0
- package/templates/template_admin/public/src/pages/video/index.jsx +12 -0
- package/templates/template_admin/public/src/provider/app.jsx +119 -0
- package/templates/template_admin/public/src/provider/menu.jsx +20 -0
- package/templates/template_admin/public/src/route.jsx +77 -0
- package/templates/template_admin/public/src/services/auth.js +28 -0
- package/templates/template_admin/public/src/services/index.js +181 -0
- package/templates/template_admin/public/src/services/user.js +26 -0
- package/templates/template_admin/public/src/utils/index.js +38 -0
- package/templates/template_admin/public/static/about.html +1 -0
- package/templates/template_admin/public/static/kssoLogin.html +22 -0
- package/templates/template_admin/readme.md +55 -0
- package/templates/template_admin/report.sh +68 -0
- package/templates/template_admin/tools/iconfont/gulpfile.js +70 -0
- package/templates/template_admin/tools/iconfont/package.json +20 -0
- package/templates/template_admin/tools/iconfont/run.sh +39 -0
- package/templates/template_admin/tools/iconfont/svg/arrowBack.svg +1 -0
- package/templates/template_admin/tools/iconfont/svg/check.svg +1 -0
- package/templates/template_admin/tools/iconfont/svg/close.svg +1 -0
- package/templates/template_admin/tools/iconfont/svg/down.svg +1 -0
- package/templates/template_admin/tools/iconfont/svg/image.svg +1 -0
- package/templates/template_admin/tools/iconfont/svg/play.svg +1 -0
- package/templates/template_admin/tools/iconfont/svg/refresh.svg +1 -0
- package/templates/template_admin/tools/iconfont/svg/warn.svg +1 -0
- package/templates/template_admin/tools/iconfont/templates/_icons.css +26 -0
- package/templates/template_admin/tools/iconfont/templates/_icons.less +29 -0
- package/templates/template_admin/tools/iconfont/templates/index.html +56 -0
- package/templates/template_admin/tools/tinypng/package.json +11 -0
- package/templates/template_admin/tools/tinypng/run.sh +15 -0
- package/templates/template_admin/webpack.api.js +33 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
|
|
2
|
+
import { Menu } from 'antd';
|
|
3
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import {matchPath,useLocation,useNavigate,} from 'react-router-dom';
|
|
5
|
+
import { AppstoreOutlined, MailOutlined, SettingOutlined } from '@ant-design/icons';
|
|
6
|
+
import {useDelay,useLoading} from '@/hooks';
|
|
7
|
+
import ProviderMenu from '@/provider/menu';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
import styles from './index.less';
|
|
11
|
+
|
|
12
|
+
const ICON_NAME={
|
|
13
|
+
'AppstoreOutlined':<AppstoreOutlined />,
|
|
14
|
+
'MailOutlined':<MailOutlined />,
|
|
15
|
+
'SettingOutlined':<SettingOutlined />,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
const LeftMenu=(props)=>{
|
|
22
|
+
|
|
23
|
+
const providerMenu = ProviderMenu.useContainer();
|
|
24
|
+
const delay = useDelay();
|
|
25
|
+
const loader = useLoading();
|
|
26
|
+
const [menus,setMenus] = useState([]);
|
|
27
|
+
const [openKeys,setOpenKeys] = useState([]);
|
|
28
|
+
const [selectedKeys,setSelectKeys] = useState([]);
|
|
29
|
+
const curRoute = useLocation();
|
|
30
|
+
const nav = useNavigate();
|
|
31
|
+
|
|
32
|
+
const MENU_KEY_COUNTER=useRef(1);
|
|
33
|
+
const MENU_KEY=useRef({});
|
|
34
|
+
const translateMenu=(data={},parent)=>{
|
|
35
|
+
const {label,icon,children,path}= data;
|
|
36
|
+
let myKey = `${MENU_KEY_COUNTER.current}`
|
|
37
|
+
let item ={
|
|
38
|
+
key:myKey,
|
|
39
|
+
label:`${label}`,
|
|
40
|
+
source:data,
|
|
41
|
+
path,
|
|
42
|
+
routepath:parent?`${parent.key}-${myKey}`:myKey
|
|
43
|
+
}
|
|
44
|
+
MENU_KEY.current[myKey] = item;
|
|
45
|
+
MENU_KEY_COUNTER.current++;
|
|
46
|
+
if(icon){
|
|
47
|
+
item.icon= ICON_NAME[icon];
|
|
48
|
+
}
|
|
49
|
+
if(children){
|
|
50
|
+
item.children = children.map(childData=>{
|
|
51
|
+
return translateMenu(childData,item)
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
return item;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
window.matchPath=matchPath;
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
const GET_ROUTE_MENU=(menuList)=>{
|
|
62
|
+
let groupKeys=[];
|
|
63
|
+
for(let key in menuList){
|
|
64
|
+
const menuItem = menuList[key];
|
|
65
|
+
const {path,routeTemplate}= menuItem.source;
|
|
66
|
+
if(path){
|
|
67
|
+
let fn = matchPath;
|
|
68
|
+
let match= fn(routeTemplate||path,curRoute.pathname);
|
|
69
|
+
if(match){
|
|
70
|
+
groupKeys = menuItem.routepath?menuItem.routepath.split('-'):'';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return groupKeys;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const loadMenu= ()=>{
|
|
78
|
+
loader.setLoading(true);
|
|
79
|
+
if(providerMenu.menus){
|
|
80
|
+
const menuList= providerMenu.menus.map(menu=>{
|
|
81
|
+
return translateMenu(menu)
|
|
82
|
+
})
|
|
83
|
+
setMenus(menuList);
|
|
84
|
+
}else{
|
|
85
|
+
setMenus([]);
|
|
86
|
+
}
|
|
87
|
+
loader.setLoading(false);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
useEffect(()=>{
|
|
91
|
+
loadMenu();
|
|
92
|
+
},[providerMenu])
|
|
93
|
+
|
|
94
|
+
useEffect(()=>{
|
|
95
|
+
let groupKeys= GET_ROUTE_MENU(MENU_KEY.current);
|
|
96
|
+
setOpenKeys(groupKeys);
|
|
97
|
+
let selectKey =groupKeys[groupKeys.length-1];
|
|
98
|
+
setSelectKeys([selectKey])
|
|
99
|
+
},[curRoute,menus]);
|
|
100
|
+
|
|
101
|
+
const onClickMenuItem=(e)=>{
|
|
102
|
+
const { item, key, keyPath, domEvent } = e;
|
|
103
|
+
const menuData = MENU_KEY.current[key];
|
|
104
|
+
if(menuData.path){
|
|
105
|
+
nav(menuData.path);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const onOpenChange=(keys)=>{
|
|
109
|
+
setOpenKeys(keys);
|
|
110
|
+
}
|
|
111
|
+
return (
|
|
112
|
+
<section className={styles.nav}>
|
|
113
|
+
<Menu
|
|
114
|
+
theme='dark'
|
|
115
|
+
selectedKeys={selectedKeys}
|
|
116
|
+
openKeys={openKeys}
|
|
117
|
+
onOpenChange={onOpenChange}
|
|
118
|
+
onClick={onClickMenuItem}
|
|
119
|
+
mode="inline"
|
|
120
|
+
items={loader.loading?[]:menus}
|
|
121
|
+
/>
|
|
122
|
+
</section>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export default LeftMenu;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
@import '~@/_variable.less';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
.nav{
|
|
5
|
+
width: var(--nav-width);
|
|
6
|
+
height:100%;
|
|
7
|
+
background-color: var(--color-primary-dark);
|
|
8
|
+
transition: all .2s;
|
|
9
|
+
z-index: var(--z-nav-mobile);
|
|
10
|
+
overflow-y: auto;
|
|
11
|
+
&[data-nav-hide='true']{
|
|
12
|
+
display: none;
|
|
13
|
+
}
|
|
14
|
+
&[data-nav-mode='mobile']{
|
|
15
|
+
position: fixed;
|
|
16
|
+
z-index: var(--z-nav-mobile);
|
|
17
|
+
box-shadow: 0 0 20px #444;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React,{useEffect, useState} from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import CSS from './index.less';
|
|
4
|
+
import Popup from '@/components/Popup';
|
|
5
|
+
import imgLoading from '@/assets/images/loading.svg';
|
|
6
|
+
|
|
7
|
+
const PageLoading = (props) => {
|
|
8
|
+
const {visible=true} = props;
|
|
9
|
+
if(!visible){
|
|
10
|
+
return '';
|
|
11
|
+
}
|
|
12
|
+
return (
|
|
13
|
+
<div className={CSS.wrap } >
|
|
14
|
+
<div className={CSS.box} data-show={visible}>
|
|
15
|
+
<img src={imgLoading} />
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const ShowPageLoading=(props={canTouch:false})=>{
|
|
22
|
+
let popup = Popup(()=>{},{cantouch:props.canTouch});
|
|
23
|
+
ReactDOM.render(
|
|
24
|
+
<PageLoading visible={true} />,
|
|
25
|
+
popup.dom
|
|
26
|
+
);
|
|
27
|
+
return popup.destory;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default React.memo(PageLoading);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
.wrap {
|
|
2
|
+
position: fixed;
|
|
3
|
+
width: 100%;
|
|
4
|
+
height: 100%;
|
|
5
|
+
left: 0;
|
|
6
|
+
top: 0;
|
|
7
|
+
z-index: 99;
|
|
8
|
+
display: flex;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
align-items: center;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.box {
|
|
14
|
+
|
|
15
|
+
width: 80px;
|
|
16
|
+
height: 80px;
|
|
17
|
+
background: rgba(0,0,0,.3);
|
|
18
|
+
border-radius: 12px;
|
|
19
|
+
display: flex;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
align-items: center;
|
|
22
|
+
img{
|
|
23
|
+
display: block;
|
|
24
|
+
width:80%;
|
|
25
|
+
}
|
|
26
|
+
&[data-show=false]{
|
|
27
|
+
opacity: 0;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import styles from './index.less';
|
|
4
|
+
styles;
|
|
5
|
+
|
|
6
|
+
const Popup = (reslove,options) => {
|
|
7
|
+
let rootDom = document.createElement('div');
|
|
8
|
+
rootDom.className='popup-box';
|
|
9
|
+
if(options&&options.cantouch)rootDom.setAttribute('data-can-touch','1');
|
|
10
|
+
if(options&&options.transparent)rootDom.setAttribute('data-transparent','1');
|
|
11
|
+
|
|
12
|
+
let destory = (result) => {
|
|
13
|
+
ReactDOM.unmountComponentAtNode(rootDom);
|
|
14
|
+
rootDom.parentNode.removeChild(rootDom);
|
|
15
|
+
if (reslove) reslove(result);
|
|
16
|
+
};
|
|
17
|
+
document.body.appendChild(rootDom);
|
|
18
|
+
return { dom: rootDom, destory };
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
export default Popup;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React,{useEffect} from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import styles from './index.less';
|
|
4
|
+
import Popup from '@/components/Popup/index.jsx';
|
|
5
|
+
|
|
6
|
+
const toastList=[];
|
|
7
|
+
const runNext=()=>{
|
|
8
|
+
let props = toastList[0];
|
|
9
|
+
if(props){
|
|
10
|
+
const {message,delay,resolve,position}=props;
|
|
11
|
+
let popup = Popup(resolve,{cantouch:true});
|
|
12
|
+
ReactDOM.render(
|
|
13
|
+
<Toast destory={popup.destory} message={message} delay={delay} position={position}/>,
|
|
14
|
+
popup.dom
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const Toast=props=>{
|
|
20
|
+
const {
|
|
21
|
+
message,
|
|
22
|
+
delay=1000*2,
|
|
23
|
+
destory,
|
|
24
|
+
position='top'
|
|
25
|
+
}=props;
|
|
26
|
+
useEffect(()=>{
|
|
27
|
+
setTimeout(()=>{
|
|
28
|
+
destory();
|
|
29
|
+
toastList.shift();
|
|
30
|
+
runNext();
|
|
31
|
+
},delay);
|
|
32
|
+
},[])
|
|
33
|
+
const ANITYPE={
|
|
34
|
+
'center':'animate__slideInDown',
|
|
35
|
+
'top':'animate__slideInDown',
|
|
36
|
+
'bottom':'animate__slideInUp'
|
|
37
|
+
}
|
|
38
|
+
return (
|
|
39
|
+
<section className={styles.wrap} data-position={position}>
|
|
40
|
+
<div className={styles.content+ ` ${ANITYPE[position]} animate__animated animate__fast`} dangerouslySetInnerHTML={{ __html:message }}>
|
|
41
|
+
</div>
|
|
42
|
+
</section>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
const ShowToast=props=>{
|
|
48
|
+
if(typeof props === 'string'){
|
|
49
|
+
props = {message:props}
|
|
50
|
+
}
|
|
51
|
+
return new Promise((resolve) => {
|
|
52
|
+
props.resolve = resolve;
|
|
53
|
+
toastList.push(props);
|
|
54
|
+
if(toastList.length===1){
|
|
55
|
+
runNext();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default ShowToast;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
@import '~@/_variable.less';
|
|
2
|
+
|
|
3
|
+
.wrap{
|
|
4
|
+
position: fixed;
|
|
5
|
+
left:0;
|
|
6
|
+
top:0;
|
|
7
|
+
width:100%;
|
|
8
|
+
height:100%;
|
|
9
|
+
pointer-events: none;
|
|
10
|
+
display: flex;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
align-items: center;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
z-index:var(--z-toast);
|
|
15
|
+
&[data-position=top]{
|
|
16
|
+
justify-content: flex-start;
|
|
17
|
+
padding-top:80px;
|
|
18
|
+
}
|
|
19
|
+
&[data-position=bottom]{
|
|
20
|
+
justify-content: flex-end;
|
|
21
|
+
padding-bottom:80px;
|
|
22
|
+
}
|
|
23
|
+
.content{
|
|
24
|
+
min-height:30px;
|
|
25
|
+
min-width:60px;
|
|
26
|
+
|
|
27
|
+
background: rgba(0,0,0,.8);
|
|
28
|
+
opacity:.8;
|
|
29
|
+
border-radius: var(--radius-default);
|
|
30
|
+
padding:var(--padding-default);
|
|
31
|
+
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
align-items: center;
|
|
36
|
+
|
|
37
|
+
font-size: 14px;
|
|
38
|
+
color: #FFFFFF;
|
|
39
|
+
text-shadow: 2px 2px 0px rgba(0, 0, 0, 0.24);
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import React, { useState,useEffect, useRef} from 'react';
|
|
2
|
+
import { matchPath,useLocation,useNavigate } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
import { LogoutOutlined, UserOutlined } from '@ant-design/icons';
|
|
6
|
+
import imgAvatar from '@/assets/images/avatar.png';
|
|
7
|
+
import { Menu,Dropdown } from 'antd'
|
|
8
|
+
import ProviderApp from '@/provider/app';
|
|
9
|
+
import ProviderMenu from '@/provider/menu';
|
|
10
|
+
import styles from './index.less';
|
|
11
|
+
import {GET_MENU} from '@/services/auth';
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 顶部导航栏
|
|
18
|
+
* 左侧导航栏的路由也继顶部导航栏来控制
|
|
19
|
+
* 路由数据结构:
|
|
20
|
+
* const MenuRoute=[
|
|
21
|
+
{
|
|
22
|
+
label:'顶部菜单A',
|
|
23
|
+
path:'/home/sub/1',
|
|
24
|
+
menus:[
|
|
25
|
+
{
|
|
26
|
+
label:'菜单组A-1',
|
|
27
|
+
icon:'MailOutlined',
|
|
28
|
+
children:[
|
|
29
|
+
{label:'菜单组A-1-home',path:'/',},
|
|
30
|
+
{label:'菜单组A-1-sub:id',path:'/home/sub/1',routeTemplate:'/home/sub/:id'},
|
|
31
|
+
{label:'菜单组A-1-sub3:id',path:'/home/sub3/2',routeTemplate:'/home/sub3/:id'},
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
顶部的导航栏结构为{label,path,menus}
|
|
38
|
+
左侧导航栏数据为顶部导航栏数据的menus内子项{label,icon,children}组成
|
|
39
|
+
routeTemplate用来识别动态参数的路由,同前端本地路由配置同步即可
|
|
40
|
+
当顶部导航栏只有一项时,将自动隐藏顶部导航菜单
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
const TopMenu=(props)=>{
|
|
44
|
+
const app = ProviderApp.useContainer();
|
|
45
|
+
const providerMenu = ProviderMenu.useContainer();
|
|
46
|
+
const curRoute = useLocation();
|
|
47
|
+
|
|
48
|
+
const [menus,setMenus]=useState([]);
|
|
49
|
+
const navigate = useNavigate();
|
|
50
|
+
const [selectedKeys,setSelectedKeys] = useState([]);
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
const MENU_KEY_COUNTER=useRef(1);
|
|
54
|
+
const MENU_KEY=useRef({})
|
|
55
|
+
const translateMenu=(data={})=>{
|
|
56
|
+
const {label,path}= data;
|
|
57
|
+
let myKey = `${MENU_KEY_COUNTER.current}`
|
|
58
|
+
let item ={
|
|
59
|
+
key:myKey,
|
|
60
|
+
label:`${label}`,
|
|
61
|
+
path,
|
|
62
|
+
source:data,
|
|
63
|
+
}
|
|
64
|
+
MENU_KEY.current[myKey] = item;
|
|
65
|
+
MENU_KEY_COUNTER.current++;
|
|
66
|
+
return item;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const transServicesMenuChildren=(menu)=>{
|
|
70
|
+
let req=[];
|
|
71
|
+
for(let i=0;i<menu.length;i++){
|
|
72
|
+
let item= menu[i];
|
|
73
|
+
const {url:path,name:label,icon,children:menus}= item;
|
|
74
|
+
let children;
|
|
75
|
+
if(menus&&menus.length>0){
|
|
76
|
+
children= transServicesMenuChildren(menus);
|
|
77
|
+
}
|
|
78
|
+
req.push({
|
|
79
|
+
path,label,icon,children
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
return req;
|
|
83
|
+
}
|
|
84
|
+
const loadMenu=async ()=>{
|
|
85
|
+
const isLogin= await app.isLogin();
|
|
86
|
+
if(!isLogin){
|
|
87
|
+
navigate('/login')
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
let reqMenu = await GET_MENU();
|
|
91
|
+
if(reqMenu?.code==0){
|
|
92
|
+
let originMenu= reqMenu.data;
|
|
93
|
+
reqMenu=[];
|
|
94
|
+
for(let i=0;i<originMenu.length;i++){
|
|
95
|
+
let topMenu= originMenu[i];
|
|
96
|
+
const {url:path,children,name:label}=topMenu;
|
|
97
|
+
const menus = transServicesMenuChildren(children);
|
|
98
|
+
reqMenu.push({
|
|
99
|
+
path,menus,label
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if(!reqMenu){
|
|
104
|
+
setMenus([]);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const data = reqMenu.map(topMenu=>{
|
|
108
|
+
return translateMenu(topMenu);
|
|
109
|
+
})
|
|
110
|
+
setMenus(data);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const GET_ROUTE_MENU=(menu)=>{
|
|
114
|
+
const {routeTemplate,path} = menu;
|
|
115
|
+
const children = menu.children||menu.menus||null;
|
|
116
|
+
if(routeTemplate||path){
|
|
117
|
+
let match= matchPath(routeTemplate||path,curRoute.pathname);
|
|
118
|
+
if(match){
|
|
119
|
+
console.log(`match route: ${routeTemplate||path} -> ${curRoute.pathname}` )
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if(children){
|
|
124
|
+
for(let subMenu of children){
|
|
125
|
+
let match = GET_ROUTE_MENU(subMenu);
|
|
126
|
+
if(match){
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const reloadOpenMenu=()=>{
|
|
135
|
+
for(let menuKey in MENU_KEY.current){
|
|
136
|
+
const topMenu = MENU_KEY.current[menuKey];
|
|
137
|
+
const match= GET_ROUTE_MENU(topMenu.source);
|
|
138
|
+
if(match){
|
|
139
|
+
let changeLeftMenu=false;//是否重新设置左侧导航菜单数据
|
|
140
|
+
if(selectedKeys[0] != menuKey){
|
|
141
|
+
changeLeftMenu= true;
|
|
142
|
+
}
|
|
143
|
+
if(!providerMenu.menus||providerMenu.menus.length<=0){
|
|
144
|
+
changeLeftMenu= true;
|
|
145
|
+
}
|
|
146
|
+
setSelectedKeys([menuKey]);
|
|
147
|
+
if(changeLeftMenu){
|
|
148
|
+
providerMenu.setMenus(topMenu.source.menus);
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
setSelectedKeys([]);
|
|
154
|
+
providerMenu.setMenus([]);
|
|
155
|
+
}
|
|
156
|
+
useEffect(loadMenu,[]);
|
|
157
|
+
|
|
158
|
+
useEffect(()=>{
|
|
159
|
+
reloadOpenMenu();
|
|
160
|
+
},[curRoute,menus]);
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
// 推出登录
|
|
165
|
+
const onAvatarClick = (e)=>{
|
|
166
|
+
if (e?.key === 'logout') {
|
|
167
|
+
app.logout();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const onHome=()=>{
|
|
171
|
+
navigate('/');
|
|
172
|
+
}
|
|
173
|
+
const onClickMenuItem=(e)=>{
|
|
174
|
+
const { item, key, keyPath, domEvent } = e;
|
|
175
|
+
const menuData = MENU_KEY.current[key];
|
|
176
|
+
const {path,source:{menus}} = menuData;
|
|
177
|
+
providerMenu.setMenus(menus);
|
|
178
|
+
if(path){
|
|
179
|
+
navigate(path)
|
|
180
|
+
}
|
|
181
|
+
setSelectedKeys([key])
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<section className={styles.topMenu}>
|
|
186
|
+
<div className={styles.left}>
|
|
187
|
+
<span className={styles.title} onClick={onHome}>后管系统</span>
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
<div className={styles.center}>
|
|
191
|
+
{
|
|
192
|
+
menus&&menus.length>1&&
|
|
193
|
+
<Menu
|
|
194
|
+
items={menus}
|
|
195
|
+
mode="horizontal"
|
|
196
|
+
onClick={onClickMenuItem}
|
|
197
|
+
|
|
198
|
+
selectedKeys={selectedKeys}
|
|
199
|
+
className={styles.menu}
|
|
200
|
+
/>
|
|
201
|
+
}
|
|
202
|
+
</div>
|
|
203
|
+
<div className={styles.right}>
|
|
204
|
+
|
|
205
|
+
<span className={styles.username}>Hi,{app?.user?.username||''}!</span>
|
|
206
|
+
<Dropdown overlay={(
|
|
207
|
+
<Menu onClick={onAvatarClick} className={styles.avatarMenu}>
|
|
208
|
+
<Menu.Item key="user">
|
|
209
|
+
<UserOutlined />
|
|
210
|
+
用户名
|
|
211
|
+
</Menu.Item>
|
|
212
|
+
|
|
213
|
+
<Menu.Item key="logout">
|
|
214
|
+
<LogoutOutlined />
|
|
215
|
+
退出登录
|
|
216
|
+
</Menu.Item>
|
|
217
|
+
</Menu>
|
|
218
|
+
)}>
|
|
219
|
+
<img className={styles.avatar} src={imgAvatar}/>
|
|
220
|
+
</Dropdown>
|
|
221
|
+
|
|
222
|
+
</div>
|
|
223
|
+
|
|
224
|
+
</section>
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export default TopMenu;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
@import '~@/_variable.less';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
.topMenu{
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
justify-content: space-between;
|
|
8
|
+
height: var(--topMenu-height);
|
|
9
|
+
width:100%;
|
|
10
|
+
z-index:var(--z-top-menu);
|
|
11
|
+
background-color: var(--color-primary-dark);
|
|
12
|
+
.left{
|
|
13
|
+
padding-left: 16px;
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
width: var(--nav-width);
|
|
17
|
+
.logo{
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
width: 110px;
|
|
20
|
+
height: 32px;
|
|
21
|
+
margin-right: 7px;
|
|
22
|
+
color:white;
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
font-size: 32px;
|
|
26
|
+
}
|
|
27
|
+
.title {
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
color: #fff;
|
|
30
|
+
font-size: 16px;
|
|
31
|
+
padding: 0 55px 0 7px;
|
|
32
|
+
font-weight: var(--weight-Light);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
.center{
|
|
36
|
+
height: 100%;
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
flex:1;
|
|
40
|
+
}
|
|
41
|
+
.right{
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
flex:1;
|
|
45
|
+
justify-content: flex-end;
|
|
46
|
+
.username{
|
|
47
|
+
color:white;
|
|
48
|
+
}
|
|
49
|
+
.avatar{
|
|
50
|
+
width: 40px;
|
|
51
|
+
height: 40px;
|
|
52
|
+
border-radius: 50%;
|
|
53
|
+
margin: 0 24px 0 24px;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.menu:global(.ant-menu){
|
|
58
|
+
line-height: var(--topMenu-height);
|
|
59
|
+
background-color: inherit;
|
|
60
|
+
border-bottom: none;
|
|
61
|
+
flex:1;
|
|
62
|
+
// min-width: 100px;
|
|
63
|
+
|
|
64
|
+
:global{
|
|
65
|
+
.ant-menu-item,
|
|
66
|
+
.ant-menu-item a{
|
|
67
|
+
color:rgba(104,114,126,1);
|
|
68
|
+
font-weight: var(--weight-Medium);
|
|
69
|
+
}
|
|
70
|
+
.ant-menu-item:hover a,
|
|
71
|
+
.ant-menu-item:hover,
|
|
72
|
+
.ant-menu-item-selected a{
|
|
73
|
+
color: rgba(255,255,255,.8);
|
|
74
|
+
}
|
|
75
|
+
.ant-menu-item-selected{
|
|
76
|
+
color: white;
|
|
77
|
+
}
|
|
78
|
+
.ant-menu-item:hover:after,
|
|
79
|
+
.ant-menu-item-selected:after{
|
|
80
|
+
border-bottom: 2px solid #fff;
|
|
81
|
+
}
|
|
82
|
+
.ant-menu-item{
|
|
83
|
+
padding: 0 24px;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
.avatarMenu{
|
|
89
|
+
min-width: 100px;
|
|
90
|
+
:global(.anticon) {
|
|
91
|
+
margin-right: 8px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
:global(.ant-dropdown-menu-item) {
|
|
95
|
+
min-width: 100px;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.navShow{
|
|
100
|
+
font-size: 26px;
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
&:hover{
|
|
103
|
+
color: var(--color-text-hover);
|
|
104
|
+
}
|
|
105
|
+
}
|