This commit is contained in:
2026-08-06 13:56:04 +08:00
parent 6736893128
commit a813426588
35 changed files with 2822 additions and 489 deletions
@@ -0,0 +1,264 @@
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
export const unifiedOrdersApiPath = '/platform/v1/orders'
export type UnifiedOrderMainStatus =
| 'PENDING_REVIEW'
| 'WAIT_MEASURE'
| 'INBOUNDED'
| 'WAIT_SPLIT'
| 'LOADING'
| 'LOADED'
| 'DELIVERED'
export const unifiedOrderStatusOptions: Array<{ value: UnifiedOrderMainStatus; label: string }> = [
{ value: 'PENDING_REVIEW', label: '待审核' },
{ value: 'WAIT_MEASURE', label: '待测量数据' },
{ value: 'INBOUNDED', 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
sailingAt: string | null
portArrivalAt: string | null
}
export interface UnifiedOrderResource {
orderId: number | string
tenantId: number | string
orderNo: string | null
mainStatus: UnifiedOrderMainStatus
nextAction: string | 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
measurement: UnifiedOrderMeasurementSummary | null
preload: UnifiedOrderPreloadSummary | null
loading: UnifiedOrderLoadingSummary | null
delivery: UnifiedOrderDeliverySummary | null
transport: UnifiedOrderTransportSummary | null
createdAt: string | null
updatedAt: 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
destinationCountryCode: string | null
destinationWarehouseId: number | string | null
destinationWarehouseName: string | null
expectedShipDate: string | null
receivingWarehouseId: number | string | null
receivingWarehouseName: string | null
channelName: string | null
createdAt: string | null
updatedAt: string | null
}
export interface UnifiedOrderDetailOrderResource {
order: UnifiedOrderDetailOrderSnapshot | null
cargoes: Array<Record<string, unknown>>
parties: Array<Record<string, unknown>>
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 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
createdFrom?: string
createdTo?: string
page: number
size: number
}
type PagePayload = Omit<UnifiedOrderPageResource, 'page' | 'size' | 'total' | 'pages'> & {
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),
totalPackageCount: nullableInteger(raw.totalPackageCount),
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<PagePayload>, ApiEnvelope<PagePayload>>(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<UnifiedOrderDetailResource>, ApiEnvelope<UnifiedOrderDetailResource>>(
`${unifiedOrdersApiPath}/${orderId}`,
{ params: { tenantId } },
)
const result = unwrapApiResponse(response)
return { ...result, summary: normalizeRow(result.summary) }
}
export function unifiedOrderStatusLabel(status: UnifiedOrderMainStatus) {
return unifiedOrderStatusOptions.find((item) => item.value === status)?.label || status
}