haixunMaster/haixun-backend/web/src/components/Style8DJobPanel.tsx

58 lines
2.1 KiB
TypeScript

import { STYLE_8D_PIPELINE_STEPS } from '../lib/styleProfile'
import { jobStatusLabel } from '../lib/jobStatus'
import type { JobData } from '../types/api'
import { ProgressBar, StatusBadge } from './ui'
import { jobStatusBadgeClass } from '../lib/jobStatus'
const STEP_STATUS_LABEL: Record<string, string> = {
pending: '等待',
running: '進行中',
succeeded: '完成',
failed: '失敗',
skipped: '略過',
cancelled: '取消',
}
export function Style8DJobPanel({ job }: { job: JobData }) {
const steps = job.progress?.steps ?? []
const stepMap = new Map(steps.map((s) => [s.id, s]))
const pct = job.progress?.percentage ?? 0
return (
<div className="space-y-4">
<p className="text-sm leading-relaxed text-ink">{job.progress?.summary || '等待 Worker 接手…'}</p>
<div className="flex flex-wrap items-center gap-2">
<StatusBadge className={jobStatusBadgeClass(job.status)}>
{jobStatusLabel(job.status)}
</StatusBadge>
<span className="text-xs font-bold text-muted">{pct}%</span>
</div>
<ProgressBar value={pct} />
<ol className="flex flex-wrap gap-2 text-[11px]">
{STYLE_8D_PIPELINE_STEPS.map((step) => {
const live = stepMap.get(step.id)
const status = live?.status ?? 'pending'
const isDone = status === 'succeeded' || status === 'done'
const isRunning = status === 'running'
return (
<li
key={step.id}
className={`inline-flex items-center gap-1 rounded-[var(--radius-pill)] border-2 px-2.5 py-1 font-bold ${
isDone
? 'border-success/40 bg-success-soft text-success'
: isRunning
? 'border-brand/40 bg-brand-soft text-brand'
: 'border-line text-muted'
}`}
title={step.hint}
>
<span>{step.title}</span>
<span className="opacity-70">· {STEP_STATUS_LABEL[status] ?? status}</span>
</li>
)
})}
</ol>
</div>
)
}