All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 47s
515 lines
19 KiB
TypeScript
515 lines
19 KiB
TypeScript
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<string> = 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)) {
|
|
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);
|
|
}
|
|
}
|