import { useEffect, useState } from "react"; import { getWechatMP, saveWechatMP, GATEWAY, type WechatMPConfig } from "../api"; // 运维 · 登录设置:微信公众号扫码登录(带参二维码 + 关注/扫码事件)。 // AppSecret 明文回显(单管理员后台,方便核对/复制;密文仍加密入库)。 export function LoginConfigPage() { const [cfg, setCfg] = useState(null); const [appid, setAppid] = useState(""); const [token, setToken] = useState(""); const [secret, setSecret] = useState(""); // 留空=沿用已存 const [busy, setBusy] = useState(false); const [err, setErr] = useState(""); const [ok, setOk] = useState(false); useEffect(() => { getWechatMP() .then((c) => { setCfg(c); setAppid(c.appid); setToken(c.token); setSecret(c.app_secret); }) .catch((e) => setErr((e as Error).message)); }, []); const save = async () => { if (busy) return; setBusy(true); setErr(""); setOk(false); try { const r = await saveWechatMP({ appid: appid.trim(), app_secret: secret, token: token.trim() }); setCfg((c) => (c ? { ...c, appid: appid.trim(), token: token.trim(), app_secret: secret, enabled: r.enabled } : c)); setOk(true); } catch (e) { setErr((e as Error).message); } finally { setBusy(false); } }; // 回调 URL 用当前后端地址推断(生产 GATEWAY 为空串=同源,显示成本域名) const origin = GATEWAY || (typeof window !== "undefined" ? window.location.origin : ""); const callbackURL = origin.replace(/:\d+$/, "") + "/wx/mp/callback"; return (

登录设置 · 微信扫码

公众号扫码登录(登录即引导关注)。AppSecret 加密入库、后台明文可见,随时可换

公众号配置

{cfg?.enabled ? ( 已启用 ) : ( 未启用(三项齐全才生效) )}
{err &&

{err}

} {ok &&

已保存

}
{/* 配置清单:把「必须在公众平台做什么」写在眼前,省得来回翻文档 */}

还需在微信公众平台「服务器配置」里配置

  1. 服务器地址(URL) 填 {callbackURL}
  2. 令牌(Token) 填与上面完全一致的那串
  3. 消息加解密方式选 明文模式(本服务按明文处理,选其它会验签失败)
  4. 「IP 白名单」加上服务器出网的公网 IP(否则拉取 access_token 报 40164,二维码建不出来)
  5. 保存服务器配置时微信会即时回调本服务验证——需先部署好本页配置再去点提交
); }