import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http' export const unifiedOrdersApiPath = '/platform/v1/orders' export type UnifiedOrderMainStatus = | 'PENDING_REVIEW' | 'WAIT_MEASURE' | 'WAIT_SPLIT' | 'LOADING' | 'LOADED' | 'DELIVERED' export const unifiedOrderStatusOptions: Array<{ value: UnifiedOrderMainStatus; label: string }> = [ { value: 'PENDING_REVIEW', label: '待审核' }, { value: 'WAIT_MEASURE', label: '待测量数据' }, { value: 'WAIT_SPLIT', label: '待分柜' }, { value: 'LOADING', label: '装柜中' }, { value: 'LOADED', label: '装柜完成' }, { value: 'DELIVERED', label: '派送完成' }, ] export interface UnifiedOrderMeasurementSummary { reviewStatus: string | null actualGrossWeightKg: number | null actualVolumeCbm: number | null chargeableWeightKg: number | null completedAt: string | null } export interface UnifiedOrderPreloadSummary { status: string | null version: number | null itemCount: number | null updatedAt: string | null } export interface UnifiedOrderLoadingSummary { status: string | null loadingVersion: number | null pickingVersion: number | null expectedCount: number | null pickedCount: number | null evidenceCount: number | null sealNo: string | null updatedAt: string | null } export interface UnifiedOrderDeliverySummary { status: string | null completedAt: string | null trackingNo: string | null } export interface UnifiedOrderTransportSummary { loadingStatus: string | null containerNo: string | null cabinetNo: string | null vesselName: string | null voyageNo: string | null estimatedSailingAt: string | null actualSailingAt: string | null effectiveSailingAt: string | null effectiveSailingAtEstimated: boolean | null estimatedPortArrivalAt: string | null actualPortArrivalAt: string | null effectivePortArrivalAt: string | null effectivePortArrivalAtEstimated: boolean | null } export interface UnifiedOrderRelationSummary { role: 'PARENT' | 'CHILD' rootOrderId: number | string | null parentOrderId: number | string | null splitSequence: number | null childCount: number } export interface UnifiedOrderResource { orderId: number | string tenantId: number | string orderNo: string | null mainStatus: UnifiedOrderMainStatus nextAction: string | null relation: UnifiedOrderRelationSummary | null internalOrderStatus: string | null customerId: number | string | null customerName: string | null channelName: string | null receivingWarehouseId: number | string | null receivingWarehouseName: string | null destinationWarehouseId: number | string | null destinationWarehouseName: string | null inboundId: number | string | null inboundVersion: number | null inboundCode: string | null expectedShipDate: string | null totalPackageCount: number | null locationCodes: string | null actualGrossWeightKg: number | null actualVolumeCbm: number | null measurement: UnifiedOrderMeasurementSummary | null preload: UnifiedOrderPreloadSummary | null loading: UnifiedOrderLoadingSummary | null delivery: UnifiedOrderDeliverySummary | null transport: UnifiedOrderTransportSummary | null createdAt: string | null updatedAt: string | null expectedArrivalAt: string | null feeReviewStatus: string | null holdCargo?: boolean | null holdReason?: string | null companyName?: string | null businessType?: string | null pickupMethod?: string | null requestedPickupAt: string | null pickupAt?: string | null pickupContactPhone?: string | null pickupAddress?: string | null pickupPostalCode?: string | null pickupContactEmail?: string | null taxMode?: string | null fullContainer?: boolean | null customsInspection?: boolean | null totalPalletCount: number | null chargeableVolumeCbm: number | null volumetricWeightKg: number | null totalNetWeightKg: number | null location?: string | null destinationType?: string | null destinationAddress?: string | null destinationPostalCode?: string | null destinationContact?: string | null destinationContactPhone?: string | null measurementCompletedAt: string | null inboundCompletedAt: string | null associatedFiles?: string[] | null markFiles?: string[] | null pcOrderFiles?: string[] | null expressCompany: string | null expressTrackingNo: string | null skuNos: string[] | null totalQuantity: number | null shipmentId: string | null referenceId: string | null remark?: string | null customerRemark?: string | null latestInternalNote?: string | null internalRemark?: string | null createdBy?: string | null } export interface UnifiedOrderTimelineEvent { source: string | null eventType: string | null mainStatus: UnifiedOrderMainStatus | null action: string | null remark: string | null operatorId: number | string | null operatorName: string | null occurredAt: string | null } export interface UnifiedOrderDetailOrderSnapshot { id: number | string | null tenantId: number | string | null orderNo: string | null customerId: number | string | null customerName: string | null transportMode: string | null tradeTerm?: string | null destinationCountryCode: string | null destinationWarehouseId: number | string | null destinationWarehouseName: string | null expectedShipDate: string | null customerRemark?: string | null pickupMethod?: string | null receivingWarehouseId: number | string | null receivingWarehouseName: string | null receivingWarehouseAddress?: string | null receivingTime?: string | null channelCode?: string | null channelName: string | null carrierId: number | string | null carrierName: string | null taxMode?: string | null containerMode?: string | null customsInspection?: boolean | null destinationType?: string | null amazonWarehouseCode?: string | null shipmentId?: string | null referenceId?: string | null expressCompany?: string | null expressTrackingNo?: string | null submittedAt?: string | null completedAt?: string | null createdAt: string | null updatedAt: string | null } export interface UnifiedOrderDetailOrderResource { order: UnifiedOrderDetailOrderSnapshot | null cargoes: Array> parties: Array> internalNotes: UnifiedOrderInternalNoteResource[] statusHistory: UnifiedOrderStatusHistoryResource[] } export interface UnifiedOrderInternalNoteResource { id: number | string content: string createdBy: number | string | null createdAt: string | null } export interface UnifiedOrderStatusHistoryResource { id: number | string fromStatus: string | null toStatus: string | null action: string | null reason: string | null operatorId: number | string | null operatorName: string | null occurredAt: string | null } export interface UnifiedOrderDetailResource { summary: UnifiedOrderResource order: UnifiedOrderDetailOrderResource timeline: UnifiedOrderTimelineEvent[] } export interface UnifiedOrderFeeDetailResource { id: number | string sourceFeeId?: number | string | null sourceFeeVersion?: number | null inboundId: number | string inboundCode: string | null reviewStatus: string | null direction: string | null customerName: string | null invoiceTitle: string | null businessDate: string | null channelName: string | null destinationName: string | null fbaNo?: string | null packageCount: number | null actualGrossWeightKg: number | null actualVolumeCbm: number | null feeTypeNameSnapshot: string | null currency: string | null amount: number | null chargeableQuantity: number | null chargeUnit: string | null unitPrice: number | null inboundedAt: string | null outboundAt?: string | null storageDays?: number | null billNo?: string | null settlementStartDate?: string | null settlementEndDate?: string | null } export interface UnifiedOrderPageResource { records: UnifiedOrderResource[] page: number size: number total: number pages: number } export interface UnifiedOrderQuery { tenantId?: string keyword?: string orderNo?: string mainStatus?: UnifiedOrderMainStatus customerId?: string receivingWarehouseId?: string destinationWarehouseId?: string inboundCode?: string internalOrderStatus?: string expectedArrivalDate?: string feeReviewStatus?: string channelName?: string containerNo?: string cabinetNo?: string sailingDate?: string loaded?: boolean fullContainer?: boolean measurementReviewStatus?: string fbaCode?: string createdFrom?: string createdTo?: string page: number size: number } type PagePayload = Omit & { page: number | string size: number | string total: number | string pages: number | string } function integer(value: number | string | null | undefined, fallback: number) { const parsed = Number(value) return Number.isFinite(parsed) && parsed >= 0 ? Math.trunc(parsed) : fallback } function nullableInteger(value: number | string | null | undefined) { if (value === null || value === undefined || value === '') return null return integer(value, 0) } function numberValue(value: number | string | null | undefined) { if (value === null || value === undefined || value === '') return null const parsed = Number(value) return Number.isFinite(parsed) ? parsed : null } function id(value: number | string | null | undefined) { return value === null || value === undefined || value === '' ? null : String(value) } function queryParams(query: UnifiedOrderQuery) { return Object.fromEntries(Object.entries(query).filter(([, value]) => value !== undefined && value !== '')) } function normalizeRow(raw: UnifiedOrderResource): UnifiedOrderResource { return { ...raw, orderId: String(raw.orderId), tenantId: String(raw.tenantId), customerId: id(raw.customerId), receivingWarehouseId: id(raw.receivingWarehouseId), destinationWarehouseId: id(raw.destinationWarehouseId), inboundId: id(raw.inboundId), inboundVersion: nullableInteger(raw.inboundVersion), relation: raw.relation ? { ...raw.relation, rootOrderId: id(raw.relation.rootOrderId), parentOrderId: id(raw.relation.parentOrderId), splitSequence: nullableInteger(raw.relation.splitSequence), childCount: integer(raw.relation.childCount, 0), } : null, totalPackageCount: nullableInteger(raw.totalPackageCount), actualGrossWeightKg: numberValue(raw.actualGrossWeightKg), actualVolumeCbm: numberValue(raw.actualVolumeCbm), totalPalletCount: nullableInteger(raw.totalPalletCount), chargeableVolumeCbm: numberValue(raw.chargeableVolumeCbm), volumetricWeightKg: numberValue(raw.volumetricWeightKg), totalNetWeightKg: numberValue(raw.totalNetWeightKg), totalQuantity: nullableInteger(raw.totalQuantity), skuNos: raw.skuNos?.filter((value) => value.trim()) ?? null, locationCodes: raw.locationCodes ?? raw.location ?? null, measurement: raw.measurement ? { ...raw.measurement, actualGrossWeightKg: numberValue(raw.measurement.actualGrossWeightKg), actualVolumeCbm: numberValue(raw.measurement.actualVolumeCbm), chargeableWeightKg: numberValue(raw.measurement.chargeableWeightKg), } : null, preload: raw.preload ? { ...raw.preload, version: nullableInteger(raw.preload.version), itemCount: nullableInteger(raw.preload.itemCount) } : null, loading: raw.loading ? { ...raw.loading, loadingVersion: nullableInteger(raw.loading.loadingVersion), pickingVersion: nullableInteger(raw.loading.pickingVersion), expectedCount: nullableInteger(raw.loading.expectedCount), pickedCount: nullableInteger(raw.loading.pickedCount), evidenceCount: nullableInteger(raw.loading.evidenceCount), } : null, transport: raw.transport ? { ...raw.transport } : null, } } export async function listPlatformUnifiedOrders(query: UnifiedOrderQuery) { const response = await http.get, ApiEnvelope>(unifiedOrdersApiPath, { params: queryParams(query), }) const result = unwrapApiResponse(response) return { ...result, records: (result.records || []).map(normalizeRow), page: integer(result.page, query.page), size: integer(result.size, query.size), total: integer(result.total, 0), pages: integer(result.pages, 0), } satisfies UnifiedOrderPageResource } export async function getPlatformUnifiedOrder(tenantId: string, orderId: string) { const response = await http.get, ApiEnvelope>( `${unifiedOrdersApiPath}/${orderId}`, { params: { tenantId } }, ) const result = unwrapApiResponse(response) return { ...result, summary: normalizeRow(result.summary) } } export function downloadPlatformProductImage(tenantId: string, fileId: string) { return http.get( `/platform/v1/files/product-images/${encodeURIComponent(tenantId)}/${encodeURIComponent(fileId)}`, { responseType: 'blob' }, ) } export function approvePlatformUnifiedOrder(tenantId: string, orderId: string) { return http.post, ApiEnvelope>( `/platform/v1/orders/first-leg/${orderId}/approve`, undefined, { params: { tenantId } }, ).then(unwrapApiResponse) } export interface UnifiedOrderBatchApprovalResult { total: number successCount: number failureCount: number successOrderIds: Array failedOrders: Array<{ orderId: number | string; code: string; message: string }> } export function batchApprovePlatformUnifiedOrders(tenantId: string, orderIds: string[]) { return http.post, ApiEnvelope>( '/platform/v1/orders/first-leg/batch-approve', { orderIds }, { params: { tenantId } }, ).then(unwrapApiResponse) } export function addPlatformUnifiedOrderNote(tenantId: string, orderId: string, content: string) { return http.post, ApiEnvelope>( `${unifiedOrdersApiPath}/${orderId}/internal-notes`, { content }, { params: { tenantId } }, ).then(unwrapApiResponse) } export async function listPlatformUnifiedOrderFeeDetails(accountId: string, inboundId: string) { const response = await http.get, ApiEnvelope>( `/platform/v1/inbounds/${encodeURIComponent(inboundId)}/fee-details`, { params: { accountId } }, ) return unwrapApiResponse(response) } export function unifiedOrderStatusLabel(status: UnifiedOrderMainStatus) { return unifiedOrderStatusOptions.find((item) => item.value === status)?.label || '未知状态' }