- 冲突「采纳改法」:有补丁瞬时改入终稿并选中;无补丁但可定位则采纳时调 AI(refiner)重写该段套入;定位不到提示手改 - 正文改为行内高亮叠层编辑器(与页面同底色、随内容增高、无滚动条),点冲突卡/锚点整页滚到并选中+闪烁 - 仅对可在正文定位的冲突显示「跳转」/锚点;locate 支持从 where 引号抽原文,杜绝定位失败刷屏 - 伏笔建议卡:新埋一键登记(预填表单)/ 疑似回收一键标记 CLOSED(复用现有端点) - 审稿页草稿自动保存(防抖 PUT /draft),与「验收本章」解耦,刷新不丢 - 写作路由带章号 ?chapter=N + 验收成功面板/大纲页「写下一章」入口;写作目录从大纲列出全部章节 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
135 lines
4.5 KiB
TypeScript
135 lines
4.5 KiB
TypeScript
"use client";
|
||
|
||
import Link from "next/link";
|
||
|
||
import type { AcceptResponse } from "@/lib/api/types";
|
||
import { buildAcceptPreview } from "@/lib/review/accept-preview";
|
||
import { ThinkingIndicator } from "@/components/ThinkingIndicator";
|
||
|
||
interface AcceptPanelProps {
|
||
projectId: string;
|
||
chapterNo: number;
|
||
conflictCount: number;
|
||
unresolvedCount: number;
|
||
// R3:当前伏笔建议数(验收前清单提醒,只读不自动落库)。
|
||
foreshadowCount: number;
|
||
accepting: boolean;
|
||
result: AcceptResponse | null;
|
||
onAccept: () => void;
|
||
}
|
||
|
||
// 验收 gate(UX §9 / §8.4):未决禁验收(置灰 + 文案),验收后呈现「本次将更新」清单。
|
||
export function AcceptPanel({
|
||
projectId,
|
||
chapterNo,
|
||
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 className="mt-3 flex flex-wrap items-center gap-2">
|
||
<Link
|
||
href={`/projects/${projectId}/write?chapter=${chapterNo + 1}`}
|
||
className="rounded bg-cinnabar px-4 py-2 text-sm text-panel hover:opacity-90"
|
||
>
|
||
→ 写第 {chapterNo + 1} 章
|
||
</Link>
|
||
<Link
|
||
href={`/projects/${projectId}/outline`}
|
||
className="rounded border border-line px-4 py-2 text-sm text-ink hover:border-cinnabar hover:text-cinnabar"
|
||
>
|
||
返回大纲
|
||
</Link>
|
||
</div>
|
||
</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>
|
||
);
|
||
}
|