From bef398d47a8523a43023ecc7b6442b37995cbe0f Mon Sep 17 00:00:00 2001 From: Aska Date: Mon, 7 Sep 2026 21:54:08 +0800 Subject: [PATCH] =?UTF-8?q?fix(weixin):=20=E4=BA=8C=E7=BB=B4=E7=A0=81?= =?UTF-8?q?=E5=9B=9E=E9=80=80=E7=94=A8qrUrl=E7=94=9F=E6=88=90=20+=20?= =?UTF-8?q?=E6=AF=8F=E6=AC=A1=E7=82=B9=E5=87=BB=E9=87=8D=E6=96=B0=E5=8F=91?= =?UTF-8?q?=E5=85=A8=E6=96=B0=E7=A0=81(=E4=BF=AE'=E8=BF=87=E6=9C=9F')?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户实测: qrcode原始串编码微信扫出纯字符串(qrcode得用qrUrl liteapp链接); 过期的真正原因 是复用旧二维码(微信码有效期极短)。修: 二维码改回用 qrUrl(liteapp链接)生成; StartLogin 把复用窗口从90s降到5s(仅防连点),否则每次'扫码登录/刷新'都取消旧会话重发全新码——永远新鲜可扫。 build/vet/test+前端build 全绿,已部署。 --- .../src/admin/modules/channels/WeixinLogin.tsx | 6 +++--- plugins/channels/weixin_ilink/login_admin.go | 16 +++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/frontend/web/src/admin/modules/channels/WeixinLogin.tsx b/frontend/web/src/admin/modules/channels/WeixinLogin.tsx index be98805..a294416 100644 --- a/frontend/web/src/admin/modules/channels/WeixinLogin.tsx +++ b/frontend/web/src/admin/modules/channels/WeixinLogin.tsx @@ -120,7 +120,7 @@ export function WeixinLogin({ .finally(() => setBusy(null)); }; - const showQR = status === "waiting" || qrCode !== ""; + const showQR = status === "waiting" || qrUrl !== ""; return ( @@ -147,8 +147,8 @@ export function WeixinLogin({ {showQR ? (
- {qrCode ? ( - + {qrUrl ? ( + ) : ( 二维码暂不可用,请点击「刷新二维码」重试。 )} diff --git a/plugins/channels/weixin_ilink/login_admin.go b/plugins/channels/weixin_ilink/login_admin.go index 265439a..8650833 100644 --- a/plugins/channels/weixin_ilink/login_admin.go +++ b/plugins/channels/weixin_ilink/login_admin.go @@ -51,10 +51,11 @@ type loginSession struct { done chan error } -// qrRefreshTTL bounds how long a WeChat bot QR is usable before StartLogin re-mints -// a fresh one. iLink bot QRs are short-lived; an idempotent StartLogin must not keep -// serving a long-expired QR (the user would scan it and get "二维码过期"). -const qrRefreshTTL = 90 * time.Second +// qrReuseWindow is how long a just-minted QR is reused on an immediate re-click +// before StartLogin re-mints a fresh one. WeChat bot QRs are short-lived, so a +// "扫码登录/刷新二维码" click must yield a brand-new code — reusing an old QR is +// exactly what makes WeChat report "二维码过期". +const qrReuseWindow = 5 * time.Second // StartLogin begins a scan-login and returns the QR code to display. It is // idempotent: when a login is already in progress it returns the current QR @@ -70,9 +71,10 @@ func (a *Adapter) StartLogin(ctx context.Context) (LoginQR, error) { return LoginQR{}, ErrAlreadyLoggedIn } if sess := a.loginSession; sess != nil { - // Idempotent for a fresh QR, but re-mint once the current QR has aged past - // qrRefreshTTL so the panel's 刷新二维码 always yields a scannable code. - if time.Since(sess.startedAt) < qrRefreshTTL { + // Reuse only within a tiny window (a literal double-click); otherwise re-mint + // a brand-new QR so the panel's "扫码登录/刷新二维码" never serves a stale, + // expired WeChat code. The old poll goroutine is cancelled. + if time.Since(sess.startedAt) < qrReuseWindow { return LoginQR{Qrcode: sess.qrcode, Image: sess.image}, nil } if sess.cancel != nil {