222 lines
11 KiB
TypeScript
222 lines
11 KiB
TypeScript
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(); }
|
||
}
|
||
}
|