Reorganize navigation and module structure based on new requirements. Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
194 lines
7.4 KiB
TypeScript
194 lines
7.4 KiB
TypeScript
"use client"
|
||
|
||
import { useState } from "react"
|
||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"
|
||
import { Button } from "@/components/ui/button"
|
||
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 { Upload, FileCode, CheckCircle } from "lucide-react"
|
||
|
||
interface UploadModelDialogProps {
|
||
open: boolean
|
||
onOpenChange: (open: boolean) => void
|
||
}
|
||
|
||
export function UploadModelDialog({ open, onOpenChange }: UploadModelDialogProps) {
|
||
const [step, setStep] = useState(1)
|
||
const [formData, setFormData] = useState({
|
||
name: "",
|
||
category: "",
|
||
description: "",
|
||
inputFeatures: "",
|
||
outputFormat: "",
|
||
updateFrequency: "",
|
||
})
|
||
const [fileUploaded, setFileUploaded] = useState(false)
|
||
|
||
const handleFileUpload = () => {
|
||
setFileUploaded(true)
|
||
}
|
||
|
||
const handleSubmit = () => {
|
||
console.log("上传模型:", formData)
|
||
onOpenChange(false)
|
||
setStep(1)
|
||
setFileUploaded(false)
|
||
}
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
<DialogContent className="sm:max-w-[600px]">
|
||
<DialogHeader>
|
||
<DialogTitle>上传自定义模型</DialogTitle>
|
||
</DialogHeader>
|
||
|
||
<div className="flex items-center gap-4 mb-6">
|
||
{[1, 2, 3].map((s) => (
|
||
<div key={s} className="flex items-center gap-2">
|
||
<div
|
||
className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium ${step >= s ? "bg-blue-500 text-white" : "bg-gray-100 text-gray-500"}`}
|
||
>
|
||
{step > s ? <CheckCircle className="w-4 h-4" /> : s}
|
||
</div>
|
||
<span className={`text-sm ${step >= s ? "text-gray-900" : "text-gray-400"}`}>
|
||
{s === 1 ? "基本信息" : s === 2 ? "上传文件" : "配置参数"}
|
||
</span>
|
||
{s < 3 && <div className={`w-12 h-0.5 ${step > s ? "bg-blue-500" : "bg-gray-200"}`} />}
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{step === 1 && (
|
||
<div className="space-y-4">
|
||
<div className="space-y-2">
|
||
<Label>模型名称</Label>
|
||
<Input
|
||
placeholder="输入模型名称"
|
||
value={formData.name}
|
||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label>模型类别</Label>
|
||
<Select
|
||
value={formData.category}
|
||
onValueChange={(value) => setFormData({ ...formData, category: value })}
|
||
>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="选择类别" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="clv">CLV模型</SelectItem>
|
||
<SelectItem value="rfm">RFM模型</SelectItem>
|
||
<SelectItem value="churn">流失预警</SelectItem>
|
||
<SelectItem value="segment">用户分群</SelectItem>
|
||
<SelectItem value="other">其他</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label>模型描述</Label>
|
||
<Textarea
|
||
placeholder="描述模型的功能和用途"
|
||
value={formData.description}
|
||
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
||
/>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{step === 2 && (
|
||
<div className="space-y-4">
|
||
<div
|
||
className={`border-2 border-dashed rounded-xl p-8 text-center cursor-pointer transition-colors ${fileUploaded ? "border-green-500 bg-green-50" : "border-gray-300 hover:border-blue-500"}`}
|
||
onClick={handleFileUpload}
|
||
>
|
||
{fileUploaded ? (
|
||
<div className="space-y-2">
|
||
<CheckCircle className="w-12 h-12 mx-auto text-green-500" />
|
||
<p className="text-green-600 font-medium">model_v1.0.pkl</p>
|
||
<p className="text-sm text-gray-500">12.5 MB</p>
|
||
</div>
|
||
) : (
|
||
<div className="space-y-2">
|
||
<Upload className="w-12 h-12 mx-auto text-gray-400" />
|
||
<p className="text-gray-600">点击或拖拽上传模型文件</p>
|
||
<p className="text-sm text-gray-400">支持 .pkl, .h5, .pt, .onnx 格式</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
<div className="p-4 bg-blue-50 rounded-xl">
|
||
<div className="flex items-start gap-3">
|
||
<FileCode className="w-5 h-5 text-blue-500 mt-0.5" />
|
||
<div>
|
||
<p className="text-sm font-medium text-blue-800">模型文件要求</p>
|
||
<ul className="text-xs text-blue-600 mt-1 space-y-1">
|
||
<li>• 模型需要导出为标准格式(pickle, HDF5, PyTorch, ONNX)</li>
|
||
<li>• 文件大小不超过 500MB</li>
|
||
<li>• 需要包含预测接口函数</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{step === 3 && (
|
||
<div className="space-y-4">
|
||
<div className="space-y-2">
|
||
<Label>输入特征(逗号分隔)</Label>
|
||
<Input
|
||
placeholder="例如:消费金额,消费频次,最近购买"
|
||
value={formData.inputFeatures}
|
||
onChange={(e) => setFormData({ ...formData, inputFeatures: e.target.value })}
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label>输出格式</Label>
|
||
<Input
|
||
placeholder="例如:分数(0-100)"
|
||
value={formData.outputFormat}
|
||
onChange={(e) => setFormData({ ...formData, outputFormat: e.target.value })}
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label>更新频率</Label>
|
||
<Select
|
||
value={formData.updateFrequency}
|
||
onValueChange={(value) => setFormData({ ...formData, updateFrequency: value })}
|
||
>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="选择更新频率" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="realtime">实时</SelectItem>
|
||
<SelectItem value="daily">每天</SelectItem>
|
||
<SelectItem value="weekly">每周</SelectItem>
|
||
<SelectItem value="monthly">每月</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
<DialogFooter>
|
||
{step > 1 && (
|
||
<Button variant="outline" onClick={() => setStep(step - 1)}>
|
||
上一步
|
||
</Button>
|
||
)}
|
||
{step < 3 ? (
|
||
<Button onClick={() => setStep(step + 1)} disabled={step === 2 && !fileUploaded}>
|
||
下一步
|
||
</Button>
|
||
) : (
|
||
<Button onClick={handleSubmit}>提交模型</Button>
|
||
)}
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
)
|
||
}
|