diff --git a/admin/dashboard/templates/index.html b/admin/dashboard/templates/index.html index 212d942..d59ef79 100644 --- a/admin/dashboard/templates/index.html +++ b/admin/dashboard/templates/index.html @@ -654,6 +654,9 @@ if (this.loginQrDialog.provider_stage === 'status_unavailable') { return '登录异常'; } + if (this.loginQrDialog.provider_stage === 'login_finalizing') { + return '登录收口中'; + } if (this.loginQrDialog.provider_stage === 'scan_confirmed') { return '已扫码待确认'; } @@ -671,6 +674,9 @@ if (this.loginQrDialog.provider_stage === 'status_unavailable') { return '864 登录异常'; } + if (this.loginQrDialog.provider_stage === 'login_finalizing') { + return '864 登录收口中'; + } if (this.loginQrDialog.provider_stage === 'scan_confirmed') { return '864 扫码确认中'; } @@ -701,6 +707,9 @@ if (this.loginQrDialog.provider_stage === 'status_unavailable') { return '请查看当前错误提示'; } + if (this.loginQrDialog.provider_stage === 'login_finalizing') { + return '扫码成功,等待服务端完成登录'; + } if (this.loginQrDialog.provider_stage === 'scan_confirmed') { return '已扫码,等待服务端确认'; } diff --git a/wechat_ipad/providers/server_864/runtime.py b/wechat_ipad/providers/server_864/runtime.py index 99fcd98..5ff7a44 100644 --- a/wechat_ipad/providers/server_864/runtime.py +++ b/wechat_ipad/providers/server_864/runtime.py @@ -223,22 +223,29 @@ class Server864RuntimeMixin: raise RuntimeError(error_message) from e if is_logged_in: await self._safe_callback( - on_login_qr_cleared, + on_login_qr_update, { + "uuid": uuid, + "url": url, + "scan_url": scan_url, + "expires_in": effective_time if effective_time > 0 else None, "status": "confirmed", # 864 进入 `state=2` 后,已经拿到了 wxid / wxnewpass 等关键登录信息: - # 1. 这说明扫码本身已经成功,不需要用户继续执行额外扫码动作; - # 2. 这里把提示文案改得更明确,减少“是不是还要继续点验证链接”的疑惑; - # 3. 后续若服务端初始化还要几秒,也归入“服务端完成登录”阶段,而不是继续归咎给扫码步骤。 + # 1. 这说明扫码本身已经成功,但并不代表 ABOT 后续初始化已经全部完成; + # 2. 若这里直接关闭弹窗,后面的版本过低/初始化失败就无法同步给前端; + # 3. 因此先保持弹窗可见,把阶段切到“登录收口中”,等真正初始化完成后再清理。 "status_text": "扫码成功,等待服务端完成登录", - "uuid": uuid, + "login_source": "fresh_qr", "provider_name": "server_864", - "provider_stage": "logged_in", + "provider_stage": "login_finalizing", "connection_ready": True, "login_required": False, + "raw_state": 2, + "login_qr_api": login_qr_api, + "login_way": login_way, }, logger=logger, - callback_name="on_login_qr_cleared", + callback_name="on_login_qr_update", ) break @@ -347,15 +354,43 @@ class Server864RuntimeMixin: ) await asyncio.sleep(5) - await self._wait_init_ready(logger=logger) - await self._refresh_identity_from_profile(logger=logger) - ipad_config["wxid"] = self.wxid - ipad_config["login_time"] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) - self._save_runtime_state( - state_path=state_path, - state_payload={"wxid": self.wxid, "login_time": ipad_config["login_time"]}, - logger=logger, - ) + try: + await self._wait_init_ready(logger=logger) + await self._refresh_identity_from_profile(logger=logger) + ipad_config["wxid"] = self.wxid + ipad_config["login_time"] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + self._save_runtime_state( + state_path=state_path, + state_payload={"wxid": self.wxid, "login_time": ipad_config["login_time"]}, + logger=logger, + ) + except Exception as e: + error_message = self._normalize_login_runtime_message(str(e)) + # 扫码成功后的收口阶段同样需要把异常同步给前端: + # 1. 这类错误往往发生在“state=2 之后但正式进入业务前”,最容易被误判成前端没刷新; + # 2. 例如当前用户遇到的“客户端版本过低”就是在这个阶段由服务端主动断开; + # 3. 因此这里明确把阶段标成 `status_unavailable`,让弹窗继续停留并展示真实原因。 + await self._safe_callback( + on_login_qr_update, + { + "uuid": uuid, + "url": url, + "scan_url": scan_url, + "status": "unavailable", + "status_text": error_message, + "login_source": "fresh_qr", + "provider_name": "server_864", + "provider_stage": "status_unavailable", + "connection_ready": False, + "login_required": True, + "raw_state": 2, + "login_qr_api": login_qr_api, + "login_way": login_way, + }, + logger=logger, + callback_name="on_login_qr_update", + ) + raise RuntimeError(error_message) from e async def _probe_login_stage(self) -> dict[str, Any]: """探测 864 当前登录阶段,供 Dashboard 展示更准确的运维状态。"""