Files
users/components/dialogs/task-detail-dialog.tsx
v0 b17b488f8e refactor: restructure navigation and module layout
Reorganize navigation and module structure based on new requirements.

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
2026-01-31 04:32:36 +00:00

229 lines
8.4 KiB
TypeScript

"use client"
import { useState } from "react"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Progress } from "@/components/ui/progress"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { ScrollArea } from "@/components/ui/scroll-area"
import { Play, Pause, RefreshCw, Clock, CheckCircle, XCircle } from "lucide-react"
interface TaskDetailDialogProps {
open: boolean
onOpenChange: (open: boolean) => void
task?: {
id: string
name: string
type: string
status: string
progress: number
schedule: string
lastRun: string
nextRun: string
duration: string
}
}
const TASK_LOGS = [
{ time: "14:35:12", level: "INFO", message: "任务开始执行" },
{ time: "14:35:13", level: "INFO", message: "连接数据源成功" },
{ time: "14:35:15", level: "INFO", message: "开始读取数据 (批次 1/10)" },
{ time: "14:35:22", level: "INFO", message: "批次 1 处理完成, 共 12,895 条" },
{ time: "14:35:25", level: "INFO", message: "开始读取数据 (批次 2/10)" },
{ time: "14:35:32", level: "WARN", message: "批次 2 发现 3 条异常数据" },
{ time: "14:35:35", level: "INFO", message: "批次 2 处理完成, 共 12,456 条" },
{ time: "14:36:02", level: "INFO", message: "任务进度: 67%" },
]
const EXECUTION_STATS = [
{ label: "总处理记录", value: "128,956" },
{ label: "成功记录", value: "128,931" },
{ label: "失败记录", value: "25" },
{ label: "平均速度", value: "3,800 条/秒" },
{ label: "内存使用", value: "2.4 GB" },
{ label: "CPU使用", value: "45%" },
]
export function TaskDetailDialog({ open, onOpenChange, task }: TaskDetailDialogProps) {
const [activeTab, setActiveTab] = useState("overview")
const getStatusBadge = (status: string) => {
switch (status) {
case "running":
return (
<Badge className="bg-blue-100 text-blue-700">
<RefreshCw className="w-3 h-3 mr-1 animate-spin" />
</Badge>
)
case "completed":
return (
<Badge className="bg-emerald-100 text-emerald-700">
<CheckCircle className="w-3 h-3 mr-1" />
</Badge>
)
case "failed":
return (
<Badge className="bg-red-100 text-red-700">
<XCircle className="w-3 h-3 mr-1" />
</Badge>
)
case "waiting":
return (
<Badge className="bg-slate-100 text-slate-700">
<Clock className="w-3 h-3 mr-1" />
</Badge>
)
default:
return <Badge variant="secondary">{status}</Badge>
}
}
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-3xl">
<DialogHeader>
<DialogTitle className="flex items-center gap-3">
{task?.name || "任务详情"}
{getStatusBadge(task?.status || "waiting")}
</DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
{task?.status === "running" && (
<div className="p-4 bg-blue-50 rounded-lg">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium text-blue-700"></span>
<span className="text-sm font-medium text-blue-700">{task.progress}%</span>
</div>
<Progress value={task.progress} className="h-2" />
</div>
)}
<Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList className="grid w-full grid-cols-3">
<TabsTrigger value="overview"></TabsTrigger>
<TabsTrigger value="logs"></TabsTrigger>
<TabsTrigger value="config"></TabsTrigger>
</TabsList>
<TabsContent value="overview" className="mt-4 space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="p-4 bg-slate-50 rounded-lg">
<div className="flex items-center gap-2 text-slate-500 text-sm mb-1">
<Clock className="w-4 h-4" />
</div>
<code className="text-sm bg-white px-2 py-1 rounded">{task?.schedule || "*/5 * * * *"}</code>
</div>
<div className="p-4 bg-slate-50 rounded-lg">
<div className="flex items-center gap-2 text-slate-500 text-sm mb-1">
<Clock className="w-4 h-4" />
</div>
<p className="font-medium">{task?.duration || "2分30秒"}</p>
</div>
<div className="p-4 bg-slate-50 rounded-lg">
<div className="flex items-center gap-2 text-slate-500 text-sm mb-1">
<Clock className="w-4 h-4" />
</div>
<p className="font-medium">{task?.lastRun || "-"}</p>
</div>
<div className="p-4 bg-slate-50 rounded-lg">
<div className="flex items-center gap-2 text-slate-500 text-sm mb-1">
<Clock className="w-4 h-4" />
</div>
<p className="font-medium">{task?.nextRun || "-"}</p>
</div>
</div>
<div className="grid grid-cols-3 gap-4">
{EXECUTION_STATS.map((stat, i) => (
<div key={i} className="text-center p-3 bg-slate-50 rounded-lg">
<p className="text-lg font-bold text-slate-800">{stat.value}</p>
<p className="text-xs text-slate-500">{stat.label}</p>
</div>
))}
</div>
</TabsContent>
<TabsContent value="logs" className="mt-4">
<ScrollArea className="h-[300px] bg-slate-900 rounded-lg p-4">
<div className="space-y-1 font-mono text-sm">
{TASK_LOGS.map((log, i) => (
<div key={i} className="flex gap-3">
<span className="text-slate-500">{log.time}</span>
<span
className={`${
log.level === "WARN"
? "text-amber-400"
: log.level === "ERROR"
? "text-red-400"
: "text-blue-400"
}`}
>
[{log.level}]
</span>
<span className="text-slate-200">{log.message}</span>
</div>
))}
</div>
</ScrollArea>
</TabsContent>
<TabsContent value="config" className="mt-4 space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<label className="text-sm text-slate-500"></label>
<p className="font-medium">{task?.type || "数据同步"}</p>
</div>
<div className="space-y-2">
<label className="text-sm text-slate-500"></label>
<p className="font-medium">30</p>
</div>
<div className="space-y-2">
<label className="text-sm text-slate-500"></label>
<p className="font-medium">3</p>
</div>
<div className="space-y-2">
<label className="text-sm text-slate-500"></label>
<p className="font-medium">4</p>
</div>
</div>
</TabsContent>
</Tabs>
<DialogFooter>
<Button variant="outline" onClick={() => onOpenChange(false)}>
</Button>
{task?.status === "running" ? (
<Button variant="destructive">
<Pause className="w-4 h-4 mr-2" />
</Button>
) : (
<Button>
<Play className="w-4 h-4 mr-2" />
</Button>
)}
</DialogFooter>
</DialogContent>
</Dialog>
)
}