Show SCUM player identifiers and login IP

This commit is contained in:
npc0-hue
2026-08-28 11:54:16 +08:00
parent dcbeb33dfc
commit 3ca67907a1
4 changed files with 47 additions and 16 deletions
+9 -6
View File
@@ -15,7 +15,7 @@ const pageSource = readFileSync(resolve(featureRoot, "page.ts"), "utf8");
const dataClientSource = readFileSync(resolve(featureRoot, "page-data.ts"), "utf8");
const surfaceData: SCUMSurfaceData = {
players: [{ gamePlayerId: "steam-1", steamId: "76561198000000001", userProfileId: "profile-1", displayName: "Mira", squadName: "Wolves", squadId: "squad-1", online: true, famePoints: 42, normalBalance: 1000, goldBalance: 3, position: { x: 10, y: 20, z: 3 }, freshness: { status: "fresh" } }],
players: [{ gamePlayerId: "steam-1", steamId: "76561198000000001", userProfileId: "profile-1", displayName: "Mira", squadName: "Wolves", squadId: "squad-1", online: true, famePoints: 42, normalBalance: 1000, goldBalance: 3, lastLoginIp: "203.0.113.7", position: { x: 10, y: 20, z: 3 }, freshness: { status: "fresh" } }],
squads: [{ squadId: "squad-1", name: "Wolves", memberCount: 1, memberLimit: 12, leaderProfileId: "profile-1", score: 88, message: "Hold the north", freshness: { status: "fresh" } }],
members: [{ gamePlayerId: "steam-1", steamId: "76561198000000001", displayName: "Mira", squadId: "squad-1", rank: "Leader", score: 42, lastLoginAt: "2026-08-10T00:00:00Z", freshness: { status: "fresh" } }],
events: [{ id: "event-1", name: "Friday Range", eventType: "range", class: 1, corn: "0 20 * * 5", placard: "Event starting", percent: 75, npc: 1, item: 3, zombie: 12, animal: 2, status: "enabled" }],
@@ -186,8 +186,7 @@ describe("SCUM plugin feature module", () => {
expect(view.nodes).toContain("section:用户管理");
expect(view.texts).not.toContain("SCUM 用户真实记录");
expect(view.texts).toEqual(expect.arrayContaining(["在线用户 ", "1 / 1"]));
expect(view.texts).toEqual(expect.arrayContaining(["用户名", "队伍", "状态", "最后活动", "操作"]));
expect(view.texts).not.toEqual(expect.arrayContaining(["Steam", "上次登录", "登录 IP", "概况"]));
expect(view.texts).toEqual(expect.arrayContaining(["用户名", "UUID / Steam", "渣币", "登录 IP", "队伍", "状态", "最后活动", "操作"]));
expect(view.texts).not.toContain("筛选结果");
expect(view.texts).not.toContain("通用数据/机器动作可用");
expect(view.buttons.map((button) => button.label)).not.toEqual(expect.arrayContaining(["同步 SCUM.db", "重新读取"]));
@@ -197,8 +196,11 @@ describe("SCUM plugin feature module", () => {
expect(pageSource).toContain("resource-filter-bar scum-filter-bar");
expect(pageSource).toContain("provider-table-wrap scum-table-wrap");
expect(view.texts).toContain("Mira");
expect(view.texts).not.toContain("76561198000000001");
expect(view.texts.join("\n")).not.toContain("Fame 42");
expect(view.texts).toEqual(expect.arrayContaining(["steam-1", "Steam 76561198000000001", "1000", "Gold 3", "203.0.113.7"]));
const ipSearch = renderAndCollect({ playerSearch: "203.0.113.7" });
expect(ipSearch.texts).toContain("Mira");
const uuidSearch = renderAndCollect({ playerSearch: "profile-1" });
expect(uuidSearch.texts).toContain("Mira");
});
it("expires online users after five minutes without activity", () => {
@@ -325,7 +327,7 @@ function gameClientActions() {
};
}
function renderAndCollect(options: { data?: SCUMSurfaceData; permissions?: string[]; pageKey?: string; pageTitle?: string; giftTab?: "definitions" | "claims" | "deliveries" | "timed" } = {}) {
function renderAndCollect(options: { data?: SCUMSurfaceData; permissions?: string[]; pageKey?: string; pageTitle?: string; giftTab?: "definitions" | "claims" | "deliveries" | "timed"; playerSearch?: string } = {}) {
const nodes: string[] = [];
const texts: string[] = [];
const buttons: Array<{ label: string; disabled: boolean; onClick?: () => void }> = [];
@@ -346,6 +348,7 @@ function renderAndCollect(options: { data?: SCUMSurfaceData; permissions?: strin
useState: <T,>(initial: T | (() => T)): [T, (next: T | ((previous: T) => T)) => void] => {
stateCall += 1;
if (stateCall === 1) return [{ status: "ready", data: options.data ?? surfaceData } as T, () => undefined];
if (stateCall === 3 && options.playerSearch !== undefined) return [options.playerSearch as T, () => undefined];
const value = typeof initial === "function" ? (initial as () => T)() : initial;
if (options.giftTab && value === "definitions") return [options.giftTab as T, () => undefined];
return [value, () => undefined];