/**
|
* @author 韩天尊
|
* @time 2024-01-15
|
* @version 1.0.0
|
* @description 登录页面组件
|
*/
|
import React, { useState, useEffect } from 'react';
|
import { useNavigate } from 'react-router-dom';
|
import { useAppContext } from '../context/AppContext';
|
import { authAPI } from '../services/api';
|
import PageHeader from '../components/PageHeader';
|
import './LoginPage.css';
|
|
const LoginPage: React.FC = () => {
|
const navigate = useNavigate();
|
const { state, dispatch } = useAppContext();
|
const [isLogin, setIsLogin] = useState(true);
|
const [formData, setFormData] = useState({
|
name: '',
|
phone: '',
|
password: '',
|
confirmPassword: ''
|
});
|
const [loading, setLoading] = useState(false);
|
const [error, setError] = useState('');
|
const [loginSuccess, setLoginSuccess] = useState(false);
|
const [autoLoginLoading, setAutoLoginLoading] = useState(true);
|
|
// 自动登录检查
|
useEffect(() => {
|
const checkAutoLogin = async () => {
|
try {
|
const fwmPhone = localStorage.getItem('fwmPhone');
|
if (fwmPhone) {
|
// 如果有缓存的手机号,尝试获取用户信息
|
const response = await authAPI.getUserByPhone(fwmPhone);
|
if (response.code === 0 && response.data.user) {
|
// 缓存token和用户信息
|
localStorage.setItem('token', response.data.token);
|
localStorage.setItem('user', JSON.stringify(response.data.user));
|
dispatch({ type: 'SET_USER', payload: response.data.user });
|
|
// 自动跳转到首页
|
navigate('/', { replace: true });
|
return;
|
} else {
|
// 如果获取用户信息失败,清除缓存
|
localStorage.removeItem('fwmPhone');
|
localStorage.removeItem('token');
|
localStorage.removeItem('user');
|
}
|
}
|
} catch (error) {
|
console.error('自动登录失败:', error);
|
// 清除可能存在的无效缓存
|
localStorage.removeItem('fwmPhone');
|
localStorage.removeItem('token');
|
localStorage.removeItem('user');
|
} finally {
|
setAutoLoginLoading(false);
|
}
|
};
|
|
checkAutoLogin();
|
}, [navigate, dispatch]);
|
|
// 表单输入处理
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const { name, value } = e.target;
|
setFormData(prev => ({
|
...prev,
|
[name]: value
|
}));
|
setError('');
|
};
|
|
// 表单提交处理
|
const handleSubmit = async (e: React.FormEvent) => {
|
e.preventDefault();
|
setLoading(true);
|
setError('');
|
|
try {
|
if (isLogin) {
|
// 登录
|
const response = await authAPI.login(formData.phone, formData.password);
|
if (response.code === 0) {
|
console.log('response.data.token:', response.data.token);
|
localStorage.setItem('token', response.data.token);
|
localStorage.setItem('user', JSON.stringify(response.data.user));
|
// 缓存手机号用于下次自动登录
|
localStorage.setItem('fwmPhone', formData.phone);
|
dispatch({ type: 'SET_USER', payload: response.data.user });
|
|
// 显示登录成功状态
|
setLoginSuccess(true);
|
setError('');
|
|
// 延迟0.8秒后跳转到首页
|
setTimeout(() => {
|
navigate('/', { replace: true });
|
}, 800);
|
} else {
|
throw new Error(response.msg || '登录失败');
|
}
|
} else {
|
// 注册
|
if (formData.password !== formData.confirmPassword) {
|
throw new Error('两次输入的密码不一致');
|
}
|
const response = await authAPI.register(formData.name, formData.phone, formData.password, '');
|
if (response.code === 0) {
|
// 注册成功后自动登录
|
const loginResponse = await authAPI.login(formData.phone, formData.password);
|
if (loginResponse.code === 0) {
|
localStorage.setItem('token', loginResponse.data.token);
|
localStorage.setItem('user', JSON.stringify(loginResponse.data.user));
|
// 缓存手机号用于下次自动登录
|
localStorage.setItem('fwmPhone', formData.phone);
|
dispatch({ type: 'SET_USER', payload: loginResponse.data.user });
|
|
// 显示注册成功状态
|
setLoginSuccess(true);
|
setError('');
|
|
// 延迟0.8秒后跳转到首页
|
setTimeout(() => {
|
navigate('/', { replace: true });
|
}, 800);
|
}
|
} else {
|
throw new Error(response.msg || '注册失败');
|
}
|
}
|
} catch (error: any) {
|
setError(error.message || '操作失败');
|
setLoginSuccess(false);
|
} finally {
|
setLoading(false);
|
}
|
};
|
|
// 切换登录/注册模式
|
const toggleMode = () => {
|
setIsLogin(!isLogin);
|
setFormData({
|
name: '',
|
phone: '',
|
password: '',
|
confirmPassword: ''
|
});
|
setError('');
|
setLoginSuccess(false);
|
};
|
|
// 如果正在自动登录检查,显示加载状态
|
if (autoLoginLoading) {
|
return (
|
<div className="page">
|
<div className="login-container">
|
<div className="login-header">
|
<div className="login-logo">
|
<i className="fas fa-heart icon-heart"></i>
|
</div>
|
<h2 className="login-title">志愿者服务平台</h2>
|
<p className="login-subtitle">正在检查登录状态...</p>
|
</div>
|
<div className="loading-container">
|
<div className="loading-spinner"></div>
|
<p>请稍候...</p>
|
</div>
|
</div>
|
</div>
|
);
|
}
|
|
return (
|
<div className="page">
|
<div className="login-container">
|
{/* 登录头部 */}
|
<div className="login-header">
|
<div className="login-logo">
|
<i className="fas fa-heart icon-heart"></i>
|
</div>
|
<h2 className="login-title">志愿者服务平台</h2>
|
<p className="login-subtitle">欢迎使用社区志愿服务积分系统</p>
|
</div>
|
|
{/* 登录表单 */}
|
<div className="login-form">
|
|
<form onSubmit={handleSubmit}>
|
{!isLogin && (
|
<div className="form-group">
|
<label>姓名</label>
|
<div className="input-wrapper">
|
<i className="fas fa-user"></i>
|
<input
|
type="text"
|
id="name"
|
name="name"
|
value={formData.name}
|
onChange={handleInputChange}
|
placeholder="请输入真实姓名"
|
className="form-input"
|
required={!isLogin}
|
/>
|
</div>
|
</div>
|
)}
|
|
<div className="form-group">
|
<label>手机号码</label>
|
<div className="input-wrapper">
|
<i className="fas fa-mobile-alt"></i>
|
<input
|
type="tel"
|
id="phone"
|
name="phone"
|
value={formData.phone}
|
onChange={handleInputChange}
|
placeholder="请输入手机号码"
|
className="form-input"
|
required
|
/>
|
</div>
|
</div>
|
|
<div className="form-group">
|
<label>密码</label>
|
<div className="input-wrapper">
|
<i className="fas fa-lock"></i>
|
<input
|
type="password"
|
id="password"
|
name="password"
|
value={formData.password}
|
onChange={handleInputChange}
|
placeholder="请输入密码"
|
className="form-input"
|
required
|
/>
|
</div>
|
</div>
|
|
{!isLogin && (
|
<div className="form-group">
|
<label>确认密码</label>
|
<div className="input-wrapper">
|
<i className="fas fa-lock"></i>
|
<input
|
type="password"
|
id="confirmPassword"
|
name="confirmPassword"
|
value={formData.confirmPassword}
|
onChange={handleInputChange}
|
placeholder="请再次输入密码"
|
className="form-input"
|
required={!isLogin}
|
/>
|
</div>
|
</div>
|
)}
|
|
{error && (
|
<div className="error-message">
|
<i className="fas fa-exclamation-circle"></i>
|
{error}
|
</div>
|
)}
|
|
{loginSuccess && (
|
<div className="success-message">
|
<i className="fas fa-check-circle"></i>
|
{isLogin ? '登录成功' : '注册成功'}
|
</div>
|
)}
|
|
{/* 登录按钮 */}
|
<div className="login-actions">
|
<button
|
type="submit"
|
className="login-btn"
|
disabled={loading || loginSuccess}
|
>
|
{loading ? (
|
<>
|
<span className="loading-spinner"></span>
|
处理中...
|
</>
|
) : loginSuccess ? (
|
<>
|
<i className="fas fa-check"></i>
|
<span>{isLogin ? '登录成功' : '注册成功'}</span>
|
</>
|
) : (
|
<>
|
<i className="fas fa-sign-in-alt"></i>
|
<span>{isLogin ? '立即登录' : '立即注册'}</span>
|
</>
|
)}
|
</button>
|
</div>
|
</form>
|
|
{/* 登录说明 */}
|
<div className="login-notice">
|
<div className="notice-item">
|
<i className="fas fa-info-circle"></i>
|
<span>首次登录将自动注册账号</span>
|
</div>
|
<div className="notice-item">
|
<i className="fas fa-shield-alt"></i>
|
<span>您的个人信息将被严格保密</span>
|
</div>
|
</div>
|
|
<div className="form-footer">
|
<button
|
type="button"
|
className="toggle-btn"
|
onClick={toggleMode}
|
>
|
{isLogin ? '还没有账号?立即注册' : '已有账号?立即登录'}
|
</button>
|
</div>
|
</div>
|
</div>
|
</div>
|
);
|
};
|
|
export default LoginPage;
|