import {useEffect,useState} from "react" import {request,ApiError} from "@/lib/auth" import {getProviders,saveProvider,type ProviderConfig,type ProviderKey} from "@/lib/providers" import {Button} from "@/components/ui/button" import {Input} from "@/components/ui/input" import {Badge} from "@/components/ui/badge" import {Card,CardContent,CardHeader,CardTitle,CardDescription} from "@/components/ui/card" import {AIReviewPanel} from "./AIReviewPanel" const titles:Record={model_primary:"主模型",model_backup:"备用模型",model_review:"审核模型",market_primary:"行情源"} export function ProvidersPanel({kind,onSessionExpired}:{kind:"model"|"market";onSessionExpired:()=>void}){ const [configs,setConfigs]=useState([]) const [loading,setLoading]=useState(true) const [error,setError]=useState("") const [generation,setGeneration]=useState(0) const [notice,setNotice]=useState("") useEffect(()=>{const controller=new AbortController();setLoading(true);setError("");getProviders(controller.signal).then(setConfigs).catch(e=>{if(controller.signal.aborted)return;if(e instanceof ApiError&&e.status===401)onSessionExpired();else setError(e instanceof Error?e.message:"配置读取失败")}).finally(()=>{if(!controller.signal.aborted)setLoading(false)});return()=>controller.abort()},[generation,onSessionExpired]) const keys:ProviderKey[]=kind==="model"?["model_primary","model_review","model_backup"]:["market_primary"] if(loading)return

正在读取配置…

if(error)return

{error}

async function copyReview(){setError("");try{const saved=await request("/api/admin/v1/providers/model_review/copy-primary",{method:"POST",body:JSON.stringify({expected_version:configs.find(c=>c.config_key==="model_review")?.version??0})});setConfigs(prev=>[...prev.filter(c=>c.config_key!=="model_review"),saved]);setNotice("审核配置已复用主模型,仍执行独立复核调用。")}catch(e){if(e instanceof ApiError&&e.status===401)onSessionExpired();else setError(e instanceof Error?e.message:"复制失败")}} return
{kind==="model"&&} {notice&&

{notice}

}

供应商信息由管理员填写,初始留空。启用表示允许后续业务使用该配置,不代表连接已验证。{kind==="model"&&"模型接口按 OpenAI 兼容协议配置。"}

{kind==="model"&&}{keys.map(key=>c.config_key===key)?.version??0}`} configKey={key} config={configs.find(c=>c.config_key===key)} onSessionExpired={onSessionExpired} onSaved={saved=>{setConfigs(prev=>[...prev.filter(c=>c.config_key!==key),saved]);setNotice(`${titles[key]}配置已保存。`)}} onReload={()=>setGeneration(v=>v+1)}/>)}
} function ProviderForm({configKey,config,onSaved,onReload,onSessionExpired}:{configKey:ProviderKey;config?:ProviderConfig;onSaved:(c:ProviderConfig)=>void;onReload:()=>void;onSessionExpired:()=>void}){ const [quoteURL,setQuoteURL]=useState(config?.quote_base_url??"") const [marketAdapter,setMarketAdapter]=useState(config?.market_adapter??""),[historyURL,setHistoryURL]=useState(config?.history_base_url??"") const [name,setName]=useState(config?.name??"") const [baseURL,setBaseURL]=useState(config?.base_url??"") const [modelName,setModelName]=useState(config?.model_name??"") const [wireAPI,setWireAPI]=useState<"responses"|"chat_completions">(config?.wire_api??"responses") const [catalogURL,setCatalogURL]=useState(config?.model_catalog_url??"") const [disableStorage,setDisableStorage]=useState(config?.disable_response_storage??true) const [requiresAuth,setRequiresAuth]=useState(config?.requires_openai_auth??true) const [apiKey,setAPIKey]=useState("") const [clearKey,setClearKey]=useState(false) const [enabled,setEnabled]=useState(config?.enabled??false) const [timeout,setTimeoutValue]=useState(config?.timeout_seconds??15) const [saving,setSaving]=useState(false) const [error,setError]=useState("") async function submit(event:React.FormEvent){event.preventDefault();setSaving(true);setError("");try{const result=await saveProvider(configKey,{quote_base_url:quoteURL,market_adapter:marketAdapter,history_base_url:historyURL,name,base_url:baseURL,model_name:modelName,wire_api:wireAPI,model_catalog_url:catalogURL,disable_response_storage:disableStorage,requires_openai_auth:requiresAuth,enabled,timeout_seconds:timeout,clear_api_key:clearKey,expected_version:config?.version??0,...(apiKey?{api_key:apiKey}:{})});setAPIKey("");setClearKey(false);onSaved(result)}catch(e){if(e instanceof ApiError&&e.status===401)onSessionExpired();else setError(e instanceof ApiError&&e.status===409?"配置已被其他管理员修改,请重新读取。":e instanceof Error?e.message:"保存失败")}finally{setSaving(false)}} const fieldClass="space-y-2 text-sm" return
{titles[configKey]}{config?.enabled?"已启用 · 未验证":"未启用"}
{config?`版本 ${config.version} · 更新于 ${new Date(config.updated_at).toLocaleString("zh-CN")}`:"尚未配置"}
{configKey==="market_primary"&&<>}{configKey!=="market_primary"&&}{configKey!=="market_primary"&&<>}{config?.has_api_key&&}
{error&&

{error}

{error.includes("重新读取")&&}
}
}