@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.
- package/audit/audit.module.js +17 -0
- package/audit/controllers/audit.controller.d.ts +64 -0
- package/audit/controllers/audit.controller.js +50 -0
- package/audit/decorators/audit-action.decorator.d.ts +74 -0
- package/audit/decorators/audit-action.decorator.js +42 -0
- package/audit/decorators/entity-audit.decorator.d.ts +10 -1
- package/audit/decorators/entity-audit.decorator.js +34 -16
- package/audit/decorators/index.d.ts +1 -0
- package/audit/decorators/index.js +1 -0
- package/audit/entities/audit-action-summary.entity.d.ts +23 -0
- package/audit/entities/audit-action-summary.entity.js +101 -0
- package/audit/entities/entity-audit-log.entity.d.ts +3 -0
- package/audit/entities/entity-audit-log.entity.js +25 -2
- package/audit/entities/entity-transaction.entity.d.ts +3 -4
- package/audit/entities/entity-transaction.entity.js +10 -3
- package/audit/entities/index.d.ts +1 -0
- package/audit/entities/index.js +1 -0
- package/audit/entities/manual-operation-log.entity.js +8 -1
- package/audit/enums/audit.enums.d.ts +1 -10
- package/audit/enums/audit.enums.js +7 -17
- package/audit/index.d.ts +2 -1
- package/audit/index.js +5 -1
- package/audit/interceptors/audit-action.interceptor.d.ts +38 -0
- package/audit/interceptors/audit-action.interceptor.js +215 -0
- package/audit/interceptors/index.d.ts +1 -0
- package/audit/interceptors/index.js +1 -0
- package/audit/interfaces/audit.interfaces.d.ts +10 -5
- package/audit/services/audit-action.service.d.ts +141 -0
- package/audit/services/audit-action.service.js +244 -0
- package/audit/services/audit-context.service.d.ts +82 -0
- package/audit/services/audit-context.service.js +170 -0
- package/audit/services/entity-audit.service.d.ts +104 -3
- package/audit/services/entity-audit.service.js +306 -9
- package/audit/services/index.d.ts +1 -0
- package/audit/services/index.js +1 -0
- package/audit/services/manual-audit-log.service.d.ts +24 -23
- package/audit/services/manual-audit-log.service.js +32 -53
- package/audit/services/operation-description.service.d.ts +13 -3
- package/audit/services/operation-description.service.js +161 -24
- package/audit/services/transaction-audit.service.js +3 -3
- package/audit/subscribers/entity-audit.subscriber.d.ts +4 -0
- package/audit/subscribers/entity-audit.subscriber.js +47 -0
- package/file-upload/controllers/file-access.controller.d.ts +23 -0
- package/file-upload/controllers/file-access.controller.js +128 -0
- package/file-upload/decorators/csv-data.decorator.d.ts +44 -0
- package/file-upload/decorators/csv-data.decorator.js +131 -0
- package/file-upload/decorators/excel-data.decorator.d.ts +44 -0
- package/file-upload/decorators/excel-data.decorator.js +125 -0
- package/file-upload/decorators/file-upload.decorator.d.ts +83 -0
- package/file-upload/decorators/file-upload.decorator.js +172 -0
- package/file-upload/decorators/index.d.ts +4 -0
- package/file-upload/decorators/index.js +20 -0
- package/file-upload/decorators/process.decorator.d.ts +40 -0
- package/file-upload/decorators/process.decorator.js +52 -0
- package/file-upload/dto/create-file.dto.d.ts +24 -0
- package/file-upload/dto/create-file.dto.js +112 -0
- package/file-upload/dto/find-files.dto.d.ts +15 -0
- package/file-upload/dto/find-files.dto.js +76 -0
- package/file-upload/dto/index.d.ts +4 -0
- package/file-upload/dto/index.js +20 -0
- package/file-upload/dto/pagination.dto.d.ts +7 -0
- package/file-upload/dto/pagination.dto.js +39 -0
- package/file-upload/dto/update-file.dto.d.ts +16 -0
- package/file-upload/dto/update-file.dto.js +71 -0
- package/file-upload/entities/file-metadata.entity.d.ts +22 -0
- package/file-upload/entities/file-metadata.entity.js +84 -0
- package/file-upload/entities/file.entity.d.ts +129 -0
- package/file-upload/entities/file.entity.js +384 -0
- package/file-upload/entities/index.d.ts +2 -0
- package/file-upload/entities/index.js +18 -0
- package/file-upload/enums/file-type.enum.d.ts +72 -0
- package/file-upload/enums/file-type.enum.js +212 -0
- package/file-upload/exceptions/file-upload.exception.d.ts +57 -0
- package/file-upload/exceptions/file-upload.exception.js +120 -0
- package/file-upload/exceptions/index.d.ts +1 -0
- package/file-upload/exceptions/index.js +17 -0
- package/file-upload/file-upload.module.d.ts +89 -0
- package/file-upload/file-upload.module.js +264 -0
- package/file-upload/index.d.ts +26 -0
- package/file-upload/index.js +59 -0
- package/file-upload/interceptors/file-upload.interceptor.d.ts +48 -0
- package/file-upload/interceptors/file-upload.interceptor.js +434 -0
- package/file-upload/interceptors/index.d.ts +1 -0
- package/file-upload/interceptors/index.js +17 -0
- package/file-upload/interfaces/custom-file-type.interface.d.ts +72 -0
- package/file-upload/interfaces/custom-file-type.interface.js +2 -0
- package/file-upload/interfaces/file-buffer.interface.d.ts +72 -0
- package/file-upload/interfaces/file-buffer.interface.js +2 -0
- package/file-upload/interfaces/file-entity.interface.d.ts +142 -0
- package/file-upload/interfaces/file-entity.interface.js +28 -0
- package/file-upload/interfaces/file-metadata.interface.d.ts +21 -0
- package/file-upload/interfaces/file-metadata.interface.js +2 -0
- package/file-upload/interfaces/file-upload-options.interface.d.ts +117 -0
- package/file-upload/interfaces/file-upload-options.interface.js +2 -0
- package/file-upload/interfaces/index.d.ts +7 -0
- package/file-upload/interfaces/index.js +24 -0
- package/file-upload/interfaces/storage-provider.interface.d.ts +239 -0
- package/file-upload/interfaces/storage-provider.interface.js +2 -0
- package/file-upload/interfaces/upload-options.interface.d.ts +19 -0
- package/file-upload/interfaces/upload-options.interface.js +2 -0
- package/file-upload/providers/index.d.ts +2 -0
- package/file-upload/providers/index.js +18 -0
- package/file-upload/providers/local-storage.provider.d.ts +98 -0
- package/file-upload/providers/local-storage.provider.js +484 -0
- package/file-upload/providers/s3-storage.provider.d.ts +87 -0
- package/file-upload/providers/s3-storage.provider.js +455 -0
- package/file-upload/services/file-signature-validator.service.d.ts +118 -0
- package/file-upload/services/file-signature-validator.service.js +376 -0
- package/file-upload/services/file.service.d.ts +190 -0
- package/file-upload/services/file.service.js +609 -0
- package/file-upload/services/index.d.ts +4 -0
- package/file-upload/services/index.js +20 -0
- package/file-upload/services/malicious-file-detector.service.d.ts +274 -0
- package/file-upload/services/malicious-file-detector.service.js +1035 -0
- package/file-upload/services/mime-registry.service.d.ts +47 -0
- package/file-upload/services/mime-registry.service.js +167 -0
- package/file-upload/utils/checksum.util.d.ts +28 -0
- package/file-upload/utils/checksum.util.js +65 -0
- package/file-upload/utils/dynamic-import.util.d.ts +50 -0
- package/file-upload/utils/dynamic-import.util.js +144 -0
- package/file-upload/utils/filename.util.d.ts +59 -0
- package/file-upload/utils/filename.util.js +184 -0
- package/file-upload/utils/filepath.util.d.ts +70 -0
- package/file-upload/utils/filepath.util.js +152 -0
- package/file-upload/utils/index.d.ts +4 -0
- package/file-upload/utils/index.js +20 -0
- package/index.d.ts +3 -1
- package/index.js +4 -1
- package/package.json +4 -5
- package/setup/bootstrap.setup.d.ts +1 -0
- package/setup/bootstrap.setup.js +1 -0
- package/shared/index.d.ts +1 -1
- package/shared/index.js +1 -1
- package/shared/{serviceRegistryModule.js → service-registry.module.js} +0 -12
- package/shared/services/index.d.ts +0 -1
- package/shared/services/index.js +0 -1
- package/transaction/__tests__/mocks.d.ts +9 -0
- package/transaction/__tests__/mocks.js +33 -0
- package/transaction/base-service-transaction.d.ts +99 -0
- package/transaction/base-service-transaction.js +286 -0
- package/transaction/cls-compatibility.service.d.ts +55 -0
- package/transaction/cls-compatibility.service.js +127 -0
- package/transaction/data-source-registry.d.ts +91 -0
- package/transaction/data-source-registry.js +349 -0
- package/transaction/database-adapter.d.ts +44 -0
- package/transaction/database-adapter.js +240 -0
- package/transaction/decorators/entity-datasource.decorator.d.ts +62 -0
- package/transaction/decorators/entity-datasource.decorator.js +105 -0
- package/transaction/index.d.ts +14 -0
- package/transaction/index.js +57 -0
- package/transaction/logging-transactional.interceptor.d.ts +18 -0
- package/transaction/logging-transactional.interceptor.js +163 -0
- package/transaction/transaction-context.service.d.ts +137 -0
- package/transaction/transaction-context.service.js +411 -0
- package/transaction/transaction-manager.d.ts +230 -0
- package/transaction/transaction-manager.js +1001 -0
- package/transaction/transaction-synchronization.d.ts +171 -0
- package/transaction/transaction-synchronization.js +380 -0
- package/transaction/transaction.errors.d.ts +91 -0
- package/transaction/transaction.errors.js +206 -0
- package/transaction/transaction.module.d.ts +30 -0
- package/transaction/transaction.module.js +98 -0
- package/transaction/transactional.decorator.d.ts +82 -0
- package/transaction/transactional.decorator.js +319 -0
- package/transaction/typeorm-module-wrapper.d.ts +96 -0
- package/transaction/typeorm-module-wrapper.js +197 -0
- package/validators/file-mimetype.validator.d.ts +0 -2
- package/validators/file-mimetype.validator.js +4 -6
- package/validators/is-exists.validator.d.ts +2 -5
- package/validators/is-exists.validator.js +4 -6
- package/validators/is-unique.validator.d.ts +2 -5
- package/validators/is-unique.validator.js +6 -11
- package/shared/services/validator.service.d.ts +0 -3
- package/shared/services/validator.service.js +0 -20
- /package/shared/{serviceRegistryModule.d.ts → service-registry.module.d.ts} +0 -0
|
@@ -32,11 +32,12 @@ const audit_context_service_1 = require("./audit-context.service");
|
|
|
32
32
|
const audit_strategy_service_1 = require("./audit-strategy.service");
|
|
33
33
|
const multi_database_service_1 = require("./multi-database.service");
|
|
34
34
|
const dto_1 = require("../../common/dto");
|
|
35
|
+
const entity_audit_decorator_1 = require("../decorators/entity-audit.decorator");
|
|
35
36
|
/**
|
|
36
37
|
* 实体审计服务
|
|
37
38
|
*/
|
|
38
39
|
let EntityAuditService = class EntityAuditService {
|
|
39
|
-
constructor(auditLogRepository, transactionRepository, manualOperationRepository, entityManager, contextService, multiDbService, auditStrategy = new audit_strategy_service_1.DefaultAuditStrategy(), config, auditConnectionName) {
|
|
40
|
+
constructor(auditLogRepository, transactionRepository, manualOperationRepository, entityManager, contextService, multiDbService, auditStrategy = new audit_strategy_service_1.DefaultAuditStrategy(), config, auditConnectionName, actionSummaryRepository) {
|
|
40
41
|
this.auditLogRepository = auditLogRepository;
|
|
41
42
|
this.transactionRepository = transactionRepository;
|
|
42
43
|
this.manualOperationRepository = manualOperationRepository;
|
|
@@ -45,6 +46,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
45
46
|
this.multiDbService = multiDbService;
|
|
46
47
|
this.auditStrategy = auditStrategy;
|
|
47
48
|
this.config = config;
|
|
49
|
+
this.actionSummaryRepository = actionSummaryRepository;
|
|
48
50
|
this.auditConnectionName = auditConnectionName || 'default';
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
@@ -90,6 +92,10 @@ let EntityAuditService = class EntityAuditService {
|
|
|
90
92
|
hashChain: ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.security) === null || _b === void 0 ? void 0 : _b.hashChainEnabled)
|
|
91
93
|
? yield this.generateHashChain(entityType, entityId, filteredNewValue)
|
|
92
94
|
: undefined,
|
|
95
|
+
// 新增:审计动作关联字段
|
|
96
|
+
auditActionId: metadata.auditActionId,
|
|
97
|
+
auditActionName: metadata.auditActionName,
|
|
98
|
+
sequenceInAction: metadata.sequenceInAction || 0,
|
|
93
99
|
});
|
|
94
100
|
// 保存变更日志
|
|
95
101
|
const savedLog = yield this.auditLogRepository.save(auditLog);
|
|
@@ -338,7 +344,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
338
344
|
/**
|
|
339
345
|
* 深度差异比较
|
|
340
346
|
*/
|
|
341
|
-
deepDiff(oldObj, newObj, path = []) {
|
|
347
|
+
deepDiff(oldObj, newObj, path = [], visited = new WeakSet()) {
|
|
342
348
|
var _a;
|
|
343
349
|
const changes = [];
|
|
344
350
|
const maxDepth = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.maxDiffDepth) || 5;
|
|
@@ -358,6 +364,19 @@ let EntityAuditService = class EntityAuditService {
|
|
|
358
364
|
}
|
|
359
365
|
return changes;
|
|
360
366
|
}
|
|
367
|
+
// 检测循环引用
|
|
368
|
+
if (visited.has(oldObj)) {
|
|
369
|
+
// 检测到循环引用,停止递归
|
|
370
|
+
return changes;
|
|
371
|
+
}
|
|
372
|
+
visited.add(oldObj);
|
|
373
|
+
// 如果newObj也是对象,也加入访问集合
|
|
374
|
+
if (typeof newObj === 'object' && newObj !== null) {
|
|
375
|
+
if (visited.has(newObj)) {
|
|
376
|
+
return changes;
|
|
377
|
+
}
|
|
378
|
+
visited.add(newObj);
|
|
379
|
+
}
|
|
361
380
|
// 处理数组
|
|
362
381
|
if (Array.isArray(oldObj)) {
|
|
363
382
|
if (!Array.isArray(newObj)) {
|
|
@@ -379,7 +398,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
379
398
|
return changes;
|
|
380
399
|
}
|
|
381
400
|
for (let i = 0; i < oldObj.length; i++) {
|
|
382
|
-
changes.push(...this.deepDiff(oldObj[i], newObj[i], [...path, i.toString()]));
|
|
401
|
+
changes.push(...this.deepDiff(oldObj[i], newObj[i], [...path, i.toString()], visited));
|
|
383
402
|
}
|
|
384
403
|
return changes;
|
|
385
404
|
}
|
|
@@ -405,7 +424,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
405
424
|
});
|
|
406
425
|
}
|
|
407
426
|
else {
|
|
408
|
-
changes.push(...this.deepDiff(oldVal, newVal, [...path, key]));
|
|
427
|
+
changes.push(...this.deepDiff(oldVal, newVal, [...path, key], visited));
|
|
409
428
|
}
|
|
410
429
|
}
|
|
411
430
|
return changes;
|
|
@@ -522,9 +541,15 @@ let EntityAuditService = class EntityAuditService {
|
|
|
522
541
|
});
|
|
523
542
|
}
|
|
524
543
|
/**
|
|
525
|
-
*
|
|
544
|
+
* 生成描述(支持多语言)
|
|
545
|
+
* @param operation 操作类型
|
|
546
|
+
* @param entityType 实体类型
|
|
547
|
+
* @param entityId 实体ID
|
|
548
|
+
* @param changedFields 变更字段列表
|
|
549
|
+
* @param language 语言(默认中文)
|
|
550
|
+
* @param entityClass 实体类(可选,用于获取实体标签)
|
|
526
551
|
*/
|
|
527
|
-
generateDescription(operation, entityType, entityId, changedFields) {
|
|
552
|
+
generateDescription(operation, entityType, entityId, changedFields, language = 'zh', entityClass) {
|
|
528
553
|
const operationText = {
|
|
529
554
|
[enums_1.AuditOperation.CREATE]: '创建',
|
|
530
555
|
[enums_1.AuditOperation.UPDATE]: '更新',
|
|
@@ -532,10 +557,32 @@ let EntityAuditService = class EntityAuditService {
|
|
|
532
557
|
[enums_1.AuditOperation.RESTORE]: '恢复',
|
|
533
558
|
};
|
|
534
559
|
const text = operationText[operation] || operation;
|
|
560
|
+
// 尝试获取实体的多语言标签
|
|
561
|
+
let entityLabel = entityType;
|
|
562
|
+
if (entityClass) {
|
|
563
|
+
try {
|
|
564
|
+
entityLabel = (0, entity_audit_decorator_1.getEntityLabel)(entityClass, language);
|
|
565
|
+
}
|
|
566
|
+
catch (error) {
|
|
567
|
+
// 忽略错误,使用默认的 entityType
|
|
568
|
+
}
|
|
569
|
+
}
|
|
535
570
|
if (operation === enums_1.AuditOperation.UPDATE && changedFields.length > 0) {
|
|
536
|
-
|
|
571
|
+
// 对于更新操作,显示哪些字段发生了变化
|
|
572
|
+
const fieldLabels = changedFields.map(field => {
|
|
573
|
+
if (entityClass) {
|
|
574
|
+
try {
|
|
575
|
+
return (0, entity_audit_decorator_1.getFieldLabel)(entityClass, field, language);
|
|
576
|
+
}
|
|
577
|
+
catch (error) {
|
|
578
|
+
return field;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return field;
|
|
582
|
+
});
|
|
583
|
+
return `${text}${entityLabel}(${entityId}), 变更字段: ${fieldLabels.join('、')}`;
|
|
537
584
|
}
|
|
538
|
-
return `${text}
|
|
585
|
+
return `${text}${entityLabel}(${entityId})`;
|
|
539
586
|
}
|
|
540
587
|
/**
|
|
541
588
|
* 检测冲突
|
|
@@ -756,6 +803,254 @@ let EntityAuditService = class EntityAuditService {
|
|
|
756
803
|
});
|
|
757
804
|
});
|
|
758
805
|
}
|
|
806
|
+
/**
|
|
807
|
+
* 查询审计动作汇总记录
|
|
808
|
+
*/
|
|
809
|
+
getAuditActions(options) {
|
|
810
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
811
|
+
if (!this.actionSummaryRepository) {
|
|
812
|
+
throw new Error('AuditActionSummaryEntity repository not available');
|
|
813
|
+
}
|
|
814
|
+
const { page = 1, limit = 20 } = options;
|
|
815
|
+
const queryBuilder = this.actionSummaryRepository.createQueryBuilder('action');
|
|
816
|
+
// 应用过滤条件
|
|
817
|
+
if (options.userId) {
|
|
818
|
+
queryBuilder.andWhere('action.userId = :userId', { userId: options.userId });
|
|
819
|
+
}
|
|
820
|
+
if (options.username) {
|
|
821
|
+
queryBuilder.andWhere('action.username LIKE :username', { username: `%${options.username}%` });
|
|
822
|
+
}
|
|
823
|
+
if (options.actionName) {
|
|
824
|
+
queryBuilder.andWhere('action.actionName = :actionName', { actionName: options.actionName });
|
|
825
|
+
}
|
|
826
|
+
if (options.success !== undefined) {
|
|
827
|
+
queryBuilder.andWhere('action.success = :success', { success: options.success });
|
|
828
|
+
}
|
|
829
|
+
if (options.startTime && options.endTime) {
|
|
830
|
+
queryBuilder.andWhere('action.createdAt BETWEEN :startTime AND :endTime', {
|
|
831
|
+
startTime: options.startTime,
|
|
832
|
+
endTime: options.endTime,
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
// 排序
|
|
836
|
+
queryBuilder.orderBy('action.createdAt', 'DESC');
|
|
837
|
+
// 分页
|
|
838
|
+
const skip = (page - 1) * limit;
|
|
839
|
+
queryBuilder.skip(skip).take(limit);
|
|
840
|
+
const [data, total] = yield queryBuilder.getManyAndCount();
|
|
841
|
+
const pageOptionsDto = new dto_1.PageOptionsDto();
|
|
842
|
+
Object.assign(pageOptionsDto, { page, pageSize: limit });
|
|
843
|
+
const pageMetaDto = new dto_1.PageMetaDto({
|
|
844
|
+
pageOptionsDto,
|
|
845
|
+
itemCount: total,
|
|
846
|
+
});
|
|
847
|
+
return new dto_1.PageDto(data, pageMetaDto);
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* 查询单个审计动作的详细信息(包含关联的实体变更)
|
|
852
|
+
*/
|
|
853
|
+
getAuditActionDetail(actionId) {
|
|
854
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
855
|
+
if (!this.actionSummaryRepository) {
|
|
856
|
+
throw new Error('AuditActionSummaryEntity repository not available');
|
|
857
|
+
}
|
|
858
|
+
// 查询汇总信息
|
|
859
|
+
const summary = yield this.actionSummaryRepository.findOne({
|
|
860
|
+
where: { id: actionId },
|
|
861
|
+
});
|
|
862
|
+
if (!summary) {
|
|
863
|
+
throw new Error(`Audit action with id ${actionId} not found`);
|
|
864
|
+
}
|
|
865
|
+
// 查询关联的实体变更
|
|
866
|
+
const entityChanges = yield this.auditLogRepository.find({
|
|
867
|
+
where: { auditActionId: actionId },
|
|
868
|
+
order: { sequenceInAction: 'ASC' },
|
|
869
|
+
});
|
|
870
|
+
// 分析每个实体的详细变化
|
|
871
|
+
const detailedChanges = entityChanges.map((change) => {
|
|
872
|
+
const fieldChanges = this.analyzeFieldChanges(change.oldValue || {}, change.newValue || {}, change.operation);
|
|
873
|
+
return {
|
|
874
|
+
id: change.id,
|
|
875
|
+
entityType: change.entityType,
|
|
876
|
+
entityId: change.entityId,
|
|
877
|
+
operation: change.operation,
|
|
878
|
+
operationLabel: this.getOperationLabel(change.operation),
|
|
879
|
+
description: change.description,
|
|
880
|
+
sequenceInAction: change.sequenceInAction,
|
|
881
|
+
createdAt: change.createdAt,
|
|
882
|
+
// 数据快照
|
|
883
|
+
oldValue: change.oldValue,
|
|
884
|
+
newValue: change.newValue,
|
|
885
|
+
// 详细的字段变化分析
|
|
886
|
+
fieldChanges,
|
|
887
|
+
changedFieldsCount: fieldChanges.length,
|
|
888
|
+
changedFields: change.changedFields,
|
|
889
|
+
};
|
|
890
|
+
});
|
|
891
|
+
// 统计信息
|
|
892
|
+
const statistics = {
|
|
893
|
+
totalChanges: entityChanges.length,
|
|
894
|
+
totalFieldChanges: detailedChanges.reduce((sum, c) => sum + c.changedFieldsCount, 0),
|
|
895
|
+
byEntityType: this.groupBy(entityChanges, 'entityType'),
|
|
896
|
+
byOperation: this.groupBy(entityChanges, 'operation'),
|
|
897
|
+
operationSequence: entityChanges.map((c) => ({
|
|
898
|
+
sequence: c.sequenceInAction,
|
|
899
|
+
entityType: c.entityType,
|
|
900
|
+
operation: c.operation,
|
|
901
|
+
})),
|
|
902
|
+
};
|
|
903
|
+
return {
|
|
904
|
+
// 汇总信息
|
|
905
|
+
summary: {
|
|
906
|
+
id: summary.id,
|
|
907
|
+
actionName: summary.actionName,
|
|
908
|
+
operationTemplateKey: summary.operationTemplateKey,
|
|
909
|
+
description: summary.description,
|
|
910
|
+
descriptionParams: summary.descriptionParams,
|
|
911
|
+
success: summary.success,
|
|
912
|
+
errorMessage: summary.errorMessage,
|
|
913
|
+
duration: summary.duration,
|
|
914
|
+
userId: summary.userId,
|
|
915
|
+
username: summary.username,
|
|
916
|
+
requestId: summary.requestId,
|
|
917
|
+
requestIp: summary.requestIp,
|
|
918
|
+
userAgent: summary.userAgent,
|
|
919
|
+
entityChangesCount: summary.entityChangesCount,
|
|
920
|
+
entityTypes: summary.entityTypes,
|
|
921
|
+
operationStats: summary.operationStats,
|
|
922
|
+
createdAt: summary.createdAt,
|
|
923
|
+
metadata: summary.metadata,
|
|
924
|
+
},
|
|
925
|
+
// 原始实体变更记录
|
|
926
|
+
entityChanges,
|
|
927
|
+
// 详细的变化分析
|
|
928
|
+
detailedChanges,
|
|
929
|
+
// 统计信息
|
|
930
|
+
statistics,
|
|
931
|
+
};
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* 分析字段变化(支持多语言)
|
|
936
|
+
* @param oldValue 旧值
|
|
937
|
+
* @param newValue 新值
|
|
938
|
+
* @param operation 操作类型
|
|
939
|
+
* @param entityClass 实体类(可选,用于获取字段和值的多语言标签)
|
|
940
|
+
* @param language 语言(默认中文)
|
|
941
|
+
*/
|
|
942
|
+
analyzeFieldChanges(oldValue, newValue, operation, entityClass, language = 'zh') {
|
|
943
|
+
const changes = [];
|
|
944
|
+
const allFields = new Set([...Object.keys(oldValue), ...Object.keys(newValue)]);
|
|
945
|
+
for (const field of allFields) {
|
|
946
|
+
const oldVal = oldValue[field];
|
|
947
|
+
const newVal = newValue[field];
|
|
948
|
+
let changeType;
|
|
949
|
+
if (operation === enums_1.AuditOperation.CREATE) {
|
|
950
|
+
// 创建操作,所有字段都是新增
|
|
951
|
+
changeType = 'added';
|
|
952
|
+
}
|
|
953
|
+
else if (operation === enums_1.AuditOperation.DELETE) {
|
|
954
|
+
// 删除操作,所有字段都是移除
|
|
955
|
+
changeType = 'removed';
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
// 更新操作,判断字段变化
|
|
959
|
+
if (oldVal === undefined && newVal !== undefined) {
|
|
960
|
+
changeType = 'added';
|
|
961
|
+
}
|
|
962
|
+
else if (oldVal !== undefined && newVal === undefined) {
|
|
963
|
+
changeType = 'removed';
|
|
964
|
+
}
|
|
965
|
+
else if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
|
|
966
|
+
changeType = 'modified';
|
|
967
|
+
}
|
|
968
|
+
else {
|
|
969
|
+
changeType = 'unchanged';
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
// 跳过未变化的字段(对于UPDATE操作)
|
|
973
|
+
if (changeType === 'unchanged' && operation === enums_1.AuditOperation.UPDATE) {
|
|
974
|
+
continue;
|
|
975
|
+
}
|
|
976
|
+
// 获取字段的多语言标签
|
|
977
|
+
let fieldLabel = field;
|
|
978
|
+
if (entityClass) {
|
|
979
|
+
try {
|
|
980
|
+
fieldLabel = (0, entity_audit_decorator_1.getFieldLabel)(entityClass, field, language);
|
|
981
|
+
}
|
|
982
|
+
catch (error) {
|
|
983
|
+
// 忽略错误,使用原字段名
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
// 获取字段值的多语言标签
|
|
987
|
+
let displayOldValue = this.formatDisplayValue(oldVal);
|
|
988
|
+
let displayNewValue = this.formatDisplayValue(newVal);
|
|
989
|
+
if (entityClass) {
|
|
990
|
+
try {
|
|
991
|
+
if (oldVal !== null && oldVal !== undefined) {
|
|
992
|
+
const valueLabel = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, field, oldVal, language);
|
|
993
|
+
if (valueLabel !== oldVal) {
|
|
994
|
+
displayOldValue = valueLabel;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
if (newVal !== null && newVal !== undefined) {
|
|
998
|
+
const valueLabel = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, field, newVal, language);
|
|
999
|
+
if (valueLabel !== newVal) {
|
|
1000
|
+
displayNewValue = valueLabel;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
catch (error) {
|
|
1005
|
+
// 忽略错误,使用默认格式化值
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
changes.push({
|
|
1009
|
+
field,
|
|
1010
|
+
fieldLabel,
|
|
1011
|
+
oldValue: oldVal,
|
|
1012
|
+
newValue: newVal,
|
|
1013
|
+
changeType,
|
|
1014
|
+
displayOldValue,
|
|
1015
|
+
displayNewValue,
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
return changes;
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* 格式化显示值
|
|
1022
|
+
*/
|
|
1023
|
+
formatDisplayValue(value) {
|
|
1024
|
+
if (value === null || value === undefined) {
|
|
1025
|
+
return '';
|
|
1026
|
+
}
|
|
1027
|
+
if (typeof value === 'object') {
|
|
1028
|
+
return JSON.stringify(value);
|
|
1029
|
+
}
|
|
1030
|
+
return String(value);
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* 获取操作标签
|
|
1034
|
+
*/
|
|
1035
|
+
getOperationLabel(operation) {
|
|
1036
|
+
const labels = {
|
|
1037
|
+
[enums_1.AuditOperation.CREATE]: '创建',
|
|
1038
|
+
[enums_1.AuditOperation.UPDATE]: '更新',
|
|
1039
|
+
[enums_1.AuditOperation.DELETE]: '删除',
|
|
1040
|
+
[enums_1.AuditOperation.RESTORE]: '恢复',
|
|
1041
|
+
};
|
|
1042
|
+
return labels[operation] || operation;
|
|
1043
|
+
}
|
|
1044
|
+
/**
|
|
1045
|
+
* 按字段分组统计
|
|
1046
|
+
*/
|
|
1047
|
+
groupBy(items, field) {
|
|
1048
|
+
return items.reduce((acc, item) => {
|
|
1049
|
+
const key = item[field];
|
|
1050
|
+
acc[key] = (acc[key] || 0) + 1;
|
|
1051
|
+
return acc;
|
|
1052
|
+
}, {});
|
|
1053
|
+
}
|
|
759
1054
|
};
|
|
760
1055
|
exports.EntityAuditService = EntityAuditService;
|
|
761
1056
|
exports.EntityAuditService = EntityAuditService = __decorate([
|
|
@@ -770,10 +1065,12 @@ exports.EntityAuditService = EntityAuditService = __decorate([
|
|
|
770
1065
|
__param(7, (0, common_1.Inject)('AUDIT_CONFIG')),
|
|
771
1066
|
__param(8, (0, common_1.Optional)()),
|
|
772
1067
|
__param(8, (0, common_1.Inject)('AUDIT_CONNECTION_NAME')),
|
|
1068
|
+
__param(9, (0, common_1.Optional)()),
|
|
1069
|
+
__param(9, (0, typeorm_1.InjectRepository)(entities_1.AuditActionSummaryEntity)),
|
|
773
1070
|
__metadata("design:paramtypes", [typeorm_2.Repository,
|
|
774
1071
|
typeorm_2.Repository,
|
|
775
1072
|
typeorm_2.Repository,
|
|
776
1073
|
typeorm_2.EntityManager,
|
|
777
1074
|
audit_context_service_1.AuditContextService,
|
|
778
|
-
multi_database_service_1.MultiDatabaseService, Object, Object, String])
|
|
1075
|
+
multi_database_service_1.MultiDatabaseService, Object, Object, String, typeorm_2.Repository])
|
|
779
1076
|
], EntityAuditService);
|
package/audit/services/index.js
CHANGED
|
@@ -21,3 +21,4 @@ __exportStar(require("./transaction-audit.service"), exports);
|
|
|
21
21
|
__exportStar(require("./multi-database.service"), exports);
|
|
22
22
|
__exportStar(require("./operation-description.service"), exports);
|
|
23
23
|
__exportStar(require("./manual-audit-log.service"), exports);
|
|
24
|
+
__exportStar(require("./audit-action.service"), exports);
|
|
@@ -2,20 +2,21 @@ import { Repository, DataSource } from 'typeorm';
|
|
|
2
2
|
import { ManualOperationLogEntity, EntityTransactionEntity } from '../entities';
|
|
3
3
|
import { AuditContextService } from './audit-context.service';
|
|
4
4
|
import { ManualLogOptions } from '../interfaces';
|
|
5
|
+
import { AuditTransactionStatus } from '../enums';
|
|
5
6
|
/**
|
|
6
7
|
* 手动审计日志服务
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
+
* 提供标准的依赖注入方式记录操作日志
|
|
10
|
+
* @deprecated 静态方法已废弃,请使用依赖注入方式
|
|
9
11
|
*/
|
|
10
12
|
export declare class ManualAuditLogService {
|
|
11
13
|
private readonly manualLogRepository;
|
|
12
14
|
private readonly transactionRepository;
|
|
13
15
|
private readonly contextService;
|
|
14
16
|
private readonly dataSource;
|
|
15
|
-
private static instance;
|
|
16
17
|
constructor(manualLogRepository: Repository<ManualOperationLogEntity>, transactionRepository: Repository<EntityTransactionEntity>, contextService: AuditContextService, dataSource: DataSource);
|
|
17
18
|
/**
|
|
18
|
-
*
|
|
19
|
+
* 记录操作日志
|
|
19
20
|
*
|
|
20
21
|
* @description
|
|
21
22
|
* 支持三种记录模式:
|
|
@@ -25,7 +26,7 @@ export declare class ManualAuditLogService {
|
|
|
25
26
|
*
|
|
26
27
|
* @example
|
|
27
28
|
* // 模式1:模板键模式
|
|
28
|
-
* await
|
|
29
|
+
* await this.manualAuditLogService.log({
|
|
29
30
|
* templateKey: 'user.login',
|
|
30
31
|
* descriptionParams: {
|
|
31
32
|
* username: 'john.doe',
|
|
@@ -35,13 +36,13 @@ export declare class ManualAuditLogService {
|
|
|
35
36
|
*
|
|
36
37
|
* @example
|
|
37
38
|
* // 模式2:直接描述模式(字符串)
|
|
38
|
-
* await
|
|
39
|
+
* await this.manualAuditLogService.log({
|
|
39
40
|
* description: '用户登录系统',
|
|
40
41
|
* });
|
|
41
42
|
*
|
|
42
43
|
* @example
|
|
43
44
|
* // 模式2:直接描述模式(多语言)
|
|
44
|
-
* await
|
|
45
|
+
* await this.manualAuditLogService.log({
|
|
45
46
|
* description: {
|
|
46
47
|
* zh: '用户登录系统',
|
|
47
48
|
* en: 'User logged in',
|
|
@@ -50,7 +51,7 @@ export declare class ManualAuditLogService {
|
|
|
50
51
|
*
|
|
51
52
|
* @example
|
|
52
53
|
* // 模式3:内联模板模式
|
|
53
|
-
* await
|
|
54
|
+
* await this.manualAuditLogService.log({
|
|
54
55
|
* descriptionTemplate: {
|
|
55
56
|
* zh: '用户 {username} 在 {time} 登录了系统',
|
|
56
57
|
* en: 'User {username} logged in at {time}',
|
|
@@ -61,52 +62,52 @@ export declare class ManualAuditLogService {
|
|
|
61
62
|
* },
|
|
62
63
|
* });
|
|
63
64
|
*/
|
|
64
|
-
|
|
65
|
+
log(options: ManualLogOptions): Promise<ManualOperationLogEntity>;
|
|
65
66
|
/**
|
|
66
67
|
* 实例方法:记录操作日志
|
|
67
68
|
*/
|
|
68
69
|
logOperation(options: ManualLogOptions): Promise<ManualOperationLogEntity>;
|
|
69
70
|
/**
|
|
70
|
-
*
|
|
71
|
+
* 开始事务
|
|
71
72
|
*
|
|
72
73
|
* @example
|
|
73
74
|
* ```typescript
|
|
74
|
-
* const txId = await
|
|
75
|
+
* const txId = await this.manualAuditLogService.beginTransaction('user-123', 'John Doe');
|
|
75
76
|
*
|
|
76
|
-
* await
|
|
77
|
+
* await this.manualAuditLogService.log({
|
|
77
78
|
* templateKey: 'order.create',
|
|
78
79
|
* descriptionParams: { orderId: 'order-1' },
|
|
79
80
|
* transactionId: txId,
|
|
80
81
|
* autoCreateTransaction: false,
|
|
81
82
|
* });
|
|
82
83
|
*
|
|
83
|
-
* await
|
|
84
|
+
* await this.manualAuditLogService.log({
|
|
84
85
|
* templateKey: 'payment.process',
|
|
85
86
|
* descriptionParams: { paymentId: 'pay-1' },
|
|
86
87
|
* transactionId: txId,
|
|
87
88
|
* autoCreateTransaction: false,
|
|
88
89
|
* });
|
|
89
90
|
*
|
|
90
|
-
* await
|
|
91
|
+
* await this.manualAuditLogService.commitTransaction(txId);
|
|
91
92
|
* ```
|
|
92
93
|
*/
|
|
93
|
-
|
|
94
|
+
beginTransaction(userId?: string, username?: string): Promise<string>;
|
|
94
95
|
/**
|
|
95
|
-
*
|
|
96
|
+
* 提交事务
|
|
96
97
|
*/
|
|
97
|
-
|
|
98
|
+
commitTransaction(transactionId: string): Promise<void>;
|
|
98
99
|
/**
|
|
99
|
-
*
|
|
100
|
+
* 回滚事务
|
|
100
101
|
*/
|
|
101
|
-
|
|
102
|
+
rollbackTransaction(transactionId: string): Promise<void>;
|
|
102
103
|
/**
|
|
103
104
|
* 创建事务
|
|
104
105
|
*/
|
|
105
|
-
|
|
106
|
+
createTransaction(userId?: string, username?: string): Promise<string>;
|
|
106
107
|
/**
|
|
107
108
|
* 更新事务状态
|
|
108
109
|
*/
|
|
109
|
-
|
|
110
|
+
updateTransactionStatus(transactionId: string, status: AuditTransactionStatus): Promise<void>;
|
|
110
111
|
/**
|
|
111
112
|
* 生成事务ID
|
|
112
113
|
*/
|
|
@@ -120,7 +121,7 @@ export declare class ManualAuditLogService {
|
|
|
120
121
|
* @example
|
|
121
122
|
* ```typescript
|
|
122
123
|
* // 混合使用多种模式
|
|
123
|
-
* await
|
|
124
|
+
* await this.manualAuditLogService.logBatch([
|
|
124
125
|
* {
|
|
125
126
|
* templateKey: 'product.update',
|
|
126
127
|
* descriptionParams: { productId: 'p1', field: 'price' },
|
|
@@ -138,11 +139,11 @@ export declare class ManualAuditLogService {
|
|
|
138
139
|
* ]);
|
|
139
140
|
* ```
|
|
140
141
|
*/
|
|
141
|
-
|
|
142
|
+
logBatch(operations: ManualLogOptions[], sharedTransactionId?: string): Promise<ManualOperationLogEntity[]>;
|
|
142
143
|
/**
|
|
143
144
|
* 查询操作日志
|
|
144
145
|
*/
|
|
145
|
-
|
|
146
|
+
findLogs(options: {
|
|
146
147
|
templateKey?: string;
|
|
147
148
|
userId?: string;
|
|
148
149
|
transactionId?: string;
|