feat(admin): simplify truck payable currency
This commit is contained in:
@@ -10,6 +10,8 @@ describe('TruckAppointmentCreateView booking-bound creation contract', () => {
|
||||
expect(source).not.toContain('customerId')
|
||||
expect(source).toContain('oceanBookingId: null, containerBookingId: null, loadingPlanId: null')
|
||||
expect(source).toContain('plannedLoadingAt: null')
|
||||
expect(source).toContain("payableAmount: '0.00', currency: 'RMB'")
|
||||
expect(source).not.toContain('receivableAmount')
|
||||
expect(source).toContain('createTruckAppointment({ ...form })')
|
||||
})
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import TruckAttachmentDialog from '../components/TruckAttachmentDialog.vue'
|
||||
import { createTruckAppointment } from '../api/platformTrucking'
|
||||
import type { SaveTruckAppointmentRequest } from '../types'
|
||||
const router = useRouter(); const saving = ref(false); const attachmentOpen = ref(false); const error = ref<ApiErrorDetails | null>(null)
|
||||
const form = reactive<SaveTruckAppointmentRequest>({ expectedVersion: 0, carrierId: null, oceanBookingId: null, containerBookingId: null, loadingPlanId: null, plannedLoadingAt: null, payableAmount: '0.00', receivableAmount: '0.00', currency: 'RMB' })
|
||||
const form = reactive<SaveTruckAppointmentRequest>({ expectedVersion: 0, carrierId: null, oceanBookingId: null, containerBookingId: null, loadingPlanId: null, plannedLoadingAt: null, payableAmount: '0.00', currency: 'RMB' })
|
||||
async function submit() { if (saving.value) return; saving.value = true; error.value = null; try { await createTruckAppointment({ ...form }); ElMessage.success('拖车预约已创建'); router.push({ name: 'trucking' }) } catch (err) { error.value = getApiErrorDetails(err, '创建失败,请稍后重试') } finally { saving.value = false } }
|
||||
</script>
|
||||
<template>
|
||||
|
||||
@@ -36,6 +36,7 @@ describe('TruckAppointmentDetailView status contract', () => {
|
||||
expect(source).toContain("carrierId: null, oceanBookingId: null, containerBookingId: null, plannedLoadingAt: null")
|
||||
expect(source).not.toContain('customerId')
|
||||
expect(source).toContain('TRUCK_APPOINTMENT_SAVE_FIELDS.map')
|
||||
expect(source).toContain('normalizeTruckAppointmentCurrency(result.currency)')
|
||||
expect(source).not.toContain('Object.assign(form, { ...result')
|
||||
expect(source).toContain("error.value = getApiErrorDetails(err, '保存失败,请稍后重试')")
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@ import { getOceanBooking, type OceanBookingDetail } from '@/modules/ocean-bookin
|
||||
import { getTruckAppointment, listTruckAppointmentAttachments, listTruckAppointmentHistory, performTruckAppointmentAction, rescheduleTruckAppointment, updateTruckAppointment, type TruckAppointmentAction } from '../api/platformTrucking'
|
||||
import TruckAppointmentForm from '../components/TruckAppointmentForm.vue'
|
||||
import TruckAttachmentDialog from '../components/TruckAttachmentDialog.vue'
|
||||
import { TRUCK_APPOINTMENT_SAVE_FIELDS, truckAppointmentActionLabel, truckAppointmentStatusLabel, truckAppointmentStatusLabels, type SaveTruckAppointmentRequest, type TruckAppointmentResource, type TruckAppointmentStatus, type TruckAppointmentStatusHistory } from '../types'
|
||||
import { TRUCK_APPOINTMENT_SAVE_FIELDS, normalizeTruckAppointmentCurrency, truckAppointmentActionLabel, truckAppointmentStatusLabel, truckAppointmentStatusLabels, type SaveTruckAppointmentRequest, type TruckAppointmentResource, type TruckAppointmentStatus, type TruckAppointmentStatusHistory } from '../types'
|
||||
import { isIso6346ContainerNumber } from '../iso6346'
|
||||
const route = useRoute(); const router = useRouter(); const loading = ref(false); const saving = ref(false); const statusSaving = ref(false); const attachmentOpen = ref(false); const resource = ref<TruckAppointmentResource | null>(null); const error = ref<ApiErrorDetails | null>(null); const form = reactive<SaveTruckAppointmentRequest>({ expectedVersion: 0, carrierId: null, oceanBookingId: null, containerBookingId: null, plannedLoadingAt: null })
|
||||
const history = ref<TruckAppointmentStatusHistory[]>([])
|
||||
@@ -35,7 +35,7 @@ async function loadRelated() {
|
||||
if (booking.status === 'fulfilled') bookingReadiness.value = booking.value
|
||||
if (attachments.status === 'rejected' || histories.status === 'rejected' || booking.status === 'rejected') relatedError.value = '附件、状态历史或订舱资料状态暂时未能加载,主详情数据不受影响;派车时仍由服务端最终校验。'
|
||||
}
|
||||
async function load() { loading.value = true; error.value = null; resource.value = null; bookingReadiness.value = null; history.value = []; relatedError.value = ''; try { const result = await getTruckAppointment(id.value); resource.value = result; const draft = Object.fromEntries(TRUCK_APPOINTMENT_SAVE_FIELDS.map((key) => [key, key === 'expectedVersion' ? result.version ?? 0 : result[key as keyof TruckAppointmentResource]])); Object.assign(form, draft); await loadRelated() } catch (err) { error.value = getApiErrorDetails(err, '详情加载失败,请稍后重试') } finally { loading.value = false } }
|
||||
async function load() { loading.value = true; error.value = null; resource.value = null; bookingReadiness.value = null; history.value = []; relatedError.value = ''; try { const result = await getTruckAppointment(id.value); resource.value = result; const draft = Object.fromEntries(TRUCK_APPOINTMENT_SAVE_FIELDS.map((key) => [key, key === 'expectedVersion' ? result.version ?? 0 : key === 'currency' ? normalizeTruckAppointmentCurrency(result.currency) : result[key as keyof TruckAppointmentResource]])); Object.assign(form, draft); await loadRelated() } catch (err) { error.value = getApiErrorDetails(err, '详情加载失败,请稍后重试') } finally { loading.value = false } }
|
||||
async function submit() { if (saving.value) return; saving.value = true; error.value = null; try { await updateTruckAppointment(id.value, form); ElMessage.success('拖车预约已保存'); await load() } catch (err) { error.value = getApiErrorDetails(err, '保存失败,请稍后重试') } finally { saving.value = false } }
|
||||
const actionByTarget: Partial<Record<TruckAppointmentStatus, TruckAppointmentAction>> = { PENDING_DISPATCH: 'SUBMIT', DISPATCHED: 'DISPATCH', PICKUP_IN_PROGRESS: 'PICKUP', ARRIVED_WAREHOUSE: 'ARRIVE', LOADING: 'LOAD', DEPARTED: 'DEPART', COMPLETED: 'COMPLETE', EXCEPTION: 'EXCEPTION', CANCELLED: 'CANCEL' }
|
||||
const primaryTargetByStatus: Partial<Record<TruckAppointmentStatus, TruckAppointmentStatus>> = { DRAFT: 'PENDING_DISPATCH', PENDING_DISPATCH: 'DISPATCHED', RESCHEDULED: 'DISPATCHED', DISPATCHED: 'PICKUP_IN_PROGRESS', PICKUP_IN_PROGRESS: 'ARRIVED_WAREHOUSE', ARRIVED_WAREHOUSE: 'LOADING', LOADING: 'DEPARTED', DEPARTED: 'COMPLETED' }
|
||||
|
||||
@@ -21,7 +21,7 @@ vi.mock('@/modules/iam', () => ({
|
||||
const row: TruckAppointmentResource = {
|
||||
id: '9001', appointmentNo: 'TA-9001', status: 'DISPATCHED', orderNo: 'ORD-1', oceanBookingNo: 'OB-1', containerBookingId: '77', cabinetNo: 'CAB-1',
|
||||
containerNo: 'CONT-1', warehouseName: '义乌仓', shippingCompanyName: '船公司A', bookingAgentName: '代理A', carrierName: '宁波运输', driverName: '王强', vehicleNo: '浙B12345',
|
||||
plannedLoadingAt: '2026-08-10T10:00:00', payableAmount: '3200.00', receivableAmount: '3800.00', attachmentCount: 2, attachments: [],
|
||||
plannedLoadingAt: '2026-08-10T10:00:00', payableAmount: '3200.00', currency: 'RMB', attachmentCount: 2, attachments: [],
|
||||
}
|
||||
|
||||
describe('TruckAppointmentsView', () => {
|
||||
@@ -125,10 +125,10 @@ describe('TruckAppointmentsView', () => {
|
||||
expect(source).not.toContain("key: 'customerName'")
|
||||
expect(source).toContain("key: 'updatedAt'")
|
||||
expect(source).toContain("key: 'payableAmount', label: '应付拖车费'")
|
||||
expect(source).toContain("key: 'receivableAmount', label: '应收拖车费'")
|
||||
expect(source.indexOf("key: 'store'")).toBeLessThan(source.indexOf("key: 'payableAmount'"))
|
||||
expect(source.indexOf("key: 'payableAmount'")).toBeLessThan(source.indexOf("key: 'receivableAmount'"))
|
||||
expect(source.indexOf("key: 'receivableAmount'")).toBeLessThan(source.indexOf("key: 'plannedLoadingAt'"))
|
||||
expect(source.indexOf("key: 'payableAmount'")).toBeLessThan(source.indexOf("key: 'plannedLoadingAt'"))
|
||||
expect(source).not.toContain('receivableAmount')
|
||||
expect(source).not.toContain('应收拖车费')
|
||||
expect(source).toContain("toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })")
|
||||
expect(source).toContain("key: 'attachmentCount'")
|
||||
})
|
||||
|
||||
@@ -38,7 +38,6 @@ const columns: DataTableColumn[] = [
|
||||
{ key: 'vehicleNo', prop: 'vehicleNo', label: '车头号', minWidth: 120, formatter: (row: TruckAppointmentResource) => row.vehicleNo || '—' },
|
||||
{ key: 'store', label: '门店', minWidth: 140, slotName: 'store' },
|
||||
{ key: 'payableAmount', label: '应付拖车费', minWidth: 130, align: 'right', formatter: (row: TruckAppointmentResource) => formatAmount(row.payableAmount, row.currency) },
|
||||
{ key: 'receivableAmount', label: '应收拖车费', minWidth: 130, align: 'right', formatter: (row: TruckAppointmentResource) => formatAmount(row.receivableAmount, row.currency) },
|
||||
{ key: 'plannedLoadingAt', label: '预计装箱日期', minWidth: 170, formatter: (row: TruckAppointmentResource) => formatDateTime(row.plannedLoadingAt) },
|
||||
{ key: 'status', label: '状态', width: 130, slotName: 'status' },
|
||||
{ key: 'attachmentCount', label: '附件', width: 90, align: 'right', formatter: (row: TruckAppointmentResource) => String(Number(row.attachmentCount ?? 0)) },
|
||||
|
||||
Reference in New Issue
Block a user