From 86459a1bd096a0a9006d9e9e113326707a8cef00 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Thu, 6 Aug 2026 18:28:06 +0800 Subject: [PATCH] =?UTF-8?q?fix(douyu):=20=E5=B7=B2=E7=BB=91=E5=AE=9A?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7=E7=94=9F=E6=88=90=E4=BA=8C=E7=BB=B4=E7=A0=81?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E7=AB=8B=E5=8D=B3=E6=88=90=E5=8A=9F,=20?= =?UTF-8?q?=E6=AD=A3=E5=B8=B8=E7=AD=89=E5=BE=85=E6=89=AB=E7=A0=81=E6=8D=A2?= =?UTF-8?q?=E7=BB=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 后端: get_xpd_bind_qr 生成二维码前记录绑定前状态(before_bound/ before_role_name); 轮询判断改为 —— 未绑定: 检测到 bind_role=1 成功; 已绑定(换绑): 角色名变化才算成功, 角色不变继续等待 - 前端: 弹窗保留二维码与角色信息; 轮询期间显示"当前绑定: 原角色", 换绑成功显示新角色; 确认绑定维持手动(小程序内人工确认) --- web/backend/services/douyu_runner.py | 24 ++++++++-- web/frontend/src/pages/DouyuTasksPage.tsx | 54 +++++++++++++---------- 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/web/backend/services/douyu_runner.py b/web/backend/services/douyu_runner.py index 92afbdf..d4f8da9 100644 --- a/web/backend/services/douyu_runner.py +++ b/web/backend/services/douyu_runner.py @@ -1086,7 +1086,7 @@ class DouyuBatchRunner: cookie: str, config: dict, ): - """生成和平小店绑定二维码并轮询等待微信扫码绑定完成。""" + """生成和平小店绑定二维码并轮询等待微信扫码绑定/换绑完成。""" client = self._client(cookie) act_alias = str(config.get("xpd_act_alias") or "").strip() if not act_alias: @@ -1096,6 +1096,16 @@ class DouyuBatchRunner: account.xpd_bind_status = "xpd_bind_qr_ready" account.updated_at = datetime.now(timezone.utc) db.commit() + # 记录绑定前状态:已绑定账号生成二维码后必须等扫码换绑,不能立即成功 + try: + before = client.xpd_bind_info(act_alias=act_alias) + result["before_bound"] = bool(before.get("bind_role")) + result["before_role_name"] = str(before.get("role_name") or "") + result["before_area_name"] = str(before.get("area_name") or "") + result["before_plat_name"] = str(before.get("plat_name") or "") + except Exception: + result["before_bound"] = False + result["before_role_name"] = "" result["bind_polling"] = True self._update_task_progress( db, @@ -1134,7 +1144,13 @@ class DouyuBatchRunner: act_alias: str, result: dict, ) -> bool: - """轮询 bindInfo,检测到绑定角色即回写账号并返回 True。""" + """轮询 bindInfo 等待绑定/换绑完成。 + + - 绑定前未绑定:检测到 bind_role=1 即绑定成功 + - 绑定前已绑定(换绑):检测到角色名变化才算换绑成功,角色不变继续等 + """ + before_bound = bool(result.get("before_bound")) + before_role_name = str(result.get("before_role_name") or "") deadline = time.monotonic() + DOUYU_XPD_BIND_POLL_SECONDS poll_count = 0 while not self._stop.is_set() and time.monotonic() <= deadline: @@ -1144,7 +1160,9 @@ class DouyuBatchRunner: result["bind_poll_count"] = poll_count result["bind_polling"] = True role_name = str(info.get("role_name") or "") - if info.get("bind_role") and role_name: + bound_now = bool(info.get("bind_role")) + changed = before_bound and bool(role_name) and role_name != before_role_name + if (not before_bound and bound_now and role_name) or changed: result.update({key: value for key, value in info.items() if key != "raw"}) result["bind_polling"] = False result["xpd_bound"] = True diff --git a/web/frontend/src/pages/DouyuTasksPage.tsx b/web/frontend/src/pages/DouyuTasksPage.tsx index 165be49..591b0ee 100644 --- a/web/frontend/src/pages/DouyuTasksPage.tsx +++ b/web/frontend/src/pages/DouyuTasksPage.tsx @@ -1064,30 +1064,36 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind }) const qrRoleName = resultText(qrRoleSourceResult, 'pending_role_name') || resultText(qrRoleSourceResult, 'role_name'); const qrAreaName = resultText(qrRoleSourceResult, 'pending_area_name') || resultText(qrRoleSourceResult, 'area_name'); const qrPlatName = resultText(qrRoleSourceResult, 'pending_plat_name') || resultText(qrRoleSourceResult, 'plat_name'); - const qrCurrentRoleName = qrQueryRoleName - || resultText(qrResult, 'current_role_name') - || ( - resultFlag(qrResult, 'is_bound_act') - ? resultText(qrResult, 'role_name') - : '' - ) - || (qrQueryIsBoundAct ? qrQueryRoleName : ''); - const qrCurrentAreaName = resultText(qrQueryResult, 'area_name') - || resultText(qrResult, 'current_area_name') - || ( - resultFlag(qrResult, 'is_bound_act') - ? resultText(qrResult, 'area_name') - : '' - ) - || (qrQueryIsBoundAct ? resultText(qrQueryResult, 'area_name') : ''); - const qrCurrentPlatName = resultText(qrQueryResult, 'plat_name') - || resultText(qrResult, 'current_plat_name') - || ( - resultFlag(qrResult, 'is_bound_act') - ? resultText(qrResult, 'plat_name') - : '' - ) - || (qrQueryIsBoundAct ? resultText(qrQueryResult, 'plat_name') : ''); + const qrCurrentRoleName = isXpdBindTask + ? resultText(qrResult, 'before_role_name') + : (qrQueryRoleName + || resultText(qrResult, 'current_role_name') + || ( + resultFlag(qrResult, 'is_bound_act') + ? resultText(qrResult, 'role_name') + : '' + ) + || (qrQueryIsBoundAct ? qrQueryRoleName : '')); + const qrCurrentAreaName = isXpdBindTask + ? resultText(qrResult, 'before_area_name') + : (resultText(qrQueryResult, 'area_name') + || resultText(qrResult, 'current_area_name') + || ( + resultFlag(qrResult, 'is_bound_act') + ? resultText(qrResult, 'area_name') + : '' + ) + || (qrQueryIsBoundAct ? resultText(qrQueryResult, 'area_name') : '')); + const qrCurrentPlatName = isXpdBindTask + ? resultText(qrResult, 'before_plat_name') + : (resultText(qrQueryResult, 'plat_name') + || resultText(qrResult, 'current_plat_name') + || ( + resultFlag(qrResult, 'is_bound_act') + ? resultText(qrResult, 'plat_name') + : '' + ) + || (qrQueryIsBoundAct ? resultText(qrQueryResult, 'plat_name') : '')); const qrRoleLine = qrBindReady ? [qrPlatName, qrAreaName, qrRoleName].filter(Boolean).join(' - ') : '';