MatchMaster/assets/seven_day_gift/SevenDayGiftRuntime.ts

145 lines
5.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { SevenDayActivityInfo, SevenDayRewardItem, SevenDayRewardReceipt } from "./SevenDayGiftApi";
import SevenDayGiftReward from "./SevenDayGiftReward";
type ClaimHandler = (callback: (success: boolean) => void) => void;
export interface SevenDayGiftRuntimeView {
playRewardEffect(items: SevenDayRewardItem[], day: number, done: () => void): void;
setData(info: SevenDayActivityInfo, claimHandler: ClaimHandler): void;
setCloseHandler(closeHandler: () => void): void;
// 绑定正式领取回调,再展示活动。
show(autoClaim?: boolean): void;
}
/** Bundle 内的正式业务逻辑,只处理活动领取、发奖和状态刷新。 */
export default class SevenDayGiftRuntime {
private info: SevenDayActivityInfo = null;
private claiming = false;
private loadingSequence = 0;
private loadingTimer: any = null;
private loadingVisible = false;
private disposed = false;
constructor(private view: SevenDayGiftRuntimeView) { }
// 接收主页传入的快照和关闭回调。
public initialize(info: SevenDayActivityInfo, closeHandler: () => void) {
if (this.disposed) return;
this.view.setCloseHandler(closeHandler);
if (info) this.updateInfo(info);
}
// 领取期间不覆盖正在使用的活动快照。
public updateInfo(info: SevenDayActivityInfo) {
if (this.disposed || this.claiming || !info) return;
this.info = info;
this.view.setData(this.info, this.claimReward.bind(this));
}
public show(autoClaim: boolean = false) {
if (!this.info || this.disposed) return;
this.view.setData(this.info, this.claimReward.bind(this));
this.view.show(autoClaim);
}
// 销毁后忽略异步结果,并清理加载提示。
public destroy() {
if (this.disposed) return;
this.disposed = true;
this.closeHomeLoading(this.loadingSequence);
this.claiming = false;
this.info = null;
this.view = null;
}
// 从当前查询快照生成奖励记录,同步成功后更新状态并播放效果。
private claimReward(callback: (success: boolean) => void) {
if (this.disposed || this.claiming || !this.info || !this.info.canClaim || this.info.todayClaimed) {
callback(false);
return;
}
const rewardDay = Number(this.info.nextRewardDay);
const reward = Array.isArray(this.info.rewards)
? this.info.rewards.find(item => Number(item.day) === rewardDay) : null;
if (!this.info.activityId || !this.info.startAt || !reward || reward.claimed || !Array.isArray(reward.items) || reward.items.length === 0) {
cc.warn("[SevenDayGift] 活动查询没有返回可领取奖励");
callback(false);
return;
}
// 消费主页查询的快照,不再次请求活动接口。UID 由 Reward 加入本地防重键。
const claimedCount = Math.max(Number(this.info.claimedCount) || 0, rewardDay);
const receipt: SevenDayRewardReceipt = {
claimId: JSON.stringify([this.info.activityId, this.info.startAt, rewardDay]),
rewardDay,
rewards: reward.items,
claimedCount,
todayClaimed: true,
completed: claimedCount >= 7,
};
this.claiming = true;
const loadingToken = this.openHomeLoading(7000);
SevenDayGiftReward.grant(receipt, (success: boolean, message?: string) => {
if (this.disposed) return;
this.claiming = false;
this.closeHomeLoading(loadingToken);
if (!success) {
cc.warn("[SevenDayGift] 奖励同步失败", message);
callback(false);
return;
}
this.applyClaimState(receipt.rewardDay, receipt.claimedCount, receipt.completed);
this.view.playRewardEffect(receipt.rewards, receipt.rewardDay, () => {
if (!this.disposed) callback(true);
});
});
}
// 本地标记当天已领,第七天领取后标记活动完成。
private applyClaimState(rewardDay: number, claimedCount: number, completed: boolean) {
if (!this.info) return;
this.info.claimedCount = Number(claimedCount) || this.info.claimedCount;
this.info.todayClaimed = true;
this.info.canClaim = false;
if (completed) this.info.status = "completed";
if (Array.isArray(this.info.rewards)) {
this.info.rewards.forEach(reward => {
if (Number(reward.day) === Number(rewardDay)) reward.claimed = true;
});
}
this.view.setData(this.info, this.claimReward.bind(this));
}
// 打开主页加载提示,设置超时以免一直遮挡。
private openHomeLoading(timeoutMs: number): number {
const token = ++this.loadingSequence;
if (this.loadingTimer !== null) clearTimeout(this.loadingTimer);
const home = this.getHomeController();
if (home && typeof home.openLoad === "function") {
this.loadingVisible = true;
home.openLoad();
}
this.loadingTimer = setTimeout(() => this.closeHomeLoading(token), timeoutMs);
return token;
}
// 仅关闭对应请求的提示,避免旧计时器干扰新请求。
private closeHomeLoading(token: number) {
if (token !== this.loadingSequence) return;
if (this.loadingTimer !== null) {
clearTimeout(this.loadingTimer);
this.loadingTimer = null;
}
if (!this.loadingVisible) return;
this.loadingVisible = false;
const home = this.getHomeController();
if (home && typeof home.closeLoad === "function") home.closeLoad();
}
// 通过主页组件调用现有加载提示。
private getHomeController(): any {
const canvas = cc.find("Canvas");
return canvas && canvas.getComponent("JiaZai");
}
}