Files
cunkebao_v3/Cunkebao/app/workspace/traffic-distribution/new/page.tsx
2025-04-02 16:00:10 +08:00

426 lines
18 KiB
TypeScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import { useState } from "react"
import { useRouter } from "next/navigation"
import { ChevronLeft, Users, Target, Settings, ArrowRight, ArrowLeft, Smartphone } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Textarea } from "@/components/ui/textarea"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
import { Switch } from "@/components/ui/switch"
import { Badge } from "@/components/ui/badge"
import { TrafficPoolSelector } from "@/app/components/traffic-pool-selector"
import { Checkbox } from "@/components/ui/checkbox"
export default function NewTrafficDistributionPage() {
const router = useRouter()
const [currentStep, setCurrentStep] = useState(1)
const [formData, setFormData] = useState({
name: "",
description: "",
priority: "high",
autoDistribute: true,
createAsPackage: false,
packagePrice: 0,
allDevices: false,
newDevices: false,
targetDevices: [] as string[],
showDeviceSelector: false,
selectedPool: "",
isPoolSelectorOpen: false,
selectedUsers: [],
})
const updateFormData = (field: string, value: any) => {
setFormData((prev) => {
if (field.includes(".")) {
const [parent, child] = field.split(".")
return {
...prev,
[parent]: {
...prev[parent as keyof typeof prev],
[child]: value,
},
}
}
return { ...prev, [field]: value }
})
}
const handleNext = () => {
setCurrentStep((prev) => prev + 1)
}
const handleBack = () => {
if (currentStep > 1) {
setCurrentStep((prev) => prev - 1)
} else {
router.back()
}
}
const handleSubmit = () => {
// 这里处理表单提交逻辑
console.log("提交表单数据:", formData)
router.push("/workspace/traffic-distribution")
}
const isStep1Valid = formData.name && formData.source
const isStep2Valid = formData.targetGroups.length > 0 || formData.targetDevices.length > 0
const isStep3Valid = true // 规则设置可以有默认值
return (
<div className="flex-1 bg-white min-h-screen">
<header className="sticky top-0 z-10 bg-white border-b">
<div className="flex items-center justify-between p-4">
<div className="flex items-center space-x-3">
<Button variant="ghost" size="icon" onClick={handleBack}>
<ChevronLeft className="h-5 w-5" />
</Button>
<h1 className="text-lg font-medium"></h1>
</div>
</div>
</header>
<div className="p-4 max-w-3xl mx-auto">
{/* 步骤指示器 */}
<div className="mb-6">
<div className="flex items-center justify-between">
{[
{ step: 1, title: "规则设定", icon: <Settings className="h-4 w-4" /> },
{ step: 2, title: "选择设备", icon: <Smartphone className="h-4 w-4" /> },
{ step: 3, title: "选择流量池", icon: <Users className="h-4 w-4" /> },
].map(({ step, title, icon }) => (
<div key={step} className="flex flex-col items-center">
<div
className={`w-10 h-10 rounded-full flex items-center justify-center ${
step === currentStep
? "bg-blue-600 text-white"
: step < currentStep
? "bg-green-500 text-white"
: "bg-gray-200 text-gray-500"
}`}
>
{step < currentStep ? "✓" : icon}
</div>
<span className="text-xs mt-1">{title}</span>
</div>
))}
</div>
<div className="relative mt-2">
<div className="absolute top-0 left-0 right-0 h-1 bg-gray-200"></div>
<div
className="absolute top-0 left-0 h-1 bg-blue-600 transition-all"
style={{ width: `${((currentStep - 1) / 2) * 100}%` }}
></div>
</div>
</div>
{/* 步骤1基本信息 */}
{currentStep === 1 && (
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<div className="space-y-2">
<Label htmlFor="name">
<span className="text-red-500">*</span>
</Label>
<Input
id="name"
placeholder="输入分发规则名称"
value={formData.name}
onChange={(e) => updateFormData("name", e.target.value)}
/>
</div>
<div className="space-y-2">
<Label htmlFor="description"></Label>
<Textarea
id="description"
placeholder="简要描述该分发规则的目标和用途"
value={formData.description}
onChange={(e) => updateFormData("description", e.target.value)}
/>
</div>
<div className="space-y-4">
<h3 className="text-sm font-medium"></h3>
<RadioGroup
value={formData.priority || "high"}
onValueChange={(value) => updateFormData("priority", value)}
className="space-y-3"
>
<div className="flex items-center space-x-2">
<RadioGroupItem value="high" id="high-priority" />
<Label htmlFor="high-priority" className="cursor-pointer">
</Label>
<span className="text-xs text-gray-500 ml-2">()</span>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="low" id="low-priority" />
<Label htmlFor="low-priority" className="cursor-pointer">
</Label>
<span className="text-xs text-gray-500 ml-2">()</span>
</div>
</RadioGroup>
</div>
<div className="space-y-2 border-t pt-4">
<div className="flex items-center justify-between">
<Label htmlFor="autoDistribute"></Label>
<Switch
id="autoDistribute"
checked={formData.autoDistribute !== false}
onCheckedChange={(checked) => updateFormData("autoDistribute", checked)}
/>
</div>
<p className="text-xs text-gray-500"></p>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between">
<Label htmlFor="createAsPackage"></Label>
<Switch
id="createAsPackage"
checked={formData.createAsPackage || false}
onCheckedChange={(checked) => updateFormData("createAsPackage", checked)}
/>
</div>
<p className="text-xs text-gray-500"></p>
</div>
{formData.createAsPackage && (
<div className="space-y-2 pl-4 border-l-2 border-blue-100">
<Label htmlFor="packagePrice"> (/)</Label>
<Input
id="packagePrice"
type="number"
placeholder="输入价格"
value={formData.packagePrice || ""}
onChange={(e) => updateFormData("packagePrice", Number.parseFloat(e.target.value))}
/>
</div>
)}
<div className="pt-4 flex justify-end">
<Button onClick={handleNext} disabled={!formData.name}>
<ArrowRight className="ml-2 h-4 w-4" />
</Button>
</div>
</CardContent>
</Card>
)}
{/* 步骤2目标设置 */}
{currentStep === 2 && (
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<div className="space-y-4">
<div className="flex items-center space-x-2">
<Checkbox
id="allDevices"
checked={formData.allDevices || false}
onCheckedChange={(checked) => {
updateFormData("allDevices", checked === true)
if (checked) updateFormData("targetDevices", [])
}}
/>
<Label htmlFor="allDevices" className="font-medium">
</Label>
<span className="text-xs text-gray-500">(线)</span>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="newDevices"
checked={formData.newDevices || false}
onCheckedChange={(checked) => updateFormData("newDevices", checked === true)}
disabled={formData.allDevices}
/>
<Label htmlFor="newDevices" className="font-medium">
</Label>
<span className="text-xs text-gray-500">()</span>
</div>
<div className="space-y-2 pt-4">
<Label className="font-medium"></Label>
<p className="text-xs text-gray-500 mb-2"></p>
<Button
variant="outline"
className="w-full"
disabled={formData.allDevices}
onClick={() => updateFormData("showDeviceSelector", true)}
>
<Smartphone className="mr-2 h-4 w-4" />
{formData.targetDevices?.length > 0 && (
<Badge variant="secondary" className="ml-2">
{formData.targetDevices.length}
</Badge>
)}
</Button>
</div>
</div>
<div className="pt-4 flex justify-between">
<Button variant="outline" onClick={handleBack}>
<ArrowLeft className="mr-2 h-4 w-4" />
</Button>
<Button
onClick={handleNext}
disabled={!formData.allDevices && (!formData.targetDevices || formData.targetDevices.length === 0)}
>
<ArrowRight className="ml-2 h-4 w-4" />
</Button>
</div>
</CardContent>
</Card>
)}
{/* 步骤3规则配置 */}
{currentStep === 3 && (
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* 普通流量包 */}
<Card
className={`cursor-pointer hover:border-blue-400 transition-colors ${
formData.selectedPool === "normal" ? "border-blue-500 bg-blue-50" : ""
}`}
onClick={() => updateFormData("selectedPool", "normal")}
>
<CardHeader className="pb-2">
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-2">
<div className="flex justify-between">
<span className="text-sm text-gray-500">:</span>
<span className="font-medium">0.50/</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-500">:</span>
<span className="font-medium">10</span>
</div>
<div className="flex flex-wrap gap-1 mt-2">
<Badge variant="outline"></Badge>
<Badge variant="outline"></Badge>
<Badge variant="outline"></Badge>
</div>
</div>
</CardContent>
</Card>
{/* 高质量流量 */}
<Card
className={`cursor-pointer hover:border-blue-400 transition-colors ${
formData.selectedPool === "high" ? "border-blue-500 bg-blue-50" : ""
}`}
onClick={() => updateFormData("selectedPool", "high")}
>
<CardHeader className="pb-2">
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-2">
<div className="flex justify-between">
<span className="text-sm text-gray-500">:</span>
<span className="font-medium">2.50/</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-500">:</span>
<span className="font-medium">25</span>
</div>
<div className="flex flex-wrap gap-1 mt-2">
<Badge variant="outline"></Badge>
<Badge variant="outline"></Badge>
<Badge variant="outline">线</Badge>
</div>
</div>
</CardContent>
</Card>
{/* 精准营销流量 */}
<Card
className={`cursor-pointer hover:border-blue-400 transition-colors ${
formData.selectedPool === "precise" ? "border-blue-500 bg-blue-50" : ""
}`}
onClick={() => updateFormData("selectedPool", "precise")}
>
<CardHeader className="pb-2">
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-2">
<div className="flex justify-between">
<span className="text-sm text-gray-500">:</span>
<span className="font-medium">3.80/</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-500">:</span>
<span className="font-medium">50</span>
</div>
<div className="flex flex-wrap gap-1 mt-2">
<Badge variant="outline"></Badge>
<Badge variant="outline"></Badge>
<Badge variant="outline"></Badge>
</div>
</div>
</CardContent>
</Card>
</div>
<div className="pt-4">
<Button variant="outline" className="w-full" onClick={() => updateFormData("isPoolSelectorOpen", true)}>
<Target className="mr-2 h-4 w-4" />
</Button>
</div>
<div className="pt-4 flex justify-between">
<Button variant="outline" onClick={handleBack}>
<ArrowLeft className="mr-2 h-4 w-4" />
</Button>
<Button onClick={handleSubmit} disabled={!formData.selectedPool}>
</Button>
</div>
</CardContent>
</Card>
)}
</div>
{/* 流量池选择器 */}
<TrafficPoolSelector
open={formData.isPoolSelectorOpen}
onOpenChange={(open) => updateFormData("isPoolSelectorOpen", open)}
selectedUsers={formData.selectedUsers}
onSelect={(users) => updateFormData("selectedUsers", users)}
/>
</div>
)
}