feat(eink): 自检页显示「对端内网」可达性

把第二步的探测结果露出来 —— 否则"走内网还是走公网"只是代码里的一个变量,
用户看不见,也就没法判断到底有没有生效(本项目一贯要求可验证)。

**三种状态必须分得开**:
  · 对端未上报(可能不在同一局域网)
  · 已上报但探不通(会列出试过哪些端点)
  · 可达(显示具体是哪个端点)
混成一句"不可用",用户就没法判断是"我这边的服务没起来"还是"对端根本没报"。

⚠️ 诚实边界:探测结果**不是实时推送的**,在下一次节流刷新时反映到界面(最多 10 秒)。
这是刻意的取舍 —— 为一个诊断行加一条推送通道要多一处要维护的接口,
而看板本来就有节流刷新,够用。

客户端 361/361、analyze 干净。
This commit is contained in:
PMon Dev committed 2026-09-18 22:40:20 +08:00
1 parent 977067c114
commit fcd7d24803
1 file changed
+19
+19
View File
@@ -466,6 +466,24 @@ class _ViewerPageState extends State<ViewerPage> with WidgetsBindingObserver {
overlays: SystemUiOverlay.values));
}
/// 对端内网可达性的一句话摘要。
///
/// **三种状态必须分得开**:对端没上报端点 / 上报了但探不通 / 探通了。
/// 混成一句"不可用",用户就没法判断是"我这边的问题"还是"对端没开"。
///
/// ⚠️ 探测结果**不是实时推送的**:它在下一次节流刷新时反映到界面(最多 10 秒)。
/// 这是刻意的取舍 —— 为一个诊断行加一条推送通道要多一处要维护的接口,
/// 而看板本来就有节流刷新,够用。
String _lanSummary() {
final s = _session;
if (s == null) return '无会话';
if (s.lanProbing) return '检测中…';
final hit = s.lanReachable;
if (hit != null) return '可达 · $hit';
if (s.lanEndpoints.isEmpty) return '对端未上报(可能不在同一局域网)';
return '不可达 · 已试 ${s.lanEndpoints.join('、')}';
}
/// 看板外壳:必要时套一层**应用内旋转**。
///
/// `RotatedBox(quarterTurns: 1)` 的关键性质是**交换子节点的约束**
@@ -817,6 +835,7 @@ class _ViewerPageState extends State<ViewerPage> with WidgetsBindingObserver {
LanService.instance.running
? '已开 · ${LanService.instance.endpoint}'
: (LanService.instance.lastError?.toString() ?? '未启动')),
('对端内网', _lanSummary()),
('刷新间隔', _einkSec == 0 ? '仅手动' : '$_einkSec 秒'),
('已收帧数', '${_series.received}'),
('本会话断点', '${_series.gapCount}'),