From 6df6f6dabc4f48913eed43b2fff893fbc4e718c8 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sat, 3 Oct 2026 20:37:03 +0800 Subject: [PATCH] fix(fleet): refresh negotiated price controls when reopening booking --- .../components/TripBookingPanel.test.ts | 24 ++++++++++++++++--- .../components/TripBookingPanel.vue | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/modules/overseas-master-data/components/TripBookingPanel.test.ts b/src/modules/overseas-master-data/components/TripBookingPanel.test.ts index 521ad9f4..e96efd5f 100644 --- a/src/modules/overseas-master-data/components/TripBookingPanel.test.ts +++ b/src/modules/overseas-master-data/components/TripBookingPanel.test.ts @@ -4,6 +4,7 @@ import TripBookingPanel from './TripBookingPanel.vue' import * as api from '../api/tripBookings' import type { FleetTrip } from '../tripTypes' import type { TripBooking } from '../bookingTypes' +import type { Component } from 'vue' const access = vi.hoisted(() => ({ writable: true, quote: true })) vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: (permission: string) => permission === 'platform:fleet:quote:list' ? access.quote : access.writable }) })) vi.mock('element-plus', () => ({ ElMessage: { success: vi.fn(), warning: vi.fn() }, ElMessageBox: { confirm: vi.fn().mockResolvedValue(undefined) } })) @@ -12,14 +13,14 @@ const row: TripBooking = { bookingNo: 'FB-1', tripNo: 'TR-1', customerId: '9', c cargo: { destinationKey: 'FBA:ONT8', cargoName: null, packageCount: 10, palletSpaces: 2, weightKg: 100, volumeCbm: 1, priceBasis: 'PALLET', unitPrice: 50, currency: 'USD', contactName: null, contactPhone: null, remark: null } } const trip = { tripNo: 'TR-1', status: 'PLANNED', recordVersion: 4, stops: [{ name: '起点' }, { name: 'ONT8', destinationKey: 'FBA:ONT8' }] } as FleetTrip const wrappers: VueWrapper[] = [] -function mount() { +function mount(realNumber?: Component, realInput?: Component) { const field = { props: ['modelValue'], emits: ['update:modelValue'], template: '' } const wrapper = shallowMount(TripBookingPanel, { props: { trip }, global: { stubs: { DataTable: { props: ['data'], template: '
' }, - AppDialog: { name: 'AppDialog', props: ['modelValue', 'showConfirm'], emits: ['confirm', 'update:modelValue'], template: '
' }, + AppDialog: { name: 'AppDialog', props: { modelValue: Boolean, showConfirm: Boolean, destroyOnClose: Boolean }, emits: ['confirm', 'update:modelValue'], template: realNumber ? '
' : '
' }, ElButton: { props: ['disabled'], template: '' }, ElForm: { template: '
' }, ElFormItem: { template: '
' }, - ElSelect: { ...field, name: 'ElSelect' }, ElInputNumber: { ...field, name: 'ElInputNumber' }, ElInput: field, ElOption: true, + ElSelect: { ...field, name: 'ElSelect' }, ElInputNumber: realNumber || { ...field, name: 'ElInputNumber' }, ElInput: realInput || field, ElOption: true, LoadErrorState: true, ApiErrorMeta: true, } } }); wrappers.push(wrapper); return wrapper } @@ -33,6 +34,23 @@ it('confirms using both current versions and updates the parent version without expect(wrapper.emitted('changed')?.[0]).toEqual([5]); expect(api.listTripBookings).toHaveBeenCalledOnce() expect(wrapper.findAll('button').some(node => node.text() === '确认承运')).toBe(false) }) +it('reopens saved negotiated price in a fresh numeric control while retaining its separate quote source', async () => { + const { ElInputNumber, ElInput } = await vi.importActual('element-plus') + const initial = { ...row, cargo: { ...row.cargo, unitPrice: 16 }, quoteSource: { ...source, quotedUnitPrice: 16 } } + const saved = { ...initial, cargo: { ...initial.cargo, unitPrice: 9 }, agreedAmount: 18, recordVersion: 1 } + vi.mocked(api.listTripBookings).mockResolvedValue({ tripRecordVersion: 4, records: [initial] }) + vi.mocked(api.updateTripBooking).mockResolvedValue({ tripRecordVersion: 5, booking: saved, replayed: false }) + const wrapper = mount(ElInputNumber, ElInput); await flushPromises() + await button(wrapper, '编辑').trigger('click'); await flushPromises() + const price = wrapper.findAllComponents({ name: 'ElInputNumber' })[4]! + await price.find('input').setValue('9'); await flushPromises() + wrapper.findComponent({ name: 'AppDialog' }).vm.$emit('confirm'); await flushPromises() + expect(wrapper.findAllComponents({ name: 'ElInputNumber' })).toHaveLength(0) + await button(wrapper, '详情').trigger('click'); await flushPromises() + expect(wrapper.findAllComponents({ name: 'ElInputNumber' })[4]!.find('input').element.value).toBe('9.00') + expect(wrapper.text()).toContain('来源单价:16.00 USD') + expect(wrapper.text()).toContain('约定运费:18.00 USD') +}) it('keeps inquiry estimates and contacts optional and retries the same uncertain create command', async () => { vi.mocked(api.createTripBooking).mockRejectedValueOnce(new Error('network')).mockResolvedValueOnce({ tripRecordVersion: 5, booking: row, replayed: true }) const wrapper = mount(); await flushPromises(); await button(wrapper, '登记外接询价').trigger('click'); await flushPromises() diff --git a/src/modules/overseas-master-data/components/TripBookingPanel.vue b/src/modules/overseas-master-data/components/TripBookingPanel.vue index cd9a48b4..bc17e4e5 100644 --- a/src/modules/overseas-master-data/components/TripBookingPanel.vue +++ b/src/modules/overseas-master-data/components/TripBookingPanel.vue @@ -151,7 +151,7 @@ onBeforeUnmount(() => { generation++; searchSequence++; quoteSequence++; clearTi - +