"use client"; import { useCallback, useEffect, useRef, useState } from "react"; import type { AddressInput, MothershipAddressCandidate, QuoteDetail, QuotePageStatus, QuoteRequestBody, } from "@/lib/frontend/types"; import { SUBMIT_LOCK_MS } from "@/lib/frontend/constants"; import { hostCreateQuote, hostContinueMsRefineHold, hostDeclineMsRefineHold, hostFetchMothershipCandidates, hostGetQuote, hostPreheatQuoteSession, hostReleaseQuoteSession, hostSubmitMsRefineDetails, hostSubmitMsCheckout, } from "@/lib/frontend/api-client"; import { applyMothershipCandidate } from "@/lib/frontend/mothership-address"; import { pollQuoteUntilDone } from "@/hooks/use-quote-polling"; import { formatQuoteErrorMessage } from "@/modules/quote/quote-error-messages"; import { QuoteForm } from "@/components/quote/quote-form"; import { QuoteResultPanel } from "@/components/quote/quote-result-panel"; import { AddressDisambiguationModal } from "@/components/quote/address-disambiguation-modal"; import { PrimaryButton, SecondaryButton } from "@/components/ui/primary-button"; import { ErrorBanner } from "@/components/ui/error-banner"; import { quoteCtaCls } from "@/components/quote/quote-form-chrome"; import { QuoteProviderSwitch, type QuoteProviderId, } from "@/components/embed/quote-provider-switch"; import { Priority1QuoteWidget } from "@/components/priority1/priority1-quote-widget"; import { FlockQuoteWidget } from "@/components/flock/flock-quote-widget"; import { MothershipLoggedInShipmentForm, type MothershipLoggedInShipmentPayload, } from "@/components/mothership/mothership-logged-in-shipment-form"; import { MothershipLoggedInDetailsForm, detailsStateToPayload, type MothershipLoggedInDetailsState, } from "@/components/mothership/mothership-logged-in-details-form"; import { MothershipLoggedInQuoteSidebar } from "@/components/mothership/mothership-logged-in-quote-sidebar"; import type { MsSidebarCheckoutIntent } from "@/components/mothership/mothership-logged-in-quote-sidebar"; import { MsRefineHoldPrompt } from "@/components/mothership/ms-refine-hold-prompt"; import { buildQuoteRequestBodyFromLoggedIn } from "@/lib/frontend/mothership-logged-in-quote-body"; import { MS_NEEDS_DETAILS_ERROR_CODE } from "@/lib/constants/ms-refine-hold"; import { useHostBridgeOptional } from "@/lib/embed/host-bridge-react"; import { postToHost, type ChajiaModuleId, } from "@/lib/embed/host-bridge"; import { mapQuotesWithSelectedFlag } from "@/lib/embed/map-quotes-selection"; /** 更新报价后滚到右侧「选择承运商」区域,避免用户停在页面底部按钮处 */ function scrollToMsQuotePanel(reason: string) { try { window.scrollTo({ top: 0, left: 0, behavior: "smooth" }); document.documentElement.scrollTop = 0; document.body.scrollTop = 0; } catch { /* ignore */ } const el = document.getElementById("ms-choose-carrier"); el?.scrollIntoView({ behavior: "smooth", block: "start" }); try { window.dispatchEvent(new Event("chajia-host-scroll-quotes")); } catch { /* ignore */ } postToHost("chajia:scroll-top", { payload: { reason }, }); } export interface EmbeddedQuoteWidgetProps { customerId: string; apiBaseUrl?: string; /** 未传时使用 Cookie 演示会话鉴权(/embed-demo) */ serviceToken?: string; /** 客户已绑定 MotherShip 账密 → 显示登录后一级查价界面 */ mothershipLoggedInUi?: boolean; /** 客户已绑定 Flock 账密 → 显示登录后 Quick 查价界面 */ flockLoggedInUi?: boolean; /** 门户驱动:强制单一数据源(配合 hideProviderSwitch) */ forcedProvider?: QuoteProviderId; /** 门户驱动:隐藏内置数据源切换(4 路线门户已在外层选路) */ hideProviderSwitch?: boolean; } const FORM_ID = "embedded-quote-form"; export function EmbeddedQuoteWidget({ serviceToken, customerId, apiBaseUrl = "", mothershipLoggedInUi = false, flockLoggedInUi = false, forcedProvider, hideProviderSwitch = false, }: EmbeddedQuoteWidgetProps) { const hostBridge = useHostBridgeOptional(); const [provider, setProvider] = useState( forcedProvider ?? "mothership", ); const resolveModule = useCallback((): ChajiaModuleId => { if (provider === "flock") { return flockLoggedInUi ? "FLOCK_LOGGED_IN" : "FLOCK_GUEST"; } return mothershipLoggedInUi ? "MS_LOGGED_IN" : "MS_GUEST"; }, [provider, flockLoggedInUi, mothershipLoggedInUi]); const [status, setStatus] = useState("idle"); const [quote, setQuote] = useState(null); const [error, setError] = useState(null); const [submitLocked, setSubmitLocked] = useState(false); const [loggedInDraft, setLoggedInDraft] = useState(null); const [loggedInDetails, setLoggedInDetails] = useState(null); const [loggedInStep, setLoggedInStep] = useState<"create" | "details">( "create", ); const [refineHold, setRefineHold] = useState< NonNullable | null >(null); const [refineAccepted, setRefineAccepted] = useState(false); /** 继续填写后保留会话与总硬限(弹窗关闭后仍需 5 分钟到期 decline) */ const [refineActive, setRefineActive] = useState<{ quoteId: string; quote_session_id: string; total_deadline_ms: number; } | null>(null); const [refineTotalLeftLabel, setRefineTotalLeftLabel] = useState( null, ); const [checkoutBusy, setCheckoutBusy] = useState(false); const [checkoutMessage, setCheckoutMessage] = useState(null); const checkoutAbortRef = useRef(null); const rootRef = useRef(null); const isEmbeddedHost = typeof window !== "undefined" && window.parent !== window; const [disambiguationOpen, setDisambiguationOpen] = useState(false); const [confirmedPickup, setConfirmedPickup] = useState( null, ); const [confirmedDelivery, setConfirmedDelivery] = useState(null); const [pickupCandidates, setPickupCandidates] = useState< MothershipAddressCandidate[] >([]); const [deliveryCandidates, setDeliveryCandidates] = useState< MothershipAddressCandidate[] >([]); const pendingBodyRef = useRef(null); const pendingSessionRef = useRef(undefined); const reset = useCallback(() => { setStatus("idle"); setQuote(null); setError(null); setConfirmedPickup(null); setConfirmedDelivery(null); setLoggedInDraft(null); setLoggedInStep("create"); setRefineHold(null); setRefineAccepted(false); setRefineActive(null); setRefineTotalLeftLabel(null); setCheckoutBusy(false); setCheckoutMessage(null); }, []); const declineRefineHold = useCallback( async ( hold: { quote_session_id: string }, quoteId: string, ) => { setRefineHold(null); setRefineAccepted(false); setRefineActive(null); setRefineTotalLeftLabel(null); await hostDeclineMsRefineHold( apiBaseUrl, serviceToken, customerId, quoteId, hold.quote_session_id, ); }, [apiBaseUrl, serviceToken, customerId], ); const finishQuote = useCallback( (detail: QuoteDetail) => { setQuote(detail); const module = resolveModule(); if (detail.status === "failed") { setStatus("error"); const msg = detail.error_message ?? formatQuoteErrorMessage(detail.error_code); setError(msg); setRefineHold(null); setRefineActive(null); hostBridge?.reportQuoteResult({ quote_id: detail.quote_id, request_id: detail.request_id, status: "failed", module, currency: detail.currency || "USD", quotes: [], error_code: detail.error_code, error_message: msg, }); return; } if (detail.status === "expired") { setStatus("expired"); setRefineHold(null); setRefineActive(null); hostBridge?.reportQuoteResult({ quote_id: detail.quote_id, request_id: detail.request_id, status: "expired", module, currency: detail.currency || "USD", quotes: [], error_code: detail.error_code, error_message: detail.error_message, }); return; } setStatus(detail.is_realtime === false ? "fallback" : "success"); if (detail.error_code === MS_NEEDS_DETAILS_ERROR_CODE) { setError( detail.error_message ?? formatQuoteErrorMessage(detail.error_code), ); } else { setError(null); } if ( mothershipLoggedInUi && detail.refine_hold?.available && !refineAccepted ) { setRefineHold(detail.refine_hold); } else { setRefineHold(null); } if (!detail.refine_hold?.available) { setRefineActive(null); setRefineTotalLeftLabel(null); } hostBridge?.reportQuoteResult({ quote_id: detail.quote_id, request_id: detail.request_id, status: "done", module, currency: detail.currency || "USD", source_type: detail.source_type, is_realtime: detail.is_realtime, quotes: (detail.quotes ?? []).map((q) => ({ carrier: q.carrier, service_level: q.service_level, rate_option: q.rate_option, transit_days: q.transit_days, transit_description: q.transit_description, raw_freight: q.raw_freight, surcharges: q.surcharges, raw_total: q.raw_total, markup_percent: q.markup_percent, markup_amount: q.markup_amount, final_total: q.final_total, base_total_before_markup: q.raw_total, customer_markup_amount: q.markup_amount, customer_final_total: q.final_total, is_customer_markup_applied: q.markup_amount > 0, pricing_mode: "customer_final" as const, breakdown: q.breakdown ?? [], estimated_pickup: loggedInDraft?.readyDate ?? null, guaranteed: /guarant/i.test(q.service_level || ""), })), error_code: null, error_message: null, }); }, [hostBridge, resolveModule, mothershipLoggedInUi, refineAccepted, loggedInDraft], ); useEffect(() => { if (!refineActive || !refineAccepted) { setRefineTotalLeftLabel(null); return; } // 填写补充信息期间不再倒计时逼迫用户,也不再自动放弃(避免提交按钮消失) setRefineTotalLeftLabel(null); }, [refineActive, refineAccepted]); /** 把当前点选报价参数同步给宿主;asSave=true 时走 quote-save,否则 quote-result 仅更新选中 */ const notifyHostQuoteSelection = useCallback( (intent: MsSidebarCheckoutIntent, opts?: { asSave?: boolean }) => { if (!hostBridge || !quote?.quote_id) return; const module = resolveModule(); const selected = intent.quoteItem; const isProtect = intent.coverage === "freight_protect"; const readyDate = loggedInDraft?.readyDate ?? null; const addBusinessDays = (isoDate: string, days: number): string | null => { const start = new Date(`${isoDate}T12:00:00`); if (Number.isNaN(start.getTime())) return null; let left = Math.max(0, days); const d = new Date(start); while (left > 0) { d.setDate(d.getDate() + 1); const wd = d.getDay(); if (wd !== 0 && wd !== 6) left -= 1; } const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, "0"); const day = String(d.getDate()).padStart(2, "0"); return `${y}-${m}-${day}`; }; const parseTransitDays = (item: { transit_days?: number | string | null; transit_description?: string | null; }): number | null => { const raw = `${item.transit_days ?? ""} ${item.transit_description ?? ""}`; const m = raw.match(/(\d+)/); if (!m) return null; const n = Number(m[1]); return Number.isFinite(n) ? n : null; }; const cargo_lines = loggedInDraft?.cargo?.map((c) => ({ cargo_type: c.cargoType, quantity: c.quantity, weight_lb: c.weightLb, length_in: c.lengthIn, width_in: c.widthIn, height_in: c.heightIn, })) ?? undefined; const pickupText = loggedInDraft?.pickupConfirmed?.formatted_address || loggedInDraft?.pickupConfirmed?.display_label || loggedInDraft?.pickupQuery || ""; const deliveryText = loggedInDraft?.deliveryConfirmed?.formatted_address || loggedInDraft?.deliveryConfirmed?.display_label || loggedInDraft?.deliveryQuery || ""; const quotes = mapQuotesWithSelectedFlag( (quote.quotes ?? []).map((q) => { const days = parseTransitDays(q); const estimated_delivery = readyDate && days != null ? addBusinessDays(readyDate, days) : null; return { carrier: q.carrier, service_level: q.service_level, rate_option: q.rate_option, transit_days: q.transit_days, transit_description: q.transit_description, raw_freight: q.raw_freight, surcharges: q.surcharges, raw_total: q.raw_total, markup_percent: q.markup_percent, markup_amount: q.markup_amount, final_total: q.final_total, base_total_before_markup: q.raw_total, customer_markup_amount: q.markup_amount, customer_final_total: q.final_total, is_customer_markup_applied: q.markup_amount > 0, pricing_mode: "customer_final" as const, breakdown: q.breakdown ?? [], guaranteed: isProtect || /guarant/i.test(q.service_level || ""), guarantee_amount: null as number | null, estimated_pickup: readyDate, estimated_delivery, }; }), selected, ).map((q) => ({ ...q, guarantee_amount: q.selected ? intent.cargoValueUsd ?? null : null, })); if (opts?.asSave) { hostBridge.reportQuoteSave({ action: "save", quote_id: quote.quote_id, request_id: quote.request_id, status: "done", module, currency: quote.currency || "USD", source_type: quote.source_type, is_realtime: quote.is_realtime, selected_carrier: intent.carrier, coverage: intent.coverage, cargo_value_usd: intent.cargoValueUsd ?? null, ready_date: readyDate, estimated_pickup: readyDate, pickup_address: pickupText ? { formatted_address: pickupText, street: pickupText } : undefined, delivery_address: deliveryText ? { formatted_address: deliveryText, street: deliveryText } : undefined, cargo_lines, quotes, error_code: null, error_message: null, }); return; } hostBridge.reportQuoteResult({ quote_id: quote.quote_id, request_id: quote.request_id, status: "done", module, currency: quote.currency || "USD", source_type: quote.source_type, is_realtime: quote.is_realtime, quotes, error_code: null, error_message: null, }); }, [hostBridge, quote, resolveModule, loggedInDraft], ); const handleSaveQuoteToHost = useCallback( (intent: MsSidebarCheckoutIntent) => { if (!quote?.quote_id) { setCheckoutMessage("请先完成询价"); return; } if (!hostBridge) { setCheckoutMessage("未检测到宿主桥接,无法保存询价记录"); return; } setCheckoutBusy(true); setCheckoutMessage("正在保存询价记录…"); try { notifyHostQuoteSelection(intent, { asSave: true }); setCheckoutMessage("已提交保存到宿主「卡派询价快照」"); } catch (err) { setCheckoutMessage( err instanceof Error ? err.message : "保存询价记录失败", ); } finally { setCheckoutBusy(false); } }, [quote, hostBridge, notifyHostQuoteSelection], ); const handleSelectQuoteForHost = useCallback( (intent: MsSidebarCheckoutIntent) => { if (!isEmbeddedHost || !hostBridge) return; try { notifyHostQuoteSelection(intent, { asSave: false }); } catch { /* 宿主同步失败不打断选价 */ } }, [isEmbeddedHost, hostBridge, notifyHostQuoteSelection], ); const handleMsCheckout = useCallback( async (intent: MsSidebarCheckoutIntent) => { if (isEmbeddedHost && hostBridge) { handleSaveQuoteToHost(intent); return; } if (!quote?.quote_id) { setCheckoutMessage("请先完成询价"); return; } checkoutAbortRef.current?.abort(); const ac = new AbortController(); checkoutAbortRef.current = ac; setCheckoutBusy(true); setCheckoutMessage("正在同步官网选择承运商与保障…"); try { const detailsPayload = loggedInDetails ? detailsStateToPayload(loggedInDetails) : undefined; const mapped = loggedInDraft ? buildQuoteRequestBodyFromLoggedIn( loggedInDraft, customerId, detailsPayload, ) : null; const res = await hostSubmitMsCheckout( apiBaseUrl, serviceToken, customerId, { quoteId: quote.quote_id, preferredCarrier: intent.carrier, coverage: intent.coverage, cargoValueUsd: intent.cargoValueUsd, mothershipDetails: mapped?.mothership_details, pickupAccessorials: mapped?.pickup_accessorials, deliveryAccessorials: mapped?.delivery_accessorials, }, ); if (ac.signal.aborted) return; if (res.code !== 0) { setCheckoutMessage(res.message); return; } const deadline = Date.now() + 8 * 60_000; while (Date.now() < deadline) { if (ac.signal.aborted) return; await new Promise((resolve, reject) => { const t = setTimeout(resolve, 2_000); ac.signal.addEventListener( "abort", () => { clearTimeout(t); reject(new DOMException("Aborted", "AbortError")); }, { once: true }, ); }).catch(() => undefined); if (ac.signal.aborted) return; const r = await hostGetQuote( apiBaseUrl, serviceToken, customerId, quote.quote_id, ); if (ac.signal.aborted) return; if (r.code !== 0) continue; const st = r.data.ms_checkout; if (!st) continue; if (st.status === "done") { setQuote(r.data); setCheckoutMessage( st.message || `已填齐详情(${st.selected_carrier ?? intent.carrier},未支付)`, ); return; } if (st.status === "failed") { setCheckoutMessage(st.message || "结账同步失败"); return; } setCheckoutMessage(st.message || "正在同步官网…"); } if (!ac.signal.aborted) { setCheckoutMessage("结账同步超时,请稍后在侧栏查看状态或重试"); } } catch (err) { if (ac.signal.aborted) return; setCheckoutMessage( err instanceof Error ? err.message : "结账同步失败", ); } finally { if (checkoutAbortRef.current === ac) { setCheckoutBusy(false); } } }, [ quote, loggedInDraft, loggedInDetails, customerId, apiBaseUrl, serviceToken, isEmbeddedHost, hostBridge, handleSaveQuoteToHost, ], ); useEffect(() => { return () => { checkoutAbortRef.current?.abort(); }; }, []); const submitQuote = useCallback( async (body: QuoteRequestBody) => { setStatus("validating"); setError(null); const created = await hostCreateQuote(apiBaseUrl, serviceToken, body); if (created.code !== 0) { setStatus("error"); setError(created.message); return; } const { quote_id, status: createStatus } = created.data; setStatus("processing"); if (createStatus === "done") { const detail = await hostGetQuote( apiBaseUrl, serviceToken, customerId, quote_id, ); if (detail.code !== 0) { setStatus("error"); setError(detail.message); return; } finishQuote(detail.data); return; } 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 }; } }); if (pollResult.type === "done") { finishQuote(pollResult.quote); return; } setStatus("error"); setError( pollResult.type === "timeout" ? formatQuoteErrorMessage("QUOTE_TIMEOUT") : pollResult.message, ); }, [apiBaseUrl, serviceToken, customerId, finishQuote], ); const handleSubmit = useCallback( async (body: QuoteRequestBody) => { if (submitLocked) return; setSubmitLocked(true); setTimeout(() => setSubmitLocked(false), SUBMIT_LOCK_MS); setStatus("resolving_address"); setError(null); let candidatesRes; try { candidatesRes = await hostFetchMothershipCandidates( apiBaseUrl, serviceToken, customerId, body.pickup_address, body.delivery_address, ); } catch { setStatus("error"); setError("地址联想请求失败,请稍后重试"); return; } if (candidatesRes.code !== 0) { setStatus("error"); setError(candidatesRes.message); return; } const { pickup_candidates, delivery_candidates, quote_session_id, } = candidatesRes.data; pendingSessionRef.current = quote_session_id; pendingBodyRef.current = body; setPickupCandidates(pickup_candidates); setDeliveryCandidates(delivery_candidates); setDisambiguationOpen(true); if (quote_session_id) { void hostPreheatQuoteSession( apiBaseUrl, serviceToken, customerId, quote_session_id, ); } setStatus("idle"); }, [apiBaseUrl, serviceToken, customerId, submitLocked], ); const handleDisambiguationConfirm = useCallback( async ( pickup: MothershipAddressCandidate, delivery: MothershipAddressCandidate, ) => { const base = pendingBodyRef.current; if (!base) { return; } setDisambiguationOpen(false); pendingBodyRef.current = null; const confirmedBody: QuoteRequestBody = { ...base, quote_session_id: pendingSessionRef.current, pickup_address: applyMothershipCandidate(base.pickup_address, pickup), delivery_address: applyMothershipCandidate( base.delivery_address, delivery, ), }; setConfirmedPickup(confirmedBody.pickup_address); setConfirmedDelivery(confirmedBody.delivery_address); pendingSessionRef.current = undefined; await submitQuote(confirmedBody); }, [submitQuote], ); const handleDisambiguationCancel = useCallback(() => { const sessionId = pendingSessionRef.current; setDisambiguationOpen(false); pendingBodyRef.current = null; pendingSessionRef.current = undefined; setStatus("idle"); if (sessionId) { void hostReleaseQuoteSession( apiBaseUrl, serviceToken, customerId, sessionId, ); } }, [apiBaseUrl, serviceToken, customerId]); const formDisabled = status === "resolving_address" || status === "validating" || status === "processing" || submitLocked || disambiguationOpen; const switchDisabled = status === "validating" || status === "processing" || status === "resolving_address"; // 点击「继续」进入二级提货/送货详情后:页面置顶(避免停在底部「继续」按钮处) useEffect(() => { if (loggedInStep !== "details") return; const t = window.setTimeout(() => { try { window.scrollTo({ top: 0, left: 0, behavior: "smooth" }); document.documentElement.scrollTop = 0; document.body.scrollTop = 0; } catch { /* ignore */ } rootRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }); // 通知宿主:把私卡询价弹窗/iframe 区域滚到视口顶部 postToHost("chajia:scroll-top", { module: resolveModule(), payload: { reason: "logged-in-details" }, }); }, 60); return () => window.clearTimeout(t); }, [loggedInStep, resolveModule]); return (

卡派查价

选择数据源填写货物信息,获取实时报价

{!hideProviderSwitch && ( { setProvider(next); reset(); }} disabled={switchDisabled} /> )} {provider === "priority1" ? ( ) : provider === "flock" ? ( ) : ( <> {error && status === "idle" && (
{error}
)} {mothershipLoggedInUi && !(loggedInStep === "details" && loggedInDraft) ? ( /* 一级「创建新货件」:取消右侧「下一步」占位,表单占满整行 */
{ setLoggedInDraft(payload); setLoggedInDetails(null); setLoggedInStep("details"); setQuote(null); setError(null); try { // 一级信息足够询价;二级仅选报价/后续填详情,不阻塞出价 const body = buildQuoteRequestBodyFromLoggedIn( payload, customerId, ); void submitQuote(body); } catch (err) { setStatus("error"); setError( err instanceof Error ? err.message : "无法构建询价请求", ); } }} />
) : (
{mothershipLoggedInUi ? ( <>
setLoggedInStep("create")} > 返回上一步
{ if (!quote?.quote_id || !refineAccepted) { setError("请先选择继续填写,或等待初步报价完成"); return; } const sessionId = refineActive?.quote_session_id || quote.refine_hold?.quote_session_id || refineHold?.quote_session_id; if (!sessionId) { setError("报价会话已失效,请重新询价"); return; } void (async () => { setStatus("processing"); setError(null); scrollToMsQuotePanel("update-quote"); const draftReady = loggedInDetails?.pickup.readyTime || loggedInDraft!.readyTime; const draftWithReady = { ...loggedInDraft!, readyTime: draftReady, readyDate: loggedInDetails?.pickup.readyDate || loggedInDraft!.readyDate, }; setLoggedInDraft(draftWithReady); const mapped = buildQuoteRequestBodyFromLoggedIn( draftWithReady, customerId, details, ); const res = await hostSubmitMsRefineDetails( apiBaseUrl, serviceToken, customerId, quote.quote_id, sessionId, mapped.mothership_details, { pickupAccessorials: mapped.pickup_accessorials, deliveryAccessorials: mapped.delivery_accessorials, }, { readyDate: mapped.ready_date, readyTime: mapped.ready_time, }, mapped.cargo_lines, ); if (res.code !== 0) { setStatus("error"); setError(res.message); scrollToMsQuotePanel("update-quote-error"); return; } const pollResult = await pollQuoteUntilDone( async () => { try { const r = await hostGetQuote( apiBaseUrl, serviceToken, customerId, quote.quote_id, ); if (r.code !== 0) { return { ok: false as const, errorMessage: r.message, }; } return { ok: true as const, data: r.data }; } catch { return { ok: false as const }; } }, ); if (pollResult.type === "done") { setRefineAccepted(false); setRefineActive(null); finishQuote(pollResult.quote); scrollToMsQuotePanel("update-quote-done"); return; } setStatus("error"); setError( pollResult.type === "timeout" ? formatQuoteErrorMessage("QUOTE_TIMEOUT") : pollResult.message, ); scrollToMsQuotePanel("update-quote-error"); })(); }} /> {refineAccepted ? (

补全必要信息后提交,系统将重新获取更准确报价。

) : null} ) : ( <> { setConfirmedPickup(null); setConfirmedDelivery(null); }} onCargoChange={() => { setQuote(null); setError(null); if (status === "success" || status === "fallback") { setStatus("idle"); } }} onValidSubmit={(body) => void handleSubmit(body)} />
获取报价
)}
{mothershipLoggedInUi && loggedInDraft ? ( void handleMsCheckout(intent)} onSelectQuote={ isEmbeddedHost && hostBridge ? handleSelectQuoteForHost : undefined } /> ) : ( setStatus("expired")} onExpiredConfirm={reset} /> )}
)} {!mothershipLoggedInUi && ( void handleDisambiguationConfirm(pickup, delivery) } onCancel={handleDisambiguationCancel} /> )} {mothershipLoggedInUi && refineHold && quote?.quote_id ? ( { setRefineAccepted(true); setRefineActive({ quoteId: quote.quote_id, quote_session_id: refineHold.quote_session_id, total_deadline_ms: refineHold.total_deadline_ms, }); setRefineHold(null); setLoggedInStep("details"); void hostContinueMsRefineHold( apiBaseUrl, serviceToken, customerId, quote.quote_id, refineHold.quote_session_id, ); }} onDecline={() => { void declineRefineHold(refineHold, quote.quote_id); }} /> ) : null} )}
); }