e847252e12
统一节点流量统计与限额展示口径,节点详情新增昨日流量, 并让今日、昨日和本月使用清晰的半开时间窗口聚合 同 machine_id 或同 host 的节点现在共享当前账期已用流量, 管理端优先使用后端 traffic_limit_snapshot 展示月额度状态, mi-node 下发的 current_used 也改为共享账期统计 新增 parent_auto_hidden 标记与父节点显隐联动服务,父节点 因自动上线或流量限额变为不可展示时会隐藏当前显示的子节点, 恢复时只恢复这批自动隐藏的子节点,避免覆盖手动操作
7.3 KiB
7.3 KiB
变更提案: 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 >= startAt且record_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=upload、d=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 build(admin-frontend)
uiValidation: optional
riskBoundary:
- 不执行数据库删除、重置或生产环境操作
- 不修改历史 StatServer 数据
7. 成果设计
设计方向
- 美学基调: 延续现有 Apple 风格节点详情卡,新增“昨日”作为同等层级数据行,不引入额外视觉系统。
- 记忆点: 今日与昨日紧邻展示,便于直接比较日流量方向变化。
- 参考: 现有节点流量 popover。
视觉要素
- 配色: 沿用现有白底、浅灰行底和蓝色总量强调。
- 字体: 沿用现有管理端字体栈,不新增字体依赖。
- 布局: 维持纵向统计行结构,顺序为今日、昨日、本月、累计。
- 动效: 沿用 Element Plus Popover 行为,不新增动效。
- 氛围: 与当前节点页一致。
技术约束
- 可访问性: 不改变现有 hover/focus 触发方式。
- 响应式: Popover 宽度维持现状,新增一行不改变表格布局。