码桶
发现社区成员的开源项目
Login.tsx3.4 KB
import { useState } from 'react'
import { useLocation, useNavigate } from 'react-router-dom'
import { Loader2, Lock, Bot } from 'lucide-react'
import { api } from '@/lib/api'
import { useAuth } from '@/lib/auth'
import { useSite } from '@/lib/site'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
import { toast } from 'sonner'
export default function Login() {
const { me, refresh } = useAuth()
const site = useSite()
const navigate = useNavigate()
const location = useLocation()
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [submitting, setSubmitting] = useState(false)
// 已登录则直接跳回首页(避免停留在登录页)
if (me) {
const to = (location.state as any)?.from || '/'
navigate(to, { replace: true })
return null
}
async function onSubmit(e: React.FormEvent) {
e.preventDefault()
if (!username || !password) { toast.error('请输入账号和密码'); return }
setSubmitting(true)
try {
const d = await api.post('/api/login', { username, password })
if (d.ok) {
await refresh()
const to = (location.state as any)?.from || '/'
navigate(to, { replace: true })
return
}
toast.error(d.msg || '登录失败')
} catch (err: any) {
toast.error(err?.message || '登录失败')
} finally {
setSubmitting(false)
}
}
return (
<div className="flex min-h-screen items-center justify-center bg-muted/30 p-4">
<Card className="w-full max-w-sm">
<CardHeader className="items-center text-center">
<div className="mb-2 flex h-12 w-12 items-center justify-center rounded-xl bg-primary/10 text-primary">
<Bot className="h-6 w-6" />
</div>
<CardTitle className="text-xl">{site.site_name}</CardTitle>
<CardDescription className="text-xs">登录后使用(个人版,仅供本人访问)</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={onSubmit} className="space-y-3">
<div className="space-y-1.5">
<Label className="text-sm">账号</Label>
<Input
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="admin"
autoFocus
/>
</div>
<div className="space-y-1.5">
<Label className="text-sm">密码</Label>
<Input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="••••••••"
/>
</div>
<Button type="submit" className="w-full" disabled={submitting}>
{submitting ? <Loader2 className="h-4 w-4 animate-spin" /> : <Lock className="h-4 w-4" />}
登录
</Button>
<p className="text-center text-[11px] text-muted-foreground">
默认账号 admin / 密码 admin123(可在「个人中心」修改)
</p>
</form>
</CardContent>
</Card>
</div>
)
}