346 lines
14 KiB
TypeScript
346 lines
14 KiB
TypeScript
"use client"
|
||
|
||
import { useState } from "react"
|
||
import { Button } from "@/components/ui/button"
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogDescription,
|
||
DialogFooter,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
DialogTrigger,
|
||
} from "@/components/ui/dialog"
|
||
import { Input } from "@/components/ui/input"
|
||
import { Label } from "@/components/ui/label"
|
||
import { Textarea } from "@/components/ui/textarea"
|
||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||
import { Plus, Upload, AlertTriangle, Loader2 } from "lucide-react"
|
||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||
import { Switch } from "@/components/ui/switch"
|
||
import { cn } from "@/lib/utils"
|
||
|
||
export function AddOutfitDialog() {
|
||
const [open, setOpen] = useState(false)
|
||
const [step, setStep] = useState(1)
|
||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||
const [outfitType, setOutfitType] = useState("")
|
||
const [rarity, setRarity] = useState("")
|
||
const [printQuantity, setPrintQuantity] = useState(1000)
|
||
const [isLimited, setIsLimited] = useState(false)
|
||
const [previewId, setPreviewId] = useState(
|
||
"OFT" +
|
||
Math.floor(Math.random() * 1000)
|
||
.toString()
|
||
.padStart(3, "0"),
|
||
)
|
||
|
||
const handleSubmit = async () => {
|
||
setIsSubmitting(true)
|
||
// 模拟API请求
|
||
await new Promise((resolve) => setTimeout(resolve, 1500))
|
||
setIsSubmitting(false)
|
||
setOpen(false)
|
||
// 重置表单
|
||
setStep(1)
|
||
setOutfitType("")
|
||
setRarity("")
|
||
setPrintQuantity(1000)
|
||
setIsLimited(false)
|
||
setPreviewId(
|
||
"OFT" +
|
||
Math.floor(Math.random() * 1000)
|
||
.toString()
|
||
.padStart(3, "0"),
|
||
)
|
||
}
|
||
|
||
const handleNext = () => {
|
||
setStep(step + 1)
|
||
}
|
||
|
||
const handleBack = () => {
|
||
setStep(step - 1)
|
||
}
|
||
|
||
const handleClose = () => {
|
||
setOpen(false)
|
||
setStep(1)
|
||
}
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={setOpen}>
|
||
<DialogTrigger asChild>
|
||
<Button 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">
|
||
<Plus className="mr-2 h-4 w-4" />
|
||
添加服装
|
||
</Button>
|
||
</DialogTrigger>
|
||
<DialogContent className="sm:max-w-[600px]">
|
||
<DialogHeader>
|
||
<DialogTitle className="text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-purple-600 to-pink-600">
|
||
添加新服装
|
||
</DialogTitle>
|
||
<DialogDescription>填写服装信息以创建新的服装卡牌。创建后将生成唯一的卡牌ID。</DialogDescription>
|
||
</DialogHeader>
|
||
|
||
<Tabs value={`step-${step}`} className="mt-2">
|
||
<TabsList className="grid w-full grid-cols-3">
|
||
<TabsTrigger
|
||
value="step-1"
|
||
className={cn(
|
||
"data-[state=active]:bg-gradient-to-r data-[state=active]:from-pink-500 data-[state=active]:to-purple-600 data-[state=active]:text-white",
|
||
step >= 1 ? "text-pink-600" : "text-gray-500",
|
||
)}
|
||
disabled
|
||
>
|
||
基本信息
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="step-2"
|
||
className={cn(
|
||
"data-[state=active]:bg-gradient-to-r data-[state=active]:from-pink-500 data-[state=active]:to-purple-600 data-[state=active]:text-white",
|
||
step >= 2 ? "text-pink-600" : "text-gray-500",
|
||
)}
|
||
disabled
|
||
>
|
||
图片上传
|
||
</TabsTrigger>
|
||
<TabsTrigger
|
||
value="step-3"
|
||
className={cn(
|
||
"data-[state=active]:bg-gradient-to-r data-[state=active]:from-pink-500 data-[state=active]:to-purple-600 data-[state=active]:text-white",
|
||
step >= 3 ? "text-pink-600" : "text-gray-500",
|
||
)}
|
||
disabled
|
||
>
|
||
确认创建
|
||
</TabsTrigger>
|
||
</TabsList>
|
||
|
||
<TabsContent value="step-1" className="space-y-4 py-4">
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="space-y-2">
|
||
<Label htmlFor="name" className="text-right">
|
||
服装名称 <span className="text-red-500">*</span>
|
||
</Label>
|
||
<Input
|
||
id="name"
|
||
placeholder="输入服装名称"
|
||
className="border-gray-300 focus-visible:ring-pink-500"
|
||
required
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="type" className="text-right">
|
||
服装类型 <span className="text-red-500">*</span>
|
||
</Label>
|
||
<Select value={outfitType} onValueChange={setOutfitType} required>
|
||
<SelectTrigger className="border-gray-300 focus:ring-pink-500">
|
||
<SelectValue placeholder="选择服装类型" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="regular">常规</SelectItem>
|
||
<SelectItem value="seasonal">季节限定</SelectItem>
|
||
<SelectItem value="festival">节日限定</SelectItem>
|
||
<SelectItem value="special">特别版</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="space-y-2">
|
||
<Label htmlFor="rarity" className="text-right">
|
||
稀有度 <span className="text-red-500">*</span>
|
||
</Label>
|
||
<Select value={rarity} onValueChange={setRarity} required>
|
||
<SelectTrigger className="border-gray-300 focus:ring-pink-500">
|
||
<SelectValue placeholder="选择稀有度" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="common">普通</SelectItem>
|
||
<SelectItem value="rare">稀有</SelectItem>
|
||
<SelectItem value="epic">史诗</SelectItem>
|
||
<SelectItem value="legendary">传说</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="print-quantity" className="text-right">
|
||
印刷数量 <span className="text-red-500">*</span>
|
||
</Label>
|
||
<Input
|
||
id="print-quantity"
|
||
type="number"
|
||
min={1}
|
||
value={printQuantity}
|
||
onChange={(e) => setPrintQuantity(Number.parseInt(e.target.value))}
|
||
placeholder="输入印刷数量"
|
||
className="border-gray-300 focus-visible:ring-pink-500"
|
||
required
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<Label htmlFor="description" className="text-right">
|
||
服装描述 <span className="text-red-500">*</span>
|
||
</Label>
|
||
<Textarea
|
||
id="description"
|
||
placeholder="输入服装描述"
|
||
className="min-h-[100px] border-gray-300 focus-visible:ring-pink-500"
|
||
required
|
||
/>
|
||
</div>
|
||
|
||
<div className="flex items-center space-x-2 pt-2">
|
||
<Switch id="limited" checked={isLimited} onCheckedChange={setIsLimited} />
|
||
<Label htmlFor="limited" className="cursor-pointer">
|
||
这是限定服装
|
||
</Label>
|
||
</div>
|
||
|
||
{isLimited && (
|
||
<div className="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" />
|
||
<div className="text-sm text-amber-700">
|
||
<p className="font-medium">限定服装提示</p>
|
||
<p>限定服装通常有特定的发布时间和限制条件。请确保在发布前设置好相关参数。</p>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</TabsContent>
|
||
|
||
<TabsContent value="step-2" className="space-y-4 py-4">
|
||
<div className="space-y-2">
|
||
<Label className="text-right">
|
||
服装图片 <span className="text-red-500">*</span>
|
||
</Label>
|
||
<div className="border-2 border-dashed border-gray-300 rounded-lg p-6 flex flex-col items-center justify-center hover:border-pink-500 transition-colors cursor-pointer">
|
||
<Upload className="h-8 w-8 text-gray-400 mb-2" />
|
||
<p className="text-sm text-gray-500">点击或拖拽上传服装图片</p>
|
||
<p className="text-xs text-gray-400 mt-1">支持 PNG, JPG, JPEG 格式,最大 5MB</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-2 mt-4">
|
||
<Label className="text-right">服装预览图 (可选)</Label>
|
||
<div className="border-2 border-dashed border-gray-300 rounded-lg p-6 flex flex-col items-center justify-center hover:border-pink-500 transition-colors cursor-pointer">
|
||
<Upload className="h-8 w-8 text-gray-400 mb-2" />
|
||
<p className="text-sm text-gray-500">点击或拖拽上传服装预览图</p>
|
||
<p className="text-xs text-gray-400 mt-1">建议上传多角度预览图,最多5张</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="p-3 bg-blue-50 border border-blue-200 rounded-lg flex items-start mt-2">
|
||
<AlertTriangle className="h-5 w-5 text-blue-500 mr-2 flex-shrink-0 mt-0.5" />
|
||
<div className="text-sm text-blue-700">
|
||
<p className="font-medium">图片要求</p>
|
||
<p>主图将用于卡牌印刷和APP展示,请确保图片清晰、比例合适。建议使用透明背景的PNG格式。</p>
|
||
</div>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
<TabsContent value="step-3" className="space-y-4 py-4">
|
||
<div className="p-4 bg-gray-50 rounded-lg">
|
||
<h3 className="text-lg font-medium mb-3">服装信息确认</h3>
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="space-y-1">
|
||
<p className="text-sm font-medium text-gray-500">服装ID</p>
|
||
<p className="font-medium text-pink-600">{previewId}</p>
|
||
</div>
|
||
<div className="space-y-1">
|
||
<p className="text-sm font-medium text-gray-500">服装类型</p>
|
||
<p className="font-medium">
|
||
{outfitType === "regular"
|
||
? "常规"
|
||
: outfitType === "seasonal"
|
||
? "季节限定"
|
||
: outfitType === "festival"
|
||
? "节日限定"
|
||
: outfitType === "special"
|
||
? "特别版"
|
||
: "-"}
|
||
</p>
|
||
</div>
|
||
<div className="space-y-1">
|
||
<p className="text-sm font-medium text-gray-500">稀有度</p>
|
||
<p className="font-medium">
|
||
{rarity === "common"
|
||
? "普通"
|
||
: rarity === "rare"
|
||
? "稀有"
|
||
: rarity === "epic"
|
||
? "史诗"
|
||
: rarity === "legendary"
|
||
? "传说"
|
||
: "-"}
|
||
</p>
|
||
</div>
|
||
<div className="space-y-1">
|
||
<p className="text-sm font-medium text-gray-500">印刷数量</p>
|
||
<p className="font-medium">{printQuantity}</p>
|
||
</div>
|
||
<div className="space-y-1">
|
||
<p className="text-sm font-medium text-gray-500">限定服装</p>
|
||
<p className="font-medium">{isLimited ? "是" : "否"}</p>
|
||
</div>
|
||
<div className="space-y-1">
|
||
<p className="text-sm font-medium text-gray-500">状态</p>
|
||
<p className="font-medium">未发布</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="mt-4 p-3 bg-pink-50 border border-pink-200 rounded-lg flex items-start">
|
||
<AlertTriangle className="h-5 w-5 text-pink-500 mr-2 flex-shrink-0 mt-0.5" />
|
||
<div className="text-sm text-pink-700">
|
||
<p className="font-medium">重要提示</p>
|
||
<p>创建服装后,系统将自动生成卡牌ID。服装发布后将无法修改基本属性,请确认信息无误。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</TabsContent>
|
||
</Tabs>
|
||
|
||
<DialogFooter className="flex items-center justify-between mt-2">
|
||
{step > 1 ? (
|
||
<Button variant="outline" onClick={handleBack} disabled={isSubmitting}>
|
||
上一步
|
||
</Button>
|
||
) : (
|
||
<Button variant="outline" onClick={handleClose} disabled={isSubmitting}>
|
||
取消
|
||
</Button>
|
||
)}
|
||
|
||
{step < 3 ? (
|
||
<Button
|
||
className="bg-gradient-to-r from-pink-500 to-purple-600 hover:from-pink-600 hover:to-purple-700"
|
||
onClick={handleNext}
|
||
>
|
||
下一步
|
||
</Button>
|
||
) : (
|
||
<Button
|
||
className="bg-gradient-to-r from-pink-500 to-purple-600 hover:from-pink-600 hover:to-purple-700"
|
||
onClick={handleSubmit}
|
||
disabled={isSubmitting}
|
||
>
|
||
{isSubmitting ? (
|
||
<>
|
||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||
创建中...
|
||
</>
|
||
) : (
|
||
"创建服装"
|
||
)}
|
||
</Button>
|
||
)}
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
)
|
||
}
|