import { _decorator, Button, Color, Component, Label, Node, Sprite, Tween, tween } from 'cc'; import { VirtualScrollView } from './VScrollView'; import { Palette } from './Palette'; import { SlotRankingDataManager } from './SlotRankingDataManager'; import { callGameApiForRank } from 'db://assets/Loading/scripts/comm'; import { AudioManager } from 'db://assets/Loading/scripts/manager/AudioManager'; import { I18nManager } from 'db://assets/Loading/scripts/manager/I18nManager'; const { ccclass, property } = _decorator; @ccclass('RewardList') export class RewardList extends Component { rewardList: Node = null; // 奖励列表节点 rewardLoadingNode: Node = null; // 奖励加载动画节点 // 奖励列表 - 虚拟列表 rewardListVScroll: VirtualScrollView = null; // 奖励列表虚拟列表 // 奖励列表 - 日周月切换 rewardRadioDWM: Node = null; // 奖励日周月单选按钮父节点 rewardRadioDayBtn: Node = null; // 奖励日榜单选按钮 rewardRadioWeekBtn: Node = null; // 奖励周榜单选按钮 rewardRadioMonthBtn: Node = null; // 奖励月榜单选按钮 rewardHistoryBtn: Node = null; // 历史记录按钮 rewardReceivedBtn: Node = null; // 一键领奖按钮 rewardBackBtn: Node = null; // 返回排行榜按钮 selfRewardListVScroll: VirtualScrollView = null; // 自己的奖励列表虚拟列表 // 活动未开启提示 activityNotOpenTip: Node = null; // 活动未开启提示 label currentRewardType: string = ''; countdownTimer: any = null; // 存储定时器 availableTypes: Set = new Set(); // 可用的类型 rewardsData: any = null; // 奖励数据 selfRewardsList: any[] = []; // 自己的奖励列表 isReceiving: boolean = false; // 是否正在领取中 slotScene: any = null; // SlotScene 引用 // 回调函数 onShowHistory: (type: string) => void = null; // 跳转到领奖记录 onShowRank: (type: string) => void = null; // 跳转回排行榜 onClose: () => void = null; // 关闭主弹窗 init(rewardListNode: Node) { this.rewardList = rewardListNode; this.rewardLoadingNode = this.rewardList.getChildByName('list').getChildByName('loading'); this.rewardListVScroll = this.rewardList.getChildByName('list').getChildByName('vScroll').getComponent(VirtualScrollView); this.rewardRadioDWM = this.rewardList.getChildByName('rewardRadioDWM'); this.rewardRadioDayBtn = this.rewardRadioDWM.getChildByName('dayBtn'); this.rewardRadioWeekBtn = this.rewardRadioDWM.getChildByName('weekBtn'); this.rewardRadioMonthBtn = this.rewardRadioDWM.getChildByName('monthBtn'); this.rewardHistoryBtn = this.rewardList.getChildByName('history'); this.rewardReceivedBtn = this.rewardList.getChildByName('receiveBtn'); let radioTitle = this.rewardList.getChildByName('radioTitle'); this.rewardBackBtn = radioTitle.getChildByName('rankBtn'); this.selfRewardListVScroll = this.rewardList.getChildByName('selfRewardList').getChildByName('vScroll').getComponent(VirtualScrollView); this.activityNotOpenTip = this.rewardList.getChildByName('list').getChildByName('activityNotOpenTip'); this.rewardList.active = false; this.rewardLoadingNode.active = false; this.activityNotOpenTip.active = false; this.rewardHistoryBtn.on(Node.EventType.TOUCH_END, this.onClickHistoryBtn, this); this.rewardReceivedBtn.on(Node.EventType.TOUCH_END, this.onClickReceiveBtn, this); this.rewardBackBtn.on(Node.EventType.TOUCH_END, this.onClickBackBtn, this); this.rewardRadioDayBtn.on(Node.EventType.TOUCH_END, this.onClickRewardRadioDayBtn, this); this.rewardRadioWeekBtn.on(Node.EventType.TOUCH_END, this.onClickRewardRadioWeekBtn, this); this.rewardRadioMonthBtn.on(Node.EventType.TOUCH_END, this.onClickRewardRadioMonthBtn, this); } // ==================== 对外接口 ==================== setSlotScene(slotScene: any) { this.slotScene = slotScene; } async show(defaultType: string = 'day') { this.rewardList.active = true; this.currentRewardType = ''; this.updateRewardButtonsAvailability(); await this.switchRewardTab(defaultType); } hide() { this.rewardList.active = false; if (this.countdownTimer) { clearInterval(this.countdownTimer); this.countdownTimer = null; } } getCurrentType(): string { return this.currentRewardType; } // ==================== 奖励列表逻辑 ==================== isTypeAvailable(type: string): boolean { return this.availableTypes.has(type); } showActivityNotOpenTip() { this.activityNotOpenTip.active = true; this.rewardListVScroll.setTotalCount(0); } async switchRewardTab(type: string) { if (this.currentRewardType === type) { return; } this.currentRewardType = type; this.setRewardRadioBtn(type); if (!this.isTypeAvailable(type) || SlotRankingDataManager.instance.getRankListStatusByType(type) !== 0) { console.log(`${type} 奖励榜单活动未开启`); this.rewardLoadingNode.active = false; this.showActivityNotOpenTip(); if (this.countdownTimer) { clearInterval(this.countdownTimer); this.countdownTimer = null; } return; } this.activityNotOpenTip.active = false; this.rewardListVScroll.setTotalCount(0); this.selfRewardListVScroll.setTotalCount(0); Tween.stopAllByTarget(this.rewardLoadingNode); this.rewardLoadingNode.active = true; tween(this.rewardLoadingNode) .by(0.3, { angle: 360 }) .repeatForever() .start(); this.setRewardEndTime(type); try { let rewardsData = await callGameApiForRank('rewardsList', {}); this.rewardsData = rewardsData; Tween.stopAllByTarget(this.rewardLoadingNode); this.rewardLoadingNode.active = false; this.openRewardPopup(); this.openSelfRewardPopup(); } catch (error) { console.error('获取奖励列表数据失败:', error); this.showActivityNotOpenTip(); Tween.stopAllByTarget(this.rewardLoadingNode); this.rewardLoadingNode.active = false; } } openRewardPopup() { let rankList = SlotRankingDataManager.instance.rankList; if (!rankList || !rankList.List) { this.rewardListVScroll.setTotalCount(0); return; } let currentActivity = rankList.List.find((item: any) => item.Type === this.currentRewardType); if (!currentActivity || !currentActivity.Rewards || currentActivity.Rewards.length === 0) { this.rewardListVScroll.setTotalCount(0); return; } let rewards = currentActivity.Rewards; this.rewardListVScroll.setTotalCount(rewards.length); this.rewardListVScroll.renderItemFn = (node: Node, idx: number) => { let rewardAmount = rewards[idx]; if (rewardAmount === undefined) { return; } let rank = idx + 1; node.getChildByName('bg').active = idx % 2 === 0; node.getChildByName('bg2').active = idx % 2 !== 0; node.getChildByName('Rank').getChildByName('sp_1').active = rank === 1; node.getChildByName('Rank').getChildByName('sp_2').active = rank === 2; node.getChildByName('Rank').getChildByName('sp_3').active = rank === 3; node.getChildByName('Rank').getChildByName('rankLab').active = rank >= 4; node.getChildByName('Rank').getChildByName('rankLab').getComponent(Label).string = rank.toString(); node.getChildByName('Win').getComponent(Label).string = rewardAmount.toString(); } this.rewardListVScroll.refreshList(rewards); } openSelfRewardPopup() { if (!this.rewardsData) { this.selfRewardListVScroll.setTotalCount(0); return; } this.selfRewardsList = []; if (this.rewardsData.DayRanks && this.rewardsData.DayRanks.length > 0) { for (let item of this.rewardsData.DayRanks) { this.selfRewardsList.push({ ...item, TypeLabel: I18nManager.instance.t('Daily Ranking') }); } } if (this.rewardsData.WeekRanks && this.rewardsData.WeekRanks.length > 0) { for (let item of this.rewardsData.WeekRanks) { this.selfRewardsList.push({ ...item, TypeLabel: I18nManager.instance.t('Weekly Ranking') }); } } if (this.rewardsData.MonthRanks && this.rewardsData.MonthRanks.length > 0) { for (let item of this.rewardsData.MonthRanks) { this.selfRewardsList.push({ ...item, TypeLabel: I18nManager.instance.t('Monthly Ranking') }); } } if (this.selfRewardsList.length === 0) { this.selfRewardListVScroll.setTotalCount(0); return; } this.selfRewardListVScroll.setTotalCount(this.selfRewardsList.length); this.selfRewardListVScroll.renderItemFn = (node: Node, idx: number) => { let itemData = this.selfRewardsList[idx]; if (!itemData) { return; } node.getChildByName('Activity').getComponent(Label).string = itemData.TypeLabel; let activityTime = itemData.Id.split('_')[0]; node.getChildByName('ActivityTime').getComponent(Label).string = activityTime; node.getChildByName('Rank').getChildByName('sp_1').active = itemData.Rank === 1; node.getChildByName('Rank').getChildByName('sp_2').active = itemData.Rank === 2; node.getChildByName('Rank').getChildByName('sp_3').active = itemData.Rank === 3; node.getChildByName('Rank').getChildByName('rankLab').active = itemData.Rank >= 4; node.getChildByName('Rank').getChildByName('rankLab').getComponent(Label).string = itemData.Rank.toString(); node.getChildByName('Win').getComponent(Label).string = itemData.Rewards.toString(); let received = node.getChildByName('HasReceived').getChildByName('received'); let unReceived = node.getChildByName('HasReceived').getChildByName('unReceived'); received.active = itemData.IsPrize; unReceived.active = !itemData.IsPrize; } this.selfRewardListVScroll.refreshList(this.selfRewardsList); } // ==================== 一键领奖 ==================== async receiveAllRewards() { if (this.isReceiving) { console.log('正在领取中,请稍候...'); return; } // 收集所有未领取的奖励ID let pendingIds: string[] = []; for (let item of this.selfRewardsList) { if (!item.IsPrize) { pendingIds.push(item.Id); } } if (pendingIds.length === 0) { console.log('没有可领取的奖励'); return; } this.isReceiving = true; this.setButtonsInteractable(false); try { // 一次性发送所有ID let result = await callGameApiForRank('getRewards', { Ids: pendingIds }); console.log('一键领奖成功', result); // 处理返回的成功ID数组 if (result && result.Ids && Array.isArray(result.Ids)) { // 更新成功领取的item状态 for (let successId of result.Ids) { let item = this.selfRewardsList.find((item: any) => item.Id === successId); if (item) { item.IsPrize = true; } } // 刷新列表显示 this.selfRewardListVScroll.refreshList(this.selfRewardsList); // 更新 slotScene 的 balance if (result.Balance !== undefined && this.slotScene && this.slotScene.slotBar) { this.slotScene.slotBar.setBalance(result.Balance); } console.log(`成功领取 ${result.Ids.length} 个奖励,新余额: ${result.Balance}`); } else { console.warn('领奖返回数据格式异常', result); } } catch (error) { console.error('一键领奖失败', error); } finally { this.isReceiving = false; this.setButtonsInteractable(true); } } setButtonsInteractable(interactable: boolean) { let receiveBtn = this.rewardReceivedBtn.getComponent(Button); if (receiveBtn) { receiveBtn.interactable = interactable; } let backBtn = this.rewardBackBtn.getComponent(Button); if (backBtn) { backBtn.interactable = interactable; } let historyBtn = this.rewardHistoryBtn.getComponent(Button); if (historyBtn) { historyBtn.interactable = interactable; } let dayBtn = this.rewardRadioDayBtn.getComponent(Button); if (dayBtn) { dayBtn.interactable = interactable; } let weekBtn = this.rewardRadioWeekBtn.getComponent(Button); if (weekBtn) { weekBtn.interactable = interactable; } let monthBtn = this.rewardRadioMonthBtn.getComponent(Button); if (monthBtn) { monthBtn.interactable = interactable; } } // ==================== 按钮状态管理 ==================== updateRewardButtonsAvailability() { let rankList = SlotRankingDataManager.instance.rankList; this.availableTypes.clear(); if (rankList && rankList.List) { for (let item of rankList.List) { this.availableTypes.add(item.Type); } } this.updateButtonAvailability(this.rewardRadioDayBtn); this.updateButtonAvailability(this.rewardRadioWeekBtn); this.updateButtonAvailability(this.rewardRadioMonthBtn); } updateButtonAvailability(btn: Node) { btn.active = true; let button = btn.getComponent(Button); if (button) { button.interactable = true; } let check = btn.getChildByName('check'); let unCheck = btn.getChildByName('unCheck'); let whiteColor = Color.WHITE; if (check) { let checkSprite = check.getComponent(Sprite); if (checkSprite) { checkSprite.color = whiteColor; } } if (unCheck) { let unCheckSprite = unCheck.getComponent(Sprite); if (unCheckSprite) { unCheckSprite.color = whiteColor; } } } setRewardRadioBtn(type: string) { let selectedColor = new Color(57, 1, 3, 255); let unselectedColor = new Color(37, 78, 21, 255); this.setRadioBtnState(this.rewardRadioDayBtn, type === 'day', selectedColor, unselectedColor); this.setRadioBtnState(this.rewardRadioWeekBtn, type === 'week', selectedColor, unselectedColor); this.setRadioBtnState(this.rewardRadioMonthBtn, type === 'month', selectedColor, unselectedColor); } setRadioBtnState(btn: Node, isSelected: boolean, selectedColor: Color, unselectedColor: Color) { let check = btn.getChildByName('check'); let unCheck = btn.getChildByName('unCheck'); let label = btn.getChildByName('label'); let palette = label?.getComponent(Palette); if (isSelected) { check.active = true; unCheck.active = false; if (palette) { palette.colorLB = selectedColor; palette.colorRB = selectedColor; } } else { check.active = false; unCheck.active = true; if (palette) { palette.colorLB = unselectedColor; palette.colorRB = unselectedColor; } } } // ==================== 倒计时功能 ==================== setRewardEndTime(type: string) { if (this.countdownTimer) { clearInterval(this.countdownTimer); this.countdownTimer = null; } let endTime = SlotRankingDataManager.instance.getRankEndTimeByType(type); this.updateCountdown(endTime); this.countdownTimer = setInterval(() => { this.updateCountdown(endTime); }, 1000); } updateCountdown(endTime: number) { let now = Math.floor(Date.now() / 1000); let remainingSeconds = endTime - now; if (remainingSeconds <= 0) { if (this.countdownTimer) { clearInterval(this.countdownTimer); this.countdownTimer = null; } return; } let timeStr = this.formatCountdown(remainingSeconds); } formatCountdown(seconds: number): string { let days = Math.floor(seconds / 86400); let hours = Math.floor((seconds % 86400) / 3600); let minutes = Math.floor((seconds % 3600) / 60); let secs = seconds % 60; if (days >= 1) { return `${days}d ${hours}h ${minutes}min ${secs}s`; } else { return `${hours}h ${minutes}min ${secs}s`; } } // ==================== 按钮事件 ==================== onClickRewardRadioDayBtn() { AudioManager.instance.playSFX("Common_Button_Click"); this.switchRewardTab('day'); } onClickRewardRadioWeekBtn() { AudioManager.instance.playSFX("Common_Button_Click"); this.switchRewardTab('week'); } onClickRewardRadioMonthBtn() { AudioManager.instance.playSFX("Common_Button_Click"); this.switchRewardTab('month'); } onClickHistoryBtn() { AudioManager.instance.playSFX("Common_Button_Click"); this.onShowHistory?.call(null, this.currentRewardType || 'day'); } onClickReceiveBtn() { AudioManager.instance.playSFX("Common_Button_Click"); this.receiveAllRewards(); } onClickBackBtn() { AudioManager.instance.playSFX("Common_Button_Click"); this.onShowRank?.call(null, this.currentRewardType || 'day'); } onDestroy() { clearInterval(this.countdownTimer); this.countdownTimer = null; this.rewardHistoryBtn.off(Node.EventType.TOUCH_END, this.onClickHistoryBtn, this); this.rewardReceivedBtn.off(Node.EventType.TOUCH_END, this.onClickReceiveBtn, this); this.rewardBackBtn.off(Node.EventType.TOUCH_END, this.onClickBackBtn, this); this.rewardRadioDayBtn.off(Node.EventType.TOUCH_END, this.onClickRewardRadioDayBtn, this); this.rewardRadioWeekBtn.off(Node.EventType.TOUCH_END, this.onClickRewardRadioWeekBtn, this); this.rewardRadioMonthBtn.off(Node.EventType.TOUCH_END, this.onClickRewardRadioMonthBtn, this); } }