"use client" import { AdminNav } from "@/components/admin-nav" import { ThemeToggle } from "@/components/theme-toggle" import { Button } from "@/components/ui/button" import { Calendar } from "@/components/ui/calendar" import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" import { Combobox } from "@/components/ui/combobox" import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form" import { Input } from "@/components/ui/input" import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover" import { Skeleton } from "@/components/ui/skeleton" import { Textarea } from "@/components/ui/textarea" import { useToast } from "@/components/ui/use-toast" import { useAuth } from "@/context/auth-context" import { fetchWithAuth } from "@/lib/api" import { zodResolver } from "@hookform/resolvers/zod" import { format } from "date-fns" import { ArrowLeft, BookOpen, CalendarIcon, ImageIcon, Loader2, Save, X } from "lucide-react" import { useRouter } from "next/navigation" import { useEffect, useState, use } from "react" import { useFieldArray, useForm } from "react-hook-form" import * as z from "zod" import { Plus } from "lucide-react" interface Publisher { publisherId: number name: string address: string } interface BookDetail { bookId: number title: string isbn: string price: number stock: number publishDate: string publisherId: number publisherName: string description: string coverImage: string author: string[] } const formSchema = z.object({ title: z.string().min(1, "标题不能为空"), isbn: z.string().min(1, "ISBN不能为空"), price: z.coerce.number().min(0, "价格不能为负数"), stock: z.coerce.number().min(0, "库存不能为负数").int("库存必须是整数"), publishDate: z.date(), publisherId: z.coerce.number(), description: z.string().optional(), coverImage: z.string().optional(), authors: z .array( z.object({ name: z.string().min(1, "作者名不能为空"), }), ) .min(1, "至少需要一位作者"), }) export default function EditBookPage({ params }: { params: Promise<{ id: string }> | { id: string } }) { // 使用 React.use() 解包 params const resolvedParams = "then" in params ? use(params) : params const bookId = resolvedParams.id const { user } = useAuth() const router = useRouter() const { toast } = useToast() const [publishers, setPublishers] = useState([]) const [book, setBook] = useState(null) const [loading, setLoading] = useState(true) const [submitting, setSubmitting] = useState(false) const [coverPreview, setCoverPreview] = useState(null) const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { title: "", isbn: "", price: 0, stock: 0, publishDate: new Date(), publisherId: 0, description: "", coverImage: "", authors: [{ name: "" }], }, }) const { fields, append, remove } = useFieldArray({ control: form.control, name: "authors", }) // 监听封面图片URL变化,更新预览 const coverImageValue = form.watch("coverImage") useEffect(() => { if (coverImageValue) { setCoverPreview(coverImageValue) } }, [coverImageValue]) useEffect(() => { // 检查用户是否登录且是管理员 if (!user) { toast({ title: "请先登录", description: "您需要登录后才能访问管理页面", variant: "destructive", }) router.push("/login") return } if (!user.isAdmin) { toast({ title: "权限不足", description: "您没有管理员权限", variant: "destructive", }) router.push("/") return } // 获取出版社列表 const fetchPublishers = async () => { try { const response = await fetchWithAuth("publisher/all") const result = await response.json() if (result.code === 0) { setPublishers(result.data) } else { toast({ variant: "destructive", title: "获取出版社失败", description: result.msg || "无法获取出版社信息", }) } } catch (error) { toast({ variant: "destructive", title: "获取出版社失败", description: "服务器连接错误,请稍后再试", }) } } // 获取图书详情 const fetchBookDetail = async () => { try { const response = await fetchWithAuth(`book/${bookId}`) const result = await response.json() if (result.code === 0) { setBook(result.data) setCoverPreview(result.data.coverImage) // 设置表单默认值 form.reset({ title: result.data.title, isbn: result.data.isbn, price: result.data.price, stock: result.data.stock, publishDate: new Date(result.data.publishDate), publisherId: result.data.publisherId, description: result.data.description || "", coverImage: result.data.coverImage || "", authors: result.data.author.map((name: string) => ({ name })), }) } else { toast({ variant: "destructive", title: "获取图书失败", description: result.msg || "无法获取图书信息", }) router.push("/admin/books") } } catch (error) { toast({ variant: "destructive", title: "获取图书失败", description: "服务器连接错误,请稍后再试", }) router.push("/admin/books") } finally { setLoading(false) } } Promise.all([fetchPublishers(), fetchBookDetail()]) }, [user, router, toast, bookId, form]) const onSubmit = async (values: z.infer) => { if (!book) return setSubmitting(true) try { const bookData = { ...values, authors: values.authors.map((author) => author.name), } const response = await fetchWithAuth(`book/admin/update/${book.bookId}`, { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify(bookData), }) const result = await response.json() if (result.code === 0) { toast({ title: "更新成功", description: "图书信息已成功更新", }) router.push("/admin/books") } else { toast({ variant: "destructive", title: "更新失败", description: result.msg || "无法更新图书信息", }) } } catch (error) { toast({ variant: "destructive", title: "更新失败", description: "服务器连接错误,请稍后再试", }) } finally { setSubmitting(false) } } if (!user || !user.isAdmin) { return null } return (
图书管理系统 - 管理后台

编辑图书

{!loading && book && (
图书ID: {book.bookId}
)}
{loading ? (
{Array.from({ length: 6 }).map((_, i) => (
))}
) : (
基本信息 编辑图书的基本信息 ( 标题 )} /> ( ISBN )} />
( 价格 )} /> ( 库存 )} />
( 出版日期 )} /> ( 出版社 ({ label: publisher.name, value: publisher.publisherId.toString(), }))} value={field.value.toString()} onChange={(value) => field.onChange(Number.parseInt(value))} placeholder="选择出版社" /> )} />
封面与描述 编辑图书的封面和描述信息 ( 封面图片URL 输入图书封面的URL地址 )} />

封面预览

{coverPreview ? ( 封面预览 setCoverPreview(null)} /> ) : (

无封面图片

)}
( 描述