2026-03-17 13:17:02 +08:00

284 lines
10 KiB
TypeScript

"use client"
import { useState } 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 } from "lucide-react"
import { AddPropDialog } from "@/components/props/add-prop-dialog"
import type { Prop } from "@/components/props/prop-detail-dialog"
import { DeleteConfirmationDialog } from "@/components/delete-confirmation-dialog"
import { useToast } from "@/components/ui/use-toast"
import Link from "next/link"
// 初始道具数据
const initialProps: Prop[] = [
{
id: "PRP001",
name: "魔法麦克风",
type: "演出道具",
rarity: "稀有",
description: "洛天依的经典原创道具,可以增强歌声的魔力,让听众更加沉浸在音乐中。",
releaseDate: "2023-11-15",
status: "已发布",
activatedCount: 1245,
image: "/placeholder.svg?height=300&width=300",
},
{
id: "PRP002",
name: "星光魔杖",
type: "互动道具",
rarity: "史诗",
description: "挥舞魔杖可以创造出美丽的星光效果,增加互动时的好感度。",
releaseDate: "2023-12-01",
status: "已发布",
activatedCount: 876,
image: "/placeholder.svg?height=300&width=300",
},
{
id: "PRP003",
name: "音乐盒",
type: "收藏品",
rarity: "传说",
description: "精美的音乐盒,打开后会播放洛天依的经典歌曲,是珍贵的收藏品。",
releaseDate: "2024-01-10",
status: "已发布",
activatedCount: 532,
image: "/placeholder.svg?height=300&width=300",
},
{
id: "PRP004",
name: "虚拟相机",
type: "互动道具",
rarity: "稀有",
description: "可以捕捉洛天依的精彩瞬间,保存为虚拟照片。",
releaseDate: "2024-02-05",
status: "已发布",
activatedCount: 967,
image: "/placeholder.svg?height=300&width=300",
},
{
id: "PRP005",
name: "节日礼盒",
type: "限定道具",
rarity: "史诗",
description: "节日限定礼盒,内含多种惊喜道具和装饰品。",
releaseDate: "",
status: "未发布",
activatedCount: 0,
image: "/placeholder.svg?height=300&width=300",
},
]
export default function PropsPage() {
const { toast } = useToast()
const [props, setProps] = useState<Prop[]>(initialProps)
const [searchTerm, setSearchTerm] = useState("")
const [currentPage, setCurrentPage] = useState(1)
const [selectedProp, setSelectedProp] = useState<Prop | null>(null)
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false)
const itemsPerPage = 5
// 过滤和分页
const filteredProps = props.filter(
(prop) =>
prop.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
prop.id.toLowerCase().includes(searchTerm.toLowerCase()) ||
prop.type.toLowerCase().includes(searchTerm.toLowerCase()),
)
const totalPages = Math.ceil(filteredProps.length / itemsPerPage)
const paginatedProps = filteredProps.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage)
// 处理添加道具
const handleAddProp = (newProp: Prop) => {
setProps((prevProps) => [...prevProps, newProp])
toast({
title: "添加成功",
description: `道具 ${newProp.name} 已成功添加`,
})
}
// 处理编辑道具
const handleEditProp = (updatedProp: Prop) => {
setProps((prevProps) => prevProps.map((prop) => (prop.id === updatedProp.id ? updatedProp : prop)))
setSelectedProp(null)
setIsEditDialogOpen(false)
toast({
title: "更新成功",
description: `道具 ${updatedProp.name} 已成功更新`,
})
}
// 处理删除道具
const handleDeleteProp = async (propId: string) => {
// 模拟API请求
await new Promise((resolve) => setTimeout(resolve, 1000))
setProps((prevProps) => prevProps.filter((prop) => prop.id !== propId))
toast({
title: "删除成功",
description: "道具已成功删除",
variant: "destructive",
})
}
// 打开编辑对话框
const openEditDialog = (prop: Prop) => {
setSelectedProp(prop)
setIsEditDialogOpen(true)
}
return (
<DashboardShell>
<DashboardHeader heading="道具管理" text="管理洛天依的道具卡牌">
<AddPropDialog onSave={handleAddProp} />
</DashboardHeader>
<div className="flex items-center justify-between space-y-2 mb-6">
<div className="flex items-center space-x-2">
<div className="relative">
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
type="search"
placeholder="搜索道具..."
className="w-[300px] pl-8 border-none bg-white shadow-md focus-visible:ring-pink-500"
value={searchTerm}
onChange={(e) => {
setSearchTerm(e.target.value)
setCurrentPage(1) // 重置到第一页
}}
/>
</div>
</div>
</div>
<Card className="border-none shadow-lg bg-gradient-to-br from-white to-purple-50">
<CardHeader>
<CardTitle className="text-xl font-bold flex items-center">
<span className="bg-clip-text text-transparent bg-gradient-to-r from-purple-600 to-pink-600"></span>
<div className="ml-2 h-1 w-10 bg-gradient-to-r from-purple-600 to-pink-600 rounded-full"></div>
</CardTitle>
<CardDescription>使</CardDescription>
</CardHeader>
<CardContent>
<Table>
<TableHeader className="bg-gray-50">
<TableRow>
<TableHead className="w-[100px]">ID</TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{paginatedProps.map((prop) => (
<TableRow key={prop.id} className="hover:bg-gray-50 transition-colors">
<TableCell className="font-medium">{prop.id}</TableCell>
<TableCell className="font-medium text-pink-600">{prop.name}</TableCell>
<TableCell>{prop.type}</TableCell>
<TableCell>{prop.rarity}</TableCell>
<TableCell>{prop.releaseDate || "-"}</TableCell>
<TableCell>
<Badge
className={
prop.status === "已发布" ? "bg-green-500 hover:bg-green-600" : "bg-gray-500 hover:bg-gray-600"
}
>
{prop.status}
</Badge>
</TableCell>
<TableCell className="font-medium">{prop.activatedCount}</TableCell>
<TableCell className="text-right">
{/* 将详情对话框替换为链接按钮 */}
<Button variant="ghost" size="icon" className="hover:bg-pink-50 hover:text-pink-600" asChild>
<Link href={`/props/${prop.id}`}>
<Eye className="h-4 w-4" />
<span className="sr-only"></span>
</Link>
</Button>
{prop.status !== "已发布" && (
<>
<Button
variant="ghost"
size="icon"
className="hover:bg-pink-50 hover:text-pink-600"
onClick={() => openEditDialog(prop)}
>
<Edit className="h-4 w-4" />
</Button>
<DeleteConfirmationDialog
title="删除道具"
description="此操作将永久删除该道具及其所有相关数据。"
itemName={prop.name}
onDelete={() => handleDeleteProp(prop.id)}
/>
</>
)}
</TableCell>
</TableRow>
))}
{paginatedProps.length === 0 && (
<TableRow>
<TableCell colSpan={8} className="h-24 text-center">
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</CardContent>
<CardFooter className="flex justify-between">
<div className="text-sm text-muted-foreground">
{paginatedProps.length > 0 ? (currentPage - 1) * itemsPerPage + 1 : 0}-
{Math.min(currentPage * itemsPerPage, filteredProps.length)} {filteredProps.length}
</div>
<div className="flex items-center space-x-2">
<Button
variant="outline"
size="sm"
className="hover:bg-pink-50 hover:text-pink-700 transition-all duration-200"
onClick={() => setCurrentPage((prev) => Math.max(prev - 1, 1))}
disabled={currentPage === 1}
>
</Button>
<Button
variant="outline"
size="sm"
className="hover:bg-pink-50 hover:text-pink-700 transition-all duration-200"
onClick={() => setCurrentPage((prev) => Math.min(prev + 1, totalPages))}
disabled={currentPage === totalPages || totalPages === 0}
>
</Button>
</div>
</CardFooter>
</Card>
{/* 编辑道具对话框 - 当选中道具时显示 */}
{selectedProp && isEditDialogOpen && (
<AddPropDialog
mode="edit"
initialProp={selectedProp}
open={isEditDialogOpen}
onOpenChange={setIsEditDialogOpen}
onSave={handleEditProp}
/>
)}
</DashboardShell>
)
}