From 3e56c90ab7df9c6d738d403d351e822c3067b8c1 Mon Sep 17 00:00:00 2001 From: liuwei Date: Thu, 7 May 2026 14:43:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B1=95=E7=A4=BA864=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E9=98=B6=E6=AE=B5=E6=98=8E=E7=A1=AE=E9=94=99=E8=AF=AF=E5=8E=9F?= =?UTF-8?q?=E5=9B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/dashboard/templates/index.html | 9 ++++ wechat_ipad/providers/server_864/runtime.py | 53 ++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/admin/dashboard/templates/index.html b/admin/dashboard/templates/index.html index 8522caa..212d942 100644 --- a/admin/dashboard/templates/index.html +++ b/admin/dashboard/templates/index.html @@ -651,6 +651,9 @@ if (this.loginQrDialog.provider_stage === 'login_required') { return '需要重新登录'; } + if (this.loginQrDialog.provider_stage === 'status_unavailable') { + return '登录异常'; + } if (this.loginQrDialog.provider_stage === 'scan_confirmed') { return '已扫码待确认'; } @@ -665,6 +668,9 @@ if (this.loginQrDialog.provider_stage === 'connection_pending') { return '864 服务端准备中'; } + if (this.loginQrDialog.provider_stage === 'status_unavailable') { + return '864 登录异常'; + } if (this.loginQrDialog.provider_stage === 'scan_confirmed') { return '864 扫码确认中'; } @@ -692,6 +698,9 @@ if (this.loginQrDialog.provider_stage === 'connection_pending') { return '等待服务端准备'; } + if (this.loginQrDialog.provider_stage === 'status_unavailable') { + 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 6a83b00..99fcd98 100644 --- a/wechat_ipad/providers/server_864/runtime.py +++ b/wechat_ipad/providers/server_864/runtime.py @@ -1,5 +1,6 @@ import asyncio import os +import re import time from typing import Any, Awaitable, Callable @@ -27,6 +28,29 @@ class Server864RuntimeMixin: def is_runtime_running(self) -> bool: return bool(getattr(self, "_runtime_running", False)) + @staticmethod + def _normalize_login_runtime_message(message: str) -> str: + """把 864 登录阶段抛出的原始错误整理成更适合前端展示的短文本。""" + raw_message = str(message or "").strip() + if not raw_message: + return "864 登录流程发生异常,请查看服务端日志" + + # 864 某些失败场景会把整段 XML 直接塞进错误信息里: + # 1. 终端日志能看到完整 XML,但前端直接展示这段原文会非常难读; + # 2. 这里优先提取 `` 里的真正提示语; + # 3. 这样像“客户端版本过低”这种关键原因可以直接显示给运维人员。 + content_match = re.search(r"", raw_message, flags=re.S) + if content_match: + extracted = str(content_match.group(1) or "").strip() + if extracted: + raw_message = extracted + + # 把换行和多余空格压平,避免弹窗里出现大段不可读排版。 + normalized = " ".join(part for part in re.split(r"\s+", raw_message) if part) + if "客户端版本过低" in normalized: + return f"{normalized} 请更换更高版本的 864 client/server 组合后再登录。" + return normalized + async def run_runtime( self, *, @@ -169,7 +193,34 @@ class Server864RuntimeMixin: ) while True: - is_logged_in, login_status = await self.check_login_status() + try: + is_logged_in, login_status = await self.check_login_status() + except Exception as e: + error_message = self._normalize_login_runtime_message(str(e)) + # 登录轮询阶段一旦出现明确错误,应立刻同步到 Dashboard: + # 1. 之前这类异常只会停在控制台日志,前端继续显示旧的“等待扫码/等待验证”文案; + # 2. 用户已经扫码后,最需要的是第一时间知道“为什么卡住了”; + # 3. 因此这里把错误直接回写成登录态,让弹窗成为当前环境登录的真实看板。 + 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, + "login_qr_api": login_qr_api, + "login_way": login_way, + }, + logger=logger, + callback_name="on_login_qr_update", + ) + raise RuntimeError(error_message) from e if is_logged_in: await self._safe_callback( on_login_qr_cleared,