Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
80 lines
5.7 KiB
TypeScript
80 lines
5.7 KiB
TypeScript
"use client";
|
||
|
||
import { SIGN_LABELS, TIER_LABELS, type SegmentSummary } from "@/lib/rectification-agentic/core/segment-summary";
|
||
import type { RangeDeliveryProjection } from "@/lib/rectification-agentic/v9/divergence-panel";
|
||
import { RECTIFICATION_USER_COPY, REPRESENTATIVE_MINUTE_DISCLAIMER } from "@/lib/rectification-agentic/user-copy";
|
||
import { SWITCH_TO_RECTIFIED_LABEL } from "@/lib/rectification-agentic/birth-time-provenance";
|
||
import { RectificationVerificationReport } from "@/components/rectification-verification-report";
|
||
import { protectVargaReport } from "@/lib/rectification-agentic/v9/delivery-window";
|
||
import { unknownProductDeliveryCopy } from "@/lib/rectification-agentic/v9/product-delivery";
|
||
|
||
export function RectificationSegmentDelivery({ summary, delivery, rangeLabel, selection, resultId, busy, accepting, onAccept, adoptLocked, markdown, candidateDate }: Readonly<{
|
||
summary: SegmentSummary | null;
|
||
delivery: RangeDeliveryProjection;
|
||
rangeLabel: string | null;
|
||
selection?: Readonly<{ resultId: string; candidateId: string; date: string; time: string; contract: "segment-v1" }> | null;
|
||
resultId: string;
|
||
busy: boolean;
|
||
accepting: boolean;
|
||
onAccept: (candidateId: string) => void;
|
||
adoptLocked?: boolean;
|
||
markdown?: string | null;
|
||
candidateDate?: string;
|
||
}>) {
|
||
const adoption = summary?.adoption_minute;
|
||
const candidateId = delivery.representative_candidate_id;
|
||
const exactAdoption = Boolean(adoption?.date && selection?.contract === "segment-v1" && selection.resultId === resultId
|
||
&& selection.candidateId === candidateId && selection.date === adoption.date && selection.time === adoption.time);
|
||
// BUG-1173: a post-adopt answer can move the server's adoption minute. Only when the adopted
|
||
// minute left the verdict (server `readopt_minute`) does the button come back, as 「改用 HH:MM」.
|
||
const readopt = delivery.readopt_minute ?? null;
|
||
const priorAdoption = selection?.contract === "segment-v1" && selection.resultId === resultId ? selection : null;
|
||
const adopted = exactAdoption || Boolean(priorAdoption && !readopt);
|
||
const charts = summary?.charts.filter((chart) => chart.tier !== "blocked") ?? [];
|
||
const blocked = summary?.charts.some((chart) => chart.tier === "blocked") === true;
|
||
const reportBlocked = !summary || blocked;
|
||
return (
|
||
<section className="rectification-candidates rectification-range-delivery" aria-label="生时校正盘型">
|
||
<div className="rectification-candidates-heading"><strong>用哪张盘解读</strong></div>
|
||
<ul className="rectification-range-delivery__shared">
|
||
{charts.map((chart) => (
|
||
<li key={chart.chart}>
|
||
{chart.chart} 上升:{chart.sign === null ? "分不开" : SIGN_LABELS[chart.sign]}
|
||
({TIER_LABELS[chart.tier]}{chart.tied ? ",头段并列" : ""})
|
||
{chart.tier !== "certain" && chart.alternatives.length > 0
|
||
? `,备选:${chart.alternatives.map((sign) => SIGN_LABELS[sign]).join("、")}` : ""}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
{blocked ? <p className="rectification-range-delivery__narrow">分盘解读需要更准的出生时间</p> : null}
|
||
{rangeLabel ? <p className="rectification-range-delivery__muted">分钟范围 {rangeLabel}</p> : null}
|
||
{!summary && delivery.product_delivery ? <p className="rectification-range-delivery__indistinct">{unknownProductDeliveryCopy(delivery.product_delivery)}</p> : null}
|
||
{summary && !summary.scan_complete ? <p className="rectification-range-delivery__muted">完整窗口扫描暂不可用;候选盘型不能证明全窗一致。{candidateDate ? `候选代表日期 ${candidateDate};原填报日期保留。` : ""}</p> : null}
|
||
{adoptLocked ? <p className="rectification-range-delivery__narrow">{RECTIFICATION_USER_COPY.rangeDeliveryAdoptLocked}</p> : null}
|
||
{delivery.provenance_line ? <p className="rectification-range-delivery__provenance">{delivery.provenance_line}</p> : null}
|
||
{adoption && candidateId ? (
|
||
<>
|
||
<p className="rectification-range-delivery__muted">采用后按 {adoption.date ? `${adoption.date} ` : ""}{adoption.time} 排盘;原填报资料保留。</p>
|
||
<button type="button" className="rectification-range-delivery__accept" disabled={busy || adoptLocked || adopted}
|
||
aria-pressed={adopted} onClick={() => onAccept(candidateId)}>
|
||
{accepting ? RECTIFICATION_USER_COPY.rangeDeliveryAdopting : adopted ? RECTIFICATION_USER_COPY.rangeDeliveryAdopted
|
||
: readopt && priorAdoption ? `改用 ${readopt}`
|
||
: delivery.record_conflict ? SWITCH_TO_RECTIFIED_LABEL : `改用 ${charts.map((chart) => chart.chart).join(" + ")} 盘解读`}
|
||
</button>
|
||
{readopt && priorAdoption && !adopted ? (
|
||
<p className="rectification-range-delivery__switch-note">现在按 {priorAdoption.time} 排盘;改用后按 {readopt} 排盘,原填报资料保留。</p>
|
||
) : null}
|
||
{delivery.record_conflict && !adopted ? (
|
||
<p className="rectification-range-delivery__switch-note">
|
||
选它之后,排盘会从出生记录时间 {delivery.record_conflict.reported_time} 换成 {adoption.date ? `${adoption.date} ` : ""}{adoption.time}。
|
||
</p>
|
||
) : null}
|
||
</>
|
||
) : null}
|
||
<p className="rectification-range-delivery__boundary">{delivery.boundary || REPRESENTATIVE_MINUTE_DISCLAIMER}</p>
|
||
<RectificationVerificationReport markdown={protectVargaReport(markdown === undefined ? delivery.verification_markdown : markdown, reportBlocked, delivery.product_delivery?.targets ?? summary?.targets,
|
||
!summary ? "完整窗口扫描暂不可用;不能提供分盘解读推荐。" : undefined)} />
|
||
</section>
|
||
);
|
||
}
|