refactor(Login): rewrite login page using Material-UI components

- Replace styled components with Material-UI's AppBar, Toolbar, and Card
- Update form fields to handle email and password instead of just username
- Improve error handling for both email and password fields
- Simplify layout and remove social login options
This commit is contained in:
2025-10-09 18:11:35 +08:00
parent 5f93573e57
commit a1e8f47ed4
3 changed files with 128 additions and 225 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 KiB

BIN
src/assets/logo_text.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 KiB

View File

@@ -9,253 +9,156 @@ import {
TextField, TextField,
Typography, Typography,
Link, Link,
styled AppBar,
Toolbar,
Card,
CardContent
} from '@mui/material'; } from '@mui/material';
const LoginContainer = styled(Box)({
height: '100vh',
display: 'flex',
flexDirection: 'column',
backgroundColor: '#f5f7fa',
});
const TopBar = styled(Box)({
height: '60px',
backgroundColor: '#1a1a2e',
display: 'flex',
alignItems: 'center',
padding: '0 20px',
});
const BrandLogo = styled(Box)({
width: '40px',
height: '40px',
backgroundColor: '#fff',
color: '#1a1a2e',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '50%',
fontWeight: 'bold',
fontSize: '1.2rem',
});
const LoginMain = styled(Box)({
flex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
});
const LoginCard = styled(Box)({
width: '400px',
backgroundColor: '#fff',
borderRadius: '8px',
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
padding: '30px',
});
const ServiceName = styled(Typography)({
fontSize: '0.75rem',
color: '#666',
marginBottom: '10px',
});
const LoginTitle = styled(Typography)({
fontSize: '1.5rem',
fontWeight: 'bold',
marginBottom: '20px',
});
const LoginForm = styled('form')({
display: 'flex',
flexDirection: 'column',
gap: '20px',
});
const RememberRow = styled(Box)({
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
});
const ActionButtons = styled(Box)({
display: 'flex',
gap: '10px',
marginTop: '10px',
});
const PrimaryButton = styled(Button)({
backgroundColor: '#e20074',
'&:hover': {
backgroundColor: '#c10062',
},
});
const SecondaryButton = styled(Button)({
color: '#333',
backgroundColor: '#f5f5f5',
'&:hover': {
backgroundColor: '#e0e0e0',
},
});
const HelpSection = styled(Box)({
marginTop: '20px',
textAlign: 'center',
fontSize: '0.875rem',
});
const SocialLogin = styled(Box)({
display: 'flex',
justifyContent: 'center',
gap: '10px',
marginTop: '15px',
});
const SocialButton = styled(Box)({
width: '30px',
height: '30px',
borderRadius: '50%',
backgroundColor: '#e0e0e0',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer',
});
const Footer = styled(Box)({
height: '50px',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '0 20px',
borderTop: '1px solid #eee',
fontSize: '0.75rem',
color: '#666',
});
const LegalLinks = styled(Box)({
display: 'flex',
gap: '15px',
});
const Login = () => { const Login = () => {
const [username, setUsername] = useState(''); const [email, setEmail] = useState('');
const [rememberUser, setRememberUser] = useState(false); const [password, setPassword] = useState('');
const [rememberEmail, setRememberEmail] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState(false); const [emailError, setEmailError] = useState(false);
const [passwordError, setPasswordError] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
if (!username.trim()) { const hasEmail = !!email.trim();
setError(true); const hasPassword = !!password.trim();
return; setEmailError(!hasEmail);
} setPasswordError(!hasPassword);
if (!hasEmail || !hasPassword) return;
setIsSubmitting(true); setIsSubmitting(true);
setError(false);
// 模拟登录过程 // 模拟登录过程
setTimeout(() => { setTimeout(() => {
navigate('/'); navigate('/');
}, 800); }, 800);
}; };
const handleCancel = () => {
navigate('/');
};
return ( return (
<LoginContainer> <Box sx={{ minHeight: '100vh', width: '100vw', bgcolor: 'background.default', display: 'flex', flexDirection: 'column' }}>
<TopBar> {/* 顶部栏使用主题主色 */}
<BrandLogo>T</BrandLogo> <AppBar position="static" color="primary" enableColorOnDark>
</TopBar> <Toolbar sx={{ minHeight: 60 }}>
<Box
sx={{
width: 40,
height: 40,
bgcolor: 'common.white',
color: 'primary.main',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontWeight: 700,
fontSize: '1.1rem',
}}
aria-label="Brand"
>
T
</Box>
</Toolbar>
</AppBar>
<LoginMain> {/* 主体卡片 */}
<LoginCard> <Container maxWidth="sm" sx={{ flex: 1, display: 'flex', alignItems: 'center' }}>
<ServiceName>Servicename</ServiceName> <Card sx={{ width: '100%' }}>
<LoginTitle> <CardContent sx={{ p: 4 }}>
Enter Login <br/> Username <Typography variant="caption" color="text.secondary" sx={{ mb: 1, display: 'block' }}>
</LoginTitle> Servicename
</Typography>
<Typography variant="h5" fontWeight={700} sx={{ mb: 2 }}>
Enter Login
<br /> Email & Password
</Typography>
<LoginForm onSubmit={handleSubmit} noValidate> <Box component="form" onSubmit={handleSubmit} noValidate>
<TextField <TextField
fullWidth fullWidth
id="username" id="email"
name="username" name="email"
placeholder="Username" type="email"
autoComplete="username" placeholder="Email"
value={username} autoComplete="email"
onChange={(e) => setUsername(e.target.value)} value={email}
error={error} onChange={(e) => setEmail(e.target.value)}
required error={emailError}
/> required
sx={{ mb: 2 }}
<RememberRow>
<FormControlLabel
control={
<Checkbox
checked={rememberUser}
onChange={(e) => setRememberUser(e.target.checked)}
id="rememberUser"
/>
}
label="Remember username"
/> />
<Link href="#" variant="caption">
Forgot your username or password?
</Link>
</RememberRow>
<ActionButtons> <TextField
<PrimaryButton
type="submit"
variant="contained"
fullWidth fullWidth
disabled={isSubmitting} id="password"
> name="password"
{isSubmitting ? 'Processing...' : 'Next'} type="password"
</PrimaryButton> placeholder="Password"
<SecondaryButton autoComplete="current-password"
type="button" value={password}
variant="contained" onChange={(e) => setPassword(e.target.value)}
fullWidth error={passwordError}
onClick={handleCancel} required
> sx={{ mb: 2 }}
Cancel />
</SecondaryButton>
</ActionButtons>
</LoginForm>
<HelpSection> <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
<Link href="#">Do you need help?</Link> <FormControlLabel
<Box mt={1}> control={
No account? <Link href="#">Sign up</Link> or log in with your social network account. <Checkbox
checked={rememberEmail}
onChange={(e) => setRememberEmail(e.target.checked)}
id="rememberEmail"
/>
}
label="Remember email"
/>
<Link href="#" variant="caption">
Forgot your username or password?
</Link>
</Box>
<Button type="submit" variant="contained" fullWidth disabled={isSubmitting}>
{isSubmitting ? 'Processing...' : 'Login'}
</Button>
</Box> </Box>
</HelpSection>
<SocialLogin> <Box sx={{ mt: 2, textAlign: 'center' }}>
<SocialButton aria-label="Login with Facebook"> <Link href="#">Do you need help?</Link>
<Link href="#" underline="none" color="inherit">f</Link> <Box mt={0.5}>
</SocialButton> {/* 保留说明文案,去掉社交登录 */}
<SocialButton aria-label="Login with Twitter"> No account? <Link href="#">Sign up</Link>.
<Link href="#" underline="none" color="inherit">t</Link> </Box>
</SocialButton> </Box>
</SocialLogin> </CardContent>
</LoginCard> </Card>
</LoginMain> </Container>
<Footer> {/* 页脚 */}
<Box
sx={{
borderTop: '1px solid',
borderColor: 'divider',
height: 50,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
px: 2,
color: 'text.secondary',
bgcolor: 'background.paper',
}}
>
<Box>© Deutsche Telekom AG</Box> <Box>© Deutsche Telekom AG</Box>
<LegalLinks> <Box sx={{ display: 'flex', gap: 2 }}>
<Link href="#" color="inherit">Imprint</Link> <Link href="#" color="inherit">Imprint</Link>
<Link href="#" color="inherit">Data privacy</Link> <Link href="#" color="inherit">Data privacy</Link>
</LegalLinks> </Box>
</Footer> </Box>
</LoginContainer> </Box>
); );
}; };