75 lines
2.3 KiB
TypeScript
75 lines
2.3 KiB
TypeScript
"use client";
|
||
|
||
import { Badge } from "@/components/ui/Badge";
|
||
import { Card } from "@/components/ui/Card";
|
||
import type { BadgeVariant } from "@/lib/ui/variants";
|
||
import type { ChainPhase, ChainResultView } from "@/lib/chain/chain";
|
||
|
||
interface ChainProgressProps {
|
||
phase: ChainPhase;
|
||
progress: number;
|
||
result: ChainResultView;
|
||
}
|
||
|
||
const PHASE_LABEL: Record<ChainPhase, string> = {
|
||
running: "运行中",
|
||
awaiting: "等待裁决",
|
||
completed: "已完成",
|
||
failed: "已失败",
|
||
};
|
||
|
||
// 相位 → 语义色:失败用危险色而非朱砂品牌色,运行/等待/完成各取信息/警示/成功。
|
||
const PHASE_VARIANT: Record<ChainPhase, BadgeVariant> = {
|
||
running: "info",
|
||
awaiting: "warning",
|
||
completed: "success",
|
||
failed: "danger",
|
||
};
|
||
|
||
// 链进度视图:相位徽标 + 进度条 + 已写章号清单(token/正文绝不展示,result 只含元数据)。
|
||
export function ChainProgress({ phase, progress, result }: ChainProgressProps) {
|
||
return (
|
||
<Card
|
||
as="section"
|
||
className="flex flex-col gap-3 p-5"
|
||
aria-label="链进度"
|
||
>
|
||
<div className="flex items-center justify-between gap-3">
|
||
<h2 className="font-serif text-lg text-ink">链进度</h2>
|
||
<Badge variant={PHASE_VARIANT[phase]} aria-live="polite">
|
||
{PHASE_LABEL[phase]}
|
||
</Badge>
|
||
</div>
|
||
|
||
<div
|
||
className="h-2 w-full overflow-hidden rounded bg-bg"
|
||
role="progressbar"
|
||
aria-label="链写章进度"
|
||
aria-valuenow={progress}
|
||
aria-valuemin={0}
|
||
aria-valuemax={100}
|
||
aria-valuetext={`已完成 ${result.written.length} 章`}
|
||
>
|
||
<div
|
||
className="h-full bg-cinnabar motion-safe:transition-all"
|
||
style={{ width: `${progress}%` }}
|
||
/>
|
||
</div>
|
||
|
||
<p className="text-sm text-ink-soft">
|
||
已完成 {result.written.length} 章
|
||
{result.written.length > 0 ? (
|
||
<span className="ml-1 font-mono text-ink">
|
||
({result.written.join("、")})
|
||
</span>
|
||
) : null}
|
||
</p>
|
||
{phase === "awaiting" && result.awaitingChapter !== null ? (
|
||
<p className="text-sm text-conflict">
|
||
第 {result.awaitingChapter} 章存在未决冲突,请在下方逐条裁决后续跑。
|
||
</p>
|
||
) : null}
|
||
</Card>
|
||
);
|
||
}
|