feat: M2 — 写→审(一致性)→裁决→验收(事务);未决冲突禁验收
- 续审 Agent 声明(AgentSpec) + 结构化输出契约(ContinuityReview/Conflict 五类) - LangGraph 并行审子图(可扩四审) + collect 落 chapter_reviews 留痕 + review SSE(section/conflict) - 验收-side Repository:章节 accepted 版本晋升 + digest append-only + 审稿留痕/裁决 - API:review(SSE) + reviews 历史 + accept(单原子事务:晋升 version + 终稿 digest + 裁决留痕) - 冲突 gate:未决裁决拦截(CONFLICT_UNRESOLVED);digest 从终稿提炼(不变量#4) - 前端:审稿报告页 + 冲突就地标注 + 裁决(采纳/忽略/手改) + 未决禁验收 + 「本次将更新」清单 - M2 E2E:真实 DB + 多档位 mock 网关零 token 走通 写→审→裁决→验收→摘要入库 - 多 agent 协同台账(PROGRESS.md) + 共享记忆(memory/contracts·decisions·gotchas)
This commit is contained in:
54
apps/web/components/review/AnnotatedText.tsx
Normal file
54
apps/web/components/review/AnnotatedText.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
"use client";
|
||||
|
||||
import type { ReviewConflict } from "@/lib/review/sse";
|
||||
|
||||
interface AnnotatedTextProps {
|
||||
text: string;
|
||||
conflicts: ReviewConflict[];
|
||||
// 当前聚焦的冲突下标(来自报告卡「跳转」),用于锚点联动。
|
||||
focusedIndex: number | null;
|
||||
onAnchorClick: (index: number) => void;
|
||||
}
|
||||
|
||||
// 正文就地标注(UX §8.3 / §6.1)。
|
||||
// M2 占位(R6):`where` 是文字定位(如「第4段」),M2 不做精确字符 range —
|
||||
// 改为段级/锚点联动:每个冲突渲染为一枚朱砂波浪线锚点挂在正文上方,点击=回跳报告卡。
|
||||
// 精确 inline range 标注留 M3+(需后端给字符 offset)。
|
||||
export function AnnotatedText({
|
||||
text,
|
||||
conflicts,
|
||||
focusedIndex,
|
||||
onAnchorClick,
|
||||
}: AnnotatedTextProps) {
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
{conflicts.length > 0 ? (
|
||||
<div className="mb-3 flex flex-wrap gap-2 border-b border-line pb-3">
|
||||
{conflicts.map((c, i) => (
|
||||
<button
|
||||
key={i}
|
||||
type="button"
|
||||
id={`anchor-${i}`}
|
||||
onClick={() => onAnchorClick(i)}
|
||||
aria-current={focusedIndex === i ? "true" : undefined}
|
||||
className={`conflict-anchor rounded px-2 py-0.5 text-xs ${
|
||||
focusedIndex === i
|
||||
? "bg-cinnabar text-panel"
|
||||
: "text-conflict hover:bg-[var(--color-conflict)]/10"
|
||||
}`}
|
||||
title={`${c.type}:${c.where || "正文"}`}
|
||||
>
|
||||
<span aria-hidden="true">⌇</span> {c.type}
|
||||
{c.where ? ` · ${c.where}` : ""}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
<article className="flex-1 overflow-auto whitespace-pre-wrap font-serif text-[17px] leading-[1.9] text-ink">
|
||||
{text || (
|
||||
<span className="text-ink-soft/60">(无待审正文,先去写作页起草本章)</span>
|
||||
)}
|
||||
</article>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user