From 18b1a51f3f9b20e050c0c82854942d5db552d390 Mon Sep 17 00:00:00 2001 From: zhi Date: Wed, 11 Mar 2026 12:41:35 +0000 Subject: [PATCH] feat: add monitor admin panel for provider/server management and challenge generation --- src/pages/MonitorPage.tsx | 140 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 136 insertions(+), 4 deletions(-) diff --git a/src/pages/MonitorPage.tsx b/src/pages/MonitorPage.tsx index fe58cf0..8e7599e 100644 --- a/src/pages/MonitorPage.tsx +++ b/src/pages/MonitorPage.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import api from '@/services/api' interface ProviderRow { @@ -38,25 +38,116 @@ interface OverviewData { generated_at: string } +interface AdminUser { + id: number + is_admin: boolean +} + +interface ProviderAccountItem { + id: number + provider: string + label: string + is_enabled: boolean + credential_masked: string +} + +interface ServerItem { + server_id: number + identifier: string + display_name: string + online: boolean +} + export default function MonitorPage() { const [data, setData] = useState(null) const [loading, setLoading] = useState(true) + const [isAdmin, setIsAdmin] = useState(false) + const [providerAccounts, setProviderAccounts] = useState([]) + const [servers, setServers] = useState([]) + + const [providerForm, setProviderForm] = useState({ provider: 'openai', label: '', credential: '' }) + const [providerTestMsg, setProviderTestMsg] = useState('') + const [serverForm, setServerForm] = useState({ identifier: '', display_name: '' }) + + const canAdmin = useMemo(() => !!localStorage.getItem('token') && isAdmin, [isAdmin]) const load = async () => { try { const res = await api.get('/monitor/public/overview') setData(res.data) + const token = localStorage.getItem('token') + if (token) { + try { + const me = await api.get('/auth/me') + setIsAdmin(!!me.data.is_admin) + } catch { + setIsAdmin(false) + } + } else { + setIsAdmin(false) + } } finally { setLoading(false) } } + const loadAdminData = async () => { + if (!canAdmin) return + const [p, s] = await Promise.all([ + api.get('/monitor/admin/providers/accounts'), + api.get('/monitor/admin/servers'), + ]) + setProviderAccounts(p.data) + setServers(s.data) + } + useEffect(() => { load() const t = setInterval(load, 30000) return () => clearInterval(t) }, []) + useEffect(() => { + loadAdminData() + }, [canAdmin]) + + const testProvider = async () => { + const r = await api.post<{ ok: boolean; message: string }>('/monitor/admin/providers/test', { + provider: providerForm.provider, + credential: providerForm.credential, + }) + setProviderTestMsg((r.data.ok ? '✅ ' : '❌ ') + r.data.message) + } + + const addProvider = async () => { + await api.post('/monitor/admin/providers/accounts', providerForm) + setProviderForm({ ...providerForm, label: '', credential: '' }) + await loadAdminData() + } + + const deleteProvider = async (id: number) => { + await api.delete('/monitor/admin/providers/accounts/' + id) + await loadAdminData() + } + + const addServer = async () => { + await api.post('/monitor/admin/servers', serverForm) + setServerForm({ identifier: '', display_name: '' }) + await loadAdminData() + } + + const deleteServer = async (id: number) => { + await api.delete('/monitor/admin/servers/' + id) + await loadAdminData() + } + + const createChallenge = async (id: number) => { + const r = await api.post<{ identifier: string; challenge_uuid: string; expires_at: string }>('/monitor/admin/servers/' + id + '/challenge') + alert('identifier=' + r.data.identifier + ' +challenge_uuid=' + r.data.challenge_uuid + ' +expires_at=' + r.data.expires_at) + } + if (loading) return
Monitor loading...
if (!data) return
Monitor load failed
@@ -80,9 +171,9 @@ export default function MonitorPage() { {data.providers.map((p) => (
  • {p.provider} / {p.label} · status: {p.status} - {p.usage_pct !== null ? : ''} - {p.reset_at ? : ''} - {p.error ? : ''} + {p.usage_pct !== null ? (' · usage: ' + p.usage_pct + '%') : ''} + {p.reset_at ? (' · reset: ' + p.reset_at) : ''} + {p.error ? (' · error: ' + p.error) : ''}
  • ))} @@ -108,6 +199,47 @@ export default function MonitorPage() { )} + + {canAdmin && ( +
    +

    Admin: Provider 管理

    +
    + + setProviderForm({ ...providerForm, label: e.target.value })} /> + setProviderForm({ ...providerForm, credential: e.target.value })} /> + + +
    + {providerTestMsg &&

    {providerTestMsg}

    } +
      + {providerAccounts.map((p) => ( +
    • {p.provider} / {p.label} / {p.credential_masked}
    • + ))} +
    + +

    Admin: 服务器管理

    +
    + setServerForm({ ...serverForm, identifier: e.target.value })} /> + setServerForm({ ...serverForm, display_name: e.target.value })} /> + +
    +
      + {servers.map((s) => ( +
    • + {s.display_name} ({s.identifier}) + + +
    • + ))} +
    +
    + )} ) }