MatchMaster/assets/testSeven/SevenApiPanel.ts

222 lines
11 KiB
TypeScript
Raw 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 Utils from "../Script/module/Pay/Utils";
const { ccclass } = cc._decorator;
/** 预览和开发版共用的接口面板;独立预览可手动填写登录信息。 */
@ccclass
export default class SevenApiPanel extends cc.Component {
public preview: (info: any) => void = null; // 独立场景:仅模拟奖励。
public testHome: (info: any) => void = null; // 开发版主页:进入真实活动流程。
private panel: cc.Node;
private uid: cc.EditBox;
private token: cc.EditBox;
private output: cc.Label;
private summary: cc.Label;
private scroll: cc.ScrollView;
private request: XMLHttpRequest = null;
private response: any = null;
private responseUid = "";
// 仅预览和微信开发版创建面板,提供查询、模拟和主页测试入口。
start() {
const fx = (cc as any).fx;
if (!CC_PREVIEW && !(fx && fx.GameTool && fx.GameTool.getWechatGameVersion() === "开发版")) return;
this.panel = new cc.Node("SevenApiPanel");
this.node.addChild(this.panel);
this.panel.zIndex = 2000;
this.panel.setContentSize(1040, 1840);
const background = this.panel.addComponent(cc.Graphics);
background.fillColor = cc.color(22, 29, 43, 255);
background.rect(-520, -920, 1040, 1840);
background.fill();
this.panel.addComponent(cc.BlockInputEvents);
this.label("七日活动 · 测试服接口", 0, 855, 32);
this.label("POST " + Utils.testHttpip + "signInActivityInfo", 0, 798, 23);
this.label("请求可能更新后端签到记录;预览奖励不增加资产", 0, 749, 24);
this.uid = this.input("测试账号 UID", 660, false);
this.token = this.input("登录 token(不保存)", 562, true);
this.button("读取当前登录", -315, 462, () => this.readLogin());
this.button("发送查询", 0, 462, () => this.send());
this.button("关闭面板", 315, 462, () => { this.panel.active = false; });
this.button(this.testHome ? "测试主页自动弹窗" : "预览返回数据", -250, 380, () => {
if (this.testHome) {
const fx = (cc as any).fx;
const current = fx && fx.GameConfig && fx.GameConfig.GM_INFO;
if (!current || !current.uid || !current.token) return this.message("主页尚未登录完成");
if (String(current.uid) !== this.uid.string.trim()) return this.message("主页流程使用当前登录账号,请先点读取当前登录");
if (!this.response || this.responseUid !== String(current.uid)) return this.message("请先发送查询,取得当前登录账号的活动数据");
if (CC_PREVIEW) return this.message("浏览器预览可查询接口;真实资产同步请在微信开发版 HomeScene 测试");
this.panel.active = false;
this.testHome(JSON.parse(JSON.stringify(this.response)));
return;
}
if (!this.response || !Array.isArray(this.response.rewards)) return this.message("请先取得有效活动数据");
if (this.preview) {
this.preview(JSON.parse(JSON.stringify(this.response)));
this.panel.active = false;
}
});
this.button("清除该账号弹窗记录", 220, 380, () => this.clearPopup());
this.summary = this.label("输入测试服 UID 和 token 后点击发送查询", 0, 265, 24);
this.summary.node.setContentSize(960, 140);
this.summary.overflow = cc.Label.Overflow.RESIZE_HEIGHT;
const viewport = new cc.Node("ResponseScroll");
this.panel.addChild(viewport);
viewport.setPosition(0, -320);
viewport.setContentSize(970, 1050);
viewport.addComponent(cc.Mask);
this.scroll = viewport.addComponent(cc.ScrollView);
this.scroll.horizontal = false;
this.scroll.vertical = true;
const content = new cc.Node("Response");
viewport.addChild(content);
content.setAnchorPoint(0.5, 1);
content.setPosition(0, 525);
content.setContentSize(950, 1050);
this.scroll.content = content;
this.output = content.addComponent(cc.Label);
this.output.fontSize = 23;
this.output.lineHeight = 30;
this.output.horizontalAlign = cc.Label.HorizontalAlign.LEFT;
this.output.verticalAlign = cc.Label.VerticalAlign.TOP;
this.output.overflow = cc.Label.Overflow.RESIZE_HEIGHT;
this.output.string = "响应 JSON 将显示在这里,可上下滚动。";
this.readLogin();
this.panel.active = false;
const toggle = new cc.Node("OpenSevenApi");
this.node.addChild(toggle);
toggle.zIndex = 1500;
toggle.setPosition(0, 925);
toggle.setContentSize(280, 60);
const title = toggle.addComponent(cc.Label);
title.string = "打开接口测试面板";
title.fontSize = 28;
toggle.on(cc.Node.EventType.TOUCH_END, () => { this.panel.active = true; this.readLogin(); });
}
// 请求测试服并展示原始响应,保留查询时的 UID 供后续校验。
private send() {
if (this.request) return this.message("请求中,请等待本次返回");
const uid = this.uid.string.trim();
const token = this.token.string.trim();
if (!uid || !token) return this.message("请填写 UID 和 token");
this.response = null;
this.responseUid = "";
const xhr = cc.loader.getXMLHttpRequest();
this.request = xhr;
const started = Date.now();
let finished = false;
const finish = (error?: string) => {
if (finished) return;
finished = true;
this.request = null;
if (!cc.isValid(this.node, true)) return;
const text = xhr.responseText || "";
this.output.string = text || error || "空响应";
if (error) this.message(error);
else {
try {
const result = JSON.parse(text);
this.output.string = JSON.stringify(result, null, 2);
console.log("[testSeven][signInActivityInfo] 回复", this.output.string);
this.responseUid = uid;
this.response = result.code === 1 && result.data && typeof result.data === "object" ? result.data : null;
const data = this.response;
this.message("HTTP " + xhr.status + " | " + (Date.now() - started) + " ms | code=" + result.code + "\n" +
(data ? "status=" + data.status + " canClaim=" + data.canClaim + " todayClaimed=" + data.todayClaimed + "\n" + this.popupRecord() : String(result.msg || "没有活动数据")));
} catch (_) { this.message("HTTP " + xhr.status + ":响应不是有效 JSON"); }
}
this.scheduleOnce(() => this.scroll.scrollToTop(0), 0);
};
xhr.onload = () => finish();
xhr.onerror = () => finish("网络失败,请检查测试服地址、网络或浏览器 CORS 配置");
xhr.ontimeout = () => finish("请求超时(8 秒),可再次手动请求");
xhr.onabort = () => finish("请求已取消");
try {
xhr.open("POST", Utils.testHttpip + "signInActivityInfo", true);
xhr.timeout = 8000;
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
this.message("请求中…");
xhr.send("uid=" + encodeURIComponent(uid) + "&token=" + encodeURIComponent(token) + "&isDebug=false");
} catch (error) { finish("请求失败:" + error.message); }
}
// 读取当前登录信息填入输入框,token 不写入存储。
private readLogin() {
const fx = (cc as any).fx;
const info = fx && fx.GameConfig && fx.GameConfig.GM_INFO;
this.uid.string = info && info.uid || "";
this.token.string = info && info.token || "";
if (!this.uid.string) {
try { this.uid.string = String(JSON.parse(cc.sys.localStorage.getItem("uid")) || ""); } catch (_) { }
}
if (this.summary) this.message(this.token.string ? "已读取当前登录信息,请确认该账号属于测试服" : "未取得登录 token,请从测试账号登录结果复制填入");
}
// 使用最近一次查询账号和活动生成弹窗记录键。
private popupKey(): string {
return "seven_day_gift_auto_open_v1:" + this.responseUid + ":" + this.response.activityId;
}
// 展示当前预览环境保存的自动弹窗记录。
private popupRecord(): string {
return "本地当天弹窗记录:" + (cc.sys.localStorage.getItem(this.popupKey()) || "无");
}
// 仅清除已查询账号的本地弹窗记录,保留奖励和服务端状态。
private clearPopup() {
if (!this.response || !this.response.activityId || !this.responseUid) return this.message("请先查询该测试账号的活动");
cc.sys.localStorage.removeItem(this.popupKey());
this.message("已清除查询账号的本地弹窗记录;未清除资产防重记录或后端签到状态");
}
// 更新接口操作提示。
private message(text: string) { this.summary.string = text; }
// 创建接口面板中的说明文字。
private label(text: string, x: number, y: number, size: number): cc.Label {
const node = new cc.Node("Text");
this.panel.addChild(node);
node.setPosition(x, y);
const label = node.addComponent(cc.Label);
label.fontSize = size;
label.lineHeight = size + 8;
label.string = text;
return label;
}
// 创建单行输入框,token 使用密码样式。
private input(placeholder: string, y: number, password: boolean): cc.EditBox {
const node = new cc.Node("Input");
this.panel.addChild(node);
node.setPosition(0, y);
node.setContentSize(920, 72);
const bg = node.addComponent(cc.Graphics);
bg.fillColor = cc.color(52, 65, 84);
bg.rect(-460, -36, 920, 72);
bg.fill();
const input = node.addComponent(cc.EditBox);
input.inputMode = cc.EditBox.InputMode.SINGLE_LINE;
input.inputFlag = password ? cc.EditBox.InputFlag.PASSWORD : cc.EditBox.InputFlag.DEFAULT;
input.fontSize = 26;
input.fontColor = cc.Color.WHITE;
input.placeholder = placeholder;
input.placeholderFontSize = 26;
input.maxLength = 4096;
return input;
}
// 创建接口面板的文字按钮。
private button(text: string, x: number, y: number, action: () => void) {
const label = this.label(text, x, y, 27);
label.node.color = cc.color(100, 220, 255);
label.node.on(cc.Node.EventType.TOUCH_END, action);
}
// 销毁面板时取消请求,防止回调访问已销毁节点。
onDestroy() {
if (this.request) { const xhr = this.request; this.request = null; xhr.onload = xhr.onerror = xhr.ontimeout = xhr.onabort = null; xhr.abort(); }
}
}