@nest-omni/core 4.1.3-11 → 4.1.3-12

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 (175) hide show
  1. package/audit/audit.module.js +17 -0
  2. package/audit/controllers/audit.controller.d.ts +64 -0
  3. package/audit/controllers/audit.controller.js +50 -0
  4. package/audit/decorators/audit-action.decorator.d.ts +74 -0
  5. package/audit/decorators/audit-action.decorator.js +42 -0
  6. package/audit/decorators/entity-audit.decorator.d.ts +10 -1
  7. package/audit/decorators/entity-audit.decorator.js +34 -16
  8. package/audit/decorators/index.d.ts +1 -0
  9. package/audit/decorators/index.js +1 -0
  10. package/audit/entities/audit-action-summary.entity.d.ts +23 -0
  11. package/audit/entities/audit-action-summary.entity.js +101 -0
  12. package/audit/entities/entity-audit-log.entity.d.ts +3 -0
  13. package/audit/entities/entity-audit-log.entity.js +25 -2
  14. package/audit/entities/entity-transaction.entity.d.ts +3 -4
  15. package/audit/entities/entity-transaction.entity.js +10 -3
  16. package/audit/entities/index.d.ts +1 -0
  17. package/audit/entities/index.js +1 -0
  18. package/audit/entities/manual-operation-log.entity.js +8 -1
  19. package/audit/enums/audit.enums.d.ts +1 -10
  20. package/audit/enums/audit.enums.js +7 -17
  21. package/audit/index.d.ts +2 -1
  22. package/audit/index.js +5 -1
  23. package/audit/interceptors/audit-action.interceptor.d.ts +38 -0
  24. package/audit/interceptors/audit-action.interceptor.js +215 -0
  25. package/audit/interceptors/index.d.ts +1 -0
  26. package/audit/interceptors/index.js +1 -0
  27. package/audit/interfaces/audit.interfaces.d.ts +10 -5
  28. package/audit/services/audit-action.service.d.ts +141 -0
  29. package/audit/services/audit-action.service.js +244 -0
  30. package/audit/services/audit-context.service.d.ts +82 -0
  31. package/audit/services/audit-context.service.js +170 -0
  32. package/audit/services/entity-audit.service.d.ts +104 -3
  33. package/audit/services/entity-audit.service.js +306 -9
  34. package/audit/services/index.d.ts +1 -0
  35. package/audit/services/index.js +1 -0
  36. package/audit/services/manual-audit-log.service.d.ts +24 -23
  37. package/audit/services/manual-audit-log.service.js +32 -53
  38. package/audit/services/operation-description.service.d.ts +13 -3
  39. package/audit/services/operation-description.service.js +161 -24
  40. package/audit/services/transaction-audit.service.js +3 -3
  41. package/audit/subscribers/entity-audit.subscriber.d.ts +4 -0
  42. package/audit/subscribers/entity-audit.subscriber.js +47 -0
  43. package/file-upload/controllers/file-access.controller.d.ts +23 -0
  44. package/file-upload/controllers/file-access.controller.js +128 -0
  45. package/file-upload/decorators/csv-data.decorator.d.ts +44 -0
  46. package/file-upload/decorators/csv-data.decorator.js +131 -0
  47. package/file-upload/decorators/excel-data.decorator.d.ts +44 -0
  48. package/file-upload/decorators/excel-data.decorator.js +125 -0
  49. package/file-upload/decorators/file-upload.decorator.d.ts +83 -0
  50. package/file-upload/decorators/file-upload.decorator.js +172 -0
  51. package/file-upload/decorators/index.d.ts +4 -0
  52. package/file-upload/decorators/index.js +20 -0
  53. package/file-upload/decorators/process.decorator.d.ts +40 -0
  54. package/file-upload/decorators/process.decorator.js +52 -0
  55. package/file-upload/dto/create-file.dto.d.ts +24 -0
  56. package/file-upload/dto/create-file.dto.js +112 -0
  57. package/file-upload/dto/find-files.dto.d.ts +15 -0
  58. package/file-upload/dto/find-files.dto.js +76 -0
  59. package/file-upload/dto/index.d.ts +4 -0
  60. package/file-upload/dto/index.js +20 -0
  61. package/file-upload/dto/pagination.dto.d.ts +7 -0
  62. package/file-upload/dto/pagination.dto.js +39 -0
  63. package/file-upload/dto/update-file.dto.d.ts +16 -0
  64. package/file-upload/dto/update-file.dto.js +71 -0
  65. package/file-upload/entities/file-metadata.entity.d.ts +22 -0
  66. package/file-upload/entities/file-metadata.entity.js +84 -0
  67. package/file-upload/entities/file.entity.d.ts +129 -0
  68. package/file-upload/entities/file.entity.js +384 -0
  69. package/file-upload/entities/index.d.ts +2 -0
  70. package/file-upload/entities/index.js +18 -0
  71. package/file-upload/enums/file-type.enum.d.ts +72 -0
  72. package/file-upload/enums/file-type.enum.js +212 -0
  73. package/file-upload/exceptions/file-upload.exception.d.ts +57 -0
  74. package/file-upload/exceptions/file-upload.exception.js +120 -0
  75. package/file-upload/exceptions/index.d.ts +1 -0
  76. package/file-upload/exceptions/index.js +17 -0
  77. package/file-upload/file-upload.module.d.ts +89 -0
  78. package/file-upload/file-upload.module.js +264 -0
  79. package/file-upload/index.d.ts +26 -0
  80. package/file-upload/index.js +59 -0
  81. package/file-upload/interceptors/file-upload.interceptor.d.ts +48 -0
  82. package/file-upload/interceptors/file-upload.interceptor.js +434 -0
  83. package/file-upload/interceptors/index.d.ts +1 -0
  84. package/file-upload/interceptors/index.js +17 -0
  85. package/file-upload/interfaces/custom-file-type.interface.d.ts +72 -0
  86. package/file-upload/interfaces/custom-file-type.interface.js +2 -0
  87. package/file-upload/interfaces/file-buffer.interface.d.ts +72 -0
  88. package/file-upload/interfaces/file-buffer.interface.js +2 -0
  89. package/file-upload/interfaces/file-entity.interface.d.ts +142 -0
  90. package/file-upload/interfaces/file-entity.interface.js +28 -0
  91. package/file-upload/interfaces/file-metadata.interface.d.ts +21 -0
  92. package/file-upload/interfaces/file-metadata.interface.js +2 -0
  93. package/file-upload/interfaces/file-upload-options.interface.d.ts +117 -0
  94. package/file-upload/interfaces/file-upload-options.interface.js +2 -0
  95. package/file-upload/interfaces/index.d.ts +7 -0
  96. package/file-upload/interfaces/index.js +24 -0
  97. package/file-upload/interfaces/storage-provider.interface.d.ts +239 -0
  98. package/file-upload/interfaces/storage-provider.interface.js +2 -0
  99. package/file-upload/interfaces/upload-options.interface.d.ts +19 -0
  100. package/file-upload/interfaces/upload-options.interface.js +2 -0
  101. package/file-upload/providers/index.d.ts +2 -0
  102. package/file-upload/providers/index.js +18 -0
  103. package/file-upload/providers/local-storage.provider.d.ts +98 -0
  104. package/file-upload/providers/local-storage.provider.js +484 -0
  105. package/file-upload/providers/s3-storage.provider.d.ts +87 -0
  106. package/file-upload/providers/s3-storage.provider.js +455 -0
  107. package/file-upload/services/file-signature-validator.service.d.ts +118 -0
  108. package/file-upload/services/file-signature-validator.service.js +376 -0
  109. package/file-upload/services/file.service.d.ts +190 -0
  110. package/file-upload/services/file.service.js +609 -0
  111. package/file-upload/services/index.d.ts +4 -0
  112. package/file-upload/services/index.js +20 -0
  113. package/file-upload/services/malicious-file-detector.service.d.ts +274 -0
  114. package/file-upload/services/malicious-file-detector.service.js +1035 -0
  115. package/file-upload/services/mime-registry.service.d.ts +47 -0
  116. package/file-upload/services/mime-registry.service.js +167 -0
  117. package/file-upload/utils/checksum.util.d.ts +28 -0
  118. package/file-upload/utils/checksum.util.js +65 -0
  119. package/file-upload/utils/dynamic-import.util.d.ts +50 -0
  120. package/file-upload/utils/dynamic-import.util.js +144 -0
  121. package/file-upload/utils/filename.util.d.ts +59 -0
  122. package/file-upload/utils/filename.util.js +184 -0
  123. package/file-upload/utils/filepath.util.d.ts +70 -0
  124. package/file-upload/utils/filepath.util.js +152 -0
  125. package/file-upload/utils/index.d.ts +4 -0
  126. package/file-upload/utils/index.js +20 -0
  127. package/index.d.ts +3 -1
  128. package/index.js +4 -1
  129. package/package.json +4 -5
  130. package/setup/bootstrap.setup.d.ts +1 -0
  131. package/setup/bootstrap.setup.js +1 -0
  132. package/shared/index.d.ts +1 -1
  133. package/shared/index.js +1 -1
  134. package/shared/{serviceRegistryModule.js → service-registry.module.js} +0 -12
  135. package/shared/services/index.d.ts +0 -1
  136. package/shared/services/index.js +0 -1
  137. package/transaction/__tests__/mocks.d.ts +9 -0
  138. package/transaction/__tests__/mocks.js +33 -0
  139. package/transaction/base-service-transaction.d.ts +99 -0
  140. package/transaction/base-service-transaction.js +286 -0
  141. package/transaction/cls-compatibility.service.d.ts +55 -0
  142. package/transaction/cls-compatibility.service.js +127 -0
  143. package/transaction/data-source-registry.d.ts +91 -0
  144. package/transaction/data-source-registry.js +349 -0
  145. package/transaction/database-adapter.d.ts +44 -0
  146. package/transaction/database-adapter.js +240 -0
  147. package/transaction/decorators/entity-datasource.decorator.d.ts +62 -0
  148. package/transaction/decorators/entity-datasource.decorator.js +105 -0
  149. package/transaction/index.d.ts +14 -0
  150. package/transaction/index.js +57 -0
  151. package/transaction/logging-transactional.interceptor.d.ts +18 -0
  152. package/transaction/logging-transactional.interceptor.js +163 -0
  153. package/transaction/transaction-context.service.d.ts +137 -0
  154. package/transaction/transaction-context.service.js +411 -0
  155. package/transaction/transaction-manager.d.ts +230 -0
  156. package/transaction/transaction-manager.js +1001 -0
  157. package/transaction/transaction-synchronization.d.ts +171 -0
  158. package/transaction/transaction-synchronization.js +380 -0
  159. package/transaction/transaction.errors.d.ts +91 -0
  160. package/transaction/transaction.errors.js +206 -0
  161. package/transaction/transaction.module.d.ts +30 -0
  162. package/transaction/transaction.module.js +98 -0
  163. package/transaction/transactional.decorator.d.ts +82 -0
  164. package/transaction/transactional.decorator.js +319 -0
  165. package/transaction/typeorm-module-wrapper.d.ts +96 -0
  166. package/transaction/typeorm-module-wrapper.js +197 -0
  167. package/validators/file-mimetype.validator.d.ts +0 -2
  168. package/validators/file-mimetype.validator.js +4 -6
  169. package/validators/is-exists.validator.d.ts +2 -5
  170. package/validators/is-exists.validator.js +4 -6
  171. package/validators/is-unique.validator.d.ts +2 -5
  172. package/validators/is-unique.validator.js +6 -11
  173. package/shared/services/validator.service.d.ts +0 -3
  174. package/shared/services/validator.service.js +0 -20
  175. /package/shared/{serviceRegistryModule.d.ts → service-registry.module.d.ts} +0 -0
@@ -0,0 +1,244 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.AuditActionService = void 0;
22
+ const common_1 = require("@nestjs/common");
23
+ const audit_context_service_1 = require("./audit-context.service");
24
+ const entity_audit_service_1 = require("./entity-audit.service");
25
+ const enums_1 = require("../enums");
26
+ /**
27
+ * 审计动作服务
28
+ * 提供声明式的审计动作管理,自动关联同一业务操作的所有实体变化
29
+ */
30
+ let AuditActionService = class AuditActionService {
31
+ constructor(contextService, auditService) {
32
+ this.contextService = contextService;
33
+ this.auditService = auditService;
34
+ }
35
+ /**
36
+ * 在审计动作上下文中执行操作
37
+ * 自动关联该动作内的所有实体变化
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * const result = await auditActionService.executeAction(
42
+ * {
43
+ * actionName: 'createOrder',
44
+ * operationTemplateKey: 'order.create',
45
+ * descriptionParams: {
46
+ * productCount: orderItems.length,
47
+ * receiver: order.receiverName,
48
+ * totalAmount: order.totalAmount,
49
+ * address: order.shippingAddress,
50
+ * },
51
+ * },
52
+ * async () => {
53
+ * // 1. 创建订单
54
+ * const order = await this.orderRepository.save(newOrder);
55
+ *
56
+ * // 2. 创建订单项
57
+ * await this.orderItemRepository.save(orderItems);
58
+ *
59
+ * // 3. 扣减库存
60
+ * await this.inventoryService.deduct(orderItems);
61
+ *
62
+ * // 4. 创建物流信息
63
+ * await this.shippingService.create(order.id);
64
+ *
65
+ * return order;
66
+ * }
67
+ * );
68
+ *
69
+ * // 结果中包含所有实体变化:
70
+ * // result.entityChanges = [
71
+ * // { entityType: 'Order', entityId: '1', operation: 'CREATE', sequence: 1 },
72
+ * // { entityType: 'OrderItem', entityId: '1', operation: 'CREATE', sequence: 2 },
73
+ * // { entityType: 'OrderItem', entityId: '2', operation: 'CREATE', sequence: 3 },
74
+ * // { entityType: 'Inventory', entityId: '1', operation: 'UPDATE', sequence: 4 },
75
+ * // { entityType: 'Shipping', entityId: '1', operation: 'CREATE', sequence: 5 },
76
+ * // ]
77
+ * ```
78
+ */
79
+ executeAction(options, operation) {
80
+ return __awaiter(this, void 0, void 0, function* () {
81
+ const actionId = this.contextService.generateActionId();
82
+ const startTime = new Date();
83
+ // 创建审计动作上下文
84
+ const actionContext = {
85
+ actionId,
86
+ actionName: options.actionName,
87
+ operationTemplateKey: options.operationTemplateKey,
88
+ descriptionParams: options.descriptionParams,
89
+ startTime,
90
+ entityChanges: [],
91
+ detailedChanges: [],
92
+ };
93
+ // 设置到 CLS
94
+ this.contextService.setActionContext(actionContext);
95
+ let success = false;
96
+ let error;
97
+ let result;
98
+ try {
99
+ // 执行业务操作
100
+ result = yield operation();
101
+ success = true;
102
+ // 记录审计动作汇总日志(可选)
103
+ yield this.recordActionSummary(actionContext, options);
104
+ return {
105
+ actionId,
106
+ actionName: options.actionName,
107
+ entityChanges: actionContext.entityChanges,
108
+ duration: Date.now() - startTime.getTime(),
109
+ success: true,
110
+ };
111
+ }
112
+ catch (err) {
113
+ error = err;
114
+ success = false;
115
+ // 记录失败的审计动作
116
+ yield this.recordActionSummary(actionContext, options, error);
117
+ throw err;
118
+ }
119
+ finally {
120
+ // 清除审计动作上下文
121
+ this.contextService.clearActionContext();
122
+ }
123
+ });
124
+ }
125
+ /**
126
+ * 记录审计动作汇总日志
127
+ */
128
+ recordActionSummary(actionContext, options, error) {
129
+ return __awaiter(this, void 0, void 0, function* () {
130
+ try {
131
+ const context = yield this.contextService.getCurrentContext();
132
+ // 使用 logEntityChangeWithTemplate 记录汇总信息
133
+ yield this.auditService.logEntityChangeWithTemplate({
134
+ entityType: 'AuditAction',
135
+ entityId: actionContext.actionId,
136
+ operation: error ? enums_1.AuditOperation.DELETE : enums_1.AuditOperation.CREATE, // 失败用 DELETE 表示回滚
137
+ oldValue: {},
138
+ newValue: {
139
+ actionName: actionContext.actionName,
140
+ entityChangesCount: actionContext.entityChanges.length,
141
+ duration: Date.now() - actionContext.startTime.getTime(),
142
+ success: !error,
143
+ error: error === null || error === void 0 ? void 0 : error.message,
144
+ },
145
+ operationTemplateKey: options.operationTemplateKey,
146
+ descriptionParams: options.descriptionParams,
147
+ metadata: Object.assign(Object.assign({}, options.metadata), { auditActionId: actionContext.actionId, entityChanges: actionContext.entityChanges }),
148
+ });
149
+ }
150
+ catch (err) {
151
+ console.error('Failed to record audit action summary:', err);
152
+ }
153
+ });
154
+ }
155
+ /**
156
+ * 获取审计动作的所有实体变化
157
+ */
158
+ getActionAuditLogs(actionId) {
159
+ return __awaiter(this, void 0, void 0, function* () {
160
+ const logs = yield this.auditService['auditLogRepository'].find({
161
+ where: { auditActionId: actionId },
162
+ order: { sequenceInAction: 'ASC', createdAt: 'ASC' },
163
+ });
164
+ return {
165
+ actionId,
166
+ logs,
167
+ summary: {
168
+ totalChanges: logs.length,
169
+ operations: this.groupByOperation(logs),
170
+ entities: this.groupByEntity(logs),
171
+ },
172
+ };
173
+ });
174
+ }
175
+ /**
176
+ * 获取请求内的所有审计动作
177
+ */
178
+ getRequestActions(requestId) {
179
+ return __awaiter(this, void 0, void 0, function* () {
180
+ const logs = yield this.auditService['auditLogRepository'].find({
181
+ where: { requestId },
182
+ order: { createdAt: 'ASC' },
183
+ });
184
+ // 按 auditActionId 分组
185
+ const actionMap = new Map();
186
+ const noActionLogs = [];
187
+ logs.forEach(log => {
188
+ if (log.auditActionId) {
189
+ if (!actionMap.has(log.auditActionId)) {
190
+ actionMap.set(log.auditActionId, []);
191
+ }
192
+ actionMap.get(log.auditActionId).push(log);
193
+ }
194
+ else {
195
+ noActionLogs.push(log);
196
+ }
197
+ });
198
+ const actions = Array.from(actionMap.entries()).map(([actionId, logs]) => {
199
+ var _a;
200
+ return ({
201
+ actionId,
202
+ actionName: ((_a = logs[0]) === null || _a === void 0 ? void 0 : _a.auditActionName) || 'Unknown',
203
+ entityChanges: logs.map(log => ({
204
+ entityType: log.entityType,
205
+ entityId: log.entityId,
206
+ operation: log.operation,
207
+ sequence: log.sequenceInAction,
208
+ timestamp: log.createdAt,
209
+ })),
210
+ logs,
211
+ });
212
+ });
213
+ return {
214
+ requestId,
215
+ actions,
216
+ noActionLogs, // 未关联到任何动作的日志
217
+ summary: {
218
+ totalActions: actions.length,
219
+ totalChanges: logs.length,
220
+ },
221
+ };
222
+ });
223
+ }
224
+ groupByOperation(logs) {
225
+ const result = new Map();
226
+ logs.forEach(log => {
227
+ result.set(log.operation, (result.get(log.operation) || 0) + 1);
228
+ });
229
+ return Object.fromEntries(result);
230
+ }
231
+ groupByEntity(logs) {
232
+ const result = new Map();
233
+ logs.forEach(log => {
234
+ result.set(log.entityType, (result.get(log.entityType) || 0) + 1);
235
+ });
236
+ return Object.fromEntries(result);
237
+ }
238
+ };
239
+ exports.AuditActionService = AuditActionService;
240
+ exports.AuditActionService = AuditActionService = __decorate([
241
+ (0, common_1.Injectable)(),
242
+ __metadata("design:paramtypes", [audit_context_service_1.AuditContextService,
243
+ entity_audit_service_1.EntityAuditService])
244
+ ], AuditActionService);
@@ -1,5 +1,55 @@
1
1
  import { ClsService } from 'nestjs-cls';
2
2
  import { AuditContext } from '../interfaces';
3
+ import { AuditOperation } from '../enums';
4
+ /**
5
+ * 实体变更详情
6
+ */
7
+ export interface EntityChangeDetail {
8
+ entityType: string;
9
+ entityId: string;
10
+ operation: AuditOperation;
11
+ oldValue: Record<string, any>;
12
+ newValue: Record<string, any>;
13
+ changedFields: string[];
14
+ sequence: number;
15
+ metadata?: Record<string, any>;
16
+ }
17
+ /**
18
+ * 审计参数上下文
19
+ */
20
+ export interface AuditParamsContext {
21
+ req: any;
22
+ result?: any;
23
+ error?: Error;
24
+ entityChanges: EntityChangeDetail[];
25
+ findEntity(entityType: string, operation?: AuditOperation): EntityChangeDetail | null;
26
+ findEntities(entityType: string, operation?: AuditOperation): EntityChangeDetail[];
27
+ countEntities(entityType: string, operation?: AuditOperation): number;
28
+ extractParams(mapping: Record<string, any>): Record<string, any>;
29
+ extractByPath(path: string): any;
30
+ extractByConfig(config: any): any;
31
+ }
32
+ /**
33
+ * 审计动作上下文
34
+ */
35
+ export interface AuditActionContext {
36
+ actionId: string;
37
+ actionName: string;
38
+ operationTemplateKey?: string;
39
+ descriptionParams?: Record<string, any>;
40
+ paramsBuilder?: (context: AuditParamsContext) => Record<string, any>;
41
+ startTime: Date;
42
+ entityChanges: Array<{
43
+ entityType: string;
44
+ entityId: string;
45
+ operation: string;
46
+ sequence: number;
47
+ }>;
48
+ detailedChanges: EntityChangeDetail[];
49
+ req?: any;
50
+ result?: any;
51
+ error?: Error;
52
+ }
3
53
  /**
4
54
  * 审计上下文服务
5
55
  */
@@ -22,4 +72,36 @@ export declare class AuditContextService {
22
72
  * 获取默认上下文
23
73
  */
24
74
  private getDefaultContext;
75
+ /**
76
+ * 获取当前审计动作上下文
77
+ */
78
+ getCurrentActionContext(): AuditActionContext | null;
79
+ /**
80
+ * 设置审计动作上下文
81
+ */
82
+ setActionContext(context: AuditActionContext): void;
83
+ /**
84
+ * 清除审计动作上下文
85
+ */
86
+ clearActionContext(): void;
87
+ /**
88
+ * 记录实体变化到当前动作(简单版本)
89
+ */
90
+ recordEntityChangeInAction(entityType: string, entityId: string, operation: string): void;
91
+ /**
92
+ * 记录详细的实体变化
93
+ */
94
+ recordDetailedEntityChange(entityType: string, entityId: string, operation: AuditOperation, oldValue: Record<string, any>, newValue: Record<string, any>, changedFields: string[], metadata?: Record<string, any>): void;
95
+ /**
96
+ * 获取当前动作内的序号
97
+ */
98
+ getSequenceInAction(): number;
99
+ /**
100
+ * 生成审计动作ID
101
+ */
102
+ generateActionId(): string;
103
+ /**
104
+ * 构建审计参数上下文
105
+ */
106
+ buildParamsContext(): AuditParamsContext | null;
25
107
  }
@@ -21,6 +21,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.AuditContextService = void 0;
22
22
  const common_1 = require("@nestjs/common");
23
23
  const nestjs_cls_1 = require("nestjs-cls");
24
+ const crypto_1 = require("crypto");
24
25
  /**
25
26
  * 审计上下文服务
26
27
  */
@@ -62,6 +63,175 @@ let AuditContextService = class AuditContextService {
62
63
  timestamp: new Date(),
63
64
  };
64
65
  }
66
+ // ========== 审计动作上下文管理 ==========
67
+ /**
68
+ * 获取当前审计动作上下文
69
+ */
70
+ getCurrentActionContext() {
71
+ return this.cls.get('auditActionContext') || null;
72
+ }
73
+ /**
74
+ * 设置审计动作上下文
75
+ */
76
+ setActionContext(context) {
77
+ this.cls.set('auditActionContext', context);
78
+ }
79
+ /**
80
+ * 清除审计动作上下文
81
+ */
82
+ clearActionContext() {
83
+ this.cls.set('auditActionContext', null);
84
+ }
85
+ /**
86
+ * 记录实体变化到当前动作(简单版本)
87
+ */
88
+ recordEntityChangeInAction(entityType, entityId, operation) {
89
+ const actionContext = this.getCurrentActionContext();
90
+ if (actionContext) {
91
+ actionContext.entityChanges.push({
92
+ entityType,
93
+ entityId,
94
+ operation,
95
+ sequence: actionContext.entityChanges.length + 1,
96
+ });
97
+ }
98
+ }
99
+ /**
100
+ * 记录详细的实体变化
101
+ */
102
+ recordDetailedEntityChange(entityType, entityId, operation, oldValue, newValue, changedFields, metadata) {
103
+ const actionContext = this.getCurrentActionContext();
104
+ if (actionContext) {
105
+ const detail = {
106
+ entityType,
107
+ entityId,
108
+ operation,
109
+ oldValue,
110
+ newValue,
111
+ changedFields,
112
+ sequence: actionContext.detailedChanges.length + 1,
113
+ metadata,
114
+ };
115
+ actionContext.detailedChanges.push(detail);
116
+ }
117
+ }
118
+ /**
119
+ * 获取当前动作内的序号
120
+ */
121
+ getSequenceInAction() {
122
+ const actionContext = this.getCurrentActionContext();
123
+ return actionContext ? actionContext.entityChanges.length + 1 : 0;
124
+ }
125
+ /**
126
+ * 生成审计动作ID
127
+ */
128
+ generateActionId() {
129
+ return (0, crypto_1.randomBytes)(16).toString('hex');
130
+ }
131
+ /**
132
+ * 构建审计参数上下文
133
+ */
134
+ buildParamsContext() {
135
+ const actionContext = this.getCurrentActionContext();
136
+ if (!actionContext) {
137
+ return null;
138
+ }
139
+ const context = {
140
+ req: actionContext.req,
141
+ result: actionContext.result,
142
+ error: actionContext.error,
143
+ entityChanges: actionContext.detailedChanges,
144
+ // 查找单个实体
145
+ findEntity(entityType, operation) {
146
+ return context.entityChanges.find((change) => change.entityType === entityType &&
147
+ (operation === undefined || change.operation === operation)) || null;
148
+ },
149
+ // 查找多个实体
150
+ findEntities(entityType, operation) {
151
+ return context.entityChanges.filter((change) => change.entityType === entityType &&
152
+ (operation === undefined || change.operation === operation));
153
+ },
154
+ // 统计实体数量
155
+ countEntities(entityType, operation) {
156
+ return context.findEntities(entityType, operation).length;
157
+ },
158
+ // 路径提取
159
+ extractParams(mapping) {
160
+ const result = {};
161
+ for (const [key, value] of Object.entries(mapping)) {
162
+ if (typeof value === 'string') {
163
+ // 简单路径: 'Order.CREATE.orderSn'
164
+ result[key] = this.extractByPath(value);
165
+ }
166
+ else if (typeof value === 'object' && value.type) {
167
+ // 复杂提取: { type: 'join', path: 'OrderItem.CREATE', field: 'name' }
168
+ result[key] = this.extractByConfig(value);
169
+ }
170
+ }
171
+ return result;
172
+ },
173
+ extractByPath(path) {
174
+ const parts = path.split('.');
175
+ if (parts.length < 2)
176
+ return undefined;
177
+ const [entityType, operationStr, ...fieldParts] = parts;
178
+ const operation = operationStr;
179
+ const entity = context.findEntity(entityType, operation);
180
+ if (!entity)
181
+ return undefined;
182
+ // 支持嵌套字段访问
183
+ let value = entity.newValue;
184
+ for (const field of fieldParts) {
185
+ if (value && typeof value === 'object') {
186
+ value = value[field];
187
+ }
188
+ else {
189
+ return undefined;
190
+ }
191
+ }
192
+ return value;
193
+ },
194
+ extractByConfig(config) {
195
+ const { type, path, field, separator = ', ' } = config;
196
+ const parts = path.split('.');
197
+ const [entityType, operationStr] = parts;
198
+ const operation = operationStr;
199
+ const entities = context.findEntities(entityType, operation);
200
+ switch (type) {
201
+ case 'count':
202
+ return entities.length;
203
+ case 'join': {
204
+ const values = entities.map((e) => {
205
+ const fieldParts = field.split('.');
206
+ let value = e.newValue;
207
+ for (const part of fieldParts) {
208
+ if (part === 'metadata') {
209
+ value = e.metadata;
210
+ }
211
+ else if (value && typeof value === 'object') {
212
+ value = value[part];
213
+ }
214
+ else {
215
+ return undefined;
216
+ }
217
+ }
218
+ return value;
219
+ }).filter(Boolean);
220
+ return values.join(separator);
221
+ }
222
+ case 'sum': {
223
+ return entities.reduce((sum, e) => {
224
+ const value = e.newValue[field];
225
+ return sum + (typeof value === 'number' ? value : 0);
226
+ }, 0);
227
+ }
228
+ default:
229
+ return undefined;
230
+ }
231
+ },
232
+ };
233
+ return context;
234
+ }
65
235
  };
66
236
  exports.AuditContextService = AuditContextService;
67
237
  exports.AuditContextService = AuditContextService = __decorate([
@@ -1,5 +1,5 @@
1
1
  import { Repository, EntityManager } from 'typeorm';
2
- import { EntityAuditLogEntity, EntityTransactionEntity, ManualOperationLogEntity } from '../entities';
2
+ import { EntityAuditLogEntity, EntityTransactionEntity, ManualOperationLogEntity, AuditActionSummaryEntity } from '../entities';
3
3
  import { AuditOperation } from '../enums';
4
4
  import { AuditConfig, IAuditStrategy, EntityDifference, RestoreOptions, RestoreResult, PreCheckResult, ManualOperationData, ChangeDetail, RollbackAction } from '../interfaces';
5
5
  import { AuditContextService } from './audit-context.service';
@@ -18,8 +18,9 @@ export declare class EntityAuditService {
18
18
  private readonly multiDbService;
19
19
  private readonly auditStrategy;
20
20
  private readonly config?;
21
+ private readonly actionSummaryRepository?;
21
22
  private readonly auditConnectionName;
22
- constructor(auditLogRepository: Repository<EntityAuditLogEntity>, transactionRepository: Repository<EntityTransactionEntity>, manualOperationRepository: Repository<ManualOperationLogEntity>, entityManager: EntityManager, contextService: AuditContextService, multiDbService: MultiDatabaseService, auditStrategy?: IAuditStrategy, config?: AuditConfig, auditConnectionName?: string);
23
+ constructor(auditLogRepository: Repository<EntityAuditLogEntity>, transactionRepository: Repository<EntityTransactionEntity>, manualOperationRepository: Repository<ManualOperationLogEntity>, entityManager: EntityManager, contextService: AuditContextService, multiDbService: MultiDatabaseService, auditStrategy?: IAuditStrategy, config?: AuditConfig, auditConnectionName?: string, actionSummaryRepository?: Repository<AuditActionSummaryEntity>);
23
24
  /**
24
25
  * 记录实体变更
25
26
  */
@@ -85,7 +86,13 @@ export declare class EntityAuditService {
85
86
  */
86
87
  private generateHashChain;
87
88
  /**
88
- * 生成描述
89
+ * 生成描述(支持多语言)
90
+ * @param operation 操作类型
91
+ * @param entityType 实体类型
92
+ * @param entityId 实体ID
93
+ * @param changedFields 变更字段列表
94
+ * @param language 语言(默认中文)
95
+ * @param entityClass 实体类(可选,用于获取实体标签)
89
96
  */
90
97
  private generateDescription;
91
98
  /**
@@ -160,4 +167,98 @@ export declare class EntityAuditService {
160
167
  * @param transactionId 事务ID
161
168
  */
162
169
  rollbackTransaction(transactionId: string): Promise<void>;
170
+ /**
171
+ * 查询审计动作汇总记录
172
+ */
173
+ getAuditActions(options: {
174
+ userId?: string;
175
+ username?: string;
176
+ actionName?: string;
177
+ success?: boolean;
178
+ startTime?: Date;
179
+ endTime?: Date;
180
+ page?: number;
181
+ limit?: number;
182
+ }): Promise<PageDto<AuditActionSummaryEntity>>;
183
+ /**
184
+ * 查询单个审计动作的详细信息(包含关联的实体变更)
185
+ */
186
+ getAuditActionDetail(actionId: string): Promise<{
187
+ summary: {
188
+ id: string;
189
+ actionName: string;
190
+ operationTemplateKey: string;
191
+ description: string;
192
+ descriptionParams: Record<string, any>;
193
+ success: boolean;
194
+ errorMessage: string;
195
+ duration: number;
196
+ userId: string;
197
+ username: string;
198
+ requestId: string;
199
+ requestIp: string;
200
+ userAgent: string;
201
+ entityChangesCount: number;
202
+ entityTypes: string[];
203
+ operationStats: Record<string, number>;
204
+ createdAt: Date;
205
+ metadata: Record<string, any>;
206
+ };
207
+ entityChanges: EntityAuditLogEntity[];
208
+ detailedChanges: {
209
+ id: string;
210
+ entityType: string;
211
+ entityId: string;
212
+ operation: AuditOperation;
213
+ operationLabel: string;
214
+ description: string;
215
+ sequenceInAction: number;
216
+ createdAt: Date;
217
+ oldValue: Record<string, any>;
218
+ newValue: Record<string, any>;
219
+ fieldChanges: {
220
+ field: string;
221
+ fieldLabel: string;
222
+ oldValue: any;
223
+ newValue: any;
224
+ changeType: "added" | "removed" | "modified" | "unchanged";
225
+ displayOldValue?: string;
226
+ displayNewValue?: string;
227
+ }[];
228
+ changedFieldsCount: number;
229
+ changedFields: string[];
230
+ }[];
231
+ statistics: {
232
+ totalChanges: number;
233
+ totalFieldChanges: number;
234
+ byEntityType: Record<string, number>;
235
+ byOperation: Record<string, number>;
236
+ operationSequence: {
237
+ sequence: number;
238
+ entityType: string;
239
+ operation: AuditOperation;
240
+ }[];
241
+ };
242
+ }>;
243
+ /**
244
+ * 分析字段变化(支持多语言)
245
+ * @param oldValue 旧值
246
+ * @param newValue 新值
247
+ * @param operation 操作类型
248
+ * @param entityClass 实体类(可选,用于获取字段和值的多语言标签)
249
+ * @param language 语言(默认中文)
250
+ */
251
+ private analyzeFieldChanges;
252
+ /**
253
+ * 格式化显示值
254
+ */
255
+ private formatDisplayValue;
256
+ /**
257
+ * 获取操作标签
258
+ */
259
+ private getOperationLabel;
260
+ /**
261
+ * 按字段分组统计
262
+ */
263
+ private groupBy;
163
264
  }