This commit is contained in:
2025-07-29 15:36:25 -07:00
commit 0c481c7a0e
29 changed files with 6682 additions and 0 deletions

210
src/pages/Register.jsx Normal file
View File

@ -0,0 +1,210 @@
import React, { useState } from 'react'
import { Link, Navigate } from 'react-router-dom'
import { useAuth } from '../contexts/AuthContext'
import {
Container,
Paper,
TextField,
Button,
Typography,
Box,
Alert,
InputAdornment,
IconButton
} from '@mui/material'
import { Visibility, VisibilityOff, PersonAdd as RegisterIcon } from '@mui/icons-material'
const Register = () => {
const { register, user } = useAuth()
const [formData, setFormData] = useState({
username: '',
email: '',
password: '',
confirmPassword: ''
})
const [showPassword, setShowPassword] = useState(false)
const [showConfirmPassword, setShowConfirmPassword] = useState(false)
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
if (user) {
return <Navigate to="/dashboard" replace />
}
const handleChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value
})
}
const validateForm = () => {
if (formData.password !== formData.confirmPassword) {
setError('两次输入的密码不一致')
return false
}
if (formData.password.length < 6) {
setError('密码长度至少6位')
return false
}
return true
}
const handleSubmit = async (e) => {
e.preventDefault()
setError('')
if (!validateForm()) {
return
}
setLoading(true)
const { confirmPassword, ...userData } = formData
const result = await register(userData)
if (!result.success) {
setError(result.message)
}
setLoading(false)
}
return (
<Container maxWidth="sm">
<Box
sx={{
minHeight: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
<Paper
elevation={3}
sx={{
p: 4,
width: '100%',
maxWidth: 400
}}
>
<Box textAlign="center" mb={3}>
<RegisterIcon sx={{ fontSize: 48, color: 'primary.main', mb: 2 }} />
<Typography variant="h4" component="h1" gutterBottom>
注册
</Typography>
<Typography variant="body2" color="text.secondary">
创建您的账户
</Typography>
</Box>
{error && (
<Alert severity="error" sx={{ mb: 2 }}>
{error}
</Alert>
)}
<form onSubmit={handleSubmit}>
<TextField
fullWidth
label="用户名"
name="username"
value={formData.username}
onChange={handleChange}
margin="normal"
required
autoComplete="username"
/>
<TextField
fullWidth
label="邮箱"
name="email"
type="email"
value={formData.email}
onChange={handleChange}
margin="normal"
required
autoComplete="email"
/>
<TextField
fullWidth
label="密码"
name="password"
type={showPassword ? 'text' : 'password'}
value={formData.password}
onChange={handleChange}
margin="normal"
required
autoComplete="new-password"
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
onClick={() => setShowPassword(!showPassword)}
edge="end"
>
{showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
)
}}
/>
<TextField
fullWidth
label="确认密码"
name="confirmPassword"
type={showConfirmPassword ? 'text' : 'password'}
value={formData.confirmPassword}
onChange={handleChange}
margin="normal"
required
autoComplete="new-password"
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
edge="end"
>
{showConfirmPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
)
}}
/>
<Button
type="submit"
fullWidth
variant="contained"
size="large"
disabled={loading}
sx={{ mt: 3, mb: 2 }}
>
{loading ? '注册中...' : '注册'}
</Button>
<Box textAlign="center">
<Typography variant="body2">
已有账户{' '}
<Link to="/login" style={{ textDecoration: 'none' }}>
<Typography
component="span"
variant="body2"
color="primary"
sx={{ cursor: 'pointer' }}
>
立即登录
</Typography>
</Link>
</Typography>
</Box>
</form>
</Paper>
</Box>
</Container>
)
}
export default Register