链页 app/projects/[id]/chains(RSC fetchProject)+ ChainPage/ChainStarter/
ChainProgress/ChainAdjudication;lib/chain 纯函数(result 收窄/相位映射/resume 组装)。
复用 useJobPoll 轮询、ConflictCard + decisions.ts 裁决、normalizeConflicts/latestReview、
friendlyError;nav 加 chains 入口。awaiting(interrupt)→ 读该章冲突渲 ConflictCard →
POST .../chains/runs/{job_id}/resume 续跑。gen:api 纳入 chains run/resume。
守 #5(链暂停=等裁决,token/正文不入 job result)。
64 lines
1.8 KiB
TypeScript
64 lines
1.8 KiB
TypeScript
"use client";
|
||
|
||
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: "已失败",
|
||
};
|
||
|
||
// 链进度视图:相位徽标 + 进度条 + 已写章号清单(token/正文绝不展示,result 只含元数据)。
|
||
export function ChainProgress({ phase, progress, result }: ChainProgressProps) {
|
||
return (
|
||
<section
|
||
className="flex flex-col gap-3 rounded border border-line bg-panel p-5"
|
||
aria-label="链进度"
|
||
>
|
||
<div className="flex items-center justify-between gap-3">
|
||
<h2 className="font-serif text-lg text-ink">链进度</h2>
|
||
<span
|
||
className="rounded bg-cinnabar/10 px-2 py-0.5 text-xs text-cinnabar"
|
||
aria-live="polite"
|
||
>
|
||
{PHASE_LABEL[phase]}
|
||
</span>
|
||
</div>
|
||
|
||
<div
|
||
className="h-2 w-full overflow-hidden rounded bg-bg"
|
||
role="progressbar"
|
||
aria-valuenow={progress}
|
||
aria-valuemin={0}
|
||
aria-valuemax={100}
|
||
>
|
||
<div
|
||
className="h-full bg-cinnabar 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}
|
||
</section>
|
||
);
|
||
}
|