feat: add rectification event decision contract v2

This commit is contained in:
Jesse_Chen
2026-08-15 00:56:06 +08:00
parent 21fce9513c
commit 83fef19779
24 changed files with 3637 additions and 562 deletions
@@ -162,7 +162,7 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
const [savedTime, setSavedTime] = useState<string | null>(null);
const [savedStatus, setSavedStatus] = useState<"accepted" | "confirmed" | null>(null);
const [candidateResult, setCandidateResult] = useState<CandidateResult>(null);
const [acceptingTime, setAcceptingTime] = useState<string | null>(null);
const [acceptingCandidateId, setAcceptingCandidateId] = useState<string | null>(null);
const [feedback, setFeedback] = useState<Record<string, "up" | "down" | undefined>>({});
const [copiedMessageKey, setCopiedMessageKey] = useState<string | null>(null);
const [regeneratingMessageKey, setRegeneratingMessageKey] = useState<string | null>(null);
@@ -384,10 +384,10 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
void send("opening", "");
}, [readonly, send, shouldStartOpening]);
const acceptCandidate = useCallback(async (time: string) => {
if (!candidateResult || acceptingTime || readonly) return;
const acceptCandidate = useCallback(async (candidateId: string) => {
if (!candidateResult || acceptingCandidateId || readonly) return;
setError("");
setAcceptingTime(time);
setAcceptingCandidateId(candidateId);
try {
const response = await fetch(
`/api/rectification/cases/${encodeURIComponent(caseId)}/candidates/accept`,
@@ -397,27 +397,26 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
body: JSON.stringify({
sessionId,
resultId: candidateResult.resultId,
candidateId: time,
candidateId,
requestId: globalThis.crypto.randomUUID(),
}),
},
);
const payload = await response.json().catch(() => null);
if (!response.ok || payload?.ok !== true) {
if (!response.ok || payload?.ok !== true || payload?.status !== "accepted") {
throw new Error(payload?.error || payload?.message || "暂时无法采用该候选时间");
}
const status = payload.status === "confirmed" ? "confirmed" : "accepted";
setCandidateResult((current) => current ? { ...current, selectedTime: payload.saved_time, selectionKind: status === "confirmed" ? "engine_confirmed" : "user_accepted" } : current);
setCandidateResult((current) => current ? { ...current, selectedTime: payload.saved_time, selectionKind: "user_accepted" } : current);
setSavedTime(payload.saved_time);
setSavedStatus(status);
onSaved?.(payload.saved_time, status);
setSavedStatus("accepted");
onSaved?.(payload.saved_time, "accepted");
onCompleted?.();
} catch (caught) {
setError(caught instanceof Error ? caught.message : "暂时无法采用该候选时间");
} finally {
setAcceptingTime(null);
setAcceptingCandidateId(null);
}
}, [acceptingTime, candidateResult, caseId, onCompleted, onSaved, readonly, sessionId]);
}, [acceptingCandidateId, candidateResult, caseId, onCompleted, onSaved, readonly, sessionId]);
async function copyMessage(message: RenderMessage) {
try {
@@ -562,7 +561,7 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
</div>
);
})}
{candidateResult?.selectionAllowed && candidateResult.candidates.length > 0 && (
{candidateResult?.selectionAllowed && (
<section className="rectification-candidates" aria-label="生时校正候选时间">
<div className="rectification-candidates-heading">
<strong>{candidateResult.confirmationAllowed ? "确认校正时间" : "当前可能的出生时间"}</strong>
@@ -577,9 +576,9 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
<button
type="button"
className={`rectification-candidate${selected ? " is-selected" : ""}`}
key={`${candidateResult.resultId}-${candidate.time}`}
disabled={selected || Boolean(acceptingTime) || readonly}
onClick={() => void acceptCandidate(candidate.time)}
key={candidate.candidateId}
disabled={selected || Boolean(acceptingCandidateId) || readonly}
onClick={() => void acceptCandidate(candidate.candidateId)}
>
<span className="rectification-candidate-time">
<strong>{candidate.time}</strong>
@@ -588,7 +587,7 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
</span>
<span className="rectification-candidate-support"> {candidate.relativeSupport}</span>
<span className="rectification-candidate-action">
{selected ? "已采用" : acceptingTime === candidate.time ? "正在采用…" : candidateResult.selectedTime ? "改选为此时间" : "采用此时间"}
{selected ? "已采用" : acceptingCandidateId === candidate.candidateId ? "正在采用…" : candidateResult.selectedTime ? "改选为此时间" : "采用此时间"}
</span>
</button>
);