import type { AddressInput, AlertRecord, ApiResponse, CreateQuoteResult, LoginResponse, MarkupConfig, MetricsDashboard, MothershipCandidatesResult, PaginatedResult, QueueStats, QuoteDetail, QuoteRequestBody, RpaStatus, } from "@/lib/frontend/types"; import { CANDIDATES_FETCH_TIMEOUT_MS } from "@/lib/frontend/constants"; async function parseJson(response: Response): Promise> { const contentType = response.headers.get("content-type") ?? ""; if (!contentType.includes("application/json")) { return { code: "INTERNAL_ERROR", message: response.ok ? "响应解析失败" : `服务异常 (HTTP ${response.status})`, data: null, }; } try { return (await response.json()) as ApiResponse; } catch { return { code: "INTERNAL_ERROR", message: "响应解析失败", data: null, }; } } function hostHeaders( serviceToken: string, customerId: string, ): Record { return { Authorization: `Bearer ${serviceToken}`, "x-customer-id": customerId, "Content-Type": "application/json", "Cache-Control": "no-store", }; } function adminHeaders(token: string): Record { return { Authorization: `Bearer ${token}`, "Content-Type": "application/json", "Cache-Control": "no-store", }; } export async function hostCreateQuote( apiBaseUrl: string, serviceToken: string, body: QuoteRequestBody, ): Promise> { const response = await fetch(`${apiBaseUrl}/api/quotes`, { method: "POST", headers: hostHeaders(serviceToken, body.customer_id), body: JSON.stringify(body), cache: "no-store", }); return parseJson(response); } export async function hostFetchMothershipCandidates( apiBaseUrl: string, serviceToken: string, customerId: string, pickup: Pick, delivery: Pick, ): Promise> { const controller = new AbortController(); const timeout = setTimeout( () => controller.abort(), CANDIDATES_FETCH_TIMEOUT_MS, ); try { const response = await fetch( `${apiBaseUrl}/api/addresses/mothership-candidates`, { method: "POST", headers: hostHeaders(serviceToken, customerId), body: JSON.stringify({ customer_id: customerId, pickup_address: pickup, delivery_address: delivery, }), cache: "no-store", signal: controller.signal, }, ); return parseJson(response); } catch (error) { if (error instanceof Error && error.name === "AbortError") { return { code: "QUOTE_TIMEOUT", message: "地址联想超时,MotherShip 响应较慢,请稍后重试", data: null, }; } throw error; } finally { clearTimeout(timeout); } } export async function hostPreheatQuoteSession( apiBaseUrl: string, serviceToken: string, customerId: string, quoteSessionId: string, ): Promise { try { await fetch( `${apiBaseUrl}/api/addresses/mothership-candidates/preheat`, { method: "POST", headers: hostHeaders(serviceToken, customerId), body: JSON.stringify({ customer_id: customerId, quote_session_id: quoteSessionId, }), cache: "no-store", }, ); } catch { /* 预热失败不阻断主流程 */ } } export async function hostConfirmMothershipAddresses( apiBaseUrl: string, serviceToken: string, customerId: string, quoteSessionId: string, pickup: MothershipCandidatesResult["pickup_candidates"][number], delivery: MothershipCandidatesResult["delivery_candidates"][number], ): Promise> { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 300_000); try { const response = await fetch( `${apiBaseUrl}/api/addresses/mothership-candidates/confirm`, { method: "POST", headers: hostHeaders(serviceToken, customerId), body: JSON.stringify({ customer_id: customerId, quote_session_id: quoteSessionId, pickup, delivery, }), cache: "no-store", signal: controller.signal, }, ); return parseJson(response); } catch (error) { if (error instanceof Error && error.name === "AbortError") { return { code: "QUOTE_TIMEOUT", message: "地址确认超时,请重试", data: null, }; } throw error; } finally { clearTimeout(timeout); } } export async function hostReleaseQuoteSession( apiBaseUrl: string, serviceToken: string, customerId: string, quoteSessionId: string, ): Promise { try { await fetch( `${apiBaseUrl}/api/addresses/mothership-candidates/release`, { method: "POST", headers: hostHeaders(serviceToken, customerId), body: JSON.stringify({ customer_id: customerId, quote_session_id: quoteSessionId, }), cache: "no-store", }, ); } catch { /* 释放失败不阻断 UI */ } } export async function hostGetQuote( apiBaseUrl: string, serviceToken: string, customerId: string, quoteId: string, ): Promise> { const response = await fetch(`${apiBaseUrl}/api/quotes/${quoteId}`, { method: "GET", headers: hostHeaders(serviceToken, customerId), cache: "no-store", }); return parseJson(response); } export async function adminLogin( apiBaseUrl: string, username: string, password: string, ): Promise> { const response = await fetch(`${apiBaseUrl}/api/auth/login`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username, password }), cache: "no-store", }); return parseJson(response); } export async function adminGetAlerts( apiBaseUrl: string, token: string, page: number, size: number, type?: string, status?: string, ): Promise>> { const params = new URLSearchParams({ page: String(page), size: String(size), }); if (type) params.set("type", type); if (status) params.set("status", status); const response = await fetch(`${apiBaseUrl}/api/alerts?${params}`, { headers: adminHeaders(token), cache: "no-store", }); return parseJson(response); } export async function adminResolveAlert( apiBaseUrl: string, token: string, alertId: string, resolverId: string, ): Promise> { const response = await fetch(`${apiBaseUrl}/api/alerts/${alertId}/resolve`, { method: "POST", headers: adminHeaders(token), body: JSON.stringify({ resolver_id: resolverId }), cache: "no-store", }); return parseJson(response); } export async function adminGetMarkupConfigs( apiBaseUrl: string, token: string, page: number, size: number, keyword?: string, ): Promise>> { const params = new URLSearchParams({ page: String(page), size: String(size), }); if (keyword) params.set("keyword", keyword); const response = await fetch( `${apiBaseUrl}/api/admin/markup-configs?${params}`, { headers: adminHeaders(token), cache: "no-store", }, ); return parseJson(response); } export async function adminUpdateMarkupConfig( apiBaseUrl: string, token: string, customerId: string, body: { markup_type: "percent" | "fixed"; markup_percent?: number; markup_fixed_amount?: number; remark?: string; }, ): Promise> { const response = await fetch( `${apiBaseUrl}/api/admin/markup-configs/${customerId}`, { method: "PUT", headers: adminHeaders(token), body: JSON.stringify(body), cache: "no-store", }, ); return parseJson(response); } export async function adminGetMetrics( apiBaseUrl: string, token: string, ): Promise> { const response = await fetch(`${apiBaseUrl}/api/metrics/dashboard`, { headers: adminHeaders(token), cache: "no-store", }); return parseJson(response); } export async function adminGetRpaStatus( apiBaseUrl: string, token: string, ): Promise> { const response = await fetch(`${apiBaseUrl}/api/rpa/status`, { headers: adminHeaders(token), cache: "no-store", }); return parseJson(response); } export async function adminGetQueueStats( apiBaseUrl: string, token: string, ): Promise> { const response = await fetch(`${apiBaseUrl}/api/admin/queues/stats`, { headers: adminHeaders(token), cache: "no-store", }); return parseJson(response); } export async function adminPauseWorker( apiBaseUrl: string, token: string, workerId: string, durationMinutes: number, ): Promise> { const response = await fetch(`${apiBaseUrl}/api/rpa/worker/pause`, { method: "POST", headers: adminHeaders(token), body: JSON.stringify({ worker_id: workerId, duration_minutes: durationMinutes, }), cache: "no-store", }); return parseJson(response); }