2025-05-22 20:42:10 +08:00

186 lines
6.3 KiB
TypeScript

"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import * as z from "zod"
import { Button } from "@/components/ui/button"
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { useToast } from "@/components/ui/use-toast"
import { useRouter } from "next/navigation"
import { useAuth } from "@/context/auth-context"
import Link from "next/link"
import { ThemeToggle } from "@/components/theme-toggle"
import { Checkbox } from "@/components/ui/checkbox"
import { useState } from "react"
const formSchema = z.object({
username: z.string().min(2, {
message: "用户名至少需要2个字符",
}),
password: z.string().min(6, {
message: "密码至少需要6个字符",
}),
rememberMe: z.boolean().default(false),
})
export default function LoginPage() {
const { toast } = useToast()
const router = useRouter()
const { login } = useAuth()
const [isLoading, setIsLoading] = useState(false)
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
username: "",
password: "",
rememberMe: false,
},
})
async function onSubmit(values: z.infer<typeof formSchema>) {
setIsLoading(true)
try {
const response = await fetch("/api/reader/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(values),
})
// 从响应头中获取 Authorization token
const authToken = response.headers.get("Authorization")
if (!authToken) {
toast({
variant: "destructive",
title: "登录失败",
description: "未能获取授权令牌",
})
setIsLoading(false)
return
}
const result = await response.json()
if (result.code === 0) {
login(result.data, authToken)
toast({
title: "登录成功",
description: "欢迎回来," + result.data.username,
})
router.push("/")
} else {
toast({
variant: "destructive",
title: "登录失败",
description: result.msg || "用户名或密码错误",
})
}
} catch (error) {
toast({
variant: "destructive",
title: "登录失败",
description: "服务器连接错误,请稍后再试",
})
} finally {
setIsLoading(false)
}
}
return (
<div className="container relative flex min-h-screen flex-col items-center justify-center md:grid lg:max-w-none lg:grid-cols-2 lg:px-0">
<div className="absolute right-4 top-4 md:right-8 md:top-8">
<ThemeToggle />
</div>
<div className="relative hidden h-full flex-col bg-muted p-10 text-white lg:flex dark:border-r">
<div className="absolute inset-0 bg-zinc-900" />
<div className="relative z-20 flex items-center text-lg font-medium">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="mr-2 h-6 w-6"
>
<path d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
</svg>
</div>
<div className="relative z-20 mt-auto">
<blockquote className="space-y-2">
<p className="text-lg">"书籍是人类进步的阶梯。"</p>
<footer className="text-sm"></footer>
</blockquote>
</div>
</div>
<div className="lg:p-8">
<div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
<div className="flex flex-col space-y-2 text-center">
<h1 className="text-2xl font-semibold tracking-tight"></h1>
<p className="text-sm text-muted-foreground"></p>
</div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<FormControl>
<Input placeholder="请输入用户名" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<FormControl>
<Input type="password" placeholder="请输入密码" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="rememberMe"
render={({ field }) => (
<FormItem className="flex flex-row items-start space-x-3 space-y-0">
<FormControl>
<Checkbox checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
<div className="space-y-1 leading-none">
<FormLabel></FormLabel>
</div>
</FormItem>
)}
/>
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? "登录中..." : "登录"}
</Button>
</form>
</Form>
<div className="text-center text-sm text-muted-foreground">
?{" "}
<Link href="/register" className="underline underline-offset-4 hover:text-primary">
</Link>
</div>
</div>
</div>
</div>
)
}