- Q6 bug: useAutosave 加 initialSavedText,进页种入已存草稿时初始即「已保存」,修「加载已存草稿却显示尚未保存」的误导。 - A: 新 ThinkingIndicator(三点波动,motion-safe 尊重 reduced-motion)接入审稿进行中/验收中/回炉中三处静态文案,长等待看得见在工作。
114 lines
3.7 KiB
TypeScript
114 lines
3.7 KiB
TypeScript
"use client";
|
||
|
||
import type { AcceptResponse } from "@/lib/api/types";
|
||
import { buildAcceptPreview } from "@/lib/review/accept-preview";
|
||
import { ThinkingIndicator } from "@/components/ThinkingIndicator";
|
||
|
||
interface AcceptPanelProps {
|
||
conflictCount: number;
|
||
unresolvedCount: number;
|
||
// R3:当前伏笔建议数(验收前清单提醒,只读不自动落库)。
|
||
foreshadowCount: number;
|
||
accepting: boolean;
|
||
result: AcceptResponse | null;
|
||
onAccept: () => void;
|
||
}
|
||
|
||
// 验收 gate(UX §9 / §8.4):未决禁验收(置灰 + 文案),验收后呈现「本次将更新」清单。
|
||
export function AcceptPanel({
|
||
conflictCount,
|
||
unresolvedCount,
|
||
foreshadowCount,
|
||
accepting,
|
||
result,
|
||
onAccept,
|
||
}: AcceptPanelProps) {
|
||
const blocked = unresolvedCount > 0;
|
||
const preview = buildAcceptPreview({
|
||
conflictCount,
|
||
foreshadowSuggestions: foreshadowCount,
|
||
});
|
||
|
||
if (result) {
|
||
return (
|
||
<div className="rounded border border-pass/50 bg-panel p-4">
|
||
<h3 className="mb-2 text-sm font-semibold text-pass">本章已验收</h3>
|
||
<ul className="space-y-1 text-xs text-ink-soft">
|
||
<li>
|
||
晋升版次:
|
||
<span className="font-mono text-ink">v{result.accepted_version}</span>
|
||
</li>
|
||
<li>
|
||
章节摘要:{result.digest_added ? "已新增一行" : "未变更"}
|
||
</li>
|
||
<li>
|
||
裁决写回:
|
||
<span className="font-mono text-ink">
|
||
{result.decisions_recorded}
|
||
</span>{" "}
|
||
条
|
||
</li>
|
||
{result.review_id ? (
|
||
<li className="truncate">
|
||
留痕:<span className="font-mono">{result.review_id}</span>
|
||
</li>
|
||
) : null}
|
||
</ul>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="rounded border border-line bg-panel p-4">
|
||
{blocked ? (
|
||
<p className="mb-2 text-xs text-conflict" role="status">
|
||
尚有 {unresolvedCount} 项冲突未裁决,处理完才能验收。
|
||
</p>
|
||
) : (
|
||
<>
|
||
<p className="mb-2 text-xs text-ink-soft">
|
||
{conflictCount === 0
|
||
? "无冲突,可直接验收。"
|
||
: "全部冲突已裁决,可验收本章。"}
|
||
</p>
|
||
{/* R3:验收前「本次将更新」清单(预期,落库口径以验收回执为准)。 */}
|
||
<div className="mb-3 rounded border border-line/70 bg-bg/50 p-3">
|
||
<h4 className="mb-1.5 text-xs font-semibold text-ink">
|
||
本次验收将更新
|
||
</h4>
|
||
<ul className="space-y-1.5">
|
||
{preview.map((item) => (
|
||
<li key={item.label} className="flex gap-2 text-xs text-ink-soft">
|
||
<span className="text-cinnabar" aria-hidden="true">
|
||
◆
|
||
</span>
|
||
<span>
|
||
<span className="text-ink">{item.label}</span>
|
||
<span className="text-ink-soft">:{item.detail}</span>
|
||
</span>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
<p className="mt-2 text-[11px] text-ink-soft/70">
|
||
以上为预期,最终以验收回执为准。
|
||
</p>
|
||
</div>
|
||
</>
|
||
)}
|
||
<button
|
||
type="button"
|
||
onClick={onAccept}
|
||
disabled={blocked || accepting}
|
||
aria-disabled={blocked || accepting}
|
||
className="w-full rounded bg-cinnabar px-4 py-2 text-sm text-panel hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-40"
|
||
>
|
||
{accepting ? (
|
||
<ThinkingIndicator label="验收中" className="justify-center" />
|
||
) : (
|
||
"全部处理完 → 验收本章"
|
||
)}
|
||
</button>
|
||
</div>
|
||
);
|
||
}
|