@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
|
@@ -52,7 +52,7 @@ typeorm_1.SelectQueryBuilder.prototype.searchByString = function (q, columnNames
|
|
|
52
52
|
}
|
|
53
53
|
this.andWhere(new typeorm_1.Brackets((qb) => {
|
|
54
54
|
for (const item of columnNames) {
|
|
55
|
-
qb.orWhere(`${item}
|
|
55
|
+
qb.orWhere(`${item} LIKE :q`);
|
|
56
56
|
}
|
|
57
57
|
}));
|
|
58
58
|
if (options === null || options === void 0 ? void 0 : options.formStart) {
|
|
@@ -167,3 +167,20 @@ typeorm_1.SelectQueryBuilder.prototype.eachBatch = function (callback, options)
|
|
|
167
167
|
}
|
|
168
168
|
});
|
|
169
169
|
};
|
|
170
|
+
typeorm_1.SelectQueryBuilder.prototype.findField = function (field) {
|
|
171
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
172
|
+
const alias = this.alias;
|
|
173
|
+
const fieldName = String(field);
|
|
174
|
+
const results = yield this.clone()
|
|
175
|
+
.select(`${alias}.${fieldName}`, fieldName)
|
|
176
|
+
.getRawMany();
|
|
177
|
+
if (results.length === 0) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const values = results.map((result) => result[fieldName]);
|
|
181
|
+
if (values.length === 1) {
|
|
182
|
+
return values[0];
|
|
183
|
+
}
|
|
184
|
+
return values;
|
|
185
|
+
});
|
|
186
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { Constructor } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* 字段元数据接口(简化版)
|
|
4
|
+
* 用于在验证错误时生成友好的错误消息
|
|
5
|
+
*/
|
|
6
|
+
export interface ValidationMetadata {
|
|
7
|
+
/** 字段名称 */
|
|
8
|
+
fieldName?: string;
|
|
9
|
+
/** i18n 翻译键 */
|
|
10
|
+
i18nKey?: string;
|
|
11
|
+
/** 字段标签(多语言)- 使用 fieldLabel 避免命名冲突 */
|
|
12
|
+
label?: string | {
|
|
13
|
+
zh?: string;
|
|
14
|
+
en?: string;
|
|
15
|
+
[lang: string]: string | undefined;
|
|
16
|
+
};
|
|
17
|
+
/** 字段描述(多语言)- 使用 fieldDescription 避免命名冲突 */
|
|
18
|
+
description?: string | {
|
|
19
|
+
zh?: string;
|
|
20
|
+
en?: string;
|
|
21
|
+
[lang: string]: string | undefined;
|
|
22
|
+
};
|
|
23
|
+
/** 是否为数组 */
|
|
24
|
+
each?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* i18n 翻译函数类型
|
|
28
|
+
*/
|
|
29
|
+
type I18nTranslateFunction = (key: string, options?: any) => string | Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* 设置全局 i18n 翻译函数
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // 在 app.module.ts 或 main.ts 中设置
|
|
35
|
+
* import { setI18nTranslate } from './common/helpers/validation-metadata-helper';
|
|
36
|
+
* import { I18nService } from 'nestjs-i18n';
|
|
37
|
+
*
|
|
38
|
+
* setI18nTranslate((key, options) => i18nService.translate(key, options));
|
|
39
|
+
*/
|
|
40
|
+
export declare function setI18nTranslate(fn: I18nTranslateFunction): void;
|
|
41
|
+
/**
|
|
42
|
+
* 获取全局 i18n 翻译函数
|
|
43
|
+
*/
|
|
44
|
+
export declare function getI18nTranslate(): I18nTranslateFunction | null;
|
|
45
|
+
/**
|
|
46
|
+
* 解析字段标签
|
|
47
|
+
* 支持以下格式:
|
|
48
|
+
* 1. i18n key 字符串: "user.username"
|
|
49
|
+
* 2. 多语言对象: { zh: '用户名', en: 'Username' }
|
|
50
|
+
* 3. 普通字符串: "Username"
|
|
51
|
+
*
|
|
52
|
+
* @param label - 字段标签
|
|
53
|
+
* @param i18nKey - i18n 翻译键(优先使用)
|
|
54
|
+
* @param lang - 语言代码 (zh, en, 等)
|
|
55
|
+
* @returns 解析后的标签文本
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveFieldLabel(label: string | {
|
|
58
|
+
zh?: string;
|
|
59
|
+
en?: string;
|
|
60
|
+
[lang: string]: string | undefined;
|
|
61
|
+
} | undefined, i18nKey?: string, lang?: string): string | {
|
|
62
|
+
zh?: string;
|
|
63
|
+
en?: string;
|
|
64
|
+
[lang: string]: string | undefined;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* 翻译字段标签
|
|
68
|
+
* 将 i18n key 或多语言对象解析为最终文本
|
|
69
|
+
*
|
|
70
|
+
* @param labelOrKey - 标签、i18n key 或多语言对象
|
|
71
|
+
* @param lang - 语言代码
|
|
72
|
+
* @returns 翻译后的文本
|
|
73
|
+
*/
|
|
74
|
+
export declare function translateFieldLabel(labelOrKey: string | {
|
|
75
|
+
zh?: string;
|
|
76
|
+
en?: string;
|
|
77
|
+
[lang: string]: string | undefined;
|
|
78
|
+
}, lang?: string): Promise<string>;
|
|
79
|
+
/**
|
|
80
|
+
* 存储验证元数据到装饰器
|
|
81
|
+
*
|
|
82
|
+
* @param target - 目标类
|
|
83
|
+
* @param propertyKey - 属性名
|
|
84
|
+
* @param metadata - 验证元数据
|
|
85
|
+
*/
|
|
86
|
+
export declare function setValidationMetadata(target: Constructor<any>, propertyKey: string, metadata: ValidationMetadata): void;
|
|
87
|
+
/**
|
|
88
|
+
* 获取验证元数据
|
|
89
|
+
*
|
|
90
|
+
* @param target - 目标类
|
|
91
|
+
* @param propertyKey - 属性名
|
|
92
|
+
* @returns 验证元数据
|
|
93
|
+
*/
|
|
94
|
+
export declare function getValidationMetadata(target: Constructor<any>, propertyKey: string): ValidationMetadata | undefined;
|
|
95
|
+
/**
|
|
96
|
+
* 获取所有验证元数据
|
|
97
|
+
*
|
|
98
|
+
* @param target - 目标类
|
|
99
|
+
* @returns 所有验证元数据
|
|
100
|
+
*/
|
|
101
|
+
export declare function getAllValidationMetadata(target: Constructor<any>): Record<string, ValidationMetadata>;
|
|
102
|
+
/**
|
|
103
|
+
* 获取字段的友好标签
|
|
104
|
+
* 根据语言环境返回对应的标签
|
|
105
|
+
* 支持优先级:fieldLabel > i18nKey > fieldName
|
|
106
|
+
*
|
|
107
|
+
* @param metadata - 验证元数据
|
|
108
|
+
* @param lang - 语言 (zh, en, 等)
|
|
109
|
+
* @returns 字段标签
|
|
110
|
+
*/
|
|
111
|
+
export declare function getFieldLabelForValidation(metadata: ValidationMetadata, lang?: string): string;
|
|
112
|
+
export {};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.setI18nTranslate = setI18nTranslate;
|
|
13
|
+
exports.getI18nTranslate = getI18nTranslate;
|
|
14
|
+
exports.resolveFieldLabel = resolveFieldLabel;
|
|
15
|
+
exports.translateFieldLabel = translateFieldLabel;
|
|
16
|
+
exports.setValidationMetadata = setValidationMetadata;
|
|
17
|
+
exports.getValidationMetadata = getValidationMetadata;
|
|
18
|
+
exports.getAllValidationMetadata = getAllValidationMetadata;
|
|
19
|
+
exports.getFieldLabelForValidation = getFieldLabelForValidation;
|
|
20
|
+
/**
|
|
21
|
+
* 全局 i18n 翻译函数(由应用设置)
|
|
22
|
+
*/
|
|
23
|
+
let globalI18nTranslate = null;
|
|
24
|
+
/**
|
|
25
|
+
* 设置全局 i18n 翻译函数
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // 在 app.module.ts 或 main.ts 中设置
|
|
29
|
+
* import { setI18nTranslate } from './common/helpers/validation-metadata-helper';
|
|
30
|
+
* import { I18nService } from 'nestjs-i18n';
|
|
31
|
+
*
|
|
32
|
+
* setI18nTranslate((key, options) => i18nService.translate(key, options));
|
|
33
|
+
*/
|
|
34
|
+
function setI18nTranslate(fn) {
|
|
35
|
+
globalI18nTranslate = fn;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 获取全局 i18n 翻译函数
|
|
39
|
+
*/
|
|
40
|
+
function getI18nTranslate() {
|
|
41
|
+
return globalI18nTranslate;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 解析字段标签
|
|
45
|
+
* 支持以下格式:
|
|
46
|
+
* 1. i18n key 字符串: "user.username"
|
|
47
|
+
* 2. 多语言对象: { zh: '用户名', en: 'Username' }
|
|
48
|
+
* 3. 普通字符串: "Username"
|
|
49
|
+
*
|
|
50
|
+
* @param label - 字段标签
|
|
51
|
+
* @param i18nKey - i18n 翻译键(优先使用)
|
|
52
|
+
* @param lang - 语言代码 (zh, en, 等)
|
|
53
|
+
* @returns 解析后的标签文本
|
|
54
|
+
*/
|
|
55
|
+
function resolveFieldLabel(label, i18nKey, lang = 'zh') {
|
|
56
|
+
// 如果有 i18n key,返回 i18n key 对象(延迟解析)
|
|
57
|
+
if (i18nKey) {
|
|
58
|
+
return i18nKey;
|
|
59
|
+
}
|
|
60
|
+
// 如果有直接提供的 label
|
|
61
|
+
if (label) {
|
|
62
|
+
return label;
|
|
63
|
+
}
|
|
64
|
+
// 默认返回空字符串
|
|
65
|
+
return '';
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 翻译字段标签
|
|
69
|
+
* 将 i18n key 或多语言对象解析为最终文本
|
|
70
|
+
*
|
|
71
|
+
* @param labelOrKey - 标签、i18n key 或多语言对象
|
|
72
|
+
* @param lang - 语言代码
|
|
73
|
+
* @returns 翻译后的文本
|
|
74
|
+
*/
|
|
75
|
+
function translateFieldLabel(labelOrKey_1) {
|
|
76
|
+
return __awaiter(this, arguments, void 0, function* (labelOrKey, lang = 'zh') {
|
|
77
|
+
// 如果是普通字符串,直接返回
|
|
78
|
+
if (typeof labelOrKey === 'string') {
|
|
79
|
+
// 尝试作为 i18n key 翻译
|
|
80
|
+
if (globalI18nTranslate && labelOrKey.includes('.')) {
|
|
81
|
+
try {
|
|
82
|
+
const translated = yield globalI18nTranslate(labelOrKey, { lang });
|
|
83
|
+
if (translated && translated !== labelOrKey) {
|
|
84
|
+
return translated;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (_a) {
|
|
88
|
+
// 翻译失败,返回原始 key
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return labelOrKey;
|
|
92
|
+
}
|
|
93
|
+
// 如果是多语言对象,返回对应语言的文本
|
|
94
|
+
if (typeof labelOrKey === 'object' && labelOrKey !== null) {
|
|
95
|
+
return (labelOrKey[lang] ||
|
|
96
|
+
labelOrKey.zh ||
|
|
97
|
+
labelOrKey.en ||
|
|
98
|
+
Object.values(labelOrKey).find((v) => v) ||
|
|
99
|
+
'');
|
|
100
|
+
}
|
|
101
|
+
return '';
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 验证元数据存储键
|
|
106
|
+
*/
|
|
107
|
+
const VALIDATION_METADATA_KEY = 'VALIDATION_METADATA_OPTIONS';
|
|
108
|
+
/**
|
|
109
|
+
* 存储验证元数据到装饰器
|
|
110
|
+
*
|
|
111
|
+
* @param target - 目标类
|
|
112
|
+
* @param propertyKey - 属性名
|
|
113
|
+
* @param metadata - 验证元数据
|
|
114
|
+
*/
|
|
115
|
+
function setValidationMetadata(target, propertyKey, metadata) {
|
|
116
|
+
const existingMetadata = Reflect.getMetadata(VALIDATION_METADATA_KEY, target) || {};
|
|
117
|
+
existingMetadata[propertyKey] = metadata;
|
|
118
|
+
Reflect.defineMetadata(VALIDATION_METADATA_KEY, existingMetadata, target);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* 获取验证元数据
|
|
122
|
+
*
|
|
123
|
+
* @param target - 目标类
|
|
124
|
+
* @param propertyKey - 属性名
|
|
125
|
+
* @returns 验证元数据
|
|
126
|
+
*/
|
|
127
|
+
function getValidationMetadata(target, propertyKey) {
|
|
128
|
+
const allMetadata = Reflect.getMetadata(VALIDATION_METADATA_KEY, target);
|
|
129
|
+
const metadata = allMetadata === null || allMetadata === void 0 ? void 0 : allMetadata[propertyKey];
|
|
130
|
+
return metadata;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 获取所有验证元数据
|
|
134
|
+
*
|
|
135
|
+
* @param target - 目标类
|
|
136
|
+
* @returns 所有验证元数据
|
|
137
|
+
*/
|
|
138
|
+
function getAllValidationMetadata(target) {
|
|
139
|
+
return Reflect.getMetadata(VALIDATION_METADATA_KEY, target) || {};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 获取字段的友好标签
|
|
143
|
+
* 根据语言环境返回对应的标签
|
|
144
|
+
* 支持优先级:fieldLabel > i18nKey > fieldName
|
|
145
|
+
*
|
|
146
|
+
* @param metadata - 验证元数据
|
|
147
|
+
* @param lang - 语言 (zh, en, 等)
|
|
148
|
+
* @returns 字段标签
|
|
149
|
+
*/
|
|
150
|
+
function getFieldLabelForValidation(metadata, lang = 'zh') {
|
|
151
|
+
// 如果有 fieldLabel,直接使用
|
|
152
|
+
if (metadata.label) {
|
|
153
|
+
if (typeof metadata.label === 'string') {
|
|
154
|
+
return metadata.label;
|
|
155
|
+
}
|
|
156
|
+
return metadata.label[lang] || metadata.label.zh || metadata.label.en || '';
|
|
157
|
+
}
|
|
158
|
+
// 如果有 i18nKey,返回 i18nKey(会在运行时翻译)
|
|
159
|
+
if (metadata.i18nKey) {
|
|
160
|
+
return metadata.i18nKey;
|
|
161
|
+
}
|
|
162
|
+
// 默认返回字段名
|
|
163
|
+
return metadata.fieldName || '';
|
|
164
|
+
}
|
package/common/index.d.ts
CHANGED
package/common/index.js
CHANGED
|
@@ -20,3 +20,7 @@ __exportStar(require("./dto"), exports);
|
|
|
20
20
|
__exportStar(require("./types"), exports);
|
|
21
21
|
__exportStar(require("./snake-naming.strategy"), exports);
|
|
22
22
|
__exportStar(require("./boilerplate.polyfill"), exports);
|
|
23
|
+
// ========================================
|
|
24
|
+
// Validation Metadata Helper
|
|
25
|
+
// ========================================
|
|
26
|
+
__exportStar(require("./helpers/validation-metadata-helper"), exports);
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 字段装饰器 i18n 翻译使用示例
|
|
3
|
+
*
|
|
4
|
+
* 本示例演示如何使用 fieldI18n 选项通过 i18n key 进行多语言转换
|
|
5
|
+
*
|
|
6
|
+
* 注意:此示例文件仅供参考,展示如何使用 fieldI18n 选项。
|
|
7
|
+
* 如果使用 TypeScript 5+ 的新装饰器语法,需要确保 tsconfig.json 中
|
|
8
|
+
* "experimentalDecorators" 设置为 true。
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* 在应用启动时(如 app.module.ts 或 main.ts)配置 i18n 翻译函数
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // app.module.ts
|
|
15
|
+
* import { setI18nTranslate } from '@your-lib/core';
|
|
16
|
+
*
|
|
17
|
+
*@Module({
|
|
18
|
+
* imports: [
|
|
19
|
+
* ConfigModule.forRoot(),
|
|
20
|
+
* I18nModule.forRoot({
|
|
21
|
+
* fallbackLanguage: 'en',
|
|
22
|
+
* loader: TranslationsLoader({
|
|
23
|
+
* config: {
|
|
24
|
+
* defaultLanguage: 'zh',
|
|
25
|
+
* languages: ['zh', 'en'],
|
|
26
|
+
* types: ['validation', 'field'],
|
|
27
|
+
* },
|
|
28
|
+
* }),
|
|
29
|
+
* }),
|
|
30
|
+
* ],
|
|
31
|
+
* providers: [AppService],
|
|
32
|
+
* })
|
|
33
|
+
* export class AppModule implements OnModuleInit {
|
|
34
|
+
* constructor(private readonly i18n: I18nService) {}
|
|
35
|
+
*
|
|
36
|
+
* async onModuleInit() {
|
|
37
|
+
* // 设置全局 i18n 翻译函数
|
|
38
|
+
* setI18nTranslate((key, options) => this.i18n.translate(key, options));
|
|
39
|
+
* }
|
|
40
|
+
* }
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* 翻译文件结构示例 (src/i18n/zh.json):
|
|
44
|
+
*
|
|
45
|
+
* {
|
|
46
|
+
* "field": {
|
|
47
|
+
* "user": {
|
|
48
|
+
* "username": "用户名",
|
|
49
|
+
* "email": "邮箱",
|
|
50
|
+
* "phone": "手机号",
|
|
51
|
+
* "role": "角色",
|
|
52
|
+
* "status": "状态",
|
|
53
|
+
* "description": "个人简介"
|
|
54
|
+
* },
|
|
55
|
+
* "product": {
|
|
56
|
+
* "name": "产品名称",
|
|
57
|
+
* "price": "价格",
|
|
58
|
+
* "stock": "库存",
|
|
59
|
+
* "status": "产品状态"
|
|
60
|
+
* }
|
|
61
|
+
* },
|
|
62
|
+
* "field.value": {
|
|
63
|
+
* "user.role": {
|
|
64
|
+
* "user": "普通用户",
|
|
65
|
+
* "admin": "管理员",
|
|
66
|
+
* "vip": "VIP用户"
|
|
67
|
+
* },
|
|
68
|
+
* "user.status": {
|
|
69
|
+
* "active": "正常",
|
|
70
|
+
* "inactive": "未激活",
|
|
71
|
+
* "suspended": "已暂停"
|
|
72
|
+
* }
|
|
73
|
+
* }
|
|
74
|
+
* }
|
|
75
|
+
*
|
|
76
|
+
* 翻译文件结构示例 (src/i18n/en.json):
|
|
77
|
+
*
|
|
78
|
+
* {
|
|
79
|
+
* "field": {
|
|
80
|
+
* "user": {
|
|
81
|
+
* "username": "Username",
|
|
82
|
+
* "email": "Email",
|
|
83
|
+
* "phone": "Phone Number",
|
|
84
|
+
* "role": "Role",
|
|
85
|
+
* "status": "Status",
|
|
86
|
+
* "description": "Bio"
|
|
87
|
+
* },
|
|
88
|
+
* "product": {
|
|
89
|
+
* "name": "Product Name",
|
|
90
|
+
* "price": "Price",
|
|
91
|
+
* "stock": "Stock",
|
|
92
|
+
* "status": "Product Status"
|
|
93
|
+
* }
|
|
94
|
+
* },
|
|
95
|
+
* "field.value": {
|
|
96
|
+
* "user.role": {
|
|
97
|
+
* "user": "User",
|
|
98
|
+
* "admin": "Administrator",
|
|
99
|
+
* "vip": "VIP User"
|
|
100
|
+
* },
|
|
101
|
+
* "user.status": {
|
|
102
|
+
* "active": "Active",
|
|
103
|
+
* "inactive": "Inactive",
|
|
104
|
+
* "suspended": "Suspended"
|
|
105
|
+
* }
|
|
106
|
+
* }
|
|
107
|
+
* }
|
|
108
|
+
*/
|
|
109
|
+
/**
|
|
110
|
+
* 用户 DTO - 使用 i18n key
|
|
111
|
+
*/
|
|
112
|
+
export declare class CreateUserDto {
|
|
113
|
+
username: string;
|
|
114
|
+
email: string;
|
|
115
|
+
phone?: string;
|
|
116
|
+
description?: string;
|
|
117
|
+
emailVerified?: boolean;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 产品 DTO - 使用 i18n key
|
|
121
|
+
*/
|
|
122
|
+
export declare class CreateProductDto {
|
|
123
|
+
name: string;
|
|
124
|
+
price: number;
|
|
125
|
+
stock: number;
|
|
126
|
+
}
|
|
127
|
+
declare enum UserRole {
|
|
128
|
+
USER = "user",
|
|
129
|
+
ADMIN = "admin",
|
|
130
|
+
VIP = "vip"
|
|
131
|
+
}
|
|
132
|
+
declare enum UserStatus {
|
|
133
|
+
ACTIVE = "active",
|
|
134
|
+
INACTIVE = "inactive",
|
|
135
|
+
SUSPENDED = "suspended"
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 用户更新 DTO - 枚举字段使用 i18n
|
|
139
|
+
*/
|
|
140
|
+
export declare class UpdateUserDto {
|
|
141
|
+
role: UserRole;
|
|
142
|
+
status: UserStatus;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* 验证错误过滤器示例
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* import { getValidationMetadata, getFieldLabelForValidation } from '@your-lib/core';
|
|
149
|
+
*
|
|
150
|
+
* @Catch(ValidationError)
|
|
151
|
+
* export class ValidationErrorFilter implements ExceptionFilter {
|
|
152
|
+
* catch(exception: ValidationError, host: ArgumentsHost) {
|
|
153
|
+
* const ctx = host.switchToHttp();
|
|
154
|
+
* const response = ctx.getResponse<Response>();
|
|
155
|
+
* const request = ctx.getRequest<Request>();
|
|
156
|
+
* const language = request.headers['accept-language'] || 'zh';
|
|
157
|
+
*
|
|
158
|
+
* const errors = exception.errors.map(error => {
|
|
159
|
+
* const metadata = getValidationMetadata(error.target.constructor, error.property);
|
|
160
|
+
* const fieldLabel = getFieldLabelForValidation(metadata, language);
|
|
161
|
+
*
|
|
162
|
+
* // 如果 fieldLabel 是 i18n key,需要翻译
|
|
163
|
+
* const displayLabel = fieldLabel.includes('.')
|
|
164
|
+
* ? this.i18n.translate(fieldLabel, { lang: language })
|
|
165
|
+
* : fieldLabel;
|
|
166
|
+
*
|
|
167
|
+
* return {
|
|
168
|
+
* field: error.property,
|
|
169
|
+
* fieldLabel: displayLabel,
|
|
170
|
+
* constraints: error.constraints,
|
|
171
|
+
* };
|
|
172
|
+
* });
|
|
173
|
+
*
|
|
174
|
+
* response.status(400).json({
|
|
175
|
+
* statusCode: 400,
|
|
176
|
+
* message: 'Validation failed',
|
|
177
|
+
* errors,
|
|
178
|
+
* });
|
|
179
|
+
* }
|
|
180
|
+
* }
|
|
181
|
+
*/
|
|
182
|
+
/**
|
|
183
|
+
* 审计日志服务示例
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* import { getAuditMetadata } from '@your-lib/core';
|
|
187
|
+
*
|
|
188
|
+
* @Injectable()
|
|
189
|
+
* export class AuditService {
|
|
190
|
+
* constructor(private readonly i18n: I18nService) {}
|
|
191
|
+
*
|
|
192
|
+
* async logFieldChange(
|
|
193
|
+
* entity: any,
|
|
194
|
+
* field: string,
|
|
195
|
+
* oldValue: any,
|
|
196
|
+
* newValue: any,
|
|
197
|
+
* language: string = 'zh',
|
|
198
|
+
* ) {
|
|
199
|
+
* const metadata = getAuditMetadata(entity.constructor, field);
|
|
200
|
+
*
|
|
201
|
+
* // 翻译字段标签
|
|
202
|
+
* let fieldLabel = metadata?.label || field;
|
|
203
|
+
* if (typeof fieldLabel === 'string' && fieldLabel.includes('.')) {
|
|
204
|
+
* fieldLabel = await this.i18n.translate(fieldLabel, { lang: language });
|
|
205
|
+
* } else if (typeof fieldLabel === 'object') {
|
|
206
|
+
* fieldLabel = fieldLabel[language] || fieldLabel.zh || fieldLabel.en;
|
|
207
|
+
* }
|
|
208
|
+
*
|
|
209
|
+
* // 翻译枚举值
|
|
210
|
+
* const valueLabels = metadata?.valueLabels;
|
|
211
|
+
* const displayOldValue = valueLabels?.[oldValue]
|
|
212
|
+
* ? await this.translateValueLabel(valueLabels[oldValue], language)
|
|
213
|
+
* : oldValue;
|
|
214
|
+
* const displayNewValue = valueLabels?.[newValue]
|
|
215
|
+
* ? await this.translateValueLabel(valueLabels[newValue], language)
|
|
216
|
+
* : newValue;
|
|
217
|
+
*
|
|
218
|
+
* return {
|
|
219
|
+
* fieldLabel,
|
|
220
|
+
* oldValue,
|
|
221
|
+
* newValue,
|
|
222
|
+
* displayOldValue,
|
|
223
|
+
* displayNewValue,
|
|
224
|
+
* };
|
|
225
|
+
* }
|
|
226
|
+
*
|
|
227
|
+
* private async translateValueLabel(
|
|
228
|
+
* label: string | { [lang: string]: string },
|
|
229
|
+
* language: string,
|
|
230
|
+
* ): Promise<string> {
|
|
231
|
+
* if (typeof label === 'string' && label.includes('.')) {
|
|
232
|
+
* return await this.i18n.translate(label, { lang: language });
|
|
233
|
+
* }
|
|
234
|
+
* if (typeof label === 'object') {
|
|
235
|
+
* return label[language] || label.zh || label.en || '';
|
|
236
|
+
* }
|
|
237
|
+
* return label;
|
|
238
|
+
* }
|
|
239
|
+
* }
|
|
240
|
+
*/
|
|
241
|
+
/**
|
|
242
|
+
* 场景 1: 纯 i18n key 方式(推荐)
|
|
243
|
+
*
|
|
244
|
+
* 优点:
|
|
245
|
+
* - 翻译集中管理,易于维护
|
|
246
|
+
* - 支持动态切换语言
|
|
247
|
+
* - 翻译可以复用
|
|
248
|
+
* - 适合大型项目和国际化需求
|
|
249
|
+
*
|
|
250
|
+
* 缺点:
|
|
251
|
+
* - 需要额外的翻译文件配置
|
|
252
|
+
* - 增加了一定的复杂度
|
|
253
|
+
*/
|
|
254
|
+
export declare class PureI18nDto {
|
|
255
|
+
username: string;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* 场景 2: 纯多语言对象方式
|
|
259
|
+
*
|
|
260
|
+
* 优点:
|
|
261
|
+
* - 简单直接,无需额外配置
|
|
262
|
+
* - 适合小型项目或固定语言场景
|
|
263
|
+
* - 翻译就在代码中,查看方便
|
|
264
|
+
*
|
|
265
|
+
* 缺点:
|
|
266
|
+
* - 翻译分散在各个 DTO 中,难以统一管理
|
|
267
|
+
* - 不易于动态切换语言
|
|
268
|
+
* - 翻译无法复用
|
|
269
|
+
*/
|
|
270
|
+
export declare class PureLabelDto {
|
|
271
|
+
username: string;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 场景 3: 混合方式(fieldLabel 优先)
|
|
275
|
+
*
|
|
276
|
+
* 优点:
|
|
277
|
+
* - 灵活性最高
|
|
278
|
+
* - 可以为特定字段覆盖 i18n 翻译
|
|
279
|
+
*
|
|
280
|
+
* 缺点:
|
|
281
|
+
* - 可能造成混淆
|
|
282
|
+
* - 建议统一使用一种方式
|
|
283
|
+
*/
|
|
284
|
+
export declare class MixedDto {
|
|
285
|
+
username: string;
|
|
286
|
+
}
|
|
287
|
+
export declare class RegisterUserDto {
|
|
288
|
+
username: string;
|
|
289
|
+
email: string;
|
|
290
|
+
password: string;
|
|
291
|
+
phone?: string;
|
|
292
|
+
agreeTerms?: boolean;
|
|
293
|
+
}
|
|
294
|
+
export {};
|