From 515838200fdc0de4da59a012e14b8eb500a07026 Mon Sep 17 00:00:00 2001 From: hobby Date: Fri, 22 Aug 2025 07:42:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81wechat=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/goCaptcha/ClickTextCapt.d.ts | 12 ++ src/pages/login/comonents/WechatLogin.tsx | 212 ++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 src/components/goCaptcha/ClickTextCapt.d.ts create mode 100644 src/pages/login/comonents/WechatLogin.tsx diff --git a/src/components/goCaptcha/ClickTextCapt.d.ts b/src/components/goCaptcha/ClickTextCapt.d.ts new file mode 100644 index 0000000..d6e1d38 --- /dev/null +++ b/src/components/goCaptcha/ClickTextCapt.d.ts @@ -0,0 +1,12 @@ +declare module '@/components/goCaptcha/ClickTextCapt.jsx' { + import React from 'react'; + + interface ClickTextCaptProps { + onVisibleChange: (visible: boolean) => void; + extraData?: any; + onSuccess: () => void; + } + + const ClickTextCapt: React.FC; + export default ClickTextCapt; +} diff --git a/src/pages/login/comonents/WechatLogin.tsx b/src/pages/login/comonents/WechatLogin.tsx new file mode 100644 index 0000000..d6e8103 --- /dev/null +++ b/src/pages/login/comonents/WechatLogin.tsx @@ -0,0 +1,212 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { Button } from "@/components/ui/button"; +import { toast } from 'sonner'; +import { request } from '@/utils/request'; +import { useIsMobile } from '@/hooks/use-mobile'; + +interface WechatLoginProps { + handleLoginSuccess: (token: string) => void; +} + +const WechatLogin: React.FC = ({ handleLoginSuccess }) => { + const [qrCode, setQrCode] = useState(''); + const [loginStatus, setLoginStatus] = useState<'loading' | 'ready' | 'scanned' | 'expired'>('loading'); + const [isLoading, setIsLoading] = useState(false); + const pollingRef = useRef(null); + const isMobile = useIsMobile(); + + // 获取备案号配置 + const icpNumber = (window as any).APP_CONFIG?.ICP_NUMBER; + + // 生成微信登录二维码 + const generateQrCode = async () => { + setIsLoading(true); + setLoginStatus('loading'); + + try { + const response = await request('/api/auth/wechat/qr-code', { + method: 'POST', + body: JSON.stringify({}), + }); + + const data = await response.json(); + + if (data.success) { + setQrCode(data.data.qr_url); + setLoginStatus('ready'); + startPolling(data.data.session_id); + } else { + toast.error(data.message || '获取二维码失败'); + setLoginStatus('expired'); + } + } catch (error) { + console.error('获取微信二维码失败:', error); + toast.error('获取二维码失败,请重试'); + setLoginStatus('expired'); + } finally { + setIsLoading(false); + } + }; + + // 轮询检查登录状态 + const startPolling = (sessionId: string) => { + pollingRef.current = setInterval(async () => { + try { + const response = await request(`/api/auth/wechat/status/${sessionId}`, { + method: 'GET', + }); + + const data = await response.json(); + + if (data.success) { + switch (data.status) { + case 'scanned': + setLoginStatus('scanned'); + break; + case 'confirmed': + // 登录成功 + handleLoginSuccess(data.data.token); + if (pollingRef.current) { + clearInterval(pollingRef.current); + } + break; + case 'expired': + setLoginStatus('expired'); + if (pollingRef.current) { + clearInterval(pollingRef.current); + } + break; + } + } + } catch (error) { + console.error('检查登录状态失败:', error); + } + }, 2000); // 每2秒检查一次 + }; + + // 刷新二维码 + const refreshQrCode = () => { + if (pollingRef.current) { + clearInterval(pollingRef.current); + } + generateQrCode(); + }; + + // 组件挂载时生成二维码 + useEffect(() => { + generateQrCode(); + + // 组件卸载时清理定时器 + return () => { + if (pollingRef.current) { + clearInterval(pollingRef.current); + } + }; + }, []); + + // 获取状态提示文本 + const getStatusText = () => { + switch (loginStatus) { + case 'loading': + return '正在加载二维码...'; + case 'ready': + return '请使用微信扫码登录'; + case 'scanned': + return '扫码成功,请在手机上确认登录'; + case 'expired': + return '二维码已过期,请点击刷新'; + default: + return ''; + } + }; + + return ( +
+
+ {/* Logo */} +
+ + botgroup.chat + +
+ +
+ 微信扫码登录 +
+ + {/* 二维码区域 */} +
+
+ {loginStatus === 'loading' ? ( +
+
+ 加载中... +
+ ) : loginStatus === 'expired' ? ( +
+
+ + + + 二维码已过期 +
+
+ ) : qrCode ? ( +
+ 微信登录二维码 + {loginStatus === 'scanned' && ( +
+
+ + + + 扫码成功 +
+
+ )} +
+ ) : null} +
+ + {/* 状态提示 */} +
+ {getStatusText()} +
+ + {/* 刷新按钮 */} + {loginStatus === 'expired' && ( + + )} +
+ + {/* 备案号显示 */} + {icpNumber && ( + + )} +
+
+ ); +}; + +export default WechatLogin;