kn-cli 1.0.92 → 1.0.94
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 +1 -1
- package/templates/template_admin/public/index.html +5 -2
- package/templates/template_admin/public/src/_antd.less +7 -1
- package/templates/template_admin/public/src/assets/images/avatars/1.png +0 -0
- package/templates/template_admin/public/src/assets/images/avatars/2.png +0 -0
- package/templates/template_admin/public/src/assets/images/avatars/3.png +0 -0
- package/templates/template_admin/public/src/components/layout/basic/index.less +3 -3
- package/templates/template_admin/public/src/components/menu/index.jsx +47 -100
- package/templates/template_admin/public/src/components/menu/topMenu/index.jsx +129 -0
- package/templates/template_admin/public/src/components/table/index.jsx +62 -0
- package/templates/template_admin/public/src/dictionary/index.js +49 -4
- package/templates/template_admin/public/src/hooks/index.jsx +4 -1
- package/templates/template_admin/public/src/hooks/useRouteMenu.jsx +232 -0
- package/templates/template_admin/public/src/mock/demo.js +177 -0
- package/templates/template_admin/public/src/mock/index.js +5 -2
- package/templates/template_admin/public/src/pages/demo/detail/index.jsx +27 -0
- package/templates/template_admin/public/src/pages/demo/edit/index.jsx +109 -0
- package/templates/template_admin/public/src/pages/demo/index.less +9 -0
- package/templates/template_admin/public/src/pages/demo/page1.jsx +161 -0
- package/templates/template_admin/public/src/pages/login/index.jsx +5 -4
- package/templates/template_admin/public/src/pages/superAdminLogin/index.jsx +9 -2
- package/templates/template_admin/public/src/provider/app.jsx +18 -8
- package/templates/template_admin/public/src/provider/menu.jsx +146 -10
- package/templates/template_admin/public/src/route.jsx +21 -18
- package/templates/template_admin/public/src/services/demo.js +54 -0
- package/templates/template_admin/public/src/services/index.js +9 -0
- package/templates/template_admin/public/src/utils/format.js +51 -0
- package/templates/template_admin/public/src/utils/rule.js +274 -0
- package/templates/template_admin/readme.md +4 -0
- package/templates/template_admin/public/src/components/topMenu/index.jsx +0 -267
- package/templates/template_admin/public/src/mock/auth.js +0 -91
- package/templates/template_admin/public/src/mock/user.js +0 -70
- package/templates/template_admin/public/src/pages/material/index.jsx +0 -84
- package/templates/template_admin/public/src/pages/order/index.jsx +0 -12
- package/templates/template_admin/public/src/pages/permission/index.jsx +0 -12
- package/templates/template_admin/public/src/pages/suggest/index.jsx +0 -12
- package/templates/template_admin/public/src/pages/user/index.jsx +0 -18
- package/templates/template_admin/public/src/pages/userData/index.jsx +0 -12
- package/templates/template_admin/public/src/pages/video/index.jsx +0 -65
- package/templates/template_admin/public/src/services/auth.js +0 -28
- package/templates/template_admin/public/src/services/user.js +0 -26
- package/templates/template_admin/public/src/services/video.js +0 -33
- /package/templates/template_admin/public/src/components/{topMenu → menu/topMenu}/index.less +0 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
//必填
|
|
2
|
+
const rule_required = { validator: async (rule,value)=>{
|
|
3
|
+
if(value===null||value===undefined||value===Number.NaN){
|
|
4
|
+
throw new Error('请填写');
|
|
5
|
+
}
|
|
6
|
+
if(!/\S+/.test(value)){
|
|
7
|
+
throw new Error('请填写');
|
|
8
|
+
}
|
|
9
|
+
return true;
|
|
10
|
+
}, message: '请填写' };
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
//整数
|
|
14
|
+
const rule_number = { pattern: /^\d*$/, message: '请填写整数数字' };
|
|
15
|
+
//可以带小数
|
|
16
|
+
const rule_float = {
|
|
17
|
+
pattern: /^([1-9]\d*$|\d+[.]\d{1,5}$)|0$/,
|
|
18
|
+
message: '请填写数字可以带小数,小数点后最长5位',
|
|
19
|
+
};
|
|
20
|
+
// pattern:/^\d+[.]{0,1}\d+$/};
|
|
21
|
+
|
|
22
|
+
const rule_xss = {
|
|
23
|
+
validator: async (rule, value) => {
|
|
24
|
+
if (/<script>/gi.test(value) || /%3Cscript/gi.test(value)) {
|
|
25
|
+
throw new Error('不能包含<script>');
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
},
|
|
29
|
+
message: '不能包含<script>',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const rule_max_title = { max: 32, message: '长度不能超过32位' };
|
|
33
|
+
const rule_max_normal = { max: 128, message: '长度不能超过128位'};
|
|
34
|
+
const rule_max_textarea = { max: 20480, message: '长度不能超过20480位' };
|
|
35
|
+
const rule_max_number = { pattern: /^\d{0,12}$/, message: '长度不能超过12位' };
|
|
36
|
+
const rule_max_weight = { pattern: /^\d{0,4}$/, message: '长度不能超过4位' };
|
|
37
|
+
const rule_max_numberStr = { pattern: /^\S{0,13}$/, message: '长度不能超过12位' };
|
|
38
|
+
|
|
39
|
+
const RULE_INPUT = [rule_required, rule_max_normal];
|
|
40
|
+
const RULE_INPUT_NR = [rule_max_normal];
|
|
41
|
+
|
|
42
|
+
const RULE_TITLE = [rule_required, rule_max_title];
|
|
43
|
+
const RULE_TEXTAREA = [rule_required, rule_max_textarea];
|
|
44
|
+
const RULE_INPUT_NUMBER = [rule_required, rule_number, rule_max_number];
|
|
45
|
+
const RULE_INPUT_NUMBER_NR = [rule_number, rule_max_number];
|
|
46
|
+
const RULE_INPUT_FLOAT = [rule_required, rule_float, rule_max_numberStr];
|
|
47
|
+
|
|
48
|
+
const RULE_INPUT_WEIGHT_NUMBER = [rule_required, rule_number, rule_max_weight];
|
|
49
|
+
const RULE_INPUT_WEIGHT_NUMBER_NR = [rule_number, rule_max_weight];
|
|
50
|
+
|
|
51
|
+
const RULE_SELECT = [{ required: true, message: '请选择' }];
|
|
52
|
+
const RULE_UPLOAD = [{ required: true, message: '请上传' }];
|
|
53
|
+
const rule_max_link = { max: 1024, message: '长度不能超过1024位' };
|
|
54
|
+
|
|
55
|
+
const RULE_LINK = [rule_required, rule_max_link];
|
|
56
|
+
const RULE_LINK_NR = [rule_max_link];
|
|
57
|
+
|
|
58
|
+
const rule_pwd = {
|
|
59
|
+
pattern: /^\w{6,16}$/,
|
|
60
|
+
type: 'string',
|
|
61
|
+
message: '请输入6-16位字母、下划线、数字任意组合的字符',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const RULE_PWD = [rule_required, rule_pwd];
|
|
65
|
+
const RULE_PWD_NR = [rule_pwd];
|
|
66
|
+
|
|
67
|
+
const rule_account = {
|
|
68
|
+
pattern: /^\w{1,12}$/,
|
|
69
|
+
type: 'string',
|
|
70
|
+
message: '请输入1-12位字母、下划线、数字任意组合的字符',
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const RULE_ACCOUNT = [rule_required, rule_account];
|
|
74
|
+
const RULE_ACCOUNT_NR = [rule_account];
|
|
75
|
+
|
|
76
|
+
const rule_nickname = {
|
|
77
|
+
pattern: /^[\u4E00-\u9FA5A-Za-z0-9`~!@#$%^&*()_\-+=<>?:"{}|,.\/;'\\[\]·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘',。、]{2,16}$/,
|
|
78
|
+
message: '请输入2-16为可见字符',
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const RULE_NICKNAME = [rule_required, rule_nickname];
|
|
82
|
+
|
|
83
|
+
const RULE_NICKNAME_NR = [rule_nickname];
|
|
84
|
+
|
|
85
|
+
const rule_phone = { pattern: /^1\d{10}$/, message: '请输入正确的手机格式' };
|
|
86
|
+
const RULE_PHONE_NR = [rule_phone];
|
|
87
|
+
const RULE_PHONE = [rule_required, rule_phone];
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
export const CUSTOM={
|
|
91
|
+
INPUT:(options)=>{
|
|
92
|
+
const {required=true,max=false,min=false,noSpace=false} = options;
|
|
93
|
+
let ret=[];
|
|
94
|
+
if(required){ret.push(rule_required)}
|
|
95
|
+
|
|
96
|
+
if(noSpace){
|
|
97
|
+
ret.push({
|
|
98
|
+
validator:async (rule,value='')=>{
|
|
99
|
+
let temp = value.trim();
|
|
100
|
+
if (/\s+/g.test(temp)) {
|
|
101
|
+
throw new Error('字符串中间不能包含空格');
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
104
|
+
},
|
|
105
|
+
message:`字符串中间不能包含空格`
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
if(max===false){
|
|
109
|
+
ret.push(rule_max_normal);
|
|
110
|
+
}else{
|
|
111
|
+
ret.push({
|
|
112
|
+
validator:async (rule,value='')=>{
|
|
113
|
+
let temp = value.trim();
|
|
114
|
+
if(temp.length <= max) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
throw new Error(`最多不能超过${max}个字`);
|
|
118
|
+
},
|
|
119
|
+
message:`最多不能超过${max}个字`
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
if(min){
|
|
123
|
+
ret.push({
|
|
124
|
+
validator:async (rule,value='')=>{
|
|
125
|
+
let temp = value.trim();
|
|
126
|
+
if (temp.length>=min) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
throw new Error(`最少需要${min}个字`);
|
|
130
|
+
},
|
|
131
|
+
message:`最少需要${min}个字`
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
return ret;
|
|
135
|
+
},
|
|
136
|
+
NUMBER:(options)=>{
|
|
137
|
+
const {required=true,max=false,min=false} = options;
|
|
138
|
+
let ret=[];
|
|
139
|
+
if(required){ret.push(rule_required)}
|
|
140
|
+
if(max){
|
|
141
|
+
ret.push({
|
|
142
|
+
validator:async (rule,value='')=>{
|
|
143
|
+
if ( +value <= max ) {
|
|
144
|
+
return true
|
|
145
|
+
}
|
|
146
|
+
throw new Error(`数值必须小于${max}`);
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
if(min){
|
|
151
|
+
ret.push({
|
|
152
|
+
validator:async (rule,value='')=>{
|
|
153
|
+
if ( +value >= min ) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
throw new Error(`数值必须大于${min}`);
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
return ret;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const list = {
|
|
165
|
+
INPUT: RULE_INPUT,
|
|
166
|
+
INPUT_NR: RULE_INPUT_NR,
|
|
167
|
+
SELECT: RULE_SELECT,
|
|
168
|
+
UPLOAD: RULE_UPLOAD,
|
|
169
|
+
TEXTAREA: RULE_TEXTAREA,
|
|
170
|
+
NUMBER: RULE_INPUT_NUMBER,
|
|
171
|
+
NUMBER_NR: RULE_INPUT_NUMBER_NR,
|
|
172
|
+
TITLE: RULE_TITLE,
|
|
173
|
+
FLOAT: RULE_INPUT_FLOAT,
|
|
174
|
+
LINK: RULE_LINK,
|
|
175
|
+
LINK_NR: RULE_LINK_NR,
|
|
176
|
+
PWD: RULE_PWD,
|
|
177
|
+
PWD_NR: RULE_PWD_NR,
|
|
178
|
+
ACCOUNT: RULE_ACCOUNT,
|
|
179
|
+
ACCOUNT_NR: RULE_ACCOUNT_NR,
|
|
180
|
+
NICKNAME: RULE_NICKNAME,
|
|
181
|
+
NICKNAME_NR: RULE_NICKNAME_NR,
|
|
182
|
+
PHONE: RULE_PHONE,
|
|
183
|
+
PHONE_NR: RULE_PHONE_NR,
|
|
184
|
+
WEIGHT: RULE_INPUT_WEIGHT_NUMBER,
|
|
185
|
+
WEIGHT_NR: RULE_INPUT_WEIGHT_NUMBER_NR,
|
|
186
|
+
};
|
|
187
|
+
Object.keys(list).forEach((key) => {
|
|
188
|
+
const rule = list[key];
|
|
189
|
+
list[key] = [rule_xss, ...rule];
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
export const validate=async (value,rules)=>{
|
|
194
|
+
for(let i=0;i<rules.length;i++){
|
|
195
|
+
let rule = rules[i];
|
|
196
|
+
let type =rule.type||'string';
|
|
197
|
+
let pattern = rule.pattern||'';
|
|
198
|
+
|
|
199
|
+
let numberValue;
|
|
200
|
+
let textValue;
|
|
201
|
+
if(type=='number'){
|
|
202
|
+
numberValue = Number(value);
|
|
203
|
+
}else{
|
|
204
|
+
textValue= `${value}`.trim();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if(pattern){
|
|
208
|
+
if(!pattern.test(value)){
|
|
209
|
+
return {success:false,message:rule.message};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// 必填
|
|
213
|
+
if(rule.required){
|
|
214
|
+
pattern = /\S+/
|
|
215
|
+
if(!pattern.test(textValue)){
|
|
216
|
+
return {success:false,message:rule.message};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// 字符长度
|
|
220
|
+
if(rule.len && type == 'string'){
|
|
221
|
+
pattern = `^.{${rule.len}}$`;
|
|
222
|
+
pattern = new RegExp(pattern);
|
|
223
|
+
if(!pattern.test(textValue)){
|
|
224
|
+
return {success:false,message:rule.message};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if(rule.max){
|
|
229
|
+
if(type=='number'){ // 最大数值
|
|
230
|
+
if(numberValue > +rule.max){
|
|
231
|
+
return {success:false,message:rule.message};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
else if(type=='string'){ // 最大字符串长度
|
|
235
|
+
pattern = `^.{0,${rule.max}}$`;
|
|
236
|
+
pattern = new RegExp(pattern);
|
|
237
|
+
if(!pattern.test(textValue)){
|
|
238
|
+
return {success:false,message:rule.message};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if(rule.min){
|
|
243
|
+
if(type=='number'){
|
|
244
|
+
if(numberValue < +rule.min){ // 最小数值
|
|
245
|
+
return {success:false,message:rule.message};;
|
|
246
|
+
}
|
|
247
|
+
}else if(type=='string'){// 最小字符串长度
|
|
248
|
+
pattern = `^.{${rule.min},}$`;
|
|
249
|
+
pattern = new RegExp(pattern);
|
|
250
|
+
if(!pattern.test(textValue)){
|
|
251
|
+
return {success:false,message:rule.message};
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if(rule.enum){
|
|
256
|
+
if(!rule.enum.includes(textValue)){
|
|
257
|
+
return {success:false,message:rule.message};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if(rule.validator){
|
|
261
|
+
try{
|
|
262
|
+
let req = await rule.validator(null,value);
|
|
263
|
+
}catch(ex){
|
|
264
|
+
return {success:false,message:ex.message}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return {success:true};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
export default list;
|
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
// @ts-ignore
|
|
2
|
-
import React, { useState,useEffect, useRef} from 'react';
|
|
3
|
-
// @ts-ignore
|
|
4
|
-
import { matchPath,useLocation,useNavigate } from 'react-router-dom';
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
import { LogoutOutlined, UserOutlined } from '@ant-design/icons';
|
|
7
|
-
// @ts-ignore
|
|
8
|
-
import { Menu,Dropdown } from 'antd';
|
|
9
|
-
|
|
10
|
-
import ProviderApp from '@/provider/app';
|
|
11
|
-
import ProviderMenu from '@/provider/menu';
|
|
12
|
-
import {GET_MENU} from '@/services/auth';
|
|
13
|
-
|
|
14
|
-
// @ts-ignore
|
|
15
|
-
import imgAvatar from '@/assets/images/avatar.png';
|
|
16
|
-
// @ts-ignore
|
|
17
|
-
import styles from './index.less';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* 菜单下的隐藏子路由集
|
|
21
|
-
* 当这些隐藏子路由打开的时候,导航栏的选中菜单会显示被匹配的这个子菜单
|
|
22
|
-
*/
|
|
23
|
-
const SUB_MENU_CONFIG=[
|
|
24
|
-
{
|
|
25
|
-
path:'/video',//匹配菜单路由是/video的菜单
|
|
26
|
-
// routeTemplate:''匹配某个模板菜单的模板
|
|
27
|
-
subRoute:[
|
|
28
|
-
{
|
|
29
|
-
path:'/video/detail',//将video/detail这个路由匹配给菜单/video
|
|
30
|
-
// routeTemplate:''//也可以将某个路由模板匹配给某个菜单
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
},
|
|
34
|
-
]
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* 顶部导航栏
|
|
38
|
-
* 左侧导航栏的路由也继顶部导航栏来控制
|
|
39
|
-
* 路由数据结构:
|
|
40
|
-
* const MenuRoute=[
|
|
41
|
-
{
|
|
42
|
-
label:'顶部菜单A',
|
|
43
|
-
path:'/home/sub/1',
|
|
44
|
-
menus:[
|
|
45
|
-
{
|
|
46
|
-
label:'菜单组A-1',
|
|
47
|
-
icon:'MailOutlined',
|
|
48
|
-
children:[
|
|
49
|
-
{label:'菜单组A-1-home',path:'/',},
|
|
50
|
-
{label:'菜单组A-1-sub:id',path:'/home/sub/1',routeTemplate:'/home/sub/:id'},
|
|
51
|
-
{label:'菜单组A-1-sub3:id',path:'/home/sub3/2',routeTemplate:'/home/sub3/:id'},
|
|
52
|
-
]
|
|
53
|
-
},
|
|
54
|
-
]
|
|
55
|
-
}
|
|
56
|
-
]
|
|
57
|
-
顶部的导航栏结构为{label,path,menus}
|
|
58
|
-
左侧导航栏数据为顶部导航栏数据的menus内子项{label,icon,children}组成
|
|
59
|
-
routeTemplate用来识别动态参数的路由,同前端本地路由配置同步即可
|
|
60
|
-
当顶部导航栏只有一项时,将自动隐藏顶部导航菜单
|
|
61
|
-
* @returns {JSX.Element}
|
|
62
|
-
*/
|
|
63
|
-
const TopMenu=()=>{
|
|
64
|
-
const app = ProviderApp.useContainer();
|
|
65
|
-
const providerMenu = ProviderMenu.useContainer();
|
|
66
|
-
const curRoute = useLocation();
|
|
67
|
-
|
|
68
|
-
const [menus,setMenus]=useState([]);
|
|
69
|
-
const navigate = useNavigate();
|
|
70
|
-
const [selectedKeys,setSelectedKeys] = useState([]);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const MENU_KEY_COUNTER=useRef(1);
|
|
74
|
-
const MENU_KEY=useRef({})
|
|
75
|
-
const translateMenu=(data={})=>{
|
|
76
|
-
const {label,path}= data;
|
|
77
|
-
let myKey = `${MENU_KEY_COUNTER.current}`
|
|
78
|
-
let item ={
|
|
79
|
-
key:myKey,
|
|
80
|
-
label:`${label}`,
|
|
81
|
-
path,
|
|
82
|
-
source:data,
|
|
83
|
-
}
|
|
84
|
-
MENU_KEY.current[myKey] = item;
|
|
85
|
-
MENU_KEY_COUNTER.current++;
|
|
86
|
-
return item;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const getSubConfig=(menu)=>{
|
|
90
|
-
const {url,routeTemplate}= menu;
|
|
91
|
-
for(let i=0;i<SUB_MENU_CONFIG.length;i++){
|
|
92
|
-
let sub= SUB_MENU_CONFIG[i];
|
|
93
|
-
if(routeTemplate&&sub.routeTemplate&&routeTemplate==sub.routeTemplate){
|
|
94
|
-
return sub.subRoute;
|
|
95
|
-
}
|
|
96
|
-
if(url&&sub.path&&url==sub.path){
|
|
97
|
-
return sub.subRoute;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
const transServicesMenuChildren=(menu)=>{
|
|
103
|
-
let req=[];
|
|
104
|
-
for(let i=0;i<menu.length;i++){
|
|
105
|
-
let item= menu[i];
|
|
106
|
-
const {url:path,name:label,icon,children:menus,routeTemplate}= item;
|
|
107
|
-
let children;
|
|
108
|
-
if(menus&&menus.length>0){
|
|
109
|
-
children= transServicesMenuChildren(menus);
|
|
110
|
-
}
|
|
111
|
-
let subRoute= getSubConfig(item);
|
|
112
|
-
req.push({
|
|
113
|
-
path,label,icon,children,routeTemplate,subRoute
|
|
114
|
-
})
|
|
115
|
-
}
|
|
116
|
-
return req;
|
|
117
|
-
}
|
|
118
|
-
const loadMenu=async ()=>{
|
|
119
|
-
let reqMenu = await GET_MENU();
|
|
120
|
-
if(reqMenu?.code==0){
|
|
121
|
-
let originMenu= reqMenu.data;
|
|
122
|
-
reqMenu=[];
|
|
123
|
-
for(let i=0;i<originMenu.length;i++){
|
|
124
|
-
let topMenu= originMenu[i];
|
|
125
|
-
const {url:path,children,name:label}=topMenu;
|
|
126
|
-
const menus = transServicesMenuChildren(children);
|
|
127
|
-
reqMenu.push({
|
|
128
|
-
path,menus,label
|
|
129
|
-
})
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
if(!reqMenu){
|
|
133
|
-
setMenus([]);
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
const data = reqMenu.map(topMenu=>{
|
|
137
|
-
return translateMenu(topMenu);
|
|
138
|
-
})
|
|
139
|
-
setMenus(data);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const GET_ROUTE_MENU=(menu)=>{
|
|
143
|
-
const {routeTemplate,path,subRoute} = menu;
|
|
144
|
-
const children = menu.children||menu.menus||null;
|
|
145
|
-
if(routeTemplate||path){
|
|
146
|
-
let match= matchPath(routeTemplate||path,curRoute.pathname);
|
|
147
|
-
if(!match&&subRoute){
|
|
148
|
-
match= subRoute.some(sub=>{
|
|
149
|
-
let subMatch= matchPath(sub.routeTemplate||sub.path,curRoute.pathname);
|
|
150
|
-
if(subMatch){
|
|
151
|
-
console.log(`match sub route: ${sub.routeTemplate||sub.path} -> ${curRoute.pathname}` )
|
|
152
|
-
return true;
|
|
153
|
-
}
|
|
154
|
-
return false;
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
if(match){
|
|
158
|
-
console.log(`match route: ${routeTemplate||path} -> ${curRoute.pathname}` )
|
|
159
|
-
return true;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
if(children){
|
|
163
|
-
for(let subMenu of children){
|
|
164
|
-
let match = GET_ROUTE_MENU(subMenu);
|
|
165
|
-
if(match){
|
|
166
|
-
return true;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return false;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const reloadOpenMenu=()=>{
|
|
174
|
-
for(let menuKey in MENU_KEY.current){
|
|
175
|
-
const topMenu = MENU_KEY.current[menuKey];
|
|
176
|
-
const match= GET_ROUTE_MENU(topMenu.source);
|
|
177
|
-
if(match){
|
|
178
|
-
let changeLeftMenu=false;//是否重新设置左侧导航菜单数据
|
|
179
|
-
if(selectedKeys[0] != menuKey){
|
|
180
|
-
changeLeftMenu= true;
|
|
181
|
-
}
|
|
182
|
-
if(!providerMenu.menus||providerMenu.menus.length<=0){
|
|
183
|
-
changeLeftMenu= true;
|
|
184
|
-
}
|
|
185
|
-
setSelectedKeys([menuKey]);
|
|
186
|
-
if(changeLeftMenu){
|
|
187
|
-
providerMenu.setMenus(topMenu.source.menus);
|
|
188
|
-
}
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
setSelectedKeys([]);
|
|
193
|
-
providerMenu.setMenus([]);
|
|
194
|
-
}
|
|
195
|
-
useEffect(()=>{loadMenu()},[]);
|
|
196
|
-
|
|
197
|
-
useEffect(()=>{
|
|
198
|
-
reloadOpenMenu();
|
|
199
|
-
},[curRoute,menus]);
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
// 推出登录
|
|
204
|
-
const onAvatarClick = (e)=>{
|
|
205
|
-
if (e?.key === 'logout') {
|
|
206
|
-
app.logout();
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
const onHome=()=>{
|
|
210
|
-
navigate('/');
|
|
211
|
-
}
|
|
212
|
-
const onClickMenuItem=(e)=>{
|
|
213
|
-
const { item, key, keyPath, domEvent } = e;
|
|
214
|
-
const menuData = MENU_KEY.current[key];
|
|
215
|
-
const {path,source:{menus}} = menuData;
|
|
216
|
-
providerMenu.setMenus(menus);
|
|
217
|
-
if(path){
|
|
218
|
-
navigate(path)
|
|
219
|
-
}
|
|
220
|
-
setSelectedKeys([key])
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return (
|
|
224
|
-
<section className={styles.topMenu}>
|
|
225
|
-
<div className={styles.left}>
|
|
226
|
-
<span className={styles.title} onClick={onHome}>后管系统</span>
|
|
227
|
-
</div>
|
|
228
|
-
|
|
229
|
-
<div className={styles.center}>
|
|
230
|
-
{
|
|
231
|
-
menus&&menus.length>1&&
|
|
232
|
-
<Menu
|
|
233
|
-
items={menus}
|
|
234
|
-
mode="horizontal"
|
|
235
|
-
onClick={onClickMenuItem}
|
|
236
|
-
|
|
237
|
-
selectedKeys={selectedKeys}
|
|
238
|
-
className={styles.menu}
|
|
239
|
-
/>
|
|
240
|
-
}
|
|
241
|
-
</div>
|
|
242
|
-
<div className={styles.right}>
|
|
243
|
-
|
|
244
|
-
<span className={styles.username}>Hi,{app?.user?.username||''}!</span>
|
|
245
|
-
<Dropdown overlay={(
|
|
246
|
-
<Menu onClick={onAvatarClick} className={styles.avatarMenu}>
|
|
247
|
-
<Menu.Item key="user">
|
|
248
|
-
<UserOutlined />
|
|
249
|
-
用户名
|
|
250
|
-
</Menu.Item>
|
|
251
|
-
|
|
252
|
-
<Menu.Item key="logout">
|
|
253
|
-
<LogoutOutlined />
|
|
254
|
-
退出登录
|
|
255
|
-
</Menu.Item>
|
|
256
|
-
</Menu>
|
|
257
|
-
)}>
|
|
258
|
-
<img className={styles.avatar} src={imgAvatar}/>
|
|
259
|
-
</Dropdown>
|
|
260
|
-
|
|
261
|
-
</div>
|
|
262
|
-
|
|
263
|
-
</section>
|
|
264
|
-
)
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
export default TopMenu;
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import {waitTime,REP_SUCCESS} from './utils.js';
|
|
2
|
-
import qs from 'qs';
|
|
3
|
-
import {GET_REQUEST} from './utils';
|
|
4
|
-
|
|
5
|
-
async function GET_MENU(req,res){
|
|
6
|
-
await waitTime();
|
|
7
|
-
const MenuRoute=[
|
|
8
|
-
{
|
|
9
|
-
name:'顶部菜单',
|
|
10
|
-
url:'/video',
|
|
11
|
-
children:[
|
|
12
|
-
{
|
|
13
|
-
name:'内容管理',
|
|
14
|
-
icon:'AppstoreOutlined',
|
|
15
|
-
children:[
|
|
16
|
-
{name:'剧集管理',url:'/video'},
|
|
17
|
-
{name:'素材管理',url:'/material'},
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
name:'数据管理',
|
|
23
|
-
icon:'AppstoreOutlined',
|
|
24
|
-
children:[
|
|
25
|
-
{name:'订单数据',url:'/order'},
|
|
26
|
-
{name:'用户数据',url:'/userData'},
|
|
27
|
-
]
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name:'用户管理',
|
|
31
|
-
icon:'UserOutlined',
|
|
32
|
-
url:'/user'
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name:'客诉管理',
|
|
36
|
-
icon:'CustomerServiceOutlined',
|
|
37
|
-
url:'/suggest'
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
name:'权限配置',
|
|
41
|
-
icon:'CrownOutlined',
|
|
42
|
-
url:'/permission'
|
|
43
|
-
},
|
|
44
|
-
]
|
|
45
|
-
}
|
|
46
|
-
]
|
|
47
|
-
return {code:0,data:MenuRoute}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function LOGIN(req,res){
|
|
51
|
-
await waitTime();
|
|
52
|
-
return {code:0,data:{
|
|
53
|
-
authorities:['admin'],
|
|
54
|
-
token:'token',
|
|
55
|
-
userId:'1',
|
|
56
|
-
username:'cx',
|
|
57
|
-
realName:'cx',
|
|
58
|
-
name:'cx'
|
|
59
|
-
|
|
60
|
-
}}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function KSSOLOGIN(req,res){
|
|
64
|
-
await waitTime();
|
|
65
|
-
return {code:0,data:{
|
|
66
|
-
authorities:['admin'],
|
|
67
|
-
token:'token',
|
|
68
|
-
userId:'1',
|
|
69
|
-
username:'cx',
|
|
70
|
-
realName:'cx',
|
|
71
|
-
name:'cx'
|
|
72
|
-
|
|
73
|
-
}}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
async function LOGOUT(req,res){
|
|
78
|
-
await waitTime();
|
|
79
|
-
return {code:0}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
LOGOUT
|
|
84
|
-
export default {
|
|
85
|
-
'/api/menu/nav':{get:GET_MENU},
|
|
86
|
-
'/api/login':{post:LOGIN},
|
|
87
|
-
'/api/ksso/auth':{post:KSSOLOGIN},
|
|
88
|
-
'/api/logout':{post:LOGOUT},
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import {waitTime,REP_SUCCESS} from './utils.js';
|
|
2
|
-
import qs from 'qs';
|
|
3
|
-
import {GET_REQUEST} from './utils';
|
|
4
|
-
async function GET_USER(req,res){
|
|
5
|
-
const query = qs.parse(req.url.split('?')[1]);
|
|
6
|
-
const {name} = query;
|
|
7
|
-
await waitTime();
|
|
8
|
-
return {code:0,data:{name}}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
async function SET_USER(req,res){
|
|
12
|
-
const query = JSON.parse(req.body);
|
|
13
|
-
const {name,age}= query;
|
|
14
|
-
await waitTime();
|
|
15
|
-
|
|
16
|
-
return {
|
|
17
|
-
"code": 0,
|
|
18
|
-
"data":{name,age}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function GET_USER_LIST(req,res){
|
|
23
|
-
const {current,pageSize} = GET_REQUEST(req,res);
|
|
24
|
-
const MAX_TOTAL=98;
|
|
25
|
-
let data=[];
|
|
26
|
-
let idx=(current-1)*pageSize;
|
|
27
|
-
|
|
28
|
-
for(let i=0;i<pageSize;i++){
|
|
29
|
-
if(idx>=MAX_TOTAL)break;
|
|
30
|
-
data.push({
|
|
31
|
-
name:`${idx++}小朋友`
|
|
32
|
-
})
|
|
33
|
-
}
|
|
34
|
-
return {
|
|
35
|
-
code:0,
|
|
36
|
-
data:{
|
|
37
|
-
list:data,
|
|
38
|
-
page:{
|
|
39
|
-
pageNum:current,
|
|
40
|
-
pageSize:pageSize,
|
|
41
|
-
total:MAX_TOTAL
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function GET_USER_TYPE(req,res){
|
|
48
|
-
let data=[];
|
|
49
|
-
for(let i=0;i<10;i++){
|
|
50
|
-
data.push({
|
|
51
|
-
label:`标题${i}`,
|
|
52
|
-
value:i,
|
|
53
|
-
key:`title${i}`
|
|
54
|
-
})
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
code:0,
|
|
58
|
-
data:data
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
export default {
|
|
66
|
-
'/userType':{get:GET_USER_TYPE},
|
|
67
|
-
'/userList':{get:GET_USER_LIST},
|
|
68
|
-
'/user':{get:GET_USER,post:SET_USER},
|
|
69
|
-
|
|
70
|
-
}
|