feat: dashboard overview, services list, and service publish pages

This commit is contained in:
zetaloop
2026-02-20 15:25:34 +08:00
parent e132ffcefb
commit 8f4e8604d3
3 changed files with 365 additions and 9 deletions
+146 -3
View File
@@ -1,8 +1,151 @@
"use client"
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"
import { ArrowLeft } from "lucide-react"
import Link from "next/link"
import { useRouter } from "next/navigation"
import { useForm } from "react-hook-form"
import { z } from "zod"
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 {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { Textarea } from "@/components/ui/textarea"
import { mockGames } from "@/lib/mock-data"
const serviceSchema = z.object({
title: z.string().min(2, "标题至少2个字符"),
description: z.string().min(10, "描述至少10个字符"),
price: z.string().min(1, "请输入价格"),
unit: z.string().min(1, "请输入单位"),
rankRange: z.string().optional(),
availability: z.string().min(1, "请输入可用时间"),
})
export default function NewServicePage() {
const router = useRouter()
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm({
resolver: standardSchemaResolver(serviceSchema),
})
const onSubmit = async () => {
await new Promise((r) => setTimeout(r, 500))
router.push("/dashboard/services")
}
return (
<div>
<h1 className="text-2xl font-bold"></h1>
<p className="mt-2 text-muted-foreground"></p>
<div className="max-w-2xl space-y-4">
<Link
href="/dashboard/services"
className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"
>
<ArrowLeft className="h-4 w-4" />
</Link>
<Card>
<CardHeader>
<CardTitle></CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
<div className="space-y-2">
<Label></Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="选择游戏" />
</SelectTrigger>
<SelectContent>
{mockGames.map((game) => (
<SelectItem key={game.id} value={game.id}>
{game.icon} {game.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="title"></Label>
<Input id="title" placeholder="例如:英雄联盟上分陪玩" {...register("title")} />
{errors.title && <p className="text-xs text-destructive">{errors.title.message}</p>}
</div>
<div className="space-y-2">
<Label htmlFor="description"></Label>
<Textarea
id="description"
placeholder="详细描述你的服务内容、优势等"
rows={4}
{...register("description")}
/>
{errors.description && (
<p className="text-xs text-destructive">{errors.description.message}</p>
)}
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="price"></Label>
<Input id="price" type="number" placeholder="30" {...register("price")} />
{errors.price && <p className="text-xs text-destructive">{errors.price.message}</p>}
</div>
<div className="space-y-2">
<Label htmlFor="unit"></Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="选择单位" />
</SelectTrigger>
<SelectContent>
<SelectItem value="局"></SelectItem>
<SelectItem value="小时"></SelectItem>
<SelectItem value="星"></SelectItem>
<SelectItem value="次"></SelectItem>
<SelectItem value="段"></SelectItem>
</SelectContent>
</Select>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="rankRange"></Label>
<Input id="rankRange" placeholder="例如:钻石-大师" {...register("rankRange")} />
</div>
<div className="space-y-2">
<Label htmlFor="availability"></Label>
<Input
id="availability"
placeholder="例如:周一至周五 19:00-23:00"
{...register("availability")}
/>
{errors.availability && (
<p className="text-xs text-destructive">{errors.availability.message}</p>
)}
</div>
<div className="flex gap-2">
<Button type="submit" className="flex-1" disabled={isSubmitting}>
{isSubmitting ? "发布中..." : "发布服务"}
</Button>
<Button type="button" variant="outline" asChild>
<Link href="/dashboard/services"></Link>
</Button>
</div>
</form>
</CardContent>
</Card>
</div>
)
}