fix(weixin): 二维码回退用qrUrl生成 + 每次点击重新发全新码(修'过期')
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

用户实测: qrcode原始串编码微信扫出纯字符串(qrcode得用qrUrl liteapp链接); 过期的真正原因
是复用旧二维码(微信码有效期极短)。修: 二维码改回用 qrUrl(liteapp链接)生成; StartLogin
把复用窗口从90s降到5s(仅防连点),否则每次'扫码登录/刷新'都取消旧会话重发全新码——永远新鲜可扫。
build/vet/test+前端build 全绿,已部署。
This commit is contained in:
Aska committed 2026-09-07 21:54:08 +08:00
1 parent b6b258498c
commit bef398d47a
2 files changed
+12 -10

No files matched your search

@@ -120,7 +120,7 @@ export function WeixinLogin({
.finally(() => setBusy(null));
};
const showQR = status === "waiting" || qrCode !== "";
const showQR = status === "waiting" || qrUrl !== "";
return (
<Surface gap="sm" className="space-y-3">
@@ -147,8 +147,8 @@ export function WeixinLogin({
{showQR ? (
<div className="space-y-2">
{qrCode ? (
<QrImage value={qrCode} />
{qrUrl ? (
<QrImage value={qrUrl} />
) : (
<Notice tone="warn">二维码暂不可用,请点击「刷新二维码」重试。</Notice>
)}
+9 -7
View File
@@ -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 {