新增Dashboard未登录二维码引导与倒计时

This commit is contained in:
liuwei
2026-05-07 11:10:00 +08:00
parent c628afc530
commit 86f8d57874
5 changed files with 900 additions and 1 deletions

View File

@@ -49,6 +49,8 @@ class Legacy855RuntimeMixin:
on_idle_payload: AsyncCallback | None = None,
on_logout: AsyncCallback | None = None,
on_runtime_state_change: AsyncCallback | None = None,
on_login_qr_update: AsyncCallback | None = None,
on_login_qr_cleared: AsyncCallback | None = None,
) -> None:
"""启动 855 provider 的完整运行时。
@@ -73,6 +75,8 @@ class Legacy855RuntimeMixin:
ipad_config=ipad_config,
state_path=state_path,
logger=logger,
on_login_qr_update=on_login_qr_update,
on_login_qr_cleared=on_login_qr_cleared,
)
# 登录后的项目初始化若失败,应直接中断启动:
@@ -163,6 +167,8 @@ class Legacy855RuntimeMixin:
ipad_config: dict,
state_path: str,
logger,
on_login_qr_update: AsyncCallback | None = None,
on_login_qr_cleared: AsyncCallback | None = None,
) -> None:
"""保证当前 provider 已完成登录,并把登录结果写回配置。
@@ -178,6 +184,15 @@ class Legacy855RuntimeMixin:
self.alias = profile.get("Alias", "")
self.phone = profile.get("BindMobile", {}).get("string", "")
self.signature = profile.get("Signature", "")
await self._safe_callback(
on_login_qr_cleared,
{
"status": "logged_in",
"status_text": "已检测到现有登录态",
},
logger=logger,
callback_name="on_login_qr_cleared",
)
logger.info(
f"wechat_ipad登录账号信息: wxid: {self.wxid} 昵称: {self.nickname} 微信号: {self.alias} 手机号: {self.phone}"
)
@@ -186,9 +201,11 @@ class Legacy855RuntimeMixin:
while not await self.is_logged_in(wxid):
uuid = ""
url = ""
login_source = "fresh_qr"
try:
if await self.get_cached_info(wxid):
uuid = await self.awaken_login(wxid)
login_source = "awaken"
logger.info(f"获取到登录uuid: {uuid}")
else:
uuid, url = await self.get_qr_code(device_id=device_id, device_name=device_name, print_qr=True)
@@ -197,17 +214,77 @@ class Legacy855RuntimeMixin:
except Exception as e:
logger.error(f"登录过程出错: {e}")
uuid, url = await self.get_qr_code(device_id=device_id, device_name=device_name, print_qr=True)
login_source = "fresh_qr"
logger.info(f"获取到登录uuid: {uuid}")
logger.info(f"获取到登录二维码: {url}")
# 每次拿到新的 uuid 都立刻把二维码状态推给上层:
# 1. 这样 Dashboard 无需等待下一次轮询结果,就能立刻弹出二维码;
# 2. 即使是 awaken 登录没有返回图片 URL也可以先靠 uuid 生成扫码内容;
# 3. 后续倒计时再通过 check_login_uuid 的轮询结果持续刷新。
scan_url = f"http://weixin.qq.com/x/{uuid}" if uuid else ""
await self._safe_callback(
on_login_qr_update,
{
"uuid": uuid,
"url": url,
"scan_url": scan_url,
"expires_in": None,
"status": "waiting",
"status_text": "等待扫码登录",
"login_source": login_source,
},
logger=logger,
callback_name="on_login_qr_update",
)
while True:
logger.info(f"uuid: {uuid}, url: {url}")
stat, data = await self.check_login_uuid(uuid, device_id=device_id)
if stat:
await self._safe_callback(
on_login_qr_cleared,
{
"status": "confirmed",
"status_text": "扫码登录成功",
"uuid": uuid,
},
logger=logger,
callback_name="on_login_qr_cleared",
)
break
# 855 的扫码登录会返回剩余有效期:
# 1. 这里把它直接同步给上层Dashboard 就能展示实时倒计时;
# 2. 一旦倒计时归零,当前二维码已失效,应跳出内层循环重新申请新二维码;
# 3. 这样新环境登录时不会卡在一张已经过期的旧码上。
expires_in = int(data or 0)
qr_status = "expired" if expires_in <= 0 else "waiting"
qr_status_text = "二维码已过期,准备刷新" if expires_in <= 0 else "等待扫码登录"
await self._safe_callback(
on_login_qr_update,
{
"uuid": uuid,
"url": url,
"scan_url": scan_url,
"expires_in": expires_in,
"status": qr_status,
"status_text": qr_status_text,
"login_source": login_source,
},
logger=logger,
callback_name="on_login_qr_update",
)
logger.info(f"等待登录中,过期倒计时:{expires_in}")
if expires_in <= 0:
break
logger.info(f"等待登录中,过期倒计时:{data}")
await asyncio.sleep(5)
if not stat:
# 当前二维码失效后回到外层 while 重新申请新二维码,
# 这样可以持续给 Dashboard 产出新的扫码入口。
continue
self._apply_login_result(data=data, logger=logger)
ipad_config["wxid"] = self.wxid
ipad_config["device_name"] = device_name