Files
20260512-skg-tk/web/components/job-status.tsx
2026-05-14 10:25:50 +08:00

57 lines
2.4 KiB
TypeScript

"use client"
import { type Job, type JobStatus } from "@/lib/api"
import { CheckCircle2, Circle, Loader2, XCircle } from "lucide-react"
const STAGES: { key: JobStatus; label: string }[] = [
{ key: "downloading", label: "下载视频" },
{ key: "splitting", label: "拆分音视频" },
{ key: "frames_extracted", label: "抽取关键帧" },
{ key: "transcribing", label: "音频转写+改写" },
{ key: "transcribed", label: "完成" },
]
const ORDER: JobStatus[] = ["created", "downloading", "splitting", "frames_extracted", "transcribing", "transcribed"]
export function JobStatusBar({ job }: { job: Job }) {
const currentIdx = ORDER.indexOf(job.status)
return (
<div className="glass-card px-5 py-4">
<div className="flex items-center justify-between mb-3">
<div className="text-xs uppercase tracking-widest text-white/40">Job {job.id.slice(0, 8)}</div>
<div className="text-xs text-white/50">
{job.status === "failed" ? `失败: ${job.error ?? "未知错误"}` : (job.message ?? "")}
</div>
</div>
<div className="flex items-center gap-2">
{STAGES.map((s, i) => {
const stageIdx = ORDER.indexOf(s.key)
const done = currentIdx >= stageIdx && job.status !== "failed"
const active = currentIdx === stageIdx - 1 && job.status !== "failed" && job.status !== "transcribed"
const failed = job.status === "failed" && currentIdx + 1 === stageIdx
return (
<div key={s.key} className="flex items-center gap-2 flex-1">
<div className="flex items-center gap-2 min-w-0">
{failed ? (
<XCircle className="h-4 w-4 text-red-400 shrink-0" />
) : done ? (
<CheckCircle2 className="h-4 w-4 text-emerald-400 shrink-0" />
) : active ? (
<Loader2 className="h-4 w-4 text-white/70 animate-spin shrink-0" />
) : (
<Circle className="h-4 w-4 text-white/20 shrink-0" />
)}
<span className={`text-xs truncate ${done ? "text-white/80" : active ? "text-white/60" : "text-white/30"}`}>
{s.label}
</span>
</div>
{i < STAGES.length - 1 && (
<div className={`flex-1 h-px ${done ? "bg-emerald-400/30" : "bg-white/10"}`} />
)}
</div>
)
})}
</div>
</div>
)
}