- موتور رویدادمحور با شرط، محدودیت، تأیید مدیر و idempotency - اتصال به لید، مشتری، معامله، فعالیت، روتین، پیشفاکتور، فاکتور و تیکت - صفحه /club و /club/admin، اعلان زنده امتیاز، آیتم منو - انتقال فرمساز سرنخ به ابزارها Co-authored-by: Cursor <cursoragent@cursor.com>
342 lines
5.2 KiB
TypeScript
342 lines
5.2 KiB
TypeScript
import { Type } from 'class-transformer';
|
|
import {
|
|
ArrayMaxSize,
|
|
IsArray,
|
|
IsBoolean,
|
|
IsIn,
|
|
IsInt,
|
|
IsOptional,
|
|
IsString,
|
|
Max,
|
|
MaxLength,
|
|
Min,
|
|
MinLength,
|
|
ValidateIf,
|
|
} from 'class-validator';
|
|
import type { GamificationCondition, GamificationLevelDef } from '@mento/shared';
|
|
import { GAMIFICATION_EVENT_KEYS } from '@mento/shared';
|
|
|
|
const nullable = () => ValidateIf((_, v) => v !== '' && v != null);
|
|
|
|
export class SaveRuleDto {
|
|
@IsString()
|
|
@MinLength(2)
|
|
@MaxLength(120)
|
|
name!: string;
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@IsString()
|
|
@MaxLength(500)
|
|
description?: string | null;
|
|
|
|
@IsIn(GAMIFICATION_EVENT_KEYS)
|
|
event!: (typeof GAMIFICATION_EVENT_KEYS)[number];
|
|
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(-10000)
|
|
@Max(100000)
|
|
score!: number;
|
|
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(0)
|
|
@Max(100000)
|
|
coins!: number;
|
|
|
|
@IsOptional()
|
|
@IsArray()
|
|
@ArrayMaxSize(10)
|
|
conditions?: GamificationCondition[];
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
isActive?: boolean;
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(1)
|
|
maxPerDay?: number | null;
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(1)
|
|
maxCoinsPerDay?: number | null;
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(1)
|
|
maxPerUser?: number | null;
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(1)
|
|
@Max(100000)
|
|
cooldownMinutes?: number | null;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
oncePerEntity?: boolean;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
firstTimeOnly?: boolean;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
requiresApproval?: boolean;
|
|
|
|
@IsOptional()
|
|
@IsArray()
|
|
@ArrayMaxSize(10)
|
|
@IsString({ each: true })
|
|
roles?: string[];
|
|
|
|
@IsOptional()
|
|
@IsArray()
|
|
@ArrayMaxSize(50)
|
|
@IsString({ each: true })
|
|
teamIds?: string[];
|
|
}
|
|
|
|
export class ToggleDto {
|
|
@IsBoolean()
|
|
isActive!: boolean;
|
|
}
|
|
|
|
export class AdjustDto {
|
|
@IsString()
|
|
userId!: string;
|
|
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(-1000000)
|
|
@Max(1000000)
|
|
amount!: number;
|
|
|
|
@IsString()
|
|
@MinLength(2)
|
|
@MaxLength(500)
|
|
reason!: string;
|
|
}
|
|
|
|
export class DecisionDto {
|
|
@IsOptional()
|
|
@nullable()
|
|
@IsString()
|
|
@MaxLength(500)
|
|
note?: string | null;
|
|
}
|
|
|
|
export class RedeemDto {
|
|
@IsString()
|
|
rewardId!: string;
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@IsString()
|
|
@MaxLength(500)
|
|
note?: string | null;
|
|
}
|
|
|
|
export class SaveRewardDto {
|
|
@IsString()
|
|
@MinLength(2)
|
|
@MaxLength(120)
|
|
name!: string;
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@IsString()
|
|
@MaxLength(500)
|
|
description?: string | null;
|
|
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(1)
|
|
@Max(10000000)
|
|
cost!: number;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(40)
|
|
icon?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(20)
|
|
color?: string;
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(0)
|
|
stock?: number | null;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
isActive?: boolean;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
requiresApproval?: boolean;
|
|
}
|
|
|
|
export class SaveBadgeDto {
|
|
@IsString()
|
|
@MinLength(2)
|
|
@MaxLength(120)
|
|
name!: string;
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@IsString()
|
|
@MaxLength(500)
|
|
description?: string | null;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(40)
|
|
icon?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(20)
|
|
color?: string;
|
|
|
|
@IsIn(['event_count', 'score_total', 'routine_streak', 'single_deal_amount'])
|
|
metric!: 'event_count' | 'score_total' | 'routine_streak' | 'single_deal_amount';
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@IsIn(GAMIFICATION_EVENT_KEYS)
|
|
event?: (typeof GAMIFICATION_EVENT_KEYS)[number] | null;
|
|
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(1)
|
|
threshold!: number;
|
|
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(0)
|
|
@Max(1000000)
|
|
coins?: number;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
isActive?: boolean;
|
|
}
|
|
|
|
export class SaveBonusDto {
|
|
@IsString()
|
|
@MinLength(2)
|
|
@MaxLength(120)
|
|
name!: string;
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@IsString()
|
|
@MaxLength(500)
|
|
description?: string | null;
|
|
|
|
@IsIn(['event_count_period', 'routine_streak', 'top_of_month'])
|
|
kind!: 'event_count_period' | 'routine_streak' | 'top_of_month';
|
|
|
|
@IsOptional()
|
|
@nullable()
|
|
@IsIn(GAMIFICATION_EVENT_KEYS)
|
|
event?: (typeof GAMIFICATION_EVENT_KEYS)[number] | null;
|
|
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(1)
|
|
threshold!: number;
|
|
|
|
@IsOptional()
|
|
@IsIn(['day', 'week', 'month'])
|
|
period?: 'day' | 'week' | 'month';
|
|
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(0)
|
|
@Max(1000000)
|
|
score?: number;
|
|
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(0)
|
|
@Max(1000000)
|
|
coins?: number;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
isActive?: boolean;
|
|
}
|
|
|
|
export class UpdateSettingsDto {
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
enabled?: boolean;
|
|
|
|
@IsOptional()
|
|
@IsArray()
|
|
@ArrayMaxSize(20)
|
|
levels?: GamificationLevelDef[];
|
|
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(1)
|
|
@Max(10000000)
|
|
monthlyGoal?: number;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
showFullLeaderboard?: boolean;
|
|
}
|
|
|
|
export class TxQueryDto {
|
|
@IsOptional()
|
|
@IsString()
|
|
userId?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
kind?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
event?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
status?: string;
|
|
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(1)
|
|
page?: number;
|
|
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(1)
|
|
@Max(100)
|
|
limit?: number;
|
|
}
|