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.
Files changed (43) hide show
  1. package/package.json +1 -1
  2. package/templates/template_admin/public/index.html +5 -2
  3. package/templates/template_admin/public/src/_antd.less +7 -1
  4. package/templates/template_admin/public/src/assets/images/avatars/1.png +0 -0
  5. package/templates/template_admin/public/src/assets/images/avatars/2.png +0 -0
  6. package/templates/template_admin/public/src/assets/images/avatars/3.png +0 -0
  7. package/templates/template_admin/public/src/components/layout/basic/index.less +3 -3
  8. package/templates/template_admin/public/src/components/menu/index.jsx +47 -100
  9. package/templates/template_admin/public/src/components/menu/topMenu/index.jsx +129 -0
  10. package/templates/template_admin/public/src/components/table/index.jsx +62 -0
  11. package/templates/template_admin/public/src/dictionary/index.js +49 -4
  12. package/templates/template_admin/public/src/hooks/index.jsx +4 -1
  13. package/templates/template_admin/public/src/hooks/useRouteMenu.jsx +232 -0
  14. package/templates/template_admin/public/src/mock/demo.js +177 -0
  15. package/templates/template_admin/public/src/mock/index.js +5 -2
  16. package/templates/template_admin/public/src/pages/demo/detail/index.jsx +27 -0
  17. package/templates/template_admin/public/src/pages/demo/edit/index.jsx +109 -0
  18. package/templates/template_admin/public/src/pages/demo/index.less +9 -0
  19. package/templates/template_admin/public/src/pages/demo/page1.jsx +161 -0
  20. package/templates/template_admin/public/src/pages/login/index.jsx +5 -4
  21. package/templates/template_admin/public/src/pages/superAdminLogin/index.jsx +9 -2
  22. package/templates/template_admin/public/src/provider/app.jsx +18 -8
  23. package/templates/template_admin/public/src/provider/menu.jsx +146 -10
  24. package/templates/template_admin/public/src/route.jsx +21 -18
  25. package/templates/template_admin/public/src/services/demo.js +54 -0
  26. package/templates/template_admin/public/src/services/index.js +9 -0
  27. package/templates/template_admin/public/src/utils/format.js +51 -0
  28. package/templates/template_admin/public/src/utils/rule.js +274 -0
  29. package/templates/template_admin/readme.md +4 -0
  30. package/templates/template_admin/public/src/components/topMenu/index.jsx +0 -267
  31. package/templates/template_admin/public/src/mock/auth.js +0 -91
  32. package/templates/template_admin/public/src/mock/user.js +0 -70
  33. package/templates/template_admin/public/src/pages/material/index.jsx +0 -84
  34. package/templates/template_admin/public/src/pages/order/index.jsx +0 -12
  35. package/templates/template_admin/public/src/pages/permission/index.jsx +0 -12
  36. package/templates/template_admin/public/src/pages/suggest/index.jsx +0 -12
  37. package/templates/template_admin/public/src/pages/user/index.jsx +0 -18
  38. package/templates/template_admin/public/src/pages/userData/index.jsx +0 -12
  39. package/templates/template_admin/public/src/pages/video/index.jsx +0 -65
  40. package/templates/template_admin/public/src/services/auth.js +0 -28
  41. package/templates/template_admin/public/src/services/user.js +0 -26
  42. package/templates/template_admin/public/src/services/video.js +0 -33
  43. /package/templates/template_admin/public/src/components/{topMenu → menu/topMenu}/index.less +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kn-cli",
3
- "version": "1.0.92",
3
+ "version": "1.0.94",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,8 +21,11 @@
21
21
  var docEl = document.documentElement;
22
22
  function setRemUnit(type) {
23
23
  let w = Math.max(window.innerWidth, docEl.clientWidth, docEl.offsetWidth);
24
- let defaultWidth = 1200;//填入设计稿上的宽度
25
- // w = w > defaultWidth ? defaultWidth : w;
24
+ let defaultWidth = 1440;//填入设计稿上的宽度
25
+ let minWidth=1200;
26
+ let maxWidth=1440;
27
+ w = w < minWidth ? minWidth :w;
28
+ w = w > maxWidth ? maxWidth :w;
26
29
  var rem = w / defaultWidth * 100;
27
30
  docEl.style.fontSize = rem + 'px'
28
31
  }
@@ -1,4 +1,10 @@
1
1
  @import '~antd/dist/antd.less';
2
2
 
3
3
  // 这里可以重写antd的主题样式变量,参考 https://4x.ant.design/docs/react/customize-theme-cn
4
- @primary-color:#EB437C;
4
+ @primary-color:#EB437C;
5
+
6
+ :global{
7
+ .ant-menu-submenu{
8
+ color:white;
9
+ }
10
+ }
@@ -17,9 +17,9 @@
17
17
  background-color: var(--color-body-background);
18
18
  flex:1;
19
19
  height:100%;
20
- &::-webkit-scrollbar {
21
- display: none;
22
- }
20
+ // &::-webkit-scrollbar {
21
+ // display: none;
22
+ // }
23
23
  }
24
24
 
25
25
  }
@@ -1,11 +1,10 @@
1
1
  // @ts-ignore
2
2
  import React, { useEffect, useRef, useState } from 'react';
3
3
  // @ts-ignore
4
- import { Menu } from 'antd';
4
+ import { Menu,Badge } from 'antd';
5
5
  // @ts-ignore
6
- import {matchPath,useLocation,useNavigate,} from 'react-router-dom';
7
- // @ts-ignore
8
- import { AppstoreOutlined, MailOutlined, SettingOutlined } from '@ant-design/icons';
6
+ import {useNavigate,} from 'react-router-dom';
7
+
9
8
 
10
9
  import {useLoading} from '@/hooks/index';
11
10
  import ProviderMenu from '@/provider/menu';
@@ -13,11 +12,6 @@ import ProviderMenu from '@/provider/menu';
13
12
  // @ts-ignore
14
13
  import styles from './index.less';
15
14
 
16
- const ICON_NAME={
17
- 'AppstoreOutlined':<AppstoreOutlined />,
18
- 'MailOutlined':<MailOutlined />,
19
- 'SettingOutlined':<SettingOutlined />,
20
- }
21
15
 
22
16
 
23
17
 
@@ -28,113 +22,66 @@ const ICON_NAME={
28
22
  */
29
23
  const LeftMenu=()=>{
30
24
 
25
+
31
26
  const providerMenu = ProviderMenu.useContainer();
32
27
  const loader = useLoading();
33
28
  const [menus,setMenus] = useState([]);
34
- const [openKeys,setOpenKeys] = useState([]);
35
- const [selectedKeys,setSelectKeys] = useState([]);
36
- const curRoute = useLocation();
29
+ const [subMenuOpen,setSubMenuOpen]= useState([]);
37
30
  const nav = useNavigate();
38
-
39
- const MENU_KEY_COUNTER=useRef(1);
40
- const MENU_KEY=useRef({});
41
- const translateMenu=(data={},parent)=>{
42
- const {label,icon,children,path}= data;
43
- let myKey = `${MENU_KEY_COUNTER.current}`
44
- let item ={
45
- key:myKey,
46
- label:`${label}`,
47
- source:data,
48
- path,
49
- routepath:parent?`${parent.key}-${myKey}`:myKey
50
- }
51
- MENU_KEY.current[myKey] = item;
52
- MENU_KEY_COUNTER.current++;
53
- if(icon){
54
- item.icon= ICON_NAME[icon];
55
- }
56
- if(children){
57
- item.children = children.map(childData=>{
58
- return translateMenu(childData,item)
59
- })
60
- }
61
- return item;
62
- }
63
-
64
- // @ts-ignore
65
- window.matchPath=matchPath;
66
-
67
-
68
- const GET_ROUTE_MENU=(menuList)=>{
69
- let groupKeys=[];
70
- for(let key in menuList){
71
- const menuItem = menuList[key];
72
- const {path,routeTemplate,subRoute}= menuItem.source;
73
- if(path){
74
- let fn = matchPath;
75
- let match= fn(routeTemplate||path,curRoute.pathname);
76
- if(!match&&subRoute){
77
- match= subRoute.some(sub=>{
78
- let subMatch= fn(sub.routeTemplate||sub.path,curRoute.pathname);
79
- if(subMatch){
80
- return true;
81
- }
82
- return false;
83
- })
84
- }
85
- if(match){
86
- groupKeys = menuItem.routepath?menuItem.routepath.split('-'):'';
87
- }
31
+
32
+ const translateMenu=(list)=>{
33
+ if(!list||list.length<=0)return [];
34
+ let req=list.map(menu=>{
35
+ const {key,name:label,icon,url,msgCount}=menu;
36
+
37
+ let item={
38
+ key,label,icon,url
88
39
  }
89
- }
90
- return groupKeys;
91
- }
92
-
93
- const loadMenu= ()=>{
94
- loader.setLoading(true);
95
- if(providerMenu.menus){
96
- const menuList= providerMenu.menus.map(menu=>{
97
- return translateMenu(menu)
98
- })
99
- setMenus(menuList);
100
- }else{
101
- setMenus([]);
102
- }
103
- loader.setLoading(false);
40
+ if(msgCount&&msgCount>0){
41
+ item.label=<span>{label}<Badge size='small' count={msgCount} offset={[5,-5]} /></span>
42
+ }
43
+ if(menu.children){
44
+ item.children = translateMenu(menu.children)
45
+ }
46
+ return item;
47
+ })
48
+ return req;
104
49
  }
105
50
 
106
51
  useEffect(()=>{
107
- loadMenu();
108
- },[providerMenu])
52
+ let menuList = translateMenu(providerMenu.leftMenu);
53
+ setMenus(menuList);
54
+ },[providerMenu.leftMenu])
109
55
 
110
- useEffect(()=>{
111
- let groupKeys= GET_ROUTE_MENU(MENU_KEY.current);
112
- setOpenKeys(groupKeys);
113
- let selectKey =groupKeys[groupKeys.length-1];
114
- setSelectKeys([selectKey])
115
- },[curRoute,menus]);
116
56
 
117
57
  const onClickMenuItem=(e)=>{
118
58
  const { item, key, keyPath, domEvent } = e;
119
- const menuData = MENU_KEY.current[key];
120
- if(menuData.path){
121
- nav(menuData.path);
122
- }
59
+ let menu = providerMenu.findMenuData(key);
60
+ nav(menu.url);
123
61
  }
124
- const onOpenChange=(keys)=>{
125
- setOpenKeys(keys);
62
+
63
+ const onOpenSubMenu=(keys)=>{
64
+ setSubMenuOpen(keys)
126
65
  }
66
+ useEffect(()=>{
67
+ if(providerMenu.selectMenus.keys && providerMenu.selectMenus.keys.length>0){
68
+ setSubMenuOpen([...subMenuOpen,...providerMenu.selectMenus.keys]);
69
+ }
70
+ },[providerMenu.selectMenus.keys])
127
71
  return (
128
72
  <section className={styles.nav}>
129
- <Menu
130
- theme='dark'
131
- selectedKeys={selectedKeys}
132
- openKeys={openKeys}
133
- onOpenChange={onOpenChange}
134
- onClick={onClickMenuItem}
135
- mode="inline"
136
- items={loader.loading?[]:menus}
137
- />
73
+ {
74
+ providerMenu.selectMenus.keys&&
75
+ <Menu
76
+ theme='dark'
77
+ openKeys={subMenuOpen}
78
+ onOpenChange={onOpenSubMenu}
79
+ selectedKeys={providerMenu.selectMenus.keys}
80
+ onClick={onClickMenuItem}
81
+ mode="inline"
82
+ items={loader.loading?[]:menus}
83
+ />
84
+ }
138
85
  </section>
139
86
  )
140
87
  }
@@ -0,0 +1,129 @@
1
+ // @ts-ignore
2
+ import React, { useState,useEffect, useRef} from 'react';
3
+ // @ts-ignore
4
+ import { useLocation,useNavigate } from 'react-router-dom';
5
+ // @ts-ignore
6
+ import { LogoutOutlined, UserOutlined } from '@ant-design/icons';
7
+ // @ts-ignore
8
+ import { Menu,Dropdown,Badge } from 'antd';
9
+
10
+ import ProviderApp from '@/provider/app';
11
+ import ProviderMenu from '@/provider/menu';
12
+
13
+ // @ts-ignore
14
+ import imgAvatar from '@/assets/images/avatar.png';
15
+ // @ts-ignore
16
+ import styles from './index.less';
17
+
18
+ const TopMenu=()=>{
19
+ const app = ProviderApp.useContainer();
20
+ const providerMenu = ProviderMenu.useContainer();
21
+ const navigate = useNavigate();
22
+
23
+ const [menus,setMenus]=useState([]);
24
+
25
+
26
+ const translateMenu=(list)=>{
27
+ if(!list||list.length<=0)return [];
28
+ let req=list.map(menu=>{
29
+ const {key,name:label,icon,url,msgCount}=menu;
30
+
31
+ let item={
32
+ key,label,icon,url
33
+ }
34
+ if(msgCount&&msgCount>0){
35
+ item.label=<span>{label}<Badge size='small' count={msgCount} offset={[5,-5]} /></span>
36
+ }
37
+ if(menu.children){
38
+ item.children = translateMenu(menu.children)
39
+ }
40
+ return item;
41
+ })
42
+ return req;
43
+ }
44
+
45
+
46
+ const reload= async ()=>{
47
+ providerMenu.reload();
48
+ }
49
+ useEffect(()=>{
50
+ let menuList = translateMenu(providerMenu.topMenu);
51
+ menuList.forEach(menu=>{
52
+ menu.children=null;//顶级菜单这里设计为不需要展示子菜单
53
+ })
54
+ setMenus(menuList);
55
+ },[providerMenu.topMenu]);
56
+
57
+ useEffect(()=>{
58
+ providerMenu.setUserAuth(app.user.authorities||[]);
59
+ },[app.user])
60
+
61
+ useEffect(()=>{
62
+ reload();
63
+ },[])
64
+
65
+
66
+ // 推出登录
67
+ const onAvatarClick = (key)=>{
68
+ if (key === 'logout') {
69
+ app.logout();
70
+ }else if(key=='relogin'){
71
+ navigate('/superAdminLogin')
72
+ }
73
+ }
74
+ const onHome=()=>{
75
+ navigate('/');
76
+ }
77
+ const onClickMenuItem=(e)=>{
78
+ const { item, key, keyPath, domEvent } = e;
79
+ let menu = providerMenu.findMenuData(key);
80
+ navigate(menu.url);
81
+ }
82
+
83
+
84
+ return (
85
+ <section className={styles.topMenu}>
86
+ <div className={styles.left}>
87
+ <span className={styles.title} onClick={onHome}>后管系统</span>
88
+ </div>
89
+
90
+ <div className={styles.center}>
91
+ {
92
+ menus&&menus.length>=1&&
93
+ <Menu
94
+ items={menus}
95
+ mode="horizontal"
96
+ onClick={onClickMenuItem}
97
+ selectedKeys={providerMenu.selectMenus.keys}
98
+ className={styles.menu}
99
+ />
100
+ }
101
+ </div>
102
+ <div className={styles.right}>
103
+
104
+ <span className={styles.username}>Hi,{app?.user?.username||''}!</span>
105
+ <Dropdown menu={{items:[
106
+ {
107
+ key:'user',
108
+ label:<span onClick={onAvatarClick.bind(this,'user')}><UserOutlined />用户名</span>
109
+ },
110
+ {
111
+ key:'relogin',
112
+ label:<span onClick={onAvatarClick.bind(this,'relogin')}><UserOutlined />重新登录</span>
113
+ },
114
+ {
115
+ key:'logout',
116
+ label:<span onClick={onAvatarClick.bind(this,'logout')}><LogoutOutlined />退出登录</span>
117
+ }
118
+
119
+ ]}}>
120
+ <img className={styles.avatar} src={imgAvatar}/>
121
+ </Dropdown>
122
+
123
+ </div>
124
+
125
+ </section>
126
+ )
127
+ }
128
+
129
+ export default TopMenu;
@@ -0,0 +1,62 @@
1
+ import React,{useCallback} from 'react';
2
+ // @ts-ignore
3
+ import { Table } from 'antd';
4
+
5
+ /**
6
+ * 页面公共Table组件
7
+ * @param {object} [props]
8
+ * @param {string} [props.rowKey] - Table主键
9
+ * @param {boolean} [props.loading] - 是否加载中
10
+ * @param {Array} [props.columns] - 表格列
11
+ * @param {Array} [props.dataSource] - 数据数组
12
+ * @param {object} [props.pagination] - 分页器,参考配置项或 pagination 文档,设为 false 时不展示和进行分页
13
+ * @param {object} [props.scroll] - 表格是否可滚动
14
+ * @param {object} [props.page] - 表格数据,包括数据数组、分页参数、loading等
15
+ *
16
+ * @returns {JSX.Element}
17
+ */
18
+ const PageTable = (props) => {
19
+ const {
20
+ rowKey,
21
+ loading,
22
+ columns,
23
+ dataSource,
24
+ pagination,
25
+ scroll,
26
+ page,
27
+ ...others
28
+ } = props;
29
+
30
+ const paginationFn = useCallback(() => {
31
+ // pagination=false时不分页
32
+ if (typeof pagination === 'boolean') {
33
+ return pagination;
34
+ }
35
+ return {
36
+ pageSizeOptions: [10, 15, 20, 50, 100],
37
+ current: page?.pagination?.current,
38
+ pageSize: page?.pagination?.pageSize,
39
+ total: page?.pagination?.total,
40
+ showTotal: (total) => `总计${total}条`,
41
+ ...pagination,
42
+ };
43
+ }, [pagination, page]);
44
+
45
+ return (
46
+ <Table
47
+ rowKey={rowKey ?? 'id'}
48
+ bordered
49
+ size="small"
50
+ loading={loading ?? page?.loading?.state}
51
+ columns={columns}
52
+ dataSource={
53
+ dataSource ?? (page?.data?.[page?.pagination?.current - 1] || [])
54
+ }
55
+ pagination={paginationFn()}
56
+ scroll={scroll ?? { y: 500 }}
57
+ {...others}
58
+ />
59
+ );
60
+ };
61
+
62
+ export default PageTable;
@@ -3,10 +3,43 @@
3
3
  import React from 'react';
4
4
  // @ts-ignore
5
5
  import {useDictionary} from 'kn-hooks';
6
+ // @ts-ignore
7
+ import {Select,Radio} from 'antd';
8
+
9
+ import {GET_ENUM_TYPE} from '@/services/demo'
6
10
 
7
- import {GET_USER_TYPE} from '@/services/user';
8
11
  import ShowToast from '@/components/toast';
9
12
 
13
+
14
+
15
+ /**
16
+ * @typedef DictionaryItem
17
+ * 字典数据的结构
18
+ * @property {string} id - 数据唯一ID
19
+ * @property {string} name - 数据唯一id对应的别名
20
+ * @property {string} label - 展示给用户看的文字
21
+ *
22
+ */
23
+
24
+ /**
25
+ * @typedef UseDictionaryResult
26
+ * @property {DictionaryItem[]} types - 字典数据列表
27
+ * @property {ReactDOM[]} selectOptions - 供Antd渲染\<Select\>的列表
28
+ * @property {ReactDOM[]} radioOptions - 供Antd渲染\<Radio\>的列表
29
+ * @property {function} getId - (labelOrName:string)=>string,搜索字典项中,label或name匹配labelOrName的项目,返回其id的值
30
+ * @property {function} getName - (id:string)=>string,搜索字典项中,id匹配id的项目,返回其name的值
31
+ * @property {function} getLabel - (id:string)=>string,搜索字典项中,id匹配id的项目,返回其label的值
32
+ * @property {function} reload - ()=>void,重新调用字典接口刷新字典列表
33
+ *
34
+ */
35
+
36
+ /**
37
+ * @callback UseDictionary
38
+ * @returns {UseDictionaryResult}
39
+ */
40
+
41
+
42
+
10
43
  export const SelectOption=(props)=>{
11
44
  const {value}=props;
12
45
  const name = props['data-keyname'];
@@ -18,11 +51,11 @@ export const SelectOption=(props)=>{
18
51
  return <hgroup onClick={onClick} key={value} name={name} value={value}>{props.children}</hgroup>
19
52
  }
20
53
 
21
- useDictionary.SetConfig({SelectOption})
54
+ useDictionary.SetConfig({SelectOption:Select.Option, RadioOption: Radio })
22
55
 
23
56
 
24
- export const useUserType = useDictionary.createDictionary({
25
- api:GET_USER_TYPE,
57
+ export const useDemoType = useDictionary.createDictionary({
58
+ api:GET_ENUM_TYPE,
26
59
  afterApi:(response)=>{
27
60
  if(response?.code==0){
28
61
  let req= response.data.map(item=>{
@@ -42,3 +75,15 @@ export const useTaskState= useDictionary.createDictionary({
42
75
  ]
43
76
  });
44
77
 
78
+
79
+ /**
80
+ * 健康状态
81
+ * @type UseDictionary
82
+ */
83
+ export const useHealthy= useDictionary.createDictionary({
84
+ defaultTypes:[
85
+ {label:'正常',id:'normal',name:'normal'},
86
+ {label:'异常',id:'abnormal',name:'abnormal'},
87
+ {label:'禁用',id:'disabled',name:'disabled'},
88
+ ]
89
+ });
@@ -6,6 +6,8 @@ import usePreload from './usePreload';
6
6
  import useSearch from './useSearch';
7
7
  import useUpdate from './useUpdate';
8
8
  import useLoading from './useLoading';
9
+ import useRouteMenu from './useRouteMenu';
10
+
9
11
  // @ts-ignore
10
12
  import {usePagination,usePaginationWithForm} from 'kn-hooks';
11
13
 
@@ -17,5 +19,6 @@ export {
17
19
  usePreload,
18
20
  useSearch,
19
21
  useUpdate,
20
- useLoading
22
+ useLoading,
23
+ useRouteMenu
21
24
  }