Files
admin-web/src/modules/ocean-bookings/api/platformOceanBookings.ts
T

67 lines
5.3 KiB
TypeScript
Raw Normal View History

2026-08-08 13:32:27 +08:00
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
import type { OceanBookingActionRequest, OceanBookingChangeRequest, OceanBookingDetail, OceanBookingPage, OceanBookingQuery, OceanBookingResource, OceanBookingSaveRequest, OceanBookingStatus, OceanBookingReleaseRequest } from '../types'
2026-08-08 13:32:27 +08:00
const basePath = '/platform/v1/ocean-bookings'
2026-08-14 18:50:11 +08:00
export interface OceanLogisticsChannel {
channelCode: string
channelName: string
}
2026-08-08 13:32:27 +08:00
function pageNumber(value: number | string, fallback: number) { const n = Number(value); return Number.isFinite(n) ? Math.trunc(n) : fallback }
2026-08-10 09:12:06 +08:00
function booking(raw: OceanBookingResource): OceanBookingResource {
const item = raw as OceanBookingResource & { version?: number | string | null }
return {
...raw,
id: String(raw.id),
version: Number(item.version ?? 0),
customerId: raw.customerId == null ? null : String(raw.customerId),
shippingCompanyId: raw.shippingCompanyId == null ? null : String(raw.shippingCompanyId),
bookingAgentId: raw.bookingAgentId == null ? null : String(raw.bookingAgentId),
2026-08-17 19:57:32 +08:00
containerCount: Number(raw.containerCount ?? 0),
2026-08-10 09:12:06 +08:00
pol: raw.pol ?? raw.departurePortName ?? null,
pod: raw.pod ?? raw.destinationPortName ?? null,
carrierName: raw.carrierName ?? raw.shippingCompanyName ?? null,
bookingAgent: raw.bookingAgent ?? raw.bookingAgentName ?? null,
etd: raw.etd ?? raw.estimatedSailingAt ?? null,
eta: raw.eta ?? raw.estimatedArrivalAt ?? null,
}
}
function detail(raw: OceanBookingDetail): OceanBookingDetail {
const source = booking(raw.oceanBooking || raw)
const histories = (raw.histories || raw.statusHistory || []).map((event) => ({ ...event, id: String(event.id) }))
return {
...raw,
...source,
oceanBooking: source,
parties: (raw.parties || []).map((party) => ({ ...party, id: party.id == null ? undefined : String(party.id) })),
2026-08-17 13:24:55 +08:00
containers: (raw.containers || []).map((container) => ({
...container,
containerBookingId: String(container.containerBookingId),
requirementId: String(container.requirementId),
allocationId: String(container.allocationId),
warehouseId: String(container.warehouseId),
customerId: container.customerId == null ? null : String(container.customerId),
})),
2026-08-10 09:12:06 +08:00
histories,
statusHistory: histories,
}
}
2026-08-08 13:32:27 +08:00
export async function listOceanBookings(query: OceanBookingQuery) {
const response = await http.get<ApiEnvelope<OceanBookingPage>, ApiEnvelope<OceanBookingPage>>(basePath, { params: query })
const result = unwrapApiResponse(response)
return { ...result, records: (result.records || []).map(booking), page: pageNumber(result.page, query.page), size: pageNumber(result.size, query.size), total: pageNumber(result.total, 0), pages: pageNumber(result.pages, 0) } satisfies OceanBookingPage
}
2026-08-10 09:12:06 +08:00
export async function getOceanBooking(id: string) { const response = await http.get<ApiEnvelope<OceanBookingDetail>, ApiEnvelope<OceanBookingDetail>>(`${basePath}/${encodeURIComponent(id)}`); return detail(unwrapApiResponse(response)) }
2026-08-08 13:46:21 +08:00
function idempotencyKey() { return `ocean-booking-${Date.now()}-${Math.random().toString(36).slice(2)}` }
2026-08-10 09:12:06 +08:00
export async function createOceanBooking(payload: OceanBookingSaveRequest) { const response = await http.post<ApiEnvelope<OceanBookingDetail>, ApiEnvelope<OceanBookingDetail>>(basePath, payload, { headers: { 'Idempotency-Key': idempotencyKey() } }); return detail(unwrapApiResponse(response)) }
2026-08-15 09:47:23 +08:00
export type OceanBookingAction = 'release' | 'cancel' | 'change-request' | 'change-confirm' | 'change-fail'
export async function performOceanBookingAction(id: string, action: Exclude<OceanBookingAction, 'change-request' | 'release'>, request: OceanBookingActionRequest) { const response = await http.post<ApiEnvelope<OceanBookingDetail>, ApiEnvelope<OceanBookingDetail>>(`${basePath}/${encodeURIComponent(id)}/${action}`, request, { headers: { 'Idempotency-Key': idempotencyKey() } }); return detail(unwrapApiResponse(response)) }
export async function releaseOceanBooking(id: string, request: OceanBookingReleaseRequest) { const response = await http.post<ApiEnvelope<OceanBookingDetail>, ApiEnvelope<OceanBookingDetail>>(`${basePath}/${encodeURIComponent(id)}/release`, request, { headers: { 'Idempotency-Key': idempotencyKey() } }); return detail(unwrapApiResponse(response)) }
2026-08-10 09:12:06 +08:00
export async function requestOceanBookingChange(id: string, request: OceanBookingChangeRequest) { const response = await http.post<ApiEnvelope<OceanBookingDetail>, ApiEnvelope<OceanBookingDetail>>(`${basePath}/${encodeURIComponent(id)}/change-request`, request, { headers: { 'Idempotency-Key': idempotencyKey() } }); return detail(unwrapApiResponse(response)) }
2026-08-08 13:32:27 +08:00
export async function printOceanBooking(id: string, type: 'SHIPPING_INSTRUCTION' | 'BILL_CONFIRMATION') { return http.get<Blob, Blob>(`${basePath}/${encodeURIComponent(id)}/print`, { params: { type }, responseType: 'blob' }) }
2026-08-14 18:50:11 +08:00
export async function listWarehouseLogisticsChannels(warehouseId: string): Promise<OceanLogisticsChannel[]> {
const response = await http.get<ApiEnvelope<OceanLogisticsChannel[]>, ApiEnvelope<OceanLogisticsChannel[]>>(`${basePath}/channels`, { params: { originWarehouseId: warehouseId } })
return (unwrapApiResponse(response) || []).map((item) => ({ channelCode: String(item.channelCode), channelName: String(item.channelName) }))
}
2026-08-08 13:32:27 +08:00
export type { OceanBookingResource, OceanBookingStatus }