import { createContext, type ReactNode, useCallback, useContext, useEffect, useMemo, useState } from "react"; import { Database, RefreshCw, TriangleAlert } from "lucide-react"; import { Button } from "~/components/ui/button"; import { Card, CardContent } from "~/components/ui/card"; import { Skeleton } from "~/components/ui/skeleton"; import { useAuth } from "~/context/AuthContext"; import { getMonthlyMonitoringResult, getOperationsModel, listOperationsModels, operationsApiMode, type OperationsApiMode, } from "~/services/operationsApi"; import type { ModelRecord, MonitoringRow } from "./modelData"; type OperationsDataContextValue = { models: ModelRecord[]; loading: boolean; error: string | null; source: OperationsApiMode; reload: () => Promise; }; const OperationsDataContext = createContext(null); export function OperationsDataProvider({ children }: { children: ReactNode }) { const { currentWorkspace } = useAuth(); const workspaceId = currentWorkspace?.workspace_id; const [models, setModels] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const load = useCallback(async (signal?: AbortSignal) => { setLoading(true); setError(null); try { setModels(await listOperationsModels({ workspaceId, signal })); } catch (cause) { if (cause instanceof DOMException && cause.name === "AbortError") return; setModels([]); setError(cause instanceof Error ? cause.message : "模型数据加载失败"); } finally { if (!signal?.aborted) setLoading(false); } }, [workspaceId]); useEffect(() => { const controller = new AbortController(); void load(controller.signal); return () => controller.abort(); }, [load]); const value = useMemo(() => ({ models, loading, error, source: operationsApiMode, reload: () => load(), }), [error, load, loading, models]); return {children}; } export function useOperationsData(): OperationsDataContextValue { const context = useContext(OperationsDataContext); if (!context) throw new Error("useOperationsData 必须在 OperationsDataProvider 内使用"); return context; } export function useOperationsModelDetail(modelId: string, month: string) { const { currentWorkspace } = useAuth(); const workspaceId = currentWorkspace?.workspace_id; const [model, setModel] = useState(null); const [monitoringResult, setMonitoringResult] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [reloadKey, setReloadKey] = useState(0); useEffect(() => { const controller = new AbortController(); setLoading(true); setError(null); void Promise.all([ getOperationsModel(modelId, workspaceId, controller.signal), getMonthlyMonitoringResult(modelId, month, workspaceId, controller.signal), ]).then(([modelValue, resultValue]) => { setModel(modelValue); setMonitoringResult(resultValue); }).catch((cause) => { if (cause instanceof DOMException && cause.name === "AbortError") return; setError(cause instanceof Error ? cause.message : "模型监控详情加载失败"); }).finally(() => { if (!controller.signal.aborted) setLoading(false); }); return () => controller.abort(); }, [modelId, month, reloadKey, workspaceId]); return { model, monitoringResult, loading, error, reload: () => setReloadKey((value) => value + 1), }; } export function OperationsDataBoundary({ children }: { children: ReactNode }) { const { loading, error, models, reload, source } = useOperationsData(); if (loading) { return (
{Array.from({ length: 4 }, (_, index) => )}
); } if (error) { return (

运维数据加载失败

{error}

当前数据源:{source === "api" ? "真实接口" : "前端 Mock"}

); } if (!models.length) { return (

暂无模型数据

请确认模型平台已同步模型信息,或调整接口环境配置。

); } return children; }