lty/qy-lty-admin/components/affinity/affinity-level-dialog.tsx
2026-03-17 13:17:02 +08:00

321 lines
11 KiB
TypeScript

"use client"
import type React from "react"
import { useState, useEffect } 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, Loader2, Award } from "lucide-react"
import { Switch } from "@/components/ui/switch"
// 定义好感度等级类型
export type AffinityLevel = {
id: string
level: number
name: string
minAffinity: number
maxAffinity: number
unlockContent: string
rewardType: string
rewardItems?: string
rewardCurrency?: number
isEnabled: boolean
}
type AffinityLevelDialogProps = {
mode?: "create" | "edit"
level?: AffinityLevel
onSave?: (level: AffinityLevel) => void
trigger?: React.ReactNode
}
export function AffinityLevelDialog({ mode = "create", level, onSave, trigger }: AffinityLevelDialogProps) {
const [open, setOpen] = useState(false)
const [isSubmitting, setIsSubmitting] = useState(false)
// 表单状态
const [levelNumber, setLevelNumber] = useState("6")
const [levelName, setLevelName] = useState("")
const [minAffinity, setMinAffinity] = useState("101")
const [maxAffinity, setMaxAffinity] = useState("120")
const [unlockContent, setUnlockContent] = useState("")
const [rewardType, setRewardType] = useState("unlock")
const [rewardItems, setRewardItems] = useState("")
const [rewardCurrency, setRewardCurrency] = useState("100")
const [isEnabled, setIsEnabled] = useState(true)
// 当编辑模式且有等级数据时,初始化表单
useEffect(() => {
if (mode === "edit" && level) {
setLevelNumber(String(level.level))
setLevelName(level.name)
setMinAffinity(String(level.minAffinity))
setMaxAffinity(String(level.maxAffinity))
setUnlockContent(level.unlockContent)
setRewardType(level.rewardType)
setRewardItems(level.rewardItems || "")
setRewardCurrency(String(level.rewardCurrency || 100))
setIsEnabled(level.isEnabled)
}
}, [mode, level, open])
// 重置表单
const resetForm = () => {
if (mode === "create") {
setLevelNumber("6")
setLevelName("")
setMinAffinity("101")
setMaxAffinity("120")
setUnlockContent("")
setRewardType("unlock")
setRewardItems("")
setRewardCurrency("100")
setIsEnabled(true)
}
}
const handleSubmit = async () => {
// 表单验证
if (!levelName || !unlockContent) {
alert("请填写所有必填字段!")
return
}
setIsSubmitting(true)
try {
// 构建等级对象
const updatedLevel: AffinityLevel = {
id: level?.id || `level-${Date.now()}`,
level: Number(levelNumber),
name: levelName,
minAffinity: Number(minAffinity),
maxAffinity: Number(maxAffinity),
unlockContent,
rewardType,
rewardItems: rewardItems || undefined,
rewardCurrency: rewardType === "currency" ? Number(rewardCurrency) : undefined,
isEnabled,
}
// 模拟API请求
await new Promise((resolve) => setTimeout(resolve, 1500))
// 调用保存回调
if (onSave) {
onSave(updatedLevel)
}
// 成功提示
alert(mode === "create" ? "好感度等级创建成功!" : "好感度等级更新成功!")
setOpen(false)
resetForm()
} catch (error) {
// 错误处理
console.error(mode === "create" ? "创建好感度等级失败:" : "更新好感度等级失败:", error)
alert(mode === "create" ? "创建好感度等级失败,请重试!" : "更新好感度等级失败,请重试!")
} finally {
setIsSubmitting(false)
}
}
return (
<Dialog
open={open}
onOpenChange={(newOpen) => {
setOpen(newOpen)
if (!newOpen) resetForm()
}}
>
<DialogTrigger asChild>
{trigger || (
<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-[550px]">
<DialogHeader>
<DialogTitle className="text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-purple-600 to-pink-600">
{mode === "create" ? "添加好感度等级" : "编辑好感度等级"}
</DialogTitle>
<DialogDescription>
{mode === "create" ? "设置新的好感度等级和对应奖励" : "修改好感度等级和对应奖励"}
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="level" className="text-right">
<span className="text-red-500">*</span>
</Label>
<Input
id="level"
type="number"
min="1"
className="border-gray-300 focus-visible:ring-pink-500"
value={levelNumber}
onChange={(e) => setLevelNumber(e.target.value)}
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="level-name" className="text-right">
<span className="text-red-500">*</span>
</Label>
<Input
id="level-name"
placeholder="输入等级名称"
className="border-gray-300 focus-visible:ring-pink-500"
value={levelName}
onChange={(e) => setLevelName(e.target.value)}
required
/>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="min-affinity" className="text-right">
<span className="text-red-500">*</span>
</Label>
<div className="flex items-center space-x-2">
<Input
id="min-affinity"
type="number"
min="0"
className="border-gray-300 focus-visible:ring-pink-500"
value={minAffinity}
onChange={(e) => setMinAffinity(e.target.value)}
required
/>
<span className="text-sm text-gray-500"></span>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="max-affinity" className="text-right">
<span className="text-red-500">*</span>
</Label>
<div className="flex items-center space-x-2">
<Input
id="max-affinity"
type="number"
min="0"
className="border-gray-300 focus-visible:ring-pink-500"
value={maxAffinity}
onChange={(e) => setMaxAffinity(e.target.value)}
required
/>
<span className="text-sm text-gray-500"></span>
</div>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="unlock-content" className="text-right">
<span className="text-red-500">*</span>
</Label>
<Textarea
id="unlock-content"
placeholder="输入该等级解锁的内容"
className="min-h-[80px] border-gray-300 focus-visible:ring-pink-500"
value={unlockContent}
onChange={(e) => setUnlockContent(e.target.value)}
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="reward-type" className="text-right">
</Label>
<Select value={rewardType} onValueChange={setRewardType}>
<SelectTrigger className="border-gray-300 focus:ring-pink-500">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="unlock"></SelectItem>
<SelectItem value="item"></SelectItem>
<SelectItem value="currency"></SelectItem>
<SelectItem value="mixed"></SelectItem>
</SelectContent>
</Select>
</div>
{rewardType === "item" && (
<div className="space-y-2">
<Label htmlFor="reward-items" className="text-right">
</Label>
<Textarea
id="reward-items"
placeholder="输入奖励的道具列表"
className="min-h-[80px] border-gray-300 focus-visible:ring-pink-500"
value={rewardItems}
onChange={(e) => setRewardItems(e.target.value)}
/>
</div>
)}
{rewardType === "currency" && (
<div className="space-y-2">
<Label htmlFor="reward-currency" className="text-right">
</Label>
<Input
id="reward-currency"
type="number"
min="0"
className="border-gray-300 focus-visible:ring-pink-500"
value={rewardCurrency}
onChange={(e) => setRewardCurrency(e.target.value)}
/>
</div>
)}
<div className="flex items-center space-x-2 pt-2">
<Switch id="enable-level" checked={isEnabled} onCheckedChange={setIsEnabled} />
<Label htmlFor="enable-level" className="cursor-pointer">
{mode === "create" ? "立即启用此等级" : "启用此等级"}
</Label>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setOpen(false)} disabled={isSubmitting}>
</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" />
{mode === "create" ? "创建中..." : "更新中..."}
</>
) : (
<>
<Award className="mr-2 h-4 w-4" />
{mode === "create" ? "创建等级" : "更新等级"}
</>
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}