feat: 微信登陆逻辑调整

This commit is contained in:
zdl
2025-10-28 19:04:58 +08:00
parent 356f865f09
commit b221c2669c
2 changed files with 73 additions and 36 deletions

View File

@@ -15,6 +15,8 @@ import { FaQrcode } from "react-icons/fa";
import { FiAlertCircle } from "react-icons/fi"; import { FiAlertCircle } from "react-icons/fi";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { authService, WECHAT_STATUS, STATUS_MESSAGES } from "../../services/authService"; import { authService, WECHAT_STATUS, STATUS_MESSAGES } from "../../services/authService";
import { useAuthModal } from "../../contexts/AuthModalContext";
import { useAuth } from "../../contexts/AuthContext";
import { logger } from "../../utils/logger"; import { logger } from "../../utils/logger";
// 配置常量 // 配置常量
@@ -45,6 +47,10 @@ const getStatusText = (status) => {
}; };
export default function WechatRegister() { export default function WechatRegister() {
// 获取关闭弹窗方法
const { closeModal } = useAuthModal();
const { refreshSession } = useAuth();
// 状态管理 // 状态管理
const [wechatAuthUrl, setWechatAuthUrl] = useState(""); const [wechatAuthUrl, setWechatAuthUrl] = useState("");
const [wechatSessionId, setWechatSessionId] = useState(""); const [wechatSessionId, setWechatSessionId] = useState("");
@@ -58,6 +64,7 @@ export default function WechatRegister() {
const timeoutRef = useRef(null); const timeoutRef = useRef(null);
const isMountedRef = useRef(true); // 追踪组件挂载状态 const isMountedRef = useRef(true); // 追踪组件挂载状态
const containerRef = useRef(null); // 容器DOM引用 const containerRef = useRef(null); // 容器DOM引用
const sessionIdRef = useRef(null); // 存储最新的 sessionId避免闭包陷阱
const navigate = useNavigate(); const navigate = useNavigate();
const toast = useToast(); const toast = useToast();
@@ -90,6 +97,7 @@ export default function WechatRegister() {
/** /**
* 清理所有定时器 * 清理所有定时器
* 注意:不清理 sessionIdRef因为 startPolling 时也会调用此函数
*/ */
const clearTimers = useCallback(() => { const clearTimers = useCallback(() => {
if (pollIntervalRef.current) { if (pollIntervalRef.current) {
@@ -124,14 +132,14 @@ export default function WechatRegister() {
} }
showSuccess( showSuccess(
status === WECHAT_STATUS.LOGIN_SUCCESS ? "登录成功" : "注册成功", status === WECHAT_STATUS.LOGIN_SUCCESS ? "登录成功" : "欢迎回来!"
"正在跳转..."
); );
// 延迟跳转,让用户看到成功提示 // 刷新 AuthContext 状态
setTimeout(() => { await refreshSession();
navigate("/home");
}, 1000); // 关闭认证弹窗,留在当前页面
closeModal();
} else { } else {
throw new Error(response?.error || '登录失败'); throw new Error(response?.error || '登录失败');
} }
@@ -139,17 +147,27 @@ export default function WechatRegister() {
logger.error('WechatRegister', 'handleLoginSuccess', error, { sessionId }); logger.error('WechatRegister', 'handleLoginSuccess', error, { sessionId });
showError("登录失败", error.message || "请重试"); showError("登录失败", error.message || "请重试");
} }
}, [navigate, showSuccess, showError]); }, [showSuccess, showError, closeModal, refreshSession]);
/** /**
* 检查微信扫码状态 * 检查微信扫码状态
* 使用 sessionIdRef.current 避免闭包陷阱
*/ */
const checkWechatStatus = useCallback(async () => { const checkWechatStatus = useCallback(async () => {
// 检查组件是否已卸载 // 检查组件是否已卸载,使用 ref 获取最新的 sessionId
if (!isMountedRef.current || !wechatSessionId) return; if (!isMountedRef.current || !sessionIdRef.current) {
logger.debug('WechatRegister', 'checkWechatStatus 跳过', {
isMounted: isMountedRef.current,
hasSessionId: !!sessionIdRef.current
});
return;
}
const currentSessionId = sessionIdRef.current;
logger.debug('WechatRegister', '检查微信状态', { sessionId: currentSessionId });
try { try {
const response = await authService.checkWechatStatus(wechatSessionId); const response = await authService.checkWechatStatus(currentSessionId);
// 安全检查:确保 response 存在且包含 status // 安全检查:确保 response 存在且包含 status
if (!response || typeof response.status === 'undefined') { if (!response || typeof response.status === 'undefined') {
@@ -158,6 +176,7 @@ export default function WechatRegister() {
} }
const { status } = response; const { status } = response;
logger.debug('WechatRegister', '微信状态', { status });
// 组件卸载后不再更新状态 // 组件卸载后不再更新状态
if (!isMountedRef.current) return; if (!isMountedRef.current) return;
@@ -167,23 +186,14 @@ export default function WechatRegister() {
// 处理成功状态 // 处理成功状态
if (status === WECHAT_STATUS.LOGIN_SUCCESS || status === WECHAT_STATUS.REGISTER_SUCCESS) { if (status === WECHAT_STATUS.LOGIN_SUCCESS || status === WECHAT_STATUS.REGISTER_SUCCESS) {
clearTimers(); // 停止轮询 clearTimers(); // 停止轮询
sessionIdRef.current = null; // 清理 sessionId
// 显示"扫码成功,登录中"提示 await handleLoginSuccess(currentSessionId, status);
if (isMountedRef.current) {
toast({
title: "扫码成功",
description: "正在登录,请稍候...",
status: "info",
duration: 2000,
isClosable: false,
});
}
await handleLoginSuccess(wechatSessionId, status);
} }
// 处理过期状态 // 处理过期状态
else if (status === WECHAT_STATUS.EXPIRED) { else if (status === WECHAT_STATUS.EXPIRED) {
clearTimers(); clearTimers();
sessionIdRef.current = null; // 清理 sessionId
if (isMountedRef.current) { if (isMountedRef.current) {
toast({ toast({
title: "授权已过期", title: "授权已过期",
@@ -195,11 +205,12 @@ export default function WechatRegister() {
} }
} }
} catch (error) { } catch (error) {
logger.error('WechatRegister', 'checkWechatStatus', error, { sessionId: wechatSessionId }); logger.error('WechatRegister', 'checkWechatStatus', error, { sessionId: currentSessionId });
// 轮询过程中的错误不显示给用户,避免频繁提示 // 轮询过程中的错误不显示给用户,避免频繁提示
// 但如果错误持续发生,停止轮询避免无限重试 // 但如果错误持续发生,停止轮询避免无限重试
if (error.message.includes('网络连接失败')) { if (error.message.includes('网络连接失败')) {
clearTimers(); clearTimers();
sessionIdRef.current = null; // 清理 sessionId
if (isMountedRef.current) { if (isMountedRef.current) {
toast({ toast({
title: "网络连接失败", title: "网络连接失败",
@@ -211,12 +222,17 @@ export default function WechatRegister() {
} }
} }
} }
}, [wechatSessionId, handleLoginSuccess, clearTimers, toast]); }, [handleLoginSuccess, clearTimers, toast]);
/** /**
* 启动轮询 * 启动轮询
*/ */
const startPolling = useCallback(() => { const startPolling = useCallback(() => {
logger.debug('WechatRegister', '启动轮询', {
sessionId: sessionIdRef.current,
interval: POLL_INTERVAL
});
// 清理旧的定时器 // 清理旧的定时器
clearTimers(); clearTimers();
@@ -227,7 +243,9 @@ export default function WechatRegister() {
// 设置超时 // 设置超时
timeoutRef.current = setTimeout(() => { timeoutRef.current = setTimeout(() => {
logger.debug('WechatRegister', '二维码超时');
clearTimers(); clearTimers();
sessionIdRef.current = null; // 清理 sessionId
setWechatStatus(WECHAT_STATUS.EXPIRED); setWechatStatus(WECHAT_STATUS.EXPIRED);
}, QR_CODE_TIMEOUT); }, QR_CODE_TIMEOUT);
}, [checkWechatStatus, clearTimers]); }, [checkWechatStatus, clearTimers]);
@@ -254,10 +272,17 @@ export default function WechatRegister() {
throw new Error(response.message || '获取二维码失败'); throw new Error(response.message || '获取二维码失败');
} }
// 同时更新 ref 和 state确保轮询能立即读取到最新值
sessionIdRef.current = response.data.session_id;
setWechatAuthUrl(response.data.auth_url); setWechatAuthUrl(response.data.auth_url);
setWechatSessionId(response.data.session_id); setWechatSessionId(response.data.session_id);
setWechatStatus(WECHAT_STATUS.WAITING); setWechatStatus(WECHAT_STATUS.WAITING);
logger.debug('WechatRegister', '获取二维码成功', {
sessionId: response.data.session_id,
authUrl: response.data.auth_url
});
// 启动轮询检查扫码状态 // 启动轮询检查扫码状态
startPolling(); startPolling();
} catch (error) { } catch (error) {
@@ -293,21 +318,26 @@ export default function WechatRegister() {
return () => { return () => {
isMountedRef.current = false; isMountedRef.current = false;
clearTimers(); clearTimers();
sessionIdRef.current = null; // 清理 sessionId
}; };
}, [clearTimers]); }, [clearTimers]);
/** /**
* 备用轮询机制 - 防止丢失状态 * 备用轮询机制 - 防止丢失状态
* 每3秒检查一次仅在获取到二维码URL且状态为waiting时执 * 每3秒检查一次在 waiting 和 scanned 状态下都保持运
* ⚠️ 已临时注释,测试主轮询是否足够可靠
*/ */
/**
useEffect(() => { useEffect(() => {
// 在有auth_url、session_id且状态为waiting时启动备用轮询 // 在有auth_url、session_id且状态为waiting或scanned时启动备用轮询
if (wechatAuthUrl && wechatSessionId && wechatStatus === WECHAT_STATUS.WAITING) { if (wechatAuthUrl && wechatSessionId &&
logger.debug('WechatRegister', '备用轮询:启动备用轮询机制'); (wechatStatus === WECHAT_STATUS.WAITING || wechatStatus === WECHAT_STATUS.SCANNED)) {
logger.debug('WechatRegister', '备用轮询:启动备用轮询机制', { status: wechatStatus });
backupPollIntervalRef.current = setInterval(() => { backupPollIntervalRef.current = setInterval(() => {
try { try {
if (wechatStatus === WECHAT_STATUS.WAITING && isMountedRef.current) { if ((wechatStatus === WECHAT_STATUS.WAITING || wechatStatus === WECHAT_STATUS.SCANNED) &&
isMountedRef.current && wechatAuthUrl) {
logger.debug('WechatRegister', '备用轮询:检查微信状态'); logger.debug('WechatRegister', '备用轮询:检查微信状态');
// 添加 .catch() 静默处理异步错误,防止被 ErrorBoundary 捕获 // 添加 .catch() 静默处理异步错误,防止被 ErrorBoundary 捕获
checkWechatStatus().catch(error => { checkWechatStatus().catch(error => {
@@ -329,7 +359,7 @@ export default function WechatRegister() {
} }
}; };
}, [wechatAuthUrl, wechatSessionId, wechatStatus, checkWechatStatus]); }, [wechatAuthUrl, wechatSessionId, wechatStatus, checkWechatStatus]);
*/
/** /**
* 测量容器尺寸并计算缩放比例 * 测量容器尺寸并计算缩放比例
*/ */
@@ -397,7 +427,7 @@ export default function WechatRegister() {
textAlign="center" textAlign="center"
mb={3} // 12px底部间距 mb={3} // 12px底部间距
> >
微信扫码 微信登陆
</Heading> </Heading>
{/* ========== 二维码区域 ========== */} {/* ========== 二维码区域 ========== */}
@@ -414,19 +444,26 @@ export default function WechatRegister() {
bg="gray.50" bg="gray.50"
boxShadow="sm" // ✅ 添加轻微阴影 boxShadow="sm" // ✅ 添加轻微阴影
> >
{wechatStatus === WECHAT_STATUS.WAITING ? ( {wechatStatus !== WECHAT_STATUS.NONE ? (
/* 已获取二维码显示iframe */ /* 已获取二维码显示iframe */
<iframe <iframe
src={wechatAuthUrl} src={wechatAuthUrl}
title="微信扫码登录" title="微信扫码登录"
width="300" width="300"
height="350" height="350"
scrolling="no" // ✅ 新增:禁止滚动
style={{ style={{
border: 'none', border: 'none',
transform: 'scale(0.77) translateY(-20px)', // ✅ 裁剪顶部logo transform: 'scale(0.77) translateY(-35px)', // ✅ 裁剪顶部logo
transformOrigin: 'top left', transformOrigin: 'top left',
marginLeft: '-5px' marginLeft: '-5px',
pointerEvents: 'auto', // 允许点击 │ │
overflow: 'hidden', // 尝试隐藏滚动条(可能不起作用)
}} }}
// 使用 onWheel 事件阻止滚动 │ │
onWheel={(e) => e.preventDefault()} // ✅ 在父容器上阻止滚动
onTouchMove={(e) => e.preventDefault()} // ✅ 移动端也阻止
/> />
) : ( ) : (
/* 未获取:显示占位符 */ /* 未获取:显示占位符 */

View File

@@ -144,8 +144,8 @@ export const WECHAT_STATUS = {
WAITING: 'waiting', WAITING: 'waiting',
SCANNED: 'scanned', SCANNED: 'scanned',
AUTHORIZED: 'authorized', AUTHORIZED: 'authorized',
LOGIN_SUCCESS: 'login_success', LOGIN_SUCCESS: 'authorized', // ✅ 与后端保持一致,统一使用 'authorized'
REGISTER_SUCCESS: 'register_success', REGISTER_SUCCESS: 'authorized', // ✅ 与后端保持一致,统一使用 'authorized'
EXPIRED: 'expired', EXPIRED: 'expired',
}; };