diff --git a/web/WEB.md b/web/WEB.md index b381f9f..9dca917 100644 --- a/web/WEB.md +++ b/web/WEB.md @@ -33,8 +33,9 @@ src/ |------|------|----------| | `/` | 工作台 | — | | `/ume` | UME 同步 | `ume` | +| `/ne` | 网元管理(CRUD / 连通性) | `ne` | | `/network` | 网络管理(左栏 + 子路由) | `network` | -| `/network/devices` | 设备列表 | `network` | +| `/network/devices` | 设备列表(只读:托管 + UME) | `network` | | `/network/alarms` | 告警信息 | `network` | | `/network/configs` | 配置信息(同步快照) | `network` | | `/network/webcrt` | redirect → `/webcrt`(保留 query) | — | @@ -44,7 +45,6 @@ src/ | `/network/tasks/port-traffic` | 端口流量(占位) | `network` | | `/topology` | 拓扑管理 | `topology` | | `/webcrt` | WebCRT 终端 | `webcrt` | -| `/ne` | redirect → `/network/devices` | — | | `/collect` | redirect → `/network/tasks/collect` | — | 菜单树见 `config/networkNav.ts`。**新增网络子页:** diff --git a/web/src/App.tsx b/web/src/App.tsx index b50bd43..3c91fa7 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -10,6 +10,7 @@ import { UmePage } from "./pages/UmePage"; import { WebcrtPage } from "./pages/WebcrtPage"; import { TopologyPage } from "./pages/TopologyPage"; import { NetworkLayout } from "./pages/network/NetworkLayout"; +import { NetworkDevicesPage } from "./pages/network/NetworkDevicesPage"; import { NetworkAlarmsPage } from "./pages/network/NetworkAlarmsPage"; import { NetworkConfigsPage } from "./pages/network/NetworkConfigsPage"; import { NetworkPlaceholderPage } from "./pages/network/NetworkPlaceholderPage"; @@ -82,11 +83,12 @@ function ProtectedApp() { } /> } /> } /> + } /> } /> } /> }> } /> - } /> + } /> } /> } /> } /> @@ -95,7 +97,6 @@ function ProtectedApp() { } /> } /> - } /> } /> } /> } /> diff --git a/web/src/config/modules.ts b/web/src/config/modules.ts index ea5078c..3509c96 100644 --- a/web/src/config/modules.ts +++ b/web/src/config/modules.ts @@ -26,13 +26,22 @@ export const MODULES: readonly ModuleDefinition[] = [ iconTone: "blue", titleKey: "layout.titleUme", }, + { + moduleId: "ne", + path: "/ne", + section: "operations", + labelKey: "workbench.cards.managedNe", + descKey: "workbench.cards.managedNeDesc", + iconTone: "green", + titleKey: "layout.titleManagedNe", + }, { moduleId: "network", path: "/network", section: "operations", labelKey: "workbench.cards.network", descKey: "workbench.cards.networkDesc", - iconTone: "green", + iconTone: "slate", titleKey: "layout.titleNetwork", }, { diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 139b877..b0e2032 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -24,7 +24,7 @@ const en = { umeSync: "UME Sync", umeSyncDesc: "UME alarms, subscription & inventory", network: "Network Management", - networkDesc: "Devices, alarms, config sync, and monitoring tasks", + networkDesc: "NE inventory, alarms, config sync, and monitoring tasks", managedNe: "NE Management", managedNeDesc: "Multi-vendor SSH/Telnet NEs & connectivity test", collect: "Batch Collect", @@ -115,6 +115,19 @@ const en = { message: "Message", }, }, + networkDevices: { + title: "Device list", + keywordPh: "Name / IP / ID", + allSource: "All sources", + empty: "No network elements.", + col: { + source: "Source", + name: "Name", + vendor: "Vendor", + deviceType: "Device type", + connect: "Connect", + }, + }, networkConfigs: { title: "Configurations", keywordPh: "Name / IP / ID", diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index 5e0fb01..dc35aa8 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -24,7 +24,7 @@ const zh = { umeSync: "UME同步", umeSyncDesc: "UME 告警同步、订阅与清单", network: "网络管理", - networkDesc: "设备、告警、配置同步与监控任务", + networkDesc: "网元清单、告警、配置同步与监控任务", managedNe: "网元管理", managedNeDesc: "多厂商 SSH/Telnet 网元与连通性测试", collect: "批量采集", @@ -115,6 +115,19 @@ const zh = { message: "消息", }, }, + networkDevices: { + title: "设备列表", + keywordPh: "名称 / IP / ID", + allSource: "全部来源", + empty: "暂无网元。", + col: { + source: "来源", + name: "名称", + vendor: "厂商", + deviceType: "设备类型", + connect: "连通状态", + }, + }, networkConfigs: { title: "配置信息", keywordPh: "名称 / IP / ID", diff --git a/web/src/pages/TopologyPage.tsx b/web/src/pages/TopologyPage.tsx index 77e7b86..322a138 100644 --- a/web/src/pages/TopologyPage.tsx +++ b/web/src/pages/TopologyPage.tsx @@ -697,8 +697,8 @@ export function TopologyPage() { const umeId = node?.data.ume_ne_id; if (managedId) { openOrFocusModule({ - moduleId: "network", - path: "/network/devices", + moduleId: "ne", + path: "/ne", }); return; } diff --git a/web/src/pages/network/NetworkDevicesPage.tsx b/web/src/pages/network/NetworkDevicesPage.tsx new file mode 100644 index 0000000..fc69ada --- /dev/null +++ b/web/src/pages/network/NetworkDevicesPage.tsx @@ -0,0 +1,113 @@ +import { useState } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { fetchCliTargets } from "../../services/api"; +import { queryKeys } from "../../constants/queryKeys"; +import { useI18n } from "../../i18n"; +import { pageCount } from "../../utils/display"; + +const PAGE_SIZE = 50; + +/** Read-only inventory of managed + UME NEs for Network Management. */ +export function NetworkDevicesPage() { + const { t } = useI18n(); + const [keyword, setKeyword] = useState(""); + const [source, setSource] = useState<"all" | "managed" | "ume">("all"); + const [page, setPage] = useState(1); + + const listQuery = useQuery({ + queryKey: queryKeys.cliTargets(`${source}:${keyword}`, page, PAGE_SIZE), + queryFn: () => fetchCliTargets({ source, keyword, page, pageSize: PAGE_SIZE }), + staleTime: 5000, + }); + + const items = listQuery.data?.items ?? []; + const total = Number(listQuery.data?.total || 0); + const pages = pageCount(total, PAGE_SIZE); + + return ( +
+
+

{t("networkDevices.title")}

+
+ +
+ { + setKeyword(e.target.value); + setPage(1); + }} + /> + + +
+ + {listQuery.isLoading ?

{t("common.refreshing")}

: null} + + + + + + + + + + + + + + {items.map((row) => ( + + + + + + + + + ))} + {!items.length && !listQuery.isLoading ? ( + + + + ) : null} + +
{t("networkDevices.col.source")}{t("networkDevices.col.name")}IP{t("networkDevices.col.vendor")}{t("networkDevices.col.deviceType")}{t("networkDevices.col.connect")}
{row.source}{row.name || row.id}{row.ip_address || "-"}{row.vendor || "-"}{row.device_type || row.ne_type || "-"}{row.connect_status || "-"}
+ {t("networkDevices.empty")} +
+ +
+ + + {t("common.pagerMeta", { total: String(total), page: String(page), pages: String(pages) })} + + +
+
+ ); +}