feat(api): 新增节点流量悬浮详情与即时自动上线同步
为 server/manage/getNodes 返回节点级今日、本月与累计流量统计, 并在节点管理页名称悬浮层展示上行、下行和合计流量。 同时为自动上线补齐单节点同步入口,在管理端保存、 批量更新以及 REST/WS 心跳后立即同步 show 状态, 避免复制节点后开启自动上线仍需等待定时任务。 另优化管理端前端 Docker 发布流程,默认仅构建 amd64, 并收敛 BuildKit 缓存导出以缩短发布时间
This commit is contained in:
+1
@@ -0,0 +1 @@
|
||||
{"status":"completed","completed":5,"failed":0,"pending":0,"total":5,"percent":100,"current":"开发实施完成,方案包已归档","updated_at":"2026-04-28 16:43:00"}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
# 变更提案: admin-frontend-node-auto-online-immediate-sync
|
||||
|
||||
## 元信息
|
||||
```yaml
|
||||
类型: 修复
|
||||
方案类型: implementation
|
||||
优先级: P1
|
||||
状态: 已规划
|
||||
创建: 2026-04-28
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. 需求
|
||||
|
||||
### 背景
|
||||
节点管理页复制节点后,新节点会保留原节点的 `auto_online` 状态但被复制接口强制设为隐藏。管理员修改新节点信息并安装节点后,即使自动上线处于开启状态,节点也不会立即显示,需要手动关闭自动上线、打开显隐、再重新开启自动上线。
|
||||
|
||||
代码事实:
|
||||
- `ManageController::copy()` 复制节点后设置 `show = 0`。
|
||||
- `NodeEditorDialog` 保存会提交 `show` 与 `auto_online`,但后端 `save()` 只落库,不主动执行自动上线同步。
|
||||
- `ServerAutoOnlineService::sync()` 目前只由 `sync:server-auto-online` 定时命令每 5 分钟调用。
|
||||
- REST 节点心跳 `ServerService::touchNode()` 只更新在线缓存,不会触发自动上线同步;WebSocket 状态上报还绕过了 `touchNode()` 直接写缓存。
|
||||
|
||||
### 目标
|
||||
- 自动上线开启的节点在管理端保存、开启自动上线或节点心跳上报后,立即按当前在线状态和墙检测状态同步 `show`。
|
||||
- 保持现有定时任务兜底能力,避免依赖管理员手动切换显隐。
|
||||
- 保持墙检测自动隐藏规则不被绕过。
|
||||
|
||||
### 约束条件
|
||||
```yaml
|
||||
时间约束: 无
|
||||
性能约束: 单节点心跳只能同步当前节点,不能触发全量扫描
|
||||
兼容性约束: 保持 sync:server-auto-online 命令输出结构不变
|
||||
业务约束: 自动上线仍以 available_status 和墙状态为准;未开启 auto_online 的节点不改变手动显隐
|
||||
```
|
||||
|
||||
### 验收标准
|
||||
- [ ] `ServerAutoOnlineService` 支持单节点同步,并复用定时全量同步的同一套判定逻辑。
|
||||
- [ ] 管理端保存节点、开启自动上线、批量开启自动上线后,若节点当前为在线或待同步且未被墙检测否决,应立即 `show=1`。
|
||||
- [ ] 节点心跳上报后,若该节点开启自动上线,应立即同步 `show`,不必等待 Scheduler。
|
||||
- [ ] 被墙状态或 `gfw_auto_hidden` 未恢复正常时,自动上线不会把节点重新显示。
|
||||
- [ ] 单元测试覆盖单节点同步和心跳触发场景。
|
||||
|
||||
---
|
||||
|
||||
## 2. 方案
|
||||
|
||||
### 技术方案
|
||||
将 `ServerAutoOnlineService` 中的自动上线判定抽出为可复用的 `syncServer(Server $server)` 单节点入口。全量定时命令继续调用 `sync()`,内部复用同一判定函数。
|
||||
|
||||
在两个关键触发点调用单节点同步:
|
||||
- 管理端 `ManageController` 的 `save()`、`update()`、`batchUpdate()` 在节点开启 `auto_online` 后立即调用。
|
||||
- `ServerService::touchNode()` 在节点心跳刷新后,如果节点开启 `auto_online`,立即调用;WebSocket 状态上报改为复用 `touchNode()`。
|
||||
|
||||
### 影响范围
|
||||
```yaml
|
||||
涉及模块:
|
||||
- server-auto-online: 抽取单节点同步入口,复用全量同步逻辑
|
||||
- admin-server-manage: 保存/开关/批量更新自动上线时立即同步
|
||||
- server-heartbeat: REST 与 WebSocket 节点心跳后触发当前节点同步
|
||||
- tests: 补充自动上线单节点与心跳行为验证
|
||||
预计变更文件: 5
|
||||
```
|
||||
|
||||
### 风险评估
|
||||
| 风险 | 等级 | 应对 |
|
||||
|------|------|------|
|
||||
| 节点心跳频繁导致额外数据库写入 | 中 | 只在 `auto_online=true` 时执行;状态无变化时不保存 |
|
||||
| 保存接口中 `show` 与 `auto_online` 同时提交时语义冲突 | 低 | 自动上线开启时以自动同步判定为准,符合 UI 中显隐开关被托管的文案 |
|
||||
| 墙检测自动隐藏被误清除 | 中 | 单节点同步复用原有 `isGfwBlocked/isGfwHeld` 判定,只在正常状态时清除 hold |
|
||||
|
||||
### 方案取舍
|
||||
```yaml
|
||||
唯一方案理由: 问题根因在后端自动上线语义只由定时任务触发;把同步能力收敛到服务层并在业务事件中调用,可以同时覆盖管理端保存、开关和节点真实上线心跳。
|
||||
放弃的替代路径:
|
||||
- 仅前端保存后强制提交 show=1: 会绕过离线/被墙判断,且无法覆盖节点稍后才心跳上线的场景。
|
||||
- 缩短 Scheduler 间隔: 仍不是立即上线,并增加全量扫描频率。
|
||||
- 复制节点时默认关闭 auto_online: 会改变复制语义,仍要求管理员额外操作。
|
||||
回滚边界: 可独立回退 ServerAutoOnlineService 单节点入口、ManageController 调用点和 ServerService::touchNode 调用点;数据库结构不变。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 技术设计
|
||||
|
||||
### 架构设计
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[管理端保存/开启自动上线] --> B[ManageController]
|
||||
C[REST/WS 节点心跳上报] --> D[ServerService::touchNode]
|
||||
B --> E[ServerAutoOnlineService::syncServer]
|
||||
D --> E
|
||||
F[sync:server-auto-online] --> G[ServerAutoOnlineService::sync]
|
||||
G --> E
|
||||
E --> H[按 available_status + GFW 状态同步 show]
|
||||
```
|
||||
|
||||
### API 设计
|
||||
不新增外部 API。现有接口保持不变:
|
||||
- `POST /server/manage/save`
|
||||
- `POST /server/manage/update`
|
||||
- `POST /server/manage/batchUpdate`
|
||||
- 节点心跳/报告接口
|
||||
|
||||
### 数据模型
|
||||
不新增字段。
|
||||
|
||||
---
|
||||
|
||||
## 4. 核心场景
|
||||
|
||||
### 场景: 复制节点后自动上线立即生效
|
||||
**模块**: admin-frontend / server-auto-online
|
||||
**条件**: 新节点由复制产生,`show=0`,`auto_online=1`,节点已经心跳在线且未被墙检测否决。
|
||||
**行为**: 管理员在节点管理页编辑并保存该节点。
|
||||
**结果**: 后端保存后立即执行单节点自动上线同步,节点 `show=1`,前端刷新列表后显示为上线。
|
||||
|
||||
### 场景: 节点稍后才上线
|
||||
**模块**: server-heartbeat / server-auto-online
|
||||
**条件**: 节点保存时尚未心跳,`auto_online=1`,`show=0`。
|
||||
**行为**: 节点安装完成并上报心跳。
|
||||
**结果**: REST 与 WebSocket 心跳都会通过 `touchNode()` 更新在线缓存并立即同步当前节点,节点不需要等待下一轮 Scheduler。
|
||||
|
||||
---
|
||||
|
||||
## 5. 验证策略
|
||||
|
||||
```yaml
|
||||
verifyMode: test-first
|
||||
reviewerFocus:
|
||||
- app/Services/ServerAutoOnlineService.php 单节点与全量同步是否共用判定逻辑
|
||||
- app/Services/ServerService.php 与 app/WebSocket/NodeEventHandlers.php 心跳触发是否只影响 auto_online 节点
|
||||
- app/Http/Controllers/V2/Admin/Server/ManageController.php 管理端更新后的同步时机
|
||||
testerFocus:
|
||||
- vendor/bin/phpunit tests/Unit/ServerAutoOnlineServiceTest.php
|
||||
- npm --prefix admin-frontend run build
|
||||
uiValidation: none
|
||||
riskBoundary:
|
||||
- 不修改数据库结构
|
||||
- 不修改节点列表视觉结构
|
||||
- 不改变未开启 auto_online 节点的手动显隐行为
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 成果设计
|
||||
|
||||
N/A。此任务不包含视觉产出。
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
# 任务清单: admin-frontend-node-auto-online-immediate-sync
|
||||
|
||||
> **@status:** completed | 2026-04-28 16:37
|
||||
|
||||
```yaml
|
||||
@feature: admin-frontend-node-auto-online-immediate-sync
|
||||
@created: 2026-04-28
|
||||
@status: completed
|
||||
@mode: R2
|
||||
```
|
||||
|
||||
## LIVE_STATUS
|
||||
|
||||
```json
|
||||
{"status":"completed","completed":5,"failed":0,"pending":0,"total":5,"percent":100,"current":"开发实施完成,方案包已归档","updated_at":"2026-04-28 16:43:00"}
|
||||
```
|
||||
|
||||
## 进度概览
|
||||
|
||||
| 完成 | 失败 | 跳过 | 总数 |
|
||||
|------|------|------|------|
|
||||
| 5 | 0 | 0 | 5 |
|
||||
|
||||
---
|
||||
|
||||
## 任务列表
|
||||
|
||||
### 1. 自动上线服务
|
||||
|
||||
- [√] 1.1 修改 `app/Services/ServerAutoOnlineService.php`
|
||||
- 预期变更: 抽出单节点同步入口 `syncServer(Server $server)`,让全量 `sync()` 复用同一判定逻辑。
|
||||
- 完成标准: 单节点和全量同步返回结构一致,仍包含 `total/updated/shown/hidden/unchanged`。
|
||||
- 验证方式: `vendor/bin/phpunit tests/Unit/ServerAutoOnlineServiceTest.php`
|
||||
- depends_on: []
|
||||
|
||||
### 2. 触发点接入
|
||||
|
||||
- [√] 2.1 修改 `app/Services/ServerService.php`
|
||||
- 预期变更: `touchNode()` 更新节点心跳缓存后,对 `auto_online=true` 的节点立即调用单节点同步。
|
||||
- 完成标准: 自动上线节点心跳后无需等待 Scheduler 即可同步 `show`,未开启自动上线的节点不受影响。
|
||||
- 验证方式: `vendor/bin/phpunit tests/Unit/ServerAutoOnlineServiceTest.php`
|
||||
- depends_on: [1.1]
|
||||
|
||||
- [√] 2.2 修改 `app/WebSocket/NodeEventHandlers.php`
|
||||
- 预期变更: WebSocket 节点状态上报改为复用 `ServerService::touchNode()`,避免绕过自动上线即时同步。
|
||||
- 完成标准: REST 与 WebSocket 心跳入口都收敛到同一个自动上线触发点。
|
||||
- 验证方式: 代码检查 + `vendor/bin/phpunit tests/Unit/ServerAutoOnlineServiceTest.php`
|
||||
- depends_on: [2.1]
|
||||
|
||||
- [√] 2.3 修改 `app/Http/Controllers/V2/Admin/Server/ManageController.php`
|
||||
- 预期变更: `save()`、`update()`、`batchUpdate()` 在保存或开启 `auto_online` 后立即执行单节点同步。
|
||||
- 完成标准: 管理端保存复制节点、行级开启自动上线、批量开启自动上线后会立即按当前状态同步 `show`。
|
||||
- 验证方式: 代码检查 + `vendor/bin/phpunit tests/Unit/ServerAutoOnlineServiceTest.php`
|
||||
- depends_on: [1.1]
|
||||
|
||||
### 3. 验证覆盖
|
||||
|
||||
- [√] 3.1 修改 `tests/Unit/ServerAutoOnlineServiceTest.php`
|
||||
- 预期变更: 增加单节点同步和 `touchNode()` 触发自动上线的测试。
|
||||
- 完成标准: 新测试能复现复制节点 `show=0 + auto_online=1` 在线后立即 `show=1` 的核心行为。
|
||||
- 验证方式: `vendor/bin/phpunit tests/Unit/ServerAutoOnlineServiceTest.php`
|
||||
- depends_on: [1.1, 2.1]
|
||||
|
||||
---
|
||||
|
||||
## 执行日志
|
||||
|
||||
| 时间 | 任务 | 状态 | 备注 |
|
||||
|------|------|------|------|
|
||||
| 2026-04-28 16:32 | DESIGN | completed | 已确认唯一方案并创建任务清单 |
|
||||
| 2026-04-28 16:37 | 1.1 | completed | 已抽出单节点自动上线同步入口并复用全量同步逻辑 |
|
||||
| 2026-04-28 16:38 | 2.1/2.2 | completed | 已接入节点心跳、管理端保存、行级更新和批量更新触发点 |
|
||||
| 2026-04-28 16:39 | 3.1 | completed | 已补充单节点同步和心跳即时同步测试 |
|
||||
| 2026-04-28 16:40 | 验证 | warning | `npm --prefix admin-frontend run build` 通过;本机缺少 PHP/vendor,PHPUnit 未运行 |
|
||||
| 2026-04-28 16:43 | 2.2 | completed | 已补齐 WebSocket 状态上报入口,统一复用 `touchNode()` |
|
||||
|
||||
---
|
||||
|
||||
## 执行备注
|
||||
|
||||
- 本次不修改前端视觉和接口签名,前端现有 `@success="() => loadNodeBoard()"` 会在保存成功后刷新列表。
|
||||
- 后端自动上线仍以 `available_status` 和墙状态为准,不做无条件显示。
|
||||
Reference in New Issue
Block a user