@nest-omni/core 4.1.3-3 → 4.1.3-31
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.d.ts +1 -0
- package/audit/audit.module.js +51 -2
- package/audit/controllers/audit.controller.d.ts +57 -1
- package/audit/controllers/audit.controller.js +43 -0
- package/audit/decorators/audit-action.decorator.d.ts +74 -0
- package/audit/decorators/audit-action.decorator.js +42 -0
- package/audit/decorators/audit-controller.decorator.d.ts +1 -1
- package/audit/decorators/audit-controller.decorator.js +2 -2
- package/audit/decorators/audit-operation.decorator.d.ts +0 -7
- package/audit/decorators/audit-operation.decorator.js +0 -7
- package/audit/decorators/entity-audit.decorator.d.ts +78 -2
- package/audit/decorators/entity-audit.decorator.js +145 -4
- package/audit/decorators/index.d.ts +2 -0
- package/audit/decorators/index.js +2 -0
- package/audit/dto/audit-action-query.dto.d.ts +13 -0
- package/audit/dto/audit-action-query.dto.js +77 -0
- package/audit/dto/index.d.ts +1 -0
- package/audit/dto/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 +7 -2
- package/audit/entities/entity-audit-log.entity.js +45 -9
- package/audit/entities/entity-transaction.entity.d.ts +8 -2
- package/audit/entities/entity-transaction.entity.js +39 -3
- package/audit/entities/index.d.ts +3 -0
- package/audit/entities/index.js +3 -0
- package/audit/entities/manual-operation-log.entity.d.ts +0 -2
- package/audit/entities/manual-operation-log.entity.js +8 -9
- package/audit/enums/audit.enums.d.ts +14 -6
- package/audit/enums/audit.enums.js +18 -9
- package/audit/examples/decorator-value-mapping.example.d.ts +70 -0
- package/audit/examples/decorator-value-mapping.example.js +414 -0
- package/audit/index.d.ts +5 -1
- package/audit/index.js +29 -2
- package/audit/interceptors/audit-action.interceptor.d.ts +39 -0
- package/audit/interceptors/audit-action.interceptor.js +217 -0
- package/audit/interceptors/audit.interceptor.d.ts +1 -0
- package/audit/interceptors/audit.interceptor.js +19 -11
- package/audit/interceptors/index.d.ts +1 -0
- package/audit/interceptors/index.js +1 -0
- package/audit/interfaces/audit.interfaces.d.ts +132 -4
- package/audit/services/audit-action.service.d.ts +142 -0
- package/audit/services/audit-action.service.js +246 -0
- package/audit/services/audit-context.service.d.ts +91 -0
- package/audit/services/audit-context.service.js +170 -0
- package/audit/services/entity-audit.service.d.ts +220 -9
- package/audit/services/entity-audit.service.js +761 -72
- package/audit/services/index.d.ts +3 -0
- package/audit/services/index.js +3 -0
- package/audit/services/manual-audit-log.service.d.ts +23 -23
- package/audit/services/manual-audit-log.service.js +34 -57
- package/audit/services/multi-database.service.d.ts +0 -5
- package/audit/services/multi-database.service.js +0 -24
- package/audit/services/operation-description.service.d.ts +14 -3
- package/audit/services/operation-description.service.js +165 -26
- package/audit/services/transaction-audit.service.d.ts +1 -0
- package/audit/services/transaction-audit.service.js +12 -9
- package/audit/subscribers/entity-audit.subscriber.d.ts +5 -0
- package/audit/subscribers/entity-audit.subscriber.js +69 -5
- package/cache/cache.module.d.ts +7 -8
- package/cache/cache.module.js +15 -13
- package/cache/cache.service.d.ts +6 -4
- package/cache/cache.service.js +24 -12
- package/cache/decorators/cache-put.decorator.js +5 -4
- package/cache/dependencies/callback.dependency.js +9 -0
- package/cache/dependencies/db.dependency.d.ts +43 -12
- package/cache/dependencies/db.dependency.js +46 -18
- package/cache/dependencies/tag.dependency.d.ts +31 -4
- package/cache/dependencies/tag.dependency.js +100 -11
- package/cache/entities/index.d.ts +1 -0
- package/cache/entities/index.js +17 -0
- package/cache/entities/typeorm-cache.entity.d.ts +71 -0
- package/cache/entities/typeorm-cache.entity.js +110 -0
- package/cache/index.d.ts +2 -1
- package/cache/index.js +19 -2
- package/cache/interfaces/cache-options.interface.d.ts +8 -0
- package/cache/providers/index.d.ts +2 -1
- package/cache/providers/index.js +2 -1
- package/cache/providers/lrucache.provider.d.ts +77 -0
- package/cache/providers/lrucache.provider.js +228 -0
- package/cache/providers/redis-cache.provider.d.ts +1 -0
- package/cache/providers/redis-cache.provider.js +8 -6
- package/cache/providers/typeorm-cache.provider.d.ts +211 -0
- package/cache/providers/typeorm-cache.provider.js +483 -0
- package/common/boilerplate.polyfill.d.ts +1 -0
- package/common/boilerplate.polyfill.js +18 -1
- package/common/helpers/validation-metadata-helper.d.ts +112 -0
- package/common/helpers/validation-metadata-helper.js +164 -0
- package/common/index.d.ts +1 -0
- package/common/index.js +4 -0
- package/decorators/examples/field-i18n.example.d.ts +294 -0
- package/decorators/examples/field-i18n.example.js +478 -0
- package/decorators/field.decorators.d.ts +95 -3
- package/decorators/field.decorators.js +152 -18
- package/decorators/transform.decorators.d.ts +0 -2
- package/decorators/transform.decorators.js +0 -23
- package/decorators/translate.decorator.d.ts +26 -0
- package/decorators/translate.decorator.js +26 -1
- package/email-log/email-log.constants.d.ts +8 -0
- package/email-log/email-log.constants.js +11 -0
- package/email-log/email-log.module.d.ts +47 -0
- package/email-log/email-log.module.js +140 -0
- package/email-log/index.d.ts +11 -0
- package/email-log/index.js +48 -0
- package/email-log/interfaces/email-log-options.interface.d.ts +61 -0
- package/email-log/interfaces/email-log-options.interface.js +134 -0
- package/email-log/interfaces/email-log-transport.interface.d.ts +20 -0
- package/email-log/interfaces/email-log-transport.interface.js +2 -0
- package/email-log/interfaces/index.d.ts +2 -0
- package/email-log/interfaces/index.js +18 -0
- package/email-log/providers/email-provider.d.ts +42 -0
- package/email-log/providers/email-provider.js +127 -0
- package/email-log/providers/index.d.ts +1 -0
- package/email-log/providers/index.js +17 -0
- package/email-log/services/email-log-alert.service.d.ts +46 -0
- package/email-log/services/email-log-alert.service.js +162 -0
- package/email-log/services/email-log-formatter.service.d.ts +78 -0
- package/email-log/services/email-log-formatter.service.js +442 -0
- package/email-log/services/email-log-logger.service.d.ts +85 -0
- package/email-log/services/email-log-logger.service.js +168 -0
- package/email-log/services/email-log-rate-limiter.service.d.ts +42 -0
- package/email-log/services/email-log-rate-limiter.service.js +110 -0
- package/email-log/services/email-log-transport.service.d.ts +80 -0
- package/email-log/services/email-log-transport.service.js +271 -0
- package/email-log/services/index.d.ts +5 -0
- package/email-log/services/index.js +21 -0
- package/email-log/transports/index.d.ts +1 -0
- package/email-log/transports/index.js +17 -0
- package/email-log/transports/pino-email.transport.d.ts +56 -0
- package/email-log/transports/pino-email.transport.js +188 -0
- package/email-log/utils/index.d.ts +2 -0
- package/email-log/utils/index.js +18 -0
- package/email-log/utils/log-level.helper.d.ts +46 -0
- package/email-log/utils/log-level.helper.js +74 -0
- package/email-log/utils/pino-transport.utils.d.ts +135 -0
- package/email-log/utils/pino-transport.utils.js +238 -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/column.decorator.d.ts +151 -0
- package/file-upload/decorators/column.decorator.js +273 -0
- package/file-upload/decorators/csv-data.decorator.d.ts +30 -0
- package/file-upload/decorators/csv-data.decorator.js +85 -0
- package/file-upload/decorators/csv-import.decorator.d.ts +34 -0
- package/file-upload/decorators/csv-import.decorator.js +24 -0
- package/file-upload/decorators/examples/column-mapping.example.d.ts +76 -0
- package/file-upload/decorators/examples/column-mapping.example.js +122 -0
- package/file-upload/decorators/excel-data.decorator.d.ts +30 -0
- package/file-upload/decorators/excel-data.decorator.js +85 -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 +5 -0
- package/file-upload/decorators/index.js +38 -0
- package/file-upload/decorators/process.decorator.d.ts +40 -0
- package/file-upload/decorators/process.decorator.js +52 -0
- package/file-upload/decorators/validate-data.decorator.d.ts +91 -0
- package/file-upload/decorators/validate-data.decorator.js +39 -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 +15 -0
- package/file-upload/dto/update-file.dto.js +67 -0
- package/file-upload/entities/file-metadata.entity.d.ts +25 -0
- package/file-upload/entities/file-metadata.entity.js +76 -0
- package/file-upload/entities/file.entity.d.ts +114 -0
- package/file-upload/entities/file.entity.js +350 -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 +292 -0
- package/file-upload/index.d.ts +37 -0
- package/file-upload/index.js +77 -0
- package/file-upload/interceptors/file-upload.interceptor.d.ts +101 -0
- package/file-upload/interceptors/file-upload.interceptor.js +594 -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-processor.interface.d.ts +93 -0
- package/file-upload/interfaces/file-processor.interface.js +2 -0
- package/file-upload/interfaces/file-upload-options.interface.d.ts +74 -0
- package/file-upload/interfaces/file-upload-options.interface.js +5 -0
- package/file-upload/interfaces/index.d.ts +7 -0
- package/file-upload/interfaces/index.js +24 -0
- package/file-upload/interfaces/processor-options.interface.d.ts +102 -0
- package/file-upload/interfaces/processor-options.interface.js +2 -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/processors/csv.processor.d.ts +98 -0
- package/file-upload/processors/csv.processor.js +391 -0
- package/file-upload/processors/excel.processor.d.ts +130 -0
- package/file-upload/processors/excel.processor.js +547 -0
- package/file-upload/processors/image.processor.d.ts +199 -0
- package/file-upload/processors/image.processor.js +377 -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 +193 -0
- package/file-upload/services/file.service.js +638 -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 +300 -0
- package/file-upload/services/malicious-file-detector.service.js +1234 -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 +54 -0
- package/file-upload/utils/dynamic-import.util.js +156 -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/filters/bad-request.filter.d.ts +9 -0
- package/filters/bad-request.filter.js +57 -16
- package/http-client/config/http-client.config.d.ts +5 -0
- package/http-client/config/http-client.config.js +27 -14
- package/http-client/decorators/http-client.decorators.d.ts +7 -28
- package/http-client/decorators/http-client.decorators.js +124 -99
- package/http-client/entities/http-log.entity.d.ts +0 -20
- package/http-client/entities/http-log.entity.js +1 -21
- package/http-client/examples/advanced-usage.example.d.ts +4 -5
- package/http-client/examples/advanced-usage.example.js +7 -59
- package/http-client/examples/axios-config-extended.example.d.ts +17 -0
- package/http-client/examples/axios-config-extended.example.js +311 -0
- package/http-client/examples/flexible-response-example.d.ts +28 -0
- package/http-client/examples/flexible-response-example.js +120 -0
- package/http-client/examples/index.d.ts +2 -0
- package/http-client/examples/index.js +2 -0
- package/http-client/examples/proxy-from-environment.example.d.ts +133 -0
- package/http-client/examples/proxy-from-environment.example.js +409 -0
- package/http-client/examples/ssl-certificate.example.d.ts +47 -0
- package/http-client/examples/ssl-certificate.example.js +432 -0
- package/http-client/http-client.module.d.ts +43 -2
- package/http-client/http-client.module.js +150 -90
- package/http-client/index.d.ts +1 -1
- package/http-client/interfaces/api-client-config.interface.d.ts +24 -103
- package/http-client/interfaces/http-client-config.interface.d.ts +137 -62
- package/http-client/services/api-client-registry.service.d.ts +8 -21
- package/http-client/services/api-client-registry.service.js +31 -282
- package/http-client/services/circuit-breaker.service.d.ts +69 -2
- package/http-client/services/circuit-breaker.service.js +185 -7
- package/http-client/services/http-client.service.d.ts +85 -23
- package/http-client/services/http-client.service.js +512 -168
- package/http-client/services/http-log-query.service.js +0 -13
- package/http-client/services/index.d.ts +0 -1
- package/http-client/services/index.js +0 -1
- package/http-client/services/logging.service.d.ts +69 -16
- package/http-client/services/logging.service.js +290 -170
- package/http-client/utils/call-stack-extractor.util.d.ts +26 -0
- package/http-client/utils/call-stack-extractor.util.js +35 -0
- package/http-client/utils/context-extractor.util.d.ts +2 -0
- package/http-client/utils/context-extractor.util.js +17 -3
- package/http-client/utils/curl-generator.util.js +2 -5
- package/http-client/utils/index.d.ts +2 -0
- package/http-client/utils/index.js +2 -0
- package/http-client/utils/proxy-environment.util.d.ts +42 -0
- package/http-client/utils/proxy-environment.util.js +154 -0
- package/http-client/utils/retry-recorder.util.d.ts +0 -4
- package/http-client/utils/retry-recorder.util.js +2 -27
- package/http-client/utils/sanitize.util.d.ts +58 -0
- package/http-client/utils/sanitize.util.js +188 -0
- package/http-client/utils/security-validator.util.d.ts +118 -0
- package/http-client/utils/security-validator.util.js +354 -0
- package/index.d.ts +4 -1
- package/index.js +6 -1
- package/interceptors/translation-interceptor.service.d.ts +7 -0
- package/interceptors/translation-interceptor.service.js +40 -8
- package/ip-filter/constants.d.ts +21 -0
- package/ip-filter/constants.js +24 -0
- package/ip-filter/decorators/index.d.ts +1 -0
- package/ip-filter/decorators/index.js +17 -0
- package/ip-filter/decorators/ip-filter.decorator.d.ts +58 -0
- package/ip-filter/decorators/ip-filter.decorator.js +79 -0
- package/ip-filter/guards/index.d.ts +1 -0
- package/ip-filter/guards/index.js +17 -0
- package/ip-filter/guards/ip-filter.guard.d.ts +62 -0
- package/ip-filter/guards/ip-filter.guard.js +174 -0
- package/ip-filter/index.d.ts +7 -0
- package/ip-filter/index.js +23 -0
- package/ip-filter/interfaces/index.d.ts +4 -0
- package/ip-filter/interfaces/index.js +20 -0
- package/ip-filter/interfaces/ip-filter-async-options.interface.d.ts +15 -0
- package/ip-filter/interfaces/ip-filter-async-options.interface.js +2 -0
- package/ip-filter/interfaces/ip-filter-metadata.interface.d.ts +26 -0
- package/ip-filter/interfaces/ip-filter-metadata.interface.js +2 -0
- package/ip-filter/interfaces/ip-filter-options.interface.d.ts +34 -0
- package/ip-filter/interfaces/ip-filter-options.interface.js +2 -0
- package/ip-filter/interfaces/ip-rule.interface.d.ts +36 -0
- package/ip-filter/interfaces/ip-rule.interface.js +2 -0
- package/ip-filter/ip-filter.module.d.ts +55 -0
- package/ip-filter/ip-filter.module.js +105 -0
- package/ip-filter/services/index.d.ts +1 -0
- package/ip-filter/services/index.js +17 -0
- package/ip-filter/services/ip-filter.service.d.ts +92 -0
- package/ip-filter/services/ip-filter.service.js +238 -0
- package/ip-filter/utils/index.d.ts +1 -0
- package/ip-filter/utils/index.js +17 -0
- package/ip-filter/utils/ip-utils.d.ts +61 -0
- package/ip-filter/utils/ip-utils.js +162 -0
- package/package.json +34 -29
- package/providers/context.provider.d.ts +9 -0
- package/providers/context.provider.js +13 -0
- package/redis-lock/comprehensive-lock-cleanup.service.d.ts +94 -0
- package/redis-lock/comprehensive-lock-cleanup.service.js +253 -0
- package/redis-lock/index.d.ts +2 -0
- package/redis-lock/index.js +5 -1
- package/redis-lock/lock-heartbeat.service.d.ts +80 -0
- package/redis-lock/lock-heartbeat.service.js +232 -0
- package/redis-lock/redis-lock.module.d.ts +6 -0
- package/redis-lock/redis-lock.module.js +136 -77
- package/redis-lock/redis-lock.service.d.ts +31 -0
- package/redis-lock/redis-lock.service.js +124 -17
- package/setup/bootstrap.setup.d.ts +2 -1
- package/setup/bootstrap.setup.js +3 -2
- package/setup/index.d.ts +1 -0
- package/setup/index.js +1 -0
- package/setup/run-in-mode.decorator.d.ts +56 -0
- package/setup/run-in-mode.decorator.js +92 -0
- package/setup/schedule.decorator.d.ts +1 -0
- package/setup/schedule.decorator.js +28 -13
- package/setup/worker.decorator.js +10 -1
- package/shared/index.d.ts +1 -1
- package/shared/index.js +1 -1
- package/shared/{serviceRegistryModule.js → service-registry.module.js} +28 -17
- package/shared/services/api-config.service.d.ts +41 -0
- package/shared/services/api-config.service.js +175 -8
- package/shared/services/index.d.ts +0 -1
- package/shared/services/index.js +0 -1
- package/validators/custom-validate.validator.d.ts +1 -0
- package/validators/custom-validate.validator.js +1 -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 +15 -6
- package/validators/is-exists.validator.js +8 -7
- package/validators/is-unique.validator.d.ts +22 -7
- package/validators/is-unique.validator.js +41 -17
- package/vault/vault-config.service.js +1 -1
- package/cache/providers/memory-cache.provider.d.ts +0 -49
- package/cache/providers/memory-cache.provider.js +0 -197
- package/http-client/services/cache.service.d.ts +0 -76
- package/http-client/services/cache.service.js +0 -333
- 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
|
@@ -21,7 +21,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
21
21
|
});
|
|
22
22
|
};
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.EntityAuditService = void 0;
|
|
24
|
+
exports.EntityAuditService = exports.AUDIT_CONSTANTS = void 0;
|
|
25
|
+
exports.registerEntityClass = registerEntityClass;
|
|
26
|
+
exports.getEntityClass = getEntityClass;
|
|
25
27
|
const common_1 = require("@nestjs/common");
|
|
26
28
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
27
29
|
const typeorm_2 = require("typeorm");
|
|
@@ -31,19 +33,56 @@ const enums_1 = require("../enums");
|
|
|
31
33
|
const audit_context_service_1 = require("./audit-context.service");
|
|
32
34
|
const audit_strategy_service_1 = require("./audit-strategy.service");
|
|
33
35
|
const multi_database_service_1 = require("./multi-database.service");
|
|
36
|
+
const operation_description_service_1 = require("./operation-description.service");
|
|
34
37
|
const dto_1 = require("../../common/dto");
|
|
38
|
+
const entity_audit_decorator_1 = require("../decorators/entity-audit.decorator");
|
|
39
|
+
const transaction_1 = require("@nest-omni/transaction");
|
|
40
|
+
/**
|
|
41
|
+
* 审计配置常量
|
|
42
|
+
*/
|
|
43
|
+
exports.AUDIT_CONSTANTS = {
|
|
44
|
+
/** 深度比较的最大深度限制 */
|
|
45
|
+
MAX_DIFF_DEPTH: 5,
|
|
46
|
+
/** 深度比较的最大键数量限制 */
|
|
47
|
+
MAX_KEYS: 100,
|
|
48
|
+
/** 描述的最大长度 */
|
|
49
|
+
MAX_DESCRIPTION_LENGTH: 1000,
|
|
50
|
+
/** 哈希截断长度 */
|
|
51
|
+
HASH_TRUNCATE_LENGTH: 64,
|
|
52
|
+
/** 部分掩码显示的字符数 */
|
|
53
|
+
PARTIAL_MASK_CHARS: 2,
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* 实体类注册表 - 用于在运行时通过 entityType 字符串获取实体类引用
|
|
57
|
+
*/
|
|
58
|
+
const ENTITY_CLASS_REGISTRY = new Map();
|
|
59
|
+
/**
|
|
60
|
+
* 注册实体类到注册表
|
|
61
|
+
*/
|
|
62
|
+
function registerEntityClass(entityType, entityClass) {
|
|
63
|
+
ENTITY_CLASS_REGISTRY.set(entityType, entityClass);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 获取实体类
|
|
67
|
+
*/
|
|
68
|
+
function getEntityClass(entityType) {
|
|
69
|
+
return ENTITY_CLASS_REGISTRY.get(entityType);
|
|
70
|
+
}
|
|
35
71
|
/**
|
|
36
72
|
* 实体审计服务
|
|
37
73
|
*/
|
|
38
74
|
let EntityAuditService = class EntityAuditService {
|
|
39
|
-
constructor(auditLogRepository, transactionRepository, entityManager, contextService, multiDbService, auditStrategy = new audit_strategy_service_1.DefaultAuditStrategy(), config, auditConnectionName) {
|
|
75
|
+
constructor(auditLogRepository, transactionRepository, manualOperationRepository, entityManager, contextService, multiDbService, auditStrategy = new audit_strategy_service_1.DefaultAuditStrategy(), config, auditConnectionName, actionSummaryRepository, descriptionService) {
|
|
40
76
|
this.auditLogRepository = auditLogRepository;
|
|
41
77
|
this.transactionRepository = transactionRepository;
|
|
78
|
+
this.manualOperationRepository = manualOperationRepository;
|
|
42
79
|
this.entityManager = entityManager;
|
|
43
80
|
this.contextService = contextService;
|
|
44
81
|
this.multiDbService = multiDbService;
|
|
45
82
|
this.auditStrategy = auditStrategy;
|
|
46
83
|
this.config = config;
|
|
84
|
+
this.actionSummaryRepository = actionSummaryRepository;
|
|
85
|
+
this.descriptionService = descriptionService;
|
|
47
86
|
this.auditConnectionName = auditConnectionName || 'default';
|
|
48
87
|
}
|
|
49
88
|
/**
|
|
@@ -51,7 +90,6 @@ let EntityAuditService = class EntityAuditService {
|
|
|
51
90
|
*/
|
|
52
91
|
logEntityChange(entityType_1, entityId_1, operation_1, oldValue_1, newValue_1) {
|
|
53
92
|
return __awaiter(this, arguments, void 0, function* (entityType, entityId, operation, oldValue, newValue, metadata = {}) {
|
|
54
|
-
var _a, _b;
|
|
55
93
|
// 检查是否应该记录
|
|
56
94
|
if (!this.auditStrategy.shouldRecord(entityType, operation)) {
|
|
57
95
|
return null;
|
|
@@ -68,9 +106,19 @@ let EntityAuditService = class EntityAuditService {
|
|
|
68
106
|
const filteredNewValue = this.filterAndMaskFields(newValue, fieldFilter);
|
|
69
107
|
// 计算变更字段
|
|
70
108
|
const changedFields = this.calculateChangedFields(filteredOldValue, filteredNewValue);
|
|
71
|
-
|
|
109
|
+
// 生成字段级别的变更详情(前后对比)
|
|
110
|
+
// CREATE 操作不需要 changeDetails,因为只有新值没有旧值
|
|
111
|
+
const changeDetails = operation === enums_1.AuditOperation.CREATE
|
|
112
|
+
? undefined
|
|
113
|
+
: this.generateChangeDetails(entityType, filteredOldValue, filteredNewValue, changedFields);
|
|
72
114
|
// 获取上下文信息
|
|
73
115
|
const context = yield this.contextService.getCurrentContext();
|
|
116
|
+
// 准备模板键和参数
|
|
117
|
+
const templateKey = metadata.operationTemplateKey || `${entityType}.${operation.toLowerCase()}`;
|
|
118
|
+
const descriptionParams = Object.assign({ entityType,
|
|
119
|
+
entityId, operation: operation.toLowerCase(), changedFields: changedFields.join(', '), changedFieldsCount: changedFields.length }, metadata.descriptionParams);
|
|
120
|
+
// 生成描述(优先使用模板)
|
|
121
|
+
const description = yield this.generateDescriptionFromTemplate(templateKey, descriptionParams, operation, entityType, entityId, changedFields);
|
|
74
122
|
// 创建审计日志
|
|
75
123
|
const auditLog = this.auditLogRepository.create({
|
|
76
124
|
entityType,
|
|
@@ -79,16 +127,19 @@ let EntityAuditService = class EntityAuditService {
|
|
|
79
127
|
oldValue: filteredOldValue,
|
|
80
128
|
newValue: filteredNewValue,
|
|
81
129
|
changedFields,
|
|
82
|
-
|
|
130
|
+
changeDetails,
|
|
83
131
|
userId: context.userId || metadata.userId,
|
|
84
132
|
username: context.username || metadata.username,
|
|
85
133
|
requestId: context.requestId || metadata.requestId,
|
|
86
134
|
requestIp: context.requestIp || metadata.requestIp,
|
|
87
135
|
userAgent: context.userAgent || metadata.userAgent,
|
|
88
|
-
description
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
136
|
+
description,
|
|
137
|
+
operationTemplateKey: templateKey,
|
|
138
|
+
descriptionParams,
|
|
139
|
+
// 新增:审计动作关联字段
|
|
140
|
+
auditActionId: metadata.auditActionId,
|
|
141
|
+
auditActionName: metadata.auditActionName,
|
|
142
|
+
sequenceInAction: metadata.sequenceInAction || 0,
|
|
92
143
|
});
|
|
93
144
|
// 保存变更日志
|
|
94
145
|
const savedLog = yield this.auditLogRepository.save(auditLog);
|
|
@@ -193,7 +244,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
193
244
|
}
|
|
194
245
|
// 获取当前实体状态
|
|
195
246
|
const repository = this.entityManager.getRepository(entityType);
|
|
196
|
-
const currentEntity = yield repository.findOne({
|
|
247
|
+
const currentEntity = yield repository.findOne({
|
|
248
|
+
where: { id: entityId },
|
|
249
|
+
});
|
|
197
250
|
if (!currentEntity) {
|
|
198
251
|
return {
|
|
199
252
|
canRestore: false,
|
|
@@ -241,7 +294,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
241
294
|
try {
|
|
242
295
|
// 获取指定的数据库连接
|
|
243
296
|
const connectionName = options.connectionName || 'default';
|
|
244
|
-
const dataSource =
|
|
297
|
+
const dataSource = (0, transaction_1.getDataSource)(connectionName);
|
|
245
298
|
const repository = dataSource.getRepository(entityType);
|
|
246
299
|
// 恢复实体
|
|
247
300
|
const restoreData = Object.assign({}, auditLog.oldValue);
|
|
@@ -279,34 +332,91 @@ let EntityAuditService = class EntityAuditService {
|
|
|
279
332
|
});
|
|
280
333
|
}
|
|
281
334
|
/**
|
|
282
|
-
*
|
|
335
|
+
* 计算变更字段(支持嵌套路径)
|
|
283
336
|
*/
|
|
284
337
|
calculateChangedFields(oldValue, newValue) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
for (const field of allFields) {
|
|
290
|
-
const oldVal = oldValue === null || oldValue === void 0 ? void 0 : oldValue[field];
|
|
291
|
-
const newVal = newValue === null || newValue === void 0 ? void 0 : newValue[field];
|
|
292
|
-
if (!this.deepEqual(oldVal, newVal)) {
|
|
293
|
-
changedFields.push(field);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
return changedFields;
|
|
338
|
+
// 使用 deepDiff 获取所有变更,包括嵌套字段
|
|
339
|
+
const diffChanges = this.deepDiff(oldValue, newValue);
|
|
340
|
+
// 将路径数组转换为点号分隔的字符串
|
|
341
|
+
return diffChanges.map(change => change.path.join('.'));
|
|
297
342
|
}
|
|
298
343
|
/**
|
|
299
|
-
*
|
|
344
|
+
* 生成字段级别的变更详情(前后对比,支持嵌套路径和装饰器值映射)
|
|
300
345
|
*/
|
|
301
|
-
|
|
302
|
-
const
|
|
303
|
-
//
|
|
304
|
-
const
|
|
305
|
-
//
|
|
306
|
-
|
|
307
|
-
|
|
346
|
+
generateChangeDetails(entityType, oldValue, newValue, changedFields) {
|
|
347
|
+
const changeDetails = [];
|
|
348
|
+
// 使用 deepDiff 获取详细变更信息
|
|
349
|
+
const diffChanges = this.deepDiff(oldValue, newValue);
|
|
350
|
+
// 尝试获取实体类(用于装饰器值映射)
|
|
351
|
+
const entityClass = getEntityClass(entityType);
|
|
352
|
+
for (const change of diffChanges) {
|
|
353
|
+
const pathStr = change.path.join('.');
|
|
354
|
+
const oldVal = change.oldValue;
|
|
355
|
+
const newVal = change.newValue;
|
|
356
|
+
const fieldName = change.path[0]; // 顶层字段名
|
|
357
|
+
// 确定变更类型
|
|
358
|
+
let changeType;
|
|
359
|
+
if (change.type === 'ADD') {
|
|
360
|
+
changeType = enums_1.ChangeType.ADDED;
|
|
361
|
+
}
|
|
362
|
+
else if (change.type === 'REMOVE') {
|
|
363
|
+
changeType = enums_1.ChangeType.REMOVED;
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
changeType = enums_1.ChangeType.MODIFIED;
|
|
367
|
+
}
|
|
368
|
+
// 尝试从装饰器获取字段标签(支持多语言)
|
|
369
|
+
let fieldLabels;
|
|
370
|
+
let displayOldValue;
|
|
371
|
+
let displayNewValue;
|
|
372
|
+
if (entityClass) {
|
|
373
|
+
try {
|
|
374
|
+
// 获取字段标签(多语言)
|
|
375
|
+
const supportedLanguages = ['zh', 'en', 'ja'];
|
|
376
|
+
fieldLabels = {};
|
|
377
|
+
for (const lang of supportedLanguages) {
|
|
378
|
+
const label = (0, entity_audit_decorator_1.getFieldLabel)(entityClass, pathStr, lang);
|
|
379
|
+
if (label && label !== pathStr) {
|
|
380
|
+
fieldLabels[lang] = label;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
// 获取字段值的标签(多语言值映射)
|
|
384
|
+
if (oldVal !== null && oldVal !== undefined) {
|
|
385
|
+
const oldValueLabel = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, fieldName, oldVal, 'zh');
|
|
386
|
+
if (oldValueLabel !== oldVal) {
|
|
387
|
+
// 如果有映射值,创建多语言映射
|
|
388
|
+
displayOldValue = {};
|
|
389
|
+
for (const lang of supportedLanguages) {
|
|
390
|
+
displayOldValue[lang] = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, fieldName, oldVal, lang);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (newVal !== null && newVal !== undefined) {
|
|
395
|
+
const newValueLabel = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, fieldName, newVal, 'zh');
|
|
396
|
+
if (newValueLabel !== newVal) {
|
|
397
|
+
// 如果有映射值,创建多语言映射
|
|
398
|
+
displayNewValue = {};
|
|
399
|
+
for (const lang of supportedLanguages) {
|
|
400
|
+
displayNewValue[lang] = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, fieldName, newVal, lang);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
// 忽略错误,使用默认值
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
changeDetails.push({
|
|
410
|
+
fieldName: pathStr,
|
|
411
|
+
fieldLabels: Object.keys(fieldLabels || {}).length > 0 ? fieldLabels : undefined,
|
|
412
|
+
oldValue: oldVal,
|
|
413
|
+
newValue: newVal,
|
|
414
|
+
displayOldValue,
|
|
415
|
+
displayNewValue,
|
|
416
|
+
changeType,
|
|
417
|
+
});
|
|
308
418
|
}
|
|
309
|
-
return
|
|
419
|
+
return changeDetails;
|
|
310
420
|
}
|
|
311
421
|
/**
|
|
312
422
|
* 深度比较对象
|
|
@@ -337,10 +447,10 @@ let EntityAuditService = class EntityAuditService {
|
|
|
337
447
|
/**
|
|
338
448
|
* 深度差异比较
|
|
339
449
|
*/
|
|
340
|
-
deepDiff(oldObj, newObj, path = []) {
|
|
341
|
-
var _a;
|
|
450
|
+
deepDiff(oldObj, newObj, path = [], visited = new WeakSet()) {
|
|
451
|
+
var _a, _b;
|
|
342
452
|
const changes = [];
|
|
343
|
-
const maxDepth = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.maxDiffDepth)
|
|
453
|
+
const maxDepth = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.maxDiffDepth) !== null && _b !== void 0 ? _b : exports.AUDIT_CONSTANTS.MAX_DIFF_DEPTH;
|
|
344
454
|
// 防止过深
|
|
345
455
|
if (path.length > maxDepth) {
|
|
346
456
|
return changes;
|
|
@@ -357,6 +467,19 @@ let EntityAuditService = class EntityAuditService {
|
|
|
357
467
|
}
|
|
358
468
|
return changes;
|
|
359
469
|
}
|
|
470
|
+
// 检测循环引用
|
|
471
|
+
if (visited.has(oldObj)) {
|
|
472
|
+
// 检测到循环引用,停止递归
|
|
473
|
+
return changes;
|
|
474
|
+
}
|
|
475
|
+
visited.add(oldObj);
|
|
476
|
+
// 如果newObj也是对象,也加入访问集合
|
|
477
|
+
if (typeof newObj === 'object' && newObj !== null) {
|
|
478
|
+
if (visited.has(newObj)) {
|
|
479
|
+
return changes;
|
|
480
|
+
}
|
|
481
|
+
visited.add(newObj);
|
|
482
|
+
}
|
|
360
483
|
// 处理数组
|
|
361
484
|
if (Array.isArray(oldObj)) {
|
|
362
485
|
if (!Array.isArray(newObj)) {
|
|
@@ -378,12 +501,22 @@ let EntityAuditService = class EntityAuditService {
|
|
|
378
501
|
return changes;
|
|
379
502
|
}
|
|
380
503
|
for (let i = 0; i < oldObj.length; i++) {
|
|
381
|
-
changes.push(...this.deepDiff(oldObj[i], newObj[i], [...path, i.toString()]));
|
|
504
|
+
changes.push(...this.deepDiff(oldObj[i], newObj[i], [...path, i.toString()], visited));
|
|
382
505
|
}
|
|
383
506
|
return changes;
|
|
384
507
|
}
|
|
385
508
|
// 处理对象
|
|
386
509
|
const allKeys = new Set([...Object.keys(oldObj), ...Object.keys(newObj)]);
|
|
510
|
+
// 添加键数量限制,防止内存溢出
|
|
511
|
+
if (allKeys.size > exports.AUDIT_CONSTANTS.MAX_KEYS) {
|
|
512
|
+
changes.push({
|
|
513
|
+
path,
|
|
514
|
+
type: 'CHANGE',
|
|
515
|
+
oldValue: `[Object with too many keys: ${allKeys.size}]`,
|
|
516
|
+
newValue: `[Object with too many keys: ${allKeys.size}]`,
|
|
517
|
+
});
|
|
518
|
+
return changes;
|
|
519
|
+
}
|
|
387
520
|
for (const key of allKeys) {
|
|
388
521
|
const oldVal = oldObj[key];
|
|
389
522
|
const newVal = newObj[key];
|
|
@@ -404,7 +537,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
404
537
|
});
|
|
405
538
|
}
|
|
406
539
|
else {
|
|
407
|
-
changes.push(...this.deepDiff(oldVal, newVal, [...path, key]));
|
|
540
|
+
changes.push(...this.deepDiff(oldVal, newVal, [...path, key], visited));
|
|
408
541
|
}
|
|
409
542
|
}
|
|
410
543
|
return changes;
|
|
@@ -490,40 +623,46 @@ let EntityAuditService = class EntityAuditService {
|
|
|
490
623
|
*/
|
|
491
624
|
partialMaskValue(value) {
|
|
492
625
|
const strValue = String(value);
|
|
493
|
-
|
|
626
|
+
const maskChars = exports.AUDIT_CONSTANTS.PARTIAL_MASK_CHARS;
|
|
627
|
+
if (strValue.length <= maskChars * 2) {
|
|
494
628
|
return '*'.repeat(strValue.length);
|
|
495
629
|
}
|
|
496
|
-
return (strValue.substring(0,
|
|
497
|
-
'*'.repeat(strValue.length -
|
|
498
|
-
strValue.substring(strValue.length -
|
|
630
|
+
return (strValue.substring(0, maskChars) +
|
|
631
|
+
'*'.repeat(strValue.length - maskChars * 2) +
|
|
632
|
+
strValue.substring(strValue.length - maskChars));
|
|
499
633
|
}
|
|
500
634
|
/**
|
|
501
|
-
*
|
|
635
|
+
* 生成描述(支持多语言)
|
|
636
|
+
* @param operation 操作类型
|
|
637
|
+
* @param entityType 实体类型
|
|
638
|
+
* @param entityId 实体ID
|
|
639
|
+
* @param changedFields 变更字段列表
|
|
640
|
+
* @param language 语言(默认中文)
|
|
641
|
+
* @param entityClass 实体类(可选,用于获取实体标签)
|
|
502
642
|
*/
|
|
503
|
-
|
|
643
|
+
/**
|
|
644
|
+
* 使用模板生成描述(优先使用 OperationDescriptionService)
|
|
645
|
+
*/
|
|
646
|
+
generateDescriptionFromTemplate(templateKey, descriptionParams, operation, entityType, entityId, changedFields) {
|
|
504
647
|
return __awaiter(this, void 0, void 0, function* () {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
};
|
|
648
|
+
// 优先尝试使用 OperationDescriptionService
|
|
649
|
+
if (this.descriptionService) {
|
|
650
|
+
try {
|
|
651
|
+
const templateDescription = yield this.descriptionService.generateDescription(templateKey, descriptionParams, 'zh');
|
|
652
|
+
// 如果成功获取到模板描述且不是原始的 templateKey,则使用它
|
|
653
|
+
if (templateDescription && templateDescription !== templateKey) {
|
|
654
|
+
return templateDescription;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
catch (error) {
|
|
658
|
+
// 模板服务失败,降级到原有方式
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
// 降级:使用原有的描述生成逻辑
|
|
662
|
+
return this.generateDescription(operation, entityType, entityId, changedFields);
|
|
521
663
|
});
|
|
522
664
|
}
|
|
523
|
-
|
|
524
|
-
* 生成描述
|
|
525
|
-
*/
|
|
526
|
-
generateDescription(operation, entityType, entityId, changedFields) {
|
|
665
|
+
generateDescription(operation, entityType, entityId, changedFields, language = 'zh', entityClass) {
|
|
527
666
|
const operationText = {
|
|
528
667
|
[enums_1.AuditOperation.CREATE]: '创建',
|
|
529
668
|
[enums_1.AuditOperation.UPDATE]: '更新',
|
|
@@ -531,10 +670,32 @@ let EntityAuditService = class EntityAuditService {
|
|
|
531
670
|
[enums_1.AuditOperation.RESTORE]: '恢复',
|
|
532
671
|
};
|
|
533
672
|
const text = operationText[operation] || operation;
|
|
673
|
+
// 尝试获取实体的多语言标签
|
|
674
|
+
let entityLabel = entityType;
|
|
675
|
+
if (entityClass) {
|
|
676
|
+
try {
|
|
677
|
+
entityLabel = (0, entity_audit_decorator_1.getEntityLabel)(entityClass, language);
|
|
678
|
+
}
|
|
679
|
+
catch (error) {
|
|
680
|
+
// 忽略错误,使用默认的 entityType
|
|
681
|
+
}
|
|
682
|
+
}
|
|
534
683
|
if (operation === enums_1.AuditOperation.UPDATE && changedFields.length > 0) {
|
|
535
|
-
|
|
684
|
+
// 对于更新操作,显示哪些字段发生了变化
|
|
685
|
+
const fieldLabels = changedFields.map(field => {
|
|
686
|
+
if (entityClass) {
|
|
687
|
+
try {
|
|
688
|
+
return (0, entity_audit_decorator_1.getFieldLabel)(entityClass, field, language);
|
|
689
|
+
}
|
|
690
|
+
catch (error) {
|
|
691
|
+
return field;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
return field;
|
|
695
|
+
});
|
|
696
|
+
return `${text}${entityLabel}(${entityId}), 变更字段: ${fieldLabels.join('、')}`;
|
|
536
697
|
}
|
|
537
|
-
return `${text}
|
|
698
|
+
return `${text}${entityLabel}(${entityId})`;
|
|
538
699
|
}
|
|
539
700
|
/**
|
|
540
701
|
* 检测冲突
|
|
@@ -554,22 +715,550 @@ let EntityAuditService = class EntityAuditService {
|
|
|
554
715
|
}
|
|
555
716
|
return conflicts;
|
|
556
717
|
}
|
|
718
|
+
// ========== 新增方法:支持模板和手动操作 ==========
|
|
719
|
+
/**
|
|
720
|
+
* 增强的记录实体变更(支持模板和结构化变更详情)
|
|
721
|
+
* @param data 审计数据
|
|
722
|
+
* @returns 审计日志实体
|
|
723
|
+
*/
|
|
724
|
+
logEntityChangeWithTemplate(data) {
|
|
725
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
726
|
+
var _a, _b, _c, _d, _e;
|
|
727
|
+
// 检查是否应该记录
|
|
728
|
+
if (!this.auditStrategy.shouldRecord(data.entityType, data.operation)) {
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
// 获取记录策略
|
|
732
|
+
const recordStrategy = this.auditStrategy.getRecordStrategy(data.entityType, data.operation);
|
|
733
|
+
if (recordStrategy === enums_1.RecordStrategy.DISABLED) {
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
// 获取字段过滤器
|
|
737
|
+
const fieldFilter = this.auditStrategy.getFieldFilter(data.entityType);
|
|
738
|
+
// 过滤和脱敏字段
|
|
739
|
+
const filteredOldValue = this.filterAndMaskFields(data.oldValue || {}, fieldFilter);
|
|
740
|
+
const filteredNewValue = this.filterAndMaskFields(data.newValue || {}, fieldFilter);
|
|
741
|
+
// 计算变更字段
|
|
742
|
+
const changedFields = data.changedFields || this.calculateChangedFields(filteredOldValue, filteredNewValue);
|
|
743
|
+
// 获取上下文信息
|
|
744
|
+
const context = yield this.contextService.getCurrentContext();
|
|
745
|
+
// 如果没有提供操作模板键,使用默认模板
|
|
746
|
+
const operationTemplateKey = data.operationTemplateKey || `${data.entityType}.${data.operation}`;
|
|
747
|
+
// 如果没有提供描述参数,使用实体数据
|
|
748
|
+
const descriptionParams = data.descriptionParams || Object.assign(Object.assign(Object.assign({}, filteredOldValue), filteredNewValue), { changedFields, changedFieldsCount: changedFields.length });
|
|
749
|
+
// 创建审计日志
|
|
750
|
+
const auditLog = this.auditLogRepository.create({
|
|
751
|
+
entityType: data.entityType,
|
|
752
|
+
entityId: data.entityId,
|
|
753
|
+
operation: data.operation,
|
|
754
|
+
oldValue: filteredOldValue,
|
|
755
|
+
newValue: filteredNewValue,
|
|
756
|
+
changedFields,
|
|
757
|
+
userId: context.userId || ((_a = data.metadata) === null || _a === void 0 ? void 0 : _a.userId),
|
|
758
|
+
username: context.username || ((_b = data.metadata) === null || _b === void 0 ? void 0 : _b.username),
|
|
759
|
+
requestId: context.requestId || ((_c = data.metadata) === null || _c === void 0 ? void 0 : _c.requestId),
|
|
760
|
+
requestIp: context.requestIp || ((_d = data.metadata) === null || _d === void 0 ? void 0 : _d.requestIp),
|
|
761
|
+
userAgent: context.userAgent || ((_e = data.metadata) === null || _e === void 0 ? void 0 : _e.userAgent),
|
|
762
|
+
description: this.generateDescription(data.operation, data.entityType, data.entityId, changedFields),
|
|
763
|
+
// 新增字段
|
|
764
|
+
operationTemplateKey,
|
|
765
|
+
descriptionParams,
|
|
766
|
+
changeDetails: data.changeDetails,
|
|
767
|
+
});
|
|
768
|
+
// 保存变更日志
|
|
769
|
+
const savedLog = yield this.auditLogRepository.save(auditLog);
|
|
770
|
+
return savedLog;
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* 记录手动操作
|
|
775
|
+
* @param data 手动操作数据
|
|
776
|
+
* @returns 手动操作日志实体
|
|
777
|
+
*/
|
|
778
|
+
logManualOperation(data) {
|
|
779
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
780
|
+
// 获取上下文信息
|
|
781
|
+
const context = yield this.contextService.getCurrentContext();
|
|
782
|
+
const manualLog = this.manualOperationRepository.create({
|
|
783
|
+
transactionId: data.transactionId,
|
|
784
|
+
operationTemplateKey: data.operationTemplateKey,
|
|
785
|
+
descriptionParams: data.descriptionParams,
|
|
786
|
+
userId: data.userId || context.userId,
|
|
787
|
+
username: data.username || context.username,
|
|
788
|
+
requestIp: data.requestIp || context.requestIp,
|
|
789
|
+
});
|
|
790
|
+
return yield this.manualOperationRepository.save(manualLog);
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* 在事务中执行操作
|
|
795
|
+
* @param fn 执行函数
|
|
796
|
+
* @param options 事务选项
|
|
797
|
+
* @returns 执���结果
|
|
798
|
+
*/
|
|
799
|
+
withTransaction(fn, options) {
|
|
800
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
801
|
+
var _a;
|
|
802
|
+
// 获取上下文信息
|
|
803
|
+
const context = yield this.contextService.getCurrentContext();
|
|
804
|
+
// 创建事务
|
|
805
|
+
const transaction = this.transactionRepository.create({
|
|
806
|
+
description: ((_a = options === null || options === void 0 ? void 0 : options.descriptionParams) === null || _a === void 0 ? void 0 : _a.description) || 'Transaction',
|
|
807
|
+
status: 'PENDING',
|
|
808
|
+
entities: [],
|
|
809
|
+
userId: (options === null || options === void 0 ? void 0 : options.userId) || context.userId,
|
|
810
|
+
username: (options === null || options === void 0 ? void 0 : options.username) || context.username,
|
|
811
|
+
requestIp: (options === null || options === void 0 ? void 0 : options.requestIp) || context.requestIp,
|
|
812
|
+
operationTemplateKey: options === null || options === void 0 ? void 0 : options.operationTemplateKey,
|
|
813
|
+
descriptionParams: options === null || options === void 0 ? void 0 : options.descriptionParams,
|
|
814
|
+
metadata: options === null || options === void 0 ? void 0 : options.metadata,
|
|
815
|
+
});
|
|
816
|
+
const savedTransaction = yield this.transactionRepository.save(transaction);
|
|
817
|
+
const transactionId = savedTransaction.id;
|
|
818
|
+
try {
|
|
819
|
+
// 设置事务ID到上下文
|
|
820
|
+
yield this.contextService.setContext(Object.assign(Object.assign({}, context), { transactionId }));
|
|
821
|
+
// 执行操作
|
|
822
|
+
const result = yield fn(transactionId);
|
|
823
|
+
// 提交事务
|
|
824
|
+
yield this.transactionRepository.update(transactionId, {
|
|
825
|
+
status: 'COMMITTED',
|
|
826
|
+
completedAt: new Date(),
|
|
827
|
+
});
|
|
828
|
+
return result;
|
|
829
|
+
}
|
|
830
|
+
catch (error) {
|
|
831
|
+
// 回滚事务
|
|
832
|
+
yield this.transactionRepository.update(transactionId, {
|
|
833
|
+
status: 'ROLLED_BACK',
|
|
834
|
+
completedAt: new Date(),
|
|
835
|
+
});
|
|
836
|
+
throw error;
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* 获取当前事务ID
|
|
842
|
+
* @returns 当前事务ID或null
|
|
843
|
+
*/
|
|
844
|
+
getCurrentTransactionId() {
|
|
845
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
846
|
+
const context = yield this.contextService.getCurrentContext();
|
|
847
|
+
return context.transactionId || null;
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* 设置当前事务ID
|
|
852
|
+
* @param transactionId 事务ID
|
|
853
|
+
*/
|
|
854
|
+
setCurrentTransactionId(transactionId) {
|
|
855
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
856
|
+
const context = yield this.contextService.getCurrentContext();
|
|
857
|
+
yield this.contextService.setContext(Object.assign(Object.assign({}, context), { transactionId }));
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* 开始事务
|
|
862
|
+
* @param userId 用户ID
|
|
863
|
+
* @param userName 用户名
|
|
864
|
+
* @param ip IP地址
|
|
865
|
+
* @param operationTemplateKey 操作模板键
|
|
866
|
+
* @param descriptionParams 描述参数
|
|
867
|
+
* @returns 事务ID
|
|
868
|
+
*/
|
|
869
|
+
beginTransaction(userId, userName, ip, operationTemplateKey, descriptionParams) {
|
|
870
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
871
|
+
// 获取上下文信息
|
|
872
|
+
const context = yield this.contextService.getCurrentContext();
|
|
873
|
+
// 创建事务
|
|
874
|
+
const transaction = this.transactionRepository.create({
|
|
875
|
+
description: (descriptionParams === null || descriptionParams === void 0 ? void 0 : descriptionParams.description) || 'Transaction',
|
|
876
|
+
status: 'pending',
|
|
877
|
+
entities: [],
|
|
878
|
+
userId: userId || context.userId,
|
|
879
|
+
username: userName || context.username,
|
|
880
|
+
requestIp: ip || context.requestIp,
|
|
881
|
+
operationTemplateKey,
|
|
882
|
+
descriptionParams,
|
|
883
|
+
});
|
|
884
|
+
const savedTransaction = yield this.transactionRepository.save(transaction);
|
|
885
|
+
return savedTransaction.id;
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* 提交事务
|
|
890
|
+
* @param transactionId 事务ID
|
|
891
|
+
*/
|
|
892
|
+
commitTransaction(transactionId) {
|
|
893
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
894
|
+
yield this.transactionRepository.update(transactionId, {
|
|
895
|
+
status: 'committed',
|
|
896
|
+
completedAt: new Date(),
|
|
897
|
+
});
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* 回滚事务
|
|
902
|
+
* @param transactionId 事务ID
|
|
903
|
+
*/
|
|
904
|
+
rollbackTransaction(transactionId) {
|
|
905
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
906
|
+
yield this.transactionRepository.update(transactionId, {
|
|
907
|
+
status: 'rolled_back',
|
|
908
|
+
completedAt: new Date(),
|
|
909
|
+
});
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* 查询审计动作汇总记录
|
|
914
|
+
*/
|
|
915
|
+
getAuditActions(options) {
|
|
916
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
917
|
+
if (!this.actionSummaryRepository) {
|
|
918
|
+
throw new Error('AuditActionSummaryEntity repository not available');
|
|
919
|
+
}
|
|
920
|
+
const { page = 1, limit = 20 } = options;
|
|
921
|
+
const queryBuilder = this.actionSummaryRepository.createQueryBuilder('action');
|
|
922
|
+
// 应用过滤条件
|
|
923
|
+
if (options.userId) {
|
|
924
|
+
queryBuilder.andWhere('action.userId = :userId', { userId: options.userId });
|
|
925
|
+
}
|
|
926
|
+
if (options.username) {
|
|
927
|
+
queryBuilder.andWhere('action.username LIKE :username', { username: `%${options.username}%` });
|
|
928
|
+
}
|
|
929
|
+
if (options.actionName) {
|
|
930
|
+
// 支持模糊匹配动作名
|
|
931
|
+
queryBuilder.andWhere('action.actionName LIKE :actionName', { actionName: `%${options.actionName}%` });
|
|
932
|
+
}
|
|
933
|
+
// 新增:全局关键词搜索(搜索多个字段)
|
|
934
|
+
if (options.keyword) {
|
|
935
|
+
queryBuilder.andWhere('(action.username LIKE :keyword OR action.actionName LIKE :keyword OR action.description LIKE :keyword)', { keyword: `%${options.keyword}%` });
|
|
936
|
+
}
|
|
937
|
+
if (options.success !== undefined) {
|
|
938
|
+
queryBuilder.andWhere('action.success = :success', { success: options.success });
|
|
939
|
+
}
|
|
940
|
+
if (options.startTime && options.endTime) {
|
|
941
|
+
queryBuilder.andWhere('action.createdAt BETWEEN :startTime AND :endTime', {
|
|
942
|
+
startTime: options.startTime,
|
|
943
|
+
endTime: options.endTime,
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
// 排序
|
|
947
|
+
queryBuilder.orderBy('action.createdAt', 'DESC');
|
|
948
|
+
// 分页
|
|
949
|
+
const skip = (page - 1) * limit;
|
|
950
|
+
queryBuilder.skip(skip).take(limit);
|
|
951
|
+
const [data, total] = yield queryBuilder.getManyAndCount();
|
|
952
|
+
const pageOptionsDto = new dto_1.PageOptionsDto();
|
|
953
|
+
Object.assign(pageOptionsDto, { page, pageSize: limit });
|
|
954
|
+
const pageMetaDto = new dto_1.PageMetaDto({
|
|
955
|
+
pageOptionsDto,
|
|
956
|
+
itemCount: total,
|
|
957
|
+
});
|
|
958
|
+
return new dto_1.PageDto(data, pageMetaDto);
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* 查询单个审计动作的详细信息(包含关联的实体变更)
|
|
963
|
+
* @param actionId 动作ID
|
|
964
|
+
* @param language 语言代码 (zh/en/ja),默认 zh
|
|
965
|
+
*/
|
|
966
|
+
getAuditActionDetail(actionId_1) {
|
|
967
|
+
return __awaiter(this, arguments, void 0, function* (actionId, language = 'zh') {
|
|
968
|
+
if (!this.actionSummaryRepository) {
|
|
969
|
+
throw new Error('AuditActionSummaryEntity repository not available');
|
|
970
|
+
}
|
|
971
|
+
// 查询汇总信息
|
|
972
|
+
const summary = yield this.actionSummaryRepository.findOne({
|
|
973
|
+
where: { id: actionId },
|
|
974
|
+
});
|
|
975
|
+
if (!summary) {
|
|
976
|
+
throw new Error(`Audit action with id ${actionId} not found`);
|
|
977
|
+
}
|
|
978
|
+
// 动态生成多语言描述
|
|
979
|
+
const description = yield this.generateLocalizedDescription(summary.operationTemplateKey, summary.actionName, summary.descriptionParams, summary.success, language);
|
|
980
|
+
// 查询关联的实体变更
|
|
981
|
+
const entityChanges = yield this.auditLogRepository.find({
|
|
982
|
+
where: { auditActionId: actionId },
|
|
983
|
+
order: { sequenceInAction: 'ASC' },
|
|
984
|
+
});
|
|
985
|
+
// 分析每个实体的详细变化(支持多语言)
|
|
986
|
+
const detailedChanges = entityChanges.map((change) => {
|
|
987
|
+
// 使用数据库中存储的 changeDetails,并根据语言转换
|
|
988
|
+
const changeDetails = this.localizeChangeDetails(change.changeDetails, language);
|
|
989
|
+
return {
|
|
990
|
+
id: change.id,
|
|
991
|
+
entityType: change.entityType,
|
|
992
|
+
entityId: change.entityId,
|
|
993
|
+
operation: change.operation,
|
|
994
|
+
operationLabel: this.getOperationLabel(change.operation, language),
|
|
995
|
+
description: change.description,
|
|
996
|
+
sequenceInAction: change.sequenceInAction,
|
|
997
|
+
createdAt: change.createdAt,
|
|
998
|
+
// 数据快照
|
|
999
|
+
oldValue: change.oldValue,
|
|
1000
|
+
newValue: change.newValue,
|
|
1001
|
+
// 详细的字段变化分析 (使用本地化的 changeDetails)
|
|
1002
|
+
changeDetails,
|
|
1003
|
+
changedFieldsCount: (changeDetails === null || changeDetails === void 0 ? void 0 : changeDetails.length) || 0,
|
|
1004
|
+
changedFields: change.changedFields,
|
|
1005
|
+
};
|
|
1006
|
+
});
|
|
1007
|
+
// 统计信息
|
|
1008
|
+
const statistics = {
|
|
1009
|
+
totalChanges: entityChanges.length,
|
|
1010
|
+
totalFieldChanges: detailedChanges.reduce((sum, c) => sum + c.changedFieldsCount, 0),
|
|
1011
|
+
byEntityType: this.groupBy(entityChanges, 'entityType'),
|
|
1012
|
+
byOperation: this.groupBy(entityChanges, 'operation'),
|
|
1013
|
+
operationSequence: entityChanges.map((c) => ({
|
|
1014
|
+
sequence: c.sequenceInAction,
|
|
1015
|
+
entityType: c.entityType,
|
|
1016
|
+
operation: c.operation,
|
|
1017
|
+
})),
|
|
1018
|
+
};
|
|
1019
|
+
return {
|
|
1020
|
+
// 汇总信息(使用本地化描述)
|
|
1021
|
+
summary: {
|
|
1022
|
+
id: summary.id,
|
|
1023
|
+
actionName: summary.actionName,
|
|
1024
|
+
operationTemplateKey: summary.operationTemplateKey,
|
|
1025
|
+
description,
|
|
1026
|
+
descriptionParams: summary.descriptionParams,
|
|
1027
|
+
success: summary.success,
|
|
1028
|
+
errorMessage: summary.errorMessage,
|
|
1029
|
+
duration: summary.duration,
|
|
1030
|
+
userId: summary.userId,
|
|
1031
|
+
username: summary.username,
|
|
1032
|
+
requestId: summary.requestId,
|
|
1033
|
+
requestIp: summary.requestIp,
|
|
1034
|
+
userAgent: summary.userAgent,
|
|
1035
|
+
entityChangesCount: summary.entityChangesCount,
|
|
1036
|
+
entityTypes: summary.entityTypes,
|
|
1037
|
+
operationStats: summary.operationStats,
|
|
1038
|
+
createdAt: summary.createdAt,
|
|
1039
|
+
metadata: summary.metadata,
|
|
1040
|
+
},
|
|
1041
|
+
// 原始实体变更记录
|
|
1042
|
+
entityChanges,
|
|
1043
|
+
// 详细的变化分析
|
|
1044
|
+
detailedChanges,
|
|
1045
|
+
// 统计信息
|
|
1046
|
+
statistics,
|
|
1047
|
+
};
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* 生成本地化的描述文本
|
|
1052
|
+
*/
|
|
1053
|
+
generateLocalizedDescription(templateKey, actionName, params, success, language) {
|
|
1054
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1055
|
+
var _a;
|
|
1056
|
+
let template;
|
|
1057
|
+
// 1. 尝试从模板服务获取多语言模板
|
|
1058
|
+
if (templateKey && this.descriptionService) {
|
|
1059
|
+
try {
|
|
1060
|
+
template = yield this.descriptionService.getTemplate(templateKey, language);
|
|
1061
|
+
}
|
|
1062
|
+
catch (error) {
|
|
1063
|
+
// 如果获取模板失败,继续使用默认逻辑
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
// 2. 如果没有模板,使用默认格式
|
|
1067
|
+
if (!template) {
|
|
1068
|
+
const actionLabels = {
|
|
1069
|
+
zh: { success: '执行操作', fail: '执行操作失败' },
|
|
1070
|
+
en: { success: 'Executed operation', fail: 'Operation failed' },
|
|
1071
|
+
ja: { success: '操作を実行', fail: '操作が失敗しました' },
|
|
1072
|
+
};
|
|
1073
|
+
const label = ((_a = actionLabels[language]) === null || _a === void 0 ? void 0 : _a[success ? 'success' : 'fail']) || actionLabels.zh[success ? 'success' : 'fail'];
|
|
1074
|
+
template = `${label}: ${actionName}`;
|
|
1075
|
+
}
|
|
1076
|
+
// 3. 执行模板替换
|
|
1077
|
+
return this.replaceTemplatePlaceholders(template, params);
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* 替换模板中的占位符
|
|
1082
|
+
* @param template 模板字符串,如 "创建了产品 {name},价格 ¥{price}"
|
|
1083
|
+
* @param params 参数对象,如 { name: "iPhone", price: 999 }
|
|
1084
|
+
* @returns 替换后的字符串
|
|
1085
|
+
*/
|
|
1086
|
+
replaceTemplatePlaceholders(template, params) {
|
|
1087
|
+
let result = template;
|
|
1088
|
+
// 匹配 {paramName} 格式的占位符
|
|
1089
|
+
const placeholderPattern = /\{([^}]+)\}/g;
|
|
1090
|
+
result = result.replace(placeholderPattern, (match, paramName) => {
|
|
1091
|
+
// 支持嵌套属性访问,如 {user.name}
|
|
1092
|
+
const value = this.getNestedValue(params, paramName);
|
|
1093
|
+
return value !== undefined && value !== null ? String(value) : match;
|
|
1094
|
+
});
|
|
1095
|
+
return result;
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* 获取嵌套对象的值
|
|
1099
|
+
* @param obj 对象
|
|
1100
|
+
* @param path 路径,如 "user.name" 或 "user.profile.age"
|
|
1101
|
+
* @returns 值或 undefined
|
|
1102
|
+
*/
|
|
1103
|
+
getNestedValue(obj, path) {
|
|
1104
|
+
return path.split('.').reduce((current, key) => {
|
|
1105
|
+
return current === null || current === void 0 ? void 0 : current[key];
|
|
1106
|
+
}, obj);
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* 本地化 changeDetails(根据语言转换 fieldLabel 和 displayValue)
|
|
1110
|
+
*/
|
|
1111
|
+
localizeChangeDetails(changeDetails, language) {
|
|
1112
|
+
if (!changeDetails)
|
|
1113
|
+
return undefined;
|
|
1114
|
+
return changeDetails.map((detail) => {
|
|
1115
|
+
var _a, _b, _c, _d, _e;
|
|
1116
|
+
return (Object.assign(Object.assign({}, detail), { fieldLabel: ((_a = detail.fieldLabels) === null || _a === void 0 ? void 0 : _a[language]) || detail.fieldName, displayOldValue: (_c = (_b = detail.displayOldValue) === null || _b === void 0 ? void 0 : _b[language]) !== null && _c !== void 0 ? _c : detail.oldValue, displayNewValue: (_e = (_d = detail.displayNewValue) === null || _d === void 0 ? void 0 : _d[language]) !== null && _e !== void 0 ? _e : detail.newValue }));
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* 获取操作标签(支持多语言)
|
|
1121
|
+
*/
|
|
1122
|
+
getOperationLabel(operation, language = 'zh') {
|
|
1123
|
+
var _a, _b;
|
|
1124
|
+
const labels = {
|
|
1125
|
+
CREATE: { zh: '创建', en: 'Create', ja: '作成' },
|
|
1126
|
+
UPDATE: { zh: '更新', en: 'Update', ja: '更新' },
|
|
1127
|
+
DELETE: { zh: '删除', en: 'Delete', ja: '削除' },
|
|
1128
|
+
RESTORE: { zh: '恢复', en: 'Restore', ja: '復元' },
|
|
1129
|
+
};
|
|
1130
|
+
return ((_a = labels[operation]) === null || _a === void 0 ? void 0 : _a[language]) || ((_b = labels[operation]) === null || _b === void 0 ? void 0 : _b.zh) || operation;
|
|
1131
|
+
}
|
|
1132
|
+
/**
|
|
1133
|
+
* 分析字段变化(支持多语言)
|
|
1134
|
+
* @param oldValue 旧值
|
|
1135
|
+
* @param newValue 新值
|
|
1136
|
+
* @param operation 操作类型
|
|
1137
|
+
* @param entityClass 实体类(可选,用于获取字段和值的多语言标签)
|
|
1138
|
+
* @param language 语言(默认中文)
|
|
1139
|
+
*/
|
|
1140
|
+
analyzeFieldChanges(oldValue, newValue, operation, entityClass, language = 'zh') {
|
|
1141
|
+
const changes = [];
|
|
1142
|
+
const allFields = new Set([...Object.keys(oldValue), ...Object.keys(newValue)]);
|
|
1143
|
+
for (const field of allFields) {
|
|
1144
|
+
const oldVal = oldValue[field];
|
|
1145
|
+
const newVal = newValue[field];
|
|
1146
|
+
let changeType;
|
|
1147
|
+
if (operation === enums_1.AuditOperation.CREATE) {
|
|
1148
|
+
// 创建操作,所有字段都是新增
|
|
1149
|
+
changeType = 'added';
|
|
1150
|
+
}
|
|
1151
|
+
else if (operation === enums_1.AuditOperation.DELETE) {
|
|
1152
|
+
// 删除操作,所有字段都是移除
|
|
1153
|
+
changeType = 'removed';
|
|
1154
|
+
}
|
|
1155
|
+
else {
|
|
1156
|
+
// 更新操作,判断字段变化
|
|
1157
|
+
if (oldVal === undefined && newVal !== undefined) {
|
|
1158
|
+
changeType = 'added';
|
|
1159
|
+
}
|
|
1160
|
+
else if (oldVal !== undefined && newVal === undefined) {
|
|
1161
|
+
changeType = 'removed';
|
|
1162
|
+
}
|
|
1163
|
+
else if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
|
|
1164
|
+
changeType = 'modified';
|
|
1165
|
+
}
|
|
1166
|
+
else {
|
|
1167
|
+
changeType = 'unchanged';
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
// 跳过未变化的字段(对于UPDATE操作)
|
|
1171
|
+
if (changeType === 'unchanged' && operation === enums_1.AuditOperation.UPDATE) {
|
|
1172
|
+
continue;
|
|
1173
|
+
}
|
|
1174
|
+
// 获取字段的多语言标签
|
|
1175
|
+
let fieldLabel = field;
|
|
1176
|
+
if (entityClass) {
|
|
1177
|
+
try {
|
|
1178
|
+
fieldLabel = (0, entity_audit_decorator_1.getFieldLabel)(entityClass, field, language);
|
|
1179
|
+
}
|
|
1180
|
+
catch (error) {
|
|
1181
|
+
// 忽略错误,使用原字段名
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
// 获取字段值的多语言标签
|
|
1185
|
+
let displayOldValue = this.formatDisplayValue(oldVal);
|
|
1186
|
+
let displayNewValue = this.formatDisplayValue(newVal);
|
|
1187
|
+
if (entityClass) {
|
|
1188
|
+
try {
|
|
1189
|
+
if (oldVal !== null && oldVal !== undefined) {
|
|
1190
|
+
const valueLabel = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, field, oldVal, language);
|
|
1191
|
+
if (valueLabel !== oldVal) {
|
|
1192
|
+
displayOldValue = valueLabel;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (newVal !== null && newVal !== undefined) {
|
|
1196
|
+
const valueLabel = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, field, newVal, language);
|
|
1197
|
+
if (valueLabel !== newVal) {
|
|
1198
|
+
displayNewValue = valueLabel;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
catch (error) {
|
|
1203
|
+
// 忽略错误,使用默认格式化值
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
changes.push({
|
|
1207
|
+
field,
|
|
1208
|
+
fieldLabel,
|
|
1209
|
+
oldValue: oldVal,
|
|
1210
|
+
newValue: newVal,
|
|
1211
|
+
changeType,
|
|
1212
|
+
displayOldValue,
|
|
1213
|
+
displayNewValue,
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
return changes;
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* 格式化显示值
|
|
1220
|
+
*/
|
|
1221
|
+
formatDisplayValue(value) {
|
|
1222
|
+
if (value === null || value === undefined) {
|
|
1223
|
+
return '';
|
|
1224
|
+
}
|
|
1225
|
+
if (typeof value === 'object') {
|
|
1226
|
+
return JSON.stringify(value);
|
|
1227
|
+
}
|
|
1228
|
+
return String(value);
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* 按字段分组统计
|
|
1232
|
+
*/
|
|
1233
|
+
groupBy(items, field) {
|
|
1234
|
+
return items.reduce((acc, item) => {
|
|
1235
|
+
const key = item[field];
|
|
1236
|
+
acc[key] = (acc[key] || 0) + 1;
|
|
1237
|
+
return acc;
|
|
1238
|
+
}, {});
|
|
1239
|
+
}
|
|
557
1240
|
};
|
|
558
1241
|
exports.EntityAuditService = EntityAuditService;
|
|
559
1242
|
exports.EntityAuditService = EntityAuditService = __decorate([
|
|
560
1243
|
(0, common_1.Injectable)(),
|
|
561
1244
|
__param(0, (0, typeorm_1.InjectRepository)(entities_1.EntityAuditLogEntity)),
|
|
562
1245
|
__param(1, (0, typeorm_1.InjectRepository)(entities_1.EntityTransactionEntity)),
|
|
563
|
-
__param(2, (0,
|
|
564
|
-
__param(
|
|
565
|
-
__param(5, (0, common_1.Inject)('AUDIT_STRATEGY')),
|
|
1246
|
+
__param(2, (0, typeorm_1.InjectRepository)(entities_1.ManualOperationLogEntity)),
|
|
1247
|
+
__param(3, (0, common_1.Inject)('AUDIT_ENTITY_MANAGER')),
|
|
566
1248
|
__param(6, (0, common_1.Optional)()),
|
|
567
|
-
__param(6, (0, common_1.Inject)('
|
|
1249
|
+
__param(6, (0, common_1.Inject)('AUDIT_STRATEGY')),
|
|
568
1250
|
__param(7, (0, common_1.Optional)()),
|
|
569
|
-
__param(7, (0, common_1.Inject)('
|
|
1251
|
+
__param(7, (0, common_1.Inject)('AUDIT_CONFIG')),
|
|
1252
|
+
__param(8, (0, common_1.Optional)()),
|
|
1253
|
+
__param(8, (0, common_1.Inject)('AUDIT_CONNECTION_NAME')),
|
|
1254
|
+
__param(9, (0, common_1.Optional)()),
|
|
1255
|
+
__param(9, (0, typeorm_1.InjectRepository)(entities_1.AuditActionSummaryEntity)),
|
|
1256
|
+
__param(10, (0, common_1.Optional)()),
|
|
570
1257
|
__metadata("design:paramtypes", [typeorm_2.Repository,
|
|
1258
|
+
typeorm_2.Repository,
|
|
571
1259
|
typeorm_2.Repository,
|
|
572
1260
|
typeorm_2.EntityManager,
|
|
573
1261
|
audit_context_service_1.AuditContextService,
|
|
574
|
-
multi_database_service_1.MultiDatabaseService, Object, Object, String
|
|
1262
|
+
multi_database_service_1.MultiDatabaseService, Object, Object, String, typeorm_2.Repository,
|
|
1263
|
+
operation_description_service_1.OperationDescriptionService])
|
|
575
1264
|
], EntityAuditService);
|