import JiaZai from "../../Script/JiaZai"; import LoadingCatAnimation from "../../Script/LoadingCatAnimation"; import Utils from "../../Script/module/Pay/Utils"; import { MiniGameSdk } from "../../Script/Sdk/MiniGameSdk"; import { applyStarterPackStatus, starterPackRemaining, starterPackTimeText } from "../../Script/module/Config/StarterPack"; const { ccclass, property } = cc._decorator; declare const wx: any; @ccclass export default class NewbieGift extends cc.Component { // Retain the unused serialized properties in the existing prefab. @property(cc.Node) monthCardTime: cc.Node = null; @property(cc.Node) monthCardBtn: cc.Node = null; @property(cc.Node) monthCardBtn2: cc.Node = null; btn_Touch = true; private paying = false; private polling = false; private onShowListener: () => void = null; private pendingOrder = ""; private confirmedOrder = ""; init(first: boolean) { this.node.opacity = 255; this.closeConfirmBox(); if (!this.paying) this.closeLoad(); const title = cc.find("ConfirmBox/title", this.node); if (title) title.getComponent(cc.Label).string = "幸运礼包充值"; // The old Spine/propBg nodes stay disabled. Preserve the authored layout. this.unschedule(this.refreshCountdown); this.schedule(this.refreshCountdown, 1); this.refreshCountdown(); if (typeof wx !== "undefined" && !this.onShowListener) { this.onShowListener = () => this.onShow(); wx.onShow(this.onShowListener); } this.onShow(); cc.fx.GameTool.recordStarterPackShown(); } refreshCountdown() { if (!cc.isValid(this)) return; const seconds = starterPackRemaining(); const label = cc.find("timeContainer/time", this.node).getComponent(cc.Label); label.string = seconds > 0 ? starterPackTimeText(seconds) : "已结束"; this.btn_Touch = seconds > 0 && !this.paying; cc.find("btnContainer/btn", this.node).getComponent(cc.Button).interactable = this.btn_Touch; } onShow() { // wx.onShow and the payment callback may arrive together. Only one query // chain owns the order; refreshing activity data is not reward delivery. if (this.polling) return; Utils.getStarter_pack(res => { if (res && res.code === 1) applyStarterPackStatus(res.data); this.refreshCountdown(); }); const order = this.pendingOrder || cc.fx.GameConfig.GM_INFO.iosStarterOrder; if (!order) return; this.polling = true; this.paying = true; this.openLoad(); // Retry only the delivery acknowledgement after payment was confirmed. if (this.confirmedOrder === order) { this.finishOrder(order); return; } const directPayment = !!this.pendingOrder; const version = cc.fx.GameTool.getWechatGameVersion(); this.logPayment("开始查单", order, { channel: directPayment ? "直购" : "iOS客服", version, server: version === "开发版" || version === "体验版" ? Utils.testHttpip : Utils.httpip, }); const done = (data) => { if (directPayment && data?.code === 1 && data.data?.pay_state === 2) { this.confirmedOrder = order; this.finishOrder(order); } else if (!directPayment && data?.code === 1 && data.data?.payment_name === "starter_pack") { // The original customer-service API already completes the order. this.completeOrder(order); } else if ((directPayment && data?.code === 1 && data.data?.pay_state === 1) || (!directPayment && data?.code === 0 && data.msg === "已经获取到奖励")) { // A completed legacy order is not a new grant; clear stale UI state. this.completeOrder(order, false); } else { this.logPayment("等待确认,保留订单供重试", order, { code: data?.code, pay_state: data?.data?.pay_state, msg: data?.msg || data?.message, }); this.polling = false; this.paying = false; this.closeLoad(); this.refreshCountdown(); // Keep the order for retry, including after the offer expires. this.openConfirmBox(); } }; if (this.pendingOrder) Utils.getPayInfo(done, order, { timeoutMs: 30000, onProgress: res => this.logPayment("查单返回", order, { code: res?.code, pay_state: res?.data?.pay_state, msg: res?.msg || res?.message, }), }); else Utils.getIosPayInfo(order, done); } againGet() { this.closeConfirmBox(); this.onShow(); } buyProduct(event?: cc.Event, customData?: string) { if (this.pendingOrder || cc.fx.GameConfig.GM_INFO.iosStarterOrder) { this.onShow(); return; } this.refreshCountdown(); if (!this.btn_Touch) return; this.paying = true; this.refreshCountdown(); this.openLoad(); // Fetch the server deadline; purchase eligibility is enforced by this UI. Utils.getStarter_pack(res => { if (!res || res.code !== 1) { this.failPayment("礼包状态获取失败,请重试"); return; } applyStarterPackStatus(res.data); if (starterPackRemaining() <= 0) { this.failPayment("礼包已结束或已购买"); return; } let systemType = "Android"; if (typeof wx !== "undefined" && wx.getSystemInfoSync().platform === "ios") systemType = "ios"; if (systemType === "ios" && !cc.fx.GameConfig.GM_INFO.iosCanPay) { this.iosOldPay(); return; } Utils.buyProp("starter_pack", 1, 300, systemType, "starter_pack", result => { if (!result || result.err) { if (result && result.errCode === 16) { this.iosOldPay(); return; } this.failPayment("充值失败"); return; } if (!result.outTradeNo) { this.failPayment("支付订单号缺失,请重进游戏检查补单"); return; } this.pendingOrder = result.outTradeNo; this.logPayment("微信支付回调成功,等待服务端确认", this.pendingOrder); this.onShow(); }); }); } private finishOrder(order: string) { this.logPayment("支付已确认,开始领取确认", order); this.paying = true; this.openLoad(); Utils.setPayInfo(res => { this.logPayment("领取确认返回", order, { code: res?.code, msg: res?.msg || res?.message }); this.polling = false; if (!res || res.code !== 1) { this.paying = false; this.openConfirmBox(); this.refreshCountdown(); return; } this.completeOrder(order); }, order); } private completeOrder(order: string, grant = true) { if (grant) { this.logPayment("开始前端发奖", order); // The legacy acknowledgement returns data: "ok", not order metadata. cc.fx.GameTool.shopBuy("starter_pack", false, { outTradeNo: order }); this.logPayment("前端发奖调用完成", order); MiniGameSdk.API.yinli_Pay(300, order, "购买金币道具:starter_pack"); MiniGameSdk.API.showToast("充值成功"); } this.pendingOrder = ""; this.confirmedOrder = ""; cc.fx.GameConfig.GM_INFO.iosStarterOrder = ""; cc.fx.GameConfig.GM_INFO.starterPackPurchased = true; this.polling = false; this.paying = false; this.buyStarter_pack(); } private logPayment(stage: string, order: string, details: any = {}) { console.log("[新手礼包支付] " + stage, { orderSuffix: String(order).slice(-6), ...details }); } buyStarter_pack() { const canvas = cc.find("Canvas"); const home = canvas && canvas.getComponent(JiaZai); if (home) { home.newbieGift = false; home.startStarter_pack(); home.updateCoin(); } const scene = canvas && canvas.getComponent("SceneManager"); if (scene) scene.refreshJungleRewardDisplay(); this.closeLoad(); if (cc.isValid(this)) this.closeStarter_pack(); } private failPayment(message: string) { this.paying = false; this.closeLoad(); this.refreshCountdown(); MiniGameSdk.API.showToast(message); cc.fx.GameTool.shushu_Track("payment_fail", { outTradeNo: this.pendingOrder || cc.fx.GameConfig.GM_INFO.iosStarterOrder || "", pay_amount: 300, payment_name: "starter_pack", payment_num: 1, fail_reason: message, }); } iosOldPay() { Utils.GoKEFu({ price: 300, payment_name: "starter_pack", payment_count: 1 }, result => { this.paying = false; this.closeLoad(); this.refreshCountdown(); if (result !== "success") { cc.fx.GameConfig.GM_INFO.iosStarterOrder = ""; MiniGameSdk.API.showToast("未能打开支付,请重试"); } }); } closeStarter_pack() { this.node.active = false; this.node.emit("starter-pack-closed"); } openLoad() { if (cc.isValid(this)) LoadingCatAnimation.play(this.node.getChildByName("Loading")); } closeLoad() { if (cc.isValid(this)) LoadingCatAnimation.stop(this.node.getChildByName("Loading")); } openConfirmBox() { this.closeLoad(); if (cc.isValid(this)) this.node.getChildByName("ConfirmBox").active = true; } closeConfirmBox() { if (cc.isValid(this)) this.node.getChildByName("ConfirmBox").active = false; } onDisable() { this.unschedule(this.refreshCountdown); if (typeof wx !== "undefined" && this.onShowListener) wx.offShow(this.onShowListener); this.onShowListener = null; } onDestroy() { this.onDisable(); } }