kn-cli 1.0.113 → 1.0.115

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 (22) hide show
  1. package/package.json +1 -1
  2. package/templates/template_admin/public/src/{menuConfig.jsx → _menuConfig.jsx} +39 -3
  3. package/templates/template_admin/public/src/config.js +4 -1
  4. package/templates/template_admin/public/src/index.jsx +12 -8
  5. package/templates/template_admin/public/src/menuConfig/auth.jsx +92 -0
  6. package/templates/template_admin/public/src/menuConfig/dashboard.jsx +25 -0
  7. package/templates/template_admin/public/src/menuConfig/dna.jsx +76 -0
  8. package/templates/template_admin/public/src/menuConfig/index.jsx +17 -0
  9. package/templates/template_admin/public/src/provider/app.jsx +1 -1
  10. package/templates/template_admin/public/src/provider/menu.jsx +2 -1
  11. package/templates/template_admin/public/src/route.jsx +47 -12
  12. package/templates/template_admin/public/src/services/demo.js +1 -1
  13. package/templates/template_admin/public/src/services/excel.js +43 -0
  14. package/templates/template_admin/public/src/services/http/index.js +155 -0
  15. package/templates/template_admin/public/src/services/index.js +32 -280
  16. package/templates/template_admin/public/src/services/interceptor/index.js +67 -0
  17. package/templates/template_admin/public/src/services/login.js +1 -1
  18. package/templates/template_admin/public/src/services/socket/index.jsx +2 -3
  19. package/templates/template_admin/public/src/services/token/index.js +41 -0
  20. package/templates/template_admin/public/src/type.js +3 -1
  21. package/templates/template_admin/public/src/utils/menu.js +33 -0
  22. package/templates/template_admin/public/src/services/auth.js +0 -39
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kn-cli",
3
- "version": "1.0.113",
3
+ "version": "1.0.115",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -13,16 +13,49 @@ const AuthUser = React.lazy(() => import('@/pages/auth/user'));
13
13
  const AuthUserCreate = React.lazy(() => import('@/pages/auth/user/create'));
14
14
 
15
15
 
16
- import Home from '@/pages/home';
16
+ /**
17
+ * 自动计算菜单权限,使父级菜单权限包含所有子菜单的权限
18
+ * @param {RouteMenuItem} menu
19
+ * @returns {RouteMenuItem}
20
+ */
21
+ export const UpdateAuth=(menu)=>{
22
+ if(menu.children){
17
23
 
24
+ let auths= menu.children.map(childMenu=>{
25
+ let _childMenu = UpdateAuth(childMenu);
26
+ if( Array.isArray(_childMenu.auth) ){
27
+ return [..._childMenu.auth];
28
+ }
29
+ return [];
30
+ });
31
+
32
+ if( Array.isArray(menu.auth) ){
33
+
34
+ menu.auth = [...menu.auth,...auths.flat()];
35
+ // @ts-ignore
36
+ menu.auth = [...new Set(menu.auth)];// 去重
37
+ }
38
+ }
39
+ return menu;
40
+ }
41
+
42
+ export const LoadComponent=(lazyComponent)=>{
43
+ return React.createElement(lazyComponent)
44
+ }
18
45
 
46
+ /**
47
+ * @type {RouteMenuItem}
48
+ */
19
49
  const DASHBOARD={
20
50
  name:'仪表盘',
21
51
  url:'/',
22
- component:<Home />,
52
+ component:LoadComponent(React.lazy(() => import('@/pages/home'))),
23
53
  children:[
24
54
  ],
25
55
  }
56
+ /**
57
+ * @type {RouteMenuItem}
58
+ */
26
59
  const DNA={
27
60
  name:'基因库',
28
61
  url:'/dna',
@@ -79,6 +112,9 @@ const DNA={
79
112
  },
80
113
  ],
81
114
  }
115
+ /**
116
+ * @type {RouteMenuItem}
117
+ */
82
118
  const AUTH={
83
119
  name:'控制室',
84
120
  url:'/auth',
@@ -149,4 +185,4 @@ const AUTH={
149
185
  }
150
186
 
151
187
 
152
- export default [DASHBOARD,DNA,AUTH];
188
+ export default [UpdateAuth(DASHBOARD), UpdateAuth(DNA), UpdateAuth(AUTH) ];
@@ -2,7 +2,7 @@
2
2
 
3
3
  // 权限调试开关
4
4
  // @ts-ignore
5
- export const AUTH_DEBUG_OPEN=BUILD_ENV=='prod'?false:true;
5
+ export const AUTH_DEBUG_OPEN= BUILD_ENV=='prod'?false:true;
6
6
  // 菜单权限调试开关
7
7
  export const AUTH_ROUTE_DEBUG_OPEN=false;
8
8
 
@@ -26,3 +26,6 @@ const DEBUG_API_HOST_CONFIG={
26
26
  // 配置本地调试时api调用的接口地址,
27
27
  export const DEBUG_API_HOST=DEBUG_API_HOST_CONFIG[DEBUG_ENV]
28
28
 
29
+ // 调试vconsole
30
+ // @ts-ignore
31
+ export const DEBUG_VCONSOLE= BUILD_ENV=='local';
@@ -6,6 +6,7 @@ import RouteList from './route';
6
6
  // @ts-ignore
7
7
  import moment from 'moment';
8
8
  import { ReactRender } from './components/react';
9
+ import {DEBUG_VCONSOLE} from '@/config';
9
10
  moment.locale('zh-cn');
10
11
 
11
12
 
@@ -39,25 +40,28 @@ window.appLog=(txt)=>{
39
40
 
40
41
  /* eslint-disable */
41
42
  // @ts-ignore
42
- if(BUILD_ENV!='prod'){
43
- // // @ts-ignore
44
- // let VConsole = require('vconsole');
45
- // // @ts-ignore
46
- // const vConsole = new VConsole();
47
- // setTimeout(() => {
48
- // vConsole.setSwitchPosition(70, 10);
49
- // }, 2000);
43
+ if(DEBUG_VCONSOLE){
44
+ // @ts-ignore
45
+ let VConsole = require('vconsole');
46
+ // @ts-ignore
47
+ const vConsole = new VConsole();
48
+ setTimeout(() => {
49
+ vConsole.setSwitchPosition(70, 10);
50
+ }, 2000);
50
51
  }
52
+
51
53
  // @ts-ignore
52
54
  if(BUILD_ENV){
53
55
  // @ts-ignore
54
56
  window.appLog(`代码环境类型:${BUILD_ENV}`);
55
57
  }
58
+
56
59
  // @ts-ignore
57
60
  if (VERSION_HASH) {
58
61
  // @ts-ignore
59
62
  window.appLog(`VERSION_HASH:${VERSION_HASH}`);
60
63
  }
64
+
61
65
  // @ts-ignore
62
66
  window.appLog(`log init`);
63
67
  // @ts-ignore
@@ -0,0 +1,92 @@
1
+ import React from 'react';
2
+ import {LoadComponent,UpdateAuth} from '@/utils/menu';
3
+
4
+ // @ts-ignore
5
+ import MenuIcon from '@/components/menuIcon';
6
+
7
+ import PageTemplate from '@/pages/pageTemplate';
8
+
9
+ const AuthUser = React.lazy(() => import('@/pages/auth/user'));
10
+ const AuthUserCreate = React.lazy(() => import('@/pages/auth/user/create'));
11
+
12
+
13
+ /**
14
+ * @type {RouteMenuItem}
15
+ */
16
+ const _AUTH={
17
+ name:'控制室',
18
+ url:'/auth',
19
+ msgCount:12,
20
+ primaryId:'auth',
21
+ auth:['auth1'],
22
+ children:[
23
+ {
24
+ name: '用户',
25
+ component:<AuthUser />,
26
+ icon:<MenuIcon name='icon-user'/>,
27
+ url: '/auth/user',
28
+ auth:true,
29
+ primaryId:'authUser',
30
+ msgCount:0,
31
+ children:[
32
+ {
33
+ component:<AuthUserCreate />,
34
+ name:'新建用户',
35
+ url:'/auth/user/create',
36
+ hideMenu:true
37
+ }
38
+ ]
39
+ },
40
+ {
41
+ name: '部门',
42
+ icon:<MenuIcon name='icon-dep'/>,
43
+ url: '/auth/dep',
44
+ auth:true,
45
+ children:[
46
+ {
47
+ component:<PageTemplate name='部门列表' />,
48
+ name:'部门列表',
49
+ url:'/auth/dep/list',
50
+ auth:true,
51
+ children:[
52
+ {
53
+ component:<PageTemplate name='部门详情' />,
54
+ name:'部门详情',
55
+ routeTemplate:'/auth/dep/detail/:id',
56
+ hideMenu:true,
57
+ auth:true,
58
+ }
59
+ ]
60
+ },
61
+
62
+ ]
63
+ },
64
+ {
65
+ name: '角色',
66
+ component:<PageTemplate name='角色' />,
67
+ icon:<MenuIcon name='icon-role'/>,
68
+ url: '/auth/role',
69
+ },
70
+ {
71
+ name: '操作记录',
72
+ component:<PageTemplate name='操作记录' />,
73
+ icon:<MenuIcon name='icon-log'/>,
74
+ url: '/auth/log',
75
+ msgCount:12,
76
+ },
77
+ {
78
+ name: '登录日志',
79
+ component:<PageTemplate name='登录日志' />,
80
+ icon:<MenuIcon name='icon-loginlog'/>,
81
+ url: '/auth/loginLog',
82
+ },
83
+ ],
84
+ }
85
+
86
+
87
+ /**
88
+ * @type {RouteMenuItem}
89
+ */
90
+ const AUTH=UpdateAuth(_AUTH);
91
+
92
+ export default AUTH;
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import {LoadComponent,UpdateAuth} from '@/utils/menu';
3
+
4
+
5
+
6
+
7
+
8
+ /**
9
+ * @type {RouteMenuItem}
10
+ */
11
+ const _DASHBOARD={
12
+ name:'仪表盘',
13
+ url:'/dashboard',
14
+ auth:['auth2'],
15
+ component:LoadComponent(React.lazy(() => import('@/pages/home'))),
16
+ children:[
17
+ ],
18
+ }
19
+
20
+ /**
21
+ * @type {RouteMenuItem}
22
+ */
23
+ const DASHBOARD=UpdateAuth(_DASHBOARD);
24
+
25
+ export default DASHBOARD;
@@ -0,0 +1,76 @@
1
+ import React from 'react';
2
+ import {LoadComponent,UpdateAuth} from '@/utils/menu';
3
+
4
+ // @ts-ignore
5
+ import MenuIcon from '@/components/menuIcon';
6
+
7
+
8
+ const Page2 = React.lazy(() => import('@/pages/demo/page2'));
9
+
10
+
11
+ /**
12
+ * @type {RouteMenuItem}
13
+ */
14
+ const _DNA={
15
+ name:'基因库',
16
+ url:'/dna',
17
+ auth:['auth1'],
18
+ children:[
19
+ {
20
+ name: '父菜单1',
21
+ icon:<MenuIcon name='icon-dep'/>,
22
+ url: '/dna/parent',
23
+ auth:['auth2'],
24
+ children:[
25
+ {
26
+ component:LoadComponent(React.lazy(() => import('@/pages/demo/page1'))),
27
+ name:'子菜单1-1',
28
+ auth:['auth3'],
29
+ url:'/dna/parent/child1'
30
+ }
31
+ ]
32
+ },
33
+ {
34
+ name: '父菜单2',
35
+ icon:<MenuIcon name='icon-dep'/>,
36
+ url: '/dna/parent2',
37
+ auth:true,
38
+ children:[
39
+ {
40
+ component:<Page2 name='父菜单2-子菜单1'/>,
41
+ name:'子菜单2-1',
42
+ auth:true,
43
+ url:'/dna/parent2/child1'
44
+ }
45
+ ]
46
+ },
47
+ {
48
+ name: '父菜单3',
49
+ icon:<MenuIcon name='icon-dep'/>,
50
+ url: '/dna/parent3',
51
+ auth:true,
52
+ children:[
53
+ {
54
+ name:'子菜单3-1',
55
+ auth:true,
56
+ url:'/dna/parent3/child1',
57
+ children:[
58
+ {
59
+ component:<Page2 name='父菜单3-子菜单1-子子菜单1'/>,
60
+ name:'子菜单3-1-1',
61
+ auth:true,
62
+ url:'/dna/parent3/child1/child1'
63
+ }
64
+ ]
65
+ }
66
+ ]
67
+ },
68
+ ],
69
+ }
70
+
71
+ /**
72
+ * @type {RouteMenuItem}
73
+ */
74
+ const DNA=UpdateAuth(_DNA);
75
+
76
+ export default DNA;
@@ -0,0 +1,17 @@
1
+ // @ts-ignore
2
+ import React from 'react';
3
+
4
+ // @ts-ignore
5
+ import DNA from './dna';
6
+ // @ts-ignore
7
+ import AUTH from './auth';
8
+ // @ts-ignore
9
+ import DASHBOARD from './dashboard';
10
+
11
+
12
+
13
+
14
+ /**
15
+ * @type {RouteMenuItem[]}
16
+ */
17
+ export default [DASHBOARD, DNA, AUTH]
@@ -8,7 +8,7 @@ import { createContainer } from "unstated-next";
8
8
  // @ts-ignore
9
9
  import { message } from "@/components/antd";
10
10
 
11
- import {setJwt,setLogout} from '@/services';
11
+ import {setJwt,setLogout} from '@/services/token';
12
12
 
13
13
  import {jumpUrl} from '@/utils';
14
14
  import { KSSO_LOGIN } from '@/services/login';
@@ -21,6 +21,7 @@ import { AUTH_ROUTE_DEBUG_OPEN } from '@/config';
21
21
  * @property {(params:MenuConfig[])=>void} setMenuConfig - 设置菜单属性
22
22
  * @property {()=>Promise<void>} reload - 重新加载渲染菜单
23
23
  * @property {(pathname:string,auths:string[])=>any} getMenuNavigateTo - 获取菜单跳转匹配结果
24
+ * @property {(menu:RouteMenuItem,userAuth:string[])=>RouteMenuItem} findHasAuthMenu - 寻找有权限的菜单
24
25
  *
25
26
  */
26
27
 
@@ -141,7 +142,7 @@ const useProvider=() =>{
141
142
  getLeftMenu(app.auths);
142
143
  },[routeMenu.source,curLocation,app.auths])
143
144
 
144
- return {leftMenu,topMenu,reload,selectMenus,findMenuData,setMenuConfig,getMenuNavigateTo}
145
+ return {leftMenu,topMenu,reload,selectMenus,findMenuData,setMenuConfig,getMenuNavigateTo,findHasAuthMenu}
145
146
  }
146
147
 
147
148
  /**
@@ -1,6 +1,6 @@
1
- import React,{Suspense} from 'react';
1
+ import React,{Suspense, useEffect} from 'react';
2
2
  // @ts-ignore
3
- import { HashRouter, Routes, Route, Navigate } from 'react-router-dom';
3
+ import { HashRouter, Routes, Route, Navigate, useNavigate } from 'react-router-dom';
4
4
  // @ts-ignore
5
5
  import { LayoutBasic, AbsoluteLayout } from '@/components/layout';
6
6
  import ErrorBoundary from '@/components/error';
@@ -16,6 +16,7 @@ import TopMenu from '@/components/topMenu';
16
16
  import ProviderMenu from '@/provider/menu';
17
17
  import Login from '@/pages/login';
18
18
  import menuConfig from './menuConfig';
19
+ import ProviderApp from '@/provider/app';
19
20
 
20
21
 
21
22
 
@@ -24,19 +25,49 @@ const Page404 = React.lazy(() => import('@/pages/error/404'));
24
25
  const Page503 = React.lazy(() => import('@/pages/error/503'));
25
26
 
26
27
 
28
+
29
+ const GetIndexRoute=()=>{
30
+ const app = ProviderApp.useContainer();
31
+ const menu = ProviderMenu.useContainer();
32
+ const nav = useNavigate();
33
+
34
+
35
+ const findRoute=()=>{
36
+ for(let _menu of menu.topMenu){
37
+ let req = menu.findHasAuthMenu(_menu,app.auths);
38
+ if(req){
39
+ debugger;
40
+ nav(req.url);
41
+ return;
42
+ }
43
+ }
44
+ }
45
+ useEffect(()=>{
46
+ findRoute();
47
+ },[])
48
+ return <></>
49
+ }
50
+
51
+
27
52
  const renderMenuConfig=(menu)=>{
28
53
  let req=[];
29
- if(menu.component){
30
- console.log(`${menu.routeTemplate||menu.url}->component`)
31
- req.push(
32
- <Route path={menu.routeTemplate||menu.url} element={menu.component} />
33
- )
34
- }else{
35
- if(menu.children && menu.children[0]){
36
- console.log(`${menu.routeTemplate||menu.url}->${menu.children[0].url}`)
54
+ if(!menu.noAutoMatch){
55
+ if(menu.component){
56
+ console.log(`${menu.routeTemplate||menu.url}->component`)
37
57
  req.push(
38
- <Route path={menu.routeTemplate||menu.url} element={<NavCheck to={menu.children[0].url} />} />
39
- )
58
+ <Route path={menu.routeTemplate||menu.url} element={menu.component} />
59
+ )
60
+ }else{
61
+ if(menu.children && menu.children[0]){
62
+ const childMenu = menu.children[0];
63
+ console.log(`${menu.routeTemplate||menu.url}->${childMenu.url}`)
64
+ if(!childMenu.url){
65
+ console.error('无法自动匹配下一个可跳转路由菜单:',menu)
66
+ }
67
+ req.push(
68
+ <Route path={menu.routeTemplate||menu.url} element={<NavCheck to={childMenu.url} />} />
69
+ )
70
+ }
40
71
  }
41
72
  }
42
73
  if(menu.children){
@@ -64,6 +95,10 @@ export const RouteList = (
64
95
  </ProviderMenu.Provider>
65
96
  }
66
97
  >
98
+
99
+ {/* 首页 */}
100
+ <Route path='/' element={<GetIndexRoute />} />
101
+
67
102
  {
68
103
  menuConfig.map(menu=>renderMenuConfig(menu))
69
104
  }
@@ -1,6 +1,6 @@
1
1
 
2
2
 
3
- import {GET_DEFAULT,POST_DEFAULT,API_ROOT} from './index.js';
3
+ import {GET_DEFAULT,POST_DEFAULT,API_ROOT} from './index';
4
4
 
5
5
 
6
6
 
@@ -0,0 +1,43 @@
1
+ // @ts-ignore
2
+ import Axios from 'axios';
3
+ // @ts-ignore
4
+ import qs from 'qs';
5
+
6
+ import {DefaultRequest} from './interceptor'
7
+
8
+ const axiosExport = Axios.create();
9
+ axiosExport.interceptors.request.use(DefaultRequest);
10
+
11
+ export async function EXPORT_EXCEL(url, param, options) {
12
+ if (param) param = qs.stringify(param, { arrayFormat: 'indices' });
13
+
14
+ let response = await axiosExport({
15
+ method: 'GET',
16
+ url: param ? `${url}?${param}` : url,
17
+ responseType: 'blob',
18
+ getResponse: true,
19
+ ...options,
20
+ });
21
+ // @ts-ignore
22
+ let fileType = response.headers.get('content-type');
23
+ // @ts-ignore
24
+ const disposition = response.headers.get('content-disposition');
25
+
26
+ const blob = new Blob([response.data], { type: `${fileType},charset=UTF-8` });
27
+ const fileName = decodeURI(
28
+ disposition ? disposition.split(';')[1].split('filename=')[1] : 'download.xlsx',
29
+ );
30
+ let blobUrl = window.URL.createObjectURL(blob);
31
+
32
+ const link = document.createElement('a');
33
+ link.href = blobUrl;
34
+ link.download = fileName.replace(/"/g, '');
35
+ document.body.appendChild(link);
36
+ link.style.display='none';
37
+ link.click();
38
+ link.remove();
39
+ setTimeout(() => window.URL.revokeObjectURL(blobUrl), 1000);
40
+
41
+ return null;
42
+ }
43
+
@@ -0,0 +1,155 @@
1
+
2
+ // @ts-ignore
3
+ import qs from 'qs';
4
+
5
+
6
+ export const CreateHttpTools=(axios)=>{
7
+ let buffer = {};
8
+
9
+ /**
10
+ * GET请求
11
+ * @param {string} url - 接口地址
12
+ * @param {Object} [param] - 接口参数
13
+ * @param {Object} [options] - 扩展参数
14
+ * @returns Promise<ServicesResponse>
15
+ */
16
+ const GET_DEFAULT= async (url, param, options) => {
17
+ if (param) param = qs.stringify(param, { arrayFormat: 'indices' });
18
+ let now = Date.now();
19
+
20
+ let bufferItem;
21
+ if (options?.ttl) {
22
+ if (buffer[url]) {
23
+ bufferItem = buffer[url];
24
+ if (bufferItem.param == param && now <= bufferItem.endTime) {
25
+ return bufferItem?.response?.data || null;
26
+ }
27
+ }
28
+ }
29
+ let response = await axios({
30
+ method: 'GET',
31
+ url: param ? `${url}?${param}` : url,
32
+ ...options,
33
+ });
34
+
35
+ if (options?.ttl) {
36
+ if (!buffer[url]) {
37
+ buffer[url] = {};
38
+ }
39
+ buffer[url].param = param;
40
+ let ttl = options.ttl === true ? 1000 * 2 : options.ttl;
41
+ buffer[url].endTime = Date.now() + ttl;
42
+ buffer[url].response = response;
43
+ }
44
+
45
+ return response && response.data ? response.data : null;
46
+ }
47
+
48
+ /**
49
+ * GET请求
50
+ * @param {string} url - 接口地址
51
+ * @param {Object} [param] - 接口参数
52
+ * @returns Promise<ServicesResponse>
53
+ */
54
+ const GET_DEFAULT_CROSS = async (url, param) => {
55
+ if (param) param = qs.stringify(param, { arrayFormat: 'indices' });
56
+
57
+ let response = await axios({
58
+ method: 'GET',
59
+ xsrfCookieName: '',
60
+ xsrfHeaderName: '',
61
+ withCredentials: true,
62
+ url: param ? `${url}?${param}` : url,
63
+ });
64
+ return response && response.data ? response.data : null;
65
+ }
66
+
67
+ /**
68
+ * POST请求
69
+ * @param {string} url - 接口地址
70
+ * @param {Object} [params] - 接口参数
71
+ * @param {Object} [options] - 特殊参数
72
+ *
73
+ * @returns Promise<ServicesResponse>
74
+ */
75
+ const POST_DEFAULT= async (url, params, options) => {
76
+ let data = params;
77
+ // if (params) params = qs.stringify(params, { arrayFormat: 'indices' });
78
+ // if (typeof params === 'string') {
79
+ // data = params;
80
+ // } else {
81
+ // data = { ...params };
82
+ // }
83
+ let response = await axios({
84
+ method: 'POST',
85
+ url: url,
86
+ data,
87
+ ...options,
88
+ // headers: { 'content-type': 'application/x-www-form-urlencoded' },
89
+ });
90
+ return response && response.data ? response.data : null;
91
+ }
92
+
93
+
94
+ /**
95
+ * POST请求
96
+ * @param {string} url - 接口地址
97
+ * @param {Object} [params] - 接口参数
98
+ *
99
+ * @returns Promise<ServicesResponse>
100
+ */
101
+ const POST_DEFAULT_CROSS= async (url, params) => {
102
+ let data = {};
103
+ // if (params) params = qs.stringify(params, { arrayFormat: 'indices' });
104
+
105
+ if (typeof params === 'string') {
106
+ data = params;
107
+ } else {
108
+ data = { ...params };
109
+ }
110
+ let response = await axios({
111
+ method: 'POST',
112
+ url: url,
113
+ xsrfCookieName: '',
114
+ xsrfHeaderName: '',
115
+ withCredentials: true,
116
+ data,
117
+ });
118
+
119
+ return response && response.data ? response.data : null;
120
+ }
121
+
122
+ const PUT_DEFAULT= async (url,params,options)=> {
123
+ let data=params;
124
+
125
+ let response=await axios({
126
+ method: 'PUT',
127
+ url: url,
128
+ data,
129
+ ...options,
130
+ });
131
+ return response&&response.data? response.data:null;
132
+ }
133
+
134
+ const DELETE_DEFAULT = async (url,params,options) => {
135
+ let data=params;
136
+
137
+ let response=await axios({
138
+ method: 'DELETE',
139
+ url: url,
140
+ data,
141
+ ...options,
142
+ });
143
+ return response&&response.data? response.data:null;
144
+ }
145
+
146
+ return {
147
+ GET_DEFAULT,
148
+ GET_DEFAULT_CROSS,
149
+ POST_DEFAULT,
150
+ POST_DEFAULT_CROSS,
151
+ PUT_DEFAULT,
152
+ DELETE_DEFAULT
153
+ }
154
+
155
+ }
@@ -1,24 +1,19 @@
1
1
  // @ts-ignore
2
2
  import Axios from 'axios';
3
3
  // @ts-ignore
4
- import qs from 'qs';
5
- // @ts-ignore
6
4
  import { message } from '@/components/antd';
7
5
  import {WriteLog} from '@/utils';
6
+ import {CreateHttpTools} from './http';
8
7
 
9
- import {DEBUG_API_HOST,DEBUG_REPORT_API_HOST } from '@/config';
8
+ import { DEBUG_API_HOST } from '@/config';
9
+ import {logout} from './token';
10
+ import {DefaultRequest} from './interceptor';
11
+ import {FormatTableService,FormatGetRequest,FormatRequestClean} from './interceptor';
10
12
 
11
13
 
12
- const axios = Axios.create();
13
14
 
14
15
  // @ts-ignore
15
16
  export const API_ROOT= BUILD_ENV=='localdebug'?DEBUG_API_HOST:API_HOST;
16
- // @ts-ignore
17
- console.log(`========API_ROOT:${API_ROOT}========`);
18
-
19
- const tokenMode='header';//header,cookie
20
- const tokenName='Authorization';
21
-
22
17
  export const RESPONSE_STRUCT={
23
18
  CODE:'code',
24
19
  MSG:'msg',
@@ -26,54 +21,17 @@ export const RESPONSE_STRUCT={
26
21
  PAGINATION:'pagination'
27
22
  }
28
23
 
29
- let Modal = {
24
+ // @ts-ignore
25
+ console.log(`========API_ROOT:${API_ROOT}========`);
26
+
27
+ const Modal = {
30
28
  error: (options) => {
31
29
  message.error(options.content);
32
30
  },
33
31
  };
34
32
 
35
- let jwt = '';
36
- let _logout = ()=>{}
37
-
38
- export const setJwt = (value) => {
39
- if(value==''){
40
- localStorage.removeItem('jwt');
41
- jwt='';
42
- return;
43
-
44
- }
45
- localStorage.setItem('jwt', value);
46
- jwt = value;
47
- };
48
- export const getJwt=()=>{
49
- return jwt;
50
- }
51
- // @ts-ignore
52
- window.setJwt=setJwt;
53
- export const setLogout=(fn)=>{
54
- _logout=fn;
55
- }
56
- export const logout=()=>{
57
- _logout();
58
- }
59
-
60
-
61
- axios.interceptors.request.use(function (config) {
62
- const header = { 'X-Requested-With': 'XMLHttpRequest' };
63
- if(tokenMode=='header'){
64
- if (jwt) {
65
- header[tokenName] = jwt;
66
- }
67
- }
68
- if (config.headers) {
69
- config.headers = { ...config.headers, ...header };
70
- } else {
71
- config.headers = header;
72
- }
73
-
74
- // 在发送请求之前做些什么
75
- return config;
76
- });
33
+ const axios = Axios.create();
34
+ axios.interceptors.request.use(DefaultRequest);
77
35
 
78
36
  let ERROR_401_COUNT=0;
79
37
  /**
@@ -139,236 +97,30 @@ axios.interceptors.response.use(
139
97
 
140
98
 
141
99
 
142
-
143
- let buffer = {};
144
- /**
145
- * GET请求
146
- * @param {string} url - 接口地址
147
- * @param {Object} [param] - 接口参数
148
- * @param {Object} [options] - 扩展参数
149
- * @returns Promise<ServicesResponse>
150
- */
151
- export async function GET_DEFAULT(url, param, options) {
152
- if (param) param = qs.stringify(param, { arrayFormat: 'indices' });
153
- let now = Date.now();
154
-
155
- let bufferItem;
156
- if (options?.ttl) {
157
- if (buffer[url]) {
158
- bufferItem = buffer[url];
159
- if (bufferItem.param == param && now <= bufferItem.endTime) {
160
- return bufferItem?.response?.data || null;
161
- }
162
- }
163
- }
164
- let response = await axios({
165
- method: 'GET',
166
- url: param ? `${url}?${param}` : url,
167
- ...options,
168
- });
169
-
170
- if (options?.ttl) {
171
- if (!buffer[url]) {
172
- buffer[url] = {};
173
- }
174
- buffer[url].param = param;
175
- let ttl = options.ttl === true ? 1000 * 2 : options.ttl;
176
- buffer[url].endTime = Date.now() + ttl;
177
- buffer[url].response = response;
178
- }
179
-
180
- return response && response.data ? response.data : null;
100
+ const DEFAULT_HTTP = CreateHttpTools(axios);
101
+ const {
102
+ GET_DEFAULT,
103
+ GET_DEFAULT_CROSS,
104
+ POST_DEFAULT,
105
+ POST_DEFAULT_CROSS,
106
+ DELETE_DEFAULT,
107
+ PUT_DEFAULT
108
+ } = DEFAULT_HTTP;
109
+
110
+ export {
111
+ GET_DEFAULT,
112
+ GET_DEFAULT_CROSS,
113
+ POST_DEFAULT,
114
+ POST_DEFAULT_CROSS,
115
+ DELETE_DEFAULT,
116
+ PUT_DEFAULT
181
117
  }
182
118
 
183
- /**
184
- * GET请求
185
- * @param {string} url - 接口地址
186
- * @param {Object} [param] - 接口参数
187
- * @returns Promise<ServicesResponse>
188
- */
189
- export async function GET_DEFAULT_CROSS(url, param) {
190
- if (param) param = qs.stringify(param, { arrayFormat: 'indices' });
191
119
 
192
- let response = await axios({
193
- method: 'GET',
194
- xsrfCookieName: '',
195
- xsrfHeaderName: '',
196
- withCredentials: true,
197
- url: param ? `${url}?${param}` : url,
198
- });
199
- return response && response.data ? response.data : null;
200
- }
201
120
 
202
- /**
203
- * POST请求
204
- * @param {string} url - 接口地址
205
- * @param {Object} [params] - 接口参数
206
- * @param {Object} [options] - 特殊参数
207
- *
208
- * @returns Promise<ServicesResponse>
209
- */
210
- export async function POST_DEFAULT(url, params, options) {
211
- let data = params;
212
- // if (params) params = qs.stringify(params, { arrayFormat: 'indices' });
213
- // if (typeof params === 'string') {
214
- // data = params;
215
- // } else {
216
- // data = { ...params };
217
- // }
218
121
 
219
- let response = await axios({
220
- method: 'POST',
221
- url: url,
222
- data,
223
- ...options,
224
- // headers: { 'content-type': 'application/x-www-form-urlencoded' },
225
- });
226
- return response && response.data ? response.data : null;
122
+ export {
123
+ FormatTableService,
124
+ FormatGetRequest,
125
+ FormatRequestClean
227
126
  }
228
-
229
-
230
- /**
231
- * POST请求
232
- * @param {string} url - 接口地址
233
- * @param {Object} [params] - 接口参数
234
- *
235
- * @returns Promise<ServicesResponse>
236
- */
237
- export async function POST_DEFAULT_CROSS(url, params) {
238
- let data = {};
239
- // if (params) params = qs.stringify(params, { arrayFormat: 'indices' });
240
-
241
- if (typeof params === 'string') {
242
- data = params;
243
- } else {
244
- data = { ...params };
245
- }
246
- let response = await axios({
247
- method: 'POST',
248
- url: url,
249
- xsrfCookieName: '',
250
- xsrfHeaderName: '',
251
- withCredentials: true,
252
- data,
253
- });
254
-
255
- return response && response.data ? response.data : null;
256
- }
257
-
258
- export async function PUT_DEFAULT(url,params,options) {
259
- let data=params;
260
-
261
- let response=await axios({
262
- method: 'PUT',
263
- url: url,
264
- data,
265
- ...options,
266
- });
267
- return response&&response.data? response.data:null;
268
- }
269
- export async function DELETE_DEFAULT(url,params,options) {
270
- let data=params;
271
-
272
- let response=await axios({
273
- method: 'DELETE',
274
- url: url,
275
- data,
276
- ...options,
277
- });
278
- return response&&response.data? response.data:null;
279
- }
280
-
281
-
282
-
283
- const axiosExport = Axios.create();
284
- axiosExport.interceptors.request.use(function (config) {
285
- const header = { 'X-Requested-With': 'XMLHttpRequest' };
286
- if(tokenMode=='header'){
287
- if (jwt) {
288
- header[tokenName] = jwt;
289
- }
290
- }
291
- if (config.headers) {
292
- config.headers = { ...config.headers, ...header };
293
- } else {
294
- config.headers = header;
295
- }
296
-
297
- // 在发送请求之前做些什么
298
- return config;
299
- });
300
- export async function EXPORT_EXCEL(url, param, options) {
301
- if (param) param = qs.stringify(param, { arrayFormat: 'indices' });
302
-
303
- let response = await axiosExport({
304
- method: 'GET',
305
- url: param ? `${url}?${param}` : url,
306
- responseType: 'blob',
307
- getResponse: true,
308
- ...options,
309
- });
310
- let fileType = response.headers.get('content-type');
311
- const disposition = response.headers.get('content-disposition');
312
-
313
- const blob = new Blob([response.data], { type: `${fileType},charset=UTF-8` });
314
- const fileName = decodeURI(
315
- disposition ? disposition.split(';')[1].split('filename=')[1] : 'download.xlsx',
316
- );
317
- let blobUrl = window.URL.createObjectURL(blob);
318
-
319
- const link = document.createElement('a');
320
- link.href = blobUrl;
321
- link.download = fileName.replace(/"/g, '');
322
- document.body.appendChild(link);
323
- link.style.display='none';
324
- link.click();
325
- link.remove();
326
- setTimeout(() => window.URL.revokeObjectURL(blobUrl), 1000);
327
-
328
- return null;
329
- }
330
-
331
-
332
- export const FormatTableService = (response)=>{
333
- let req={
334
- code:response[RESPONSE_STRUCT.CODE]||0,
335
- data:response[RESPONSE_STRUCT.DATA]||null,
336
- msg:response[RESPONSE_STRUCT.MSG]||''
337
- };
338
- if(response[RESPONSE_STRUCT.PAGINATION]){
339
- req.page = response[RESPONSE_STRUCT.PAGINATION]
340
- }
341
- return req;
342
- };
343
-
344
- /**
345
- * 格式化处理GET请求的参数,将传参为空的删除掉,因为后端认为空字符串也是属于一个特定字符查询
346
- * @param {object} requestParams
347
- * @returns {object}
348
- */
349
- export const FormatGetRequest=(requestParams)=>{
350
- for(let key in requestParams){
351
- if(requestParams[key]==''
352
- ||requestParams[key]===null
353
- ||requestParams[key]==undefined
354
- ){
355
- delete requestParams[key];
356
- }
357
- }
358
- return requestParams;
359
- }
360
-
361
-
362
- /**
363
- * 清理以_开头的不参与接口提交的参数
364
- * @param {object} requestParams
365
- * @returns {object}
366
- */
367
- export const FormatRequestClean=(requestParams)=>{
368
- for(let key in requestParams){
369
- if(/^[_].*/.test(key)){
370
- delete requestParams[key];
371
- }
372
- }
373
- return requestParams;
374
- }
@@ -0,0 +1,67 @@
1
+
2
+
3
+ import {RESPONSE_STRUCT} from '../';
4
+ import {addToken} from '../token';
5
+
6
+
7
+
8
+ export const DefaultRequest=(config)=> {
9
+ let header = { 'X-Requested-With': 'XMLHttpRequest' };
10
+ header = addToken(header);
11
+ if (config.headers) {
12
+ config.headers = { ...config.headers, ...header };
13
+ } else {
14
+ config.headers = header;
15
+ }
16
+ // 在发送请求之前做些什么
17
+ return config;
18
+ }
19
+
20
+
21
+
22
+ export const FormatTableService = (response)=>{
23
+ let req={
24
+ code:response[RESPONSE_STRUCT.CODE]||0,
25
+ data:response[RESPONSE_STRUCT.DATA]||null,
26
+ msg:response[RESPONSE_STRUCT.MSG]||''
27
+ };
28
+ if(response[RESPONSE_STRUCT.PAGINATION]){
29
+ req.page = response[RESPONSE_STRUCT.PAGINATION]
30
+ }
31
+ return req;
32
+ };
33
+
34
+ /**
35
+ * 格式化处理GET请求的参数,将传参为空的删除掉,因为后端认为空字符串也是属于一个特定字符查询
36
+ * @param {object} requestParams
37
+ * @returns {object}
38
+ */
39
+ export const FormatGetRequest=(requestParams)=>{
40
+ for(let key in requestParams){
41
+ if(requestParams[key]==''
42
+ ||requestParams[key]===null
43
+ ||requestParams[key]==undefined
44
+ ){
45
+ delete requestParams[key];
46
+ }
47
+ }
48
+ return requestParams;
49
+ }
50
+
51
+
52
+ /**
53
+ * 清理以_开头的不参与接口提交的参数
54
+ * @param {object} requestParams
55
+ * @returns {object}
56
+ */
57
+ export const FormatRequestClean=(requestParams)=>{
58
+ for(let key in requestParams){
59
+ if(/^[_].*/.test(key)){
60
+ delete requestParams[key];
61
+ }
62
+ }
63
+ return requestParams;
64
+ }
65
+
66
+
67
+
@@ -1,4 +1,4 @@
1
- import {GET_DEFAULT,API_ROOT,POST_DEFAULT,PUT_DEFAULT} from './index.js';
1
+ import {GET_DEFAULT,API_ROOT,POST_DEFAULT} from './index';
2
2
 
3
3
 
4
4
 
@@ -1,10 +1,9 @@
1
1
 
2
- import {getJwt} from '@/services'
2
+ import {getJwt,logout} from '../token'
3
3
  // @ts-ignore
4
4
  import {Modal} from '@/components/antd';
5
-
6
5
  import { CONSOLE_LOG ,WriteLog} from '@/utils';
7
- import {logout} from '@/services'
6
+
8
7
  let _ws;
9
8
  let timer=null;
10
9
 
@@ -0,0 +1,41 @@
1
+
2
+ const tokenMode='header';//header,cookie
3
+ const tokenName='Authorization';
4
+
5
+ let jwt = '';
6
+ let _logout = ()=>{}
7
+
8
+
9
+ export const setJwt = (value) => {
10
+ if(value==''){
11
+ localStorage.removeItem('jwt');
12
+ jwt='';
13
+ return;
14
+
15
+ }
16
+ localStorage.setItem('jwt', value);
17
+ jwt = value;
18
+ };
19
+ export const getJwt=()=>{
20
+ return jwt;
21
+ }
22
+
23
+ export const setLogout=(fn)=>{
24
+ _logout=fn;
25
+ }
26
+ export const logout=()=>{
27
+ _logout();
28
+ }
29
+
30
+ export const addToken=(header)=>{
31
+ if(tokenMode=='header'){
32
+ if (jwt) {
33
+ header[tokenName] = jwt;
34
+ }
35
+ }
36
+ return header;
37
+ }
38
+
39
+ if(window){
40
+ window['setJwt']=setJwt;
41
+ }
@@ -49,7 +49,9 @@
49
49
  * 菜单项
50
50
  * @typedef RouteMenuItem
51
51
  * @property {string} name - 菜单展示的名称
52
- * @property {string|JSX.Element} [icon] - 菜单图标
52
+ * @property {boolean} [noAutoMatch=false] - 关闭自动菜单匹配跳转
53
+ * @property {import("react").JSX.Element} [component] - 菜单对应的页面JSX组件
54
+ * @property {string|import("react").JSX.Element} [icon] - 菜单图标
53
55
  * @property {string} [url] - 菜单的URL地址
54
56
  * @property {string} [routeTemplate] - 菜单的路由模版,用于匹配动态路由
55
57
  * @property {number} [msgCount] - 菜单的未读消息数量
@@ -0,0 +1,33 @@
1
+ import React from "react";
2
+
3
+
4
+ export const LoadComponent=(lazyComponent)=>{
5
+ return React.createElement(lazyComponent)
6
+ }
7
+
8
+ /**
9
+ * 自动计算菜单权限,使父级菜单权限包含所有子菜单的权限
10
+ * @param {RouteMenuItem} menu
11
+ * @returns {RouteMenuItem}
12
+ */
13
+ export const UpdateAuth=(menu)=>{
14
+ if(menu.children){
15
+
16
+ let auths= menu.children.map(childMenu=>{
17
+ let _childMenu = UpdateAuth(childMenu);
18
+ if( Array.isArray(_childMenu.auth) ){
19
+ return [..._childMenu.auth];
20
+ }
21
+ return [];
22
+ });
23
+
24
+ if( Array.isArray(menu.auth) ){
25
+
26
+ menu.auth = [...menu.auth,...auths.flat()];
27
+ // @ts-ignore
28
+ menu.auth = [...new Set(menu.auth)];// 去重
29
+ }
30
+ }
31
+ return menu;
32
+ }
33
+
@@ -1,39 +0,0 @@
1
- import {GET_DEFAULT,API_ROOT,POST_DEFAULT,PUT_DEFAULT} from './index.js';
2
-
3
-
4
- /**
5
- * 获取当前用户的权限列表
6
- * @returns {Promise<ServicesResponse>}
7
- */
8
- export function GET_MY_AUTH(params={
9
- isTree:'',
10
- isShow:''
11
- }){
12
- return GET_DEFAULT(`${API_ROOT}/my/permissions`,params)
13
- }
14
-
15
- /**
16
- * 获取我的角色列表
17
- * @returns {Promise<ServicesResponse>}
18
- */
19
- export function GET_MY_ROLES(params={}){
20
- return GET_DEFAULT(`${API_ROOT}/my/roles`,params)
21
-
22
- }
23
-
24
- /**
25
- * 获取我的账号列表
26
- * @returns {Promise<ServicesResponse>}
27
- */
28
- export function GET_MY_WORK_USERS(params={}){
29
- return GET_DEFAULT(`${API_ROOT}/my/weworkUsers`,params)
30
- }
31
-
32
- /**
33
- * 切换账号列表
34
- * @returns {Promise<ServicesResponse>}
35
- */
36
- export function CHANGE_MY_WORK_USERS(params={}) {
37
- return PUT_DEFAULT(`${API_ROOT}/my/weworkUsers/selected`,params)
38
- }
39
-