feat: 独立运维控制台 (sundynix-admin) — LLM 模型配置控制面前端
新增独立 Vite+React 控制台(:5174),运维在此配置控制面,区别于桌面端构建者 UI。 - sundynix-admin: 模型页(列表[激活徽标/脱敏key] + 登记表单 + 测试连接 + 激活/删除) → 调 Gateway /api/v1/admin/models*;数据源/租户/护栏 占位(规划中);Gateway 健康灯 - gateway CORS 补 DELETE(控制台删除模型用) - Makefile admin 目标(Vite :5174); .claude/launch.json 加 admin-console 验证: npm build✓; 真实浏览器跑通——控制台拉到真实模型列表, 填表→测试连接 ✓连接成功(HTTP 200,browser→GW→mock), 保存→表格新增行。激活会经 NATS 热更新 Dispatcher(上一提交已证)。控制台↔控制面↔Dispatcher 全链路打通。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { ModelsPage } from "./ModelsPage";
|
||||
import { gatewayOnline } from "./api";
|
||||
|
||||
type Tab = "models" | "datasources" | "tenants" | "guardrails";
|
||||
const NAV: Array<{ key: Tab; label: string; ready?: boolean }> = [
|
||||
{ key: "models", label: "模型", ready: true },
|
||||
{ key: "datasources", label: "数据源" },
|
||||
{ key: "tenants", label: "租户" },
|
||||
{ key: "guardrails", label: "护栏" },
|
||||
];
|
||||
|
||||
function Soon({ title, desc }: { title: string; desc: string }) {
|
||||
return (
|
||||
<div className="rounded-lg border border-dashed bg-gray-50 p-6">
|
||||
<div className="mb-1 text-sm font-semibold text-gray-600">{title}</div>
|
||||
<p className="text-xs leading-relaxed text-gray-400">{desc}</p>
|
||||
<span className="mt-3 inline-block rounded bg-gray-200 px-2 py-0.5 text-[10px] text-gray-500">规划中</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const [tab, setTab] = useState<Tab>("models");
|
||||
const [online, setOnline] = useState(false);
|
||||
useEffect(() => {
|
||||
const ping = () => gatewayOnline().then(setOnline);
|
||||
ping();
|
||||
const id = setInterval(ping, 4000);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen w-screen text-gray-900">
|
||||
<aside className="flex w-56 shrink-0 flex-col border-r bg-gray-50">
|
||||
<div className="border-b p-4">
|
||||
<div className="text-sm font-bold text-gray-800">sundynix-agentix</div>
|
||||
<div className="text-[11px] text-gray-400">运维控制台</div>
|
||||
</div>
|
||||
<nav className="flex flex-col p-2">
|
||||
{NAV.map((n) => (
|
||||
<button
|
||||
key={n.key}
|
||||
onClick={() => setTab(n.key)}
|
||||
className={`flex items-center justify-between rounded px-3 py-2 text-left text-sm ${
|
||||
tab === n.key ? "bg-violet-50 font-medium text-violet-700" : "text-gray-600 hover:bg-gray-100"
|
||||
}`}
|
||||
>
|
||||
{n.label}
|
||||
{!n.ready && <span className="text-[9px] text-gray-300">规划</span>}
|
||||
</button>
|
||||
))}
|
||||
</nav>
|
||||
<div className="mt-auto flex items-center gap-2 border-t p-4 text-[11px] text-gray-500">
|
||||
<span className={`h-2 w-2 rounded-full ${online ? "bg-emerald-500" : "bg-rose-500"}`} />
|
||||
Gateway {online ? "在线" : "离线"}
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main className="flex-1 overflow-auto p-6">
|
||||
<h1 className="mb-4 text-lg font-semibold text-gray-800">
|
||||
{NAV.find((n) => n.key === tab)?.label}
|
||||
</h1>
|
||||
{tab === "models" && <ModelsPage />}
|
||||
{tab === "datasources" && (
|
||||
<Soon
|
||||
title="数据源(向量库 / 图库 / 全文)"
|
||||
desc="配置 Milvus(:19530) / Neo4j(:7687) / Bleve 连接 + 测试连接 + 状态。后端 search.Hybrid 接真后接通(RAG 核心链)。"
|
||||
/>
|
||||
)}
|
||||
{tab === "tenants" && (
|
||||
<Soon title="租户 / 工作区" desc="多租户隔离、配额、用户与计费。垂直行业平台级复制的基座。" />
|
||||
)}
|
||||
{tab === "guardrails" && (
|
||||
<Soon title="护栏" desc="输入/输出 Guardrail 规则(脱敏 / 免责 / 强制引用)。受监管垂直必备。" />
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user