tms-auth 1.3.26

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 (47) hide show
  1. package/.editorconfig +16 -0
  2. package/.prettierignore +7 -0
  3. package/.prettierrc.js +1 -0
  4. package/.umirc.ts +10 -0
  5. package/.vscode/settings.json +3 -0
  6. package/README.md +37 -0
  7. package/bin/scripts.js +45 -0
  8. package/config/paths.js +23 -0
  9. package/config/rollup.config.js +54 -0
  10. package/dist/index.js +1 -0
  11. package/docs/index.md +2 -0
  12. package/package.json +82 -0
  13. package/publish_dist_to_branch.js +263 -0
  14. package/scripts/build.js +33 -0
  15. package/scripts/start.js +38 -0
  16. package/src/Error/403.tsx +18 -0
  17. package/src/Error/404.tsx +18 -0
  18. package/src/actions/lang.js +5 -0
  19. package/src/index.ts +28 -0
  20. package/src/layouts/BaseLayout.tsx +518 -0
  21. package/src/layouts/Header.tsx +33 -0
  22. package/src/layouts/HeaderLeft.tsx +145 -0
  23. package/src/layouts/HeaderRight.tsx +152 -0
  24. package/src/layouts/Ifame/index.less +7 -0
  25. package/src/layouts/Ifame/index.tsx +27 -0
  26. package/src/layouts/Loading/index.less +22 -0
  27. package/src/layouts/Loading/index.tsx +44 -0
  28. package/src/layouts/NavigationBar.tsx +49 -0
  29. package/src/layouts/NavigationBarWithAntd.tsx +165 -0
  30. package/src/layouts/Prompt/index.less +6 -0
  31. package/src/layouts/Prompt/index.tsx +102 -0
  32. package/src/layouts/index.less +283 -0
  33. package/src/layouts/logo.svg +21 -0
  34. package/src/login/Callback.tsx +63 -0
  35. package/src/login/Index.tsx +27 -0
  36. package/src/login/Login.tsx +120 -0
  37. package/src/login/index.less +59 -0
  38. package/src/login/logo.svg +21 -0
  39. package/src/reducers/lang.js +21 -0
  40. package/src/store/index.js +5 -0
  41. package/src/styles/global.less +103 -0
  42. package/src/styles/mixin.less +35 -0
  43. package/src/utils/fetch.ts +33 -0
  44. package/src/utils/sdk.ts +608 -0
  45. package/src/utils/utils.ts +15 -0
  46. package/tsconfig.json +19 -0
  47. package/typings.d.ts +2 -0
@@ -0,0 +1,608 @@
1
+ import fetchData from './fetch';
2
+ import { stringify } from 'qs';
3
+ import store from '@/store';
4
+ import { UPDATE_LANG } from '@/actions/lang';
5
+ import { HELLO_MSG, REPLY_MSG } from './utils';
6
+ import { history } from 'umi';
7
+ import { recordPath } from '@/layouts/BaseLayout';
8
+
9
+ type AppMenuList = {
10
+ id: number;
11
+ appId: string;
12
+ sortOrder: number;
13
+ appDomain: string;
14
+ defaultDomain: string;
15
+ children: AppMenuList;
16
+ }[];
17
+
18
+ const PUBLISH_PATH = /https?:\/\/[^\/]+(.*)/;
19
+ /**
20
+ * @description 直接出发TMS的接口
21
+ */
22
+ const TMS_API_DOMAIN = {
23
+ dev: `https://tms-gateway-dev.chatlabs.net`,
24
+ uat: `https://tms-gateway-staging.chatlabs.net`,
25
+ demo: 'https://tms-gateway-demo.chatlabs.net',
26
+ live: 'https://login.chatlabs.net',
27
+ portal: 'https://portal.chatlabs.net',
28
+ };
29
+
30
+ const getTmsAdminApiDomain = (_env: keyof typeof TMS_API_DOMAIN) => {
31
+ if (!_env || ['dev', 'uat', 'demo', 'live', 'portal'].indexOf(_env) == -1) {
32
+ _env = 'dev';
33
+ }
34
+ const TMS_ADMIN_API_DOMAIN = `${TMS_API_DOMAIN[_env]}/admin`; // swagger上的接口
35
+ return TMS_ADMIN_API_DOMAIN;
36
+ };
37
+
38
+ const env = process.env.NODE_ENV;
39
+ const IS_DEV = window.location.hostname == 'localhost';
40
+
41
+ var showLog = IS_DEV || env === 'development';
42
+
43
+ class Tms {
44
+ state = {
45
+ config: {
46
+ appDomain: window.location.origin,
47
+ login_api_domain: '', // TMS 换取 token 和 刷新token 的特定api前缀
48
+ client_id: '',
49
+
50
+ callbackPath: '/callback', // callback路径
51
+ loginPath: '/login', // 登录页面路径
52
+ indexPath: '/tmsiframe', // index路径
53
+ error403Path: '/403', // 403 路径
54
+ error404Path: '/404', // 403 路径
55
+
56
+ tokenKey: 'TOKEN', // token
57
+ sessionIdKey: 'SESSION_ID', // session-id
58
+ curAppKey: 'CUR_APP', // 当前应用
59
+ curMenuKey: 'CUR_MENU', // 当前菜单
60
+ lastPathKey: 'LAST_PATH', // 上一页面路径
61
+
62
+ lang: 'cn', // 语种 cn/en
63
+ useSessionStorage: false, // 默认为false;true用ssessionStorage,false 用localStorage
64
+ env: 'dev', // 默认使用tms的dev环境 dev、uat、live
65
+
66
+ needPostMsg: true, // 当打开窗口的时候传递数据
67
+ storage: localStorage,
68
+ },
69
+
70
+ isinitialized: false, // 是否已初始化
71
+ };
72
+
73
+ constructor() {}
74
+
75
+ /**
76
+ *
77
+ * @param config 初始化的配置项,在业务方 tms/config 文件内
78
+ */
79
+ initConfig(config: any = {}) {
80
+ console.log('当前 tms-auth 包的版本:', 'TMS_AUTH_VERSION');
81
+ console.log('initConfig', JSON.stringify(config));
82
+
83
+ this.state.config = {
84
+ ...this.state.config,
85
+ ...config,
86
+ storage: config.useSessionStorage ? sessionStorage : localStorage,
87
+ };
88
+ this.state.isinitialized = true;
89
+ const tmsConfig = this.state.config;
90
+ let listener = (e: any) => {
91
+ try {
92
+ const data = JSON.parse(e.data);
93
+ if (data.type === 'logout') {
94
+ recordPath();
95
+ history.replace(tmsConfig.loginPath);
96
+ }
97
+ } catch (error) {}
98
+ };
99
+ window.addEventListener('message', listener, false);
100
+ store.dispatch({ type: UPDATE_LANG, payload: config.lang || this.state.config.lang });
101
+ }
102
+
103
+ getConfig() {
104
+ return this.state.config;
105
+ }
106
+
107
+ getConfigByKey(key = '') {
108
+ return this.state.config[key];
109
+ }
110
+
111
+ checkIsinitialized() {
112
+ const initialized = this.state.isinitialized;
113
+ showLog && console.log('检查是否已初始化配置参数', initialized);
114
+ return initialized;
115
+ }
116
+
117
+ /**
118
+ *
119
+ * @param params 非必传
120
+ * appDomain 默认是 window.location.origin, 若应用的请求数据路径跟其有异,则需要传入该参数
121
+ * tenant_id 在切换应用的时候才获取
122
+ */
123
+ login(params: any = null) {
124
+ const { config: tmsConfig } = this.state;
125
+ const domain = IS_DEV
126
+ ? tmsConfig.appDomain
127
+ : (params && params.appDomain) || tmsConfig.appDomain;
128
+ showLog && console.log('login tmsConfig', params, JSON.stringify(tmsConfig));
129
+
130
+ window.location = `${TMS_API_DOMAIN[tmsConfig.env]}/auth/oauth/authorize?client_id=${
131
+ tmsConfig.client_id
132
+ }&response_type=code&redirect_uri=${domain}${tmsConfig.callbackPath}&app_domain=${domain}${
133
+ params && params.tenant_id ? `&TENANT-ID=${params.tenant_id}` : ''
134
+ }&language=${tmsConfig.lang}`; // 直接跳转这个路径,由后端进行重定向
135
+ }
136
+
137
+ //租户当前应用无权限时跳转
138
+ tmsErrorLogin(params: any = null) {
139
+ const { config: tmsConfig } = this.state;
140
+ const domain = IS_DEV
141
+ ? tmsConfig.appDomain
142
+ : (params && params.appDomain) || tmsConfig.appDomain;
143
+ showLog && console.log('login tmsConfig', params, JSON.stringify(tmsConfig));
144
+
145
+ window.location = `${TMS_API_DOMAIN[tmsConfig.env]}/auth/token/login?client_id=${
146
+ tmsConfig.client_id
147
+ }&response_type=code&redirect_uri=${domain}${
148
+ tmsConfig.callbackPath
149
+ }&app_domain=${domain}&relogin=true&language=${tmsConfig.lang}`; // 直接跳转这个路径,由后端进行重定向
150
+ }
151
+
152
+ /**
153
+ *
154
+ * @param params 非必传
155
+ * tenantId 默认从sessionStorage获取;如果无法从sessionStorage里获取token 以及 tenant_id 等信息,则需要从参数中传入,一般发生在登录时账号报错/不匹配/无权限等异常情况
156
+ * sessionId 默认从sessionStorage获取;如无法从sessionStorage获取,则需要从参数中传入,一般发生在登录时账号报错/不匹配/无权限等异常情况
157
+ * @returns
158
+ */
159
+ logout(params = {}) {
160
+ showLog && console.log('logout 接口', params);
161
+ // window?.parent?.postMessage(JSON.stringify({ type: 'logout' }), '*');
162
+ return new Promise((resolve, reject) => {
163
+ try {
164
+ const { login_api_domain, sessionIdKey, tokenKey } = this.state.config;
165
+ const TmsStorage = this.getStorage();
166
+ const tokenStr = TmsStorage.getItem(tokenKey) || '{}';
167
+ const tokenObj = JSON.parse(tokenStr);
168
+
169
+ const dataParams = {
170
+ sessionId: TmsStorage.getItem(sessionIdKey),
171
+ ...params,
172
+ };
173
+
174
+ // 如登录时发生错误,还没来得及获取到token,则无accessToken信息,不需要传给后端
175
+ if (tokenObj && tokenObj.access_token) {
176
+ dataParams.accessToken = tokenObj.access_token;
177
+ }
178
+
179
+ fetchData(
180
+ `${login_api_domain}/sso/logout?${dataParams ? stringify(dataParams) : ''}`,
181
+ 'GET',
182
+ null,
183
+ {
184
+ 'TENANT-ID': (params && params.tenantId) || tokenObj.tenant_id,
185
+ },
186
+ )
187
+ .then((res) => {
188
+ return res.json();
189
+ })
190
+ .then((res) => {
191
+ console.log('logout fetchData res', res);
192
+ const { code, data, msg } = res;
193
+ if (code == 0) {
194
+ TmsStorage.removeItem(sessionIdKey);
195
+ TmsStorage.removeItem(tokenKey);
196
+ if (window.opener) window.opener = null; // 避免login加载message监听事件
197
+ resolve();
198
+ } else {
199
+ reject(res);
200
+ }
201
+ // {code: 1, msg: 'Invalid authorization code: 1PdJQT', data: 'invalid_exception'}
202
+ });
203
+ } catch (error) {
204
+ console.log('logout fetch data error', error);
205
+ }
206
+ });
207
+ }
208
+
209
+ /**
210
+ *
211
+ * @param params 必传
212
+ * callback callback页面,默认获取当前页面,如有不同则需传入
213
+ * code 由TMS返回,在query上获取
214
+ * TENANT-ID 由TMS返回,在query上获取
215
+ * SESSION-ID 由TMS返回,在query上获取
216
+ * @returns
217
+ */
218
+ getToken(params = {}) {
219
+ showLog && console.log('getToken', params);
220
+ return new Promise((resolve, reject) => {
221
+ try {
222
+ const { login_api_domain, sessionIdKey, tokenKey, callbackPath, appDomain } =
223
+ this.state.config;
224
+ const TmsStorage = this.getStorage();
225
+ const tenantId = params['TENANT-ID'],
226
+ sessionId = params['SESSION-ID']; // 这个TENANT-ID、SESSION-ID是后端返回的参数,不能改
227
+ const dataParams = {
228
+ callback: `${appDomain}${callbackPath}`,
229
+ ...params,
230
+ };
231
+ fetchData(
232
+ `${login_api_domain}/sso/token?${dataParams ? stringify(dataParams) : ''}`,
233
+ 'GET',
234
+ null,
235
+ {
236
+ 'TENANT-ID': tenantId,
237
+ },
238
+ )
239
+ .then((res) => {
240
+ return res.json();
241
+ })
242
+ .then((res) => {
243
+ console.log('getToken fetchData res', JSON.stringify(res), res);
244
+ const { code, data, msg } = res;
245
+ if (code == 0 && data) {
246
+ TmsStorage.setItem(sessionIdKey, sessionId);
247
+ TmsStorage.setItem(tokenKey, JSON.stringify(data));
248
+
249
+ resolve(data);
250
+ } else {
251
+ const { loginPath, appDomain } = this.state.config;
252
+ console.log('getToken fetchData reject ');
253
+ if (code == 425) {
254
+ return this.tmsErrorLogin();
255
+ }
256
+ const publishPath = (appDomain.match(PUBLISH_PATH) || [])[1];
257
+ const redirectLogin =
258
+ typeof publishPath === 'string' && publishPath !== '/'
259
+ ? publishPath + loginPath
260
+ : loginPath;
261
+
262
+ this.logout({
263
+ sessionId: sessionId,
264
+ tenantId: tenantId,
265
+ })
266
+ .then(() => {
267
+ window.location.href = redirectLogin;
268
+ })
269
+ .catch((err) => {
270
+ window.location.href = redirectLogin;
271
+ });
272
+ }
273
+ // {code: 1, msg: 'Invalid authorization code: 1PdJQT', data: 'invalid_exception'}
274
+ });
275
+ } catch (error) {
276
+ console.log('getToken fetch data error', error);
277
+ }
278
+ });
279
+ }
280
+
281
+ /**
282
+ * 刷新token
283
+ * @returns
284
+ */
285
+ refreshToken() {
286
+ showLog && console.log('refreshToken');
287
+ return new Promise((resolve, reject) => {
288
+ try {
289
+ const { config: tmsConfig } = this.state;
290
+ const TmsStorage = this.getStorage();
291
+ const tokenStr = TmsStorage.getItem(tmsConfig.tokenKey);
292
+ const tokenObj = JSON.parse(tokenStr);
293
+
294
+ const dataParams = {
295
+ refreshToken: tokenObj.refresh_token,
296
+ };
297
+
298
+ fetchData(
299
+ `${tmsConfig.login_api_domain}/sso/refreshToken?${
300
+ dataParams ? stringify(dataParams) : ''
301
+ }`,
302
+ 'GET',
303
+ null,
304
+ {
305
+ 'TENANT-ID': tokenObj.tenant_id,
306
+ },
307
+ )
308
+ .then((res) => {
309
+ return res.json();
310
+ })
311
+ .then((res) => {
312
+ console.log('refreshToken fetchData res', JSON.stringify(res), res);
313
+ const { code, data, msg } = res;
314
+ if (code == 0 && data) {
315
+ TmsStorage.setItem(tmsConfig.tokenKey, JSON.stringify(data));
316
+ resolve(data);
317
+ } else {
318
+ reject(res);
319
+ }
320
+ // {code: 1, msg: 'Invalid authorization code: 1PdJQT', data: 'invalid_exception'}
321
+ })
322
+ .catch((err) => {
323
+ reject(err);
324
+ });
325
+ } catch (error) {
326
+ console.log('refreshToken fetch data error', error);
327
+ }
328
+ });
329
+ }
330
+
331
+ // 更新token,如果失效了直接自动登录
332
+ refreshTokenWithAutoLogin(recordPath = true) {
333
+ console.log('refreshTokenWithAutoLogin: 我在刷新token');
334
+ return new Promise((reslove, reject) => {
335
+ const { config: tmsConfig } = this.state;
336
+ showLog && console.log('refreshTokenWithAutoLogin --- tmsConfig', tmsConfig);
337
+ const TmsStorage = this.getStorage();
338
+ const tokenStr = TmsStorage.getItem(tmsConfig.tokenKey);
339
+ if (tokenStr) {
340
+ const tokenObj = JSON.parse(tokenStr);
341
+ this.refreshToken()
342
+ .then((tokenRes) => {
343
+ // window.location.reload();
344
+ reslove();
345
+ })
346
+ .catch((err) => {
347
+ console.log(err, 'errCode');
348
+ this.login();
349
+ });
350
+ } else {
351
+ this.login();
352
+ }
353
+ });
354
+ }
355
+ getauthorization(tokenParams: any) {
356
+ if (tokenParams?.token_type && tokenParams?.access_token) {
357
+ return `${tokenParams.token_type} ${tokenParams.access_token}`;
358
+ } else {
359
+ return '';
360
+ }
361
+ }
362
+
363
+ // 获取当前token的权限菜单
364
+ getAuthApp() {
365
+ showLog && console.log('getAuthApp');
366
+ return new Promise((resolve, reject) => {
367
+ try {
368
+ const tmsConfig = this.state.config;
369
+ const TmsStorage = this.getStorage();
370
+ const tokenStr = TmsStorage.getItem(tmsConfig.tokenKey) || '{}';
371
+ const tokenParams = JSON.parse(tokenStr);
372
+
373
+ fetchData(`${getTmsAdminApiDomain(tmsConfig.env)}/tenant/app`, 'GET', null, {
374
+ authorization: this.getauthorization(tokenParams),
375
+ 'TENANT-ID': tokenParams?.tenant_id || '',
376
+ })
377
+ .then((response) => {
378
+ response
379
+ .clone()
380
+ .json()
381
+ .then((res) => {
382
+ const resData = {
383
+ httpStatus: response.status,
384
+ ...res,
385
+ };
386
+ const { code, data, msg } = res;
387
+ if (response.status === 200 && code == 0) {
388
+ resolve(resData);
389
+ } else {
390
+ reject(resData);
391
+ }
392
+ });
393
+ })
394
+ .catch((error) => {
395
+ reject({ httpStatus: 'failFecth' });
396
+ });
397
+ } catch (error) {
398
+ console.log('getAuthApp fetch data error', error);
399
+ }
400
+ });
401
+ }
402
+
403
+ // 获取当前token的权限菜单
404
+ /**
405
+ *
406
+ * @param params 必传
407
+ * @returns appId 应用id
408
+ */
409
+ getAuthMenu(params = {}) {
410
+ showLog && console.log('getAuthMenu');
411
+ return new Promise((resolve, reject) => {
412
+ try {
413
+ const tmsConfig = this.state.config;
414
+ const TmsStorage = this.getStorage();
415
+ const tokenStr = TmsStorage.getItem(tmsConfig.tokenKey) || '{}';
416
+ const tokenParams = JSON.parse(tokenStr);
417
+
418
+ fetchData(
419
+ `${getTmsAdminApiDomain(tmsConfig.env)}/tenant/menu?${params ? stringify(params) : ''}`,
420
+ 'GET',
421
+ null,
422
+ {
423
+ authorization: `${tokenParams.token_type} ${tokenParams.access_token}`,
424
+ 'TENANT-ID': tokenParams.tenant_id,
425
+ },
426
+ ).then((response) => {
427
+ response
428
+ .clone()
429
+ .json()
430
+ .then((res) => {
431
+ const resData = {
432
+ httpStatus: response.status,
433
+ ...res,
434
+ };
435
+ const { code, data, msg } = res;
436
+ if (response.status === 200 && code == 0) {
437
+ resolve(resData);
438
+ } else {
439
+ reject(resData);
440
+ }
441
+ });
442
+ });
443
+ } catch (error) {
444
+ console.log('getAuthMenu fetch data error', error);
445
+ }
446
+ });
447
+ }
448
+
449
+ updateLanguage(lang: string) {
450
+ return new Promise((resolve, reject) => {
451
+ try {
452
+ this.state.config.lang = lang;
453
+ store.dispatch({ type: UPDATE_LANG, payload: lang });
454
+ resolve(lang);
455
+ } catch (error) {
456
+ reject(error);
457
+ }
458
+ });
459
+ }
460
+
461
+ updateDocumentTitle(title: string) {
462
+ return new Promise((resolve, reject) => {
463
+ try {
464
+ document.title = title;
465
+ resolve(title);
466
+ } catch (error) {
467
+ reject(error);
468
+ }
469
+ });
470
+ }
471
+
472
+ updateDocumentIcon(src: string) {
473
+ return new Promise((resolve, reject) => {
474
+ try {
475
+ var t = document.getElementsByTagName('link');
476
+ for (var i = 0; i < t.length; i++) {
477
+ if (t[i].rel == 'icon' || t[i].rel == 'shortcut icon') {
478
+ t[i].remove();
479
+ }
480
+ }
481
+
482
+ var linkEle = document.createElement('link');
483
+ linkEle.href = src || '/favicon.ico';
484
+ linkEle.type = 'image/x-icon';
485
+ linkEle.rel = 'shortcut icon';
486
+ document.head.appendChild(linkEle);
487
+ resolve(src);
488
+ } catch (error) {
489
+ reject(error);
490
+ }
491
+ });
492
+ }
493
+
494
+ /**
495
+ *
496
+ * @param path 非必传,默认取当前页面 window.location.href
497
+ * @returns
498
+ */
499
+ recordCurrentPath(path: string) {
500
+ return new Promise((resolve, reject) => {
501
+ try {
502
+ const tmsConfig = this.state.config;
503
+ const TmsStorage = this.getStorage();
504
+ var currentPath = path || window.location.href;
505
+ if (window.location.pathname != tmsConfig.loginPath) {
506
+ TmsStorage.setItem(tmsConfig.lastPathKey, currentPath);
507
+ resolve(currentPath);
508
+ } else {
509
+ reject(new Error('当前页面是login,不能记录'));
510
+ }
511
+ } catch (error) {
512
+ reject(error);
513
+ }
514
+ });
515
+ }
516
+
517
+ getStorage() {
518
+ const tmsConfig = this.state.config;
519
+ return tmsConfig.useSessionStorage ? sessionStorage : localStorage;
520
+ }
521
+ /**
522
+ *
523
+ * @param param
524
+ * link 跳转链接
525
+ * data 其他数据
526
+ */
527
+ openWindow({ link, data: realData = {} }) {
528
+ let done = false;
529
+ const MAX_TIME = 40000; // 页面会在打开后20s内接收数据,所以发送预留的时间稍长一点,避免新打开的页面加载过慢
530
+
531
+ const tmsConfig = this.state.config;
532
+ const TmsStorage = this.getStorage();
533
+ const windowObj = window.open(link);
534
+
535
+ const linkStr = link.split('/');
536
+ const targetDomain = linkStr[0] + '//' + linkStr[2];
537
+
538
+ if (tmsConfig.needPostMsg) {
539
+ console.log('开始发送请求消息', new Date().getTime());
540
+ const interval = setInterval(() => {
541
+ windowObj?.postMessage(HELLO_MSG, targetDomain);
542
+ }, 16.66);
543
+ setTimeout(() => {
544
+ if (!done) {
545
+ console.log('超时关闭postMessage', new Date().getTime());
546
+ clearInterval(interval);
547
+ done = true;
548
+ }
549
+ }, MAX_TIME);
550
+
551
+ const listener = (event: MessageEvent<any>) => {
552
+ let { data, source, origin } = event;
553
+ console.log('收到响应消息', origin, data, new Date().getTime());
554
+ if (data == REPLY_MSG && origin != window.location.origin && !done) {
555
+ done = true;
556
+ clearInterval(interval);
557
+
558
+ const tokenInfo = TmsStorage.getItem(tmsConfig.tokenKey);
559
+ const appInfo = TmsStorage.getItem(tmsConfig.curAppKey);
560
+ const _data = {
561
+ ...realData,
562
+ language: tmsConfig.lang,
563
+ userInfo: tokenInfo ? JSON.parse(tokenInfo) : null,
564
+ fromApp: realData && realData.fromApp ? realData.fromApp : JSON.parse(appInfo),
565
+ };
566
+ const _postMsg = JSON.stringify(_data);
567
+
568
+ console.log('发送认证数据', _postMsg, targetDomain, new Date().getTime());
569
+ windowObj?.postMessage(_postMsg, targetDomain);
570
+ window.removeEventListener('message', listener);
571
+ }
572
+ };
573
+ window.addEventListener('message', listener);
574
+ }
575
+ }
576
+
577
+ /**
578
+ * @description 排序 menu 和 app 菜单
579
+ * @param {AppMenuList} list
580
+ * @return {*} {AppMenuList}
581
+ * @memberof Tms
582
+ */
583
+ sortAppMenu(list: AppMenuList): AppMenuList {
584
+ const new_list = (list || []).sort((a, b) => {
585
+ let a_sort = typeof a.sortOrder === 'object' ? Number.MAX_SAFE_INTEGER : a.sortOrder;
586
+ let b_sort = typeof b.sortOrder === 'object' ? Number.MAX_SAFE_INTEGER : b.sortOrder;
587
+ return a_sort == b_sort ? a.id - b.id : a_sort - b_sort;
588
+ });
589
+
590
+ const hasChild = new_list.some((item) => item.children && item.children.length > 0);
591
+ if (hasChild) {
592
+ // children也要sort
593
+ const listWithChildren = new_list.map((item) => {
594
+ const children_list = item.children;
595
+ const newItem = item;
596
+ if (children_list && children_list.length > 0) {
597
+ newItem.children = this.sortAppMenu(item.children);
598
+ }
599
+ return newItem;
600
+ });
601
+ return listWithChildren;
602
+ } else {
603
+ return new_list;
604
+ }
605
+ }
606
+ }
607
+
608
+ export default new Tms();
@@ -0,0 +1,15 @@
1
+ import qs from 'qs';
2
+
3
+ export const toSearchObj = (str?: string) => {
4
+ var obj;
5
+ try {
6
+ obj = qs.parse((str || '').slice(1));
7
+ } catch (e) {
8
+ console.log('catch', e);
9
+ }
10
+ return obj || {};
11
+ };
12
+
13
+
14
+ export const HELLO_MSG = 'You have a message, please reply "ready" to recieve it.';
15
+ export const REPLY_MSG = 'ready';
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "dist",
4
+ "target": "es5",
5
+ "module": "esnext",
6
+ "moduleResolution": "node",
7
+ "jsx": "react",
8
+ "lib": ["dom"],
9
+ "esModuleInterop": true,
10
+ "types": ["jest"],
11
+ "strict": true,
12
+ "skipLibCheck": true,
13
+ "declaration": true,
14
+ "baseUrl": "./",
15
+ "paths": {
16
+ "@/*": ["src/*"]
17
+ }
18
+ }
19
+ }
package/typings.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ declare module '*.css';
2
+ declare module '*.less';