@jiangood/open-admin 2.5.5 → 2.5.7

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 (112) hide show
  1. package/config/common-plugin.js +2 -2
  2. package/package.json +3 -2
  3. package/src/.umi-production/appData.json +91 -90
  4. package/src/.umi-production/core/route.tsx +6 -6
  5. package/src/.umi-production/umi.ts +1 -1
  6. package/src/framework/GlobalData.d.ts +8 -0
  7. package/src/framework/GlobalData.js +33 -0
  8. package/src/framework/{components/system → biz}/HasPerm.tsx +1 -1
  9. package/src/framework/{components/OrgTree/index.tsx → biz/OrgTree.tsx} +12 -2
  10. package/src/framework/{components/system/ButtonList.tsx → biz/PermActions.tsx} +6 -5
  11. package/src/framework/{components/RoleTree/index.tsx → biz/RoleTree.tsx} +13 -3
  12. package/src/framework/{components/system → biz}/index.tsx +4 -2
  13. package/src/framework/components/ContextMenu/index.tsx +12 -4
  14. package/src/framework/components/DownloadModal/index.tsx +332 -0
  15. package/src/framework/components/ErrorBoundary/index.tsx +18 -0
  16. package/src/framework/components/NamedIcon/{index.jsx → index.tsx} +8 -3
  17. package/src/framework/components/Page/index.tsx +2 -2
  18. package/src/framework/components/ProTable/index.tsx +3 -10
  19. package/src/framework/components/index.ts +2 -6
  20. package/src/framework/fields/BaseRemoteSelect/index.tsx +2 -3
  21. package/src/framework/fields/FieldBoolean/index.tsx +3 -4
  22. package/src/framework/fields/FieldDate/index.tsx +0 -21
  23. package/src/framework/fields/FieldEditor/index.tsx +35 -44
  24. package/src/framework/fields/FieldNumberRange/index.tsx +2 -2
  25. package/src/framework/fields/FieldRemoteTree/index.tsx +1 -1
  26. package/src/framework/fields/FieldTable/index.tsx +24 -27
  27. package/src/framework/fields/FieldUploadFile/index.tsx +10 -3
  28. package/src/framework/fields/index.ts +1 -3
  29. package/src/framework/index.ts +2 -0
  30. package/src/framework/utils/ArrayUtils.d.ts +6 -0
  31. package/src/framework/utils/ArrayUtils.js +30 -0
  32. package/src/framework/utils/DateUtils.d.ts +20 -0
  33. package/src/framework/utils/DateUtils.js +81 -0
  34. package/src/framework/utils/DeviceUtils.d.ts +3 -0
  35. package/src/framework/utils/DeviceUtils.js +10 -0
  36. package/src/framework/utils/EventBus.d.ts +6 -0
  37. package/src/framework/utils/EventBus.js +51 -0
  38. package/src/framework/utils/MessageUtils.d.ts +10 -0
  39. package/src/framework/utils/MessageUtils.js +43 -0
  40. package/src/framework/utils/ObjectUtils.d.ts +14 -0
  41. package/src/framework/utils/ObjectUtils.js +12 -0
  42. package/src/framework/utils/StorageUtils.d.ts +4 -0
  43. package/src/framework/utils/{StorageUtils.ts → StorageUtils.js} +7 -11
  44. package/src/framework/utils/StringUtils.d.ts +17 -0
  45. package/src/framework/utils/StringUtils.js +107 -0
  46. package/src/framework/utils/TreeUtils.d.ts +13 -0
  47. package/src/framework/utils/TreeUtils.js +64 -0
  48. package/src/framework/utils/UrlUtils.d.ts +6 -0
  49. package/src/framework/utils/UrlUtils.js +71 -0
  50. package/src/framework/utils/index.ts +1 -5
  51. package/src/framework/utils/system/DictUtils.d.ts +20 -0
  52. package/src/framework/utils/system/DictUtils.js +31 -0
  53. package/src/framework/utils/system/FormRegistry.d.ts +8 -0
  54. package/src/framework/utils/system/FormRegistry.js +31 -0
  55. package/src/framework/utils/system/HttpUtils.d.ts +14 -0
  56. package/src/framework/utils/system/HttpUtils.js +87 -0
  57. package/src/framework/utils/system/PageUtils.d.ts +14 -0
  58. package/src/framework/utils/system/PageUtils.js +59 -0
  59. package/src/framework/utils/system/PermUtils.d.ts +5 -0
  60. package/src/framework/utils/system/PermUtils.js +27 -0
  61. package/src/framework/utils/system/ThemeUtils.d.ts +6 -0
  62. package/src/framework/utils/system/{ThemeUtils.ts → ThemeUtils.js} +19 -19
  63. package/src/framework/utils/system/index.ts +1 -2
  64. package/src/framework/views/ViewFile/index.tsx +3 -3
  65. package/src/framework/views/ViewImage/index.tsx +3 -3
  66. package/src/framework/views/{ViewBooleanEnableDisable → ViewSwitch}/index.tsx +1 -1
  67. package/src/framework/views/index.ts +3 -4
  68. package/src/layouts/admin/HeaderRight.jsx +32 -47
  69. package/src/layouts/admin/index.jsx +5 -29
  70. package/src/layouts/index.jsx +29 -19
  71. package/src/pages/about.jsx +0 -1
  72. package/src/pages/{userCenter/ChangePassword.jsx → account/changePassword.jsx} +1 -2
  73. package/src/pages/{userCenter → account}/index.jsx +2 -6
  74. package/src/pages/forceUpdatePwd.jsx +89 -0
  75. package/src/pages/login.jsx +5 -5
  76. package/src/pages/system/dict/index.jsx +6 -6
  77. package/src/pages/system/file/index.jsx +4 -4
  78. package/src/pages/system/job/index.jsx +2 -2
  79. package/src/pages/system/org/index.jsx +2 -2
  80. package/src/pages/system/role/index.jsx +4 -4
  81. package/src/pages/system/role/{perm.jsx → rolePerm.jsx} +2 -2
  82. package/src/pages/system/user/index.jsx +4 -4
  83. package/src/framework/components/DownloadFileButton/index.tsx +0 -33
  84. package/src/framework/components/NamedIcon/index.d.ts +0 -7
  85. package/src/framework/components/ProTable/utils/index.ts +0 -62
  86. package/src/framework/fields/FieldRemoteSelectMultipleInline/index.tsx +0 -33
  87. package/src/framework/fields/FieldRemoteTreeSelectMultiple/index.tsx +0 -43
  88. package/src/framework/utils/ArrayUtils.ts +0 -186
  89. package/src/framework/utils/ColorsUtils.ts +0 -378
  90. package/src/framework/utils/DateUtils.ts +0 -187
  91. package/src/framework/utils/DeviceUtils.ts +0 -46
  92. package/src/framework/utils/DomUtils.ts +0 -50
  93. package/src/framework/utils/EventBusUtils.ts +0 -143
  94. package/src/framework/utils/Logger.ts +0 -40
  95. package/src/framework/utils/MessageUtils.tsx +0 -90
  96. package/src/framework/utils/ObjectUtils.ts +0 -118
  97. package/src/framework/utils/StringUtils.ts +0 -436
  98. package/src/framework/utils/TreeUtils.ts +0 -251
  99. package/src/framework/utils/UrlUtils.ts +0 -152
  100. package/src/framework/utils/UuidUtils.ts +0 -88
  101. package/src/framework/utils/ValidateUtils.ts +0 -28
  102. package/src/framework/utils/system/DictUtils.ts +0 -96
  103. package/src/framework/utils/system/FormRegistryUtils.ts +0 -76
  104. package/src/framework/utils/system/HttpUtils.ts +0 -251
  105. package/src/framework/utils/system/PageUtils.ts +0 -163
  106. package/src/framework/utils/system/PermUtils.ts +0 -79
  107. package/src/framework/utils/system/SysUtils.ts +0 -105
  108. package/src/framework/views/ViewProcessInstanceProgress/index.tsx +0 -98
  109. package/src/framework/views/ViewProcessInstanceProgressButton/index.tsx +0 -23
  110. package/src/pages/userCenter/message.jsx +0 -105
  111. /package/src/framework/{components → views}/ViewRange/index.tsx +0 -0
  112. /package/src/pages/system/user/{UserPerm.jsx → userPerm.jsx} +0 -0
@@ -0,0 +1,12 @@
1
+ export class ObjectUtils {
2
+
3
+ static copyPropertyIfPresent(source, target) {
4
+ if (!source || !target || typeof source !== 'object' || typeof target !== 'object') return;
5
+ const keys = Object.keys(target);
6
+ for (const key of keys) {
7
+ if (Object.hasOwn(source, key)) {
8
+ target[key] = source[key];
9
+ }
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,4 @@
1
+ export class StorageUtils {
2
+ static get<T>(key: string, defaultValue?: T | null): T | null;
3
+ static set<T>(key: string, value: T | null | undefined): void;
4
+ }
@@ -6,11 +6,11 @@ export class StorageUtils {
6
6
 
7
7
  /**
8
8
  * 从 localStorage 获取数据。
9
- * @param key 存储的键。
10
- * @param defaultValue 如果找不到键或值,返回的默认值 (默认为 null)。
11
- * @returns 存储的值或默认值。
9
+ * @param {string} key 存储的键。
10
+ * @param {*} [defaultValue=null] 如果找不到键或值,返回的默认值。
11
+ * @returns {*} 存储的值或默认值。
12
12
  */
13
- static get<T>(key: string, defaultValue: T | null = null): T | null {
13
+ static get(key, defaultValue = null) {
14
14
  const vStr = localStorage.getItem(key);
15
15
  if (vStr == null) {
16
16
  return defaultValue;
@@ -19,7 +19,6 @@ export class StorageUtils {
19
19
  try {
20
20
  return JSON.parse(vStr);
21
21
  } catch (error) {
22
- // 如果 JSON 解析失败 (例如,存储的值不是一个包含 createTime 和 data 的有效 JSON 结构)
23
22
  console.error(`Error parsing storage item for key: ${key}`, error);
24
23
  return defaultValue;
25
24
  }
@@ -28,22 +27,19 @@ export class StorageUtils {
28
27
  /**
29
28
  * 将数据存储到 localStorage。
30
29
  * 如果值为 null 或 undefined,则删除该键。
31
- * @param key 存储的键。
32
- * @param value 要存储的值。
30
+ * @param {string} key 存储的键。
31
+ * @param {*} value 要存储的值。
33
32
  */
34
- static set<T>(key: string, value: T | null | undefined): void {
35
- // 如果值为 null 或 undefined,则删除该键
33
+ static set(key, value) {
36
34
  if (value == null) {
37
35
  localStorage.removeItem(key);
38
36
  return;
39
37
  }
40
38
 
41
-
42
39
  try {
43
40
  const dataStr = JSON.stringify(value);
44
41
  localStorage.setItem(key, dataStr);
45
42
  } catch (error) {
46
- // 捕获 JSON.stringify 错误 (例如,如果 value 包含循环引用)
47
43
  console.error(`Error stringify storage value for key: ${key}`, error);
48
44
  }
49
45
  }
@@ -0,0 +1,17 @@
1
+ export class StringUtils {
2
+ static readonly ISO_SPLITTER: string;
3
+ static removePrefix(str: string | null | undefined, ch: string): string;
4
+ static removeSuffix(str: string | null | undefined, ch: string): string;
5
+ static random(length: number): string;
6
+ static contains(str: string | null | undefined, subStr: string): boolean;
7
+ static subAfter(source: string | null | undefined, str: string): string;
8
+ static subAfterLast(source: string | null | undefined, str: string): string;
9
+ static subBefore(str: string | null | undefined, sub: string): string;
10
+ static pad(input: string | number | null | undefined, totalLen: number, padChar?: string): string;
11
+ static getWidth(str: string | null | undefined): number;
12
+ static cutByWidth(str: string, maxWidth: number): string;
13
+ static ellipsis(str: string | null | undefined, len: number, suffix?: string): string;
14
+ static isString(value: any): value is string;
15
+ static split(str: any, sp: string): string[];
16
+ static join(arr: any, sp: string): string;
17
+ }
@@ -0,0 +1,107 @@
1
+ export class StringUtils {
2
+
3
+ static ISO_SPLITTER = "/";
4
+
5
+ static removePrefix(str, ch) {
6
+ if (str != null && str.startsWith(ch)) {
7
+ return str.substring(ch.length);
8
+ }
9
+ return str ?? '';
10
+ }
11
+
12
+ static removeSuffix(str, ch) {
13
+ if (str != null && str.endsWith(ch)) {
14
+ return str.substring(0, str.length - ch.length);
15
+ }
16
+ return str ?? '';
17
+ }
18
+
19
+ static random(length) {
20
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
21
+ let result = '';
22
+ for (let i = 0; i < length; i++) {
23
+ result += characters.charAt(Math.floor(Math.random() * characters.length));
24
+ }
25
+ return result;
26
+ }
27
+
28
+ static contains(str, subStr) {
29
+ if (!str) return false;
30
+ return str.includes(subStr);
31
+ }
32
+
33
+ static subAfter(source, str) {
34
+ if (source == null) return '';
35
+ const index = source.indexOf(str);
36
+ return index === -1 ? source : source.substring(index + str.length);
37
+ }
38
+
39
+ static subAfterLast(source, str) {
40
+ if (source == null) return '';
41
+ const index = source.lastIndexOf(str);
42
+ return index === -1 ? source : source.substring(index + str.length);
43
+ }
44
+
45
+ static subBefore(str, sub) {
46
+ if (str == null) return "";
47
+ const index = str.indexOf(sub);
48
+ return index === -1 ? str : str.substring(0, index);
49
+ }
50
+
51
+ static pad(input, totalLen, padChar = '0') {
52
+ if (input == null) return padChar.repeat(totalLen);
53
+ let str = String(input);
54
+ const charsNeeded = totalLen - str.length;
55
+ if (charsNeeded > 0) {
56
+ str = padChar.repeat(charsNeeded) + str;
57
+ }
58
+ return str;
59
+ }
60
+
61
+ static getWidth(str) {
62
+ if (str == null || str.length === 0) return 0;
63
+ return str.split('').reduce((pre, cur) => {
64
+ const charCode = cur.charCodeAt(0);
65
+ return pre + (charCode >= 0 && charCode <= 128 ? 1 : 2);
66
+ }, 0);
67
+ }
68
+
69
+ static cutByWidth(str, maxWidth) {
70
+ let showLength = 0;
71
+ return str.split('').reduce((pre, cur) => {
72
+ const charCode = cur.charCodeAt(0);
73
+ const charWidth = (charCode >= 0 && charCode <= 128) ? 1 : 2;
74
+ if (showLength + charWidth <= maxWidth) {
75
+ showLength += charWidth;
76
+ return pre + cur;
77
+ }
78
+ return pre;
79
+ }, '');
80
+ }
81
+
82
+ static ellipsis(str, len, suffix = '...') {
83
+ if (str == null) return '';
84
+ if (!StringUtils.isString(str)) return '';
85
+ if (str.length * 2 < len) return str;
86
+ const fullLength = StringUtils.getWidth(str);
87
+ if (fullLength <= len) return str;
88
+ return StringUtils.cutByWidth(str, len) + suffix;
89
+ }
90
+
91
+ static isString(value) {
92
+ return typeof value === 'string';
93
+ }
94
+
95
+ static split(str, sp) {
96
+ if (str == null || str.length === 0) return [];
97
+ if (Array.isArray(str)) return str;
98
+ return str.split(sp);
99
+ }
100
+
101
+ static join(arr, sp) {
102
+ if (arr == null || !Array.isArray(arr)) {
103
+ return '';
104
+ }
105
+ return arr.join(sp);
106
+ }
107
+ }
@@ -0,0 +1,13 @@
1
+ export interface TreeNode<T = any> {
2
+ id: string | number;
3
+ pid: string | number | null;
4
+ children?: TreeNode<T>[];
5
+ [key: string]: any;
6
+ }
7
+
8
+ export class TreeUtils {
9
+ static walk<T extends TreeNode>(tree: T[], callback: (node: T) => void): void;
10
+ static findByKey<T extends TreeNode>(key: string | number, list: T[], keyName?: keyof T | 'id'): T | undefined;
11
+ static flattenTree<T extends TreeNode>(treeNodeList: T[]): T[];
12
+ static getKeyList<T extends TreeNode>(tree: T[], value: string | number): (string | number)[];
13
+ }
@@ -0,0 +1,64 @@
1
+ export class TreeUtils {
2
+ static walk(tree, callback) {
3
+ if (tree == null) return;
4
+ for (const node of tree) {
5
+ callback(node);
6
+ if (node.children && node.children.length > 0) {
7
+ TreeUtils.walk(node.children, callback);
8
+ }
9
+ }
10
+ }
11
+
12
+ static findByKey(key, list, keyName = 'id') {
13
+ for (const item of list) {
14
+ if (item[keyName] === key) return item;
15
+ if (item.children && item.children.length) {
16
+ const rs = TreeUtils.findByKey(key, item.children, keyName);
17
+ if (rs) return rs;
18
+ }
19
+ }
20
+ return undefined;
21
+ }
22
+
23
+ /** @private */
24
+ static getChildRecursive(treeNode, buffer) {
25
+ if (treeNode.children != null && treeNode.children.length > 0) {
26
+ treeNode.children.forEach((c) => {
27
+ buffer.push(c);
28
+ TreeUtils.getChildRecursive(c, buffer);
29
+ });
30
+ }
31
+ return buffer;
32
+ }
33
+
34
+ static flattenTree(treeNodeList) {
35
+ const buffer = [];
36
+ if (treeNodeList != null) {
37
+ treeNodeList.forEach((t) => {
38
+ buffer.push(t);
39
+ TreeUtils.getChildRecursive(t, buffer);
40
+ });
41
+ }
42
+ return buffer;
43
+ }
44
+
45
+ static getKeyList(tree, value) {
46
+ const list = TreeUtils.flattenTree(tree);
47
+ const map = new Map();
48
+ list.forEach((t) => {
49
+ const key = t.key || t.id;
50
+ map.set(key, t);
51
+ });
52
+ const targetNode = map.get(value);
53
+ if (targetNode == null) return [];
54
+ const keys = [targetNode.key || targetNode.id];
55
+ let parentKey = targetNode.parentKey || targetNode.pid;
56
+ while (parentKey != null) {
57
+ const parent = map.get(parentKey);
58
+ if (parent == null) break;
59
+ keys.push(parent.key || parent.id);
60
+ parentKey = parent.parentKey || parent.pid;
61
+ }
62
+ return keys.reverse();
63
+ }
64
+ }
@@ -0,0 +1,6 @@
1
+ export class UrlUtils {
2
+ static getParams(url?: string | null): Record<string, string>;
3
+ static setParam(url: string, key: string, value: string | number | boolean | null | undefined): string;
4
+ static getWebsocketBaseUrl(): string;
5
+ static contextPath(path: string): string;
6
+ }
@@ -0,0 +1,71 @@
1
+ import {StringUtils} from './StringUtils';
2
+
3
+ export class UrlUtils {
4
+ static getParams(url = null) {
5
+ let targetUrl;
6
+ if (url === null || url === undefined) {
7
+ targetUrl = location.href;
8
+ } else {
9
+ targetUrl = url;
10
+ }
11
+
12
+ if (!StringUtils.contains(targetUrl, '?')) return {};
13
+ const search = StringUtils.subAfter(targetUrl, '?');
14
+ const params = new URLSearchParams(search);
15
+ const result = {};
16
+ for (const [key, value] of params.entries()) {
17
+ result[key] = value;
18
+ }
19
+ return result;
20
+ }
21
+
22
+ static getPathname(url) {
23
+ if (!url) return null;
24
+ return StringUtils.subBefore(url, '?');
25
+ }
26
+
27
+ static paramsToSearch(params) {
28
+ if (!params) return "";
29
+ const buffer = [];
30
+ for (const k in params) {
31
+ if (Object.prototype.hasOwnProperty.call(params, k)) {
32
+ const v = params[k];
33
+ if (v !== null && v !== undefined) {
34
+ buffer.push(`${k}=${v}`);
35
+ }
36
+ }
37
+ }
38
+ return buffer.join('&');
39
+ }
40
+
41
+ static setParam(url, key, value) {
42
+ const currentParams = this.getParams(url);
43
+ if (value === null || value === undefined) {
44
+ delete currentParams[key];
45
+ } else {
46
+ currentParams[key] = String(value);
47
+ }
48
+ const pathname = this.getPathname(url);
49
+ const newSearch = this.paramsToSearch(currentParams);
50
+ if (newSearch.length > 0) {
51
+ return `${pathname}?${newSearch}`;
52
+ }
53
+ return pathname || url;
54
+ }
55
+
56
+ /**
57
+ * 根据当前页面协议和主机名构建 WebSocket 基础 URL
58
+ */
59
+ static getWebsocketBaseUrl() {
60
+ const protocol = location.protocol === 'http:' ? 'ws:' : 'wss:';
61
+ return `${protocol}//${location.host}`;
62
+ }
63
+
64
+ /**
65
+ * 为路径添加 SERVLET_CONTEXT 前缀
66
+ */
67
+ static contextPath(path) {
68
+ const base = (typeof SERVLET_CONTEXT !== 'undefined' && SERVLET_CONTEXT) || '';
69
+ return base + path;
70
+ }
71
+ }
@@ -2,14 +2,10 @@ export * from "./DateUtils";
2
2
  export * from "./ArrayUtils";
3
3
  export * from "./UrlUtils"
4
4
  export * from "./StringUtils"
5
- export * from "./EventBusUtils";
6
- export * from "./ColorsUtils"
7
- export * from "./DomUtils"
8
- export * from "./UuidUtils";
5
+ export * from "./EventBus";
9
6
  export * from "./TreeUtils";
10
7
  export * from './StorageUtils'
11
8
  export * from './DeviceUtils'
12
9
  export * from './ObjectUtils'
13
- export * from './ValidateUtils'
14
10
  export * from './system'
15
11
  export * from './MessageUtils'
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import {Tag} from 'antd';
3
+
4
+ export interface DictItem {
5
+ code: string | number;
6
+ label: string;
7
+ color?: string;
8
+ }
9
+
10
+ export interface DictOption {
11
+ value: string | number;
12
+ label: string;
13
+ }
14
+
15
+ export class DictUtils {
16
+ static dictList(code: string): DictItem[];
17
+ static dictOptions(typeCode: string): DictOption[];
18
+ static dictLabel(typeCode: string, code: string | number): string | undefined;
19
+ static dictTag(typeCode: string, code: string | number): React.ReactElement | string | null;
20
+ }
@@ -0,0 +1,31 @@
1
+ import {GlobalData} from '../../GlobalData';
2
+ import {Tag} from 'antd';
3
+ import React from 'react';
4
+
5
+ export class DictUtils {
6
+ static dictList(code) {
7
+ const info = GlobalData.getDictInfo();
8
+ if (!info) return [];
9
+ return info.filter(e => e.typeCode === code);
10
+ }
11
+
12
+ static dictOptions(typeCode) {
13
+ const list = DictUtils.dictList(typeCode);
14
+ return list.map(i => ({ value: i.code, label: i.label }));
15
+ }
16
+
17
+ static dictLabel(typeCode, code) {
18
+ const items = DictUtils.dictList(typeCode);
19
+ const item = items.find(i => i.code === code);
20
+ return item ? item.label : undefined;
21
+ }
22
+
23
+ static dictTag(typeCode, code) {
24
+ if (typeCode == null || code == null) return null;
25
+ const item = DictUtils.dictList(typeCode).find(i => i.code === code);
26
+ if (item == null) return null;
27
+ const {label, color} = item;
28
+ if (color == null) return label;
29
+ return React.createElement(Tag, {color: color.toLowerCase()}, label);
30
+ }
31
+ }
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+
3
+ export class FormRegistry {
4
+ static register(formKey: string, formComponent: React.ComponentType<any>): void;
5
+ static get(formKey: string): React.ComponentType<any> | null;
6
+ static has(formKey: string): boolean;
7
+ static getAllKeys(): string[];
8
+ }
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+
3
+ export class FormRegistry {
4
+ static forms = new Map();
5
+
6
+ static register(formKey, formComponent) {
7
+ if (!formKey || !formComponent) {
8
+ throw new Error("表单 Key 和组件不能为空!");
9
+ }
10
+ if (FormRegistry.forms.has(formKey)) {
11
+ console.warn(`表单 "${formKey}" 已存在,将被覆盖!`);
12
+ }
13
+ FormRegistry.forms.set(formKey, formComponent);
14
+ }
15
+
16
+ static get(formKey) {
17
+ const formComponent = FormRegistry.forms.get(formKey);
18
+ if (!formComponent) {
19
+ console.warn(`表单 "${formKey}" 未注册!`);
20
+ }
21
+ return formComponent ?? null;
22
+ }
23
+
24
+ static has(formKey) {
25
+ return FormRegistry.forms.has(formKey);
26
+ }
27
+
28
+ static getAllKeys() {
29
+ return Array.from(FormRegistry.forms.keys());
30
+ }
31
+ }
@@ -0,0 +1,14 @@
1
+ import {AxiosRequestConfig} from "axios";
2
+
3
+ declare const SERVLET_CONTEXT: string | undefined;
4
+
5
+ interface RequestOptions extends AxiosRequestConfig {
6
+ showError?: boolean;
7
+ }
8
+
9
+ export class HttpUtils {
10
+ static coreRequest<T = any>(config: RequestOptions, transformData?: boolean): Promise<T>;
11
+ static get<T = any>(url: string, params?: any, options?: Partial<RequestOptions>): Promise<T>;
12
+ static post<T = any>(url: string, data?: any, params?: any, options?: Partial<RequestOptions>): Promise<T>;
13
+ static postForm<T = any>(url: string, data: any, options?: Partial<RequestOptions>): Promise<T>;
14
+ }
@@ -0,0 +1,87 @@
1
+ import axios from "axios";
2
+ import qs from 'qs';
3
+ import {PageUtils} from "./PageUtils";
4
+ import {MessageUtils} from "../MessageUtils";
5
+
6
+ const axiosInstance = axios.create({
7
+ baseURL: (typeof SERVLET_CONTEXT !== 'undefined' && SERVLET_CONTEXT) || '',
8
+ withCredentials: true,
9
+ headers: { 'Content-Type': 'application/json' },
10
+ paramsSerializer: (params) => qs.stringify(params, {indices: false})
11
+ });
12
+
13
+ export class HttpUtils {
14
+ static coreRequest(config, transformData = true) {
15
+ const url = config.url;
16
+ config.url = url.startsWith('admin') ? '/' + url : url;
17
+
18
+ return new Promise((resolve, reject) => {
19
+ axiosInstance(config).then((response) => {
20
+ const body = response.data;
21
+ let {success, message, data} = body;
22
+ if (success == undefined) {
23
+ resolve(response);
24
+ return;
25
+ }
26
+ if (!success) {
27
+ console.error(`[HttpUtils] 请求失败: ${url}`, {code: body.code, message, data: body});
28
+ if (config.showError !== false) {
29
+ MessageUtils.error(message || '操作失败');
30
+ }
31
+ reject(message || '操作失败');
32
+ return;
33
+ }
34
+ if (message) {
35
+ MessageUtils.success(message);
36
+ }
37
+ resolve(transformData ? data : response);
38
+ }).catch((e) => {
39
+ console.error(`[HttpUtils] 请求异常: ${url}`, e);
40
+ if (axios.isAxiosError(e) && e.response?.status === 401) {
41
+ MessageUtils.confirm('登录已过期,请重新登录').then(() => {
42
+ PageUtils.redirectToLogin();
43
+ });
44
+ reject('登录过期');
45
+ return;
46
+ }
47
+ const msg = HttpUtils.extractErrorMessage(e);
48
+ if (config.showError !== false) {
49
+ MessageUtils.error(msg);
50
+ }
51
+ reject(msg);
52
+ });
53
+ });
54
+ }
55
+
56
+ static extractErrorMessage(e, defaultMsg = '操作失败') {
57
+ if (axios.isAxiosError(e)) {
58
+ const responseData = e.response?.data;
59
+ const status = e.response?.status;
60
+ if (status === 504) return '504 请求后端服务失败';
61
+ if (responseData && responseData.message) return responseData.message;
62
+ if (e.message) return e.message;
63
+ return defaultMsg;
64
+ }
65
+ if (e instanceof Error) return e.message || defaultMsg;
66
+ return defaultMsg;
67
+ }
68
+
69
+ static get(url, params = null, options = {}) {
70
+ return HttpUtils.coreRequest({...options, url, method: 'GET', params});
71
+ }
72
+
73
+ static post(url, data = null, params = null, options = {}) {
74
+ return HttpUtils.coreRequest({...options, url, method: 'POST', data, params});
75
+ }
76
+
77
+ static postForm(url, data, options = {}) {
78
+ return HttpUtils.coreRequest({
79
+ ...options,
80
+ url,
81
+ method: 'POST',
82
+ data: qs.stringify(data),
83
+ headers: {'Content-Type': 'application/x-www-form-urlencoded'}
84
+ });
85
+ }
86
+
87
+ }
@@ -0,0 +1,14 @@
1
+ import {history} from "umi";
2
+
3
+ export class PageUtils {
4
+ static redirectToLogin(): void;
5
+ static currentParams(): Record<string, string | undefined>;
6
+ static currentPathname(): string;
7
+ static currentUrl(): string;
8
+ static currentPathnameLastPart(): string | undefined;
9
+ static open(path: string, label?: string): void;
10
+ static openNoLayout(path: string): void;
11
+ static currentLabel(): string | undefined;
12
+ static closeCurrent(): void;
13
+ static closeCurrentAndOpenPage(alertMessage: string, path: string, label: string): void;
14
+ }
@@ -0,0 +1,59 @@
1
+ import {history} from "umi";
2
+ import {StringUtils} from "../StringUtils";
3
+ import {UrlUtils} from "../UrlUtils";
4
+ import {MessageUtils} from "../MessageUtils";
5
+
6
+ export class PageUtils {
7
+ static redirectToLogin() {
8
+ const url = PageUtils.currentUrl();
9
+ const encodedUrl = encodeURIComponent(url);
10
+ history.push(`/login?redirect=${encodedUrl}`);
11
+ }
12
+
13
+ static currentParams() {
14
+ return UrlUtils.getParams();
15
+ }
16
+
17
+ static currentPathname() {
18
+ const path = window.location.hash.substring(1);
19
+ return StringUtils.subBefore(path, '?');
20
+ }
21
+
22
+ static currentUrl() {
23
+ return window.location.hash.substring(1);
24
+ }
25
+
26
+ static currentPathnameLastPart() {
27
+ const path = this.currentPathname();
28
+ return StringUtils.subAfterLast(path, '/') || undefined;
29
+ }
30
+
31
+ static open(path, label = '未命名') {
32
+ let targetPath = path;
33
+ if (label) {
34
+ targetPath = UrlUtils.setParam(targetPath, '_label', label);
35
+ }
36
+ history.push(targetPath);
37
+ }
38
+
39
+ static openNoLayout(path) {
40
+ const targetPath = UrlUtils.setParam(path, '_noLayout', true);
41
+ history.push(targetPath);
42
+ }
43
+
44
+ static currentLabel() {
45
+ return this.currentParams()['_label'];
46
+ }
47
+
48
+ static closeCurrent() {
49
+ const event = new CustomEvent('close-page-event', {detail: {url: PageUtils.currentUrl()}});
50
+ document.dispatchEvent(event);
51
+ }
52
+
53
+ static closeCurrentAndOpenPage(alertMessage, path, label) {
54
+ MessageUtils.alert(alertMessage).then(() => {
55
+ this.closeCurrent();
56
+ this.open(path, label);
57
+ });
58
+ }
59
+ }
@@ -0,0 +1,5 @@
1
+ export class PermUtils {
2
+ static hasPermission(perm: string | null | undefined): boolean;
3
+ static isPermitted(p: string | null | undefined): boolean;
4
+ static notPermitted(p: string | null | undefined): boolean;
5
+ }
@@ -0,0 +1,27 @@
1
+ import {GlobalData} from '../../GlobalData';
2
+ import {ArrayUtils} from '../ArrayUtils';
3
+
4
+ export class PermUtils {
5
+ static getPermissions() {
6
+ const info = GlobalData.getLoginInfo();
7
+ const { permissions } = info;
8
+ if (permissions == null || permissions.length === 0) return [];
9
+ return permissions;
10
+ }
11
+
12
+ static hasPermission(perm) {
13
+ if (perm === null || perm === undefined || perm === '') return false;
14
+ const permissions = PermUtils.getPermissions();
15
+ if (permissions.length === 0) return false;
16
+ if (ArrayUtils.contains(permissions, "*")) return true;
17
+ return permissions.indexOf(perm) > -1;
18
+ }
19
+
20
+ static isPermitted(p) {
21
+ return PermUtils.hasPermission(p);
22
+ }
23
+
24
+ static notPermitted(p) {
25
+ return !PermUtils.isPermitted(p);
26
+ }
27
+ }