/** 前端类型定义 — 与 PRD / API 契约一致 */ export type QuotePageStatus = | "idle" | "resolving_address" | "validating" | "processing" | "success" | "fallback" | "error" | "expired"; export type DataPageStatus = "loading" | "success" | "empty" | "error"; export type ServiceLevel = "standard" | "guaranteed"; export type RateOption = "lowest" | "fastest" | "bestValue"; export type UnitWeight = "lb" | "kg"; export type UnitDim = "in" | "cm"; export type DisplayUnit = "imperial" | "metric"; export type CargoType = | "general_freight" | "machinery" | "furniture" | "electronics" | "building_materials" | "auto_parts" | "food_nonperishable" | "apparel" | "other"; export interface AddressInput { street: string; city: string; state: string; zip: string; place_id: string; formatted_address: string; selected_from_suggestions: boolean; mothership_option_id?: string; mothership_display_label?: string; selected_from_mothership?: boolean; } export interface MothershipAddressCandidate { option_id: string; display_label: string; formatted_address: string; street: string; city: string; state: string; zip: string; selectable?: boolean; unavailable_reason?: string; } export interface MothershipCandidatesResult { pickup_candidates: MothershipAddressCandidate[]; delivery_candidates: MothershipAddressCandidate[]; requires_selection: boolean; quote_session_id?: string; } export interface QuoteRequestBody { request_id: string; customer_id: string; pickup_address: AddressInput; delivery_address: AddressInput; weight: { value: number; unit: UnitWeight }; dimensions: { length: number; width: number; height: number; unit: UnitDim; }; pallet_count: number; cargo_type: CargoType; service_level?: ServiceLevel; rate_option?: RateOption; display_unit?: DisplayUnit; quote_session_id?: string; } export type QuoteStatus = "processing" | "done" | "failed" | "expired"; export type SourceType = "rpa" | "cache" | "stale"; export interface QuoteItem { service_level: ServiceLevel; rate_option: RateOption; carrier: string; transit_days: string; transit_description: string; raw_freight: number; surcharges: number; raw_total: number; markup_percent: number; markup_amount: number; final_total: number; breakdown: Array<{ item: string; amount: number }>; } export interface QuoteDetail { quote_id: string; request_id: string; status: QuoteStatus; valid_until?: string | null; source_type?: SourceType | null; is_realtime?: boolean; confidence_score?: number | null; currency: string; quotes?: QuoteItem[]; error_code?: string | null; error_message?: string | null; } export interface CreateQuoteResult { quote_id: string; status: "processing" | "done"; } export type MarkupType = "percent" | "fixed"; export interface MarkupConfig { customer_id: string; markup_type: MarkupType; markup_percent: number; markup_fixed_amount: number | null; operator_id: string; remark: string | null; updated_at: string; } export type AlertType = | "PRICE_DEVIATION" | "STALE_FALLBACK" | "RPA_FAILED" | "RPA_CAPTCHA" | "STRUCT_CHANGE" | "SESSION_EXPIRED" | "SECURITY" | "MANUAL_FALLBACK"; export interface AlertRecord { id: string; alert_type: AlertType; quote_id: string | null; cargo_hash: string | null; detail_json: Record | null; status: "open" | "resolved"; resolver_id: string | null; resolved_at: string | null; created_at: string; } export type ErrorCode = | "VALIDATION_FAILED" | "UNAUTHORIZED" | "FORBIDDEN" | "QUOTE_NOT_FOUND" | "RATE_LIMITED" | "QUOTE_UNAVAILABLE" | "QUOTE_TIMEOUT" | "INTERNAL_ERROR"; export interface ApiOk { code: 0; message: string; data: T; } export interface ApiErr { code: ErrorCode | string; message: string; data: null; } export type ApiResponse = ApiOk | ApiErr; export interface AdminUser { user_id: string; role: "admin"; } export interface LoginResponse { token: string; user: AdminUser; } export interface PaginatedResult { list: T[]; total: number; page: number; size: number; } export interface MetricsDashboard { api_success_rate: number; rpa_success_rate: number; realtime_rate: number; cache_hit_rate: number; p95_latency_ms: number; queue_depth: number; open_alerts_count: number; } export interface RpaStatus { workers: Array<{ worker_id: string; last_seen_ms: number | null; paused_seconds: number; online: boolean; }>; queue_depth: number; circuit_open: boolean; success_rate_24h: number; } export interface QueueStats { queue_name: string; waiting: number; active: number; delayed: number; failed: number; completed: number; depth: number; }