midway-fatcms 0.0.5 → 0.0.6

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 (126) hide show
  1. package/README.md +377 -134
  2. package/dist/controller/manage/CrudStandardDesignApi.d.ts +0 -2
  3. package/dist/controller/manage/CrudStandardDesignApi.js +11 -85
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.js +2 -0
  6. package/dist/libs/crud-pro/CrudPro.d.ts +9 -1
  7. package/dist/libs/crud-pro/CrudPro.js +15 -0
  8. package/dist/libs/crud-pro/README.md +809 -0
  9. package/dist/libs/crud-pro/README_FUNC.md +193 -0
  10. package/dist/libs/crud-pro/exceptions.d.ts +2 -0
  11. package/dist/libs/crud-pro/exceptions.js +2 -0
  12. package/dist/libs/crud-pro/interfaces.d.ts +34 -1
  13. package/dist/libs/crud-pro/models/ExecuteContext.d.ts +3 -3
  14. package/dist/libs/crud-pro/models/ExecuteContext.js +2 -0
  15. package/dist/libs/crud-pro/models/RequestModel.d.ts +41 -1
  16. package/dist/libs/crud-pro/models/RequestModel.js +103 -39
  17. package/dist/libs/crud-pro/models/ResModel.d.ts +6 -4
  18. package/dist/libs/crud-pro/models/ServiceHub.d.ts +1 -0
  19. package/dist/libs/crud-pro/models/keys.d.ts +6 -1
  20. package/dist/libs/crud-pro/models/keys.js +5 -0
  21. package/dist/libs/crud-pro/services/CrudProDataTypeConvertService.d.ts +52 -0
  22. package/dist/libs/crud-pro/services/CrudProDataTypeConvertService.js +158 -0
  23. package/dist/libs/crud-pro/services/CrudProExecuteSqlService.js +20 -1
  24. package/dist/libs/crud-pro/services/CrudProFieldValidateService.d.ts +7 -0
  25. package/dist/libs/crud-pro/services/CrudProFieldValidateService.js +32 -0
  26. package/dist/libs/crud-pro/services/CrudProGenSqlService.d.ts +13 -0
  27. package/dist/libs/crud-pro/services/CrudProGenSqlService.js +44 -7
  28. package/dist/libs/crud-pro/services/CrudProOriginToExecuteSql.d.ts +43 -0
  29. package/dist/libs/crud-pro/services/CrudProOriginToExecuteSql.js +132 -1
  30. package/dist/libs/crud-pro/services/CrudProTableMetaService.d.ts +15 -1
  31. package/dist/libs/crud-pro/services/CrudProTableMetaService.js +107 -0
  32. package/dist/libs/crud-pro/services/CurdProServiceHub.d.ts +5 -1
  33. package/dist/libs/crud-pro/services/CurdProServiceHub.js +11 -0
  34. package/dist/libs/crud-pro/utils/DateTimeUtils.d.ts +1 -0
  35. package/dist/libs/crud-pro/utils/DateTimeUtils.js +3 -0
  36. package/dist/libs/crud-pro/utils/MixinUtils.d.ts +32 -0
  37. package/dist/libs/crud-pro/utils/MixinUtils.js +85 -1
  38. package/dist/libs/crud-pro/utils/ValidateUtils.js +1 -1
  39. package/dist/libs/crud-sharding/ROUTING_LOGIC.md +944 -0
  40. package/dist/libs/crud-sharding/ShardingConfig.d.ts +218 -0
  41. package/dist/libs/crud-sharding/ShardingConfig.js +32 -0
  42. package/dist/libs/crud-sharding/ShardingCountCache.d.ts +69 -0
  43. package/dist/libs/crud-sharding/ShardingCountCache.js +160 -0
  44. package/dist/libs/crud-sharding/ShardingCrudPro.d.ts +363 -0
  45. package/dist/libs/crud-sharding/ShardingCrudPro.js +699 -0
  46. package/dist/libs/crud-sharding/ShardingMerger.d.ts +130 -0
  47. package/dist/libs/crud-sharding/ShardingMerger.js +280 -0
  48. package/dist/libs/crud-sharding/ShardingRouter.d.ts +69 -0
  49. package/dist/libs/crud-sharding/ShardingRouter.js +377 -0
  50. package/dist/libs/crud-sharding/ShardingTableCreator.d.ts +146 -0
  51. package/dist/libs/crud-sharding/ShardingTableCreator.js +805 -0
  52. package/dist/libs/crud-sharding/ShardingUtils.d.ts +38 -0
  53. package/dist/libs/crud-sharding/ShardingUtils.js +77 -0
  54. package/dist/libs/crud-sharding/index.d.ts +45 -0
  55. package/dist/libs/crud-sharding/index.js +55 -0
  56. package/dist/models/StandardColumns.d.ts +71 -0
  57. package/dist/models/StandardColumns.js +28 -0
  58. package/dist/service/SysAppService.js +2 -2
  59. package/dist/service/SysConfigService.js +1 -1
  60. package/dist/service/SysDictDataService.js +2 -2
  61. package/dist/service/SysMenuService.js +1 -1
  62. package/dist/service/UserAccountService.d.ts +1 -1
  63. package/dist/service/crudstd/CrudStdService.d.ts +0 -1
  64. package/dist/service/crudstd/CrudStdService.js +0 -27
  65. package/dist/service/curd/CrudProQuick.d.ts +134 -4
  66. package/dist/service/curd/CrudProQuick.js +155 -3
  67. package/dist/service/curd/CurdMixService.d.ts +2 -1
  68. package/dist/service/curd/CurdMixService.js +5 -1
  69. package/dist/service/curd/CurdProService.d.ts +44 -2
  70. package/dist/service/curd/CurdProService.js +53 -1
  71. package/dist/service/curd/README.md +1001 -0
  72. package/dist/service/curd/fixSoftDelete.d.ts +14 -0
  73. package/dist/service/curd/fixSoftDelete.js +29 -11
  74. package/dist/service/flow/FlowConfigService.js +1 -1
  75. package/dist/service/flow/FlowInstanceCrudService.js +1 -1
  76. package/package.json +3 -1
  77. package/src/controller/gateway/AsyncTaskController.ts +1 -1
  78. package/src/controller/manage/CrudStandardDesignApi.ts +16 -100
  79. package/src/index.ts +3 -0
  80. package/src/libs/crud-pro/CrudPro.ts +19 -1
  81. package/src/libs/crud-pro/README.md +809 -0
  82. package/src/libs/crud-pro/README_FUNC.md +193 -0
  83. package/src/libs/crud-pro/exceptions.ts +2 -0
  84. package/src/libs/crud-pro/interfaces.ts +38 -1
  85. package/src/libs/crud-pro/models/ExecuteContext.ts +6 -3
  86. package/src/libs/crud-pro/models/RequestModel.ts +108 -44
  87. package/src/libs/crud-pro/models/ResModel.ts +10 -4
  88. package/src/libs/crud-pro/models/ServiceHub.ts +2 -0
  89. package/src/libs/crud-pro/models/keys.ts +5 -0
  90. package/src/libs/crud-pro/services/CrudProDataTypeConvertService.ts +171 -0
  91. package/src/libs/crud-pro/services/CrudProExecuteSqlService.ts +24 -1
  92. package/src/libs/crud-pro/services/CrudProFieldValidateService.ts +53 -1
  93. package/src/libs/crud-pro/services/CrudProGenSqlService.ts +51 -7
  94. package/src/libs/crud-pro/services/CrudProOriginToExecuteSql.ts +159 -2
  95. package/src/libs/crud-pro/services/CrudProTableMetaService.ts +139 -1
  96. package/src/libs/crud-pro/services/CurdProServiceHub.ts +16 -1
  97. package/src/libs/crud-pro/utils/DateTimeUtils.ts +3 -0
  98. package/src/libs/crud-pro/utils/MixinUtils.ts +97 -1
  99. package/src/libs/crud-pro/utils/ValidateUtils.ts +1 -1
  100. package/src/libs/crud-sharding/ROUTING_LOGIC.md +944 -0
  101. package/src/libs/crud-sharding/ShardingConfig.ts +240 -0
  102. package/src/libs/crud-sharding/ShardingCountCache.ts +200 -0
  103. package/src/libs/crud-sharding/ShardingCrudPro.ts +856 -0
  104. package/src/libs/crud-sharding/ShardingMerger.ts +382 -0
  105. package/src/libs/crud-sharding/ShardingRouter.ts +512 -0
  106. package/src/libs/crud-sharding/ShardingTableCreator.ts +1007 -0
  107. package/src/libs/crud-sharding/ShardingUtils.ts +84 -0
  108. package/src/libs/crud-sharding/index.ts +64 -0
  109. package/src/models/StandardColumns.ts +76 -0
  110. package/src/service/FileCenterService.ts +1 -1
  111. package/src/service/SysAppService.ts +2 -2
  112. package/src/service/SysConfigService.ts +1 -1
  113. package/src/service/SysDictDataService.ts +2 -2
  114. package/src/service/SysMenuService.ts +2 -2
  115. package/src/service/WorkbenchService.ts +1 -1
  116. package/src/service/anyapi/AnyApiService.ts +1 -1
  117. package/src/service/asyncTask/AsyncTaskRunnerService.ts +1 -1
  118. package/src/service/crudstd/CrudStdService.ts +0 -32
  119. package/src/service/curd/CrudProQuick.ts +164 -5
  120. package/src/service/curd/CurdMixService.ts +7 -2
  121. package/src/service/curd/CurdProService.ts +62 -3
  122. package/src/service/curd/README.md +1001 -0
  123. package/src/service/curd/fixCfgModel.ts +1 -2
  124. package/src/service/curd/fixSoftDelete.ts +38 -16
  125. package/src/service/flow/FlowConfigService.ts +1 -1
  126. package/src/service/flow/FlowInstanceCrudService.ts +1 -1
@@ -1,13 +1,16 @@
1
1
  import { CrudProServiceBase } from './CrudProServiceBase';
2
- import { IExecuteUnsafeQueryCtx, ITableColumn, ITableMeta, ITableMetaQuery } from '../interfaces';
2
+ import { IExecuteUnsafeQueryCtx, ITableColumn, ITableInfo, ITableListResult, ITableMeta, ITableMetaQuery, ITableNamesQuery, ITableNamesOptions } from '../interfaces';
3
3
  import { SqlDbType } from '../models/keys';
4
4
  // import { pickAndConvertRowsByMix } from '../utils/sqlConvert/convertMix';
5
5
 
6
6
  class CrudProTableMetaCache {
7
7
  private cacheMap: Record<string, ITableMeta> = {};
8
+ private tableInfoCacheMap: Record<string, { tableInfos: ITableListResult; expiredTime: number }> = {};
9
+
8
10
  private getCacheKey(query: ITableMetaQuery) {
9
11
  return `${query.sqlDatabase}:::${query.sqlSchema}:::${query.sqlDbType}:::${query.sqlTable}`;
10
12
  }
13
+
11
14
  public getMeta(query: ITableMetaQuery) {
12
15
  const cacheKey = this.getCacheKey(query);
13
16
  const obj = this.cacheMap[cacheKey];
@@ -21,6 +24,21 @@ class CrudProTableMetaCache {
21
24
  const cacheKey = this.getCacheKey(query);
22
25
  this.cacheMap[cacheKey] = metaObj;
23
26
  }
27
+
28
+ public getTableInfos(cacheKey: string): ITableListResult | null {
29
+ const cached = this.tableInfoCacheMap[cacheKey];
30
+ if (cached && cached.expiredTime > Date.now()) {
31
+ return cached.tableInfos;
32
+ }
33
+ return null;
34
+ }
35
+
36
+ public setTableInfos(cacheKey: string, tableInfos: ITableListResult, cacheTime: number): void {
37
+ this.tableInfoCacheMap[cacheKey] = {
38
+ tableInfos,
39
+ expiredTime: Date.now() + cacheTime,
40
+ };
41
+ }
24
42
  }
25
43
 
26
44
  const metaCache = new CrudProTableMetaCache();
@@ -35,6 +53,126 @@ class CrudProTableMetaService extends CrudProServiceBase {
35
53
  return obj;
36
54
  }
37
55
 
56
+ // ============ 获取表和视图信息(带类型) ============
57
+
58
+
59
+ /**
60
+ * 获取数据库所有表和视图信息(包含类型)
61
+ *
62
+ * @param query 数据库查询参数
63
+ * @param options 缓存控制选项
64
+ * - skipCache: 跳过缓存,直接查询数据库
65
+ * - refreshCache: 查询后更新缓存
66
+ */
67
+ public async getAllTableInfos(
68
+ query: ITableNamesQuery,
69
+ options: ITableNamesOptions = {}
70
+ ): Promise<ITableListResult> {
71
+ const { skipCache = false, refreshCache = false } = options;
72
+
73
+ // 1. 尝试从缓存获取(使用独立的缓存key)
74
+ const cacheKey = this.getTableInfoCacheKey(query);
75
+ if (!skipCache) {
76
+ const cached = metaCache.getTableInfos(cacheKey);
77
+ if (cached) {
78
+ return cached;
79
+ }
80
+ }
81
+
82
+ // 2. 查询数据库
83
+ const result = await this.loadAllTableInfos(query);
84
+
85
+ // 3. 更新缓存
86
+ if (!skipCache || refreshCache) {
87
+ const { tableMetaCacheTime } = this.getContextCfg();
88
+ metaCache.setTableInfos(cacheKey, result, tableMetaCacheTime || 3600000);
89
+ }
90
+
91
+ return result;
92
+ }
93
+
94
+ private getTableInfoCacheKey(query: ITableNamesQuery): string {
95
+ return `tableInfo:::${query.sqlDatabase}:::${query.sqlSchema || 'public'}:::${query.sqlDbType}`;
96
+ }
97
+
98
+ private async loadAllTableInfos(query: ITableNamesQuery): Promise<ITableListResult> {
99
+ const { sqlDbType } = query;
100
+
101
+ if (sqlDbType === SqlDbType.mysql) {
102
+ return this.loadMySQLAllTableInfos(query);
103
+ } else if (sqlDbType === SqlDbType.postgres) {
104
+ return this.loadPostgreSQLAllTableInfos(query);
105
+ } else if (sqlDbType === SqlDbType.sqlserver) {
106
+ return this.loadSQLServerAllTableInfos(query);
107
+ }
108
+
109
+ throw new Error('暂不支持的数据库类型:' + sqlDbType);
110
+ }
111
+
112
+ private async loadMySQLAllTableInfos(query: ITableNamesQuery): Promise<ITableListResult> {
113
+ const dbUtil = { sqlDatabase: query.sqlDatabase, sqlDbType: query.sqlDbType } as IExecuteUnsafeQueryCtx;
114
+
115
+ // 获取物理表
116
+ const tableSql = `SHOW TABLES FROM ${query.sqlDatabase}`;
117
+ const tableRes = await this.executeUnsafeQuery(dbUtil, tableSql);
118
+ const tableNames: string[] = (tableRes.rows || []).map((row: any) => Object.values(row)[0] as string);
119
+
120
+ // 获取视图
121
+ const viewSql = `SHOW FULL TABLES FROM ${query.sqlDatabase} WHERE Table_type = 'VIEW'`;
122
+ const viewRes = await this.executeUnsafeQuery(dbUtil, viewSql);
123
+ const viewNames: string[] = (viewRes.rows || []).map((row: any) => Object.values(row)[0] as string);
124
+
125
+ const tables: ITableInfo[] = [
126
+ ...tableNames.map(name => ({ name, tableType: 'table' })),
127
+ ...viewNames.map(name => ({ name, tableType: 'view' })),
128
+ ];
129
+
130
+ return { tables, tableNames, viewNames };
131
+ }
132
+
133
+ private async loadPostgreSQLAllTableInfos(query: ITableNamesQuery): Promise<ITableListResult> {
134
+ const schema = query.sqlSchema || 'public';
135
+ const dbUtil = { sqlDatabase: query.sqlDatabase, sqlDbType: query.sqlDbType } as IExecuteUnsafeQueryCtx;
136
+
137
+ // 获取物理表
138
+ const tableSql = `SELECT tablename FROM pg_tables WHERE schemaname = '${schema}' ORDER BY tablename`;
139
+ const tableRes = await this.executeUnsafeQuery(dbUtil, tableSql);
140
+ const tableNames: string[] = (tableRes.rows || []).map((row: any) => row.tablename);
141
+
142
+ // 获取视图
143
+ const viewSql = `SELECT viewname FROM pg_views WHERE schemaname = '${schema}' ORDER BY viewname`;
144
+ const viewRes = await this.executeUnsafeQuery(dbUtil, viewSql);
145
+ const viewNames: string[] = (viewRes.rows || []).map((row: any) => row.viewname);
146
+
147
+ const tables: ITableInfo[] = [
148
+ ...tableNames.map(name => ({ name, tableType: 'table' })),
149
+ ...viewNames.map(name => ({ name, tableType: 'view' })),
150
+ ];
151
+
152
+ return { tables, tableNames, viewNames };
153
+ }
154
+
155
+ private async loadSQLServerAllTableInfos(query: ITableNamesQuery): Promise<ITableListResult> {
156
+ const dbUtil = { sqlDatabase: query.sqlDatabase, sqlDbType: query.sqlDbType } as IExecuteUnsafeQueryCtx;
157
+
158
+ // 获取物理表
159
+ const tableSql = `SELECT name FROM sys.tables`;
160
+ const tableRes = await this.executeUnsafeQuery(dbUtil, tableSql);
161
+ const tableNames: string[] = (tableRes.rows || []).map((row: any) => row.name);
162
+
163
+ // 获取视图
164
+ const viewSql = `SELECT name FROM sys.views`;
165
+ const viewRes = await this.executeUnsafeQuery(dbUtil, viewSql);
166
+ const viewNames: string[] = (viewRes.rows || []).map((row: any) => row.name);
167
+
168
+ const tables: ITableInfo[] = [
169
+ ...tableNames.map(name => ({ name, tableType: 'table' })),
170
+ ...viewNames.map(name => ({ name, tableType: 'view' })),
171
+ ];
172
+
173
+ return { tables, tableNames, viewNames };
174
+ }
175
+
38
176
  private async loadTableMeta(query: ITableMetaQuery): Promise<ITableMeta> {
39
177
  const { tableMetaCacheTime } = this.getContextCfg();
40
178
 
@@ -1,4 +1,4 @@
1
- import { IFuncCfgModel, IRequestCfgModel, ISqlCfgModel, ITableMeta, ITableMetaQuery } from '../interfaces';
1
+ import { IFuncCfgModel, IRequestCfgModel, ISqlCfgModel, ITableListResult, ITableMeta, ITableMetaQuery, ITableNamesOptions, ITableNamesQuery } from '../interfaces';
2
2
  import { RequestModel } from '../models/RequestModel';
3
3
  import { CrudProFieldValidateService } from './CrudProFieldValidateService';
4
4
  import { CrudProFieldUpdateService } from './CrudProFieldUpdateService';
@@ -14,6 +14,7 @@ import { FuncContext } from '../models/FuncContext';
14
14
  import { CrudProExecuteFuncService } from './CrudProExecuteFuncService';
15
15
  import { CrudProTableMetaService } from './CrudProTableMetaService';
16
16
  import { CrudProDataFilterService } from './CrudProDataFilterService';
17
+ import { CrudProDataTypeConvertService } from './CrudProDataTypeConvertService';
17
18
 
18
19
  class CurdProServiceHub implements ICurdProServiceHub {
19
20
  private readonly executeContext: ExecuteContext;
@@ -27,6 +28,7 @@ class CurdProServiceHub implements ICurdProServiceHub {
27
28
  private readonly executeFuncService: CrudProExecuteFuncService;
28
29
  private readonly tableMetaService: CrudProTableMetaService;
29
30
  private readonly dataFilterService: CrudProDataFilterService;
31
+ private readonly dataTypeConvertService: CrudProDataTypeConvertService;
30
32
 
31
33
  constructor(executeContext: ExecuteContext) {
32
34
  this.executeContext = executeContext;
@@ -39,6 +41,7 @@ class CurdProServiceHub implements ICurdProServiceHub {
39
41
  this.executeFuncService = new CrudProExecuteFuncService(this);
40
42
  this.tableMetaService = new CrudProTableMetaService(this);
41
43
  this.dataFilterService = new CrudProDataFilterService(this);
44
+ this.dataTypeConvertService = new CrudProDataTypeConvertService(this);
42
45
  }
43
46
 
44
47
  getExecuteContext(): ExecuteContext {
@@ -57,6 +60,10 @@ class CurdProServiceHub implements ICurdProServiceHub {
57
60
  return this.fieldValidateService.validateByCfg(cfgModel, reqModel);
58
61
  }
59
62
 
63
+ validateDataType(cfgModel: RequestCfgModel, reqModel: RequestModel) {
64
+ return this.fieldValidateService.validateDataType(cfgModel, reqModel);
65
+ }
66
+
60
67
  async validateByAuthCfg(cfgModel: RequestCfgModel, reqModel: RequestModel): Promise<any> {
61
68
  const contextFunc = this.executeContext.contextFunc;
62
69
  if (contextFunc && contextFunc.validateByAuthCfg) {
@@ -91,9 +98,17 @@ class CurdProServiceHub implements ICurdProServiceHub {
91
98
  return await this.tableMetaService.getTableMeta(query);
92
99
  }
93
100
 
101
+ async getAllTableInfos(query: ITableNamesQuery, options?: ITableNamesOptions): Promise<ITableListResult> {
102
+ return await this.tableMetaService.getAllTableInfos(query, options);
103
+ }
104
+
94
105
  async filterDataByTableMeta(data: Record<string, any>, sqlCfgModel: ISqlCfgModel | SqlCfgModel): Promise<Record<string, any>> {
95
106
  return await this.dataFilterService.filterDataByTableMeta(data, sqlCfgModel);
96
107
  }
108
+
109
+ async convertDataTypeByTableMeta(reqModel: RequestModel, cfgModel: RequestCfgModel): Promise<void> {
110
+ return await this.dataTypeConvertService.convertDataTypeByTableMeta(reqModel, cfgModel);
111
+ }
97
112
  }
98
113
 
99
114
  export { CurdProServiceHub };
@@ -5,6 +5,9 @@ const DateTimeUtils = {
5
5
  getCurrentTimeStampMs(): number {
6
6
  return Date.now();
7
7
  },
8
+ getCurrentTimeString(): string {
9
+ return moment().format('YYYY-MM-DD HH:mm:ss');
10
+ },
8
11
  // 以秒为单位的时间戳
9
12
  getCurrentTimeStampSecond(): number {
10
13
  return Math.floor(Date.now() / 1000);
@@ -3,6 +3,85 @@ import { CommonException, Exceptions } from '../exceptions';
3
3
  // 至少需要2个字符
4
4
  const FIELD_NAME_REG_EXP = /^[a-zA-Z][0-9a-zA-Z_]+$/;
5
5
 
6
+ // ===================== 雪花ID =====================
7
+ let snowflakeSeq = 0;
8
+ let snowflakeLastTs = -1;
9
+
10
+ /**
11
+ * 生成雪花ID(64位整数,JS 中以 string 返回)
12
+ * 结构:1位符号 + 41位时间戳(ms) + 10位机器ID + 12位序列号
13
+ * - 时间戳:相对于 2024-01-01 00:00:00 的毫秒偏移,可用约 69 年
14
+ * - 机器ID:0-1023,优先取参数 > 环境变量 SNOWFLAKE_MACHINE_ID > process.pid 低10位
15
+ * - 序列号:0-4095,同一毫秒内自增
16
+ *
17
+ * @param machineId 机器ID(0-1023),不传则依次从环境变量 SNOWFLAKE_MACHINE_ID、process.pid 获取
18
+ * @returns 雪花ID字符串
19
+ */
20
+ function generateSnowflakeId(machineId?: number): string {
21
+ const EPOCH = 1704067200000; // 2024-01-01 00:00:00 UTC
22
+
23
+ let mid = machineId;
24
+ if (mid === undefined || mid === null) {
25
+ // 优先从环境变量获取,适配多实例部署场景
26
+ const envMid = typeof process !== 'undefined' && process.env && process.env.SNOWFLAKE_MACHINE_ID
27
+ ? parseInt(process.env.SNOWFLAKE_MACHINE_ID, 10)
28
+ : NaN;
29
+ mid = !isNaN(envMid) ? envMid : (typeof process !== 'undefined' && process.pid ? process.pid & 0x3ff : 0);
30
+ }
31
+ mid = mid & 0x3ff; // 确保在 0-1023 范围
32
+
33
+ let now = Date.now();
34
+ let ts = now - EPOCH;
35
+
36
+ if (ts === snowflakeLastTs) {
37
+ snowflakeSeq = (snowflakeSeq + 1) & 0xfff; // 0-4095 循环
38
+ if (snowflakeSeq === 0) {
39
+ // 本毫秒序列号耗尽,等待下一毫秒
40
+ while (now <= Date.now()) {
41
+ now = Date.now();
42
+ }
43
+ ts = now - EPOCH;
44
+ }
45
+ } else {
46
+ snowflakeSeq = 0;
47
+ }
48
+
49
+ snowflakeLastTs = ts;
50
+
51
+ // 雪花ID超过JS安全整数范围(2^53),不能用Number位运算,采用字符串拼接
52
+ const tsPart = ts * 4194304; // ts << 22,等价于 ts * 2^22
53
+ const midPart = mid * 4096; // mid << 12,等价于 mid * 2^12
54
+ return '' + (tsPart + midPart + snowflakeSeq);
55
+ }
56
+
57
+
58
+
59
+ /**
60
+ * 生成 UUID v4 字符串(纯随机,无外部依赖)
61
+ * 格式:xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,其中 y 为 8/9/a/b 之一
62
+ * @returns 符合 RFC 4122 v4 规范的 UUID 字符串
63
+ */
64
+ function uuid(): string {
65
+ // crypto.getRandomValues 在 Node.js >= 11 和现代浏览器中可用
66
+ if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
67
+ const bytes = new Uint8Array(16);
68
+ crypto.getRandomValues(bytes);
69
+ // 版本位:第6字节高4位设为 0100 (v4)
70
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
71
+ // 变体位:第8字节高2位设为 10
72
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
73
+ const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
74
+ return hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20);
75
+ }
76
+ // 降级方案:Math.random
77
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
78
+ const r = Math.random() * 16 | 0;
79
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
80
+ return v.toString(16);
81
+ });
82
+ }
83
+
84
+
6
85
  const MixinUtils = {
7
86
  isNil(obj: any): boolean {
8
87
  return typeof obj === 'undefined' || obj === null;
@@ -284,7 +363,24 @@ const MixinUtils = {
284
363
  },
285
364
  sleepMs(ms: number): Promise<any> {
286
365
  return new Promise(resolve => setTimeout(resolve, ms));
287
- }
366
+ },
367
+
368
+ /**
369
+ * 生成 UUID v4 字符串(纯随机,无外部依赖)
370
+ * 格式:xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,其中 y 为 8/9/a/b 之一
371
+ * @returns 符合 RFC 4122 v4 规范的 UUID 字符串
372
+ */
373
+ uuid: uuid,
374
+
375
+ /**
376
+ * 生成雪花ID(64位整数,以字符串返回)
377
+ * 结构:1位符号 + 41位时间戳(ms) + 10位机器ID + 12位序列号
378
+ * 同一毫秒内可生成 4096 个不重复ID,单机每秒可生成约 400 万个
379
+ *
380
+ * @param machineId 机器ID(0-1023),不传则依次从环境变量 SNOWFLAKE_MACHINE_ID、process.pid 获取
381
+ * @returns 雪花ID字符串
382
+ */
383
+ generateSnowflakeId: generateSnowflakeId,
288
384
  };
289
385
 
290
386
  export { MixinUtils };
@@ -50,7 +50,7 @@ const validatorUtils = {
50
50
  },
51
51
 
52
52
  isMomentValid(itemCfg: string, itemValue: any): boolean {
53
- const cfgPart = itemCfg.substring(KeysOfValidators.ENUM.length).trim();
53
+ const cfgPart = itemCfg.substring(KeysOfValidators.MOMENT.length).trim();
54
54
  return moment(itemValue, cfgPart, true).isValid();
55
55
  },
56
56