feat: finalize operations model workspace

This commit is contained in:
Codex Local
2026-08-31 11:29:56 +08:00
parent 78e0a19acb
commit a8cdec98d1
15 changed files with 406 additions and 63 deletions
+24 -2
View File
@@ -29,6 +29,7 @@ import {
MenuFoldOutlined,
MenuUnfoldOutlined,
ReloadOutlined,
RobotOutlined,
SearchOutlined,
SettingOutlined,
ToolOutlined,
@@ -42,8 +43,9 @@ import { OpsBillingWorkspace } from "./OpsBillingWorkspace";
import { OpsConfigWorkspace } from "./OpsConfigWorkspace";
import { OpsDiagnosticsWorkspace } from "./OpsDiagnosticsWorkspace";
import { OpsDeviceWorkspace } from "./OpsDeviceWorkspace";
import { OpsContentModelWorkspace } from "./OpsContentModelWorkspace";
type MaintenanceArea = "overview" | "devices" | "config" | "quality" | "billing" | "alerts" | "diagnostics";
type MaintenanceArea = "overview" | "devices" | "config" | "models" | "quality" | "billing" | "alerts" | "diagnostics";
type HealthState = {
loading: boolean;
@@ -59,6 +61,7 @@ const areaMeta: Record<MaintenanceArea, { title: string; description: string; ic
overview: { title: "维护总览", description: "集中查看服务健康、构建版本和当前维护权限。", icon: <DashboardOutlined /> },
devices: { title: "设备管理", description: "登记设备、维护家庭与长者归属、吊销设备并安全轮换密钥。", icon: <DatabaseOutlined /> },
config: { title: "运行配置", description: "管理配置版本、资源引用、离线评测、审批和灰度发布。", icon: <SettingOutlined /> },
models: { title: "大模型管理", description: "按客户组织配置、测试并激活聊天总结、关键词和故事候选生成模型。", icon: <RobotOutlined /> },
quality: { title: "内容质量", description: "按模型和提示词版本检查故事、事实与记忆的人工审核反馈。", icon: <BarChartOutlined /> },
billing: { title: "用量、费用与额度", description: "查看整体通话时长并按家庭、设备筛选,同时维护核价与硬额度策略。", icon: <DollarOutlined /> },
alerts: { title: "告警处置", description: "维护告警路由、通知测试、静默窗口和处置时间线。", icon: <AlertOutlined /> },
@@ -69,6 +72,7 @@ export function MaintenancePortal() {
const auth = useAuth();
const [collapsed, setCollapsed] = useState(() => window.innerWidth <= 720);
const [area, setArea] = useState<MaintenanceArea>(() => areaFromURL());
const [searchValue, setSearchValue] = useState("");
const [health, setHealth] = useState<HealthState>({ loading: true });
const refreshHealth = useCallback(async (signal?: AbortSignal) => {
@@ -120,11 +124,28 @@ export function MaintenancePortal() {
window.history.pushState({ area: next }, "", `${url.pathname}${url.search}${url.hash}`);
}
function search() {
const value = searchValue.trim().toLowerCase();
if (!value) return;
const matches: Array<[string[], MaintenanceArea]> = [
[["总览", "健康", "版本", "health"], "overview"],
[["设备管理", "资产", "密钥", "device management"], "devices"],
[["配置", "灰度", "模型路由", "config"], "config"],
[["大模型", "模型", "豆包", "ollama", "model"], "models"],
[["质量", "审核", "反馈", "quality"], "quality"],
[["费用", "额度", "账单", "用量", "billing", "cost"], "billing"],
[["告警", "静默", "路由", "alert"], "alerts"]
];
const target = matches.find(([keywords]) => keywords.some((keyword) => value.includes(keyword)))?.[1] ?? "diagnostics";
navigate(target);
}
const menuItems: MenuProps["items"] = [
{ type: "group", label: "平台维护", children: [
{ key: "overview", icon: <DashboardOutlined />, label: "维护总览" },
{ key: "devices", icon: <DatabaseOutlined />, label: "设备管理" },
{ key: "config", icon: <SettingOutlined />, label: "运行配置" },
{ key: "models", icon: <RobotOutlined />, label: "大模型管理" },
{ key: "quality", icon: <BarChartOutlined />, label: "内容质量" },
{ key: "billing", icon: <DollarOutlined />, label: "用量与费用" },
{ key: "alerts", icon: <AlertOutlined />, label: "告警处置" },
@@ -147,7 +168,7 @@ export function MaintenancePortal() {
{(Object.entries(areaMeta) as Array<[MaintenanceArea, (typeof areaMeta)[MaintenanceArea]]>).map(([key, item]) => <button type="button" className={area === key ? "active" : ""} key={key} onClick={() => navigate(key)}>{item.title.replace("维护", "")}</button>)}
</nav>
<div className="maintenance-header__actions">
<Input prefix={<SearchOutlined />} placeholder="搜索设备、通话、作业" allowClear className="maintenance-search" />
<Input.Search value={searchValue} onChange={(event) => setSearchValue(event.target.value)} onSearch={search} prefix={<SearchOutlined />} placeholder="搜索设备、通话、作业" allowClear className="maintenance-search" />
<Tooltip title="平台就绪状态"><Badge status={health.ready === "ready" ? "success" : health.loading ? "processing" : "warning"} /></Tooltip>
<Button type="text" icon={<BellOutlined />} aria-label="查看告警" onClick={() => navigate("alerts")} />
{auth.currentUser ? <Dropdown menu={{ items: accountMenu }} placement="bottomRight"><Button type="text" className="maintenance-account"><Avatar size={30} icon={<UserOutlined />} /><span>{auth.currentUser.identity.display_name || auth.currentUser.identity.preferred_username}</span></Button></Dropdown> : <Button type="primary" onClick={() => void auth.login()}>维护人员登录</Button>}
@@ -176,6 +197,7 @@ export function MaintenancePortal() {
{area === "overview" ? <MaintenanceOverview health={health} accounts={operationsAccounts} /> : null}
{area === "devices" ? <OpsDeviceWorkspace accessToken={auth.oidcUser.access_token} accounts={operationsAccounts} /> : null}
{area === "config" ? <OpsConfigWorkspace accessToken={auth.oidcUser.access_token} accounts={operationsAccounts} /> : null}
{area === "models" ? <OpsContentModelWorkspace accessToken={auth.oidcUser.access_token} accounts={operationsAccounts} /> : null}
{area === "quality" ? <ContentQualityWorkspace accessToken={auth.oidcUser.access_token} accounts={operationsAccounts} /> : null}
{area === "billing" ? <OpsBillingWorkspace accessToken={auth.oidcUser.access_token} accounts={operationsAccounts} /> : null}
{area === "alerts" ? <OpsAlertWorkspace accessToken={auth.oidcUser.access_token} accounts={operationsAccounts} /> : null}