feat(client): P4 节点实测延迟/设备/套餐价/兑换/统计接真(#6 6D)
ci-pangolin / Lint — shellcheck (push) Has been cancelled
ci-pangolin / OpenAPI Sync Check (push) Has been cancelled
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Has been cancelled
ci-pangolin / Flutter — analyze + test (push) Has been cancelled

- latency_probe.dart:并行 TCP 握手实测各节点 per-client RTT(服务端无法代知)。
- nodes_provider:解析 /v1/nodes 的 host/port,后台测延迟回填 Node.ping;智能选择
  按实测最小;去掉 8 个伪造演示节点(空列表用中性占位,不再伪造服务器)。
- Node:+host/port/copyWith/pingLabel(未测显示 —);各端 ping 显示改 pingLabel。
- account_screens:PlansScreen 接 /v1/plans(价格 priceLabel + me 标当前档);
  DevicesScreen 接 /v1/me/devices + 移除 DELETE + last_seen;RedeemScreen 接
  /v1/redeem(成功刷新 me,失败显示后端文案)。
- stats_page:周柱接 me.weekly_gb,本月流量/时长接 usage(30),延迟用生效节点实测。
- 顺带补登记早前 log_time.dart 的删除(log.dart 重构遗漏 stage)。

flutter analyze 0 error;115 tests passed;受影响 4 golden 重生成。
本机设备高亮 + 真实 device id 随 P6(device_info_plus)落地。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-19 00:04:25 +08:00
parent bb39b36d84
commit f20eddad55
15 changed files with 321 additions and 162 deletions
+20
View File
@@ -5,6 +5,7 @@
// 在后续阶段加入本文件。
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../models/device.dart';
import '../models/me.dart';
import '../models/plan.dart';
import '../models/usage_point.dart';
@@ -58,3 +59,22 @@ final usageProvider = FutureProvider.family<List<UsagePoint>, int>((ref, days) a
if (!ref.watch(authProvider).isLoggedIn) return const [];
return ref.read(accountApiProvider).usage(days: days);
});
/// 已登录设备列表(GET /v1/me/devices)。
class DevicesNotifier extends AsyncNotifier<List<Device>> {
@override
Future<List<Device>> build() async {
if (!ref.watch(authProvider).isLoggedIn) return const [];
return ref.read(accountApiProvider).devices();
}
/// 移除设备(DELETE)后刷新列表。
Future<void> remove(String uuid) async {
await ref.read(accountApiProvider).removeDevice(uuid);
ref.invalidateSelf();
await future;
}
}
final devicesProvider =
AsyncNotifierProvider<DevicesNotifier, List<Device>>(DevicesNotifier.new);