// src/views/Authentication/SignIn/SignInIllustration.js - Session版本 import React, { useState, useEffect } from "react"; import { Box, Button, Flex, FormControl, Input, Text, Heading, VStack, HStack, useToast, Icon, InputGroup, InputRightElement, IconButton, Link as ChakraLink, Center, useDisclosure, FormErrorMessage } from "@chakra-ui/react"; import { ViewIcon, ViewOffIcon } from "@chakra-ui/icons"; import { FaMobile, FaWeixin, FaLock, FaQrcode } from "react-icons/fa"; import { useNavigate, useLocation } from "react-router-dom"; import { useAuth } from "../../../contexts/AuthContext"; import PrivacyPolicyModal from "../../../components/PrivacyPolicyModal"; import UserAgreementModal from "../../../components/UserAgreementModal"; import AuthBackground from "../../../components/Auth/AuthBackground"; import AuthHeader from "../../../components/Auth/AuthHeader"; import AuthFooter from "../../../components/Auth/AuthFooter"; import VerificationCodeInput from "../../../components/Auth/VerificationCodeInput"; // API配置 const isProduction = process.env.NODE_ENV === 'production'; const API_BASE_URL = isProduction ? "" : "http://49.232.185.254:5000"; export default function SignInIllustration() { const navigate = useNavigate(); const location = useLocation(); const toast = useToast(); const { login, checkSession } = useAuth(); // 页面状态 const [isLoading, setIsLoading] = useState(false); const [errors, setErrors] = useState({}); // 检查URL参数中的错误信息(微信登录失败时) useEffect(() => { const params = new URLSearchParams(location.search); const error = params.get('error'); if (error) { let errorMessage = '登录失败'; switch (error) { case 'wechat_auth_failed': errorMessage = '微信授权失败'; break; case 'session_expired': errorMessage = '会话已过期,请重新登录'; break; case 'token_failed': errorMessage = '获取微信授权失败'; break; case 'userinfo_failed': errorMessage = '获取用户信息失败'; break; case 'login_failed': errorMessage = '登录处理失败,请重试'; break; default: errorMessage = '登录失败,请重试'; } toast({ title: "登录失败", description: errorMessage, status: "error", duration: 5000, isClosable: true, }); // 清除URL参数 const newUrl = window.location.pathname; window.history.replaceState({}, document.title, newUrl); } }, [location, toast]); // 传统登录数据 // 表单数据初始化 const [formData, setFormData] = useState({ username: "", // 用户名称 email: "", // 邮箱 phone: "", // 电话 password: "", // 密码 verificationCode: "", // 添加验证码字段 }); // 验证码登录状态 是否开启验证码 const [useVerificationCode, setUseVerificationCode] = useState(false); // 密码展示状态 const [showPassword, setShowPassword] = useState(false); const [verificationCodeSent, setVerificationCodeSent] = useState(false); // 验证码发送状态 const [sendingCode, setSendingCode] = useState(false); // 发送验证码状态 // 隐私政策弹窗状态 const { isOpen: isPrivacyModalOpen, onOpen: onPrivacyModalOpen, onClose: onPrivacyModalClose } = useDisclosure(); // 用户协议弹窗状态 const { isOpen: isUserAgreementModalOpen, onOpen: onUserAgreementModalOpen, onClose: onUserAgreementModalClose } = useDisclosure(); // 输入框输入 const handleInputChange = (e) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); }; // ========== 发送验证码逻辑 ============= // 倒计时效果 const [countdown, setCountdown] = useState(0); useEffect(() => { let timer; if (countdown > 0) { timer = setInterval(() => { setCountdown(prev => prev - 1); }, 1000); } else if (countdown === 0) { setVerificationCodeSent(false); } return () => clearInterval(timer); }, [countdown]); // 发送验证码 const sendVerificationCode = async () => { const credential = formData.phone; const type = 'phone'; if (!credential) { toast({ title: "请先输入手机号", status: "warning", duration: 3000, }); return; } // 基本格式验证 if (!/^1[3-9]\d{9}$/.test(credential)) { toast({ title: "请输入有效的手机号", status: "warning", duration: 3000, }); return; } try { setSendingCode(true); const response = await fetch(`${API_BASE_URL}/api/auth/send-verification-code`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ credential, type, purpose: 'login' }), }); const data = await response.json(); if (response.ok && data.success) { toast({ title: "验证码已发送", description: "验证码已发送到您的手机号", status: "success", duration: 3000, }); setVerificationCodeSent(true); setCountdown(60); // 60秒倒计时 } else { throw new Error(data.error || '发送验证码失败'); } } catch (error) { toast({ title: "发送验证码失败", description: error.message || "请稍后重试", status: "error", duration: 3000, }); } finally { setSendingCode(false); } }; // 点击扫码,打开微信登录窗口 const openWechatLogin = async () => { try { setIsLoading(true); console.log("请求微信登录1..."); // 获取微信二维码地址 const response = await fetch(`${API_BASE_URL}/api/auth/wechat/qrcode`); if (!response.ok) { throw new Error('获取二维码失败'); } const data = await response.json(); // 方案1:直接跳转(推荐) window.location.href = data.auth_url; } catch (error) { console.error('获取微信授权失败:', error); toast({ title: "获取微信授权失败", description: error.message || "请稍后重试", status: "error", duration: 3000, }); } finally { setIsLoading(false); } }; // 验证码登录函数 const loginWithVerificationCode = async (credential, verificationCode, authLoginType) => { try { const response = await fetch(`${API_BASE_URL}/api/auth/login-with-code`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, credentials: 'include', body: JSON.stringify({ credential, verification_code: verificationCode, login_type: authLoginType }), }); const data = await response.json(); if (response.ok && data.success) { // 更新认证状态 await checkSession(); toast({ title: "登录成功", description: "欢迎回来!", status: "success", duration: 3000, }); return { success: true }; } else { throw new Error(data.error || '验证码登录失败'); } } catch (error) { toast({ title: "登录失败", description: error.message || "请检查验证码是否正确", status: "error", duration: 3000, }); return { success: false, error: error.message }; } }; // 传统行业登陆 const handleTraditionalLogin = async (e) => { e.preventDefault(); setIsLoading(true); try { const credential = formData.phone; const authLoginType = 'phone'; if (useVerificationCode) { // 验证码登陆 if (!credential || !formData.verificationCode) { toast({ title: "请填写完整信息", description: "手机号和验证码不能为空", status: "warning", duration: 3000, }); return; } const result = await loginWithVerificationCode(credential, formData.verificationCode, authLoginType); if (result.success) { navigate("/home"); } } else { // 密码登陆 if (!credential || !formData.password) { toast({ title: "请填写完整信息", description: `手机号和密码不能为空`, status: "warning", duration: 3000, }); return; } const result = await login(credential, formData.password, authLoginType); if (result.success) { // ✅ 显示成功提示 toast({ title: "登录成功", description: "欢迎回来!", status: "success", duration: 3000, isClosable: true, }); navigate("/home"); } else { // ❌ 显示错误提示 toast({ title: "登录失败", description: result.error || "请检查您的登录信息", status: "error", duration: 3000, isClosable: true, }); } } } catch (error) { console.error('Login error:', error); toast({ title: "登录失败", description: error.message || "发生未预期的错误,请重试", status: "error", duration: 3000, isClosable: true, }); } finally { setIsLoading(false); } }; // 切换登录方式 const handleChangeMethod = () => { setUseVerificationCode(!useVerificationCode); // 切换到密码模式时清空验证码 if (useVerificationCode) { setFormData(prev => ({ ...prev, verificationCode: "" })); } }; return ( {/* 背景 */} {/* 主要内容 */} {/* 登录卡片 */} {/* 头部区域 */} {/* 左右布局 */} {/* 左侧:手机号登陆 - 80% 宽度 */}
手机号登陆 {errors.phone} {/* 密码/验证码输入框 */} {useVerificationCode ? ( ) : ( : } onClick={() => setShowPassword(!showPassword)} aria-label={showPassword ? "Hide password" : "Show password"} /> {errors.password} )}
{/* 右侧:微信登陆 - 20% 宽度 */}
微信扫一扫 {/* isLoading={isLoading || !wechatAuthUrl} */}
{/* 底部链接 */} {/* 协议同意勾选框 */} 注册登录即表示阅读并同意{" "} 《用户协议》 {" "}和{" "} 《隐私政策》
{/* 隐私政策弹窗 */} {/* 用户协议弹窗 */}
); }