// video-media.dto.ts import { IsInt, IsOptional, IsString, IsIn, IsArray, IsMongoId, Min, Max, MaxLength, } from 'class-validator'; import { Type } from 'class-transformer'; import { PageListDto } from '@box/common/dto/page-list.dto'; export class VideoMediaListQueryDto extends PageListDto { /** * 搜索关键词:匹配标题、文件名等(具体逻辑在 service 里实现) */ @IsOptional() @IsString() @MaxLength(100) keyword?: string; /** * 分类过滤:可选 */ @IsOptional() @IsMongoId() categoryId?: string; /** * 标签过滤(通常前端只会传一个 tagId) */ @IsOptional() @IsMongoId() tagId?: string; /** * 上/下架状态过滤 * 0 = 下架, 1 = 上架 */ @IsOptional() @Type(() => Number) @IsInt() @IsIn([0, 1]) listStatus?: number; } export class UpdateVideoMediaManageDto { @IsOptional() @IsString() @MaxLength(200) title?: string; /** * 分类 ID,可为空(取消分类) */ @IsOptional() @IsMongoId() categoryId?: string | null; /** * 标签 ID 列表,最多 5 个 */ @IsOptional() @IsArray() @IsMongoId({ each: true }) tagIds?: string[]; /** * 上/下架状态,也可以在这里一起保存(可选) * 0 = 下架, 1 = 上架 */ @IsOptional() @Type(() => Number) @IsInt() @IsIn([0, 1]) listStatus?: number; } export class UpdateVideoMediaStatusDto { @Type(() => Number) @IsInt() @IsIn([0, 1]) listStatus!: number; } export class BatchUpdateVideoMediaStatusDto { @IsArray() @IsMongoId({ each: true }) ids!: string[]; @Type(() => Number) @IsInt() @IsIn([0, 1]) listStatus!: number; } export class UpdateVideoMediaCoverResponseDto { @IsString() id!: string; @IsString() coverImg!: string; /** * 新 editedAt 值 */ @IsString() editedAt!: string; } export class VideoMediaListItemDto { @IsString() id!: string; @IsString() title!: string; @IsString() filename!: string; /** * 视频时长(秒) */ @Type(() => Number) @IsInt() videoTime!: number; /** * 文件大小(业务上 BigInt 存储,DTO 建议用字符串避免精度问题) */ @IsString() size!: string; /** * 封面 URL / key */ @IsString() coverImg!: string; /** * 分类 ID,可空 */ @IsOptional() @IsMongoId() categoryId?: string | null; /** * 当前选中的标签 ID 列表(最多 5 个) */ @IsArray() @IsMongoId({ each: true }) tagIds!: string[]; /** * 上/下架状态 0 = 下架, 1 = 上架 */ @Type(() => Number) @IsInt() @IsIn([0, 1]) listStatus!: number; /** * 本地编辑时间(BigInt epoch)— 字符串返回 */ @IsString() editedAt!: string; } export class VideoMediaDetailDto { @IsString() id!: string; // --- Provider fields (read-only for mgnt) --- @IsString() title!: string; @IsString() filename!: string; @Type(() => Number) @IsInt() videoTime!: number; @IsString() size!: string; // from BigInt @IsString() coverImg!: string; @IsString() type!: string; @Type(() => Number) @IsInt() formatType!: number; @Type(() => Number) @IsInt() contentType!: number; @IsString() country!: string; @IsString() status!: string; @IsString() desc!: string; // --- Local business fields --- @IsOptional() @IsMongoId() categoryId?: string | null; @IsArray() @IsMongoId({ each: true }) tagIds!: string[]; @Type(() => Number) @IsInt() @IsIn([0, 1]) listStatus!: number; @IsString() editedAt!: string; // --- Optional denormalized information for UI convenience --- @IsOptional() @IsString() categoryName?: string | null; @IsOptional() @IsArray() tags?: { id: string; name: string }[]; }