448 lines
14 KiB
TypeScript
448 lines
14 KiB
TypeScript
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<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 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<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),
|
|
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<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 downloadPlatformProductImage(tenantId: string, fileId: string) {
|
|
return http.get<Blob, Blob>(
|
|
`/platform/v1/files/product-images/${encodeURIComponent(tenantId)}/${encodeURIComponent(fileId)}`,
|
|
{ responseType: 'blob' },
|
|
)
|
|
}
|
|
|
|
export function approvePlatformUnifiedOrder(tenantId: string, orderId: string) {
|
|
return http.post<ApiEnvelope<void>, ApiEnvelope<void>>(
|
|
`/platform/v1/orders/first-leg/${orderId}/approve`,
|
|
undefined,
|
|
{ params: { tenantId } },
|
|
).then(unwrapApiResponse)
|
|
}
|
|
|
|
export interface UnifiedOrderBatchApprovalResult {
|
|
total: number
|
|
successCount: number
|
|
failureCount: number
|
|
successOrderIds: Array<number | string>
|
|
failedOrders: Array<{ orderId: number | string; code: string; message: string }>
|
|
}
|
|
|
|
export function batchApprovePlatformUnifiedOrders(tenantId: string, orderIds: string[]) {
|
|
return http.post<ApiEnvelope<UnifiedOrderBatchApprovalResult>, ApiEnvelope<UnifiedOrderBatchApprovalResult>>(
|
|
'/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<number | string>, ApiEnvelope<number | string>>(
|
|
`${unifiedOrdersApiPath}/${orderId}/internal-notes`,
|
|
{ content },
|
|
{ params: { tenantId } },
|
|
).then(unwrapApiResponse)
|
|
}
|
|
|
|
export async function listPlatformUnifiedOrderFeeDetails(accountId: string, inboundId: string) {
|
|
const response = await http.get<ApiEnvelope<UnifiedOrderFeeDetailResource[]>, ApiEnvelope<UnifiedOrderFeeDetailResource[]>>(
|
|
`/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 || '未知状态'
|
|
}
|