feat: frontend auth flow (login, user management, audit logs, route guards)
This commit is contained in:
@@ -1,14 +1,115 @@
|
||||
import { type FormEvent, useState } from 'react'
|
||||
import { useNavigate, Link } from 'react-router-dom'
|
||||
import { useAuth } from '../hooks/useAuth'
|
||||
import Button from '../components/ui/Button'
|
||||
import toast from '../components/ui/Toast'
|
||||
|
||||
export default function LoginPage() {
|
||||
const { login } = useAuth()
|
||||
const navigate = useNavigate()
|
||||
const [username, setUsername] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
|
||||
const handleSubmit = async (e: FormEvent) => {
|
||||
e.preventDefault()
|
||||
setError('')
|
||||
setLoading(true)
|
||||
try {
|
||||
await login(username, password)
|
||||
toast.success('登录成功')
|
||||
navigate('/dashboard', { replace: true })
|
||||
} catch (err: any) {
|
||||
const status = err?.response?.status
|
||||
const detail = err?.response?.data?.detail ?? '登录失败'
|
||||
if (status === 423) {
|
||||
setError('账户已锁定,请 15 分钟后再试')
|
||||
} else if (status === 401) {
|
||||
setError('用户名或密码错误')
|
||||
} else {
|
||||
setError(detail)
|
||||
}
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center" style={{ background: 'var(--bg-root)' }}>
|
||||
<div
|
||||
className="p-8 rounded-[var(--radius)] w-[360px]"
|
||||
style={{ background: 'var(--bg-card)', boxShadow: 'var(--shadow-lg)' }}
|
||||
>
|
||||
<h1 className="text-center mb-6" style={{ color: 'var(--honey)', fontSize: 20, fontWeight: 700 }}>
|
||||
{/* Logo */}
|
||||
<h1 className="text-center" style={{ color: 'var(--honey)', fontSize: 20, fontWeight: 700 }}>
|
||||
🐝 知微蜂巢
|
||||
</h1>
|
||||
<p className="text-center" style={{ color: 'var(--text-dim)', fontSize: 13 }}>登录页面(待实现)</p>
|
||||
<p className="text-center mt-1" style={{ color: 'var(--text-dim)', fontSize: 13 }}>
|
||||
Hive Manage v3
|
||||
</p>
|
||||
|
||||
{/* Error */}
|
||||
{error && (
|
||||
<div
|
||||
className="mt-4 p-3 rounded-[var(--radius)] text-[13px] font-medium"
|
||||
style={{ background: 'var(--bg-error)', color: 'var(--red)' }}
|
||||
>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Form */}
|
||||
<form onSubmit={handleSubmit} className="mt-6 flex flex-col gap-4">
|
||||
<div>
|
||||
<label className="text-[12px] font-semibold uppercase tracking-wider" style={{ color: 'var(--text-dim)' }}>
|
||||
用户名
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
placeholder="请输入用户名"
|
||||
required
|
||||
autoFocus
|
||||
className="w-full mt-1 px-3 py-[9px] rounded-[var(--radius-sm)] text-[13px] outline-none transition-colors"
|
||||
style={{
|
||||
background: 'var(--bg-root)',
|
||||
color: 'var(--text)',
|
||||
border: '1px solid var(--border)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-[12px] font-semibold uppercase tracking-wider" style={{ color: 'var(--text-dim)' }}>
|
||||
密码
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
placeholder="请输入密码"
|
||||
required
|
||||
className="w-full mt-1 px-3 py-[9px] rounded-[var(--radius-sm)] text-[13px] outline-none transition-colors"
|
||||
style={{
|
||||
background: 'var(--bg-root)',
|
||||
color: 'var(--text)',
|
||||
border: '1px solid var(--border)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" loading={loading} className="w-full !py-[9px]">
|
||||
登入
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
{/* Register link */}
|
||||
<p className="text-center mt-4 text-[13px]" style={{ color: 'var(--text-dim)' }}>
|
||||
还没有账号?{' '}
|
||||
<Link to="/register" style={{ color: 'var(--honey)', fontWeight: 600 }}>
|
||||
注册
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user