2026-05-19 18:04:08 +08:00

251 lines
10 KiB
TypeScript

import { apiRequest } from "@/shared/api/request";
import { API_ENDPOINTS, API_OPERATIONS, apiEndpointPath } from "@/shared/api/generated/endpoints";
import type { ApiPage, PageQuery } from "@/shared/api/types";
export interface LuckyGiftTierDto {
pool: string;
tierId: string;
rewardCoins: number;
weight: number;
highWaterOnly: boolean;
enabled: boolean;
}
export interface LuckyGiftConfigDto {
appCode?: 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;
tiers: LuckyGiftTierDto[];
updatedByAdminId?: number;
createdAtMs?: number;
updatedAtMs?: number;
}
export interface LuckyGiftConfigPayload {
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;
tiers: Array<{
pool: string;
tier_id: string;
reward_coins: number;
weight: number;
high_water_only: boolean;
enabled: boolean;
}>;
}
export interface LuckyGiftDrawDto {
drawId: string;
commandId?: string;
giftId: string;
ruleVersion: number;
experiencePool: string;
selectedTierId: string;
baseRewardCoins: number;
roomAtmosphereRewardCoins: number;
activitySubsidyCoins: number;
effectiveRewardCoins: number;
budgetSourcesJson?: string;
rewardStatus?: string;
rtpWindowIndex: number;
giftRTPWindowIndex: number;
globalBaseRTPPPM: number;
giftBaseRTPPPM: number;
stageFeedback: boolean;
highMultiplier: boolean;
createdAtMs?: number;
}
type RawConfig = LuckyGiftConfigDto & Record<string, unknown>;
type RawTier = LuckyGiftTierDto & Record<string, unknown>;
type RawDraw = LuckyGiftDrawDto & Record<string, unknown>;
export function getLuckyGiftConfig(): Promise<LuckyGiftConfigDto> {
const endpoint = API_ENDPOINTS.getLuckyGiftConfig;
return apiRequest<RawConfig>(apiEndpointPath(API_OPERATIONS.getLuckyGiftConfig), {
method: endpoint.method,
}).then(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,
},
).then(normalizeConfig);
}
export function listLuckyGiftDraws(query: PageQuery = {}): Promise<ApiPage<LuckyGiftDrawDto>> {
const endpoint = API_ENDPOINTS.listLuckyGiftDraws;
return apiRequest<ApiPage<RawDraw>>(apiEndpointPath(API_OPERATIONS.listLuckyGiftDraws), {
method: endpoint.method,
query,
}).then((page) => ({
...page,
items: (page.items || []).map(normalizeDraw),
}));
}
function normalizeConfig(item: RawConfig): LuckyGiftConfigDto {
return {
appCode: stringValue(item.appCode ?? item.app_code),
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),
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),
weight: numberValue(item.weight),
highWaterOnly: booleanValue(item.highWaterOnly ?? item.high_water_only),
enabled: booleanValue(item.enabled),
};
}
function normalizeDraw(item: RawDraw): LuckyGiftDrawDto {
return {
drawId: stringValue(item.drawId ?? item.draw_id),
commandId: stringValue(item.commandId ?? item.command_id),
giftId: stringValue(item.giftId ?? item.gift_id),
ruleVersion: numberValue(item.ruleVersion ?? item.rule_version),
experiencePool: stringValue(item.experiencePool ?? item.experience_pool),
selectedTierId: stringValue(item.selectedTierId ?? item.selected_tier_id),
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),
effectiveRewardCoins: numberValue(item.effectiveRewardCoins ?? item.effective_reward_coins),
budgetSourcesJson: stringValue(item.budgetSourcesJson ?? item.budget_sources_json),
rewardStatus: stringValue(item.rewardStatus ?? item.reward_status),
rtpWindowIndex: numberValue(item.rtpWindowIndex ?? item.rtp_window_index),
giftRTPWindowIndex: numberValue(item.giftRTPWindowIndex ?? item.gift_rtp_window_index),
globalBaseRTPPPM: numberValue(item.globalBaseRTPPPM ?? item.global_base_rtp_ppm),
giftBaseRTPPPM: numberValue(item.giftBaseRTPPPM ?? item.gift_base_rtp_ppm),
stageFeedback: booleanValue(item.stageFeedback ?? item.stage_feedback),
highMultiplier: booleanValue(item.highMultiplier ?? item.high_multiplier),
createdAtMs: numberValue(item.createdAtMs ?? item.created_at_ms),
};
}
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;
}