import { CheckCircle2, RefreshCw, ShieldAlert, SlidersHorizontal, UsersRound } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { platformApiClient } from "../api/client"; import type { GamePlayerProfileResponse, GamePlayerResponse, GamePlayerStatePatchResponse, GamePlayerStateResponse } from "../api/types"; import { ErrorState, LoadingState } from "./StateViews"; import { GameGiftCatalogPanel } from "./GameGiftCatalogPanel"; type Selected = { profile: GamePlayerProfileResponse; state?: GamePlayerStateResponse; patches: GamePlayerStatePatchResponse[]; reason: string; after: Record; note?: string }; type State = { status: "loading" } | { status: "error"; reason: string } | { status: "ready"; players: GamePlayerResponse[]; selected?: Selected }; export function GamePlayerIntelligencePanel({ serverInstanceId }: { serverInstanceId: string }) { const [state, setState] = useState({ status: "loading" }); const load = useCallback(async () => { setState({ status: "loading" }); try { const result = await platformApiClient.listGamePlayers(serverInstanceId); setState({ status: "ready", players: result.items }); } catch (error) { setState({ status: "error", reason: message(error, "玩家档案读取失败。") }); } }, [serverInstanceId]); useEffect(() => { void load(); }, [load]); async function select(player: GamePlayerResponse) { try { const [profile, stateSnapshot, patchList] = await Promise.all([platformApiClient.getGamePlayerProfile(serverInstanceId, player.id), platformApiClient.getGamePlayerState(serverInstanceId, player.id), platformApiClient.listGamePlayerStatePatches(serverInstanceId, player.id)]); const after = Object.fromEntries(stateSnapshot.fields.map((field) => [field.key, String(field.value)])); setState((current) => current.status === "ready" ? { ...current, selected: { profile, state: stateSnapshot, patches: patchList.items, reason: "", after } } : current); } catch (error) { setState((current) => current.status === "ready" ? { ...current, selected: { profile: { player, aliases: [], sessions: [], accessAttempts: [], securitySignals: [] }, patches: [], reason: "", after: {}, note: message(error, "玩家状态快照不可用,已禁用修改。") } } : { status: "error", reason: message(error, "玩家档案读取失败。") }); } } async function submitPatch() { if (state.status !== "ready") return; const selected = state.selected; if (!selected || !selected.state) return; const snapshot = selected.state; const changes = snapshot.fields.filter((field) => selected.after[field.key] !== String(field.value)).map((field) => ({ fieldKey: field.key, before: field.value, after: Number(selected.after[field.key]) })); try { const patch = await platformApiClient.requestGamePlayerStatePatch(serverInstanceId, selected.profile.player.id, { gameVersion: snapshot.gameVersion, expectedStateVersion: snapshot.stateVersion, safetyWindow: snapshot.safetyWindow || "", reason: selected.reason, changes }); setState((current) => current.status === "ready" && current.selected ? { ...current, selected: { ...current.selected, patches: [patch, ...current.selected.patches], note: "修改申请已保存,等待平台管理员审批。" } } : current); } catch (error) { setState((current) => current.status === "ready" && current.selected ? { ...current, selected: { ...current.selected, note: message(error, "修改申请未被接受。") } } : current); } } async function approvePatch(patch: GamePlayerStatePatchResponse) { if (state.status !== "ready" || !state.selected) return; try { const approved = await platformApiClient.approveGamePlayerStatePatch(serverInstanceId, state.selected.profile.player.id, patch.id); setState((current) => current.status === "ready" && current.selected ? { ...current, selected: { ...current.selected, patches: current.selected.patches.map((item) => item.id === approved.id ? approved : item), note: "已批准并通过受控游戏通道排队执行。" } } : current); } catch (error) { setState((current) => current.status === "ready" && current.selected ? { ...current, selected: { ...current.selected, note: message(error, "审批失败。") } } : current); } } if (state.status === "loading") return ; if (state.status === "error") return void load()} />; const selected = state.selected; return <>

本地玩家档案与登录轨迹

游戏身份独立于平台账号;网络数据仅用于服务器内不可逆关联,绝不展示或持久化原始值。

{state.players.length ? state.players.map((player) => ) :

暂无已投影的成功登录记录。

}
{selected && setSelected(setState, reason)} onAfter={(key, value) => setAfter(setState, key, value)} onSubmit={() => void submitPatch()} onApprove={(patch) => void approvePatch(patch)} />}
; } function PlayerDetail({ selected, onReason, onAfter, onSubmit, onApprove }: { selected: Selected; onReason: (value: string) => void; onAfter: (key: string, value: string) => void; onSubmit: () => void; onApprove: (patch: GamePlayerStatePatchResponse) => void }) { const writable = Boolean(selected.state?.supported && selected.state.maintenanceVerified && !selected.state.playerOnline && selected.state.safetyWindow); return

{selected.profile.player.displayName} 的审阅记录

别名 {selected.profile.aliases.length} · 会话 {selected.profile.sessions.length}
别名{selected.profile.aliases.map((alias) => alias.alias).join(" / ") || "无"}
{selected.profile.sessions.slice(0, 10).map((session) =>
会话{formatTime(session.startedAt)} → {session.endedAt ? formatTime(session.endedAt) : "仍在线"} {session.endReason ? `(${session.endReason})` : ""}
)}
{selected.profile.securitySignals.length ? selected.profile.securitySignals.map((signal) =>
) :

未发现需要人工审核的风险信号。

}
{selected.profile.accessAttempts.length > 0 &&

失败尝试:{selected.profile.accessAttempts.length} 条(仅显示结果与时间,不显示网络标识)。

}

受控技能与角色属性修改

{writable ? "已验证维护/离线安全窗口" : "未验证版本或安全窗口,已禁用修改"}
{selected.state && <>

版本:{selected.state.gameVersion} · 状态版本:{selected.state.stateVersion}。仅显示此服务器版本明确支持的字段。

{selected.state.fields.map((field) => )}