优化864登录三态展示并更新适配路线文档
This commit is contained in:
@@ -20,6 +20,10 @@ def _serialize_login_qr_state(server) -> dict:
|
||||
"logged_in": False,
|
||||
"active": False,
|
||||
"status": "unavailable",
|
||||
"provider_name": "",
|
||||
"provider_stage": "status_unavailable",
|
||||
"connection_ready": False,
|
||||
"login_required": False,
|
||||
"status_text": "机器人运行态暂不可用",
|
||||
"current": {},
|
||||
"history": [],
|
||||
@@ -31,6 +35,10 @@ def _serialize_login_qr_state(server) -> dict:
|
||||
"logged_in": bool(state.get("logged_in", False)),
|
||||
"active": bool(state.get("active", False)),
|
||||
"status": str(state.get("status", "idle") or "idle"),
|
||||
"provider_name": str(state.get("provider_name", "") or ""),
|
||||
"provider_stage": str(state.get("provider_stage", "bootstrap") or "bootstrap"),
|
||||
"connection_ready": bool(state.get("connection_ready", False)),
|
||||
"login_required": bool(state.get("login_required", False)),
|
||||
"status_text": str(state.get("status_text", "尚未进入扫码登录流程") or "尚未进入扫码登录流程"),
|
||||
"runtime_running": bool(state.get("runtime_running", False)),
|
||||
"wxid": str(state.get("wxid", "") or ""),
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<template slot="title">
|
||||
<div class="login-qr-banner__content">
|
||||
<div>
|
||||
<div class="login-qr-banner__title">当前微信未登录,首页已进入扫码引导模式</div>
|
||||
<div class="login-qr-banner__title">{% raw %}{{ loginQrBannerTitle }}{% endraw %}</div>
|
||||
<div class="login-qr-banner__desc">
|
||||
{% raw %}{{ loginQrDialog.status_text || '请使用手机微信扫码登录当前环境。' }}{% endraw %}
|
||||
</div>
|
||||
@@ -575,6 +575,10 @@
|
||||
logged_in: false,
|
||||
active: false,
|
||||
status: 'idle',
|
||||
provider_name: '',
|
||||
provider_stage: 'bootstrap',
|
||||
connection_ready: false,
|
||||
login_required: false,
|
||||
status_text: '尚未进入扫码登录流程',
|
||||
current: {},
|
||||
history: [],
|
||||
@@ -622,8 +626,23 @@
|
||||
return !this.loginQrDialog.logged_in;
|
||||
},
|
||||
loginQrStatusTone() {
|
||||
if (this.loginQrDialog.provider_stage === 'connection_pending') {
|
||||
return 'soft';
|
||||
}
|
||||
if (this.loginQrDialog.provider_stage === 'login_required') {
|
||||
return 'danger';
|
||||
}
|
||||
return this.mapLoginQrTone(this.loginQrDialog.status);
|
||||
},
|
||||
loginQrBannerTitle() {
|
||||
if (this.loginQrDialog.provider_stage === 'connection_pending') {
|
||||
return '当前 864 服务连接尚未建立,首页已进入登录准备模式';
|
||||
}
|
||||
if (this.loginQrDialog.provider_stage === 'login_required') {
|
||||
return '当前微信登录态已失效,首页已进入重新登录模式';
|
||||
}
|
||||
return '当前微信未登录,首页已进入扫码引导模式';
|
||||
},
|
||||
loginQrStatusText() {
|
||||
const toneMap = {
|
||||
waiting: '等待扫码',
|
||||
@@ -633,9 +652,22 @@
|
||||
idle: '等待登录流程',
|
||||
unavailable: '状态暂不可用'
|
||||
};
|
||||
if (this.loginQrDialog.provider_stage === 'connection_pending') {
|
||||
return '等待建立连接';
|
||||
}
|
||||
if (this.loginQrDialog.provider_stage === 'login_required') {
|
||||
return '需要重新登录';
|
||||
}
|
||||
return toneMap[this.loginQrDialog.status] || '等待登录流程';
|
||||
},
|
||||
loginQrSourceText() {
|
||||
const providerName = String(this.loginQrDialog.provider_name || '').toLowerCase();
|
||||
if (providerName === 'server_864' || providerName === '864') {
|
||||
if (this.loginQrDialog.provider_stage === 'connection_pending') {
|
||||
return '864 服务端准备中';
|
||||
}
|
||||
return '864 服务端登录';
|
||||
}
|
||||
const source = this.loginQrCurrent.login_source;
|
||||
if (source === 'awaken') {
|
||||
return '缓存唤醒登录';
|
||||
@@ -652,6 +684,12 @@
|
||||
if (this.loginQrDialog.status === 'expired') {
|
||||
return '已过期,等待刷新';
|
||||
}
|
||||
if (this.loginQrDialog.provider_stage === 'connection_pending') {
|
||||
return '等待服务端准备';
|
||||
}
|
||||
if (this.loginQrDialog.provider_stage === 'login_required' && !this.loginQrCurrent.uuid) {
|
||||
return '等待新二维码';
|
||||
}
|
||||
if (!this.loginQrCurrent.uuid) {
|
||||
return '等待生成';
|
||||
}
|
||||
@@ -866,6 +904,10 @@
|
||||
this.loginQrCountdownSeconds = 0;
|
||||
return;
|
||||
}
|
||||
if (this.loginQrDialog.provider_stage === 'connection_pending') {
|
||||
this.loginQrCountdownSeconds = 0;
|
||||
return;
|
||||
}
|
||||
if (this.loginQrCountdownSeconds > 0) {
|
||||
this.loginQrCountdownSeconds -= 1;
|
||||
return;
|
||||
|
||||
@@ -33,12 +33,14 @@
|
||||
- 已在 [robot.py](/d:/learn/abot/robot.py:1) 中为 864 增加登录态硬隔离,默认不再回读 855 的历史 `config.toml` 与动态字段
|
||||
- 已基于真实 864 服务联调修正首批路由差异:二维码返回结构、联系人详情路由、群公告路由、二维码有效期倒计时同步
|
||||
- 已确认 864 的消息发送类接口在“尚未建立连接对象”时会优先返回“该链接不存在”,这与登录态接口返回“需要重新登录”属于不同阶段
|
||||
- 已开始把 864 的“等待服务端准备 / 需要重新登录 / 等待扫码”三态显式回传给 Dashboard,避免首页把不同问题混成一类未登录提示
|
||||
|
||||
当前尚未完成的关键项:
|
||||
|
||||
- 855 provider 仍需完成一轮“当前项目实际依赖接口”的可上线回归验证
|
||||
- 855 provider 仍需继续梳理“项目真实使用到的接口覆盖面”,确认是否还有遗漏能力未纳入 provider 目录
|
||||
- 864 provider 仍需完成真机联调,尤其是消息字段归一化、视频发送、名片发送等增强能力
|
||||
- Dashboard 仍需继续做少量多 provider 登录文案收敛,但登录状态结构已具备扩展空间
|
||||
|
||||
因此,当前状态可以定义为:
|
||||
|
||||
@@ -440,6 +442,7 @@ wechat_ipad/
|
||||
- 已实现 HTTP 轮询消息同步
|
||||
- 已实现联系人、群资料、当前账号资料、朋友圈基础接口
|
||||
- 已保留与 855 尽量一致的对外方法名,便于 `Robot` 无感切换
|
||||
- 已补一层登录阶段探测,首页可以直接区分“等待服务端准备”“需要重新登录”“等待扫码”
|
||||
|
||||
当前仍待补强的范围:
|
||||
|
||||
|
||||
41
robot.py
41
robot.py
@@ -446,6 +446,10 @@ class Robot:
|
||||
"logged_in": False,
|
||||
"active": False,
|
||||
"status": "idle",
|
||||
"provider_name": "",
|
||||
"provider_stage": "bootstrap",
|
||||
"connection_ready": False,
|
||||
"login_required": False,
|
||||
"status_text": "尚未进入扫码登录流程",
|
||||
"current": {},
|
||||
"history": [],
|
||||
@@ -485,10 +489,21 @@ class Robot:
|
||||
with self._ipad_login_qr_lock:
|
||||
login_state_flag = bool(self.ipad_login_qr_state.get("logged_in", False))
|
||||
qr_status = str(self.ipad_login_qr_state.get("status", "idle") or "idle")
|
||||
provider_name = str(
|
||||
self.ipad_login_qr_state.get("provider_name", self.ipad_config.get("server_type", "") if self.ipad_config else "")
|
||||
or ""
|
||||
).strip()
|
||||
provider_stage = str(self.ipad_login_qr_state.get("provider_stage", "bootstrap") or "bootstrap").strip()
|
||||
connection_ready = bool(self.ipad_login_qr_state.get("connection_ready", False))
|
||||
login_required = bool(self.ipad_login_qr_state.get("login_required", False))
|
||||
state = {
|
||||
"logged_in": bool(self.wxid) or login_state_flag or qr_status in {"confirmed", "logged_in"},
|
||||
"active": bool(self.ipad_login_qr_state.get("active", False)),
|
||||
"status": qr_status,
|
||||
"provider_name": provider_name,
|
||||
"provider_stage": provider_stage,
|
||||
"connection_ready": connection_ready,
|
||||
"login_required": login_required,
|
||||
"status_text": str(
|
||||
self.ipad_login_qr_state.get("status_text", "尚未进入扫码登录流程") or "尚未进入扫码登录流程"
|
||||
),
|
||||
@@ -520,6 +535,13 @@ class Robot:
|
||||
status = str((payload or {}).get("status", "waiting") or "waiting").strip() or "waiting"
|
||||
status_text = str((payload or {}).get("status_text", "等待扫码登录") or "等待扫码登录").strip()
|
||||
login_source = str((payload or {}).get("login_source", "fresh_qr") or "fresh_qr").strip()
|
||||
provider_name = str(
|
||||
(payload or {}).get("provider_name", self.ipad_config.get("server_type", "") if self.ipad_config else "")
|
||||
or ""
|
||||
).strip()
|
||||
provider_stage = str((payload or {}).get("provider_stage", "waiting_scan") or "waiting_scan").strip()
|
||||
connection_ready = bool((payload or {}).get("connection_ready", False))
|
||||
login_required = bool((payload or {}).get("login_required", True))
|
||||
expires_in = (payload or {}).get("expires_in")
|
||||
expires_in = None if expires_in in (None, "") else max(0, int(expires_in))
|
||||
current_record = {
|
||||
@@ -530,6 +552,10 @@ class Robot:
|
||||
"status": status,
|
||||
"status_text": status_text,
|
||||
"login_source": login_source,
|
||||
"provider_name": provider_name,
|
||||
"provider_stage": provider_stage,
|
||||
"connection_ready": connection_ready,
|
||||
"login_required": login_required,
|
||||
"updated_at": now_ts,
|
||||
"updated_at_text": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(now_ts)),
|
||||
}
|
||||
@@ -559,6 +585,10 @@ class Robot:
|
||||
"logged_in": False,
|
||||
"active": status != "confirmed",
|
||||
"status": status,
|
||||
"provider_name": provider_name,
|
||||
"provider_stage": provider_stage,
|
||||
"connection_ready": connection_ready,
|
||||
"login_required": login_required,
|
||||
"status_text": status_text,
|
||||
"current": current_record,
|
||||
"history": history_records,
|
||||
@@ -571,6 +601,13 @@ class Robot:
|
||||
status = str((payload or {}).get("status", "idle") or "idle").strip() or "idle"
|
||||
status_text = str((payload or {}).get("status_text", "登录流程已结束") or "登录流程已结束").strip()
|
||||
cleared_uuid = str((payload or {}).get("uuid", "") or "").strip()
|
||||
provider_name = str(
|
||||
(payload or {}).get("provider_name", self.ipad_config.get("server_type", "") if self.ipad_config else "")
|
||||
or ""
|
||||
).strip()
|
||||
provider_stage = str((payload or {}).get("provider_stage", "logged_in") or "logged_in").strip()
|
||||
connection_ready = bool((payload or {}).get("connection_ready", True))
|
||||
login_required = bool((payload or {}).get("login_required", False))
|
||||
|
||||
with self._ipad_login_qr_lock:
|
||||
history_records = list(self.ipad_login_qr_state.get("history", []) or [])
|
||||
@@ -586,6 +623,10 @@ class Robot:
|
||||
"logged_in": status in {"confirmed", "logged_in"} or bool(self.wxid),
|
||||
"active": False,
|
||||
"status": status,
|
||||
"provider_name": provider_name,
|
||||
"provider_stage": provider_stage,
|
||||
"connection_ready": connection_ready,
|
||||
"login_required": login_required,
|
||||
"status_text": status_text,
|
||||
"current": {},
|
||||
"history": history_records[:3],
|
||||
|
||||
@@ -103,12 +103,31 @@ class Server864RuntimeMixin:
|
||||
await self._refresh_identity_from_profile(logger=logger)
|
||||
await self._safe_callback(
|
||||
on_login_qr_cleared,
|
||||
{"status": "logged_in", "status_text": "已检测到现有登录态"},
|
||||
{
|
||||
"status": "logged_in",
|
||||
"status_text": "已检测到现有登录态",
|
||||
"provider_name": "server_864",
|
||||
"provider_stage": "logged_in",
|
||||
"connection_ready": True,
|
||||
"login_required": False,
|
||||
},
|
||||
logger=logger,
|
||||
callback_name="on_login_qr_cleared",
|
||||
)
|
||||
return
|
||||
|
||||
# 先探测一次 864 当前阶段,让 Dashboard 能直接区分“等服务端准备”和“需要扫码”:
|
||||
# 1. 864 的未登录态并不只有一种,部分场景其实是远端连接对象还没建好;
|
||||
# 2. 若首页始终只显示“未登录”,运维很难判断下一步是等服务端还是去扫码;
|
||||
# 3. 这里把差异压缩成轻量阶段字段,供前端直接展示,不改动核心登录流程。
|
||||
login_stage_snapshot = await self._probe_login_stage()
|
||||
await self._safe_callback(
|
||||
on_login_qr_update,
|
||||
login_stage_snapshot,
|
||||
logger=logger,
|
||||
callback_name="on_login_qr_update",
|
||||
)
|
||||
|
||||
uuid, url = await self.get_qr_code(print_qr=True)
|
||||
scan_url = f"http://weixin.qq.com/x/{uuid}" if uuid else ""
|
||||
await self._safe_callback(
|
||||
@@ -121,6 +140,10 @@ class Server864RuntimeMixin:
|
||||
"status": "waiting",
|
||||
"status_text": "等待扫码登录",
|
||||
"login_source": "fresh_qr",
|
||||
"provider_name": "server_864",
|
||||
"provider_stage": "waiting_scan",
|
||||
"connection_ready": False,
|
||||
"login_required": True,
|
||||
},
|
||||
logger=logger,
|
||||
callback_name="on_login_qr_update",
|
||||
@@ -131,7 +154,15 @@ class Server864RuntimeMixin:
|
||||
if is_logged_in:
|
||||
await self._safe_callback(
|
||||
on_login_qr_cleared,
|
||||
{"status": "confirmed", "status_text": "扫码登录成功", "uuid": uuid},
|
||||
{
|
||||
"status": "confirmed",
|
||||
"status_text": "扫码登录成功",
|
||||
"uuid": uuid,
|
||||
"provider_name": "server_864",
|
||||
"provider_stage": "logged_in",
|
||||
"connection_ready": True,
|
||||
"login_required": False,
|
||||
},
|
||||
logger=logger,
|
||||
callback_name="on_login_qr_cleared",
|
||||
)
|
||||
@@ -158,6 +189,10 @@ class Server864RuntimeMixin:
|
||||
"status": "waiting",
|
||||
"status_text": str(login_status.get("msg") or login_status.get("loginState") or "等待扫码登录"),
|
||||
"login_source": "fresh_qr",
|
||||
"provider_name": "server_864",
|
||||
"provider_stage": "waiting_scan" if uuid else "login_required",
|
||||
"connection_ready": False,
|
||||
"login_required": True,
|
||||
},
|
||||
logger=logger,
|
||||
callback_name="on_login_qr_update",
|
||||
@@ -180,6 +215,10 @@ class Server864RuntimeMixin:
|
||||
"status": "waiting",
|
||||
"status_text": "二维码已刷新,等待扫码登录",
|
||||
"login_source": "refresh_qr",
|
||||
"provider_name": "server_864",
|
||||
"provider_stage": "waiting_scan",
|
||||
"connection_ready": False,
|
||||
"login_required": True,
|
||||
},
|
||||
logger=logger,
|
||||
callback_name="on_login_qr_update",
|
||||
@@ -196,6 +235,64 @@ class Server864RuntimeMixin:
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
async def _probe_login_stage(self) -> dict[str, Any]:
|
||||
"""探测 864 当前登录阶段,供 Dashboard 展示更准确的运维状态。"""
|
||||
default_payload = {
|
||||
"status": "waiting",
|
||||
"status_text": "等待扫码登录",
|
||||
"login_source": "fresh_qr",
|
||||
"provider_name": "server_864",
|
||||
"provider_stage": "login_required",
|
||||
"connection_ready": False,
|
||||
"login_required": True,
|
||||
}
|
||||
try:
|
||||
login_status = await self.get_login_status(auto_login=False)
|
||||
except Exception as e:
|
||||
error_message = str(e).strip()
|
||||
if "该链接不存在" in error_message:
|
||||
return {
|
||||
**default_payload,
|
||||
"status_text": "864 服务端连接尚未建立,等待创建登录连接",
|
||||
"provider_stage": "connection_pending",
|
||||
"login_required": False,
|
||||
}
|
||||
if "重新登录" in error_message or "未登录" in error_message:
|
||||
return {
|
||||
**default_payload,
|
||||
"status_text": error_message or "当前登录态已失效,等待重新扫码登录",
|
||||
}
|
||||
return {
|
||||
**default_payload,
|
||||
"status": "unavailable",
|
||||
"status_text": error_message or "864 登录状态暂不可用",
|
||||
"provider_stage": "status_unavailable",
|
||||
}
|
||||
|
||||
if isinstance(login_status, dict):
|
||||
login_message = str(
|
||||
login_status.get("msg")
|
||||
or login_status.get("message")
|
||||
or login_status.get("loginState")
|
||||
or ""
|
||||
).strip()
|
||||
if "在线" in login_message or str(login_status.get("loginState", "")).strip().lower() == "online":
|
||||
return {
|
||||
"status": "logged_in",
|
||||
"status_text": "已检测到现有登录态",
|
||||
"login_source": "runtime_state",
|
||||
"provider_name": "server_864",
|
||||
"provider_stage": "logged_in",
|
||||
"connection_ready": True,
|
||||
"login_required": False,
|
||||
}
|
||||
if "重新登录" in login_message or "未登录" in login_message:
|
||||
return {
|
||||
**default_payload,
|
||||
"status_text": login_message or "当前登录态已失效,等待重新扫码登录",
|
||||
}
|
||||
return default_payload
|
||||
|
||||
async def _wait_init_ready(self, *, logger) -> None:
|
||||
"""等待 864 server 侧初始化完成。"""
|
||||
for _ in range(30):
|
||||
|
||||
Reference in New Issue
Block a user