@jiangood/open-admin 1.0.0-beta.5

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 (186) hide show
  1. package/config/common-plugin.js +94 -0
  2. package/config/config.js +58 -0
  3. package/config/utils.js +73 -0
  4. package/package.json +42 -0
  5. package/src/.umi-production/appData.json +2365 -0
  6. package/src/.umi-production/core/EmptyRoute.tsx +9 -0
  7. package/src/.umi-production/core/defineApp.ts +16 -0
  8. package/src/.umi-production/core/helmet.ts +10 -0
  9. package/src/.umi-production/core/helmetContext.ts +4 -0
  10. package/src/.umi-production/core/history.ts +72 -0
  11. package/src/.umi-production/core/historyIntelli.ts +132 -0
  12. package/src/.umi-production/core/plugin.ts +40 -0
  13. package/src/.umi-production/core/pluginConfig.ts +324 -0
  14. package/src/.umi-production/core/pluginConfigJoi.d.ts +7 -0
  15. package/src/.umi-production/core/polyfill.ts +220 -0
  16. package/src/.umi-production/core/route.tsx +54 -0
  17. package/src/.umi-production/core/routeProps.js +5 -0
  18. package/src/.umi-production/core/routeProps.ts +6 -0
  19. package/src/.umi-production/core/terminal.ts +37 -0
  20. package/src/.umi-production/exports.ts +17 -0
  21. package/src/.umi-production/testBrowser.tsx +90 -0
  22. package/src/.umi-production/tsconfig.json +44 -0
  23. package/src/.umi-production/typings.d.ts +136 -0
  24. package/src/.umi-production/umi.ts +83 -0
  25. package/src/framework/components/DownloadFileButton/index.d.ts +11 -0
  26. package/src/framework/components/DownloadFileButton/index.jsx +33 -0
  27. package/src/framework/components/Gap/index.d.ts +23 -0
  28. package/src/framework/components/Gap/index.jsx +46 -0
  29. package/src/framework/components/LinkButton/index.d.ts +14 -0
  30. package/src/framework/components/LinkButton/index.jsx +10 -0
  31. package/src/framework/components/NamedIcon/index.d.ts +5 -0
  32. package/src/framework/components/NamedIcon/index.jsx +11 -0
  33. package/src/framework/components/OrgTree/index.d.ts +4 -0
  34. package/src/framework/components/OrgTree/index.jsx +58 -0
  35. package/src/framework/components/Page/index.d.ts +17 -0
  36. package/src/framework/components/Page/index.jsx +30 -0
  37. package/src/framework/components/Page/index.less +10 -0
  38. package/src/framework/components/PageLoading/index.d.ts +1 -0
  39. package/src/framework/components/PageLoading/index.jsx +25 -0
  40. package/src/framework/components/ProModal/index.tsx +66 -0
  41. package/src/framework/components/ProTable/components/ToolBar/index.jsx +123 -0
  42. package/src/framework/components/ProTable/components/ToolBar/index.less +53 -0
  43. package/src/framework/components/ProTable/index.d.ts +42 -0
  44. package/src/framework/components/ProTable/index.jsx +260 -0
  45. package/src/framework/components/ProTable/index.less +14 -0
  46. package/src/framework/components/ProTable/utils/index.js +43 -0
  47. package/src/framework/components/RoleTree/index.d.ts +4 -0
  48. package/src/framework/components/RoleTree/index.jsx +50 -0
  49. package/src/framework/components/ValueType/index.jsx +34 -0
  50. package/src/framework/components/ValueType/registry.jsx +26 -0
  51. package/src/framework/components/ViewRange/index.d.ts +14 -0
  52. package/src/framework/components/ViewRange/index.jsx +20 -0
  53. package/src/framework/components/index.ts +13 -0
  54. package/src/framework/components/system/ButtonList.d.ts +8 -0
  55. package/src/framework/components/system/ButtonList.jsx +42 -0
  56. package/src/framework/components/system/HasPerm.tsx +14 -0
  57. package/src/framework/components/system/index.tsx +29 -0
  58. package/src/framework/fields/FieldBoolean/index.d.ts +9 -0
  59. package/src/framework/fields/FieldBoolean/index.jsx +73 -0
  60. package/src/framework/fields/FieldDate/index.d.ts +23 -0
  61. package/src/framework/fields/FieldDate/index.jsx +116 -0
  62. package/src/framework/fields/FieldDateRange/index.d.ts +22 -0
  63. package/src/framework/fields/FieldDateRange/index.jsx +103 -0
  64. package/src/framework/fields/FieldDictSelect/index.d.ts +12 -0
  65. package/src/framework/fields/FieldDictSelect/index.jsx +16 -0
  66. package/src/framework/fields/FieldEditor/index.d.ts +14 -0
  67. package/src/framework/fields/FieldEditor/index.jsx +59 -0
  68. package/src/framework/fields/FieldNumberRange/index.d.ts +10 -0
  69. package/src/framework/fields/FieldNumberRange/index.jsx +55 -0
  70. package/src/framework/fields/FieldPercent/index.d.ts +8 -0
  71. package/src/framework/fields/FieldPercent/index.jsx +30 -0
  72. package/src/framework/fields/FieldRemoteSelect/index.d.ts +44 -0
  73. package/src/framework/fields/FieldRemoteSelect/index.jsx +125 -0
  74. package/src/framework/fields/FieldRemoteSelectMultiple/index.d.ts +20 -0
  75. package/src/framework/fields/FieldRemoteSelectMultiple/index.jsx +85 -0
  76. package/src/framework/fields/FieldRemoteSelectMultipleInline/index.d.ts +21 -0
  77. package/src/framework/fields/FieldRemoteSelectMultipleInline/index.jsx +88 -0
  78. package/src/framework/fields/FieldRemoteTree/index.d.ts +20 -0
  79. package/src/framework/fields/FieldRemoteTree/index.jsx +50 -0
  80. package/src/framework/fields/FieldRemoteTreeCascader/index.d.ts +18 -0
  81. package/src/framework/fields/FieldRemoteTreeCascader/index.jsx +59 -0
  82. package/src/framework/fields/FieldRemoteTreeSelect/index.d.ts +19 -0
  83. package/src/framework/fields/FieldRemoteTreeSelect/index.jsx +57 -0
  84. package/src/framework/fields/FieldRemoteTreeSelectMultiple/index.d.ts +20 -0
  85. package/src/framework/fields/FieldRemoteTreeSelectMultiple/index.jsx +62 -0
  86. package/src/framework/fields/FieldSysOrgTree/index.d.ts +9 -0
  87. package/src/framework/fields/FieldSysOrgTree/index.jsx +20 -0
  88. package/src/framework/fields/FieldSysOrgTreeSelect/index.d.ts +9 -0
  89. package/src/framework/fields/FieldSysOrgTreeSelect/index.jsx +22 -0
  90. package/src/framework/fields/FieldTable/index.d.ts +14 -0
  91. package/src/framework/fields/FieldTable/index.jsx +108 -0
  92. package/src/framework/fields/FieldTable/styles.less +29 -0
  93. package/src/framework/fields/FieldTableSelect/index.d.ts +19 -0
  94. package/src/framework/fields/FieldTableSelect/index.jsx +60 -0
  95. package/src/framework/fields/FieldUploadFile/index.d.ts +31 -0
  96. package/src/framework/fields/FieldUploadFile/index.jsx +139 -0
  97. package/src/framework/fields/index.ts +22 -0
  98. package/src/framework/fields/types.ts +16 -0
  99. package/src/framework/index.ts +5 -0
  100. package/src/framework/pages/LoginPage.d.ts +16 -0
  101. package/src/framework/pages/LoginPage.jsx +135 -0
  102. package/src/framework/pages/LoginPage.less +53 -0
  103. package/src/framework/pages/LoginPageUtils.ts +36 -0
  104. package/src/framework/pages/index.ts +2 -0
  105. package/src/framework/utils/ArrUtils.ts +229 -0
  106. package/src/framework/utils/ColorsUtils.ts +378 -0
  107. package/src/framework/utils/DateUtils.ts +187 -0
  108. package/src/framework/utils/DeviceUtils.ts +46 -0
  109. package/src/framework/utils/DomUtils.ts +50 -0
  110. package/src/framework/utils/EventBusUtils.ts +144 -0
  111. package/src/framework/utils/Logger.ts +40 -0
  112. package/src/framework/utils/MessageUtils.tsx +170 -0
  113. package/src/framework/utils/ObjectUtils.ts +118 -0
  114. package/src/framework/utils/StorageUtils.ts +50 -0
  115. package/src/framework/utils/StringUtils.ts +436 -0
  116. package/src/framework/utils/TreeUtils.ts +251 -0
  117. package/src/framework/utils/UrlUtils.ts +152 -0
  118. package/src/framework/utils/UuidUtils.ts +88 -0
  119. package/src/framework/utils/ValidateUtils.ts +28 -0
  120. package/src/framework/utils/index.ts +15 -0
  121. package/src/framework/utils/system/DictUtils.ts +97 -0
  122. package/src/framework/utils/system/FormRegistryUtils.ts +77 -0
  123. package/src/framework/utils/system/HttpUtils.ts +247 -0
  124. package/src/framework/utils/system/PageUtils.ts +163 -0
  125. package/src/framework/utils/system/PermUtils.ts +79 -0
  126. package/src/framework/utils/system/SysUtils.ts +97 -0
  127. package/src/framework/utils/system/ThemeUtils.ts +27 -0
  128. package/src/framework/utils/system/index.ts +7 -0
  129. package/src/framework/views/ViewApproveStatus/index.d.ts +3 -0
  130. package/src/framework/views/ViewApproveStatus/index.jsx +21 -0
  131. package/src/framework/views/ViewBoolean/index.d.ts +3 -0
  132. package/src/framework/views/ViewBoolean/index.jsx +4 -0
  133. package/src/framework/views/ViewBooleanEnableDisable/index.d.ts +5 -0
  134. package/src/framework/views/ViewBooleanEnableDisable/index.jsx +15 -0
  135. package/src/framework/views/ViewFile/index.d.ts +10 -0
  136. package/src/framework/views/ViewFile/index.jsx +49 -0
  137. package/src/framework/views/ViewFileButton/index.d.ts +10 -0
  138. package/src/framework/views/ViewFileButton/index.jsx +22 -0
  139. package/src/framework/views/ViewImage/index.d.ts +6 -0
  140. package/src/framework/views/ViewImage/index.jsx +60 -0
  141. package/src/framework/views/ViewPassword/index.d.ts +5 -0
  142. package/src/framework/views/ViewPassword/index.jsx +24 -0
  143. package/src/framework/views/ViewProcessInstanceProgress/index.d.ts +12 -0
  144. package/src/framework/views/ViewProcessInstanceProgress/index.jsx +97 -0
  145. package/src/framework/views/ViewProcessInstanceProgressButton/index.d.ts +6 -0
  146. package/src/framework/views/ViewProcessInstanceProgressButton/index.jsx +24 -0
  147. package/src/framework/views/ViewText/index.d.ts +16 -0
  148. package/src/framework/views/ViewText/index.jsx +42 -0
  149. package/src/framework/views/index.ts +12 -0
  150. package/src/framework/views/types.ts +26 -0
  151. package/src/index.ts +2 -0
  152. package/src/layouts/PageRender.d.ts +22 -0
  153. package/src/layouts/PageRender.jsx +90 -0
  154. package/src/layouts/admin/HeaderRight.jsx +104 -0
  155. package/src/layouts/admin/TabPageRender.jsx +158 -0
  156. package/src/layouts/admin/index.jsx +159 -0
  157. package/src/layouts/admin/index.less +65 -0
  158. package/src/layouts/index.jsx +187 -0
  159. package/src/layouts/index.less +24 -0
  160. package/src/loading.jsx +18 -0
  161. package/src/pages/404.jsx +13 -0
  162. package/src/pages/about.jsx +12 -0
  163. package/src/pages/index.jsx +10 -0
  164. package/src/pages/login.jsx +16 -0
  165. package/src/pages/system/api/ApiDoc.jsx +148 -0
  166. package/src/pages/system/api/index.jsx +267 -0
  167. package/src/pages/system/api/perm.jsx +69 -0
  168. package/src/pages/system/dict/Dict.jsx +67 -0
  169. package/src/pages/system/dict/DictItem.jsx +175 -0
  170. package/src/pages/system/dict/index.jsx +25 -0
  171. package/src/pages/system/file/index.jsx +147 -0
  172. package/src/pages/system/job/index.jsx +324 -0
  173. package/src/pages/system/log/index.jsx +77 -0
  174. package/src/pages/system/org/index.jsx +260 -0
  175. package/src/pages/system/role/index.jsx +302 -0
  176. package/src/pages/system/role/perm.jsx +107 -0
  177. package/src/pages/system/sysManual/index.jsx +126 -0
  178. package/src/pages/system/user/UserPerm.jsx +94 -0
  179. package/src/pages/system/user/index.jsx +253 -0
  180. package/src/pages/test/views.jsx +95 -0
  181. package/src/pages/ureport/index.jsx +16 -0
  182. package/src/pages/userCenter/ChangePassword.jsx +64 -0
  183. package/src/pages/userCenter/index.jsx +90 -0
  184. package/src/pages/userCenter/manual.jsx +57 -0
  185. package/src/pages/userCenter/message.jsx +103 -0
  186. package/src/style/global.less +51 -0
@@ -0,0 +1,118 @@
1
+ /**
2
+ * ObjectUtils 提供了对对象进行操作的静态方法,例如安全地获取嵌套属性和复制属性。
3
+ */
4
+ export class ObjectUtils {
5
+
6
+ static clone(obj:any){
7
+ return JSON.parse(JSON.stringify(obj));
8
+ }
9
+
10
+
11
+ /**
12
+ * 🎯 安全地获取深度嵌套的对象属性的值。
13
+ * 如果属性链中的任何一级为 undefined 或 null,getDefinition 函数会返回一个默认值,而不是抛出错误。
14
+ *
15
+ * @template TObj 目标对象的类型。
16
+ * @template TDefault 默认值的类型。
17
+ * @param obj 要查找属性的对象。
18
+ * @param path 属性路径,可以是点分隔的字符串(如 'a.b.c')或字符串数组(如 ['a', '0', 'b', 'c'])。
19
+ * @param defaultValue 如果属性不存在或路径中有 null/undefined 值时返回的默认值。
20
+ * @returns 属性的值,如果找不到则返回 defaultValue。
21
+ *
22
+ * @example
23
+ * const obj = { 'a': [{ 'b': { 'c': 3 } }] };
24
+ * const value = ObjectUtils.getDefinition(obj, 'a[0].b.c', 0); // 3
25
+ * const missing = ObjectUtils.getDefinition(obj, 'a[1].d', 'default'); // 'default'
26
+ */
27
+ static get<TObj extends object, TDefault = unknown>(
28
+ obj: TObj | null | undefined,
29
+ path: string | (keyof TObj)[],
30
+ defaultValue: TDefault | undefined = undefined
31
+ ): unknown | TDefault {
32
+
33
+ // 路径处理:将 'a[0].b.c' 转换为 ['a', '0', 'b', 'c'] 以支持数组索引
34
+ // 注意:这里简化处理,只处理点分隔符,如果需要完整的 lodash getDefinition 行为,需要更复杂的正则解析。
35
+ const pathArray: string[] = Array.isArray(path)
36
+ ? path.map(String) // 确保路径段都是字符串
37
+ : path.split('.');
38
+
39
+ let result: any = obj;
40
+
41
+ // 遍历路径
42
+ for (const segment of pathArray) {
43
+ // 如果当前结果是 null 或 undefined,则后续路径无法访问,返回默认值
44
+ if (result == null) {
45
+ return defaultValue;
46
+ }
47
+
48
+ // 尝试访问属性
49
+ // 使用 segment 作为索引,TypeScript 默认这里是合法的
50
+ result = result[segment];
51
+ }
52
+
53
+ // 如果最终结果是 null 或 undefined,则返回默认值;否则返回结果
54
+ return result !== null && result !== undefined ? result : defaultValue;
55
+ }
56
+
57
+
58
+ /**
59
+ * 📋 复制对象属性,仅复制源对象 (source) 中 **存在** 且目标对象 (target) 中 **也有** 对应属性的那些值。
60
+ * 主要用于根据目标对象的结构来过滤和填充数据。
61
+ *
62
+ * @param source 源对象。
63
+ * @param target 目标对象。
64
+ * @returns void
65
+ */
66
+ static copyPropertyIfPresent<TSource extends object, TTarget extends object>(
67
+ source: TSource | null | undefined,
68
+ target: TTarget | null | undefined
69
+ ): void {
70
+ if (!source || !target || typeof source !== 'object' || typeof target !== 'object') {
71
+ return;
72
+ }
73
+
74
+ // 遍历目标对象的键,确保我们只复制目标对象上已有的属性
75
+ const keys = Object.keys(target) as (keyof TTarget)[];
76
+
77
+ for (const key of keys) {
78
+ // 检查源对象是否有这个属性
79
+ if (Object.hasOwn(source, key)) {
80
+ // 因为目标对象和源对象都被约束为 object,所以这里的类型转换是相对安全的
81
+ const value = (source as any)[key];
82
+ (target as any)[key] = value;
83
+ }
84
+ }
85
+ }
86
+
87
+
88
+ /**
89
+ * 📝 复制对象属性,将源对象 (source) 中 **非 undefined** 的属性值复制到目标对象 (target) 对应的属性上。
90
+ * 仅复制目标对象 (target) 中 **已有** 的属性,如果源对象中的值是 undefined 则不复制。
91
+ *
92
+ * @param source 源对象。
93
+ * @param target 目标对象。
94
+ * @returns void
95
+ */
96
+ static copyProperty<TSource extends object, TTarget extends object>(
97
+ source: TSource | null | undefined,
98
+ target: TTarget | null | undefined
99
+ ): void {
100
+ if (!source || !target || typeof source !== 'object' || typeof target !== 'object') {
101
+ return;
102
+ }
103
+
104
+ // 遍历目标对象的键
105
+ const keys = Object.keys(target) as (keyof TTarget)[];
106
+
107
+ for (const key of keys) {
108
+ // 尝试从源对象获取值
109
+ const value = (source as any)[key];
110
+
111
+ // 只有当值明确不是 undefined 时才复制(即允许复制 null 或其他 falsy 值)
112
+ if (value !== undefined) {
113
+ (target as any)[key] = value;
114
+ }
115
+ }
116
+ }
117
+
118
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * 存储工具类
3
+ * 使用 localStorage 进行数据的存取,并包含时间戳和默认值处理。
4
+ */
5
+ export class StorageUtils {
6
+
7
+ /**
8
+ * 从 localStorage 获取数据。
9
+ * @param key 存储的键。
10
+ * @param defaultValue 如果找不到键或值,返回的默认值 (默认为 null)。
11
+ * @returns 存储的值或默认值。
12
+ */
13
+ static get<T>(key: string, defaultValue: T | null = null): T | null {
14
+ const vStr = localStorage.getItem(key);
15
+ if (vStr == null) {
16
+ return defaultValue;
17
+ }
18
+
19
+ try {
20
+ return JSON.parse(vStr);
21
+ } catch (error) {
22
+ // 如果 JSON 解析失败 (例如,存储的值不是一个包含 createTime 和 data 的有效 JSON 结构)
23
+ console.error(`Error parsing storage item for key: ${key}`, error);
24
+ return defaultValue;
25
+ }
26
+ }
27
+
28
+ /**
29
+ * 将数据存储到 localStorage。
30
+ * 如果值为 null 或 undefined,则删除该键。
31
+ * @param key 存储的键。
32
+ * @param value 要存储的值。
33
+ */
34
+ static set<T>(key: string, value: T | null | undefined): void {
35
+ // 如果值为 null 或 undefined,则删除该键
36
+ if (value == null) {
37
+ localStorage.removeItem(key);
38
+ return;
39
+ }
40
+
41
+
42
+ try {
43
+ const dataStr = JSON.stringify(value);
44
+ localStorage.setItem(key, dataStr);
45
+ } catch (error) {
46
+ // 捕获 JSON.stringify 错误 (例如,如果 value 包含循环引用)
47
+ console.error(`Error stringify storage value for key: ${key}`, error);
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,436 @@
1
+ /**
2
+ * 字符串工具类
3
+ */
4
+ export class StringUtils {
5
+
6
+ static readonly ISO_SPLITTER = "/";
7
+
8
+ /**
9
+ * 移除字符串前缀
10
+ * @param str 原始字符串
11
+ * @param ch 要移除的前缀
12
+ * @returns 移除前缀后的字符串,或原字符串
13
+ */
14
+ static removePrefix(str: string | null | undefined, ch: string): string | null | undefined {
15
+ if (str != null && str.startsWith(ch)) {
16
+ return str.substring(ch.length);
17
+ }
18
+ return str;
19
+ }
20
+
21
+ /**
22
+ * 移除字符串后缀
23
+ * @param str 原始字符串
24
+ * @param ch 要移除的后缀
25
+ * @returns 移除后缀后的字符串,或原字符串
26
+ */
27
+ static removeSuffix(str: string | null | undefined, ch: string): string | null | undefined {
28
+ if (str != null && str.endsWith(ch)) {
29
+ return str.substring(0, str.length - ch.length);
30
+ }
31
+ return str;
32
+ }
33
+
34
+ static removePrefixAndSuffix(str: string , prefix: string, suffix: string): string {
35
+ if (str != null) {
36
+ str = StringUtils.removePrefix(str, prefix);
37
+ str = StringUtils.removeSuffix(str, suffix);
38
+ }
39
+ return str;
40
+ }
41
+
42
+
43
+ /**
44
+ * 生成指定长度的随机字符串
45
+ * @param length 随机字符串的长度
46
+ * @returns 生成的随机字符串
47
+ */
48
+ static random(length: number): string {
49
+ const characters: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
50
+ let result: string = '';
51
+ for (let i = 0; i < length; i++) {
52
+ result += characters.charAt(Math.floor(Math.random() * characters.length));
53
+ }
54
+ return result;
55
+ }
56
+
57
+ /**
58
+ * 处理空值,返回 "key未定义"
59
+ * @param key 键名
60
+ * @returns 处理后的字符串
61
+ */
62
+ static nullText(key: string | null | undefined): string {
63
+ return (key || '') + '未定义';
64
+ }
65
+
66
+ /**
67
+ * 检查字符串是否包含子字符串
68
+ * @param str 原始字符串
69
+ * @param subStr 要检查的子字符串
70
+ * @returns 如果包含则返回 true,否则返回 false
71
+ */
72
+ static contains(str: string | null | undefined, subStr: string): boolean {
73
+ if (!str) {
74
+ return false;
75
+ }
76
+ return str.includes(subStr);
77
+ }
78
+
79
+ static containsAll(str: string | null | undefined, subStr: string, subStr2: string): boolean {
80
+ if (!str) {
81
+ return false;
82
+ }
83
+ return str.includes(subStr) && str.includes(subStr2);
84
+ }
85
+
86
+
87
+ /**
88
+ * 统计子字符串在原始字符串中出现的次数
89
+ * @param str 原始字符串
90
+ * @param subStr 要统计的子字符串
91
+ * @returns 出现的次数
92
+ */
93
+ static count(str: string | null | undefined, subStr: string): number {
94
+ if (str == null || str.length === 0) {
95
+ return 0;
96
+ }
97
+ let count: number = 0;
98
+ let index: number = 0;
99
+
100
+ while (true) {
101
+ index = str.indexOf(subStr, index);
102
+ if (index === -1) {
103
+ break;
104
+ }
105
+ count++;
106
+ index += subStr.length;
107
+ }
108
+
109
+ return count;
110
+ }
111
+
112
+ /**
113
+ * 将字符串的首字母转换为大写
114
+ * @param str 原始字符串
115
+ * @returns 首字母大写后的字符串,或原值
116
+ */
117
+ static capitalize(str: string | null | undefined): string | null | undefined {
118
+ if (str == null) {
119
+ return str;
120
+ }
121
+ return str.charAt(0).toUpperCase() + str.slice(1);
122
+ }
123
+
124
+ /**
125
+ * 颠倒字符串的顺序
126
+ * @param str 原始字符串
127
+ * @returns 颠倒顺序后的字符串,或原值
128
+ */
129
+ static reverse(str: string | null | undefined): string | null | undefined {
130
+ if (str == null) {
131
+ return str;
132
+ }
133
+ return str.split('').reverse().join('');
134
+ }
135
+
136
+ /**
137
+ * 截取字符串,返回子字符串后面部分。如果不包含,则原样返回
138
+ * @param source 原始字符串
139
+ * @param str 分隔符
140
+ * @returns 分隔符后面的字符串,或原字符串
141
+ */
142
+ static subAfter(source: string | null | undefined, str: string): string | null | undefined {
143
+ if (source == null) {
144
+ return source;
145
+ }
146
+ const index = source.indexOf(str);
147
+ return index === -1 ? source : source.substring(index + str.length); // 修正:应为 index + str.length
148
+ }
149
+
150
+ /**
151
+ * 截取字符串,返回最后一个子字符串后面的部分。如果不包含,则原样返回
152
+ * @param source 原始字符串
153
+ * @param str 分隔符
154
+ * @returns 最后一个分隔符后面的字符串,或原字符串
155
+ */
156
+ static subAfterLast(source: string | null | undefined, str: string): string | null | undefined {
157
+ if (source == null) {
158
+ return source;
159
+ }
160
+ const index = source.lastIndexOf(str);
161
+ return index === -1 ? source : source.substring(index + str.length); // 修正:应为 index + str.length
162
+ }
163
+
164
+ /**
165
+ * 截取字符串,返回子字符串前面的部分。如果不包含,则原样返回
166
+ * @param str 原始字符串
167
+ * @param sub 分隔符
168
+ * @returns 分隔符前面的字符串,或原字符串
169
+ */
170
+ static subBefore(str: string | null | undefined, sub: string): string {
171
+ if (str == null) {
172
+ return "";
173
+ }
174
+ const index = str.indexOf(sub);
175
+ return index === -1 ? str : str.substring(0, index);
176
+ }
177
+
178
+ /**
179
+ * 混淆字符串 (通过在每个字符后添加 '1')
180
+ * @param str 原始字符串
181
+ * @returns 混淆后的字符串
182
+ */
183
+ static obfuscateString(str: string | null | undefined): string | null | undefined {
184
+ if (str == null) {
185
+ return str;
186
+ }
187
+ return str.split('').map(char => char + '1').join('');
188
+ }
189
+
190
+ /**
191
+ * 补零或补指定字符
192
+ * @param input 输入值(字符串或数字)
193
+ * @param totalLen 总长度
194
+ * @param padChar 填充字符,默认为 '0'
195
+ * @returns 填充后的字符串
196
+ */
197
+ static pad(input: string | number | null | undefined, totalLen: number, padChar: string = '0'): string {
198
+ if (input == null) {
199
+ return padChar.repeat(totalLen);
200
+ }
201
+ let str = String(input);
202
+ const charsNeeded: number = totalLen - str.length;
203
+ if (charsNeeded > 0) {
204
+ str = padChar.repeat(charsNeeded) + str;
205
+ }
206
+ return str;
207
+ }
208
+
209
+ /**
210
+ * 简单加密:将每个字符的 ASCII 码加 1,并转换为四位十六进制表示
211
+ * @param str 原始字符串
212
+ * @returns 加密后的十六进制字符串
213
+ */
214
+ static encrypt(str: string | null | undefined): string | null | undefined {
215
+ if (str == null) {
216
+ return str;
217
+ }
218
+ let encrypted: string = '';
219
+ for (let i = 0; i < str.length; i++) {
220
+ let charCode: number = str.charCodeAt(i);
221
+ charCode += 1;
222
+ // 转换为四位的十六进制表示,并确保至少四位
223
+ encrypted += ('0000' + charCode.toString(16)).slice(-4);
224
+ }
225
+ return encrypted;
226
+ }
227
+
228
+ /**
229
+ * 简单解密:还原加密字符串
230
+ * @param hexString 加密后的十六进制字符串
231
+ * @returns 解密后的字符串
232
+ */
233
+ static decrypt(hexString: string | null | undefined): string | null | undefined {
234
+ if (hexString == null) {
235
+ return hexString;
236
+ }
237
+ let decrypted: string = '';
238
+ // 确保是 4 的倍数,否则可能无法正确解密
239
+ if (hexString.length % 4 !== 0) {
240
+ // 应该抛出错误或根据业务逻辑处理,这里为兼容原 js 逻辑,简单返回
241
+ return hexString;
242
+ }
243
+
244
+ for (let i = 0; i < hexString.length; i += 4) {
245
+ const hexCharCode: string = hexString.substring(i, i + 4);
246
+ let charCode: number = parseInt(hexCharCode, 16); // 将十六进制转换为十进制
247
+ if (isNaN(charCode)) {
248
+ // 如果解析失败,也应根据业务逻辑处理
249
+ return hexString;
250
+ }
251
+ charCode -= 1;
252
+ decrypted += String.fromCharCode(charCode);
253
+ }
254
+ return decrypted;
255
+ }
256
+
257
+ /**
258
+ * 获取字符串的显示宽度:英文字符 1 宽,中文字符 2 宽
259
+ * @param str 原始字符串
260
+ * @returns 字符串的显示宽度
261
+ */
262
+ static getWidth(str: string | null | undefined): number {
263
+ if (str == null || str.length === 0) {
264
+ return 0;
265
+ }
266
+ // 使用非空断言 ! 简化
267
+ return str!.split('').reduce((pre, cur) => {
268
+ const charCode: number = cur.charCodeAt(0);
269
+ // 假设 0-128 为半角字符
270
+ if (charCode >= 0 && charCode <= 128) {
271
+ return pre + 1;
272
+ }
273
+ // 其它视为全角字符
274
+ return pre + 2;
275
+ }, 0);
276
+ }
277
+
278
+ /**
279
+ * 按显示宽度截取字符串
280
+ * @param str 原始字符串
281
+ * @param maxWidth 最大显示宽度
282
+ * @returns 截取后的字符串
283
+ */
284
+ static cutByWidth(str: string, maxWidth: number): string {
285
+ let showLength: number = 0;
286
+ return str.split('').reduce((pre, cur) => {
287
+ const charCode: number = cur.charCodeAt(0);
288
+ let charWidth: number = (charCode >= 0 && charCode <= 128) ? 1 : 2;
289
+
290
+ if (showLength + charWidth <= maxWidth) {
291
+ showLength += charWidth;
292
+ return pre + cur;
293
+ }
294
+ return pre;
295
+ }, '');
296
+ }
297
+
298
+
299
+ /**
300
+ * 字符串省略处理(按显示宽度计算)
301
+ * @param str 原始字符串
302
+ * @param len 字符长度(宽度),注:中文字符算 2
303
+ * @param suffix 省略号后缀,默认为 '...'
304
+ * @returns 处理后的字符串
305
+ */
306
+ static ellipsis(str: string | null | undefined, len: number, suffix: string = '...'): string | null | undefined {
307
+ if (str == null) {
308
+ return str;
309
+ }
310
+ if (!StringUtils.isStr(str)) { // 使用类方法调用
311
+ return str;
312
+ }
313
+
314
+ // 快速判断
315
+ if (str.length * 2 < len) {
316
+ return str;
317
+ }
318
+
319
+ const fullLength: number = StringUtils.getWidth(str);
320
+
321
+ if (fullLength <= len) {
322
+ return str;
323
+ }
324
+
325
+ // 截取
326
+ return StringUtils.cutByWidth(str, len) + suffix;
327
+ }
328
+
329
+ /**
330
+ * 判断值是否为字符串类型
331
+ * @param value 任意值
332
+ * @returns 是否为字符串
333
+ */
334
+ static isStr(value: any): value is string {
335
+ return typeof value === 'string';
336
+ }
337
+
338
+
339
+ /**
340
+ * 将下划线或连字符分隔的字符串转为驼峰命名
341
+ * @param str 原始字符串
342
+ * @param firstLower 转换后首字母是否小写,默认为 true
343
+ * @returns 转换后的驼峰字符串
344
+ */
345
+ static toCamelCase(str: string, firstLower: boolean = true): string {
346
+ // 匹配下划线或连字符后跟一个字母
347
+ let result: string = str.replace(/[-_](\w)/g, function (all, letter) {
348
+ return letter.toUpperCase();
349
+ });
350
+
351
+ if (firstLower) {
352
+ // 确保首字母小写
353
+ result = result.substring(0, 1).toLowerCase() + result.substring(1);
354
+ }
355
+
356
+ return result;
357
+ }
358
+
359
+ /**
360
+ * 将驼峰命名字符串转为下划线命名
361
+ * @param name 驼峰命名字符串
362
+ * @returns 下划线命名字符串
363
+ */
364
+ static toUnderlineCase(name: string | null | undefined): string | null | undefined {
365
+ if (name == null) {
366
+ return null;
367
+ }
368
+ // 在大写字母前添加下划线,并全部转小写
369
+ let result: string = name.replace(/([A-Z])/g, '_$1').toLowerCase();
370
+
371
+ // 移除开头多余的下划线
372
+ if (result.startsWith('_')) {
373
+ result = result.substring(1);
374
+ }
375
+ return result;
376
+ }
377
+
378
+ /**
379
+ * 比较两个字符串是否相等,忽略大小写
380
+ * @param a 字符串 a
381
+ * @param b 字符串 b
382
+ * @returns 是否相等(忽略大小写)
383
+ */
384
+ static equalsIgnoreCase(a: string | null | undefined, b: string | null | undefined): boolean {
385
+ if (a === b) { // 引用相同,或同时为 null/undefined
386
+ return true;
387
+ }
388
+
389
+ if (a != null && b != null) {
390
+ return a.toLowerCase() === b.toLowerCase();
391
+ }
392
+
393
+ // 只有在 a === b 时,null/undefined 才是 true
394
+ return false;
395
+ }
396
+
397
+ /**
398
+ * 分割字符串
399
+ * @param str
400
+ * @param sp
401
+ */
402
+ static split(str: any, sp: string):string[] {
403
+ if(str == null || str.length === 0){
404
+ return []
405
+ }
406
+ if(Array.isArray(str)){
407
+ return str as string[];
408
+ }
409
+
410
+ return str.split(sp)
411
+ }
412
+ static splitTrim(str: any, sp: string):string[] {
413
+ const arr = StringUtils.split(str, sp).map(item => item.trim())
414
+ for (let i = 0; i < arr.length; i++) {
415
+ arr[i] = arr[i].trim()
416
+ }
417
+ return arr;
418
+ }
419
+
420
+ /**
421
+ * 连接字符串
422
+ * @param arr
423
+ * @param sp 分隔符
424
+ */
425
+ static join(arr, sp: string) {
426
+ if (arr == null) {
427
+ return []
428
+ }
429
+
430
+ if(!Array.isArray(arr)){
431
+ return arr;
432
+ }
433
+
434
+ return arr.join(sp);
435
+ }
436
+ }