feat: add rectification event decision contract v2
This commit is contained in:
@@ -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>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user