import { useCallback, useEffect, useState } from "react"; import "../../styles/pages/provider-health.css"; import { CheckCircleOutlined, CloseCircleOutlined, ExclamationCircleOutlined, ReloadOutlined, } from "@ant-design/icons"; import { providerHealthClient, type ProviderHealthResponse } from "../../api/providerHealthClient"; import WorkspacePageShell from "../../components/WorkspacePageShell"; import type { WebUserSession } from "../../types"; interface ProviderHealthPageProps { session: WebUserSession | null; onOpenLogin: () => void; } const STATUS_ICON: Record = { healthy: , arrears: , denied: , error: , timeout: , no_key: , unknown: , }; const STATUS_LABEL: Record = { healthy: "正常", arrears: "欠费", denied: "权限拒绝", error: "异常", timeout: "超时", no_key: "无密钥", unknown: "未知", }; export default function ProviderHealthPage({ session, onOpenLogin }: ProviderHealthPageProps) { const isAdmin = session?.user?.role === "admin"; const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const load = useCallback(async () => { setLoading(true); setError(null); try { const result = await providerHealthClient.getStatus(); setData(result); } catch (err) { setError(err instanceof Error ? err.message : "加载失败"); } finally { setLoading(false); } }, []); useEffect(() => { if (isAdmin) void load(); }, [isAdmin, load]); if (!session) { return (

请登录管理员账号后查看。

); } if (!isAdmin) { return (

当前账号没有管理员权限。

); } return (

服务商健康监控

各 AI 服务商的健康状态、调用统计与密钥池负载。

{error ?

{error}

: null} {/* Health status cards */}
{data?.health ? Object.entries(data.health).map(([provider, entry]) => (
{STATUS_ICON[entry.status] || STATUS_ICON.unknown} {provider} {STATUS_LABEL[entry.status] || entry.status}
{entry.lastCheck ? ( 上次检查: {new Date(entry.lastCheck).toLocaleString("zh-CN")} ) : null} {entry.lastError ? (

{entry.lastError}

) : null}
)) : null}
{/* Call stats table */} {data?.callStats?.length ? (

最近 1h 调用统计

{data.callStats.map((row, i) => ( ))}
服务商模型状态调用数平均耗时总成本
{row.provider} {row.model} {row.status} {row.count} {row.avg_ms ? `${Math.round(Number(row.avg_ms))}ms` : "-"} {row.total_cost ? `¥${Number(row.total_cost).toFixed(2)}` : "-"}
) : null} {/* Key pool stats */} {data?.keyStats?.length ? (

密钥池负载

{data.keyStats.map((row, i) => ( ))}
服务商总密钥活跃密钥当前负载
{row.provider} {row.total_keys} {row.active_keys} {row.current_load}
) : null}
); }