import { Type } from 'class-transformer'; import { IsInt, IsOptional, Max, Min } from 'class-validator'; /** 契约 data-models.md §1:列表接口统一分页参数 */ export class PageQueryDto { @IsOptional() @Type(() => Number) @IsInt() @Min(1) page: number = 1; @IsOptional() @Type(() => Number) @IsInt() @Min(1) @Max(200) pageSize: number = 20; get skip(): number { return (this.page - 1) * this.pageSize; } } export interface Paged { items: T[]; total: number; page: number; pageSize: number; } export function toPaged(items: T[], total: number, query: { page: number; pageSize: number }): Paged { return { items, total, page: query.page, pageSize: query.pageSize }; } /** 规范化分页参数(用于非 DTO 校验路径,如内部调用) */ export function normalizePaging(page?: number, pageSize?: number, maxPageSize = 200): { page: number; pageSize: number; skip: number } { const p = Number.isFinite(page) && (page as number) >= 1 ? Math.floor(page as number) : 1; const rawSize = Number.isFinite(pageSize) ? Math.floor(pageSize as number) : 20; const size = Math.min(Math.max(rawSize, 1), maxPageSize); return { page: p, pageSize: size, skip: (p - 1) * size }; }