MatchMaster/assets/seven_day_gift/debug/SevenDayGiftApiFeedbackPanel.ts
2026-09-04 18:36:07 +08:00

208 lines
8.4 KiB
TypeScript

import { SevenDayApiTrace } from "../SevenDayGiftApi";
export interface SevenDayGiftApiFeedbackActions {
queryAll: () => void;
queryLevel: () => void;
queryActivity: () => void;
queryCoin: () => void;
queryProps: () => void;
queryPower: () => void;
}
/** 独立的接口请求/响应查看器,仅用于非正式环境。 */
export default class SevenDayGiftApiFeedbackPanel {
private readonly maxTraceCount = 120;
private root: cc.Node = null;
private panel: cc.Node = null;
private content: cc.Node = null;
private logLabel: cc.Label = null;
private scrollView: cc.ScrollView = null;
private traces: string[] = [];
constructor(private parent: cc.Node, private actions: SevenDayGiftApiFeedbackActions) { }
public build() {
this.root = new cc.Node("sevenDayGiftApiFeedback");
this.root.parent = this.parent;
this.root.setContentSize(this.parent.getContentSize());
this.root.zIndex = 31000;
const toggle = this.createButton("feedbackToggle", "接口反馈", 160, 72, () => this.show());
toggle.parent = this.root;
toggle.setPosition(-this.root.width * 0.5 + 95, this.root.height * 0.5 - 190);
this.panel = new cc.Node("panel");
this.panel.parent = this.root;
this.panel.setContentSize(720, 1180);
this.panel.addComponent(cc.BlockInputEvents);
this.drawRect(this.panel, cc.color(21, 27, 38, 248), 720, 1180);
const scale = Math.min(1, (this.root.width - 20) / 720, (this.root.height - 20) / 1180);
this.panel.setScale(scale);
this.panel.active = false;
this.createLabel(this.panel, "七日活动接口反馈", 36, -40, 540, 540, 56, cc.color(114, 218, 255));
const close = this.createButton("close", "关闭", 120, 58, () => this.hide());
close.parent = this.panel;
close.setPosition(290, 540);
this.addButton("查询全部", -235, 462, () => this.actions.queryAll(), cc.color(31, 143, 105));
this.addButton("查询服务器等级", 0, 462, () => this.actions.queryLevel(), cc.color(43, 123, 190));
this.addButton("查询签到活动", 235, 462, () => this.actions.queryActivity(), cc.color(43, 123, 190));
this.addButton("查询金币", -235, 384, () => this.actions.queryCoin(), cc.color(154, 107, 34));
this.addButton("查询道具", 0, 384, () => this.actions.queryProps(), cc.color(116, 77, 164));
this.addButton("查询无限体力", 235, 384, () => this.actions.queryPower(), cc.color(174, 70, 96));
this.createLabel(this.panel,
"领取和猫皮肤接口会在真实领取时自动记录;下方可上下滚动查看完整字段",
23, -55, 326, 555, 50, cc.color(255, 220, 142));
const clear = this.createButton("clear", "清空记录", 125, 52, () => this.clear());
clear.parent = this.panel;
clear.setPosition(290, 326);
this.buildScrollView();
this.appendSystemMessage("等待请求。可点击“查询全部”,或分别查询单个接口。");
}
public appendTrace(trace: SevenDayApiTrace) {
const elapsed = trace.elapsedMs === undefined ? "" : " 耗时=" + trace.elapsedMs + "ms";
const text = "[" + trace.time + "] [#" + trace.requestId + "] [" + trace.phase + "]\n"
+ "接口:" + trace.endpoint + elapsed + "\n"
+ "地址:" + trace.url + "\n"
+ (trace.phase === "REQUEST" ? "请求参数:" : "返回内容:") + "\n"
+ trace.payload;
this.traces.push(text);
if (this.traces.length > this.maxTraceCount) this.traces.shift();
this.refreshLog();
}
public appendSystemMessage(message: string) {
this.traces.push("[提示] " + message);
this.refreshLog();
}
public show() {
if (!this.panel) return;
this.panel.active = true;
this.refreshLog();
}
public hide() {
if (this.panel) this.panel.active = false;
}
public clear() {
this.traces = [];
this.appendSystemMessage("记录已清空。");
}
public destroy() {
if (this.root && cc.isValid(this.root)) this.root.destroy();
this.root = null;
this.panel = null;
this.content = null;
this.logLabel = null;
this.scrollView = null;
}
private buildScrollView() {
const scrollNode = new cc.Node("scrollView");
scrollNode.parent = this.panel;
scrollNode.setContentSize(670, 820);
scrollNode.setPosition(0, -110);
this.drawRect(scrollNode, cc.color(8, 12, 18, 235), 670, 820);
const view = new cc.Node("view");
view.parent = scrollNode;
view.setContentSize(650, 800);
view.addComponent(cc.Mask);
this.content = new cc.Node("content");
this.content.parent = view;
this.content.setAnchorPoint(0.5, 1);
this.content.setContentSize(630, 800);
this.content.setPosition(0, 400);
const labelNode = new cc.Node("logLabel");
labelNode.parent = this.content;
labelNode.setAnchorPoint(0.5, 1);
labelNode.setContentSize(610, 780);
labelNode.setPosition(0, -10);
labelNode.color = cc.color(224, 235, 244);
this.logLabel = labelNode.addComponent(cc.Label);
this.logLabel.fontSize = 23;
this.logLabel.lineHeight = 29;
this.logLabel.horizontalAlign = cc.Label.HorizontalAlign.LEFT;
this.logLabel.verticalAlign = cc.Label.VerticalAlign.TOP;
this.logLabel.overflow = cc.Label.Overflow.CLAMP;
this.scrollView = scrollNode.addComponent(cc.ScrollView);
this.scrollView.content = this.content;
this.scrollView.horizontal = false;
this.scrollView.vertical = true;
this.scrollView.inertia = true;
this.scrollView.elastic = true;
}
private refreshLog() {
if (!this.logLabel || !this.content) return;
const text = this.traces.slice().reverse().join("\n\n────────────────────────\n\n");
const lineCount = this.estimateVisualLines(text, 44);
const height = Math.max(800, lineCount * 29 + 35);
this.content.setContentSize(630, height);
this.logLabel.node.setContentSize(610, height - 20);
this.logLabel.node.setPosition(0, -10);
this.logLabel.string = text;
if (this.scrollView) this.scrollView.scrollToTop(0);
}
private estimateVisualLines(text: string, charsPerLine: number): number {
if (!text) return 1;
return text.split("\n").reduce((total, line) => {
return total + Math.max(1, Math.ceil(line.length / charsPerLine));
}, 0);
}
private addButton(text: string, x: number, y: number, callback: () => void, color: cc.Color) {
const button = this.createButton(text, text, 210, 64, callback, color);
button.parent = this.panel;
button.setPosition(x, y);
}
private createButton(name: string, text: string, width: number, height: number,
callback: () => void, color?: cc.Color): cc.Node {
const node = new cc.Node(name);
node.setContentSize(width, height);
node.addComponent(cc.Button);
this.drawRect(node, color || cc.color(43, 123, 190), width, height);
this.createLabel(node, text, 24, 0, 0, width - 8, height, cc.Color.WHITE);
node.on(cc.Node.EventType.TOUCH_END, (event: cc.Event) => {
event.stopPropagation();
callback();
});
return node;
}
private createLabel(parent: cc.Node, text: string, fontSize: number, x: number, y: number,
width: number, height: number, color: cc.Color): cc.Label {
const node = new cc.Node("label");
node.parent = parent;
node.setContentSize(width, height);
node.setPosition(x, y);
node.color = color;
const label = node.addComponent(cc.Label);
label.string = text;
label.fontSize = fontSize;
label.lineHeight = fontSize + 5;
label.horizontalAlign = cc.Label.HorizontalAlign.CENTER;
label.verticalAlign = cc.Label.VerticalAlign.CENTER;
return label;
}
private drawRect(node: cc.Node, color: cc.Color, width: number, height: number) {
const graphics = node.addComponent(cc.Graphics);
graphics.fillColor = color;
graphics.rect(-width * 0.5, -height * 0.5, width, height);
graphics.fill();
}
}