feat(ui): refine public detail pages

This commit is contained in:
zetaloop
2026-04-25 20:12:23 +08:00
parent 93b880f932
commit 151fabe8c2
3 changed files with 97 additions and 42 deletions
+43 -27
View File
@@ -10,10 +10,12 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { EmptyState } from "@/components/ui/empty-state"
import { Separator } from "@/components/ui/separator"
import { StatusBadge } from "@/components/ui/status-badge"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { getPlayerById, listReviewsByTargetUser, listServicesByPlayer } from "@/lib/api"
import { CheckCircle, Clock, MapPin, MessageSquare, ShoppingBag, Star } from "lucide-react"
import { Clock, Gamepad2, MapPin, MessageSquare, ShoppingBag, Star } from "lucide-react"
import Link from "next/link"
import { notFound } from "next/navigation"
@@ -34,7 +36,7 @@ export default async function PlayerDetailPage({ params }: { params: Promise<{ i
<div className="container mx-auto py-8 px-4 max-w-5xl">
<div className="flex flex-col md:flex-row gap-8 mb-8">
<div className="flex-shrink-0">
<Avatar className="w-32 h-32 border-4 border-background shadow-card">
<Avatar className="w-32 h-32 border border-border shadow-sm">
<AvatarImage src={player.user.avatar} alt={player.user.nickname} />
<AvatarFallback>{player.user.nickname[0]}</AvatarFallback>
</Avatar>
@@ -45,16 +47,26 @@ export default async function PlayerDetailPage({ params }: { params: Promise<{ i
<div>
<h1 className="text-3xl font-bold flex items-center gap-3">
{player.user.nickname}
<Badge
variant={player.status === "available" ? "default" : "secondary"}
className="text-sm"
<StatusBadge
status={
player.status === "available"
? "success"
: player.status === "busy"
? "warning"
: "neutral"
}
className="text-sm font-normal"
>
{player.status === "available" ? "可接单" : "忙碌中"}
</Badge>
{player.status === "available"
? "可接单"
: player.status === "busy"
? "忙碌中"
: "离线"}
</StatusBadge>
</h1>
<div className="flex items-center gap-2 mt-2 text-muted-foreground">
<div className="flex items-center text-yellow-500">
<Star className="w-4 h-4 fill-current" />
<div className="flex items-center text-warning">
<Star className="w-4 h-4 fill-warning" />
<span className="ml-1 font-medium text-foreground">{player.rating}</span>
</div>
<Separator orientation="vertical" className="h-4" />
@@ -75,11 +87,13 @@ export default async function PlayerDetailPage({ params }: { params: Promise<{ i
<FavoriteButton initialFavorited={false} targetType="player" targetId={player.id} />
</div>
<div className="bg-muted/50 p-4 rounded-xl">
<p className="text-sm leading-relaxed">
{player.user.bio || "这个打手很懒,什么都没写~"}
</p>
</div>
{player.user.bio ? (
<div className="bg-muted/50 p-4 rounded-xl border border-border/50">
<p className="text-sm leading-relaxed">{player.user.bio}</p>
</div>
) : (
<EmptyState className="min-h-[120px] p-6" title="暂无个人简介" />
)}
<div className="flex flex-wrap gap-2">
{player.tags.map((tag) => (
@@ -103,7 +117,9 @@ export default async function PlayerDetailPage({ params }: { params: Promise<{ i
<Card key={service.id} className="flex flex-col h-full">
<CardHeader>
<div className="flex justify-between items-start">
<Badge variant="outline">{service.gameName}</Badge>
<Badge variant="info" className="font-normal">
{service.gameName}
</Badge>
<div className="text-lg font-bold text-primary">
¥{service.price}{" "}
<span className="text-sm text-muted-foreground font-normal">
@@ -140,8 +156,12 @@ export default async function PlayerDetailPage({ params }: { params: Promise<{ i
</Card>
))}
{playerServices.length === 0 && (
<div className="col-span-full text-center py-12 text-muted-foreground">
<p></p>
<div className="col-span-full">
<EmptyState
title="暂无服务"
description="该陪玩尚未添加任何服务项"
icon={Gamepad2}
/>
</div>
)}
</div>
@@ -166,21 +186,20 @@ export default async function PlayerDetailPage({ params }: { params: Promise<{ i
{new Date(review.createdAt).toLocaleDateString()}
</div>
</div>
<div className="flex items-center text-yellow-500">
<div className="flex items-center text-warning">
{[1, 2, 3, 4, 5].map((star) => (
<Star
key={star}
className={`w-4 h-4 ${star <= review.rating ? "fill-current" : "text-muted stroke-muted-foreground"}`}
className={`w-4 h-4 ${star <= review.rating ? "fill-warning" : "text-muted stroke-muted-foreground"}`}
/>
))}
</div>
</div>
<p className="text-sm text-foreground/90">{review.content}</p>
{review.sealed && (
<div className="flex items-center gap-1 text-xs text-green-600 bg-green-50 w-fit px-2 py-1 rounded-full">
<CheckCircle className="w-3 h-3" />
<span></span>
</div>
<StatusBadge status="success" className="text-xs font-normal">
</StatusBadge>
)}
</div>
</div>
@@ -188,10 +207,7 @@ export default async function PlayerDetailPage({ params }: { params: Promise<{ i
</Card>
))
) : (
<div className="text-center py-12 text-muted-foreground">
<MessageSquare className="w-12 h-12 mx-auto mb-4 opacity-20" />
<p></p>
</div>
<EmptyState title="暂无评价" description="还没有收到任何评价" icon={MessageSquare} />
)}
</div>
</TabsContent>