import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http' export interface CalendarContainer { containerBookingId: string cabinetNo: string | null containerNo: string | null vesselName: string | null voyageNo: string | null destinationPortName: string | null destinationWarehouseCode: string | null arrivalAt: string | null arrivalType: 'ACTUAL' | 'ESTIMATED' } export interface CalendarReturn { containerBookingId: string containerNo: string | null fleetSupplierName: string | null actualEmptyReturnAt: string | null emptyReturnWarning: { status: string; deadlineAt: string | null } } export interface CalendarSources { containers: CalendarContainer[]; emptyReturns: CalendarReturn[]; emptyReturnsReadable: boolean } export interface WarehouseArrival { sourceContainerBookingId: string cabinetNo?: string | null containerNo: string | null warehouseName: string | null warehouseCode: string | null plannedAt: string | null actualAt: string | null version: number planCount: number canEdit: boolean plannedDate?: string | null isDefault?: boolean } export interface ScheduleRange { from: string; to: string } type WarehouseArrivalWire = Omit & { planCount: string | number plannedAt?: string | null actualAt?: string | null } /** 在接口边界统一长整型数量,未知数量不能被当成零触发默认日期。 */ function normalizeWarehouseArrival(row: WarehouseArrivalWire): WarehouseArrival { const count = row.planCount if (typeof count !== 'number' && (typeof count !== 'string' || !/^(0|[1-9]\d*)$/.test(count))) { throw new Error('到仓记录的入库计划数量无效,请刷新后重试') } const planCount = Number(count) if (!Number.isSafeInteger(planCount) || planCount < 0) { throw new Error('到仓记录的入库计划数量无效,请刷新后重试') } return { ...row, planCount, plannedAt: row.plannedAt ?? null, actualAt: row.actualAt ?? null } } export async function getCalendarSources(range: ScheduleRange, signal?: AbortSignal) { return unwrapApiResponse(await http.get, ApiEnvelope>( '/platform/v1/terminal-drayages/calendar-sources', { params: range, signal }, )) } export async function getWarehouseArrivals(range: ScheduleRange, sourceContainerBookingIds: string[], signal?: AbortSignal) { const rows = unwrapApiResponse(await http.post, ApiEnvelope>( '/platform/v1/last-leg/appointment-calendar/warehouse-arrivals/query', { ...range, sourceContainerBookingIds }, { signal }, )) return rows.map(normalizeWarehouseArrival) } export interface WarehouseArrivalChange { estimatedWarehouseArrivalAt: string; expectedVersion: number } export async function saveWarehouseArrival(containerId: string, body: WarehouseArrivalChange, key: string) { return unwrapApiResponse(await http.put, ApiEnvelope>( `/platform/v1/last-leg/orders/container-summaries/${encodeURIComponent(containerId)}/expected-arrival`, body, { headers: { 'Idempotency-Key': key } }, )) }