Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/nest/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`工具,支持分页等功能 &nbsp;-&nbsp; by **142vip.cn** in https://github.com/142vip/core-x/issues/731 [<samp>(2593e)</samp>](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
Expand Down
2 changes: 1 addition & 1 deletion packages/nest/package.json
Original file line number Diff line number Diff line change
@@ -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 <mmdapl@163.com>",
Expand Down
1 change: 1 addition & 0 deletions packages/nest/src/decorators/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './transform.decorator'
141 changes: 141 additions & 0 deletions packages/nest/src/decorators/transform.decorator.ts
Original file line number Diff line number Diff line change
@@ -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}`
}
})
}
5 changes: 5 additions & 0 deletions packages/nest/src/dtos/base.vo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export class BaseVo<T> {
constructor(obj: T) {
Object.assign(this, obj)
}
}
3 changes: 3 additions & 0 deletions packages/nest/src/dtos/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './base.vo'
export * from './pagination.dto'
export * from './pagination.vo'
26 changes: 26 additions & 0 deletions packages/nest/src/dtos/pagination.dto.ts
Original file line number Diff line number Diff line change
@@ -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
}
32 changes: 32 additions & 0 deletions packages/nest/src/dtos/pagination.vo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Exclude, Expose } from 'class-transformer'
import { BaseVo } from './base.vo'

/**
* 分页
*/
@Exclude()
export class PaginationVo<T> extends BaseVo<PaginationVo<T>> {
/**
* 总数
*/
@Expose()
total!: number

/**
* 分页数据
*/
@Expose()
data!: T[]

/**
* 页码
*/
@Expose()
pageNum!: number

/**
* 每页数量
*/
@Expose()
pageSize!: number
}
2 changes: 2 additions & 0 deletions packages/nest/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './app.module'
export * from './decorators'
export * from './dtos'
Loading