19 KiB
19 KiB
NexusGate UI 全量套皮报告(NexusGate → amo)
- 日期:2026-10-21
- 基线:
7c21742(含按月重置,仅 panel-go 实现) - 范围:前端按 3x-ui 定版样张全量重写;后端 Node 参考实现与 panel-go 双实现对称新增节点排序、在线状态(presence)、近似速度、系统状态采样、客户凭据接口、订阅聚合管线、服务器启停门禁;agent / agent-go 零改动;版本保持
0.6.8。 - 结论:Node 测试 61/61、panel-go 测试全过、difftest 差分 E2E(selftest + Node vs Go 正式)各 65/65 全过;四页 + 客户表单三页签真机(Go 主控 + 种子库)截图自检通过;同种子同口径 RSS 新版未增(见 §7)。
1. 改动清单
1.1 前端(public/,双实现共用;panel-go 经 build.sh 同步进 embed)
index.html:样张骨架(224px 侧边栏 + 顶栏 + 内容区);品牌纯文字 amo(无 logo/图标);<title>amo</title>;head 内联脚本按 localStoragenexusgate-theme预置主题防闪烁;六个导航页:系统状态(原总览)、服务器、客户与订阅、转发与节点、安装与命令、设置与运维。styles.css:四样张 CSS 合并;浅色默认 + 深色变量双套;字体为 3x-ui 同款系统字体栈(-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif),零 webfont/外链;紧凑密度;弹窗/表单/页签/入站选择器/浮层/toast/登录/展开行样式齐备。app.js:全量重写(保留 api/CSRF/toast/弹窗/45s 自动刷新/哈希路由骨架)。全站无说明性文字(page-intro 类已绝迹,grep 验证);原生 confirm/prompt 全部换成样式化弹窗;列表默认 50 条/页(客户/服务器/节点)。- 四页按定版列落地:
- 系统状态:四小卡(主控 CPU/内存/存储 + 今日全网流量,带迷你走势线;存储卡显示剩余)、整体速度双线图 + 三格统计(已发送/已接收/窗口均值)、连接数卡、底部信息条(运行时间:面板/系统|面板:内存/在线节点/客户|IP 地址 IPv4/IPv6)。
- 服务器:统计条(设备总数/在线/离线/平均延迟)+ 15 列(展开 +|复选|操作|已启用开关|名称|地址打码 + 表头 👁 显隐|状态|CPU|内存|Agent 版本 + 「有可用更新」徽标|核心版本|运行时长|客户端总数/在线数|延迟|上次心跳);展开行承载旧详情与全部旧动作。
- 客户与订阅:定版列(操作图标栏:二维码/详情/重置流量/编辑/红删除|已启用开关|在线药丸 + 已暂停红字|客户端名 + 备注两行|关联入站协议分色 chip + 「+N」弹层|流量药丸 + 迷你条|速度|剩余药丸|时长药丸)。
- 转发与节点:定版列(拖动手柄|复选|ID=排序序号|铅笔 + ⋮ 菜单|启用开关|备注|服务器 chip 三态色|端口|协议徽标组单行|客户端总数 + 绿色在线数 + 悬停名单浮层(挂 body)|流量药丸|速度药丸|到期时间药丸)。
1.2 后端 Node(lib/、server.js)
- 新增
lib/presence.js(在线/速度推导)、lib/sysstat.js(主控采样 + 环形历史 + 全局 IP 挑选)、lib/extsub.js(外部订阅拉取/解析/SSRF/退避/去重命名)、lib/reset.js(按月重置从 panel-go 1:1 移植补齐 parity,见 §5)。 lib/orchestrator.js:绑定数据层抽出assignCustomerData/unassignCustomerData+ 新增alignCustomerNodes(表单全量对齐);部署校验加设备停用门禁;用量上报写 presence/速度(含节点lastSampleAt落盘,与 Go 对齐)。lib/subscriptions.js:entries 按节点 sortIndex 排序;新增聚合管线aggregateEntries(自有 → 手动 → 外部合并/命名/去重)。server.js:GET /api/system、客户凭据 GET/regenerate、外部源手动刷新、节点 reorder 路由;客户 POST/PATCH 支持nodeIds全量对齐与聚合字段;housekeeping 接月重置 + 采样 + 到期源刷新;启动时 sortIndex 迁移。lib/store.js:默认brandName改为amo。
1.3 后端 Go(panel-go/,与 Node 逐项对称)
- 新增
presence.go、sysstat.go、extsub.go;types.go增字段(Server.Enabled、Node.SortIndex+ 速度/活跃指针字段、UsageSlot速度字段、Customer.ExternalSources/ManualLinks、顶层SubSourceCache、设置项);orchestrator.go(绑定对齐、停用门禁、用量写 presence/速度);subscriptions.go(sortIndex 排序 + 聚合);handlers.go(/api/system、凭据、刷新、reorder 路由与列表附加字段);main.go(sortIndex 迁移、housekeeping 采样/刷新);默认品牌名amo。
1.4 测试
- 新增
test/uireskin.test.js(Node,9 个)与panel-go/uireskin_test.go(Go:聚合解析、SSRF 拦截、排序/去重、presence 窗口等)。 - difftest 扩展 phase-3(见 §6),
ID_PREFIXES补src/lnk。
2. 旧功能对照表(逐项核对旧前端动作入口)
旧前端共 22 个 data-action,新前端 38 个。逐项结论:
| 旧功能 | 新入口 | 结论 |
|---|---|---|
| 新建/编辑/删除服务器、复制注册命令 | 服务器页操作列同名动作 | ✅ 保留 |
| 服务器详情(资源余量、TLS 证书、引擎状态、流量统计状态、旧版 agent 警告、重试清理、遗忘离线、SSH 卸载 Agent) | 服务器展开行 | ✅ 保留(样张 15 列放不下的收进展开行) |
| 新建/编辑/删除客户、启停、重置流量、重置令牌 | 客户页操作列 + 表单左下「重置流量」+ 订阅弹窗重置令牌 | ✅ 保留 |
| 客户详情(IP 观测、使用限制、订阅访问日志、清空日志) | 操作列详情 ⓘ 弹窗 | ✅ 保留(列表不显示 IP/设备上限,详情与表单仍在) |
| 订阅链接(9 种格式 + 信息页 + 各节点入站链接 + 二维码) | 订阅弹窗,顶部 auto 格式二维码 + 逐行复制/二维码 | ✅ 保留 |
| 新建/编辑节点、部署、修复、删除 | 节点页菜单(铅笔/⋮) | ✅ 保留 |
| 节点行「停用/启用」按钮 | 去除(用户定版:与行首开关重复,只留开关) | ⛔ 按定版删除 |
| 节点页「分配客户」表单 + 客户端弹窗内解绑 | 去除;绑定写入口收敛到客户表单「关联入站」(用户定版,防两处不一致);/assign、/unassign API 保留不动;节点客户端弹窗改只读名单 + 可复制链接 |
⛔ 按定版收敛 |
copy-uri 复制动作 |
改名统一为 copy-text(订阅行、命令、入站链接同一处理器) |
✅ 改名保留 |
| 安装与命令页全部命令复制 | 命令页换皮、删除每条命令的说明小字 | ✅ 保留 |
| 设置与运维(改密、备份下载/恢复等) | 运维页换皮、删除说明段(备份卡保留一句凭据保管警告) | ✅ 保留 |
旧前端死代码 renderNodeLinks |
未迁移(无入口调用) | ⛔ 死代码不迁移 |
3. 客户表单三页签(基本 / 凭据 / 链接)
- 基本:名称、分组、流量上限 GB、快速到期 + 到期日期/时间、IP 限制、设备(HWID)限制、流量重置成对控件(「流量重置」下拉:不重置/每月 + 「每月重置日」数字输入并排;直接绑定既有
trafficResetDay,非「每月」时重置日输入禁用,截图与 DOM 实测验证)、标签、备注、启用开关(编辑态绑定状态)、左下「重置流量」(仅编辑态)。- 关联入站(基本页签内):点击输入框弹下拉面板列全部节点(按 sortIndex 序、可滚动、已选高亮 + ✓、点击切换),右侧 🔍 按节点名搜索过滤;已选项以 chips 呈现可 × 单删;「全选 / 全部清除」按钮。保存 = 按勾选全量对齐
nodeClients(走现有部署/回收链路与凭据生成,不另起数据)。 - 3x-ui 独有而模型没有的字段(自动续期/Telegram ID/反向标签等)未加。
- 关联入站(基本页签内):点击输入框弹下拉面板列全部节点(按 sortIndex 序、可滚动、已选高亮 + ✓、点击切换),右侧 🔍 按节点名搜索过滤;已选项以 chips 呈现可 × 单删;「全选 / 全部清除」按钮。保存 = 按勾选全量对齐
- 凭据:订阅令牌行(复制 + ↻ 重置,沿用既有 rotate-subscription);每条节点绑定一行:节点名/协议/状态、UUID(
credentials.clientId)、密码(credentials.relayPassword,SS/HY2/AnyTLS/SOCKS 共用)、Reality Short ID(credentials.shortId)、SOCKS 时用户名(ng:<customerId>);逐项只读 + 复制 + ↻ 重新生成(二次确认)。- 凭据对应关系(按代码模型点名):凭据挂在「客户 × 节点」绑定(nodeClients)上、每条绑定一套,不是客户级一套——同一客户在不同节点上的 UUID/密码/Short ID 各自独立;订阅令牌(subId)才是客户级的。新接口:
GET /api/customers/:id/credentials、POST /api/customers/:id/credentials/:ncid/regenerate(重生成后对已部署节点自动 rebuildNode 下发;打审计regenerate_credentials);生成规则沿用既有newNodeClientCredentials(protocol),未新造格式。
- 凭据对应关系(按代码模型点名):凭据挂在「客户 × 节点」绑定(nodeClients)上、每条绑定一套,不是客户级一套——同一客户在不同节点上的 UUID/密码/Short ID 各自独立;订阅令牌(subId)才是客户级的。新接口:
- 链接:顶部一句短文案(「添加第三方分享链接和远程订阅地址,将其包含在该客户的订阅中」);「+ 添加外部链接」+ 手动链接列表(空态「暂无外部链接」;每条:链接本体 + 备注 + 启用开关 + 删除);「+ 添加外部订阅」+ 订阅源列表(空态「暂无外部订阅」;每条:地址 + 备注 + 可选 UA + 启用开关 + 删除 + 状态行(条数/上次成功/失败原因/已忽略 N 条)+「立即刷新」)。
4. 订阅聚合(按 SUB-AGGREGATION-DESIGN.md 全文)
- 客户新增
externalSources(≤5)与manualLinks(≤50);拉取缓存独立顶层subSourceCache(与客户配置分离,删源/删客户顺手清键)。 - 拉取:超时 10s、体上限 1MiB、每源 ≤200 条、重定向 ≤3 跳逐跳复检;SSRF:解析全部地址、任一非全局即拒绝(
settings.allowPrivateSubSources默认关时才放行内网)、连接钉死校验过的 IP 并保留 Host/SNI;UA 默认v2rayN/6.55可按源覆盖;解析只吃链接列表(整体 base64 或明文逐行),协议白名单vless/ss/hysteria2/anytls/socks5,其余丢弃并计数droppedCount。 - 刷新:全局间隔
settings.externalSubRefreshMinutes默认 60(钳 15–720);失败指数退避 + 确定性 jitter(双实现一致);housekeeping 每轮串行最多 3 个到期源;保存新增/改 URL 后台立即拉一次;手动刷新端点同步返回结果;失败永远用上次成功缓存兜底。 - 合并:顺序自有(sortIndex)→ 手动(列表序)→ 外部(源序/缓存序);外部项命名加
[源备注]前缀,手动项取备注 → URI 自带名 → 「手动节点 N」;跨段重名追加(2);去重键 = 协议 + 主机(小写)+ 端口 + 凭据指纹(解码后 userinfo 的 sha256 前 16 hex),自有优先;外部项不计量;客户停用仍整单 403;自有-only 客户输出与改造前逐字节一致(difftest 金标准守)。 - 注:面板没有
/api/settings路由(双实现都没有,旧前端也无此调用),externalSubRefreshMinutes/allowPrivateSubSources只能改数据文件——属既有形态,本轮未新造设置 UI。
5. 口径取舍专节(被迫近似与信号缺口,逐项点名)
- presence 粒度近似(B2):agent 用量样本只有
{kind:'user', id:customerId}(按服务器聚合,无节点线索)与{kind:'inbound', id:nodeId};observations 只有{customerId, ip}。故客户×节点在线的推导为:客户在其绑定节点的服务器上有新鲜活跃槽(180s 窗口)⇒ 该客户在该服务器的全部绑定节点上同时点亮。同机多节点无法区分——这是上报粒度的上限,agent 协议未动。customer.lastOnlineAt此前双实现从未写入,本轮在用量 delta>0 与 observations 接受时补写。 - 速度为近似值(B3):相邻两次已处理样本 delta/时间差(dt≥5s 才更新,epoch 变更跳过),有效期 150s;无历史显「—」。difftest 里速度值依赖墙钟,只比形状(正/零)不比数值。
- 连接数替代呈现(B4):agent 上报没有连接数字段,未编造通道——系统状态「连接数」卡与 /api/system 的
connections用在线客户数替代呈现,前端卡内如实标注「在线客户」及在线节点/客户明细。「今日流量」基线为纯内存(面板启动时刻的节点累计量),面板重启后从启动时重新累计;历史环形缓冲 240 条纯内存(主控指标 + 全网速度/连接数),量级百 KB 内。 - 服务器延迟无数据源:agent 心跳不上报延迟——服务器页统计条与延迟列恒显「—」,未编造。
- 核心版本(sing-box 版本)无数据源:engine 上报只有
singBoxInstalled布尔——核心版本列恒显「—」。CPU% 由 load1/cpuCount 换算,内存% 由 memoryTotal/memoryAvailable 算。 - 节点到期时间恒 ∞:节点模型无到期字段,到期时间药丸恒显 ∞,未造字段。
- IP 地址口径(B5):从主机网卡挑全局地址(排除 RFC1918/CGNAT/链路本地/ULA/回环/组播),取不到显「—」;不调用任何外部 IP 查询服务。沙箱实测显示 198.19.0.2(VM 出口的基准测试段地址,属网卡地址列表口径内;真实硬件上为实际网卡全局地址)。
- 系统状态页活动区:样张底部无活动区;为保「旧功能零丢失」,在信息条下方补回异常节点提示条(有才显)+ 最近活动面板——相对样张的唯一版式增补,特此点名。
- 存储卡走势线:无历史数据源时以当前占用率画平线(真实采样累积后即为真实曲线)。
- 服务器 enabled(新实现):server 加
enabled(默认 true):停用后禁止其上节点部署(409「设备 X 已停用」)、reconcile 跳过该设备;与状态(在线/离线)正交。 - 按月重置 Node parity 补齐:该功能原只有 panel-go 实现(7c21742);本轮按 reset.go 语义 1:1 移植到 Node 并接进 create/PATCH/housekeeping——这是 parity 补齐,不是行为变更,Go 侧行为不变。
- 种⼦环境假象(验收时确认非缺陷):种子库节点在面板重启后被既有 reconcile 置为 deploying(无真实 agent 轮询完成),故截图里「在线节点」按 active 计数为 0、节点开关呈启用态——与生产(agent 数秒内轮询完成)表现不同,非套皮问题。
6. 改名清单(NexusGate → amo,仅展示层)
改了的可见点:
- 侧边栏品牌、登录页品牌:纯文字「amo」加粗,无 logo。
- 页面
<title>amo</title>、顶栏面包屑前缀、订阅输出可见名相关默认值。 - Node 与 Go 的默认设置
brandName:NexusGate→amo(新库默认;brandName当前无渲染消费点,老库里的存量值不会出现在任何用户可见输出中)。 - 面板对外文案中的产品名(前端静态文案)。
刻意保留的内部标识(未改):
- 仓库目录、二进制名(
nexusgate-panel等)、数据路径(/etc/nexusgate、nexusgate.json)、环境变量(NG_*)、agent 协议与字段名。 - 安装/卸载命令里的仓库 URL(
git.881218.xyz/rogue/NexusGate)。 - 启动日志行与数据文件损坏错误文案中的 "NexusGate"(运维耦合的日志/错误前缀,按定版保留)。
7. 测试与验收证据
| 项目 | 结果 |
|---|---|
Node 测试 npm test |
61/61 全过(含新增 uireskin 9 个) |
Go 测试 go test ./... |
全过(含新增 uireskin_test.go) |
| difftest selftest(Node vs Node) | 65/65 |
| difftest 正式(Node vs Go 二进制) | 65/65 |
| 真跑截图自检 | Go 主控 + 混合种子库(3 服务器/6 客户/3 节点/6 绑定,含在线/离线/额度暂停/手动停用/过期/聚合客户),四页 + 表单三页签 + 深色抽查,见下 |
| RSS 对比 | 同一种子、同样预热请求、无 GOMEMLIMIT 的同口径:基线(7c21742)VmRSS 45,528–45,596 kB;新版 43,164–43,224 kB——新版未增(差值在 Go 运行时波动量级内);新增历史环形缓冲纯内存 240 条封顶 |
difftest phase-3 新增覆盖(双实现逐项比对):节点 reorder 后列表序与订阅输出序、客户 PATCH nodeIds 全量对齐(加/清绑定)、凭据 GET 形状与 regenerate 后凭据变化、两段用量上报后的 presence 投影(在线布尔/速度正性)与速度字段形状归一、/api/system 键结构形状、聚合全链路(本地 fixture 源:手动刷新返回 count=2/dropped=1、externalStatus 状态、Dave 全格式订阅逐项比对)。时间依赖值(速度数值、/api/system 数值)按设计只比形状——Normalizer 对 speedUpBps/speedDownBps 做正/零归一并注明原因。既有约束保持:Alice 订阅与 seed 金标准逐字节比对、DB 互换(swap)后互通、phase-2 全部步骤不变。
截图(浅色默认,深色抽查客户页):
~/workspace/nexusgate-ui-reskin-shots/01-overview-light.png系统状态~/workspace/nexusgate-ui-reskin-shots/02-servers-light.png服务器~/workspace/nexusgate-ui-reskin-shots/03-customers-light.png客户与订阅(在线/离线/额度暂停/手动停用/已过期五态齐全;无备注客户第二行留空、无分组回退)~/workspace/nexusgate-ui-reskin-shots/04-nodes-light.png转发与节点~/workspace/nexusgate-ui-reskin-shots/05-customer-form-basic.png客户表单·基本(流量重置成对控件、关联入站 chips、左下重置流量)~/workspace/nexusgate-ui-reskin-shots/06-customer-form-credentials.png客户表单·凭据(Dave:令牌 + N1 绑定 UUID/密码/Short ID)~/workspace/nexusgate-ui-reskin-shots/07-customer-form-links.png客户表单·链接(手动链接 + 外部源 + 状态行 + 立即刷新)~/workspace/nexusgate-ui-reskin-shots/08-customers-dark.png客户页深色
自检中发现并处置:① difftest interop 暴露 Node 侧节点 lastSampleAt 未落盘(速度计算借道 lastUsageAt)——已按设计对齐落盘并复跑全绿;② 截图种子一度用了模型不存在的 disabled 状态——模型手动停用为 suspended+manual,前端推导与后端一致,种子已修正(非产品缺陷)。
8. 提交
本地提交(不 push):
feat(panel): reskin backend — node sortIndex, presence/speed, /api/system, credentials, subscription aggregation (Node+Go parity)(含 SUB-AGGREGATION-DESIGN.md、difftest phase-3)feat(web): 3x-ui style reskin — amo branding, light/dark themes, four pages + tabbed customer formdocs: UI reskin report