"use client"; import type { ReviewConflict } from "@/lib/review/sse"; import type { DecisionDraft, Verdict } from "@/lib/review/decisions"; interface ConflictCardProps { index: number; conflict: ReviewConflict; draft: DecisionDraft; missing: boolean; // R1:命中段内联预览(无段号/越界时为 null,回退到「跳转」按钮)。 snippet: string | null; // 该冲突能否在正文里定位(决定是否显示「跳转」——定位不到就别给会失败的入口)。 locatable: boolean; // 正在 AI 改写(采纳无补丁冲突时):禁用按钮 + 显示进度,避免重复点。 rewriting: boolean; onVerdict: (index: number, verdict: Verdict) => void; onNote: (index: number, note: string) => void; onJump: (index: number) => void; } // R2:采纳改法=朱砂主按钮(primary),忽略/手改=次级(secondary),不再三者同权。 const VERDICT_OPTIONS: { value: Verdict; label: string; primary: boolean }[] = [ { value: "accept", label: "采纳改法", primary: true }, { value: "ignore", label: "忽略", primary: false }, { value: "manual", label: "手改", primary: false }, ]; // 裁决按钮样式:激活=朱砂填充;未激活的主按钮=朱砂描边强调,次级=低对比描边。 function verdictClass(active: boolean, primary: boolean): string { if (active) return "bg-cinnabar text-panel"; if (primary) return "border border-cinnabar text-cinnabar hover:bg-cinnabar/10"; return "border border-line text-ink-soft hover:border-cinnabar hover:text-ink"; } // 单个冲突报告卡(UX §6.4):五类徽标 + where + refs + suggestion + 裁决三态。 // 冲突=赭红;未决/缺判时加图标+文案(不单靠色,a11y §10)。 export function ConflictCard({ index, conflict, draft, missing, snippet, locatable, rewriting, onVerdict, onNote, onJump, }: ConflictCardProps) { const resolved = draft.verdict !== null; return (
  • {conflict.suggestion}

    {conflict.original && conflict.replacement ? (
    改法: {conflict.original} {conflict.replacement} (点「采纳改法」改入终稿)
    ) : null} {snippet ? (
    {snippet}
    ) : null}
    {conflict.where && locatable ? ( ) : null} {conflict.refs.map((ref) => ( ▸ {ref} ))}
    冲突 {index + 1} 裁决
    {VERDICT_OPTIONS.map((opt) => { const active = draft.verdict === opt.value; return ( ); })} {rewriting ? ( ✦ AI 改写中… ) : resolved ? ( ) : ( 未裁决 )}
    {draft.verdict === "manual" ? (
    onNote(index, e.target.value)} placeholder="手改说明(可选)" className="w-full rounded border border-line bg-bg px-3 py-1.5 text-sm text-ink focus:border-cinnabar focus:outline-none" />
    ) : null}
  • ); }