Files
dukang/server/dukang-api/src/modules/promo/dto/promo-code.dto.ts
T
jacy 53e0db6a98 feat(promo): promo metric event logs and HQ timeline charts (v3.4.13)
Add log_promo_event for scan/attribution/register/order with IP; admin metrics APIs and ECharts on promo detail page.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-06 00:06:52 +08:00

124 lines
2.3 KiB
TypeScript

import { Type } from 'class-transformer';
import { IsIn, IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator';
import { PromoCodeScene, PromoCodeStatus } from '@dukang/shared-types';
export class PromoCodeListQueryDto {
@IsOptional()
@Type(() => Number)
page?: number;
@IsOptional()
@Type(() => Number)
pageSize?: number;
@IsOptional()
@IsString()
name?: string;
@IsOptional()
@IsString()
code?: string;
@IsOptional()
@IsIn(['ACTIVE', 'DISABLED'])
status?: PromoCodeStatus;
@IsOptional()
@IsIn(['ONLINE_LINK', 'OFFLINE_PICKUP', 'PARTNER_CHANNEL', 'EVENT', 'OTHER'])
scene?: PromoCodeScene;
@IsOptional()
@IsString()
ownerUserId?: string;
}
export class CreatePromoCodeDto {
@IsString()
@IsNotEmpty()
@MaxLength(128)
name: string;
@IsOptional()
@IsString()
@MaxLength(32)
code?: string;
@IsOptional()
@IsIn(['ONLINE_LINK', 'OFFLINE_PICKUP', 'PARTNER_CHANNEL', 'EVENT', 'OTHER'])
scene?: PromoCodeScene;
@IsOptional()
@IsString()
ownerUserId?: string;
@IsOptional()
@IsString()
@MaxLength(256)
remark?: string;
/** 小程序码落地页路径,如 pages/home/index;留空用环境变量 WX_MINI_PROMO_PAGE */
@IsOptional()
@IsString()
@MaxLength(128)
page?: string;
}
export class UpdatePromoCodeDto {
@IsOptional()
@IsString()
@MaxLength(128)
name?: string;
@IsOptional()
@IsIn(['ONLINE_LINK', 'OFFLINE_PICKUP', 'PARTNER_CHANNEL', 'EVENT', 'OTHER'])
scene?: PromoCodeScene;
@IsOptional()
@IsString()
ownerUserId?: string | null;
@IsOptional()
@IsString()
@MaxLength(256)
remark?: string | null;
}
export class UpdatePromoCodeStatusDto {
@IsIn(['ACTIVE', 'DISABLED'])
status: PromoCodeStatus;
}
export class PromoMetricTimelineQueryDto {
@IsString()
dateFrom: string;
@IsString()
dateTo: string;
@IsOptional()
@IsIn(['day', 'hour'])
granularity?: 'day' | 'hour';
}
export class PromoMetricEventsQueryDto {
@IsOptional()
@Type(() => Number)
page?: number;
@IsOptional()
@Type(() => Number)
pageSize?: number;
@IsOptional()
@IsIn(['SCAN', 'ATTRIBUTION', 'REGISTER', 'ORDER'])
eventType?: 'SCAN' | 'ATTRIBUTION' | 'REGISTER' | 'ORDER';
@IsOptional()
@IsString()
dateFrom?: string;
@IsOptional()
@IsString()
dateTo?: string;
}