import { useEffect, useMemo, useState } from "react"; import { useAuth } from "@/_core/hooks/useAuth"; import { trpc } from "@/lib/trpc"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { formatDateTimeShanghai } from "@/lib/time"; import { toast } from "sonner"; import { Activity, Database, RefreshCw, Settings2, Shield, Sparkles, Users } from "lucide-react"; export default function AdminConsole() { const { user } = useAuth(); const utils = trpc.useUtils(); const usersQuery = trpc.admin.users.useQuery({ limit: 100 }, { enabled: user?.role === "admin" }); const tasksQuery = trpc.admin.tasks.useQuery({ limit: 100 }, { enabled: user?.role === "admin" }); const liveSessionsQuery = trpc.admin.liveSessions.useQuery({ limit: 50 }, { enabled: user?.role === "admin" }); const settingsQuery = trpc.admin.settings.useQuery(undefined, { enabled: user?.role === "admin" }); const auditQuery = trpc.admin.auditLogs.useQuery({ limit: 100 }, { enabled: user?.role === "admin" }); const [settingsDrafts, setSettingsDrafts] = useState>({}); const refreshAllMutation = trpc.admin.refreshAllNtrp.useMutation({ onSuccess: () => { toast.success("已提交全量 NTRP 刷新任务"); utils.admin.tasks.invalidate(); }, onError: (error) => toast.error(`提交失败: ${error.message}`), }); const refreshUserMutation = trpc.admin.refreshUserNtrp.useMutation({ onSuccess: () => { toast.success("已提交用户 NTRP 刷新任务"); utils.admin.tasks.invalidate(); }, onError: (error) => toast.error(`提交失败: ${error.message}`), }); const refreshUserNowMutation = trpc.admin.refreshUserNtrpNow.useMutation({ onSuccess: () => { toast.success("用户 NTRP 已即时刷新"); utils.admin.users.invalidate(); utils.admin.auditLogs.invalidate(); }, onError: (error) => toast.error(`即时刷新失败: ${error.message}`), }); const updateSettingMutation = trpc.admin.updateSetting.useMutation({ onSuccess: () => { toast.success("设置已更新"); utils.admin.settings.invalidate(); utils.admin.auditLogs.invalidate(); }, onError: (error) => toast.error(`设置更新失败: ${error.message}`), }); useEffect(() => { const drafts: Record = {}; (settingsQuery.data || []).forEach((item: any) => { drafts[item.settingKey] = JSON.stringify(item.value ?? null); }); setSettingsDrafts(drafts); }, [settingsQuery.data]); const totals = useMemo(() => ({ users: (usersQuery.data || []).length, tasks: (tasksQuery.data || []).length, sessions: (liveSessionsQuery.data || []).length, }), [liveSessionsQuery.data, tasksQuery.data, usersQuery.data]); if (user?.role !== "admin") { return ( 需要管理员权限 当前账号没有管理系统访问权限。 ); } return (

管理系统

这里集中查看用户、后台任务、实时分析记录、全局设置和审计日志。H1 管理员可以提交和执行用户级评分刷新。

用户数
{totals.users}
后台任务
{totals.tasks}
实时分析会话
{totals.sessions}
用户 任务 会话 设置 审计 用户列表 支持排队刷新和即时刷新单个用户的 NTRP。 {(usersQuery.data || []).map((item: any) => (
{item.name} {item.role} NTRP {Number(item.ntrpRating || 1.5).toFixed(1)}
训练 {item.totalSessions || 0} 次 · {item.totalMinutes || 0} 分钟 · 连练 {item.currentStreak || 0} 天
))}
后台任务 {(tasksQuery.data || []).map((task: any) => (
{task.title} {task.type} {task.status}
{task.userName || task.userId} · {formatDateTimeShanghai(task.createdAt)}
{task.message || "无描述"} {task.progress || 0}%
))} 实时分析会话 {(liveSessionsQuery.data || []).map((session: any) => (
{session.title} {session.userName || session.userId} {session.sessionMode}
主动作 {session.dominantAction || "unknown"} · 有效片段 {session.effectiveSegments || 0}/{session.totalSegments || 0}
{Math.round(session.overallScore || 0)} 分 · {Math.round((session.durationMs || 0) / 1000)} 秒
))}
全局设置 设置值以 JSON 形式保存,适合阈值、开关和结构化配置。 {(settingsQuery.data || []).map((setting: any) => (
{setting.label}
{setting.description}
setSettingsDrafts((current) => ({ ...current, [setting.settingKey]: event.target.value }))} className="mt-3 h-11 rounded-2xl" />
))}
审计日志 {(auditQuery.data || []).map((item: any) => (
{item.actionType} {item.entityType} {item.targetUserId ? 目标用户 {item.targetUserId} : null}
管理员 {item.adminName || item.adminUserId} · {formatDateTimeShanghai(item.createdAt)}
{item.entityId ?
实体 {item.entityId}
: null}
))}
); }