2025-10-10 11:15:56 +08:00
|
|
|
import { useTranslation } from 'react-i18next';
|
2025-10-09 17:23:15 +08:00
|
|
|
import {
|
|
|
|
|
Box,
|
|
|
|
|
Button,
|
|
|
|
|
Checkbox,
|
|
|
|
|
Container,
|
|
|
|
|
FormControlLabel,
|
|
|
|
|
TextField,
|
|
|
|
|
Typography,
|
|
|
|
|
Link,
|
2025-10-09 18:11:35 +08:00
|
|
|
AppBar,
|
|
|
|
|
Toolbar,
|
|
|
|
|
Card,
|
2025-10-10 15:09:04 +08:00
|
|
|
CardContent,
|
2025-10-10 18:25:20 +08:00
|
|
|
Alert,
|
|
|
|
|
Tabs,
|
|
|
|
|
Tab
|
2025-10-09 17:23:15 +08:00
|
|
|
} from '@mui/material';
|
2025-10-10 11:15:56 +08:00
|
|
|
import LanguageSwitcher from '../components/LanguageSwitcher';
|
2025-10-10 18:25:20 +08:00
|
|
|
import { useLoginPage } from '../hooks/login-hooks';
|
2025-10-09 17:23:15 +08:00
|
|
|
|
|
|
|
|
const Login = () => {
|
2025-10-10 11:15:56 +08:00
|
|
|
const { t } = useTranslation();
|
2025-10-10 18:25:20 +08:00
|
|
|
const {
|
|
|
|
|
// 表单状态
|
|
|
|
|
tabValue,
|
|
|
|
|
setTabValue,
|
|
|
|
|
error,
|
|
|
|
|
loginForm,
|
|
|
|
|
registerForm,
|
2025-10-10 15:09:04 +08:00
|
|
|
|
2025-10-10 18:25:20 +08:00
|
|
|
// 表单操作
|
|
|
|
|
handleTabChange,
|
|
|
|
|
|
|
|
|
|
// 提交处理
|
|
|
|
|
handleLogin,
|
|
|
|
|
handleRegister,
|
|
|
|
|
isSubmitting,
|
2025-10-10 15:09:04 +08:00
|
|
|
|
2025-10-10 18:25:20 +08:00
|
|
|
// 验证规则
|
|
|
|
|
loginValidation,
|
|
|
|
|
registerValidation
|
|
|
|
|
} = useLoginPage();
|
2025-10-09 17:23:15 +08:00
|
|
|
|
|
|
|
|
return (
|
2025-10-09 18:11:35 +08:00
|
|
|
<Box sx={{ minHeight: '100vh', width: '100vw', bgcolor: 'background.default', display: 'flex', flexDirection: 'column' }}>
|
|
|
|
|
{/* 顶部栏使用主题主色 */}
|
|
|
|
|
<AppBar position="static" color="primary" enableColorOnDark>
|
2025-10-10 11:15:56 +08:00
|
|
|
<Toolbar sx={{ minHeight: 60, justifyContent: 'space-between' }}>
|
2025-10-09 18:11:35 +08:00
|
|
|
<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>
|
2025-10-10 11:15:56 +08:00
|
|
|
<LanguageSwitcher />
|
2025-10-09 18:11:35 +08:00
|
|
|
</Toolbar>
|
|
|
|
|
</AppBar>
|
|
|
|
|
|
|
|
|
|
{/* 主体卡片 */}
|
|
|
|
|
<Container maxWidth="sm" sx={{ flex: 1, display: 'flex', alignItems: 'center' }}>
|
|
|
|
|
<Card sx={{ width: '100%' }}>
|
|
|
|
|
<CardContent sx={{ p: 4 }}>
|
2025-10-10 11:15:56 +08:00
|
|
|
<Typography variant="subtitle1" color="text.secondary" sx={{ mb: 1, display: 'block' }}>
|
|
|
|
|
T-Systems Enterprise RAG Empowerment System
|
2025-10-09 18:11:35 +08:00
|
|
|
</Typography>
|
2025-10-10 18:25:20 +08:00
|
|
|
|
|
|
|
|
{/* 标签页 */}
|
|
|
|
|
<Tabs value={tabValue} onChange={handleTabChange} sx={{ mb: 3 }}>
|
|
|
|
|
<Tab label={t('login.login')} />
|
|
|
|
|
<Tab label={t('login.signUp')} />
|
|
|
|
|
</Tabs>
|
2025-10-09 18:11:35 +08:00
|
|
|
|
2025-10-10 18:25:20 +08:00
|
|
|
{error && (
|
|
|
|
|
<Alert severity="error" sx={{ mb: 2 }}>
|
|
|
|
|
{error}
|
|
|
|
|
</Alert>
|
|
|
|
|
)}
|
2025-10-09 18:11:35 +08:00
|
|
|
|
2025-10-10 18:25:20 +08:00
|
|
|
{/* 登录表单 */}
|
|
|
|
|
{tabValue === 0 && (
|
|
|
|
|
<Box component="form" onSubmit={loginForm.handleSubmit(handleLogin)} noValidate>
|
|
|
|
|
<Typography variant="h5" fontWeight={700} sx={{ mb: 2 }}>
|
|
|
|
|
{t('login.loginDescription')}
|
|
|
|
|
</Typography>
|
|
|
|
|
|
|
|
|
|
<TextField
|
|
|
|
|
fullWidth
|
|
|
|
|
id="login-email"
|
|
|
|
|
type="email"
|
|
|
|
|
placeholder={t('login.emailPlaceholder')}
|
|
|
|
|
autoComplete="email"
|
|
|
|
|
{...loginForm.register('email', loginValidation.email)}
|
|
|
|
|
error={!!loginForm.formState.errors.email}
|
|
|
|
|
helperText={loginForm.formState.errors.email?.message}
|
|
|
|
|
sx={{ mb: 2 }}
|
|
|
|
|
/>
|
2025-10-09 18:11:35 +08:00
|
|
|
|
2025-10-10 18:25:20 +08:00
|
|
|
<TextField
|
|
|
|
|
fullWidth
|
|
|
|
|
id="login-password"
|
|
|
|
|
type="password"
|
|
|
|
|
placeholder={t('login.passwordPlaceholder')}
|
|
|
|
|
autoComplete="current-password"
|
|
|
|
|
{...loginForm.register('password', loginValidation.password)}
|
|
|
|
|
error={!!loginForm.formState.errors.password}
|
|
|
|
|
helperText={loginForm.formState.errors.password?.message}
|
|
|
|
|
sx={{ mb: 2 }}
|
2025-10-09 18:11:35 +08:00
|
|
|
/>
|
2025-10-10 18:25:20 +08:00
|
|
|
|
|
|
|
|
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
|
|
|
|
<FormControlLabel
|
|
|
|
|
control={
|
|
|
|
|
<Checkbox
|
|
|
|
|
{...loginForm.register('rememberEmail')}
|
|
|
|
|
id="rememberEmail"
|
|
|
|
|
/>
|
|
|
|
|
}
|
|
|
|
|
label={t('login.rememberMe')}
|
|
|
|
|
/>
|
|
|
|
|
</Box>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
type="submit"
|
|
|
|
|
variant="contained"
|
|
|
|
|
fullWidth
|
|
|
|
|
disabled={isSubmitting}
|
|
|
|
|
sx={{ mb: 2 }}
|
|
|
|
|
>
|
|
|
|
|
{isSubmitting ? 'Processing...' : t('login.login')}
|
|
|
|
|
</Button>
|
2025-10-09 18:11:35 +08:00
|
|
|
</Box>
|
2025-10-10 18:25:20 +08:00
|
|
|
)}
|
2025-10-09 18:11:35 +08:00
|
|
|
|
2025-10-10 18:25:20 +08:00
|
|
|
{/* 注册表单 */}
|
|
|
|
|
{tabValue === 1 && (
|
|
|
|
|
<Box component="form" onSubmit={registerForm.handleSubmit(handleRegister)} noValidate>
|
|
|
|
|
<Typography variant="h5" fontWeight={700} sx={{ mb: 2 }}>
|
|
|
|
|
{t('login.registerDescription')}
|
|
|
|
|
</Typography>
|
|
|
|
|
|
|
|
|
|
<TextField
|
|
|
|
|
fullWidth
|
|
|
|
|
id="register-nickname"
|
|
|
|
|
placeholder={t('login.nicknamePlaceholder')}
|
|
|
|
|
{...registerForm.register('nickname', registerValidation.nickname)}
|
|
|
|
|
error={!!registerForm.formState.errors.nickname}
|
|
|
|
|
helperText={registerForm.formState.errors.nickname?.message}
|
|
|
|
|
sx={{ mb: 2 }}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<TextField
|
|
|
|
|
fullWidth
|
|
|
|
|
id="register-email"
|
|
|
|
|
type="email"
|
|
|
|
|
placeholder={t('login.emailPlaceholder')}
|
|
|
|
|
autoComplete="email"
|
|
|
|
|
{...registerForm.register('email', registerValidation.email)}
|
|
|
|
|
error={!!registerForm.formState.errors.email}
|
|
|
|
|
helperText={registerForm.formState.errors.email?.message}
|
|
|
|
|
sx={{ mb: 2 }}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<TextField
|
|
|
|
|
fullWidth
|
|
|
|
|
id="register-password"
|
|
|
|
|
type="password"
|
|
|
|
|
placeholder={t('login.passwordPlaceholder')}
|
|
|
|
|
autoComplete="new-password"
|
|
|
|
|
{...registerForm.register('password', registerValidation.password)}
|
|
|
|
|
error={!!registerForm.formState.errors.password}
|
|
|
|
|
helperText={registerForm.formState.errors.password?.message}
|
|
|
|
|
sx={{ mb: 2 }}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
type="submit"
|
|
|
|
|
variant="contained"
|
|
|
|
|
fullWidth
|
|
|
|
|
disabled={isSubmitting}
|
|
|
|
|
sx={{ mb: 2 }}
|
|
|
|
|
>
|
|
|
|
|
{isSubmitting ? 'Processing...' : t('login.register')}
|
|
|
|
|
</Button>
|
|
|
|
|
</Box>
|
|
|
|
|
)}
|
2025-10-09 18:11:35 +08:00
|
|
|
|
|
|
|
|
<Box sx={{ mt: 2, textAlign: 'center' }}>
|
|
|
|
|
<Box mt={0.5}>
|
2025-10-10 18:25:20 +08:00
|
|
|
{tabValue === 0 ? (
|
|
|
|
|
<>
|
|
|
|
|
{t('login.signInTip')} <Link href="#" onClick={() => setTabValue(1)}>{t('login.signUp')}</Link>.
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
{t('login.signUpTip')} <Link href="#" onClick={() => setTabValue(0)}>{t('login.login')}</Link>.
|
|
|
|
|
</>
|
|
|
|
|
)}
|
2025-10-09 18:11:35 +08:00
|
|
|
</Box>
|
2025-10-09 17:23:15 +08:00
|
|
|
</Box>
|
2025-10-09 18:11:35 +08:00
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
</Container>
|
|
|
|
|
|
|
|
|
|
{/* 页脚 */}
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
borderTop: '1px solid',
|
|
|
|
|
borderColor: 'divider',
|
|
|
|
|
height: 50,
|
|
|
|
|
display: 'flex',
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
|
px: 2,
|
|
|
|
|
color: 'text.secondary',
|
|
|
|
|
bgcolor: 'background.paper',
|
|
|
|
|
}}
|
|
|
|
|
>
|
2025-10-09 17:23:15 +08:00
|
|
|
<Box>© Deutsche Telekom AG</Box>
|
2025-10-09 18:11:35 +08:00
|
|
|
<Box sx={{ display: 'flex', gap: 2 }}>
|
2025-10-09 17:23:15 +08:00
|
|
|
<Link href="#" color="inherit">Imprint</Link>
|
|
|
|
|
<Link href="#" color="inherit">Data privacy</Link>
|
2025-10-09 18:11:35 +08:00
|
|
|
</Box>
|
|
|
|
|
</Box>
|
|
|
|
|
</Box>
|
2025-10-09 17:23:15 +08:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default Login;
|