"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import clsx from "clsx"; type SessionSummary = { sessionId: string; account: string; role: string; displayName: string; loginMethod: string; createdAt: string; expiresAt: string; lastSeenAt: string; current: boolean; }; function formatTime(value: string) { return new Date(value).toLocaleString("zh-CN", { hour12: false }); } export function SessionManagementClient({ initialSessions }: { initialSessions: SessionSummary[] }) { const router = useRouter(); const [sessions, setSessions] = useState(initialSessions); const [busySessionId, setBusySessionId] = useState(""); const [message, setMessage] = useState(""); async function refresh() { const response = await fetch("/api/v1/auth/sessions", { cache: "no-store" }); const result = (await response.json()) as { ok: boolean; sessions?: SessionSummary[]; message?: string }; if (!response.ok || !result.ok) { throw new Error(result.message ?? "刷新失败"); } setSessions(result.sessions ?? []); } async function revoke(sessionId: string, current: boolean) { setBusySessionId(sessionId); setMessage(""); try { const response = await fetch("/api/v1/auth/sessions", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "revoke_session", sessionId }), }); const result = (await response.json()) as { ok: boolean; message?: string }; if (!response.ok || !result.ok) { throw new Error(result.message ?? "撤销失败"); } if (current) { router.replace("/auth/login"); router.refresh(); return; } await refresh(); setMessage("会话已撤销。"); } catch (error) { setMessage(error instanceof Error ? error.message : "撤销失败"); } finally { setBusySessionId(""); } } return (
登录会话
管理当前账号的登录端;最高管理员可看到所有账号的会话。
{sessions.length === 0 ? (
暂无可管理会话。
) : ( sessions.map((session) => (
{session.displayName || session.account}
{session.current ? ( 当前 ) : null}
{session.account} · {session.loginMethod === "code" ? "验证码" : "账号密码"}
最近活跃:{formatTime(session.lastSeenAt)}
到期:{formatTime(session.expiresAt)}
)) )}
{message ?
{message}
: null}
); }