Refactor web UI: feature-first structure, tokenized styles, modern blue theme.

Structure
- pages/ -> features/<domain>/{Page, components, hooks, lib}; 95 files moved,
  333 imports rewritten, verified with tsc.
- services/api.ts -> services/api/<domain>.ts (250 exports preserved),
  types.ts -> types/<domain>.ts, i18n zh/en -> locales/<lang>/<namespace>.ts
  (2696 messages deep-equal before/after).
- ESLint rule: shared layers must not import features/.

Styles
- index.css (16k lines) split losslessly into styles/{base,layout,components,
  pages,legacy,theme}; compiled CSS was byte-identical before tokenizing.
- ~930 hard-coded colors replaced by --nx-* tokens (theme/tokens.css); WebCRT
  off-palette colors unified; fixed dark-on-dark text introduced by mapping.
- theme/theme.css: modern blue design language (rounded shapes, gradients,
  unified buttons/fields/tables/modals), form-grid alignment fix, flat nav list
  without tree indent, soft selected state instead of left accent bar.

Docs: WEB.md documents code structure and style rules.
Not touched: the large Biz*/Webcrt/Topology page components (to be split later).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
oliver 2026-10-12 03:17:51 +08:00
parent 3b45d6abe3
commit 0d894efe5e
196 changed files with 26947 additions and 28091 deletions

View file

@ -0,0 +1,200 @@
const managedNe = {
title: "网元管理",
credsNotConfigured: "未配置 NETX_CREDENTIAL_SECRET_KEY,无法保存密码。请在 .env 中设置 Fernet 密钥后重启 API。",
add: "新增网元",
importBtn: "批量导入",
downloadTemplate: "下载导入模板",
importing: "导入中…",
edit: "编辑",
delete: "删除",
openTerminal: "终端",
confirmDelete:
"确定删除该网元?若拓扑中仅绑定此运维网元(无 UME),将同时删除对应 Fabric 节点及其直连链路。",
batchDelete: "批量删除",
batchDeleting: "删除中…",
batchDeleteConfirm:
"确定删除选中的 {{n}} 台网元?不可恢复。仅绑定运维侧的节点会级联清除 Fabric 节点与直连链路;仍绑 UME 的会保留拓扑。",
batchDeleteDone: "已删除 {{n}} 台网元",
batchDeleteSelectRequired: "请先勾选要删除的网元",
keywordPh: "名称 / IP / 用户名 / 标签",
allVendors: "全部厂商",
allConnectStatus: "全部连通状态",
stats: {
title: "统计",
total: "共 {{n}} 台网元",
pass: "已连通",
fail: "失败",
unknown: "未测试",
testing: "测试中",
batchProxy: "一键添加代理",
batchTest: "一键连通性测试",
tagFilter: "按标签筛选",
all: "全部",
allTag: "全部(无标签筛选)",
noTag: "无标签",
tagStats: "按标签统计(Top)",
confirm: "将对 {{n}} 台网元执行操作,确认继续?",
proxyDone: "已为 {{n}} 台网元提交代理配置",
testDone: "已提交 {{n}} 台网元连通性测试",
loadingIds: "加载中…",
},
col: {
name: "名称",
vendor: "厂商",
deviceType: "设备类型",
execPolicy: "CLI 执行策略",
source: "来源",
ip: "管理地址",
port: "端口",
protocol: "协议",
user: "用户名",
password: "密码",
tags: "标签",
remark: "备注",
connect: "连通性",
testedAt: "测试时间",
actions: "操作",
},
execPolicy: {
readonly: "只读(show/display/ping)",
linuxShell: "Shell/脚本(允许多行/heredoc)",
unrestricted: "实验室全开(允许多行/heredoc)",
hint: "仅影响 MCP/API 的 execManagedNe。默认只读;Linux 与 MikroTik(routeros/switchos)可选 shell / 实验室全开,支持多行脚本与 heredoc。",
},
source: {
manual: "手工",
ume_sync: "UME 同步",
webcrt: "WebCRT",
lldp: "LLDP 占位",
topology: "拓扑占位",
},
connect: {
run: "连通性测试",
running: "测试中…",
submitted: "已提交 {{n}} 台设备测试",
retest: "重新测试",
},
connectDetail: "详情",
connectDetailTitle: "连通性测试日志",
connectDetailEmpty: "暂无日志。请先执行连通性测试;失败时会记录完整错误与跳板上下文(不含密码)。",
umeSync: {
sync: "同步 UME 网元",
syncing: "同步中…",
delete: "删除 UME 网元",
deleting: "删除中…",
deleteConfirm:
"确定删除所有通过 UME 同步到网元管理中的网元?不可恢复。仅绑定这些 ManagedNE、且无 UME 投影的 Fabric 节点会连同直连链路一并清除。",
done: "UME 同步完成:新增 {{inserted}},更新 {{updated}},删除 {{deleted}},UME 清单共 {{total}} 台",
deletedDone: "已删除 {{n}} 台 UME 同步网元",
},
account: {
batchAdd: "一键添加账号",
batchByTag: "按标签添加账号",
batchTitle: "批量添加账号",
batchHint: "将以下账号信息应用到已选中的 {{n}} 台网元。",
batchByTagHint: "将以下账号信息应用到指定标签下的网元;密码可留空,仅更新用户名。",
batchDone: "已为 {{n}} 台网元更新账号",
selectRequired: "请先勾选要配置账号的网元",
applying: "应用中…",
apply: "应用到网元",
usernameOrPasswordRequired: "用户名和密码至少填写一项",
passwordOptionalBatch: "留空则不修改",
},
help:
"【批量导入】\n" +
"· 必填列:device_type、ip、username、port、protocol、name、vendor(可先下载模板)\n" +
"· password 可留空:直连需填;堡垒机托管或后续「批量添加代理」时可空\n" +
"· 推荐:导入网元 → 勾选 →「批量添加代理」统一配置跳板\n\n" +
"【跳板 / 堡垒机】\n" +
"· 用户名模板:{hop_user}@{target_user}@{target_ip}(堡垒机地址另填跳板地址)\n" +
"· 托管模式填跳板密码(Vault);目标密码可空。手动模式需填目标密码\n" +
"· JumpServer/CBH 跳板端口多为 2222,部分现场为 22\n\n" +
"【连通性 / 编辑】\n" +
"· 保存密码需配置 NETX_CREDENTIAL_SECRET_KEY\n" +
"· 编辑时密码留空表示不改;失败请看「详情」中的 hop 上下文(不含密码)",
importResult: {
done: "导入完成:新增 {{inserted}},更新 {{updated}},失败 {{failed}} 行",
},
form: {
requiredHint: "带 * 为必填项",
nameConnectHint: "连通性测试成功后将自动更新为设备名称",
createTitle: "新增网元",
editTitle: "编辑网元",
save: "保存",
saving: "保存中…",
cancel: "取消",
created: "网元已创建",
updated: "网元已更新",
deleted: "网元已删除",
passwordRequired: "请填写密码",
passwordOptional: "留空则不修改",
},
hop: {
sectionTitle: "跳板 / 代理",
type: "跳板类型",
enable: "经跳板登录目标网元",
vendor: {
zte: "ZTE 设备(CLI 跳登)",
huawei: "华为设备(CLI 跳登)",
cisco: "思科设备(CLI 跳登)",
linux: "Linux 服务器(SSH 隧道)",
bastion: "堡垒机(SSH 协议代理)",
},
zteHint: "在 ZTE 设备上执行 ssh/telnet 命令跳转到目标,目标账号由二次认证输入。",
huaweiHint: "在华为设备上执行 telnet / stelnet(SSH)跳登;stelnet 即 SSH。目标账号由二次认证输入。",
ciscoHint: "在思科设备上执行 ssh -vrf / telnet /vrf 跳登,目标账号由二次认证输入。",
linuxHint: "先 SSH 登录 Linux 跳板,经 direct-tcpip 隧道连接目标 IP:端口(等同 ProxyJump)。",
bastionHint:
"SSH 复合用户名直连堡垒机(跳板地址可为 IP 或域名),由堡垒机协议代理到目标。示例:bastion-user@target-user@198.51.100.20@192.0.2.10 或 bastion-user@target-user@198.51.100.20@ssh-bastion.example.com;密码为 Vault/堡垒机密码。JumpServer/CBH 常用端口 2222。",
targetAuthMode: "目标凭据",
targetAuthBastionManaged: "堡垒机托管(目标密码可留空)",
targetAuthManual: "手动输入(连接后二次认证)",
targetAuthHint: "堡垒机托管时仅需堡垒机密码;手动模式需填写目标网元密码。",
usernameTemplate: "SSH 用户名模板",
templateHintBastion:
"默认 {hop_user}@{target_user}@{target_ip},堡垒机地址(IP 或域名)填「跳板地址」。命令行示例:ssh bastion-user@target-user@198.51.100.20@ssh-bastion.example.com。",
host: "跳板地址",
hostPlaceholderBastion: "192.0.2.10 或 ssh-bastion.example.com",
hostHintBastion:
"支持 IP 或 FQDN。也可粘贴完整 SSH 目标串(如 bastion-user@target-user@198.51.100.20@ssh-bastion.example.com),失焦后自动拆成跳板用户名与地址。",
port: "跳板端口",
protocol: "跳板协议",
protocolSshStelnet: "ssh(stelnet)",
username: "跳板用户名",
password: "跳板密码",
vrf: "管理 VRF(可选)",
vpnInstance: "VPN-Instance(可选)",
vrfCisco: "VRF(可选,如 MGMT)",
enterSystemView: "跳登前是否进入系统视图",
enterSystemViewNo: "不进入(用户视图,默认)",
enterSystemViewYes: "进入系统视图(system-view)",
enterSystemViewHint:
"部分华为跳板仅在系统视图下支持 stelnet/telnet。需自行选择;不会因失败自动重试。",
commandTemplate: "跳登命令模板",
templateHint:
"ZTE 常用:telnet {target_ip}、telnet {target_ip} vrf {vrf}、ssh {target_ip}、ssh {target_ip} vrf {vrf}。按跳板协议与 VRF 自动推荐;留空时后端同样规则。目标账号密码由二次认证提示输入。",
templateHintHuawei:
"华为常用:telnet {target_ip}、telnet vpn-instance {vrf} {target_ip}、stelnet {target_ip}、stelnet {target_ip} -vpn-instance {vrf}。SSH 协议对应 stelnet。留空时按协议与 VPN-Instance 自动推荐。",
templateHintCisco:
"思科常用:ssh {target_ip}、ssh -vrf {vrf} {target_ip}、telnet {target_ip}、telnet {target_ip} /vrf {vrf}。留空时按协议与 VRF 自动推荐。",
badge: {
zte: "ZTE跳板",
huawei: "华为跳板",
cisco: "思科跳板",
linux: "Linux跳板",
bastion: "堡垒机",
},
hostRequired: "请填写跳板地址",
userRequired: "请填写跳板用户名",
passwordRequired: "请填写跳板密码",
batchAdd: "添加代理",
batchTitle: "批量添加代理",
batchHint: "将以下跳板配置应用到已选中的 {{n}} 台网元(会覆盖原有跳板设置)。",
batchDone: "已为 {{n}} 台网元配置代理",
selectRequired: "请先勾选要配置的网元",
applying: "应用中…",
apply: "应用到选中网元",
},
};
export default managedNe;