Refactor homepage for focused search and data display; streamline data platform; enhance user and tag management; focus AI assistant on data analysis and report generation. Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
695 lines
27 KiB
TypeScript
695 lines
27 KiB
TypeScript
"use client"
|
||
|
||
import { useState } from "react"
|
||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||
import { Button } from "@/components/ui/button"
|
||
import { Input } from "@/components/ui/input"
|
||
import { Badge } from "@/components/ui/badge"
|
||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||
import { Progress } from "@/components/ui/progress"
|
||
import { Switch } from "@/components/ui/switch"
|
||
import { Label } from "@/components/ui/label"
|
||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||
import { Textarea } from "@/components/ui/textarea"
|
||
import {
|
||
Database,
|
||
Activity,
|
||
AlertCircle,
|
||
CheckCircle,
|
||
Clock,
|
||
Brain,
|
||
Search,
|
||
Filter,
|
||
Download,
|
||
Settings,
|
||
RefreshCw,
|
||
Shield,
|
||
BarChart3,
|
||
Plus,
|
||
RotateCcw,
|
||
Target,
|
||
} from "lucide-react"
|
||
import { TooltipHelp, TooltipProvider } from "@/components/ui/tooltip-help"
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogDescription,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
DialogFooter,
|
||
} from "@/components/ui/dialog"
|
||
|
||
export default function DataPlatformPage() {
|
||
const [selectedSource, setSelectedSource] = useState("all")
|
||
const [searchQuery, setSearchQuery] = useState("")
|
||
const [isAddingSource, setIsAddingSource] = useState(false)
|
||
const [isTrainingModel, setIsTrainingModel] = useState(false)
|
||
const [selectedModel, setSelectedModel] = useState<string | null>(null)
|
||
|
||
// 数据源管理
|
||
const [dataSources, setDataSources] = useState([
|
||
{
|
||
id: "1",
|
||
name: "用户行为数据库",
|
||
type: "MySQL",
|
||
status: "connected",
|
||
lastSync: "2分钟前",
|
||
records: 1200000,
|
||
description: "用户行为轨迹和交互数据",
|
||
connectionString: "mysql://localhost:3306/user_behavior",
|
||
},
|
||
{
|
||
id: "2",
|
||
name: "触客宝API",
|
||
type: "REST API",
|
||
status: "connected",
|
||
lastSync: "5分钟前",
|
||
records: 856000,
|
||
description: "客户通话记录和服务数据",
|
||
connectionString: "https://api.chukebao.com/v1",
|
||
},
|
||
{
|
||
id: "3",
|
||
name: "抖音数据接口",
|
||
type: "API",
|
||
status: "syncing",
|
||
lastSync: "10分钟前",
|
||
records: 324000,
|
||
description: "抖音平台内容和用户数据",
|
||
connectionString: "https://api.douyin.com/data",
|
||
},
|
||
{
|
||
id: "4",
|
||
name: "小红书数据源",
|
||
type: "API",
|
||
status: "connected",
|
||
lastSync: "3分钟前",
|
||
records: 567000,
|
||
description: "小红书用户画像和内容数据",
|
||
connectionString: "https://api.xiaohongshu.com/user",
|
||
},
|
||
{
|
||
id: "5",
|
||
name: "微信生态数据",
|
||
type: "Database",
|
||
status: "connected",
|
||
lastSync: "1分钟前",
|
||
records: 2340000,
|
||
description: "微信用户关系和群组数据",
|
||
connectionString: "mongodb://localhost:27017/wechat_data",
|
||
},
|
||
])
|
||
|
||
// AI模型管理
|
||
const [aiModels, setAiModels] = useState([
|
||
{
|
||
id: "1",
|
||
name: "用户画像模型",
|
||
type: "classification",
|
||
status: "active",
|
||
accuracy: 94.2,
|
||
lastTrained: "2024-01-10",
|
||
predictions: 15420,
|
||
trainingData: "用户行为数据",
|
||
parameters: {
|
||
algorithm: "Random Forest",
|
||
features: 156,
|
||
epochs: 100,
|
||
learningRate: 0.001,
|
||
},
|
||
},
|
||
{
|
||
id: "2",
|
||
name: "流失预测模型",
|
||
type: "prediction",
|
||
status: "active",
|
||
accuracy: 88.7,
|
||
lastTrained: "2024-01-12",
|
||
predictions: 8765,
|
||
trainingData: "用户活跃度数据",
|
||
parameters: {
|
||
algorithm: "XGBoost",
|
||
features: 89,
|
||
epochs: 150,
|
||
learningRate: 0.01,
|
||
},
|
||
},
|
||
{
|
||
id: "3",
|
||
name: "价值评估模型",
|
||
type: "regression",
|
||
status: "training",
|
||
accuracy: 91.3,
|
||
lastTrained: "2024-01-08",
|
||
predictions: 12340,
|
||
trainingData: "交易和行为数据",
|
||
parameters: {
|
||
algorithm: "Neural Network",
|
||
features: 234,
|
||
epochs: 200,
|
||
learningRate: 0.005,
|
||
},
|
||
},
|
||
{
|
||
id: "4",
|
||
name: "行为预测模型",
|
||
type: "prediction",
|
||
status: "active",
|
||
accuracy: 86.5,
|
||
lastTrained: "2024-01-14",
|
||
predictions: 9876,
|
||
trainingData: "用户行为序列",
|
||
parameters: {
|
||
algorithm: "LSTM",
|
||
features: 67,
|
||
epochs: 80,
|
||
learningRate: 0.002,
|
||
},
|
||
},
|
||
])
|
||
|
||
const getStatusIcon = (status: string) => {
|
||
switch (status) {
|
||
case "connected":
|
||
return <CheckCircle className="h-4 w-4 text-green-500" />
|
||
case "syncing":
|
||
return <RefreshCw className="h-4 w-4 text-blue-500 animate-spin" />
|
||
case "error":
|
||
return <AlertCircle className="h-4 w-4 text-red-500" />
|
||
case "active":
|
||
return <Activity className="h-4 w-4 text-green-500" />
|
||
case "training":
|
||
return <Brain className="h-4 w-4 text-blue-500 animate-pulse" />
|
||
default:
|
||
return <Clock className="h-4 w-4 text-gray-500" />
|
||
}
|
||
}
|
||
|
||
const getStatusBadge = (status: string) => {
|
||
switch (status) {
|
||
case "connected":
|
||
return <Badge className="bg-green-100 text-green-800">已连接</Badge>
|
||
case "syncing":
|
||
return <Badge className="bg-blue-100 text-blue-800">同步中</Badge>
|
||
case "error":
|
||
return <Badge className="bg-red-100 text-red-800">错误</Badge>
|
||
case "active":
|
||
return <Badge className="bg-green-100 text-green-800">运行中</Badge>
|
||
case "training":
|
||
return <Badge className="bg-blue-100 text-blue-800">训练中</Badge>
|
||
default:
|
||
return <Badge className="bg-gray-100 text-gray-800">未知</Badge>
|
||
}
|
||
}
|
||
|
||
// 添加数据源
|
||
const handleAddDataSource = () => {
|
||
setIsAddingSource(true)
|
||
}
|
||
|
||
// 导入数据源数据
|
||
const handleImportData = (sourceId: string) => {
|
||
const source = dataSources.find((s) => s.id === sourceId)
|
||
if (source) {
|
||
// 模拟数据导入过程
|
||
setDataSources((prev) =>
|
||
prev.map((s) => (s.id === sourceId ? { ...s, status: "syncing", lastSync: "正在同步..." } : s)),
|
||
)
|
||
|
||
setTimeout(() => {
|
||
setDataSources((prev) =>
|
||
prev.map((s) =>
|
||
s.id === sourceId
|
||
? {
|
||
...s,
|
||
status: "connected",
|
||
lastSync: "刚刚",
|
||
records: s.records + Math.floor(Math.random() * 10000),
|
||
}
|
||
: s,
|
||
),
|
||
)
|
||
}, 3000)
|
||
}
|
||
}
|
||
|
||
// 重新训练模型
|
||
const handleRetrainModel = (modelId: string) => {
|
||
setAiModels((prev) =>
|
||
prev.map((m) => (m.id === modelId ? { ...m, status: "training", lastTrained: "训练中..." } : m)),
|
||
)
|
||
|
||
setTimeout(() => {
|
||
setAiModels((prev) =>
|
||
prev.map((m) =>
|
||
m.id === modelId
|
||
? {
|
||
...m,
|
||
status: "active",
|
||
lastTrained: new Date().toISOString().split("T")[0],
|
||
accuracy: Math.min(95, m.accuracy + Math.random() * 2),
|
||
}
|
||
: m,
|
||
),
|
||
)
|
||
}, 5000)
|
||
}
|
||
|
||
return (
|
||
<TooltipProvider>
|
||
<div className="container mx-auto p-6 space-y-6">
|
||
{/* 页面标题 */}
|
||
<div className="flex items-center justify-between">
|
||
<div>
|
||
<h1 className="text-3xl font-bold flex items-center gap-2">
|
||
<Database className="h-8 w-8 text-blue-600" />
|
||
数据中台
|
||
</h1>
|
||
<p className="text-muted-foreground mt-2">统一数据管理和AI模型训练平台</p>
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
<Button variant="outline" size="sm">
|
||
<Download className="h-4 w-4 mr-2" />
|
||
导出配置
|
||
</Button>
|
||
<Button size="sm">
|
||
<Settings className="h-4 w-4 mr-2" />
|
||
系统设置
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 核心指标概览 */}
|
||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||
<Card>
|
||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||
<CardTitle className="text-sm font-medium flex items-center gap-1">
|
||
数据源
|
||
<TooltipHelp content="已接入的数据源总数,支持实时同步" />
|
||
</CardTitle>
|
||
<Database className="h-4 w-4 text-muted-foreground" />
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="text-2xl font-bold">{dataSources.length}</div>
|
||
<p className="text-xs text-muted-foreground">
|
||
<span className="text-green-600">{dataSources.filter((s) => s.status === "connected").length}</span>{" "}
|
||
个正常运行
|
||
</p>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||
<CardTitle className="text-sm font-medium flex items-center gap-1">
|
||
数据记录
|
||
<TooltipHelp content="所有数据源中的记录总数" />
|
||
</CardTitle>
|
||
<BarChart3 className="h-4 w-4 text-muted-foreground" />
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="text-2xl font-bold">
|
||
{(dataSources.reduce((sum, source) => sum + source.records, 0) / 1000000).toFixed(1)}M
|
||
</div>
|
||
<p className="text-xs text-muted-foreground">较昨日 +2.3%</p>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||
<CardTitle className="text-sm font-medium flex items-center gap-1">
|
||
AI模型
|
||
<TooltipHelp content="运行中的AI模型数量和平均准确率" />
|
||
</CardTitle>
|
||
<Brain className="h-4 w-4 text-muted-foreground" />
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="text-2xl font-bold">{aiModels.filter((m) => m.status === "active").length}</div>
|
||
<p className="text-xs text-muted-foreground">
|
||
平均准确率 {(aiModels.reduce((sum, m) => sum + m.accuracy, 0) / aiModels.length).toFixed(1)}%
|
||
</p>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||
<CardTitle className="text-sm font-medium flex items-center gap-1">
|
||
系统状态
|
||
<TooltipHelp content="整体系统健康状态和可用性" />
|
||
</CardTitle>
|
||
<Shield className="h-4 w-4 text-muted-foreground" />
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="text-2xl font-bold text-green-600">99.8%</div>
|
||
<p className="text-xs text-muted-foreground">系统可用性</p>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
|
||
{/* 主要功能区域 */}
|
||
<Tabs defaultValue="sources" className="space-y-6">
|
||
<TabsList className="grid w-full grid-cols-2">
|
||
<TabsTrigger value="sources">数据源管理</TabsTrigger>
|
||
<TabsTrigger value="ai-models">AI模型</TabsTrigger>
|
||
</TabsList>
|
||
|
||
{/* 数据源管理 */}
|
||
<TabsContent value="sources" className="space-y-6">
|
||
<Card>
|
||
<CardHeader>
|
||
<div className="flex justify-between items-center">
|
||
<div>
|
||
<CardTitle className="flex items-center gap-2">
|
||
<Database className="h-5 w-5" />
|
||
数据源管理
|
||
<TooltipHelp content="管理所有数据源的连接、同步和数据导入" />
|
||
</CardTitle>
|
||
<CardDescription>统一管理多源异构数据,支持一键导入所有数据</CardDescription>
|
||
</div>
|
||
<div className="flex space-x-2">
|
||
<div className="relative">
|
||
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
||
<Input
|
||
placeholder="搜索数据源..."
|
||
className="pl-8 w-64"
|
||
value={searchQuery}
|
||
onChange={(e) => setSearchQuery(e.target.value)}
|
||
/>
|
||
</div>
|
||
<Button variant="outline" size="sm">
|
||
<Filter className="mr-2 h-4 w-4" />
|
||
筛选
|
||
</Button>
|
||
<Button size="sm" onClick={handleAddDataSource}>
|
||
<Plus className="mr-2 h-4 w-4" />
|
||
添加数据源
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<Table>
|
||
<TableHeader>
|
||
<TableRow>
|
||
<TableHead>数据源名称</TableHead>
|
||
<TableHead>类型</TableHead>
|
||
<TableHead>状态</TableHead>
|
||
<TableHead>记录数</TableHead>
|
||
<TableHead>最后同步</TableHead>
|
||
<TableHead>操作</TableHead>
|
||
</TableRow>
|
||
</TableHeader>
|
||
<TableBody>
|
||
{dataSources.map((source) => (
|
||
<TableRow key={source.id}>
|
||
<TableCell>
|
||
<div>
|
||
<div className="font-medium">{source.name}</div>
|
||
<div className="text-sm text-gray-500">{source.description}</div>
|
||
</div>
|
||
</TableCell>
|
||
<TableCell>
|
||
<Badge variant="outline">{source.type}</Badge>
|
||
</TableCell>
|
||
<TableCell>
|
||
<div className="flex items-center space-x-2">
|
||
{getStatusIcon(source.status)}
|
||
{getStatusBadge(source.status)}
|
||
</div>
|
||
</TableCell>
|
||
<TableCell>{source.records.toLocaleString()}</TableCell>
|
||
<TableCell>{source.lastSync}</TableCell>
|
||
<TableCell>
|
||
<div className="flex space-x-2">
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
onClick={() => handleImportData(source.id)}
|
||
disabled={source.status === "syncing"}
|
||
>
|
||
<Download className="h-4 w-4 mr-1" />
|
||
导入数据
|
||
</Button>
|
||
<Button variant="ghost" size="sm">
|
||
<Settings className="h-4 w-4" />
|
||
</Button>
|
||
<Button variant="ghost" size="sm">
|
||
<RefreshCw className="h-4 w-4" />
|
||
</Button>
|
||
</div>
|
||
</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</CardContent>
|
||
</Card>
|
||
</TabsContent>
|
||
|
||
{/* AI模型管理 */}
|
||
<TabsContent value="ai-models" className="space-y-6">
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
{aiModels.map((model) => (
|
||
<Card key={model.id} className="relative">
|
||
<CardHeader>
|
||
<div className="flex justify-between items-start">
|
||
<div>
|
||
<CardTitle className="text-base flex items-center gap-2">
|
||
<Brain className="h-5 w-5 text-purple-600" />
|
||
{model.name}
|
||
</CardTitle>
|
||
<CardDescription>类型: {model.type}</CardDescription>
|
||
</div>
|
||
{getStatusBadge(model.status)}
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="space-y-4">
|
||
<div className="flex justify-between items-center">
|
||
<span className="text-sm font-medium">准确率</span>
|
||
<span className="text-sm font-bold">{model.accuracy}%</span>
|
||
</div>
|
||
<Progress value={model.accuracy} className="h-2" />
|
||
|
||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||
<div>
|
||
<span className="text-muted-foreground">最后训练</span>
|
||
<div className="font-medium">{model.lastTrained}</div>
|
||
</div>
|
||
<div>
|
||
<span className="text-muted-foreground">预测次数</span>
|
||
<div className="font-medium">{model.predictions.toLocaleString()}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="text-sm">
|
||
<span className="text-muted-foreground">训练数据: </span>
|
||
<span className="font-medium">{model.trainingData}</span>
|
||
</div>
|
||
|
||
<div className="flex space-x-2">
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
className="flex-1 bg-transparent"
|
||
onClick={() => handleRetrainModel(model.id)}
|
||
disabled={model.status === "training"}
|
||
>
|
||
<RotateCcw className="h-4 w-4 mr-2" />
|
||
{model.status === "training" ? "训练中..." : "重新训练"}
|
||
</Button>
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
className="flex-1 bg-transparent"
|
||
onClick={() => setSelectedModel(model.id)}
|
||
>
|
||
<Settings className="h-4 w-4 mr-2" />
|
||
设置
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
))}
|
||
</div>
|
||
|
||
{/* 模型性能监控 */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle className="flex items-center gap-2">
|
||
<Target className="h-5 w-5" />
|
||
模型性能监控
|
||
</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 text-center">
|
||
<div>
|
||
<div className="text-2xl font-bold">
|
||
{aiModels.reduce((sum, m) => sum + m.predictions, 0).toLocaleString()}
|
||
</div>
|
||
<div className="text-sm text-muted-foreground">总预测次数</div>
|
||
</div>
|
||
<div>
|
||
<div className="text-2xl font-bold">
|
||
{(aiModels.reduce((sum, m) => sum + m.accuracy, 0) / aiModels.length).toFixed(1)}%
|
||
</div>
|
||
<div className="text-sm text-muted-foreground">平均准确率</div>
|
||
</div>
|
||
<div>
|
||
<div className="text-2xl font-bold">156ms</div>
|
||
<div className="text-sm text-muted-foreground">平均响应时间</div>
|
||
</div>
|
||
<div>
|
||
<div className="text-2xl font-bold">99.8%</div>
|
||
<div className="text-sm text-muted-foreground">服务可用性</div>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</TabsContent>
|
||
</Tabs>
|
||
|
||
{/* 添加数据源对话框 */}
|
||
<Dialog open={isAddingSource} onOpenChange={setIsAddingSource}>
|
||
<DialogContent className="sm:max-w-[500px]">
|
||
<DialogHeader>
|
||
<DialogTitle>添加数据源</DialogTitle>
|
||
<DialogDescription>配置新的数据源连接,支持自动导入所有数据</DialogDescription>
|
||
</DialogHeader>
|
||
<div className="grid gap-4 py-4">
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label htmlFor="source-name" className="text-right">
|
||
数据源名称
|
||
</Label>
|
||
<Input id="source-name" className="col-span-3" placeholder="例如:用户行为数据库" />
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label htmlFor="source-type" className="text-right">
|
||
数据源类型
|
||
</Label>
|
||
<Select>
|
||
<SelectTrigger id="source-type" className="col-span-3">
|
||
<SelectValue placeholder="选择数据源类型" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="mysql">MySQL</SelectItem>
|
||
<SelectItem value="postgresql">PostgreSQL</SelectItem>
|
||
<SelectItem value="mongodb">MongoDB</SelectItem>
|
||
<SelectItem value="api">REST API</SelectItem>
|
||
<SelectItem value="file">文件导入</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label htmlFor="connection-string" className="text-right">
|
||
连接字符串
|
||
</Label>
|
||
<Input
|
||
id="connection-string"
|
||
className="col-span-3"
|
||
placeholder="例如:mysql://user:pass@host:port/db"
|
||
/>
|
||
</div>
|
||
<div className="grid grid-cols-4 items-start gap-4">
|
||
<Label htmlFor="description" className="text-right pt-2">
|
||
描述
|
||
</Label>
|
||
<Textarea id="description" className="col-span-3" placeholder="数据源描述信息" rows={3} />
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<div className="text-right">
|
||
<Label htmlFor="auto-import">自动导入</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2 col-span-3">
|
||
<Switch id="auto-import" defaultChecked />
|
||
<Label htmlFor="auto-import">连接成功后自动导入所有数据</Label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<DialogFooter>
|
||
<Button variant="outline" onClick={() => setIsAddingSource(false)}>
|
||
取消
|
||
</Button>
|
||
<Button onClick={() => setIsAddingSource(false)}>
|
||
<Plus className="mr-2 h-4 w-4" />
|
||
添加数据源
|
||
</Button>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
|
||
{/* 模型设置对话框 */}
|
||
<Dialog open={!!selectedModel} onOpenChange={(open) => !open && setSelectedModel(null)}>
|
||
<DialogContent className="sm:max-w-[600px]">
|
||
<DialogHeader>
|
||
<DialogTitle>模型设置</DialogTitle>
|
||
<DialogDescription>配置AI模型的训练参数和设置</DialogDescription>
|
||
</DialogHeader>
|
||
{selectedModel && (
|
||
<div className="grid gap-4 py-4">
|
||
{(() => {
|
||
const model = aiModels.find((m) => m.id === selectedModel)
|
||
if (!model) return null
|
||
return (
|
||
<>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label className="text-right">模型名称</Label>
|
||
<Input className="col-span-3" defaultValue={model.name} />
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label className="text-right">算法</Label>
|
||
<Select defaultValue={model.parameters.algorithm}>
|
||
<SelectTrigger className="col-span-3">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="Random Forest">Random Forest</SelectItem>
|
||
<SelectItem value="XGBoost">XGBoost</SelectItem>
|
||
<SelectItem value="Neural Network">Neural Network</SelectItem>
|
||
<SelectItem value="LSTM">LSTM</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label className="text-right">特征数量</Label>
|
||
<Input className="col-span-3" type="number" defaultValue={model.parameters.features} />
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label className="text-right">训练轮数</Label>
|
||
<Input className="col-span-3" type="number" defaultValue={model.parameters.epochs} />
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label className="text-right">学习率</Label>
|
||
<Input
|
||
className="col-span-3"
|
||
type="number"
|
||
step="0.001"
|
||
defaultValue={model.parameters.learningRate}
|
||
/>
|
||
</div>
|
||
<div className="grid grid-cols-4 items-start gap-4">
|
||
<Label className="text-right pt-2">训练数据</Label>
|
||
<Textarea className="col-span-3" defaultValue={model.trainingData} rows={3} />
|
||
</div>
|
||
</>
|
||
)
|
||
})()}
|
||
</div>
|
||
)}
|
||
<DialogFooter>
|
||
<Button variant="outline" onClick={() => setSelectedModel(null)}>
|
||
取消
|
||
</Button>
|
||
<Button onClick={() => setSelectedModel(null)}>
|
||
<Settings className="mr-2 h-4 w-4" />
|
||
保存设置
|
||
</Button>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
</div>
|
||
</TooltipProvider>
|
||
)
|
||
}
|