export type SubscriptionTier = 'free' | 'pro' | 'proplus'; export type SubscriptionStatus = 'none' | 'active' | 'expired' | 'cancelled'; export type NodeStatus = 'done' | 'current' | 'locked' | 'chest'; export type LeaderboardScope = 'region' | 'topic'; export type RewardSource = 'ad' | 'check_in' | 'subscription' | 'admin_grant' | 'debug'; export type SubscriptionPlatform = 'huawei' | 'apple' | 'google'; export interface RegionDto { code: string; name: string; shortName: string; parentCode: string | null; level: number; sortOrder: number; enabled: boolean; } export interface RegionsConfigDto { version: string; countryCode: 'CN'; hierarchy: 'flat'; updatedAt: string; regions: readonly RegionDto[]; } export interface UserRegionDto { code: string; name: string; shortName: string; selectedAt: string | null; nextChangeAllowedAt: string | null; } export interface UserBriefDto { id: string; nickname: string; avatarUrl: string | null; tier: SubscriptionTier; level: number; region: UserRegionDto | null; } export interface SubscriptionDto { status: SubscriptionStatus; tier: SubscriptionTier; expiresAt: string | null; autoRenew?: boolean; } export interface ProgressSummaryDto { hearts: number; maxHearts: number; nextHeartRestoreAt: string | null; dailyAttemptsLeft: number; dailyAttemptsMax: number; nextAttemptResetAt: string | null; highRewardSessionsLeft: number; highRewardSessionsMax: number; xp: number; level: number; xpToNextLevel: number; streakDays: number; checkInDays: number; streakProtectedUntil: string | null; activeTrackId: string | null; isSubscribed: boolean; } export interface ThemeNodeDto { id: string; title: string; status: NodeStatus; reward: string; questionCount: number; } export interface ThemeTrackDto { id: string; name: string; icon: string; progress: number; nodes: ThemeNodeDto[]; } export interface ShopBenefitDto { id: string; type: 'hearts' | 'attempts' | 'streak' | 'subscription'; title: string; description: string; enabled: boolean; requiresAd: boolean; } export type ShopProductType = 'item' | 'cosmetic'; export type ShopProductId = | 'hint-feather' | 'heart-supply' | 'double-xp-potion' | 'streak-shield' | 'mascot-outfit-starter'; export interface ShopProductDto { id: ShopProductId; type: ShopProductType; itemId: string; title: string; description: string; priceCoins: number; quantity: number; enabled: boolean; } export interface ShopCatalogDto { benefits: readonly ShopBenefitDto[]; products: readonly ShopProductDto[]; } export interface ShopPurchaseResultDto { product: ShopProductDto; coinsSpent: number; coinsBalance: number; item: { itemId: string; quantity: number; activeUntil: string | null; metadata: Record | null; }; rewards: ReadonlyArray<{ type: string; source?: string; amount?: number; itemId?: string; quantity?: number; title?: string; }>; } export interface WalletDto { coinsBalance: number; } export interface InventoryItemDto { itemId: string; quantity: number; activeUntil: string | null; metadata: Record | null; } export interface InventoryDto { items: readonly InventoryItemDto[]; } export type UsableInventoryItemId = 'streak_shield' | 'double_xp_potion' | 'heart_supply' | 'hint_feather'; export interface UseInventoryItemResultDto { itemId: UsableInventoryItemId; quantityRemaining: number; effect: { type: 'restore_hearts' | 'double_xp' | 'hint' | 'streak_protection'; activeUntil?: string | null; hearts?: number; excludedOptions?: readonly string[]; streakProtectedUntil?: string | null; }; } export interface BootstrapDto { user: UserBriefDto; progress: ProgressSummaryDto; tracks: ThemeTrackDto[]; shopBenefits: readonly ShopBenefitDto[]; shop: ShopCatalogDto; wallet: WalletDto; inventory: InventoryDto; subscription: SubscriptionDto; } export interface ChallengeQuestionDto { challengeId: string; trackId: string; nodeId: string; question: { id: string; prompt: string; options: ReadonlyArray<{ id: string; text: string }>; }; } export interface ChallengeSessionDto { challengeId: string; trackId: string; nodeId: string; totalQuestions: number; highRewardEligible: boolean; questions: readonly ChallengeQuestionDto[]; /** 已提交过答案的题目 ID(用于 session 续答场景,客户端据此跳到下一道未答题)。 */ answeredQuestionIds: readonly string[]; } /** 知识卡查看事件响应:返回本次发放的 XP 奖励和最新进度。 */ export interface KnowledgeCardViewDto { cardId: string; rewards: ReadonlyArray<{ type: string; source?: string; amount?: number; title?: string; }>; progress: ProgressSummaryDto; } export interface AnswerRequestDto { challengeId: string; questionId: string; selectedOptionId: string; timeMs: number; submitRequestId?: string; } export interface AnswerResultDto { answerState: 'correct' | 'wrong'; correctOptionId: string; xpDelta: number; progress: { hearts: number; dailyAttemptsLeft: number; highRewardSessionsLeft: number; highRewardSessionsMax: number; xp: number; streakDays: number; }; knowledgeCard: { id: string; title: string; summary: string; fact: string; }; rewards: ReadonlyArray<{ type: string; source?: string; amount?: number; itemId?: string; quantity?: number; title?: string; }>; } export interface LeaderboardEntryDto { rank: number; userId: string; displayName: string; avatarUrl: string | null; xp: number; badge: string; isMe: boolean; } /** 周榜元信息,附带在排行榜响应中。 */ export interface LeaderboardMetaDto { weekStart: string; weekEnd: string; nextRefreshAt: string; groupId: string | null; requiresRegionSelection?: boolean; selectedRegion?: UserRegionDto | null; viewRegion?: RegionDto | null; /** 当前用户组内排名(仅 /leaderboards/me 返回)。 */ rank?: number; /** 当前周奖励预览:各组前 3 名的金币奖励。 */ rewardPreview: Array<{ rank: number; coins: number }>; }