"use client" import { useState, useEffect, useCallback } from "react" import { DashboardShell } from "@/components/dashboard-shell" import { DashboardHeader } from "@/components/dashboard-header" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" import { Input } from "@/components/ui/input" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Badge } from "@/components/ui/badge" import { Search, Edit, Eye, Loader2, Archive } from "lucide-react" import { AddPropDialog } from "@/components/props/add-prop-dialog" import type { Prop as ComponentProp } from "@/components/props/prop-detail-dialog" import { DeleteConfirmationDialog } from "@/components/delete-confirmation-dialog" import { PublishConfirmationDialog } from "@/components/publish-confirmation-dialog" import { useToast } from "@/components/ui/use-toast" import { isSuperUser } from "@/lib/api/auth" import { getProps, deleteProp, publishProp, archiveProp } from "@/lib/api/props" import type { Prop } from "@/lib/api/types" import Link from "next/link" // 格式化日期时间 function formatDate(dateStr: string): string { if (!dateStr) return "" try { return new Date(dateStr).toLocaleDateString("zh-CN", { year: "numeric", month: "2-digit", day: "2-digit", }) } catch { return dateStr } } // 将 API Prop 转换为组件显示用的 Prop function toDisplayProp(prop: Prop): ComponentProp { return { id: prop.id, name: prop.name, type: prop.category || "", rarity: prop.rarity || "", description: prop.description || "", releaseDate: formatDate(prop.publishedAt || prop.createdAt || ""), status: prop.status || "未发布", activatedCount: prop.activeCardsCount || 0, image: prop.imageUrl || "/placeholder.svg?height=300&width=300", } } export default function PropsPage() { const { toast } = useToast() const [props, setProps] = useState([]) const [searchTerm, setSearchTerm] = useState("") const [currentPage, setCurrentPage] = useState(1) const [totalItems, setTotalItems] = useState(0) const [selectedProp, setSelectedProp] = useState(null) const [isEditDialogOpen, setIsEditDialogOpen] = useState(false) const [loading, setLoading] = useState(true) const itemsPerPage = 10 // 从后端获取道具列表 const fetchProps = useCallback(async () => { try { setLoading(true) const response = await getProps({ page: currentPage, pageSize: itemsPerPage, search: searchTerm || undefined, }) setProps(response.items.map(toDisplayProp)) setTotalItems(response.total) } catch (error) { console.error("获取道具列表失败:", error) toast({ title: "获取失败", description: "无法获取道具列表,请稍后重试", variant: "destructive", }) } finally { setLoading(false) } }, [currentPage, searchTerm, toast]) useEffect(() => { fetchProps() }, [fetchProps]) const totalPages = Math.ceil(totalItems / itemsPerPage) // 处理添加道具 const handleAddProp = (newProp: ComponentProp) => { // 添加后刷新列表 fetchProps() toast({ title: "添加成功", description: `道具 ${newProp.name} 已成功添加`, }) } // 处理编辑道具 const handleEditProp = (updatedProp: ComponentProp) => { // 编辑后刷新列表 fetchProps() setSelectedProp(null) setIsEditDialogOpen(false) toast({ title: "更新成功", description: `道具 ${updatedProp.name} 已成功更新`, }) } // 处理删除道具 - 调用真实的后端 API const handleDeleteProp = async (propId: string) => { try { await deleteProp(propId) // 删除后刷新列表 await fetchProps() toast({ title: "删除成功", description: "道具已成功删除", variant: "destructive", }) } catch (error) { console.error("删除道具失败:", error) toast({ title: "删除失败", description: "无法删除道具,请稍后重试", variant: "destructive", }) } } // 发布道具 const handlePublishProp = async (propId: string, propName: string) => { try { await publishProp(propId) await fetchProps() toast({ title: "发布成功", description: `道具 "${propName}" 已成功发布`, }) } catch (error) { console.error("发布道具失败:", error) toast({ title: "发布失败", description: "无法发布道具,请稍后重试", variant: "destructive", }) } } // 归档道具 const handleArchiveProp = async (propId: string, propName: string) => { try { await archiveProp(propId) await fetchProps() toast({ title: "归档成功", description: `道具 "${propName}" 已归档`, }) } catch (error) { console.error("归档道具失败:", error) toast({ title: "归档失败", description: "无法归档道具,请稍后重试", variant: "destructive", }) } } // 打开编辑对话框 const openEditDialog = (prop: ComponentProp) => { setSelectedProp(prop) setIsEditDialogOpen(true) } return (
{ setSearchTerm(e.target.value) setCurrentPage(1) }} />
道具列表
管理洛天依可以使用的道具
{loading ? (
加载中...
) : ( ID 道具名称 类型 稀有度 发布日期 状态 激活数量 操作 {props.map((prop) => ( {prop.id} {prop.name} {prop.type} {prop.rarity} {prop.releaseDate || "-"} {prop.status} {prop.activatedCount} {/* 草稿状态:显示发布按钮 */} {prop.status === "草稿" && ( handlePublishProp(prop.id, prop.name)} /> )} {/* 已发布状态:显示归档按钮 */} {prop.status === "已发布" && ( )} {(prop.status !== "已发布" || isSuperUser()) && ( <> handleDeleteProp(prop.id)} /> )} ))} {props.length === 0 && ( 没有找到匹配的道具 )}
)}
显示 {props.length > 0 ? (currentPage - 1) * itemsPerPage + 1 : 0}- {Math.min(currentPage * itemsPerPage, totalItems)} 共 {totalItems} 个道具
{/* 编辑道具对话框 - 当选中道具时显示 */} {selectedProp && isEditDialogOpen && ( )}
) }