优化
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { http } from '@/shared/api/http'
|
||||
import { changeTruckAppointmentStatus, createTruckAppointment, getTruckAppointment, listTruckAppointments } from './platformTrucking'
|
||||
import { createTruckAppointment, getTruckAppointment, listTruckAppointments, performTruckAppointmentAction } from './platformTrucking'
|
||||
|
||||
vi.mock('@/shared/api/http', () => ({ http: { get: vi.fn(), post: vi.fn(), put: vi.fn(), patch: vi.fn() }, unwrapApiResponse: (response: { data: unknown }) => response.data }))
|
||||
|
||||
@@ -9,17 +9,17 @@ describe('truck appointment API', () => {
|
||||
|
||||
it('normalizes page values and maps filters', async () => {
|
||||
vi.mocked(http.get).mockResolvedValue({ data: { records: [], page: '2', size: '20', total: '21', pages: '2' } })
|
||||
await expect(listTruckAppointments({ page: 2, size: 20, keyword: ' BY ', status: 'DISPATCHED', containerType: '40HC' })).resolves.toMatchObject({ page: 2, total: 21, pages: 2 })
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/truck-appointments', { params: { page: 2, size: 20, keyword: 'BY', status: 'DISPATCHED', containerType: '40HC' } })
|
||||
await expect(listTruckAppointments({ page: 2, size: 20, keyword: ' BY ', status: 'DISPATCHED', containerBookingId: '77' })).resolves.toMatchObject({ page: 2, total: 21, pages: 2 })
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/truck-appointments', { params: { page: 2, size: 20, keyword: 'BY', status: 'DISPATCHED', containerBookingId: '77' } })
|
||||
})
|
||||
|
||||
it('uses detail, create, and status contracts', async () => {
|
||||
vi.mocked(http.get).mockResolvedValue({ data: { id: '9001', status: 'DRAFT' } })
|
||||
vi.mocked(http.post).mockResolvedValue({ data: '9001' })
|
||||
vi.mocked(http.patch).mockResolvedValue({ data: null })
|
||||
vi.mocked(http.post).mockResolvedValue({ data: { id: '9001', status: 'DISPATCHED' } })
|
||||
await expect(getTruckAppointment('9001')).resolves.toMatchObject({ id: '9001' })
|
||||
await expect(createTruckAppointment({ expectedLoadingDate: '2026-08-10' })).resolves.toBe('9001')
|
||||
await expect(changeTruckAppointmentStatus('9001', 'DISPATCHED')).resolves.toBeNull()
|
||||
expect(http.patch).toHaveBeenCalledWith('/platform/v1/truck-appointments/9001/status', { status: 'DISPATCHED' })
|
||||
await expect(createTruckAppointment({ plannedLoadingAt: '2026-08-10T10:00:00', expectedVersion: 0 })).resolves.toMatchObject({ id: '9001' })
|
||||
await expect(performTruckAppointmentAction('9001', 'DISPATCH', 2)).resolves.toMatchObject({ status: 'DISPATCHED' })
|
||||
expect(http.post).toHaveBeenCalledWith('/platform/v1/truck-appointments/9001/dispatch', { expectedVersion: 2, reason: null }, { headers: {} })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -11,7 +11,6 @@ watch(() => props.modelValue, (value) => Object.assign(draft, value), { deep: tr
|
||||
watch(draft, (value) => emit('update:modelValue', { ...value }), { deep: true })
|
||||
const rules: FormRules = {
|
||||
plannedLoadingAt: [{ required: true, message: '请选择预计装箱时间', trigger: 'change' }],
|
||||
carrierId: [{ required: true, message: '请输入承运商 ID', trigger: 'blur' }],
|
||||
}
|
||||
const relationText = computed(() => [props.resource?.customerName, props.resource?.outboundOrderId, props.resource?.containerBookingId].filter(Boolean).join(' / ') || '由服务端关联资源返回')
|
||||
async function validate() { return formRef.value?.validate() }
|
||||
|
||||
@@ -11,7 +11,7 @@ import { getTruckAppointment, performTruckAppointmentAction, rescheduleTruckAppo
|
||||
import TruckAppointmentForm from '../components/TruckAppointmentForm.vue'
|
||||
import TruckAttachmentDialog from '../components/TruckAttachmentDialog.vue'
|
||||
import { TRUCK_APPOINTMENT_STATUSES, truckAppointmentStatusLabels, type SaveTruckAppointmentRequest, type TruckAppointmentResource, type TruckAppointmentStatus, type TruckAttachmentReference } from '../types'
|
||||
const route = useRoute(); const router = useRouter(); const open = ref(true); 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>({})
|
||||
const route = useRoute(); const router = useRouter(); const open = ref(true); 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 })
|
||||
const access = useAccessPreviewStore(); const editing = computed(() => route.query.edit === '1'); const id = computed(() => String(route.params.id)); const canEdit = computed(() => access.can('platform:firstleg:truck-appointment:edit') && !['COMPLETED','CANCELLED'].includes(resource.value?.status || '') && editing.value); const canChangeStatus = computed(() => access.can('platform:firstleg:truck-appointment:operate'))
|
||||
async function load() { loading.value = true; error.value = null; try { const result = await getTruckAppointment(id.value); resource.value = result; Object.assign(form, { ...result, expectedVersion: result.version ?? 0, attachmentRefs: result.attachments || [] }) } catch (err) { error.value = getApiErrorDetails(err, '详情加载失败,请稍后重试') } finally { loading.value = false } }
|
||||
async function submit() { 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 } }
|
||||
|
||||
@@ -8,13 +8,12 @@ import type { TruckAppointmentResource } from '../types'
|
||||
|
||||
vi.mock('../api/platformTrucking', () => ({
|
||||
listTruckAppointments: vi.fn(),
|
||||
exportTruckAppointments: vi.fn(),
|
||||
}))
|
||||
|
||||
const row: TruckAppointmentResource = {
|
||||
id: '9001', appointmentNo: 'TA-9001', status: 'DISPATCHED', customerName: '示例企业', orderNo: 'ORD-1',
|
||||
containerNo: 'CONT-1', containerType: '40HC', transportCompanyName: '宁波运输', driverName: '王强', tractorNo: '浙B12345',
|
||||
expectedLoadingDate: '2026-08-10', payableAmount: '3200.00', receivableAmount: '3800.00', attachments: [],
|
||||
id: '9001', appointmentNo: 'TA-9001', status: 'DISPATCHED', customerName: '示例企业', orderNo: 'ORD-1', containerBookingId: '77',
|
||||
containerNo: 'CONT-1', carrierName: '宁波运输', driverName: '王强', vehicleNo: '浙B12345',
|
||||
plannedLoadingAt: '2026-08-10T10:00:00', payableAmount: '3200.00', receivableAmount: '3800.00', attachments: [],
|
||||
}
|
||||
|
||||
describe('TruckAppointmentsView', () => {
|
||||
@@ -26,9 +25,9 @@ describe('TruckAppointmentsView', () => {
|
||||
it('loads the real list and renders relationship snapshots', async () => {
|
||||
const wrapper = mount(TruckAppointmentsView, { global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
expect(listTruckAppointments).toHaveBeenCalledWith({ page: 1, size: 20, keyword: '', status: '', containerType: '' })
|
||||
expect(listTruckAppointments).toHaveBeenCalledWith({ page: 1, size: 20, keyword: '', status: '', containerBookingId: '' })
|
||||
expect(wrapper.text()).toContain('TA-9001')
|
||||
expect(wrapper.text()).toContain('40HC')
|
||||
expect(wrapper.text()).toContain('柜体 77')
|
||||
expect(wrapper.text()).toContain('宁波运输')
|
||||
expect(wrapper.find('button[aria-label="查看 TA-9001"]').exists()).toBe(true)
|
||||
})
|
||||
|
||||
@@ -62,6 +62,7 @@ export interface TruckAppointmentResource {
|
||||
storeCity?: string | null
|
||||
storeZipcode?: string | null
|
||||
plannedLoadingAt?: string | null
|
||||
actualLoadingAt?: string | null
|
||||
transitMinutes?: number | string | null
|
||||
packageCount?: number | string | null
|
||||
grossWeightKg?: string | null
|
||||
|
||||
Reference in New Issue
Block a user