fix: align fleet controls and protect appointment retries

This commit is contained in:
2026-10-11 13:07:52 +08:00
parent 1edb65df77
commit d77abbef7c
13 changed files with 262 additions and 36 deletions
@@ -1,6 +1,9 @@
import { ElTable, ElTableColumn } from 'element-plus/es/components/table/index'
import { ElInputNumber } from 'element-plus/es/components/input-number/index'
import { ElInput } from 'element-plus/es/components/input/index'
import { createPinia } from 'pinia'
import { afterEach, beforeEach, expect, it, vi } from 'vitest'
import { shallowMount, flushPromises, type VueWrapper } from '@vue/test-utils'
import { mount as mountFull, shallowMount, flushPromises, type VueWrapper } from '@vue/test-utils'
import TripBookingFulfillmentDialog from './TripBookingFulfillmentDialog.vue'
import * as api from '../api/tripBookings'
import type { FleetTrip } from '../tripTypes'
@@ -73,3 +76,40 @@ it.each([
expect(api.acceptTripIncoming).not.toHaveBeenCalled()
expect(api.bindTripBookingDispatch).not.toHaveBeenCalled()
})
it('anchors receipt control sizing inside the real DataTable slot and disables cell ellipsis', async () => {
const wrapper = mountFull(TripBookingFulfillmentDialog, {
props: { modelValue: true, trip, booking, mode: 'receipt' },
global: { plugins: [createPinia()], components: { ElTable, ElTableColumn, ElInputNumber, ElInput }, directives: { loading: () => undefined }, stubs: {
ElForm: { template: '<div><slot/></div>' }, ElFormItem: { template: '<div><slot/></div>' }, ElButton: { template: '<button><slot/></button>' },
AppDialog: { template: '<div><slot/></div>' }, LoadErrorState: true, ApiErrorMeta: true,
} },
})
wrappers.push(wrapper); await flushPromises()
const control = wrapper.get('.el-table__body .receipt-spaces-control')
const scope = control.element.getAttributeNames().find(name => name.startsWith('data-v-'))
expect(scope).toBeDefined()
expect(control.find('.el-input-number').exists()).toBe(true)
expect(control.element.closest('td')?.classList.contains('data-table__single-line-cell')).toBe(false)
expect(control.element.closest('.cell')?.classList.contains('el-tooltip')).toBe(false)
// DataTable forwards classes to its inner table, which does not carry this SFC's scope.
expect(wrapper.find(`.receipt-pallet-table[${scope}]`).exists()).toBe(false)
const input = control.get('input')
await input.setValue('2'); await input.trigger('change'); await flushPromises()
expect(wrapper.text()).toContain('2 托位')
})
it('compares real receipt with the forecast, preserves unknown values, and does not invent historical forecasts', async () => {
const wrapper = mount('receipt'); await flushPromises()
const rows = () => wrapper.get('[aria-label="预报与实收对照"]').findAll('tbody tr').map(row => row.findAll('td').map(cell => cell.text()))
expect(rows()).toEqual([
['箱数', '20', '22', '+2'], ['实托数', '—', '1', '—'], ['标准托位(待核对)', '2', '1', '-1'],
['重量(kg)', '100', '150', '+50'], ['体积(m³)', '1', '1.5', '+0.5'],
])
await wrapper.setProps({ booking: { ...booking, status: 'RECEIVED' } })
expect(rows().every(row => row[1] === '—' && row[3] === '—')).toBe(true)
expect(wrapper.text()).toContain('无法还原原始预报')
await wrapper.setProps({ mode: 'view' }); await flushPromises()
expect(wrapper.find('[aria-label="预报与实收对照"]').exists()).toBe(false)
expect(api.acceptTripIncoming).not.toHaveBeenCalled()
})