| | |
| | | import Image from 'next/image'; |
| | | import { motion } from 'framer-motion'; |
| | | import Link from 'next/link'; |
| | | import { useRouter } from 'next/navigation'; |
| | | import { useUser } from '@/context/UserContext'; |
| | | import ApiService from '@/utils/api'; |
| | | |
| | | // 定义User接口 |
| | | interface User { |
| | | id: number; |
| | | username: string; |
| | | email: string; |
| | | // 其他用户属性... |
| | | } |
| | | |
| | | export default function LoginPage() { |
| | | const [email, setEmail] = useState(''); |
| | |
| | | const [isLoading, setIsLoading] = useState(false); |
| | | const [mounted, setMounted] = useState(false); |
| | | const [loginMethod, setLoginMethod] = useState<'password' | 'sms'>('password'); |
| | | const [error, setError] = useState(''); |
| | | const router = useRouter(); |
| | | const { setUser } = useUser(); |
| | | |
| | | // 确保组件挂载后再显示动画效果 |
| | | useEffect(() => { |
| | | setMounted(true); |
| | | }, []); |
| | | |
| | | const handleSubmit = (e: React.FormEvent) => { |
| | | const handleSubmit = async (e: React.FormEvent) => { |
| | | e.preventDefault(); |
| | | setIsLoading(true); |
| | | setError(''); // 清除之前的错误信息 |
| | | |
| | | // 模拟登录请求 |
| | | setTimeout(() => { |
| | | try { |
| | | const response = await ApiService.post<string>('/users/login', { |
| | | accountName: email, |
| | | password, |
| | | }); |
| | | |
| | | if (response.code === 200) { |
| | | // 获取token |
| | | const token = response.data; |
| | | // 使用ApiService的方法设置token |
| | | ApiService.setToken(token); |
| | | |
| | | // 使用新token获取用户信息 |
| | | try { |
| | | const userData = await ApiService.get<User>('/users/info', token); |
| | | |
| | | if (userData.code === 200) { |
| | | // 保存用户信息到全局状态 |
| | | setUser(userData.data); |
| | | router.push('/'); // 登录成功后跳转到首页 |
| | | } else { |
| | | setError('获取用户信息失败'); |
| | | } |
| | | } catch (error) { |
| | | setError('获取用户信息失败'); |
| | | } |
| | | } else { |
| | | setError(response.message || '登录失败,请检查账号密码'); |
| | | } |
| | | } catch (err) { |
| | | setError('网络错误,请稍后重试'); |
| | | } finally { |
| | | setIsLoading(false); |
| | | // 这里应该添加实际登录逻辑 |
| | | }, 2000); |
| | | } |
| | | }; |
| | | |
| | | return ( |
| | |
| | | |
| | | {/* 账号登录表单 */} |
| | | <form onSubmit={handleSubmit} className="space-y-4"> |
| | | {error && ( |
| | | <motion.div |
| | | initial={{ opacity: 0, y: -10 }} |
| | | animate={{ opacity: 1, y: 0 }} |
| | | className="relative overflow-hidden backdrop-blur-sm bg-[#FF6A88]/5 border border-[#FF6A88]/20 rounded-lg p-3" |
| | | > |
| | | <div className="absolute top-0 left-0 right-0 h-[1px] bg-gradient-to-r from-transparent via-[#FF6A88]/50 to-transparent"></div> |
| | | <div className="absolute bottom-0 left-0 right-0 h-[1px] bg-gradient-to-r from-transparent via-[#FF6A88]/50 to-transparent"></div> |
| | | <div className="absolute top-0 bottom-0 left-0 w-[1px] bg-gradient-to-b from-transparent via-[#FF6A88]/50 to-transparent"></div> |
| | | <div className="absolute top-0 bottom-0 right-0 w-[1px] bg-gradient-to-b from-transparent via-[#FF6A88]/50 to-transparent"></div> |
| | | |
| | | <div className="flex items-center space-x-2"> |
| | | <svg className="w-4 h-4 text-[#FF6A88]" fill="none" viewBox="0 0 24 24" stroke="currentColor"> |
| | | <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /> |
| | | </svg> |
| | | <span className="text-xs text-[#FF6A88]">{error}</span> |
| | | </div> |
| | | |
| | | {/* 动态扫描线 */} |
| | | <div className="absolute top-0 -left-full w-[200%] h-full bg-gradient-to-r from-transparent via-[#FF6A88]/10 to-transparent animate-error-scan"></div> |
| | | </motion.div> |
| | | )} |
| | | |
| | | <div className="space-y-3"> |
| | | {loginMethod === 'password' ? ( |
| | | <> |