import type { QuoteRecord } from "@prisma/client"; import { getConfidenceScore } from "@/modules/quote/confidence"; import { formatQuoteErrorMessage } from "@/modules/quote/quote-error-messages"; export type QuoteDetailResponse = { quote_id: string; request_id: string; status: "processing" | "done" | "failed" | "expired"; valid_until?: string; source_type?: "rpa" | "cache" | "stale"; is_realtime?: boolean; confidence_score?: number; currency: string; error_code?: string; error_message?: string; quotes?: unknown[]; }; export type QuoteSummaryItem = { quote_id: string; request_id: string; status: string; source_type: string | null; is_realtime: boolean; created_at: string; valid_until: string | null; pallet_count: number; cargo_type: string; error_code: string | null; }; function resolveStatus(record: QuoteRecord): QuoteDetailResponse["status"] { if ( record.status === "done" && record.validUntil && record.validUntil.getTime() < Date.now() ) { return "expired"; } return record.status as QuoteDetailResponse["status"]; } /** 将 QuoteRecord 格式化为 GET /quotes/{id} 响应 */ export function serializeQuoteDetail(record: QuoteRecord): QuoteDetailResponse { const status = resolveStatus(record); const sourceType = record.sourceType as | "rpa" | "cache" | "stale" | null | undefined; const base: QuoteDetailResponse = { quote_id: record.quoteId, request_id: record.requestId, status, currency: record.currency, }; if (status === "processing") { return base; } if (status === "failed") { const errorCode = record.errorCode ?? "QUOTE_UNAVAILABLE"; return { ...base, error_code: errorCode, error_message: formatQuoteErrorMessage(errorCode, record.errorMessage), is_realtime: record.isRealtime, }; } if (status === "expired") { return { ...base, valid_until: record.validUntil?.toISOString(), source_type: sourceType ?? undefined, is_realtime: record.isRealtime, }; } const confidence = record.confidenceScore != null ? Number(record.confidenceScore) : sourceType ? getConfidenceScore(sourceType) : 0.95; return { ...base, valid_until: record.validUntil?.toISOString(), source_type: sourceType ?? undefined, is_realtime: record.isRealtime, confidence_score: confidence, quotes: (record.quotesJson as unknown[]) ?? [], }; } /** 历史列表摘要 */ export function serializeQuoteSummary(record: QuoteRecord): QuoteSummaryItem { const status = resolveStatus(record); return { quote_id: record.quoteId, request_id: record.requestId, status, source_type: record.sourceType, is_realtime: record.isRealtime, created_at: record.createdAt.toISOString(), valid_until: record.validUntil?.toISOString() ?? null, pallet_count: record.palletCount, cargo_type: record.cargoType, error_code: record.errorCode, }; }