import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http' import type { CapacityOffer, CapacityInquiry, CapacityOfferDetail, CapacityLoad, OfferPage, OfferQuery, InquiryQuery, OfferWrite, OfferCommand, InquiryWrite, InquiryCommand, OfferResult, InquiryResult, OfferCustomerOption } from '../capacityOfferTypes' import { normalizeFleetQuotePage, normalizeFleetQuoteSource, type WireQuotePage } from './fleetQuoteCandidates' import type { TripBookingQuoteCriteria } from './tripBookings' const base = '/platform/v1/last-leg/fleet/capacity-offers' const path = (value: string) => `${base}/${encodeURIComponent(value)}` const inquiryPath = (value: string) => `${base}/inquiries/${encodeURIComponent(value)}` const number = (value: number) => { const n = Number(value); if (value == null || !Number.isFinite(n)) throw new Error('运力数据数值无效'); return n } const nullable = (value: number | null) => value == null ? null : number(value) const load = (value: CapacityLoad | null) => value == null ? null : { palletSpaces: number(value.palletSpaces), weightKg: number(value.weightKg), volumeCbm: number(value.volumeCbm) } export function normalizeOffer(value: CapacityOffer): CapacityOffer { return { ...value, recordVersion: number(value.recordVersion), tripRecordVersion: number(value.tripRecordVersion), destinations: value.destinations.map(d => ({ ...d, deliveryIndex: number(d.deliveryIndex), remaining: load(d.remaining) })), segments: value.segments.map(s => ({ ...s, fromIndex: number(s.fromIndex), toIndex: number(s.toIndex), planned: load(s.planned), reserved: load(s.reserved), remaining: load(s.remaining) })) } } export function normalizeInquiry(value: CapacityInquiry): CapacityInquiry { return { ...value, recordVersion: number(value.recordVersion), offerRecordVersion: number(value.offerRecordVersion), tripRecordVersion: number(value.tripRecordVersion), expectedPalletCount: nullable(value.expectedPalletCount), agreedAmount: nullable(value.agreedAmount), quoteSource: value.quoteSource ? normalizeFleetQuoteSource(value.quoteSource) : null, cargo: { ...value.cargo, packageCount: nullable(value.cargo.packageCount), palletSpaces: nullable(value.cargo.palletSpaces), weightKg: nullable(value.cargo.weightKg), volumeCbm: nullable(value.cargo.volumeCbm), unitPrice: nullable(value.cargo.unitPrice) } } } function page(value: OfferPage, normalize: (row: T) => T): OfferPage { return { records: value.records.map(normalize), page: number(value.page), size: number(value.size), total: number(value.total), pages: number(value.pages) } } const offerResult = (value: OfferResult): OfferResult => ({ ...value, offer: normalizeOffer(value.offer) }) const inquiryResult = (value: InquiryResult): InquiryResult => ({ ...offerResult(value), inquiry: normalizeInquiry(value.inquiry) }) async function get(url: string, params?: object) { return unwrapApiResponse(await http.get, ApiEnvelope>(url, { params })) } async function post(url: string, body: object) { return unwrapApiResponse(await http.post, ApiEnvelope>(url, body)) } async function put(url: string, body: object) { return unwrapApiResponse(await http.put, ApiEnvelope>(url, body)) } export async function listCapacityOffers(query: OfferQuery) { return page(await get>(base, query), normalizeOffer) } export async function getCapacityOffer(offerNo: string): Promise { const value = await get(path(offerNo)); return { offer: normalizeOffer(value.offer), inquiries: page(value.inquiries, normalizeInquiry) } } export async function listCapacityInquiries(query: InquiryQuery) { return page(await get>(`${base}/inquiries`, query), normalizeInquiry) } export async function getCapacityInquiry(bookingNo: string) { return normalizeInquiry(await get(inquiryPath(bookingNo))) } export async function saveCapacityOffer(offerNo: string | null, body: OfferWrite) { return offerResult(await (offerNo ? put(path(offerNo), body) : post(base, body))) } export async function commandCapacityOffer(offerNo: string, action: 'publish' | 'pause' | 'resume' | 'close', body: OfferCommand) { return offerResult(await post(`${path(offerNo)}/${action}`, body)) } export async function saveCapacityInquiry(offerNo: string, bookingNo: string | null, body: InquiryWrite) { return inquiryResult(await (bookingNo ? put(inquiryPath(bookingNo), body) : post(`${path(offerNo)}/inquiries`, body))) } export async function commandCapacityInquiry(bookingNo: string, action: 'confirm' | 'cancel', body: InquiryCommand) { return inquiryResult(await post(`${inquiryPath(bookingNo)}/${action}`, body)) } export const listOfferCustomers = (keyword?: string) => get(`${base}/customer-options`, { keyword }) export async function listOfferQuotes(offerNo: string, query: TripBookingQuoteCriteria) { return normalizeFleetQuotePage(await get(`${path(offerNo)}/quote-candidates`, query)) }