feat: order creation page and link from player detail service cards
This commit is contained in:
@@ -150,7 +150,9 @@ export default async function PlayerDetailPage({ params }: { params: Promise<{ i
|
|||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardFooter>
|
<CardFooter>
|
||||||
<Button className="w-full">立即下单</Button>
|
<Button className="w-full" asChild>
|
||||||
|
<Link href={`/order/new?serviceId=${service.id}`}>立即下单</Link>
|
||||||
|
</Button>
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -0,0 +1,178 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { ArrowLeft, CheckCircle, CreditCard, ShieldCheck } from "lucide-react"
|
||||||
|
import Link from "next/link"
|
||||||
|
import { useSearchParams } from "next/navigation"
|
||||||
|
import { useState } from "react"
|
||||||
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
|
import { Input } from "@/components/ui/input"
|
||||||
|
import { Label } from "@/components/ui/label"
|
||||||
|
import { Separator } from "@/components/ui/separator"
|
||||||
|
import { Textarea } from "@/components/ui/textarea"
|
||||||
|
import { mockPlayers, mockServices, walletBalance } from "@/lib/mock-data"
|
||||||
|
|
||||||
|
export default function NewOrderPage() {
|
||||||
|
const searchParams = useSearchParams()
|
||||||
|
const serviceId = searchParams.get("serviceId")
|
||||||
|
|
||||||
|
const service = mockServices.find((s) => s.id === serviceId)
|
||||||
|
const player = service ? mockPlayers.find((p) => p.id === service.playerId) : null
|
||||||
|
|
||||||
|
const [quantity, setQuantity] = useState(1)
|
||||||
|
const [note, setNote] = useState("")
|
||||||
|
const [submitted, setSubmitted] = useState(false)
|
||||||
|
|
||||||
|
if (!service || !player) {
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto py-8 px-4 text-center text-muted-foreground">
|
||||||
|
服务不存在
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalPrice = service.price * quantity
|
||||||
|
|
||||||
|
if (submitted) {
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto py-8 px-4 max-w-lg text-center space-y-4">
|
||||||
|
<CheckCircle className="h-12 w-12 mx-auto text-green-500" />
|
||||||
|
<h2 className="text-xl font-bold">下单成功</h2>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
订单已创建,等待打手接单。你可以在订单列表中查看进度。
|
||||||
|
</p>
|
||||||
|
<div className="flex gap-2 justify-center">
|
||||||
|
<Button asChild>
|
||||||
|
<Link href="/orders">查看订单</Link>
|
||||||
|
</Button>
|
||||||
|
<Button variant="outline" asChild>
|
||||||
|
<Link href={`/player/${player.id}`}>返回打手主页</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto py-8 px-4 max-w-2xl">
|
||||||
|
<Link
|
||||||
|
href={`/player/${player.id}`}
|
||||||
|
className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground mb-4"
|
||||||
|
>
|
||||||
|
<ArrowLeft className="h-4 w-4" />
|
||||||
|
返回打手主页
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<h1 className="text-2xl font-bold mb-6">确认下单</h1>
|
||||||
|
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-base">服务信息</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<Avatar className="h-10 w-10">
|
||||||
|
<AvatarImage src={player.user.avatar} />
|
||||||
|
<AvatarFallback>{player.user.nickname[0]}</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium">{player.user.nickname}</p>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{player.shopName ? `${player.shopName} · ` : ""}
|
||||||
|
{service.gameName}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Separator />
|
||||||
|
<div className="space-y-2 text-sm">
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">服务</span>
|
||||||
|
<span>{service.title}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">单价</span>
|
||||||
|
<span>
|
||||||
|
¥{service.price}/{service.unit}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{service.rankRange && (
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">段位范围</span>
|
||||||
|
<span>{service.rankRange}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-base">订单信息</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="quantity">数量({service.unit})</Label>
|
||||||
|
<Input
|
||||||
|
id="quantity"
|
||||||
|
type="number"
|
||||||
|
min={1}
|
||||||
|
max={99}
|
||||||
|
value={quantity}
|
||||||
|
onChange={(e) => setQuantity(Math.max(1, Number.parseInt(e.target.value, 10) || 1))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="note">备注(可选)</Label>
|
||||||
|
<Textarea
|
||||||
|
id="note"
|
||||||
|
placeholder="例如:希望晚上8点后开始"
|
||||||
|
value={note}
|
||||||
|
onChange={(e) => setNote(e.target.value)}
|
||||||
|
rows={3}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-base">支付信息</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-3">
|
||||||
|
<div className="flex justify-between text-sm">
|
||||||
|
<span className="text-muted-foreground">
|
||||||
|
{service.title} × {quantity}
|
||||||
|
</span>
|
||||||
|
<span>¥{totalPrice}</span>
|
||||||
|
</div>
|
||||||
|
<Separator />
|
||||||
|
<div className="flex justify-between font-medium">
|
||||||
|
<span>应付金额</span>
|
||||||
|
<span className="text-lg text-primary">¥{totalPrice}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
|
<CreditCard className="h-4 w-4" />
|
||||||
|
<span>钱包余额: ¥{walletBalance}</span>
|
||||||
|
{walletBalance < totalPrice && <span className="text-destructive">(余额不足)</span>}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||||
|
<ShieldCheck className="h-3.5 w-3.5" />
|
||||||
|
<span>资金由平台托管,服务完成后支付给打手</span>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
className="w-full"
|
||||||
|
size="lg"
|
||||||
|
disabled={walletBalance < totalPrice}
|
||||||
|
onClick={() => setSubmitted(true)}
|
||||||
|
>
|
||||||
|
确认支付 ¥{totalPrice}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user