2026-05-25 19:36:44 +08:00

249 lines
10 KiB
TypeScript

import { apiRequest } from "@/shared/api/request";
import { API_ENDPOINTS, API_OPERATIONS, apiEndpointPath } from "@/shared/api/generated/endpoints";
export interface LuckyGiftTierDto {
pool: string;
tierId: string;
rewardCoins: number;
multiplierPPM: number;
weight: number;
highWaterOnly: boolean;
enabled: boolean;
}
export interface LuckyGiftConfigDto {
appCode?: string;
poolId: string;
enabled: boolean;
ruleVersion: number;
giftPrice: number;
targetRTPPPM: number;
poolRatePPM: number;
globalWindowDraws: number;
giftWindowDraws: number;
noviceDrawLimit: number;
intermediateDrawLimit: number;
highMultiplier: number;
highWaterPoolMultiple: number;
platformPoolWeightPPM: number;
roomPoolWeightPPM: number;
giftPoolWeightPPM: number;
initialPlatformPool: number;
initialGiftPool: number;
initialRoomPool: number;
platformReserve: number;
giftReserve: number;
roomReserve: number;
maxSinglePayout: number;
userHourlyPayoutCap: number;
userDailyPayoutCap: number;
deviceDailyPayoutCap: number;
roomHourlyPayoutCap: number;
anchorDailyPayoutCap: number;
roomAtmosphereRatePPM: number;
roomAtmosphereInitial: number;
roomAtmosphereReserve: number;
activityBudget: number;
activityDailyLimit: number;
largeTierEnabled: boolean;
multiplierPPMs: number[];
tiers: LuckyGiftTierDto[];
updatedByAdminId?: number;
createdAtMs?: number;
updatedAtMs?: number;
}
export interface LuckyGiftConfigPayload {
pool_id: string;
enabled: boolean;
gift_price: number;
target_rtp_ppm: number;
pool_rate_ppm: number;
global_window_draws: number;
gift_window_draws: number;
novice_draw_limit: number;
intermediate_draw_limit: number;
high_multiplier: number;
high_water_pool_multiple: number;
platform_pool_weight_ppm: number;
room_pool_weight_ppm: number;
gift_pool_weight_ppm: number;
initial_platform_pool: number;
initial_gift_pool: number;
initial_room_pool: number;
platform_reserve: number;
gift_reserve: number;
room_reserve: number;
max_single_payout: number;
user_hourly_payout_cap: number;
user_daily_payout_cap: number;
device_daily_payout_cap: number;
room_hourly_payout_cap: number;
anchor_daily_payout_cap: number;
room_atmosphere_rate_ppm: number;
room_atmosphere_initial: number;
room_atmosphere_reserve: number;
activity_budget: number;
activity_daily_limit: number;
large_tier_enabled: boolean;
multiplier_ppms: number[];
tiers: Array<{
pool: string;
tier_id: string;
reward_coins: number;
multiplier_ppm: number;
weight: number;
high_water_only: boolean;
enabled: boolean;
}>;
}
export interface LuckyGiftDrawSummaryDto {
poolId: string;
totalDraws: number;
uniqueUsers: number;
uniqueRooms: number;
totalSpentCoins: number;
totalRewardCoins: number;
baseRewardCoins: number;
roomAtmosphereRewardCoins: number;
activitySubsidyCoins: number;
actualRTPPPM: number;
pendingDraws: number;
grantedDraws: number;
failedDraws: number;
}
type RawConfig = LuckyGiftConfigDto & Record<string, unknown>;
type RawTier = LuckyGiftTierDto & Record<string, unknown>;
type RawSummary = LuckyGiftDrawSummaryDto & Record<string, unknown>;
type LuckyGiftDrawSummaryQuery = Record<string, number | string | undefined>;
export function getLuckyGiftConfig(poolId: string): Promise<LuckyGiftConfigDto> {
const endpoint = API_ENDPOINTS.getLuckyGiftConfig;
return apiRequest<RawConfig>(apiEndpointPath(API_OPERATIONS.getLuckyGiftConfig), {
method: endpoint.method,
query: { pool_id: poolId },
}).then(normalizeConfig);
}
export function listLuckyGiftConfigs(): Promise<LuckyGiftConfigDto[]> {
const endpoint = API_ENDPOINTS.listLuckyGiftConfigs;
return apiRequest<RawConfig[]>(apiEndpointPath(API_OPERATIONS.listLuckyGiftConfigs), {
method: endpoint.method,
}).then((items) => (items || []).map(normalizeConfig));
}
export function updateLuckyGiftConfig(payload: LuckyGiftConfigPayload): Promise<LuckyGiftConfigDto> {
const endpoint = API_ENDPOINTS.upsertLuckyGiftConfig;
return apiRequest<RawConfig, LuckyGiftConfigPayload>(apiEndpointPath(API_OPERATIONS.upsertLuckyGiftConfig), {
body: payload,
method: endpoint.method,
query: { pool_id: payload.pool_id },
}).then(normalizeConfig);
}
export function getLuckyGiftDrawSummary(query: LuckyGiftDrawSummaryQuery = {}): Promise<LuckyGiftDrawSummaryDto> {
const endpoint = API_ENDPOINTS.getLuckyGiftDrawSummary;
return apiRequest<RawSummary>(apiEndpointPath(API_OPERATIONS.getLuckyGiftDrawSummary), {
method: endpoint.method,
query,
}).then(normalizeSummary);
}
function normalizeConfig(item: RawConfig): LuckyGiftConfigDto {
return {
appCode: stringValue(item.appCode ?? item.app_code),
poolId: stringValue(item.poolId ?? item.pool_id ?? item.gift_id),
enabled: booleanValue(item.enabled),
ruleVersion: numberValue(item.ruleVersion ?? item.rule_version),
giftPrice: numberValue(item.giftPrice ?? item.gift_price),
targetRTPPPM: numberValue(item.targetRTPPPM ?? item.target_rtp_ppm),
poolRatePPM: numberValue(item.poolRatePPM ?? item.pool_rate_ppm),
globalWindowDraws: numberValue(item.globalWindowDraws ?? item.global_window_draws),
giftWindowDraws: numberValue(item.giftWindowDraws ?? item.gift_window_draws),
noviceDrawLimit: numberValue(item.noviceDrawLimit ?? item.novice_draw_limit),
intermediateDrawLimit: numberValue(item.intermediateDrawLimit ?? item.intermediate_draw_limit),
highMultiplier: numberValue(item.highMultiplier ?? item.high_multiplier),
highWaterPoolMultiple: numberValue(item.highWaterPoolMultiple ?? item.high_water_pool_multiple),
platformPoolWeightPPM: numberValue(item.platformPoolWeightPPM ?? item.platform_pool_weight_ppm),
roomPoolWeightPPM: numberValue(item.roomPoolWeightPPM ?? item.room_pool_weight_ppm),
giftPoolWeightPPM: numberValue(item.giftPoolWeightPPM ?? item.gift_pool_weight_ppm),
initialPlatformPool: numberValue(item.initialPlatformPool ?? item.initial_platform_pool),
initialGiftPool: numberValue(item.initialGiftPool ?? item.initial_gift_pool),
initialRoomPool: numberValue(item.initialRoomPool ?? item.initial_room_pool),
platformReserve: numberValue(item.platformReserve ?? item.platform_reserve),
giftReserve: numberValue(item.giftReserve ?? item.gift_reserve),
roomReserve: numberValue(item.roomReserve ?? item.room_reserve),
maxSinglePayout: numberValue(item.maxSinglePayout ?? item.max_single_payout),
userHourlyPayoutCap: numberValue(item.userHourlyPayoutCap ?? item.user_hourly_payout_cap),
userDailyPayoutCap: numberValue(item.userDailyPayoutCap ?? item.user_daily_payout_cap),
deviceDailyPayoutCap: numberValue(item.deviceDailyPayoutCap ?? item.device_daily_payout_cap),
roomHourlyPayoutCap: numberValue(item.roomHourlyPayoutCap ?? item.room_hourly_payout_cap),
anchorDailyPayoutCap: numberValue(item.anchorDailyPayoutCap ?? item.anchor_daily_payout_cap),
roomAtmosphereRatePPM: numberValue(item.roomAtmosphereRatePPM ?? item.room_atmosphere_rate_ppm),
roomAtmosphereInitial: numberValue(item.roomAtmosphereInitial ?? item.room_atmosphere_initial),
roomAtmosphereReserve: numberValue(item.roomAtmosphereReserve ?? item.room_atmosphere_reserve),
activityBudget: numberValue(item.activityBudget ?? item.activity_budget),
activityDailyLimit: numberValue(item.activityDailyLimit ?? item.activity_daily_limit),
largeTierEnabled: booleanValue(item.largeTierEnabled ?? item.large_tier_enabled),
multiplierPPMs: arrayValue(item.multiplierPPMs ?? item.multiplier_ppms).map(numberValue),
tiers: arrayValue(item.tiers).map(normalizeTier),
updatedByAdminId: numberValue(item.updatedByAdminId ?? item.updated_by_admin_id),
createdAtMs: numberValue(item.createdAtMs ?? item.created_at_ms),
updatedAtMs: numberValue(item.updatedAtMs ?? item.updated_at_ms),
};
}
function normalizeTier(raw: unknown): LuckyGiftTierDto {
const item = asRecord(raw) as RawTier;
return {
pool: stringValue(item.pool),
tierId: stringValue(item.tierId ?? item.tier_id),
rewardCoins: numberValue(item.rewardCoins ?? item.reward_coins),
multiplierPPM: numberValue(item.multiplierPPM ?? item.multiplier_ppm),
weight: numberValue(item.weight),
highWaterOnly: booleanValue(item.highWaterOnly ?? item.high_water_only),
enabled: booleanValue(item.enabled),
};
}
function normalizeSummary(item: RawSummary): LuckyGiftDrawSummaryDto {
return {
poolId: stringValue(item.poolId ?? item.pool_id),
totalDraws: numberValue(item.totalDraws ?? item.total_draws),
uniqueUsers: numberValue(item.uniqueUsers ?? item.unique_users),
uniqueRooms: numberValue(item.uniqueRooms ?? item.unique_rooms),
totalSpentCoins: numberValue(item.totalSpentCoins ?? item.total_spent_coins),
totalRewardCoins: numberValue(item.totalRewardCoins ?? item.total_reward_coins),
baseRewardCoins: numberValue(item.baseRewardCoins ?? item.base_reward_coins),
roomAtmosphereRewardCoins: numberValue(item.roomAtmosphereRewardCoins ?? item.room_atmosphere_reward_coins),
activitySubsidyCoins: numberValue(item.activitySubsidyCoins ?? item.activity_subsidy_coins),
actualRTPPPM: numberValue(item.actualRTPPPM ?? item.actual_rtp_ppm),
pendingDraws: numberValue(item.pendingDraws ?? item.pending_draws),
grantedDraws: numberValue(item.grantedDraws ?? item.granted_draws),
failedDraws: numberValue(item.failedDraws ?? item.failed_draws),
};
}
function asRecord(value: unknown): Record<string, unknown> {
return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : {};
}
function arrayValue(value: unknown): unknown[] {
return Array.isArray(value) ? value : [];
}
function booleanValue(value: unknown) {
return value === true || value === "true" || value === 1 || value === "1";
}
function stringValue(value: unknown) {
return typeof value === "string" ? value : value === undefined || value === null ? "" : String(value);
}
function numberValue(value: unknown) {
const number = Number(value || 0);
return Number.isFinite(number) ? number : 0;
}