"use client"; import { useCallback, useMemo, useState } from "react"; import type { Priority1DemoInput } from "@/workers/rpa/priority1/demo-input"; import type { QuoteDetail, QuotePageStatus } from "@/lib/frontend/types"; import { SUBMIT_LOCK_MS } from "@/lib/frontend/constants"; import { resolvePriority1UserMessage } from "@/lib/priority1/api-errors"; import { hostCreatePriority1Quote, hostGetQuote } from "@/lib/frontend/api-client"; import { pollQuoteUntilDone } from "@/hooks/use-quote-polling"; import { formatQuoteErrorMessage } from "@/modules/quote/quote-error-messages"; import { isPriority1ManualFollowupDetail } from "@/modules/priority1/quote-outcome"; import { uuidV4 } from "@/lib/frontend/format"; import { Priority1Simulator } from "@/components/priority1/priority1-simulator"; import { Priority1QuoteResultPanel } from "@/components/priority1/priority1-quote-result-panel"; import type { Priority1ShipmentSummary } from "@/components/priority1/priority1-ftl-schedule-calendar"; export interface Priority1QuoteWidgetProps { serviceToken?: string; customerId: string; apiBaseUrl?: string; } function toShipmentSummary(input: Priority1DemoInput): Priority1ShipmentSummary { const weight = Number(input.weightLb); return { originZip: input.originZip, destinationZip: input.destinationZip, pickupDate: input.pickupDate, weightLb: Number.isFinite(weight) && weight > 0 ? weight : undefined, itemsLabel: input.shipmentType === "ltl" ? input.packaging : input.commodity, }; } function shipmentFromQuote( quote: QuoteDetail, fallback?: Priority1ShipmentSummary, ): Priority1ShipmentSummary | undefined { const meta = quote.priority1?.shipment_meta; if (!meta?.origin_zip || !meta.destination_zip) { return fallback; } return { originZip: meta.origin_zip, destinationZip: meta.destination_zip, pickupDate: meta.pickup_date ?? fallback?.pickupDate ?? "", weightLb: meta.weight_lb ?? fallback?.weightLb, itemsLabel: meta.commodity ?? fallback?.itemsLabel, }; } /** Priority1 模拟填表 + RPA 真实询价 */ export function Priority1QuoteWidget({ serviceToken, customerId, apiBaseUrl = "", }: Priority1QuoteWidgetProps) { const [status, setStatus] = useState("idle"); const [quote, setQuote] = useState(null); const [error, setError] = useState(null); const [submitLocked, setSubmitLocked] = useState(false); const [lastInput, setLastInput] = useState(null); const reset = useCallback(() => { setStatus("idle"); setQuote(null); setError(null); }, []); const finishQuote = useCallback((detail: QuoteDetail) => { setQuote(detail); if (detail.status === "failed") { setStatus("error"); setError( resolvePriority1UserMessage( detail.error_code, detail.error_message ?? formatQuoteErrorMessage(detail.error_code), ), ); return; } if (detail.status === "expired") { setStatus("expired"); return; } if (isPriority1ManualFollowupDetail(detail)) { setStatus("manual_followup"); setError(null); return; } setStatus(detail.is_realtime === false ? "fallback" : "success"); setError(null); }, []); const handleSubmit = useCallback( async (input: Priority1DemoInput) => { if (submitLocked) return; setSubmitLocked(true); setTimeout(() => setSubmitLocked(false), SUBMIT_LOCK_MS); setLastInput(input); setStatus("validating"); setError(null); const created = await hostCreatePriority1Quote( apiBaseUrl, serviceToken, { request_id: uuidV4(), customer_id: customerId, priority1_input: input, }, ); if (created.code !== 0) { setStatus("error"); setError(resolvePriority1UserMessage(created.code, created.message)); return; } const { quote_id } = created.data; setStatus("processing"); const pollResult = await pollQuoteUntilDone( async () => { try { const res = await hostGetQuote( apiBaseUrl, serviceToken, customerId, quote_id, ); if (res.code !== 0) { return { ok: false, errorMessage: res.message }; } return { ok: true, data: res.data }; } catch { return { ok: false }; } }, { fastAfterMs: 5_000, fastIntervalMs: 600, }, ); if (pollResult.type === "done") { finishQuote(pollResult.quote); return; } setStatus("error"); setError( pollResult.type === "timeout" ? "Priority1 询价超时,请稍后重试" : resolvePriority1UserMessage("INTERNAL_ERROR", pollResult.message), ); }, [ apiBaseUrl, serviceToken, customerId, submitLocked, finishQuote, ], ); const formDisabled = status === "validating" || status === "processing" || submitLocked; const shipmentContext = useMemo(() => { if (quote) { return shipmentFromQuote( quote, lastInput ? toShipmentSummary(lastInput) : undefined, ); } return lastInput ? toShipmentSummary(lastInput) : undefined; }, [quote, lastInput]); const showWideResult = quote?.priority1?.display_mode === "ftl_calendar" && quote.priority1.lines.length > 0; return (

按 Priority1 流程填写;第 1 步底部点击「获取即时报价」进入第 2 步,再次点击将提交真实询价。

void handleSubmit(input)} />
{!showWideResult ? (
) : null}
{showWideResult ? ( ) : null}
); }