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(' - ') : '';