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

299 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import { useState, useEffect } from "react"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { DashboardShell } from "@/components/dashboard-shell"
import { DashboardHeader } from "@/components/dashboard-header"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { ArrowLeft, Edit, AlertTriangle, FileText, Loader2 } from "lucide-react"
import Link from "next/link"
import { AddPrintBatchDialog } from "@/components/food/add-print-batch-dialog"
import { ExportCardsDialog } from "@/components/food/export-cards-dialog"
import { useToast } from "@/components/ui/use-toast"
import { getFood } from "@/lib/api/food"
import type { Food } from "@/components/food/food-detail-dialog"
// 扩展Food类型以包含批次相关信息
type FoodWithBatches = Food & {
printedCount?: number
batches?: Array<{
id: string
date: string
quantity: number
startId: string
endId: string
activatedCount: number
}>
}
export default function FoodDetailPage({ params }: { params: { id: string } }) {
const { toast } = useToast()
const [food, setFood] = useState<FoodWithBatches | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
// 获取食物详情
const fetchFoodDetail = async () => {
try {
setLoading(true)
setError(null)
const response = await getFood(params.id)
if (response.success && response.data) {
// 为演示目的,添加一些模拟的批次数据
const foodWithBatches: FoodWithBatches = {
...response.data,
printedCount: response.data.activatedCount + Math.floor(Math.random() * 1000),
batches: [
{
id: "B001",
date: "2023-08-01",
quantity: 2000,
startId: `${response.data.id}-0001`,
endId: `${response.data.id}-2000`,
activatedCount: Math.floor(response.data.activatedCount * 0.6),
},
{
id: "B002",
date: "2023-11-15",
quantity: 1000,
startId: `${response.data.id}-2001`,
endId: `${response.data.id}-3000`,
activatedCount: Math.floor(response.data.activatedCount * 0.4),
},
]
}
setFood(foodWithBatches)
} else {
setError("食物不存在或获取失败")
}
} catch (error) {
console.error("获取食物详情失败:", error)
setError(error instanceof Error ? error.message : "获取食物详情失败")
toast({
title: "获取数据失败",
description: error instanceof Error ? error.message : "无法获取食物详情",
variant: "destructive",
})
} finally {
setLoading(false)
}
}
useEffect(() => {
fetchFoodDetail()
}, [params.id])
if (loading) {
return (
<DashboardShell>
<div className="flex items-center justify-center h-[60vh]">
<Loader2 className="h-8 w-8 animate-spin text-pink-500" />
<span className="ml-2 text-gray-500">...</span>
</div>
</DashboardShell>
)
}
if (error || !food) {
return (
<DashboardShell>
<div className="flex flex-col items-center justify-center h-[60vh]">
<AlertTriangle className="h-16 w-16 text-red-500 mb-4" />
<h1 className="text-2xl font-bold mb-2"></h1>
<p className="text-gray-500 mb-6">
{error || `找不到ID为 ${params.id} 的食物`}
</p>
<Button asChild>
<Link href="/food">
<ArrowLeft className="mr-2 h-4 w-4" />
</Link>
</Button>
</div>
</DashboardShell>
)
}
const isPublished = food.status === "已发布"
return (
<DashboardShell>
<div className="absolute top-0 right-0 w-1/2 h-48 bg-gradient-to-bl from-pink-200 via-orange-200 to-transparent opacity-20 rounded-bl-full" />
<div className="flex items-center mb-6">
<Button variant="ghost" size="sm" className="mr-4" asChild>
<Link href="/food">
<ArrowLeft className="mr-2 h-4 w-4" />
</Link>
</Button>
<DashboardHeader heading={food.name} text={`食物ID: ${food.id}`}>
<div className="flex space-x-2 ml-auto">
{!isPublished && (
<Button
asChild
className="bg-gradient-to-r from-pink-500 to-purple-600 hover:from-pink-600 hover:to-purple-700 transition-all duration-300 shadow-md hover:shadow-lg"
>
<Link href={`/food/edit/${params.id}`}>
<Edit className="mr-2 h-4 w-4" />
</Link>
</Button>
)}
<ExportCardsDialog foodId={food.id} />
</div>
</DashboardHeader>
</div>
<Tabs defaultValue="details" className="space-y-4">
<TabsList>
<TabsTrigger value="details"></TabsTrigger>
<TabsTrigger value="batches"></TabsTrigger>
<TabsTrigger value="analytics"></TabsTrigger>
</TabsList>
<TabsContent value="details" className="space-y-4">
<div className="grid gap-6 md:grid-cols-3">
<Card className="md:col-span-1 border-none shadow-lg bg-white">
<CardHeader>
<CardTitle className="text-lg font-bold"></CardTitle>
</CardHeader>
<CardContent className="flex justify-center">
<div className="relative w-full aspect-square max-w-[300px] rounded-lg overflow-hidden bg-gray-100 flex items-center justify-center">
<img src={food.image || "/placeholder.svg"} alt={food.name} className="object-cover" />
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-3">
<Badge className={`${isPublished ? "bg-green-500" : "bg-gray-500"}`}>{food.status}</Badge>
</div>
</div>
</CardContent>
</Card>
<Card className="md:col-span-2 border-none shadow-lg bg-gradient-to-br from-white to-purple-50">
<CardHeader>
<CardTitle className="text-lg font-bold"></CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-1">
<p className="text-sm font-medium text-gray-500"></p>
<p className="font-medium">{food.type}</p>
</div>
<div className="space-y-1">
<p className="text-sm font-medium text-gray-500"></p>
<p className="font-medium">{food.rarity}</p>
</div>
<div className="space-y-1">
<p className="text-sm font-medium text-gray-500"></p>
<p className="font-medium">{food.releaseDate || "尚未发布"}</p>
</div>
<div className="space-y-1">
<p className="text-sm font-medium text-gray-500"></p>
<p className="font-medium">{food.status}</p>
</div>
<div className="space-y-1">
<p className="text-sm font-medium text-gray-500"></p>
<p className="font-medium">{food.activatedCount}</p>
</div>
<div className="space-y-1">
<p className="text-sm font-medium text-gray-500"></p>
<p className="font-medium">{food.printedCount || 0}</p>
</div>
<div className="col-span-2 space-y-1">
<p className="text-sm font-medium text-gray-500"></p>
<p className="font-medium">{food.description}</p>
</div>
</div>
{isPublished && (
<div className="mt-6 p-3 bg-amber-50 border border-amber-200 rounded-lg flex items-start">
<AlertTriangle className="h-5 w-5 text-amber-500 mr-2 flex-shrink-0 mt-0.5" />
<p className="text-sm text-amber-700"></p>
</div>
)}
</CardContent>
</Card>
</div>
</TabsContent>
<TabsContent value="batches" className="space-y-4">
<Card className="border-none shadow-lg bg-gradient-to-br from-white to-blue-50">
<CardHeader className="flex flex-row items-center justify-between">
<div>
<CardTitle className="text-lg font-bold"></CardTitle>
<CardDescription>ID</CardDescription>
</div>
<AddPrintBatchDialog foodId={food.id} isPublished={isPublished} />
</CardHeader>
<CardContent>
<div className="rounded-md border">
<table className="w-full">
<thead>
<tr className="bg-gray-50 border-b">
<th className="py-3 px-4 text-left text-sm font-medium text-gray-500">ID</th>
<th className="py-3 px-4 text-left text-sm font-medium text-gray-500"></th>
<th className="py-3 px-4 text-left text-sm font-medium text-gray-500"></th>
<th className="py-3 px-4 text-left text-sm font-medium text-gray-500">ID</th>
<th className="py-3 px-4 text-left text-sm font-medium text-gray-500">ID</th>
<th className="py-3 px-4 text-left text-sm font-medium text-gray-500"></th>
<th className="py-3 px-4 text-right text-sm font-medium text-gray-500"></th>
</tr>
</thead>
<tbody>
{food.batches?.map((batch) => (
<tr key={batch.id} className="border-b hover:bg-gray-50">
<td className="py-3 px-4 text-sm font-medium">{batch.id}</td>
<td className="py-3 px-4 text-sm">{batch.date}</td>
<td className="py-3 px-4 text-sm">{batch.quantity}</td>
<td className="py-3 px-4 text-sm font-mono text-xs">{batch.startId}</td>
<td className="py-3 px-4 text-sm font-mono text-xs">{batch.endId}</td>
<td className="py-3 px-4 text-sm">{batch.activatedCount}</td>
<td className="py-3 px-4 text-right">
<Button variant="ghost" size="sm" className="h-8 hover:bg-blue-50 hover:text-blue-600">
<FileText className="h-4 w-4 mr-1" />
ID
</Button>
</td>
</tr>
))}
{(!food.batches || food.batches.length === 0) && (
<tr>
<td colSpan={7} className="py-8 text-center text-gray-500">
</td>
</tr>
)}
</tbody>
</table>
</div>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="analytics" className="space-y-4">
<Card className="border-none shadow-lg bg-gradient-to-br from-white to-green-50">
<CardHeader>
<CardTitle className="text-lg font-bold"></CardTitle>
<CardDescription>使</CardDescription>
</CardHeader>
<CardContent>
<div className="grid gap-6 md:grid-cols-2">
<div className="h-[300px] bg-gray-50 rounded-lg flex items-center justify-center">
<p className="text-gray-500"></p>
</div>
<div className="h-[300px] bg-gray-50 rounded-lg flex items-center justify-center">
<p className="text-gray-500"></p>
</div>
<div className="md:col-span-2 h-[300px] bg-gray-50 rounded-lg flex items-center justify-center">
<p className="text-gray-500"></p>
</div>
</div>
</CardContent>
</Card>
</TabsContent>
</Tabs>
</DashboardShell>
)
}