存客宝 React
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
"use client"
|
||||
|
||||
import type React from "react"
|
||||
|
||||
import { useState } from "react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { Checkbox } from "@/components/ui/checkbox"
|
||||
import { Card } from "@/components/ui/card"
|
||||
import { BarChart3, Users, Activity, Brain, Search } from "lucide-react"
|
||||
|
||||
interface BasicSettingsProps {
|
||||
formData: {
|
||||
taskName: string
|
||||
analysisTypes: string[]
|
||||
}
|
||||
updateFormData: (
|
||||
data: Partial<{
|
||||
taskName: string
|
||||
analysisTypes: string[]
|
||||
}>,
|
||||
) => void
|
||||
onNext: () => void
|
||||
}
|
||||
|
||||
interface AnalysisType {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
icon: React.ReactNode
|
||||
}
|
||||
|
||||
export function BasicSettings({ formData, updateFormData, onNext }: BasicSettingsProps) {
|
||||
const [errors, setErrors] = useState<{ taskName?: string; analysisTypes?: string }>({})
|
||||
|
||||
const analysisTypes: AnalysisType[] = [
|
||||
{
|
||||
id: "comprehensive",
|
||||
name: "综合分析",
|
||||
description: "全面分析用户画像、行为习惯和互动模式",
|
||||
icon: <Brain className="h-5 w-5 text-blue-500" />,
|
||||
},
|
||||
{
|
||||
id: "friend-info",
|
||||
name: "好友信息分析",
|
||||
description: "分析好友基本信息、地域分布和标签特征",
|
||||
icon: <Users className="h-5 w-5 text-green-500" />,
|
||||
},
|
||||
{
|
||||
id: "user-behavior",
|
||||
name: "用户行为分析",
|
||||
description: "分析用户互动频率、活跃时间和内容偏好",
|
||||
icon: <Activity className="h-5 w-5 text-purple-500" />,
|
||||
},
|
||||
{
|
||||
id: "content-preference",
|
||||
name: "内容偏好分析",
|
||||
description: "分析用户对不同类型内容的反应和互动情况",
|
||||
icon: <BarChart3 className="h-5 w-5 text-orange-500" />,
|
||||
},
|
||||
{
|
||||
id: "keyword-analysis",
|
||||
name: "关键词分析",
|
||||
description: "分析用户聊天和互动中的高频关键词和话题",
|
||||
icon: <Search className="h-5 w-5 text-red-500" />,
|
||||
},
|
||||
]
|
||||
|
||||
const handleAnalysisTypeChange = (typeId: string, checked: boolean) => {
|
||||
if (checked) {
|
||||
updateFormData({
|
||||
analysisTypes: [...formData.analysisTypes, typeId],
|
||||
})
|
||||
} else {
|
||||
updateFormData({
|
||||
analysisTypes: formData.analysisTypes.filter((id) => id !== typeId),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const validateForm = () => {
|
||||
const newErrors: { taskName?: string; analysisTypes?: string } = {}
|
||||
|
||||
if (!formData.taskName.trim()) {
|
||||
newErrors.taskName = "请输入任务名称"
|
||||
}
|
||||
|
||||
if (formData.analysisTypes.length === 0) {
|
||||
newErrors.analysisTypes = "请至少选择一种分析类型"
|
||||
}
|
||||
|
||||
setErrors(newErrors)
|
||||
return Object.keys(newErrors).length === 0
|
||||
}
|
||||
|
||||
const handleNext = () => {
|
||||
if (validateForm()) {
|
||||
onNext()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold mb-4">创建分析计划</h2>
|
||||
<p className="text-gray-500 mb-6">设置分析任务名称并选择需要的分析类型</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label htmlFor="taskName" className="text-base">
|
||||
任务名称
|
||||
</Label>
|
||||
<Input
|
||||
id="taskName"
|
||||
placeholder="例如:11月用户行为分析"
|
||||
value={formData.taskName}
|
||||
onChange={(e) => updateFormData({ taskName: e.target.value })}
|
||||
className="mt-1"
|
||||
/>
|
||||
{errors.taskName && <p className="text-red-500 text-sm mt-1">{errors.taskName}</p>}
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label className="text-base">分析类型(可多选)</Label>
|
||||
|
||||
{errors.analysisTypes && <p className="text-red-500 text-sm">{errors.analysisTypes}</p>}
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
{analysisTypes.map((type) => (
|
||||
<Card
|
||||
key={type.id}
|
||||
className={`p-4 cursor-pointer hover:shadow-md transition-shadow ${
|
||||
formData.analysisTypes.includes(type.id) ? "border-2 border-blue-500" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start space-x-3">
|
||||
<Checkbox
|
||||
id={`type-${type.id}`}
|
||||
checked={formData.analysisTypes.includes(type.id)}
|
||||
onCheckedChange={(checked) => handleAnalysisTypeChange(type.id, checked as boolean)}
|
||||
className="mt-1"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<Label htmlFor={`type-${type.id}`} className="flex items-center cursor-pointer">
|
||||
<div className="mr-2">{type.icon}</div>
|
||||
<span className="font-medium">{type.name}</span>
|
||||
</Label>
|
||||
<p className="text-sm text-gray-500 mt-1">{type.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end pt-4">
|
||||
<Button onClick={handleNext}>下一步</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect } from "react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Search, Tag, MapPin } from "lucide-react"
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert"
|
||||
import { AlertCircle } from "lucide-react"
|
||||
import { DeviceSelector } from "@/app/components/DeviceSelector"
|
||||
|
||||
interface TargetSelectionProps {
|
||||
formData: {
|
||||
targetType: string
|
||||
selectedDevices: string[]
|
||||
selectedTrafficPool: string
|
||||
tags: string[]
|
||||
regions: string[]
|
||||
keywords: string[]
|
||||
}
|
||||
updateFormData: (
|
||||
data: Partial<{
|
||||
targetType: string
|
||||
selectedDevices: string[]
|
||||
selectedTrafficPool: string
|
||||
tags: string[]
|
||||
regions: string[]
|
||||
keywords: string[]
|
||||
}>,
|
||||
) => void
|
||||
onSubmit: () => void
|
||||
onBack: () => void
|
||||
}
|
||||
|
||||
interface TrafficUser {
|
||||
id: string
|
||||
avatar: string
|
||||
nickname: string
|
||||
wechatId: string
|
||||
phone: string
|
||||
region: string
|
||||
tags: string[]
|
||||
addTime: string
|
||||
source: string
|
||||
}
|
||||
|
||||
export function TargetSelection({ formData, updateFormData, onSubmit, onBack }: TargetSelectionProps) {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [trafficUsers, setTrafficUsers] = useState<TrafficUser[]>([])
|
||||
const [searchQuery, setSearchQuery] = useState("")
|
||||
const [selectedTags, setSelectedTags] = useState<string[]>([])
|
||||
const [selectedRegions, setSelectedRegions] = useState<string[]>([])
|
||||
const [errors, setErrors] = useState<{ selection?: string }>({})
|
||||
|
||||
// 模拟加载流量池用户数据
|
||||
useEffect(() => {
|
||||
const fetchTrafficUsers = async () => {
|
||||
setIsLoading(true)
|
||||
await new Promise((resolve) => setTimeout(resolve, 800))
|
||||
|
||||
const mockUsers: TrafficUser[] = [
|
||||
{
|
||||
id: "user-1",
|
||||
avatar: "/placeholder.svg?height=40&width=40",
|
||||
nickname: "张小明",
|
||||
wechatId: "zhangxm123",
|
||||
phone: "138****1234",
|
||||
region: "北京",
|
||||
tags: ["新用户", "低活跃度"],
|
||||
addTime: "2023-10-15",
|
||||
source: "朋友圈",
|
||||
},
|
||||
{
|
||||
id: "user-2",
|
||||
avatar: "/placeholder.svg?height=40&width=40",
|
||||
nickname: "李华",
|
||||
wechatId: "lihua456",
|
||||
phone: "139****5678",
|
||||
region: "上海",
|
||||
tags: ["高消费", "高活跃度"],
|
||||
addTime: "2023-09-20",
|
||||
source: "群聊",
|
||||
},
|
||||
{
|
||||
id: "user-3",
|
||||
avatar: "/placeholder.svg?height=40&width=40",
|
||||
nickname: "王芳",
|
||||
wechatId: "wangfang789",
|
||||
phone: "137****9012",
|
||||
region: "广州",
|
||||
tags: ["潜在客户", "有购买意向"],
|
||||
addTime: "2023-11-05",
|
||||
source: "搜索",
|
||||
},
|
||||
{
|
||||
id: "user-4",
|
||||
avatar: "/placeholder.svg?height=40&width=40",
|
||||
nickname: "赵明",
|
||||
wechatId: "zhaoming321",
|
||||
phone: "136****3456",
|
||||
region: "深圳",
|
||||
tags: ["网购达人", "中高消费"],
|
||||
addTime: "2023-10-28",
|
||||
source: "附近的人",
|
||||
},
|
||||
{
|
||||
id: "user-5",
|
||||
avatar: "/placeholder.svg?height=40&width=40",
|
||||
nickname: "刘洋",
|
||||
wechatId: "liuyang654",
|
||||
phone: "135****7890",
|
||||
region: "杭州",
|
||||
tags: ["90后", "学生"],
|
||||
addTime: "2023-11-10",
|
||||
source: "名片",
|
||||
},
|
||||
{
|
||||
id: "user-6",
|
||||
avatar: "/placeholder.svg?height=40&width=40",
|
||||
nickname: "陈静",
|
||||
wechatId: "chenjing987",
|
||||
phone: "134****1234",
|
||||
region: "成都",
|
||||
tags: ["00后", "学生"],
|
||||
addTime: "2023-11-15",
|
||||
source: "朋友推荐",
|
||||
},
|
||||
{
|
||||
id: "user-7",
|
||||
avatar: "/placeholder.svg?height=40&width=40",
|
||||
nickname: "林小红",
|
||||
wechatId: "linxh123",
|
||||
phone: "133****5678",
|
||||
region: "南京",
|
||||
tags: ["潜在客户", "华东地区"],
|
||||
addTime: "2023-10-05",
|
||||
source: "扫码",
|
||||
},
|
||||
{
|
||||
id: "user-8",
|
||||
avatar: "/placeholder.svg?height=40&width=40",
|
||||
nickname: "黄强",
|
||||
wechatId: "huangq456",
|
||||
phone: "132****9012",
|
||||
region: "武汉",
|
||||
tags: ["高消费", "有购买意向"],
|
||||
addTime: "2023-09-15",
|
||||
source: "朋友圈",
|
||||
},
|
||||
]
|
||||
|
||||
setTrafficUsers(mockUsers)
|
||||
setIsLoading(false)
|
||||
}
|
||||
|
||||
fetchTrafficUsers()
|
||||
}, [])
|
||||
|
||||
const allTags = Array.from(new Set(trafficUsers.flatMap((user) => user.tags)))
|
||||
const allRegions = Array.from(new Set(trafficUsers.map((user) => user.region)))
|
||||
|
||||
const filteredUsers = trafficUsers.filter((user) => {
|
||||
const matchesSearch =
|
||||
user.nickname.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
user.wechatId.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
user.region.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
user.tags.some((tag) => tag.toLowerCase().includes(searchQuery.toLowerCase()))
|
||||
|
||||
const matchesTags = selectedTags.length === 0 || selectedTags.some((tag) => user.tags.includes(tag))
|
||||
|
||||
const matchesRegions = selectedRegions.length === 0 || selectedRegions.includes(user.region)
|
||||
|
||||
return matchesSearch && matchesTags && matchesRegions
|
||||
})
|
||||
|
||||
const handleDeviceSelect = (deviceIds: string[]) => {
|
||||
updateFormData({ selectedDevices: deviceIds })
|
||||
}
|
||||
|
||||
const handleUserSelect = (userId: string) => {
|
||||
updateFormData({
|
||||
selectedTrafficPool: userId === formData.selectedTrafficPool ? "" : userId,
|
||||
})
|
||||
}
|
||||
|
||||
const handleTagSelect = (tag: string) => {
|
||||
setSelectedTags((prev) => (prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]))
|
||||
}
|
||||
|
||||
const handleRegionSelect = (region: string) => {
|
||||
setSelectedRegions((prev) => (prev.includes(region) ? prev.filter((r) => r !== region) : [...prev, region]))
|
||||
}
|
||||
|
||||
const validateForm = () => {
|
||||
const newErrors: { selection?: string } = {}
|
||||
|
||||
if (formData.targetType === "device" && formData.selectedDevices.length === 0) {
|
||||
newErrors.selection = "请至少选择一个设备"
|
||||
} else if (formData.targetType === "trafficPool" && !formData.selectedTrafficPool) {
|
||||
newErrors.selection = "请选择一个流量池"
|
||||
}
|
||||
|
||||
setErrors(newErrors)
|
||||
return Object.keys(newErrors).length === 0
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (validateForm()) {
|
||||
onSubmit()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold mb-4">选择分析对象</h2>
|
||||
<p className="text-gray-500 mb-6">选择要分析的设备或流量池</p>
|
||||
</div>
|
||||
|
||||
<Tabs
|
||||
defaultValue="device"
|
||||
onValueChange={(value) => updateFormData({ targetType: value })}
|
||||
value={formData.targetType}
|
||||
>
|
||||
<TabsList className="grid w-full grid-cols-2 mb-6">
|
||||
<TabsTrigger value="device">设备列表</TabsTrigger>
|
||||
<TabsTrigger value="trafficPool">流量池</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="device" className="space-y-4">
|
||||
<DeviceSelector
|
||||
onSelect={handleDeviceSelect}
|
||||
initialSelectedDevices={formData.selectedDevices}
|
||||
excludeUsedDevices={false}
|
||||
/>
|
||||
|
||||
{errors.selection && formData.targetType === "device" && (
|
||||
<p className="text-red-500 text-sm">{errors.selection}</p>
|
||||
)}
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="trafficPool" className="space-y-6">
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="relative flex-1">
|
||||
<Search className="absolute left-3 top-2.5 h-4 w-4 text-gray-400" />
|
||||
<Input
|
||||
placeholder="搜索标签、地区、昵称信息"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="pl-9"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-2 items-center">
|
||||
<Label className="flex items-center">
|
||||
<Tag className="h-4 w-4 mr-1" />
|
||||
<span>标签筛选:</span>
|
||||
</Label>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{allTags.map((tag) => (
|
||||
<Badge
|
||||
key={tag}
|
||||
variant={selectedTags.includes(tag) ? "default" : "outline"}
|
||||
className="cursor-pointer"
|
||||
onClick={() => handleTagSelect(tag)}
|
||||
>
|
||||
{tag}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-2 items-center">
|
||||
<Label className="flex items-center">
|
||||
<MapPin className="h-4 w-4 mr-1" />
|
||||
<span>地区筛选:</span>
|
||||
</Label>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{allRegions.map((region) => (
|
||||
<Badge
|
||||
key={region}
|
||||
variant={selectedRegions.includes(region) ? "default" : "outline"}
|
||||
className="cursor-pointer"
|
||||
onClick={() => handleRegionSelect(region)}
|
||||
>
|
||||
{region}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="flex justify-center py-12">
|
||||
<div className="w-8 h-8 border-4 border-t-blue-500 border-blue-200 rounded-full animate-spin"></div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="overflow-hidden rounded-md border">
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
<tr className="bg-gray-50">
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-500">用户</th>
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-500">微信号</th>
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-500">地区</th>
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-500">标签</th>
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-500">来源</th>
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-500">添加时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{filteredUsers.map((user) => (
|
||||
<tr
|
||||
key={user.id}
|
||||
className={`border-t hover:bg-gray-50 cursor-pointer ${
|
||||
formData.selectedTrafficPool === user.id ? "bg-blue-50" : ""
|
||||
}`}
|
||||
onClick={() => handleUserSelect(user.id)}
|
||||
>
|
||||
<td className="px-4 py-3 text-sm">
|
||||
<div className="flex items-center">
|
||||
<div className="h-8 w-8 flex-shrink-0 rounded-full overflow-hidden mr-3">
|
||||
<img
|
||||
src={user.avatar || "/placeholder.svg"}
|
||||
alt={user.nickname}
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-medium">{user.nickname}</div>
|
||||
<div className="text-gray-500 text-xs">{user.phone}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-sm">{user.wechatId}</td>
|
||||
<td className="px-4 py-3 text-sm">{user.region}</td>
|
||||
<td className="px-4 py-3 text-sm">
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{user.tags.map((tag) => (
|
||||
<Badge key={tag} variant="secondary" className="text-xs">
|
||||
{tag}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-sm">{user.source}</td>
|
||||
<td className="px-4 py-3 text-sm">{user.addTime}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{filteredUsers.length === 0 && !isLoading && (
|
||||
<div className="text-center py-8 bg-gray-50 rounded-lg border">
|
||||
<p className="text-gray-500">没有找到符合条件的微信用户</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{errors.selection && formData.targetType === "trafficPool" && (
|
||||
<p className="text-red-500 text-sm">{errors.selection}</p>
|
||||
)}
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
{formData.targetType === "device" && formData.selectedDevices.length > 0 && (
|
||||
<Alert className="bg-blue-50 border-blue-200">
|
||||
<AlertCircle className="h-4 w-4 text-blue-500" />
|
||||
<AlertDescription className="text-blue-700">
|
||||
已选择 {formData.selectedDevices.length} 个设备进行分析
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{formData.targetType === "trafficPool" && formData.selectedTrafficPool && (
|
||||
<Alert className="bg-blue-50 border-blue-200">
|
||||
<AlertCircle className="h-4 w-4 text-blue-500" />
|
||||
<AlertDescription className="text-blue-700">
|
||||
已选择用户: {trafficUsers.find((u) => u.id === formData.selectedTrafficPool)?.nickname}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<div className="flex justify-between pt-4">
|
||||
<Button variant="outline" onClick={onBack}>
|
||||
上一步
|
||||
</Button>
|
||||
<Button onClick={handleSubmit}>提交</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
103
Cunkebao/app/workspace/ai-analyzer/create/page.tsx
Normal file
103
Cunkebao/app/workspace/ai-analyzer/create/page.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { BasicSettings } from "./components/basic-settings"
|
||||
import { TargetSelection } from "./components/target-selection"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { Steps, Step } from "@/components/ui/steps"
|
||||
import { useToast } from "@/components/ui/use-toast"
|
||||
|
||||
export default function CreateAnalyzerPage() {
|
||||
const router = useRouter()
|
||||
const { toast } = useToast()
|
||||
const [currentStep, setCurrentStep] = useState(0)
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
taskName: "",
|
||||
analysisTypes: [] as string[],
|
||||
targetType: "device",
|
||||
selectedDevices: [] as string[],
|
||||
selectedTrafficPool: "",
|
||||
tags: [] as string[],
|
||||
regions: [] as string[],
|
||||
keywords: [] as string[],
|
||||
})
|
||||
|
||||
const updateFormData = (data: Partial<typeof formData>) => {
|
||||
setFormData((prev) => ({ ...prev, ...data }))
|
||||
}
|
||||
|
||||
const handleNext = () => {
|
||||
setCurrentStep(1)
|
||||
}
|
||||
|
||||
const handleBack = () => {
|
||||
setCurrentStep(0)
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// 模拟提交
|
||||
try {
|
||||
// 显示加载状态
|
||||
toast({
|
||||
title: "正在创建分析计划...",
|
||||
description: "请稍候",
|
||||
})
|
||||
|
||||
// 模拟API请求延迟
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500))
|
||||
|
||||
// 成功提示
|
||||
toast({
|
||||
title: "分析计划创建成功",
|
||||
description: "您可以在列表中查看分析进度",
|
||||
variant: "success",
|
||||
})
|
||||
|
||||
// 跳转回列表页
|
||||
router.push("/workspace/ai-analyzer")
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: "创建失败",
|
||||
description: "请稍后重试",
|
||||
variant: "destructive",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const steps = [
|
||||
{ id: "basic", title: "基础设置" },
|
||||
{ id: "target", title: "选择分析对象" },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="container max-w-4xl py-6">
|
||||
<div className="mb-8">
|
||||
<Steps currentStep={currentStep} className="mb-8">
|
||||
{steps.map((step, index) => (
|
||||
<Step key={step.id} title={step.title} />
|
||||
))}
|
||||
</Steps>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
{currentStep === 0 && (
|
||||
<BasicSettings formData={formData} updateFormData={updateFormData} onNext={handleNext} />
|
||||
)}
|
||||
|
||||
{currentStep === 1 && (
|
||||
<TargetSelection
|
||||
formData={formData}
|
||||
updateFormData={updateFormData}
|
||||
onBack={handleBack}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user