From 6a64c3d008554b1ada9d630fe42af38385b6d2fd Mon Sep 17 00:00:00 2001 From: Rodger-Wang <1367893453@qq.com> Date: Fri, 4 Sep 2026 23:38:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=8A=E4=B8=A4=E5=A4=84=E7=BD=91=E7=BB=9C?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E7=A7=BB=E5=87=BA=E5=90=AF=E5=8A=A8=E4=B8=8E?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E9=A1=B5=E7=9A=84=E5=85=B3=E9=94=AE=E8=B7=AF?= =?UTF-8?q?=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 会议模板不再挡启动与登录 _performParallelTasks 名字叫并行、实际完全串行(网络检查 → 版本检查 → token 校验,后者内部又是 getLoginToken → getAppConfig → _initMeetingTemplate), 冷启动要串等 5 次网络往返,而 _initializeApp 要等这一整串跑完才允许导航。 其中 ②③ 之间的串行是刻意的(强更弹窗必须先出、把 splash 卡住,见 CLAUDE.md), 不能改回并行;但 _initMeetingTemplate 排在最后、**启动时没有任何地方要用它** ——模板只落 sqlite,由会议模板页 getMeetingTemplateList 消费。改成 unawaited, 模板照常拉取更新,启动不再等它。 登录流程里同一句挡在 Get.offAllNamed(Routes.home) 前面,一并改。 设备页先渲染再补登记 loadDevices 里 `await BesDeviceAuth.verifyConnected()` 串在 getdevices 前面,首次进入白名单没命中时会真的去打 user_binddevice(带 10s 超时), 整个页面干等两次网络往返——就是「点设备页半天没响应」。 - isLoading 改成只在本地无数据时才遮罩:onInit 里 _refreshFromUser() 本来 就已经拿本地列表渲染过一次了,再盖一层纯属让用户对着转圈等。 - verifyConnected 挪到列表渲染之后、改成后台跑。它登记成功时会直接把设备 塞进 User.instance.devices,回来 _refreshFromUser() 刷一次即可, 不必再拉一遍 getdevices。 ⚠️ 代价:首次连接的新耳机会晚一两秒才出现在列表里(以前是干等到它出现才 显示整个页面)。这是「页面立刻可见」的必然结果。 ⚠️ 两处的实际收益都要在 release 包上量,debug 的 JIT 会把差异淹掉。 Co-Authored-By: Claude Opus 5 --- .../login/controllers/login_controller.dart | 5 ++++- .../controllers/my_devices_controller.dart | 22 ++++++++++++++----- .../splash/controllers/splash_controller.dart | 7 +++++- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/apps/client/lib/modules/login/controllers/login_controller.dart b/apps/client/lib/modules/login/controllers/login_controller.dart index a1a2d205..6dcd8eb2 100644 --- a/apps/client/lib/modules/login/controllers/login_controller.dart +++ b/apps/client/lib/modules/login/controllers/login_controller.dart @@ -704,7 +704,10 @@ class LoginController extends GetxController { // 获取app的配置信息 await getAppConfig(); - await _initMeetingTemplate(); + // 会议模板不挡登录:它只被会议模板页读取(落 sqlite), + // await 它等于让用户在登录按钮上多等一次网络往返才跳主页。 + // 与 splash 的处理一致。 + unawaited(_initMeetingTemplate()); // 登录成功 → 直接进入首页 Get.offAllNamed(Routes.home); } else { diff --git a/apps/client/lib/modules/my_devices/controllers/my_devices_controller.dart b/apps/client/lib/modules/my_devices/controllers/my_devices_controller.dart index 3e323127..fb165b26 100644 --- a/apps/client/lib/modules/my_devices/controllers/my_devices_controller.dart +++ b/apps/client/lib/modules/my_devices/controllers/my_devices_controller.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:get/get.dart'; import '/core/utils/logger.dart'; @@ -35,13 +37,10 @@ class MyDevicesController extends GetxController { /// 从服务端拉取最新的设备列表,并刷新 [User.instance.devices]。 Future loadDevices() async { if (!User.isLoggedIn()) return; - isLoading.value = true; + // 本地已有数据就不要遮罩:onInit 里 _refreshFromUser() 已经拿本地列表渲染过 + // 一次了,再盖一层 loading 只会让用户对着转圈干等网络往返。 + isLoading.value = User.instance.devices.isEmpty; try { - // 补校当前连着的恒玄耳机(顺带完成绑定登记)。 - // 「先连耳机、后登录」是很常见的顺序,那时候连接事件里的登记会因为 - // 未登录而跳过;不在这里补一次,这台设备就要等下次重连才会出现在列表里。 - // 放在拉取之前,这样这次刷新就能看到它。 - await BesDeviceAuth.verifyConnected(); final response = await Api.getdevices(); if (response != null) { final list = response['devices'] as List?; @@ -60,6 +59,17 @@ class MyDevicesController extends GetxController { _refreshFromUser(); isLoading.value = false; } + + // 补校当前连着的恒玄耳机(顺带完成绑定登记)。 + // 「先连耳机、后登录」是很常见的顺序,那时候连接事件里的登记会因为未登录 + // 而跳过;不在这里补一次,这台设备就要等下次重连才会出现在列表里。 + // + // ⚠️ 但**不能串在 getdevices 前面**:首次连接时白名单没命中,它会真的去打 + // user_binddevice(带 10s 超时),整个页面就得干等这一趟——表现就是 + // 「点设备页半天没响应」。放到列表渲染之后跑,页面立刻可见。 + // 它登记成功时会直接把设备塞进 User.instance.devices,所以回来刷一次就够, + // 不必再拉一遍 getdevices。 + unawaited(BesDeviceAuth.verifyConnected().then((_) => _refreshFromUser())); } /// 解绑设备:调接口成功后从本地列表移除;如果是当前连接的设备,断开并跳到扫描页。 diff --git a/apps/client/lib/modules/splash/controllers/splash_controller.dart b/apps/client/lib/modules/splash/controllers/splash_controller.dart index 50e03897..682ef267 100644 --- a/apps/client/lib/modules/splash/controllers/splash_controller.dart +++ b/apps/client/lib/modules/splash/controllers/splash_controller.dart @@ -218,7 +218,12 @@ class SplashController extends GetxController { if (isLoggedIn) { // 只有登录成功,才获取App配置 await getAppConfig(); - await _initMeetingTemplate(); + // ⚠️ 会议模板**不放在启动关键路径上**:它只被会议模板页读取 + // (落 sqlite,由 SqfliteApi.getMeetingTemplateList 消费), + // 启动时没有任何地方要用。原来 await 它等于让每次冷启动的白屏 + // 多背一次网络往返——而 _initializeApp 要等这一整串跑完才允许导航。 + // 改成后台拉:模板照常更新,启动不再等它。 + unawaited(_initMeetingTemplate()); } else { await User.clearUserSession(); // }