This commit is contained in:
beabigegg
2025-11-12 22:53:17 +08:00
commit da700721fa
130 changed files with 23393 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import { useAuthStore } from '@/store/authStore'
import { apiClient } from '@/services/api'
export default function LoginPage() {
const { t } = useTranslation()
const navigate = useNavigate()
const setUser = useAuthStore((state) => state.setUser)
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setError('')
setLoading(true)
try {
await apiClient.login({ username, password })
// For now, just set a basic user object (backend doesn't return user info)
setUser({ id: 1, username })
navigate('/upload')
} catch (err: any) {
const errorDetail = err.response?.data?.detail
if (Array.isArray(errorDetail)) {
// Handle validation error array from backend
setError(errorDetail.map((e: any) => e.msg || e.message || String(e)).join(', '))
} else if (typeof errorDetail === 'string') {
setError(errorDetail)
} else {
setError(t('auth.loginError'))
}
} finally {
setLoading(false)
}
}
return (
<div className="min-h-screen bg-background flex items-center justify-center">
<div className="w-full max-w-md">
<div className="bg-card rounded-lg shadow-lg p-8 border">
<div className="text-center mb-8">
<h1 className="text-3xl font-bold text-foreground mb-2">{t('app.title')}</h1>
<p className="text-muted-foreground">{t('app.subtitle')}</p>
</div>
<form onSubmit={handleSubmit} className="space-y-6">
<div>
<label htmlFor="username" className="block text-sm font-medium text-foreground mb-2">
{t('auth.username')}
</label>
<input
id="username"
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
className="w-full px-3 py-2 border border-input bg-background rounded-md focus:outline-none focus:ring-2 focus:ring-ring"
required
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-foreground mb-2">
{t('auth.password')}
</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full px-3 py-2 border border-input bg-background rounded-md focus:outline-none focus:ring-2 focus:ring-ring"
required
/>
</div>
{error && (
<div className="p-3 bg-destructive/10 border border-destructive rounded-md text-sm text-destructive">
{error}
</div>
)}
<button
type="submit"
disabled={loading}
className="w-full py-2 px-4 bg-primary text-primary-foreground rounded-md font-medium hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? t('common.loading') : t('auth.loginButton')}
</button>
</form>
</div>
</div>
</div>
)
}