Files
Xboard/.helloagents/archive/2026-04/202604290123_node-traffic-yesterday-stats/proposal.md
T
yinjianm e847252e12 fix(api): 修复节点流量限额共享统计与父子显隐联动
统一节点流量统计与限额展示口径,节点详情新增昨日流量,
并让今日、昨日和本月使用清晰的半开时间窗口聚合

同 machine_id 或同 host 的节点现在共享当前账期已用流量,
管理端优先使用后端 traffic_limit_snapshot 展示月额度状态,
mi-node 下发的 current_used 也改为共享账期统计

新增 parent_auto_hidden 标记与父节点显隐联动服务,父节点
因自动上线或流量限额变为不可展示时会隐藏当前显示的子节点,
恢复时只恢复这批自动隐藏的子节点,避免覆盖手动操作
2026-04-29 02:24:57 +08:00

7.3 KiB
Raw Blame History

变更提案: node-traffic-yesterday-stats

元信息

类型: 修复 + 新功能
方案类型: implementation
优先级: P1
状态: 已规划
创建: 2026-04-29

1. 需求

背景

管理后台 #/nodes 的节点流量详情卡当前展示“今日 / 本月 / 累计”。用户反馈某节点“今日下行很多,但本月上行最多”看起来不匹配,并要求统计加入“昨日”。

目标

  • 核对节点统计的上行/下行字段映射,确认是否存在前后端反转或聚合口径错误。
  • 在节点流量详情卡中新增“昨日”统计,口径与“今日”一致。
  • 收紧统计窗口边界,保证“今日 / 昨日 / 本月 / 累计”各自窗口清晰。

约束条件

时间约束: 
性能约束: 节点列表接口仍按当前批量聚合方式查询,避免逐节点查询
兼容性约束: 保持现有 traffic_stats.today/month/total 字段兼容,新增 yesterday 字段
业务约束: 不改变 StatServer.u/d 的含义,不迁移历史数据

验收标准

  • server/manage/getNodes 响应中的 traffic_stats 包含 yesterday
  • today 只统计当天 [today, tomorrow)yesterday 只统计 [yesterday, today)month 只统计 [monthStart, nextMonthStart)
  • 前端节点流量详情卡按“今日 / 昨日 / 本月 / 累计”展示。
  • 后端测试覆盖新窗口边界,前端构建通过。

2. 方案

技术方案

ManageController 内扩展节点流量窗口构建:

  • emptyNodeTrafficStats() 增加 yesterday 默认值。
  • buildNodeTrafficStats() 使用 strtotime('today')strtotime('tomorrow')strtotime('yesterday') 和下月月初计算窗口。
  • fillTrafficWindow() 支持可选结束时间,查询使用半开区间:record_at >= startAtrecord_at < endAt

前端同步:

  • AdminNodeTrafficStats 增加 yesterday: TrafficAmount
  • NodeTrafficDetail.key 增加 yesterday
  • getNodeTrafficDetails() 在“今日”和“本月”之间插入“昨日”。

测试:

  • 新增/扩展 ManageController 单元测试,通过反射调用私有构建方法,构造跨天、跨月和未来记录,验证各窗口不会互相污染。

影响范围

涉及模块:
  - admin-frontend: 节点流量详情卡类型与展示行
  - backend-admin-api: 节点列表接口 traffic_stats 聚合窗口
  - tests: 节点统计窗口单元测试
预计变更文件: 4-6

风险评估

风险 等级 应对
历史数据中 u/d 语义本身来自节点端上报,若节点端上报方向定义与面板相反,面板无法单独纠正 本次只核对面板字段链路;不改变历史语义,避免误修
新增窗口可能增加查询次数 仍为按 server_id 批量聚合,仅从 3 个窗口增至 4 个窗口
月统计加入上界后不再包含未来 record_at 这是更严格的窗口口径,符合预期

方案取舍

唯一方案理由: 后端统一输出 yesterday 字段,前端只按接口字段展示,可以保持统计口径单一且兼容现有调用方。
放弃的替代路径:
  - 仅前端用 today/month/total 推导昨日: 无法准确还原昨日上行/下行。
  - 修改 StatServerJob 的 u/d 写入方向: 当前面板链路内 u=上行、d=下行一致,贸然反转会破坏历史数据和用户统计。
  - 新增独立节点详情接口: 本次只影响列表详情卡,新增接口会扩大维护面。
回滚边界: 可独立回退 ManageController 的 yesterday/window 变更、前端类型/展示变更和测试文件,不涉及数据库迁移。

3. 技术设计

API 设计

GET server/manage/getNodes

  • 响应新增字段: traffic_stats.yesterday
  • 结构:
{
  "traffic_stats": {
    "today": {"upload": 0, "download": 0, "total": 0},
    "yesterday": {"upload": 0, "download": 0, "total": 0},
    "month": {"upload": 0, "download": 0, "total": 0},
    "total": {"upload": 0, "download": 0, "total": 0}
  }
}

数据模型

不新增数据表或字段,继续读取 v2_stat_server 的日统计记录:

字段 类型 说明
u bigint 上行流量
d bigint 下行流量
record_at int 日统计归属日的 00:00:00 Unix 时间戳
record_type char 本节点页只读取 d

4. 核心场景

场景: 节点流量详情卡查看昨日统计

模块: admin-frontend
条件: 管理员打开 #/nodes 并悬停节点名称
行为: 前端读取 traffic_stats.yesterday 并渲染“昨日”行
结果: 管理员可以直接对比今日、昨日、本月和累计的上行/下行分布

场景: 节点列表接口按清晰窗口聚合

模块: backend-admin-api
条件: v2_stat_server 存在昨天、今天、本月其他日期和未来日期记录
行为: server/manage/getNodes 构建半开时间窗口
结果: 今日、昨日、本月统计互不串窗,累计仍覆盖全部历史记录


5. 技术决策

node-traffic-yesterday-stats#D001: 保持 u/d 语义并新增后端 yesterday 字段

日期: 2026-04-29
状态: 采纳
背景: 用户反馈上行/下行看起来不匹配,同时要求加入昨日统计。代码链路显示前端、接口和入库任务均使用 u=uploadd=download
选项分析:

选项 优点 缺点
A: 后端新增 traffic_stats.yesterday 并收紧窗口 口径统一、可测试、兼容当前字段 增加一个聚合查询
B: 前端推导昨日 不改后端 无法准确得到昨日上行/下行
C: 反转 u/d 字段 可能符合某些节点端方向理解 会破坏现有面板语义和历史统计
决策: 选择方案 A
理由: 问题核心是缺少可对比的昨日窗口和窗口边界不够明确,不是面板链路内字段反转。
影响: server/manage/getNodes 响应字段增加,节点页详情卡增加一行展示。

6. 验证策略

verifyMode: test-first
reviewerFocus:
  - app/Http/Controllers/V2/Admin/Server/ManageController.php 的窗口边界和兼容字段
  - admin-frontend/src/utils/nodes.ts 的展示顺序与空值兜底
testerFocus:
  - php artisan test --filter NodeTrafficStatsTest
  - npm run buildadmin-frontend
uiValidation: optional
riskBoundary:
  - 不执行数据库删除、重置或生产环境操作
  - 不修改历史 StatServer 数据

7. 成果设计

设计方向

  • 美学基调: 延续现有 Apple 风格节点详情卡,新增“昨日”作为同等层级数据行,不引入额外视觉系统。
  • 记忆点: 今日与昨日紧邻展示,便于直接比较日流量方向变化。
  • 参考: 现有节点流量 popover。

视觉要素

  • 配色: 沿用现有白底、浅灰行底和蓝色总量强调。
  • 字体: 沿用现有管理端字体栈,不新增字体依赖。
  • 布局: 维持纵向统计行结构,顺序为今日、昨日、本月、累计。
  • 动效: 沿用 Element Plus Popover 行为,不新增动效。
  • 氛围: 与当前节点页一致。

技术约束

  • 可访问性: 不改变现有 hover/focus 触发方式。
  • 响应式: Popover 宽度维持现状,新增一行不改变表格布局。