57 lines
2.4 KiB
TypeScript
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: "Gemini 转录+翻译" },
|
|
{ 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>
|
|
)
|
|
}
|