Add fan group entry on live room; update planet matching with 4 type buttons. Co-authored-by: undefined <undefined+undefined@users.noreply.github.com>
205 lines
7.7 KiB
TypeScript
205 lines
7.7 KiB
TypeScript
"use client"
|
|
|
|
import { useState, useEffect } from "react"
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
|
import { Label } from "@/components/ui/label"
|
|
import { Input } from "@/components/ui/input"
|
|
import { Checkbox } from "@/components/ui/checkbox"
|
|
import { GAME_CASCADE_DATA } from "@/lib/data/game-cascade-data"
|
|
|
|
type DynamicCascadeFormProps = {
|
|
gameName: string
|
|
onDataChange: (data: Record<string, any>) => void
|
|
}
|
|
|
|
export function DynamicCascadeForm({ gameName, onDataChange }: DynamicCascadeFormProps) {
|
|
const config = GAME_CASCADE_DATA[gameName]
|
|
|
|
const [selectedRegion, setSelectedRegion] = useState<string>("")
|
|
const [selectedServer, setSelectedServer] = useState<string>("")
|
|
const [selectedSubOption, setSelectedSubOption] = useState<string>("")
|
|
const [attributeValues, setAttributeValues] = useState<Record<string, any>>({})
|
|
|
|
useEffect(() => {
|
|
// Reset when game changes
|
|
setSelectedRegion("")
|
|
setSelectedServer("")
|
|
setSelectedSubOption("")
|
|
setAttributeValues({})
|
|
}, [gameName])
|
|
|
|
useEffect(() => {
|
|
// Notify parent of data changes
|
|
onDataChange({
|
|
region: selectedRegion,
|
|
server: selectedServer,
|
|
subOption: selectedSubOption,
|
|
...attributeValues,
|
|
})
|
|
}, [selectedRegion, selectedServer, selectedSubOption, attributeValues, onDataChange])
|
|
|
|
if (!config) {
|
|
return <div className="text-gray-400 text-sm">该游戏暂无配置</div>
|
|
}
|
|
|
|
const currentRegion = config.regions.find((r) => r.value === selectedRegion)
|
|
const serverOptions = currentRegion?.children || []
|
|
|
|
const currentServer = serverOptions.find((s) => s.value === selectedServer)
|
|
const subOptions = currentServer?.children || []
|
|
|
|
const handleAttributeChange = (label: string, value: any) => {
|
|
setAttributeValues((prev) => ({ ...prev, [label]: value }))
|
|
}
|
|
|
|
const handleMultiSelectChange = (label: string, option: string, checked: boolean) => {
|
|
setAttributeValues((prev) => {
|
|
const current = prev[label] || []
|
|
if (checked) {
|
|
return { ...prev, [label]: [...current, option] }
|
|
} else {
|
|
return { ...prev, [label]: current.filter((v: string) => v !== option) }
|
|
}
|
|
})
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-5">
|
|
{/* Region Selection */}
|
|
{config.regions.length > 0 && (
|
|
<div className="space-y-2">
|
|
<Label className="text-gray-400">游戏区</Label>
|
|
<Select
|
|
value={selectedRegion}
|
|
onValueChange={(v) => {
|
|
setSelectedRegion(v)
|
|
setSelectedServer("")
|
|
setSelectedSubOption("")
|
|
}}
|
|
>
|
|
<SelectTrigger className="bg-[#12121A] border-white/10 h-11 text-white focus:ring-1 focus:ring-blue-500">
|
|
<SelectValue placeholder="选择游戏区" />
|
|
</SelectTrigger>
|
|
<SelectContent className="bg-[#1A1A2E] border-white/10 text-white">
|
|
{config.regions.map((region) => (
|
|
<SelectItem key={region.value} value={region.value}>
|
|
{region.label}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
)}
|
|
|
|
{/* Server Selection */}
|
|
{serverOptions.length > 0 && (
|
|
<div className="space-y-2">
|
|
<Label className="text-gray-400">游戏服</Label>
|
|
<Select
|
|
value={selectedServer}
|
|
onValueChange={(v) => {
|
|
setSelectedServer(v)
|
|
setSelectedSubOption("")
|
|
}}
|
|
disabled={!selectedRegion}
|
|
>
|
|
<SelectTrigger className="bg-[#12121A] border-white/10 h-11 text-white focus:ring-1 focus:ring-blue-500">
|
|
<SelectValue placeholder="选择服务器" />
|
|
</SelectTrigger>
|
|
<SelectContent className="bg-[#1A1A2E] border-white/10 text-white max-h-[300px]">
|
|
{serverOptions.map((server) => (
|
|
<SelectItem key={server.value} value={server.value}>
|
|
{server.label}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
)}
|
|
|
|
{/* Sub Options */}
|
|
{subOptions.length > 0 && (
|
|
<div className="space-y-2">
|
|
<Label className="text-gray-400">游戏属性</Label>
|
|
<Select value={selectedSubOption} onValueChange={setSelectedSubOption} disabled={!selectedServer}>
|
|
<SelectTrigger className="bg-[#12121A] border-white/10 h-11 text-white focus:ring-1 focus:ring-blue-500">
|
|
<SelectValue placeholder="选择属性" />
|
|
</SelectTrigger>
|
|
<SelectContent className="bg-[#1A1A2E] border-white/10 text-white">
|
|
{subOptions.map((option) => (
|
|
<SelectItem key={option.value} value={option.value}>
|
|
{option.label}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
)}
|
|
|
|
{/* Dynamic Attributes */}
|
|
{config.attributes.map((attr, index) => (
|
|
<div key={index} className="space-y-2">
|
|
<Label className="text-gray-400">
|
|
{attr.label}
|
|
{attr.required && <span className="text-red-400 ml-1">*</span>}
|
|
</Label>
|
|
|
|
{attr.type === "select" && attr.options && (
|
|
<Select
|
|
value={attributeValues[attr.label] || ""}
|
|
onValueChange={(v) => handleAttributeChange(attr.label, v)}
|
|
>
|
|
<SelectTrigger className="bg-[#12121A] border-white/10 h-11 text-white focus:ring-1 focus:ring-purple-500">
|
|
<SelectValue placeholder={`选择${attr.label}`} />
|
|
</SelectTrigger>
|
|
<SelectContent className="bg-[#1A1A2E] border-white/10 text-white max-h-[300px]">
|
|
{attr.options.map((option) => (
|
|
<SelectItem key={option} value={option}>
|
|
{option}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
)}
|
|
|
|
{attr.type === "multiselect" && attr.options && (
|
|
<div className="bg-[#12121A] border border-white/10 rounded-lg p-4 max-h-[200px] overflow-y-auto space-y-2">
|
|
{attr.options.slice(0, 20).map((option) => (
|
|
<div key={option} className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id={`${attr.label}-${option}`}
|
|
checked={(attributeValues[attr.label] || []).includes(option)}
|
|
onCheckedChange={(checked) => handleMultiSelectChange(attr.label, option, checked as boolean)}
|
|
className="border-white/20"
|
|
/>
|
|
<label htmlFor={`${attr.label}-${option}`} className="text-sm text-gray-300 cursor-pointer">
|
|
{option}
|
|
</label>
|
|
</div>
|
|
))}
|
|
{attr.options.length > 20 && <div className="text-xs text-gray-500 text-center pt-2">显示前20项...</div>}
|
|
</div>
|
|
)}
|
|
|
|
{attr.type === "input" && (
|
|
<Input
|
|
value={attributeValues[attr.label] || ""}
|
|
onChange={(e) => handleAttributeChange(attr.label, e.target.value)}
|
|
placeholder={`输入${attr.label}`}
|
|
className="bg-[#12121A] border-white/10 h-11 text-white focus:border-purple-500"
|
|
/>
|
|
)}
|
|
</div>
|
|
))}
|
|
|
|
{/* Screenshot Upload Hint */}
|
|
<div className="bg-[#12121A] border border-blue-500/20 rounded-lg p-3 mt-4">
|
|
<p className="text-xs text-blue-300 flex items-center gap-2">
|
|
<span className="text-blue-500">📸</span>
|
|
请准备游戏截图以便进行账号验证
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|