80 lines
3.3 KiB
TypeScript
80 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
import { useParams } from "next/navigation";
|
|
import type { Pet, Schedule } from "@/types";
|
|
import { Card } from "@/components/ui/Card";
|
|
import { Button } from "@/components/ui/Button";
|
|
import { PetCard } from "@/components/pet/PetCard";
|
|
import { ScheduleCard } from "@/components/pet/ScheduleCard";
|
|
import { EmptyState } from "@/components/ui/EmptyState";
|
|
|
|
export default function PetDetailPage() {
|
|
const params = useParams();
|
|
const [pet, setPet] = useState<Pet | null>(null);
|
|
const [schedules, setSchedules] = useState<Schedule[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
// TODO: Replace with actual API call
|
|
const loadData = async () => {
|
|
setLoading(true);
|
|
// Simulated data
|
|
setPet({
|
|
id: params.id as string,
|
|
ownerId: "u1",
|
|
name: "毛球",
|
|
species: "猫",
|
|
breed: "英短",
|
|
birthDate: "2023-03-15",
|
|
weightKg: 4.5,
|
|
avatarUrl: "",
|
|
createdAt: new Date().toISOString(),
|
|
});
|
|
setSchedules([
|
|
{ id: "s1", petId: params.id as string, type: "vaccine", title: "年度疫苗", scheduledAt: "2026-07-01T09:00:00Z", completed: false },
|
|
{ id: "s2", petId: params.id as string, type: "deworming", title: "季度驱虫", scheduledAt: "2026-06-15T10:00:00Z", completed: false },
|
|
{ id: "s3", petId: params.id as string, type: "checkup", title: "体检", scheduledAt: "2026-05-20T14:00:00Z", completed: true },
|
|
]);
|
|
setLoading(false);
|
|
};
|
|
loadData();
|
|
}, [params.id]);
|
|
|
|
if (loading) return <div className="flex justify-center py-16"><div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500" /></div>;
|
|
if (!pet) return <EmptyState icon="🐾" title="未找到宠物" description="该宠物可能已被删除" />;
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Pet Profile */}
|
|
<div className="bg-gradient-to-br from-amber-100 to-orange-100 rounded-2xl p-6 text-center">
|
|
<div className="w-24 h-24 mx-auto rounded-full bg-white shadow flex items-center justify-center text-5xl">
|
|
{pet.avatarUrl ? <img src={pet.avatarUrl} alt={pet.name} className="w-full h-full rounded-full object-cover" /> : "🐱"}
|
|
</div>
|
|
<h1 className="text-2xl font-bold text-gray-800 mt-3">{pet.name}</h1>
|
|
<p className="text-sm text-gray-500">{pet.breed} · {pet.weightKg}kg · {pet.species}</p>
|
|
</div>
|
|
|
|
{/* Health Schedule */}
|
|
<section>
|
|
<h2 className="text-lg font-semibold text-gray-800 mb-3">健康日程</h2>
|
|
<div className="space-y-2">
|
|
{schedules.length > 0 ? schedules.map(s => <ScheduleCard key={s.id} schedule={s} />) : <EmptyState icon="📅" title="暂无日程" />}
|
|
</div>
|
|
</section>
|
|
|
|
{/* Quick Info */}
|
|
<div className="grid grid-cols-2 gap-3">
|
|
<Card className="text-center">
|
|
<p className="text-2xl font-bold text-gray-800">{pet.weightKg}</p>
|
|
<p className="text-xs text-gray-500">体重 (kg)</p>
|
|
</Card>
|
|
<Card className="text-center">
|
|
<p className="text-2xl font-bold text-gray-800">{new Date().getFullYear() - new Date(pet.birthDate).getFullYear()}岁</p>
|
|
<p className="text-xs text-gray-500">年龄</p>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|