feat(fleet): show vehicle delivery and reassignment records

This commit is contained in:
2026-10-03 10:12:55 +08:00
parent 94b8b8b31c
commit f7b84ea887
9 changed files with 209 additions and 6 deletions
@@ -0,0 +1,17 @@
import { beforeEach, expect, it, vi } from 'vitest'
import { http } from '@/shared/api/http'
import { listVehicleDeliveries, listVehicleAssignmentChanges } from './vehicleFulfillment'
vi.mock('@/shared/api/http', () => ({ http: { get: vi.fn() }, unwrapApiResponse: (value: {data: unknown}) => value.data }))
beforeEach(() => { vi.clearAllMocks() })
it('encodes the stable vehicle key and adapts serialized pagination without a plate or customer override', async () => {
vi.mocked(http.get).mockResolvedValue({ data: { records: [{ deliveryNo: 'DL-1' }], page: '1', size: '10', total: '1', pages: '1' } })
const result=await listVehicleDeliveries('900719925474099301')
expect(http.get).toHaveBeenCalledExactlyOnceWith('/platform/v1/last-leg/fleet/vehicles/900719925474099301/deliveries', { params: { page: 1, size: 10 } })
expect(result.total).toBe(1)
})
it('history preserves large serialized versions and rejects invalid pagination', async () => {
vi.mocked(http.get).mockResolvedValue({ data: { records: [{ tripNo:'TR-1', recordVersion:'900719925474099301' }], page:'1',size:'10',total:'1',pages:'1' } })
expect((await listVehicleAssignmentChanges('8')).records[0]?.recordVersion).toBe('900719925474099301')
vi.mocked(http.get).mockResolvedValue({ data: { records: [], page:'1',size:'10',total:'not-a-number',pages:'1' } })
await expect(listVehicleAssignmentChanges('8')).rejects.toThrow('分页数值')
})
@@ -0,0 +1,33 @@
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
import type { PageResult } from './overseasMasterData'
export interface VehicleDelivery {
deliveryNo: string; dispatchNo: string; tripNo: string; bolNo: string | null; customerName: string | null
destinationType: string; destinationWarehouseCode: string | null; destinationWarehouseName: string | null
deliveryAddress: string | null; plannedDeliveryAt: string | null; status: string; relationship: 'PLANNED' | 'DEPARTED'
}
export interface VehicleAssignmentChange {
tripNo: string; recordVersion: string; occurredAt: string; reason: string | null
previousVehiclePlate: string | null; vehiclePlate: string | null; previousDriverName: string | null; driverName: string | null
relationship: 'REPLACED_OUT' | 'REPLACED_IN' | 'DRIVER_CHANGED'; dispatchNos: string[]
}
type Numeric = string | number
type WirePage<T> = { records: T[]; page: Numeric; size: Numeric; total: Numeric; pages: Numeric }
type WireChange = Omit<VehicleAssignmentChange, 'recordVersion'> & { recordVersion: Numeric }
function integer(value: Numeric) {
const number = Number(value)
if (value == null || value === '' || !Number.isSafeInteger(number) || number < 0) throw new Error('车辆履约接口返回无效分页数值')
return number
}
function page<T, W>(value: WirePage<W>, normalize: (row: W) => T): PageResult<T> {
return { records: value.records.map(normalize), page: integer(value.page), size: integer(value.size), total: integer(value.total), pages: integer(value.pages) }
}
const base = (vehicleId: string) => `/platform/v1/last-leg/fleet/vehicles/${encodeURIComponent(vehicleId)}`
export async function listVehicleDeliveries(vehicleId: string, currentPage = 1, size = 10) {
const result = unwrapApiResponse(await http.get<ApiEnvelope<WirePage<VehicleDelivery>>, ApiEnvelope<WirePage<VehicleDelivery>>>(`${base(vehicleId)}/deliveries`, { params: { page: currentPage, size } }))
return page(result, row => row)
}
export async function listVehicleAssignmentChanges(vehicleId: string, currentPage = 1, size = 10) {
const result = unwrapApiResponse(await http.get<ApiEnvelope<WirePage<WireChange>>, ApiEnvelope<WirePage<WireChange>>>(`${base(vehicleId)}/assignment-history`, { params: { page: currentPage, size } }))
return page(result, row => ({ ...row, recordVersion: String(row.recordVersion) }))
}