midway-fatcms 0.0.17 → 0.0.19

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/dist/libs/crud-pro/services/CrudProDataTypeConvertService.d.ts +2 -37
  2. package/dist/libs/crud-pro/services/CrudProDataTypeConvertService.js +137 -213
  3. package/dist/libs/crud-pro/utils/MixinUtils.d.ts +2 -17
  4. package/dist/libs/crud-pro/utils/MixinUtils.js +4 -84
  5. package/dist/libs/crud-pro/utils/idgene/generateSnowflakeId.d.ts +12 -0
  6. package/dist/libs/crud-pro/utils/idgene/generateSnowflakeId.js +61 -0
  7. package/dist/libs/crud-pro/utils/idgene/generateSnowflakeIdExt.d.ts +27 -0
  8. package/dist/libs/crud-pro/utils/idgene/generateSnowflakeIdExt.js +96 -0
  9. package/dist/libs/crud-pro/utils/idgene/index.d.ts +3 -0
  10. package/dist/libs/crud-pro/utils/idgene/index.js +10 -0
  11. package/dist/libs/crud-pro/utils/idgene/uuid.d.ts +7 -0
  12. package/dist/libs/crud-pro/utils/idgene/uuid.js +28 -0
  13. package/dist/libs/crud-pro-quick/fixSoftDelete.d.ts +0 -17
  14. package/dist/libs/crud-pro-quick/fixSoftDelete.js +55 -5
  15. package/dist/libs/crud-pro-quick/models.d.ts +11 -1
  16. package/dist/service/SysAppService.d.ts +0 -3
  17. package/dist/service/SysAppService.js +0 -15
  18. package/dist/service/SysConfigService.d.ts +0 -1
  19. package/dist/service/SysConfigService.js +0 -6
  20. package/dist/service/SysDictDataService.d.ts +0 -2
  21. package/dist/service/SysDictDataService.js +0 -12
  22. package/dist/service/SysMenuService.d.ts +0 -1
  23. package/dist/service/SysMenuService.js +0 -3
  24. package/dist/service/WorkbenchService.d.ts +0 -1
  25. package/dist/service/WorkbenchService.js +0 -3
  26. package/dist/service/base/bizmemcache/BizMemCacheService.js +4 -2
  27. package/dist/service/base/bizmemcache/BizMemCacheStore.js +10 -9
  28. package/dist/service/crudstd/CrudStdService.js +1 -1
  29. package/dist/service/curd/fixCfgModel.js +21 -1
  30. package/package.json +1 -1
  31. package/src/libs/crud-pro/services/CrudProDataTypeConvertService.ts +149 -219
  32. package/src/libs/crud-pro/utils/MixinUtils.ts +309 -400
  33. package/src/libs/crud-pro/utils/idgene/generateSnowflakeId.ts +65 -0
  34. package/src/libs/crud-pro/utils/idgene/generateSnowflakeIdExt.ts +106 -0
  35. package/src/libs/crud-pro/utils/idgene/index.ts +3 -0
  36. package/src/libs/crud-pro/utils/idgene/uuid.ts +26 -0
  37. package/src/libs/crud-pro-quick/fixSoftDelete.ts +84 -18
  38. package/src/libs/crud-pro-quick/models.ts +15 -3
  39. package/src/service/SysAppService.ts +0 -18
  40. package/src/service/SysConfigService.ts +0 -8
  41. package/src/service/SysDictDataService.ts +0 -14
  42. package/src/service/SysMenuService.ts +0 -4
  43. package/src/service/WorkbenchService.ts +0 -5
  44. package/src/service/base/bizmemcache/BizMemCacheService.ts +4 -2
  45. package/src/service/base/bizmemcache/BizMemCacheStore.ts +10 -9
  46. package/src/service/crudstd/CrudStdService.ts +3 -2
  47. package/src/service/curd/fixCfgModel.ts +145 -125
@@ -1,400 +1,309 @@
1
- import { CommonException, Exceptions } from '../exceptions';
2
-
3
- // 至少需要2个字符
4
- const FIELD_NAME_REG_EXP = /^[a-zA-Z][0-9a-zA-Z_]+$/;
5
-
6
- // ===================== 雪花ID =====================
7
- const SNOWFLAKE_SEQ_START = 1
8
- let snowflakeSeq = SNOWFLAKE_SEQ_START;
9
- let snowflakeLastTs = -1;
10
-
11
- /**
12
- * 生成雪花ID(64位整数,JS 中以 string 返回)
13
- * 结构:1位符号 + 41位时间戳(ms) + 10位机器ID + 12位序列号
14
- * - 时间戳:相对于 2024-01-01 00:00:00 的毫秒偏移,可用约 69 年
15
- * - 机器ID:0-1023,优先取参数 > 环境变量 SNOWFLAKE_MACHINE_ID > process.pid 低10位
16
- * - 序列号:0-4095,同一毫秒内自增
17
- *
18
- * @param machineId 机器ID(0-1023),不传则依次从环境变量 SNOWFLAKE_MACHINE_ID、process.pid 获取
19
- * @returns 雪花ID字符串
20
- */
21
- function generateSnowflakeId(machineId?: number): string {
22
- const EPOCH = 1704067200000; // 2024-01-01 00:00:00 UTC
23
-
24
- let mid = Number(machineId);
25
- if (mid === undefined || mid === null || isNaN(mid)) {
26
- // 优先从环境变量获取,适配多实例部署场景
27
- const envMid = typeof process !== 'undefined' && process.env && process.env.SNOWFLAKE_MACHINE_ID
28
- ? parseInt(process.env.SNOWFLAKE_MACHINE_ID, 10)
29
- : NaN;
30
- mid = !isNaN(envMid) ? envMid : (typeof process !== 'undefined' && process.pid ? process.pid & 0x3ff : 0);
31
- }
32
-
33
- mid = Math.abs(mid) & 0x3ff; // 确保在 0-1023 范围
34
-
35
- let now = Date.now();
36
- let ts = now - EPOCH;
37
-
38
- // 时钟回拨保护:若当前时间戳小于上次,直接沿用上次时间戳继续递增,
39
- // 避免 NTP 校正/VM 快照恢复等场景下生成重复 ID,同时不阻塞 CPU
40
- if (ts < snowflakeLastTs) {
41
- const drift = snowflakeLastTs - ts;
42
- if (drift <= 5) {
43
- // 小幅回拨,沿用上次时间戳(ID 仅比实际时间快 ≤5ms,不影响唯一性和排序性)
44
- ts = snowflakeLastTs;
45
- } else {
46
- // 大幅回拨,无法安全恢复,抛出异常
47
- throw new Error(`Snowflake clock drift detected: ${drift}ms backwards. Refusing to generate ID.`);
48
- }
49
- }
50
-
51
- if (ts === snowflakeLastTs) {
52
- snowflakeSeq = (snowflakeSeq + 1) & 0xfff; // 0-4095 循环
53
- if (snowflakeSeq === 0) {
54
- // 本毫秒序列号耗尽,直接推进到下一毫秒(不阻塞CPU忙等待)
55
- // ID 的时间戳比实际时间快 ≤1ms,不影响唯一性和排序性
56
- ts = snowflakeLastTs + 1;
57
- snowflakeSeq = SNOWFLAKE_SEQ_START;
58
- }
59
- } else {
60
- snowflakeSeq = SNOWFLAKE_SEQ_START;
61
- }
62
-
63
- snowflakeLastTs = ts;
64
-
65
- // 雪花ID超过JS安全整数范围(2^53),Number运算会丢失精度
66
- // 使用 BigInt 做位移拼接,确保 64 位精度完整
67
- const id = (BigInt(ts) << BigInt(22)) | (BigInt(mid) << BigInt(12)) | BigInt(snowflakeSeq);
68
- return id.toString();
69
- }
70
-
71
-
72
-
73
- /**
74
- * 生成 UUID v4 字符串(纯随机,无外部依赖)
75
- * 格式:xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,其中 y 为 8/9/a/b 之一
76
- * @returns 符合 RFC 4122 v4 规范的 UUID 字符串
77
- */
78
- function uuid(): string {
79
- // crypto.getRandomValues 在 Node.js >= 11 和现代浏览器中可用
80
- if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
81
- const bytes = new Uint8Array(16);
82
- crypto.getRandomValues(bytes);
83
- // 版本位:第6字节高4位设为 0100 (v4)
84
- bytes[6] = (bytes[6] & 0x0f) | 0x40;
85
- // 变体位:第8字节高2位设为 10
86
- bytes[8] = (bytes[8] & 0x3f) | 0x80;
87
- const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
88
- return hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20);
89
- }
90
- // 降级方案:Math.random
91
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
92
- const r = Math.random() * 16 | 0;
93
- const v = c === 'x' ? r : (r & 0x3 | 0x8);
94
- return v.toString(16);
95
- });
96
- }
97
-
98
-
99
- const MixinUtils = {
100
- isNil(obj: any): boolean {
101
- return typeof obj === 'undefined' || obj === null;
102
- },
103
- isNotNil(obj: any): boolean {
104
- return !MixinUtils.isNil(obj);
105
- },
106
- isEmpty(obj: any): boolean {
107
- if (typeof obj === 'number' || typeof obj === 'boolean') {
108
- return false; // 数字和布尔值永远不为空
109
- }
110
-
111
- if (obj === null || obj === undefined) {
112
- return true;
113
- }
114
-
115
- if (typeof obj === 'string') {
116
- return obj.length === 0;
117
- }
118
-
119
- if (Array.isArray(obj)) {
120
- return obj.length === 0;
121
- }
122
-
123
- if (typeof obj === 'object') {
124
- return Object.keys(obj).length === 0;
125
- }
126
-
127
- return false;
128
- },
129
-
130
- isNotEmpty(obj: any): boolean {
131
- return !MixinUtils.isEmpty(obj);
132
- },
133
-
134
- equals(obj1: any, obj2: any): boolean {
135
- return obj1 === obj2;
136
- },
137
-
138
- equalsIgnoreCase(str1: string, str2: string): boolean {
139
- // 严格检查类型
140
- if (typeof str1 !== 'string' || typeof str2 !== 'string') {
141
- return str1 === str2;
142
- }
143
- return str1.toUpperCase() === str2.toUpperCase();
144
- },
145
-
146
- startsWith(str1: string, str2: string): boolean {
147
- if (typeof str1 === 'string' && typeof str2 === 'string') {
148
- return str1.startsWith(str2);
149
- }
150
- return false;
151
- },
152
-
153
- isValidFieldName(s: string): boolean {
154
- if (MixinUtils.isEmpty(s)) {
155
- return false;
156
- }
157
- return FIELD_NAME_REG_EXP.test(s);
158
- },
159
-
160
- isElementAllMatch(array: any, match: (e: any) => boolean): boolean {
161
- for (let i = 0; i < array.length; i++) {
162
- const e = array[i];
163
- if (!match(e)) {
164
- return false;
165
- }
166
- }
167
- return true;
168
- },
169
-
170
- parseColumns(columns: string | string[]) {
171
- return MixinUtils.parseStringArray(columns);
172
- },
173
-
174
- parseStringArray(columns: string | string[]): any[] {
175
- if (!columns || columns === '*') {
176
- return [];
177
- }
178
-
179
- if (typeof columns === 'string') {
180
- const columnsTrim = columns.trim();
181
- // JSON形式
182
- if (columnsTrim.startsWith('[') && columnsTrim.endsWith(']')) {
183
- return MixinUtils.parseJsonObject(columnsTrim);
184
- }
185
- //逗号形式
186
- return columnsTrim.split(',').filter(s => {
187
- return s.length > 0;
188
- });
189
- }
190
-
191
- if (!Array.isArray(columns)) {
192
- throw new CommonException(Exceptions.CFG_PARSE_ERROR, 'params must be an array or string');
193
- }
194
-
195
- return columns.filter(s => {
196
- return !MixinUtils.isEmpty(s);
197
- });
198
- },
199
-
200
- removeStringPrefix(str: string, prefix: string): string {
201
- if (!str) {
202
- return '';
203
- }
204
- if (str === prefix) {
205
- return '';
206
- }
207
- if (str.startsWith(prefix)) {
208
- return str.substring(prefix.length);
209
- }
210
- return str;
211
- },
212
- getErrorMessage(e: any) {
213
- if (!e) {
214
- return '';
215
- }
216
- const obj = {};
217
- let fieldCount = 0;
218
- const keys = ['code', 'message', 'errno', 'sql', 'sqlState', 'sqlMessage', 'stack'];
219
- for (let i = 0; i < keys.length; i++) {
220
- const key = keys[i];
221
- const value = e[key];
222
- if (value) {
223
- obj[key] = value;
224
- fieldCount++;
225
- }
226
- }
227
-
228
- if (fieldCount > 0) {
229
- return JSON.stringify(obj);
230
- }
231
-
232
- return '' + e;
233
- },
234
-
235
- parseJsonObject(str: any): any {
236
- if (!str) {
237
- return null;
238
- }
239
-
240
- if (typeof str === 'object' || Array.isArray(str)) {
241
- return str;
242
- }
243
-
244
- if (typeof str === 'string') {
245
- str = str.trim();
246
- if (str.startsWith('{') || str.startsWith('[')) {
247
- try {
248
- return JSON.parse(str);
249
- } catch (e) {
250
- return null;
251
- }
252
- }
253
- }
254
-
255
- return null;
256
- },
257
-
258
- /**
259
- * 将数组转换成Map方便查询
260
- * @param list
261
- * @param getKey
262
- */
263
- toMap<T>(list: T[], getKey: (e: T) => string): Record<string, T> {
264
- const map = {};
265
- if (Array.isArray(list) && list.length) {
266
- for (let i = 0; i < list.length; i++) {
267
- const e = list[i];
268
- const key = getKey(e);
269
- map[key] = e;
270
- }
271
- }
272
- return map;
273
- },
274
-
275
- /**
276
- * 将数组转换成Map方便查询
277
- * @param list
278
- * @param getKey
279
- */
280
- toNewMap<T>(list: T[], getKey: (e: T) => string): Map<string, T> {
281
- const map = new Map();
282
- if (list && list.length) {
283
- for (let i = 0; i < list.length; i++) {
284
- const e = list[i];
285
- const key = getKey(e);
286
- map.set(key, e);
287
- }
288
- }
289
- return map;
290
- },
291
-
292
- deepTravelObject(obj: any, objTravelCallback: (value, key, index, keyPath) => void, keyPath: string) {
293
- if (!obj || !objTravelCallback) {
294
- return;
295
- }
296
-
297
- if (Array.isArray(obj)) {
298
- const collection = obj;
299
- for (let i = 0; i < collection.length; i++) {
300
- const value = collection[i];
301
- const curKeyPath = keyPath + '[' + i + ']';
302
- objTravelCallback(value, null, i, curKeyPath);
303
- MixinUtils.deepTravelObject(value, objTravelCallback, curKeyPath);
304
- }
305
- return;
306
- }
307
-
308
- if (typeof obj === 'object') {
309
- const keys = Object.keys(obj);
310
- for (let i = 0; i < keys.length; i++) {
311
- const objKey = keys[i];
312
- const keyStr = objKey;
313
- const value = obj[objKey];
314
- const curKeyPath = keyPath + '.' + keyStr;
315
- objTravelCallback(value, keyStr, null, curKeyPath);
316
- MixinUtils.deepTravelObject(value, objTravelCallback, curKeyPath);
317
- }
318
- }
319
-
320
- },
321
- removeEmptyAttrs(obj: any): any {
322
- const result = {};
323
- const keys = Object.keys(obj);
324
- for (let i = 0; i < keys.length; i++) {
325
- const key = keys[i];
326
- const value = obj[key];
327
- if (MixinUtils.isNotNil(value)) {
328
- result[key] = value;
329
- }
330
- }
331
- return result;
332
- },
333
-
334
- /**
335
- * 判断集合A中,是否包含任意一个集合B中的元素
336
- * @param a
337
- * @param b
338
- */
339
- hasAny(a: string[], b: string[]): boolean {
340
- const aSet = new Set(a);
341
- for (let i = 0; i < b.length; i++) {
342
- const bElement = b[i];
343
- if (aSet.has(bElement)) {
344
- return true;
345
- }
346
- }
347
- return false;
348
- },
349
-
350
- selectNotEmpty(a: any, b: any): any {
351
- if (MixinUtils.isNotEmpty(a)) {
352
- return a;
353
- }
354
- return b;
355
- },
356
-
357
- parseValueByType(value: any, targetType: string): any {
358
- if (value === undefined || value === null) {
359
- return value;
360
- }
361
- if (targetType === 'string') {
362
- return '' + value;
363
- }
364
- if (targetType === 'number') {
365
- return Number(value);
366
- }
367
- if (targetType === 'boolean') {
368
- return value === 1 || value === true || value === 'true';
369
- }
370
- if (targetType === 'array') {
371
- return MixinUtils.parseStringArray(value);
372
- }
373
- if (targetType === 'JSONObject') {
374
- return MixinUtils.parseJsonObject(value);
375
- }
376
- return value;
377
- },
378
- sleepMs(ms: number): Promise<any> {
379
- return new Promise(resolve => setTimeout(resolve, ms));
380
- },
381
-
382
- /**
383
- * 生成 UUID v4 字符串(纯随机,无外部依赖)
384
- * 格式:xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,其中 y 为 8/9/a/b 之一
385
- * @returns 符合 RFC 4122 v4 规范的 UUID 字符串
386
- */
387
- uuid: uuid,
388
-
389
- /**
390
- * 生成雪花ID(64位整数,以字符串返回)
391
- * 结构:1位符号 + 41位时间戳(ms) + 10位机器ID + 12位序列号
392
- * 同一毫秒内可生成 4096 个不重复ID,单机每秒可生成约 400 万个
393
- *
394
- * @param machineId 机器ID(0-1023),不传则依次从环境变量 SNOWFLAKE_MACHINE_ID、process.pid 获取
395
- * @returns 雪花ID字符串
396
- */
397
- generateSnowflakeId: generateSnowflakeId,
398
- };
399
-
400
- export { MixinUtils };
1
+ import { CommonException, Exceptions } from '../exceptions';
2
+ import { generateSnowflakeId, uuid, generateSnowflakeIdExt } from './idgene';
3
+
4
+ // 至少需要2个字符
5
+ const FIELD_NAME_REG_EXP = /^[a-zA-Z][0-9a-zA-Z_]+$/;
6
+
7
+ const MixinUtils = {
8
+ isNil(obj: any): boolean {
9
+ return typeof obj === 'undefined' || obj === null;
10
+ },
11
+ isNotNil(obj: any): boolean {
12
+ return !MixinUtils.isNil(obj);
13
+ },
14
+ isEmpty(obj: any): boolean {
15
+ if (typeof obj === 'number' || typeof obj === 'boolean') {
16
+ return false; // ✅ 数字和布尔值永远不为空
17
+ }
18
+
19
+ if (obj === null || obj === undefined) {
20
+ return true;
21
+ }
22
+
23
+ if (typeof obj === 'string') {
24
+ return obj.length === 0;
25
+ }
26
+
27
+ if (Array.isArray(obj)) {
28
+ return obj.length === 0;
29
+ }
30
+
31
+ if (typeof obj === 'object') {
32
+ return Object.keys(obj).length === 0;
33
+ }
34
+
35
+ return false;
36
+ },
37
+
38
+ isNotEmpty(obj: any): boolean {
39
+ return !MixinUtils.isEmpty(obj);
40
+ },
41
+
42
+ equals(obj1: any, obj2: any): boolean {
43
+ return obj1 === obj2;
44
+ },
45
+
46
+ equalsIgnoreCase(str1: string, str2: string): boolean {
47
+ // 严格检查类型
48
+ if (typeof str1 !== 'string' || typeof str2 !== 'string') {
49
+ return str1 === str2;
50
+ }
51
+ return str1.toUpperCase() === str2.toUpperCase();
52
+ },
53
+
54
+ startsWith(str1: string, str2: string): boolean {
55
+ if (typeof str1 === 'string' && typeof str2 === 'string') {
56
+ return str1.startsWith(str2);
57
+ }
58
+ return false;
59
+ },
60
+
61
+ isValidFieldName(s: string): boolean {
62
+ if (MixinUtils.isEmpty(s)) {
63
+ return false;
64
+ }
65
+ return FIELD_NAME_REG_EXP.test(s);
66
+ },
67
+
68
+ isElementAllMatch(array: any, match: (e: any) => boolean): boolean {
69
+ for (let i = 0; i < array.length; i++) {
70
+ const e = array[i];
71
+ if (!match(e)) {
72
+ return false;
73
+ }
74
+ }
75
+ return true;
76
+ },
77
+
78
+ parseColumns(columns: string | string[]) {
79
+ return MixinUtils.parseStringArray(columns);
80
+ },
81
+
82
+ parseStringArray(columns: string | string[]): any[] {
83
+ if (!columns || columns === '*') {
84
+ return [];
85
+ }
86
+
87
+ if (typeof columns === 'string') {
88
+ const columnsTrim = columns.trim();
89
+ // JSON形式
90
+ if (columnsTrim.startsWith('[') && columnsTrim.endsWith(']')) {
91
+ return MixinUtils.parseJsonObject(columnsTrim);
92
+ }
93
+ //逗号形式
94
+ return columnsTrim.split(',').filter(s => {
95
+ return s.length > 0;
96
+ });
97
+ }
98
+
99
+ if (!Array.isArray(columns)) {
100
+ throw new CommonException(Exceptions.CFG_PARSE_ERROR, 'params must be an array or string');
101
+ }
102
+
103
+ return columns.filter(s => {
104
+ return !MixinUtils.isEmpty(s);
105
+ });
106
+ },
107
+
108
+ removeStringPrefix(str: string, prefix: string): string {
109
+ if (!str) {
110
+ return '';
111
+ }
112
+ if (str === prefix) {
113
+ return '';
114
+ }
115
+ if (str.startsWith(prefix)) {
116
+ return str.substring(prefix.length);
117
+ }
118
+ return str;
119
+ },
120
+ getErrorMessage(e: any) {
121
+ if (!e) {
122
+ return '';
123
+ }
124
+ const obj = {};
125
+ let fieldCount = 0;
126
+ const keys = ['code', 'message', 'errno', 'sql', 'sqlState', 'sqlMessage', 'stack'];
127
+ for (let i = 0; i < keys.length; i++) {
128
+ const key = keys[i];
129
+ const value = e[key];
130
+ if (value) {
131
+ obj[key] = value;
132
+ fieldCount++;
133
+ }
134
+ }
135
+
136
+ if (fieldCount > 0) {
137
+ return JSON.stringify(obj);
138
+ }
139
+
140
+ return '' + e;
141
+ },
142
+
143
+ parseJsonObject(str: any): any {
144
+ if (!str) {
145
+ return null;
146
+ }
147
+
148
+ if (typeof str === 'object' || Array.isArray(str)) {
149
+ return str;
150
+ }
151
+
152
+ if (typeof str === 'string') {
153
+ str = str.trim();
154
+ if (str.startsWith('{') || str.startsWith('[')) {
155
+ try {
156
+ return JSON.parse(str);
157
+ } catch (e) {
158
+ return null;
159
+ }
160
+ }
161
+ }
162
+
163
+ return null;
164
+ },
165
+
166
+ /**
167
+ * 将数组转换成Map方便查询
168
+ * @param list
169
+ * @param getKey
170
+ */
171
+ toMap<T>(list: T[], getKey: (e: T) => string): Record<string, T> {
172
+ const map = {};
173
+ if (Array.isArray(list) && list.length) {
174
+ for (let i = 0; i < list.length; i++) {
175
+ const e = list[i];
176
+ const key = getKey(e);
177
+ map[key] = e;
178
+ }
179
+ }
180
+ return map;
181
+ },
182
+
183
+ /**
184
+ * 将数组转换成Map方便查询
185
+ * @param list
186
+ * @param getKey
187
+ */
188
+ toNewMap<T>(list: T[], getKey: (e: T) => string): Map<string, T> {
189
+ const map = new Map();
190
+ if (list && list.length) {
191
+ for (let i = 0; i < list.length; i++) {
192
+ const e = list[i];
193
+ const key = getKey(e);
194
+ map.set(key, e);
195
+ }
196
+ }
197
+ return map;
198
+ },
199
+
200
+ deepTravelObject(obj: any, objTravelCallback: (value, key, index, keyPath) => void, keyPath: string) {
201
+ if (!obj || !objTravelCallback) {
202
+ return;
203
+ }
204
+
205
+ if (Array.isArray(obj)) {
206
+ const collection = obj;
207
+ for (let i = 0; i < collection.length; i++) {
208
+ const value = collection[i];
209
+ const curKeyPath = keyPath + '[' + i + ']';
210
+ objTravelCallback(value, null, i, curKeyPath);
211
+ MixinUtils.deepTravelObject(value, objTravelCallback, curKeyPath);
212
+ }
213
+ return;
214
+ }
215
+
216
+ if (typeof obj === 'object') {
217
+ const keys = Object.keys(obj);
218
+ for (let i = 0; i < keys.length; i++) {
219
+ const objKey = keys[i];
220
+ const keyStr = objKey;
221
+ const value = obj[objKey];
222
+ const curKeyPath = keyPath + '.' + keyStr;
223
+ objTravelCallback(value, keyStr, null, curKeyPath);
224
+ MixinUtils.deepTravelObject(value, objTravelCallback, curKeyPath);
225
+ }
226
+ }
227
+ },
228
+ removeEmptyAttrs(obj: any): any {
229
+ const result = {};
230
+ const keys = Object.keys(obj);
231
+ for (let i = 0; i < keys.length; i++) {
232
+ const key = keys[i];
233
+ const value = obj[key];
234
+ if (MixinUtils.isNotNil(value)) {
235
+ result[key] = value;
236
+ }
237
+ }
238
+ return result;
239
+ },
240
+
241
+ /**
242
+ * 判断集合A中,是否包含任意一个集合B中的元素
243
+ * @param a
244
+ * @param b
245
+ */
246
+ hasAny(a: string[], b: string[]): boolean {
247
+ const aSet = new Set(a);
248
+ for (let i = 0; i < b.length; i++) {
249
+ const bElement = b[i];
250
+ if (aSet.has(bElement)) {
251
+ return true;
252
+ }
253
+ }
254
+ return false;
255
+ },
256
+
257
+ selectNotEmpty(a: any, b: any): any {
258
+ if (MixinUtils.isNotEmpty(a)) {
259
+ return a;
260
+ }
261
+ return b;
262
+ },
263
+
264
+ parseValueByType(value: any, targetType: string): any {
265
+ if (value === undefined || value === null) {
266
+ return value;
267
+ }
268
+ if (targetType === 'string') {
269
+ return '' + value;
270
+ }
271
+ if (targetType === 'number') {
272
+ return Number(value);
273
+ }
274
+ if (targetType === 'boolean') {
275
+ return value === 1 || value === true || value === 'true';
276
+ }
277
+ if (targetType === 'array') {
278
+ return MixinUtils.parseStringArray(value);
279
+ }
280
+ if (targetType === 'JSONObject') {
281
+ return MixinUtils.parseJsonObject(value);
282
+ }
283
+ return value;
284
+ },
285
+ sleepMs(ms: number): Promise<any> {
286
+ return new Promise(resolve => setTimeout(resolve, ms));
287
+ },
288
+
289
+ /**
290
+ * 生成 UUID v4 字符串(纯随机,无外部依赖)
291
+ * 格式:xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,其中 y 为 8/9/a/b 之一
292
+ * @returns 符合 RFC 4122 v4 规范的 UUID 字符串
293
+ */
294
+ uuid: uuid,
295
+
296
+ /**
297
+ * 生成雪花ID(64位整数,以字符串返回)
298
+ * 结构:1位符号 + 41位时间戳(ms) + 10位机器ID + 12位序列号
299
+ * 同一毫秒内可生成 4096 个不重复ID,单机每秒可生成约 400 万个
300
+ *
301
+ * @param machineId 机器ID(0-1023),不传则依次从环境变量 SNOWFLAKE_MACHINE_ID、process.pid 获取
302
+ * @returns 雪花ID字符串
303
+ */
304
+ generateSnowflakeId: generateSnowflakeId,
305
+
306
+ generateSnowflakeIdExt: generateSnowflakeIdExt,
307
+ };
308
+
309
+ export { MixinUtils };