diff --git a/packages/nest/CHANGELOG.md b/packages/nest/CHANGELOG.md index f9529c7c..6e345e70 100644 --- a/packages/nest/CHANGELOG.md +++ b/packages/nest/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## v0.0.1-alpha.3 (2025-11-05) + +### ✨ Features + +- 增加通用`dto`、`decorator`工具,支持分页等功能  -  by **142vip.cn** in https://github.com/142vip/core-x/issues/731 [(2593e)](https://github.com/142vip/core-x/commit/2593eeb4) + +**Release New Version v0.0.1-alpha.3 [👉 View New Package On NPM](https://www.npmjs.com/package/@142vip/nest)** + ## v0.0.1-alpha.2 (2025-11-04) ### ✨ Features diff --git a/packages/nest/package.json b/packages/nest/package.json index b89b6486..6a03c3e3 100644 --- a/packages/nest/package.json +++ b/packages/nest/package.json @@ -1,6 +1,6 @@ { "name": "@142vip/nest", - "version": "0.0.1-alpha.2", + "version": "0.0.1-alpha.3", "private": false, "description": "Nest.js框架基础模块,管理生产、开发依赖", "author": "mmdapl ", diff --git a/packages/nest/src/decorators/index.ts b/packages/nest/src/decorators/index.ts new file mode 100644 index 00000000..5c792153 --- /dev/null +++ b/packages/nest/src/decorators/index.ts @@ -0,0 +1 @@ +export * from './transform.decorator' diff --git a/packages/nest/src/decorators/transform.decorator.ts b/packages/nest/src/decorators/transform.decorator.ts new file mode 100644 index 00000000..2062b5ae --- /dev/null +++ b/packages/nest/src/decorators/transform.decorator.ts @@ -0,0 +1,141 @@ +import { HttpException, HttpStatus } from '@nestjs/common' +import { Transform } from 'class-transformer' + +export function TransformToBoolean(): PropertyDecorator { + return Transform(({ value }) => { + switch (typeof value) { + case 'string': + return value === 'true' || value === '1' + ? true + : value === 'false' || value === '0' + ? false + : value + case 'number': + return Boolean(value) + default: + return value + } + }) +} + +export function TransformToNumber(): PropertyDecorator { + return Transform(({ value }) => Number(value)) +} + +export function TransformToNumberArray(): PropertyDecorator { + return Transform(({ value }) => { + switch (typeof value) { + case 'string': + return value.split(',').map(i => Number(i.trim())) + case 'object': + return Array.isArray(value) ? value.map(i => Number(i)) : value + default: + return value + } + }) +} + +export function TransformToStringArray(): PropertyDecorator { + return Transform(({ value }) => { + switch (typeof value) { + case 'string': + return value.split(',') + case 'object': + return Array.isArray(value) ? value.map(i => String(i)) : value + default: + return value + } + }) +} + +export function TransformToStringAndNumberArray(): PropertyDecorator { + return Transform(({ value }) => { + switch (typeof value) { + case 'string': + return value.split(',').map((i) => { + const num = Number(i.trim()) + return Number.isNaN(num) ? i.trim() : num + }) + case 'object': + return Array.isArray(value) + ? value.map((i) => { + const num = Number(i) + return Number.isNaN(num) ? i : num + }) + : value + default: + return value + } + }) +} + +/** + * 自动转化开启使用 + */ +export function Trim(): PropertyDecorator { + return Transform(p => p.value?.trim()) +} + +/** + * 用于转换boolean类型的值 + */ +export function DtoTransformToBoolean(): PropertyDecorator { + return Transform(p => + p.obj[p.key] === 'true' + ? true + : p.obj[p.key] === 'false' + ? false + : undefined, + ) +} + +/** + * Get请求 + * 用于前端传递的字符串参数解码 + */ +export function DtoDecodeURI(): PropertyDecorator { + return Transform((p) => { + // 对解密失败的字段,抛错 + try { + return p.value != null ? decodeURI(p.value) : p.value + } + catch { + throw new HttpException('参数格式异常', HttpStatus.BAD_REQUEST) + } + }) +} + +/** + * 设置默认值(当值为null时生效) + */ +export function DefaultValue(value?: unknown): PropertyDecorator { + return Transform(target => target.value ?? value) +} + +/** + * 手机号、API key等数据脱敏 + */ +export function StrDesensitize(): PropertyDecorator { + return Transform(({ value }) => { + if (typeof value !== 'string') { + return value + } + + const length = value.length + + if (length === 0) { + return '' + } + else if (length <= 2) { + return '*'.repeat(length) + } + else if (length === 3 || length === 4) { + return `${value[0]}${'*'.repeat(length - 2)}${value[length - 1]}` + } + else { + const start = value.slice(0, 2) + const end = value.slice(-2) + return `${start}${'*'.repeat(length - 4)}${end}` + } + }) +} diff --git a/packages/nest/src/dtos/base.vo.ts b/packages/nest/src/dtos/base.vo.ts new file mode 100644 index 00000000..05c2fbea --- /dev/null +++ b/packages/nest/src/dtos/base.vo.ts @@ -0,0 +1,5 @@ +export class BaseVo { + constructor(obj: T) { + Object.assign(this, obj) + } +} diff --git a/packages/nest/src/dtos/index.ts b/packages/nest/src/dtos/index.ts new file mode 100644 index 00000000..95b3721c --- /dev/null +++ b/packages/nest/src/dtos/index.ts @@ -0,0 +1,3 @@ +export * from './base.vo' +export * from './pagination.dto' +export * from './pagination.vo' diff --git a/packages/nest/src/dtos/pagination.dto.ts b/packages/nest/src/dtos/pagination.dto.ts new file mode 100644 index 00000000..54ad77ee --- /dev/null +++ b/packages/nest/src/dtos/pagination.dto.ts @@ -0,0 +1,26 @@ +import { Exclude, Expose, Transform } from 'class-transformer' +import { IsOptional, IsPositive } from 'class-validator' + +/** + * 默认分页参数 + */ +@Exclude() +export class PaginationDto { + /** + * 页号 默认1 + */ + @Expose() + @IsOptional() + @Transform(({ value }) => Number(value) ?? 1) + @IsPositive() + pageNum!: number + + /** + * 单页大小,默认10 + */ + @Expose() + @IsOptional() + @Transform(({ value }) => Number(value) ?? 10) + @IsPositive() + pageSize!: number +} diff --git a/packages/nest/src/dtos/pagination.vo.ts b/packages/nest/src/dtos/pagination.vo.ts new file mode 100644 index 00000000..5f97ab7d --- /dev/null +++ b/packages/nest/src/dtos/pagination.vo.ts @@ -0,0 +1,32 @@ +import { Exclude, Expose } from 'class-transformer' +import { BaseVo } from './base.vo' + +/** + * 分页 + */ +@Exclude() +export class PaginationVo extends BaseVo> { + /** + * 总数 + */ + @Expose() + total!: number + + /** + * 分页数据 + */ + @Expose() + data!: T[] + + /** + * 页码 + */ + @Expose() + pageNum!: number + + /** + * 每页数量 + */ + @Expose() + pageSize!: number +} diff --git a/packages/nest/src/index.ts b/packages/nest/src/index.ts index d45dbeff..125d554f 100644 --- a/packages/nest/src/index.ts +++ b/packages/nest/src/index.ts @@ -1 +1,3 @@ export * from './app.module' +export * from './decorators' +export * from './dtos'