import SevenApiPanel from "./SevenApiPanel"; const { ccclass } = cc._decorator; /** 仅编辑器预览使用。通过真实 Prefab 的视图接口模拟,不调用正式 Runtime。 */ @ccclass export default class TestSeven extends cc.Component { private gift: cc.Node = null; private view: any = null; private info: any = null; private status: cc.Label = null; private busy = false; private failNext = false; // 仅在编辑器预览加载真实活动 Prefab,并创建测试按钮。 start() { if (!CC_PREVIEW) { cc.error("[testSeven] 仅允许编辑器预览,请从构建中排除 testSeven。"); return; } this.status = this.label("正在加载 seven_day_gift…", 0, 850, 26); this.button("临时打开 JungleTreasure", 0, 645, () => this.openJunglePreview()); const apiPanel = this.node.addComponent(SevenApiPanel); apiPanel.preview = info => { if (!this.view || this.busy) return this.report("请等待活动资源加载或奖励动画结束"); this.info = info; this.open(); this.report("接口数据模拟 | 点击当天奖励领取,或点击外部只领取,本次不关闭(不增加资产)"); }; cc.assetManager.loadBundle("seven_day_gift", (error, bundle) => { if (!cc.isValid(this.node, true)) return; if (error) return this.report("分包加载失败:" + error.message); bundle.load("prefab/sevenDayGift", cc.Prefab, (loadError, prefab: cc.Prefab) => { if (!cc.isValid(this.node, true)) return; if (loadError) return this.report("Prefab 加载失败:" + loadError.message); this.gift = cc.instantiate(prefab); this.node.addChild(this.gift); this.gift.setPosition(0, 0); this.view = this.gift.getComponent("SevenDayGift"); if (!this.view) return this.report("缺少 SevenDayGift 组件"); this.view.setCloseHandler(() => this.report("已关闭,可选择状态重新打开")); // 控制面板在遮罩上方,使用与活动一致的 1080 × 1920 设计尺寸。 for (let day = 1; day <= 7; day++) { this.button("第" + day + "天", (day - 4) * 140, -670, () => this.select(day)); } this.button("今日已领", -330, -755, () => this.select(this.info.nextRewardDay, "claimed")); this.button("全部完成", -110, -755, () => this.select(7, "completed")); this.button("已过期", 110, -755, () => this.select(3, "expired")); this.button("点击外部", 330, -755, () => { if (this.gift.active) this.view.close(); else this.report("弹窗已关闭,请先重新打开"); }); this.button("下次失败", -220, -840, () => { this.failNext = true; this.report("下一次领取模拟失败,可再次点击重试"); }); this.button("重新打开", 0, -840, () => this.open()); this.button("重置", 220, -840, () => { this.failNext = false; this.select(1); }); this.button("预览弹出上浮(不领取)", 0, 730, () => { if (!this.gift.active) this.open(); const reward = this.info.rewards.find(item => Number(item.day) === Number(this.info.nextRewardDay)); if (!reward) return; this.busy = true; this.view.playRewardEffect(reward.items, reward.day, () => { this.busy = false; }); }); this.select(1); }); }); } // 临时查看真实丛林活动界面;使用内存样例和原有动画预览模式。 private openJunglePreview() { if (!CC_PREVIEW || this.busy) return; this.busy = true; this.report("正在加载 JungleTreasure…"); cc.assetManager.loadBundle("jungle_treasure", (error, bundle) => { if (!cc.isValid(this.node, true)) return; if (error) { this.busy = false; return this.report("丛林分包加载失败:" + error.message); } bundle.load("prefab/jungle", cc.Prefab, (loadError, prefab: cc.Prefab) => { if (!cc.isValid(this.node, true)) return; if (loadError) { this.busy = false; return this.report("丛林界面加载失败:" + loadError.message); } const node = cc.instantiate(prefab); node.active = false; const manager: any = node.getComponent("jungle_Manager"); if (!manager) { node.destroy(); this.busy = false; return this.report("丛林界面缺少 jungle_Manager 组件"); } manager.previewAnimationOnly = true; // 独立预览场景没有主页音频管理器,当前实例关闭音效。 manager.anniuMusic = manager.unLockMusic = manager.rewardMusic = null; this.node.addChild(node); node.setPosition(0, 0); node.zIndex = 3000; const close = () => { node.destroy(); this.busy = false; this.report("已关闭 JungleTreasure,可继续七日活动测试"); }; node.on("jungle-close", close, this); node.on("jungle-complete", close, this); node.active = true; const types = ["coin", "freeze", "hammer", "magic_wand", "infinite_health"]; const config = { activityId: "testSeven-jungle-preview", endAt: Date.now() + 86400000, tiers: types.map((type, index) => ({ id: index + 1, price: index === 2 ? 6 : 0, rewards: [{ type, count: type === "coin" ? 500 : type === "infinite_health" ? 1800 : 2 }], })), }; if (!manager.setServerData(config, [1, 1, 0, 1, 1])) { close(); return this.report("丛林预览数据初始化失败"); } manager.openActivity(); this.report("JungleTreasure 本地界面预览,不发奖、不支付"); }); }); } // 生成指定天数和状态的内存样例,不修改账号资产。 private select(day: number, state: string = "active") { if (this.busy) return; const claimedCount = state === "completed" ? 7 : state === "claimed" ? day : day - 1; const items = [ [{ type: "coin", count: 100 }], [{ type: "hammer", count: 2 }], [{ type: "freeze", count: 2 }, { type: "coin", count: 200 }], [{ type: "magic_wand", count: 2 }], [{ type: "infinite_health", count: 1800 }], // 秒:30 分钟,效果显示 +1800秒。 [{ type: "hammer", count: 1 }, { type: "freeze", count: 1 }], // 第六天移除魔法棒。 [{ type: "infinite_health", count: 1800 }, { type: "cat_skin", count: 1, itemId: 1 }], ]; this.info = { serverNow: Date.now(), activityId: "testSeven-memory", status: state === "claimed" ? "active" : state, triggerLevel: 23, triggerReached: true, startAt: Date.now() - 86400000, endAt: Date.now() + (state === "expired" ? -1 : 7 * 86400000), claimedCount, todayClaimed: state === "claimed" || state === "completed", canClaim: state === "active", nextRewardDay: day, rewards: items.map((reward, index) => ({ day: index + 1, items: reward, claimed: index < claimedCount })), }; this.open(); } // 用当前模拟状态重新打开弹窗。 private open() { if (this.busy || !this.view || !this.info) return; this.bindData(); this.view.show(); this.report("本地模拟 | 第" + this.info.nextRewardDay + "天 | " + this.info.status + " | 已领 " + this.info.claimedCount + "/7"); } // 本地领取立即响应,支持一次失败;成功后使用正式视图的领取效果。 private bindData() { this.view.setData(this.info, (done: (success: boolean) => void) => { if (this.busy || !this.info.canClaim) return done(false); const reward = this.info.rewards.find(item => Number(item.day) === Number(this.info.nextRewardDay)); if (!reward || reward.claimed || !Array.isArray(reward.items) || reward.items.length === 0) { done(false); return this.report("当前数据没有可领取奖励,请重新选择模拟天数或查询接口"); } if (this.failNext) { this.failNext = false; done(false); return this.report("模拟领取失败,弹窗保留;可点击当天奖励或外部重试"); } this.busy = true; reward.claimed = true; this.info.claimedCount++; this.info.todayClaimed = true; this.info.canClaim = false; if (this.info.claimedCount === 7) this.info.status = "completed"; // 更新视图仍沿用本地回调,不调用 initializeRuntime。 this.bindData(); this.view.playRewardEffect(reward.items, reward.day, () => { this.busy = false; done(true); }); this.report("模拟领取成功(不写入资产):" + reward.items.map(item => item.type + " × " + item.count).join(" / ")); }); } // 更新测试状态提示。 private report(message: string) { this.status.string = message; } // 创建测试面板文字,放在活动遮罩上方。 private label(text: string, x: number, y: number, size: number): cc.Label { const node = new cc.Node("testSevenLabel"); this.node.addChild(node); node.setPosition(x, y); node.zIndex = 1000; const label = node.addComponent(cc.Label); label.string = text; label.fontSize = size; label.lineHeight = size + 6; return label; } // 创建测试按钮,忙碌时忽略操作,避免切换正在播放的数据。 private button(text: string, x: number, y: number, action: () => void) { const label = this.label(text, x, y, 28); label.node.color = cc.color(110, 225, 255); label.node.on(cc.Node.EventType.TOUCH_END, (event: cc.Event) => { event.stopPropagation(); if (!this.busy) action(); }); } }