diff --git a/robot.py b/robot.py index 6d78332..582a853 100644 --- a/robot.py +++ b/robot.py @@ -543,6 +543,9 @@ class Robot: connection_ready = bool((payload or {}).get("connection_ready", False)) login_required = bool((payload or {}).get("login_required", True)) verification_url = str((payload or {}).get("verification_url", "") or "").strip() + raw_state = int((payload or {}).get("raw_state", 0) or 0) + nick_name = str((payload or {}).get("nick_name", "") or "").strip() + head_img_url = str((payload or {}).get("head_img_url", "") or "").strip() expires_in = (payload or {}).get("expires_in") expires_in = None if expires_in in (None, "") else max(0, int(expires_in)) current_record = { @@ -550,6 +553,9 @@ class Robot: "scan_url": scan_url, "raw_url": raw_url, "verification_url": verification_url, + "raw_state": raw_state, + "nick_name": nick_name, + "head_img_url": head_img_url, "image_data": self._build_qr_image_data(scan_url), "status": status, "status_text": status_text, diff --git a/wechat_ipad/providers/server_864/login.py b/wechat_ipad/providers/server_864/login.py index 2b7d74c..51623e1 100644 --- a/wechat_ipad/providers/server_864/login.py +++ b/wechat_ipad/providers/server_864/login.py @@ -117,7 +117,20 @@ class LoginMixin(Server864APIClientBase): ) if verification_url: normalized["verification_url"] = str(verification_url).strip() + # 864 的扫码状态字段在不同版本里语义并不完全一致: + # 1. 上层运行时需要知道原始 state,才能区分“等待扫码 / 安全验证 / 终态缓存未清理”等场景; + # 2. 因此这里除了保留旧的 `state` 字段外,再显式放一份 `raw_state` 供 runtime 做分支; + # 3. 同时把昵称、头像这些已扫描用户信息一并透出,便于 Dashboard 展示最新状态。 state = int(normalized.get("state", 0) or 0) + normalized["raw_state"] = state + if self._pick_first(normalized, "nick_name", "nickName", "NickName"): + normalized["nick_name"] = str( + self._pick_first(normalized, "nick_name", "nickName", "NickName") or "" + ).strip() + if self._pick_first(normalized, "head_img_url", "headImgUrl", "HeadImgUrl"): + normalized["head_img_url"] = str( + self._pick_first(normalized, "head_img_url", "headImgUrl", "HeadImgUrl") or "" + ).strip() login_state = str(normalized.get("loginState", "") or "").strip().lower() return state == 2 or login_state == "online", normalized diff --git a/wechat_ipad/providers/server_864/runtime.py b/wechat_ipad/providers/server_864/runtime.py index 717ec4a..8b0dcc3 100644 --- a/wechat_ipad/providers/server_864/runtime.py +++ b/wechat_ipad/providers/server_864/runtime.py @@ -193,23 +193,42 @@ class Server864RuntimeMixin: # 3. 一旦 server 侧切换了新的 uuid,这里也要及时覆盖本地展示态,避免前端一直盯着旧码。 latest_uuid = str(login_status.get("uuid", "") or uuid).strip() or uuid effective_time = int(login_status.get("effective_time", 0) or 0) + raw_state = int(login_status.get("raw_state", login_status.get("state", 0)) or 0) verification_url = str(login_status.get("verification_url", "") or "").strip() + nick_name = str(login_status.get("nick_name", "") or "").strip() + head_img_url = str(login_status.get("head_img_url", "") or "").strip() if latest_uuid != uuid: uuid = latest_uuid scan_url = f"http://weixin.qq.com/x/{uuid}" if uuid else "" url = f"https://api.2dcode.biz/v1/create-qr-code?data={scan_url}" if scan_url else url - provider_stage = "verification_required" if verification_url else ("waiting_scan" if uuid else "login_required") - # 864 在“已扫码但待安全验证”阶段,`msg/loginState` 往往是空字符串: - # 1. 若直接套用默认“等待扫码登录”,用户会误以为还没扫上; - # 2. 因此这里优先识别 `verification_url`,给 Dashboard 一个更准确的引导文案; - # 3. 只有完全拿不到状态提示时,才回退到普通扫码等待文案。 + # 864 的 `CheckLoginStatus` 存在一类“状态缓存已终态,但服务端连接没有继续推进”的情况: + # 1. 实测里扫码并完成安全验证后,接口可能停在 `state=4 + VerificationUrl`,前端会一直看见旧状态; + # 2. 结合服务端源码,这类 `state=4` 更接近终态/失效态,而不是可继续等待的中间态; + # 3. 因此这里把它单独识别出来,避免 Dashboard 长时间卡在“等待安全验证”的旧文案。 raw_status_text = str(login_status.get("msg") or login_status.get("loginState") or "").strip() - if verification_url and not raw_status_text: - status_text = "扫码已完成,请继续打开验证链接完成安全验证" + if raw_state == 4: + provider_stage = "login_required" + status = "expired" + if verification_url: + status_text = "安全验证链路已结束,但服务端未完成登录收口,正在准备刷新二维码" + else: + status_text = raw_status_text or "二维码状态已结束,正在准备刷新二维码" + elif verification_url: + provider_stage = "verification_required" + status = "waiting" + if not raw_status_text: + status_text = "扫码已完成,请继续打开验证链接完成安全验证" + else: + status_text = raw_status_text else: + provider_stage = "waiting_scan" if uuid else "login_required" + status = "waiting" status_text = raw_status_text or "等待扫码登录" + if verification_url and raw_state != 4 and not raw_status_text: + status_text = "扫码已完成,请继续打开验证链接完成安全验证" + await self._safe_callback( on_login_qr_update, { @@ -217,7 +236,7 @@ class Server864RuntimeMixin: "url": url, "scan_url": scan_url, "expires_in": effective_time if effective_time > 0 else None, - "status": "waiting", + "status": status, "status_text": status_text, "login_source": "fresh_qr", "provider_name": "server_864", @@ -225,6 +244,9 @@ class Server864RuntimeMixin: "connection_ready": False, "login_required": True, "verification_url": verification_url, + "raw_state": raw_state, + "nick_name": nick_name, + "head_img_url": head_img_url, "login_qr_api": login_qr_api, "login_way": login_way, }, @@ -232,11 +254,11 @@ class Server864RuntimeMixin: callback_name="on_login_qr_update", ) - # 若 server 已明确告知二维码失效,则立即重新申请一张新码: + # 若 server 已明确告知二维码失效或停在终态缓存,则立即重新申请一张新码: # 1. 这能避免 Dashboard 一直展示一张已经不可扫的旧二维码; - # 2. 也能让新环境登录时的交互与 855 保持一致,都是“过期就自动刷新”; - # 3. 重新申请后直接回到当前 while 顶部继续轮询新的 uuid 状态。 - if effective_time <= 0: + # 2. 864 某些版本即使 `effective_time` 还大于 0,也可能已经停在 `state=4` 终态缓存里; + # 3. 因此这里补充 `raw_state == 4` 的刷新条件,让前端能尽快得到新的登录入口。 + if effective_time <= 0 or raw_state == 4: uuid, url = await self.get_qr_code(print_qr=True, login_qr_api=login_qr_api, login_way=login_way) scan_url = f"http://weixin.qq.com/x/{uuid}" if uuid else "" await self._safe_callback(