优化
This commit is contained in:
@@ -7,6 +7,10 @@ import type {
|
||||
SmartLoadingCandidate,
|
||||
SmartLoadingItem,
|
||||
SmartLoadingPlan,
|
||||
BusinessDocument,
|
||||
ContainerDocumentType,
|
||||
ContainerOverview,
|
||||
ContainerOverviewDocument,
|
||||
} from '../types'
|
||||
|
||||
const containerPath = '/platform/v1/containers'
|
||||
@@ -19,6 +23,35 @@ function numberValue(value: unknown, fallback = 0): number {
|
||||
return Number.isFinite(parsed) ? parsed : fallback
|
||||
}
|
||||
function operationId(prefix: string) { return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}` }
|
||||
function document(raw: BusinessDocument | null | undefined): BusinessDocument | null {
|
||||
if (!raw) return null
|
||||
return { ...raw, id: raw.id == null ? null : id(raw.id), fileId: id(raw.fileId), uploadedBy: raw.uploadedBy == null ? null : id(raw.uploadedBy), completedBy: raw.completedBy == null ? null : id(raw.completedBy), version: numberValue(raw.version) }
|
||||
}
|
||||
|
||||
function overviewDocument(raw: ContainerOverviewDocument): ContainerOverviewDocument {
|
||||
return { ...raw, id: id(raw.id), fileId: id(raw.fileId), uploadedBy: optionalId(raw.uploadedBy), version: numberValue(raw.version) }
|
||||
}
|
||||
|
||||
function overview(raw: ContainerOverview): ContainerOverview {
|
||||
return {
|
||||
...raw,
|
||||
container: { ...raw.container, id: id(raw.container.id), warehouseId: id(raw.container.warehouseId), version: numberValue(raw.container.version) },
|
||||
loadingPlanId: optionalId(raw.loadingPlanId),
|
||||
pda: raw.pda ? {
|
||||
...raw.pda, taskId: id(raw.pda.taskId), loadingPlanId: id(raw.pda.loadingPlanId),
|
||||
containerBookingId: id(raw.pda.containerBookingId), taskVersion: numberValue(raw.pda.taskVersion),
|
||||
itemCount: numberValue(raw.pda.itemCount), completedItemCount: numberValue(raw.pda.completedItemCount),
|
||||
unresolvedItemCount: numberValue(raw.pda.unresolvedItemCount),
|
||||
photoCounts: (raw.pda.photoCounts || []).map((item) => ({ ...item, count: numberValue(item.count) })),
|
||||
photos: (raw.pda.photos || []).map((item) => ({ ...item, evidenceId: id(item.evidenceId), tenantId: id(item.tenantId), inboundId: id(item.inboundId), fileId: id(item.fileId) })),
|
||||
exceptionReasons: raw.pda.exceptionReasons || [],
|
||||
} : null,
|
||||
documents: (raw.documents || []).map(overviewDocument),
|
||||
exception: { ...raw.exception, markedBy: optionalId(raw.exception?.markedBy) },
|
||||
exceptionHistory: (raw.exceptionHistory || []).map((entry) => ({ ...entry, id: id(entry.id), operatorId: optionalId(entry.operatorId) })),
|
||||
timeline: (raw.timeline || []).map((entry) => ({ ...entry, operatorId: optionalId(entry.operatorId) })),
|
||||
}
|
||||
}
|
||||
|
||||
function container(raw: ContainerBookingResource): ContainerBookingResource {
|
||||
return {
|
||||
@@ -30,6 +63,7 @@ function container(raw: ContainerBookingResource): ContainerBookingResource {
|
||||
version: numberValue(raw.version),
|
||||
capacityCbm: raw.capacityCbm == null ? null : numberValue(raw.capacityCbm),
|
||||
maxWeightKg: raw.maxWeightKg == null ? null : numberValue(raw.maxWeightKg),
|
||||
clearanceDocument: document(raw.clearanceDocument),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +95,39 @@ export async function getContainer(containerId: string) {
|
||||
return container(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export async function getContainerOverview(containerId: string) {
|
||||
const response = await http.get<ApiEnvelope<ContainerOverview>, ApiEnvelope<ContainerOverview>>(`${containerPath}/${encodeURIComponent(containerId)}/overview`)
|
||||
return overview(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export async function markContainerException(containerId: string, expectedVersion: number, reason: string) {
|
||||
const response = await http.post<ApiEnvelope<null>, ApiEnvelope<null>>(`${containerPath}/${encodeURIComponent(containerId)}/exception`, { expectedVersion, reason }, { headers: { 'Idempotency-Key': operationId('container-exception-mark') } })
|
||||
unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function cancelContainerException(containerId: string, expectedVersion: number, reason: string) {
|
||||
const response = await http.delete<ApiEnvelope<null>, ApiEnvelope<null>>(`${containerPath}/${encodeURIComponent(containerId)}/exception`, { data: { expectedVersion, reason }, headers: { 'Idempotency-Key': operationId('container-exception-cancel') } })
|
||||
unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function uploadContainerDocument(containerId: string, documentType: Extract<ContainerDocumentType, 'DELIVERY_ORDER' | 'PICKUP_ORDER'>, file: File, expectedVersion: number, operationReason?: string | null) {
|
||||
const body = new FormData()
|
||||
body.append('file', file)
|
||||
body.append('expectedVersion', String(expectedVersion))
|
||||
if (operationReason) body.append('operationReason', operationReason)
|
||||
const response = await http.post<ApiEnvelope<BusinessDocument>, ApiEnvelope<BusinessDocument>>(`${containerPath}/${encodeURIComponent(containerId)}/documents/${documentType}/upload`, body, { headers: { 'Content-Type': 'multipart/form-data', 'Idempotency-Key': operationId(`container-${documentType.toLowerCase()}-upload`) } })
|
||||
return document(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export function downloadContainerDocument(containerId: string, documentType: Extract<ContainerDocumentType, 'DELIVERY_ORDER' | 'PICKUP_ORDER'>, fileId: string) {
|
||||
return http.get<Blob, Blob>(`${containerPath}/${encodeURIComponent(containerId)}/documents/${documentType}/${encodeURIComponent(fileId)}/download`, { responseType: 'blob' })
|
||||
}
|
||||
|
||||
export function downloadContainerPdaPhoto(downloadPath: string) {
|
||||
if (!downloadPath.startsWith('/api/platform/v1/files/loading-evidence/')) throw new Error('invalid container photo path')
|
||||
return http.get<Blob, Blob>(downloadPath, { responseType: 'blob' })
|
||||
}
|
||||
|
||||
export async function createContainer(payload: ContainerSaveRequest) {
|
||||
const response = await http.post<ApiEnvelope<ContainerBookingResource>, ApiEnvelope<ContainerBookingResource>>(containerPath, payload)
|
||||
return container(unwrapApiResponse(response))
|
||||
@@ -76,6 +143,25 @@ export async function updateContainerTransport(containerId: string, version: num
|
||||
return container(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export async function getContainerClearance(containerId: string) {
|
||||
const response = await http.get<ApiEnvelope<BusinessDocument | null>, ApiEnvelope<BusinessDocument | null>>(`${containerPath}/${encodeURIComponent(containerId)}/clearance`)
|
||||
return document(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export async function uploadContainerClearance(containerId: string, file: File, expectedVersion: number, operationReason?: string | null) {
|
||||
const body = new FormData()
|
||||
body.append('file', file)
|
||||
body.append('expectedVersion', String(expectedVersion))
|
||||
if (operationReason) body.append('operationReason', operationReason)
|
||||
const response = await http.post<ApiEnvelope<BusinessDocument>, ApiEnvelope<BusinessDocument>>(`${containerPath}/${encodeURIComponent(containerId)}/clearance/document/upload`, body, { headers: { 'Content-Type': 'multipart/form-data', 'Idempotency-Key': operationId('container-clearance-upload') } })
|
||||
return document(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export async function completeContainerClearance(containerId: string, expectedVersion: number, operationReason?: string | null) {
|
||||
const response = await http.post<ApiEnvelope<BusinessDocument>, ApiEnvelope<BusinessDocument>>(`${containerPath}/${encodeURIComponent(containerId)}/clearance/complete`, { expectedVersion, operationReason }, { headers: { 'Idempotency-Key': operationId('container-clearance-complete') } })
|
||||
return document(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export async function listSmartLoadingCandidates(bookingId: string, warehouseId: string) {
|
||||
const response = await http.get<ApiEnvelope<SmartLoadingCandidate[]>, ApiEnvelope<SmartLoadingCandidate[]>>(`${smartLoadingPath}/candidates`, { params: { bookingId, warehouseId } })
|
||||
return unwrapApiResponse(response).map((raw) => ({
|
||||
|
||||
Reference in New Issue
Block a user