fix(admin): stabilize released booking association

This commit is contained in:
2026-08-25 20:18:59 +08:00
parent c3ea54dcd4
commit 10ff84497f
6 changed files with 63 additions and 22 deletions
@@ -11,6 +11,7 @@ import { listPlatformPartners } from '@/modules/master-data'
import { listSuppliers } from '@/modules/suppliers'
import { getOceanBooking, listOceanBookingLinkCandidates, listOceanBookings } from '@/modules/ocean-bookings'
import { getContainer, getContainerOverview, listContainers, updateContainer } from '../api/platformContainerLoading'
import AppDialog from '@/shared/components/AppDialog.vue'
vi.mock('@/modules/warehouses', () => ({ listAllPlatformWarehouses: vi.fn() }))
vi.mock('@/modules/master-data', () => ({ listPlatformPartners: vi.fn() }))
@@ -265,8 +266,14 @@ describe('ContainersView', () => {
expect(source).not.toContain('v-model="form.maxWeightKg"')
})
it('loads one frozen candidate page per open and ignores repeated clicks while it is pending', async () => {
it('keeps OB-260825-0183 selectable for CAB-260825-0215 when only capacity snapshots differ and blocks duplicate waves', async () => {
let resolveCandidates!: (value: Awaited<ReturnType<typeof listOceanBookingLinkCandidates>>) => void
vi.mocked(listContainers).mockResolvedValue({ records: [{
id: '215', planId: null, bookingNo: 'CB-260825-0215', cabinetNo: 'CAB-260825-0215', containerNo: null,
sourceType: 'SIMULATION', oceanBookingId: null, warehouseId: '8', warehouseName: '义乌仓',
channelCode: 'ZBYHK', channelName: '美森正班海卡包税', containerType: '45HC', planStatus: 'WAIT_LOADING',
capacityCbm: 86, maxWeightKg: 29000, version: 7,
}], page: 1, size: 20, total: 1, pages: 1 } as never)
vi.mocked(listOceanBookingLinkCandidates).mockReturnValueOnce(new Promise((resolve) => { resolveCandidates = resolve }))
const router = createTestRouter()
await router.push('/'); await router.isReady()
@@ -275,17 +282,20 @@ describe('ContainersView', () => {
await wrapper.find('button[aria-label="更多货柜操作"]').trigger('click')
await flushPromises()
const linkAction = Array.from(document.body.querySelectorAll<HTMLElement>('.el-dropdown-menu__item'))
.find((item) => item.textContent?.includes('关联已放舱订舱'))!
.filter((item) => item.textContent?.includes('关联已放舱订舱')).at(-1)!
linkAction.click()
linkAction.click()
expect(listOceanBookingLinkCandidates).toHaveBeenCalledTimes(1)
expect(listOceanBookingLinkCandidates).toHaveBeenCalledWith({ warehouseId: '8', channelCode: 'ZBYHK', containerType: '40HC', capacityCbm: 76, maxWeightKg: 28000, page: 1, size: 200 })
expect(listOceanBookingLinkCandidates).toHaveBeenCalledWith({ warehouseId: '8', channelCode: 'ZBYHK', containerType: '45HC', page: 1, size: 200 })
expect(getOceanBooking).not.toHaveBeenCalled()
resolveCandidates({ records: [{ oceanBookingId: '101', bookingNo: 'OB-1', requirementId: '202', containerType: '40HC', capacityCbm: 76, maxWeightKg: 28000, requiredQuantity: 2, allocatedQuantity: 1, remainingQuantity: 1, customerName: '客户', warehouseName: '义乌仓', channelName: '美森正班海卡包税' }], page: 1, size: 200, total: 1, pages: 1 })
expect(readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/ContainersView.vue'), 'utf8'))
.toContain('暂无符合当前装柜仓库、物流渠道和柜型的已放舱需求')
resolveCandidates({ records: [{ oceanBookingId: '183', bookingNo: 'OB-260825-0183', requirementId: '45183', containerType: '45HC', capacityCbm: 85, maxWeightKg: 28500, requiredQuantity: 2, allocatedQuantity: 1, remainingQuantity: 1, customerName: '客户', warehouseName: '义乌仓', channelName: '美森正班海卡包税' }], page: 1, size: 200, total: 1, pages: 1 })
await flushPromises()
expect(document.body.textContent).toContain('OB-1 · 40HC × 1')
expect(document.body.textContent).toContain('OB-260825-0183 · 45HC × 1')
expect((wrapper.vm as unknown as { linkCandidates: Array<{ disabled: boolean }> }).linkCandidates[0]?.disabled).toBe(false)
wrapper.unmount()
})
@@ -303,10 +313,10 @@ describe('ContainersView', () => {
await wrapper.find('button[aria-label="更多货柜操作"]').trigger('click')
await flushPromises()
Array.from(document.body.querySelectorAll<HTMLElement>('.el-dropdown-menu__item'))
.find((item) => item.textContent?.includes('关联已放舱订舱'))!.click()
.filter((item) => item.textContent?.includes('关联已放舱订舱')).at(-1)!.click()
await flushPromises()
Array.from(document.body.querySelectorAll<HTMLButtonElement>('button'))
.find((button) => button.textContent?.trim() === '取消')!.click()
wrapper.findAllComponents(AppDialog)
.find((dialog) => dialog.props('title') === '关联已放舱订舱')!.vm.$emit('update:modelValue', false)
await flushPromises()
await wrapper.find('button[aria-label="更多货柜操作"]').trigger('click')
@@ -319,8 +329,9 @@ describe('ContainersView', () => {
await flushPromises()
expect(listOceanBookingLinkCandidates).toHaveBeenCalledTimes(2)
expect(document.body.textContent).toContain('OB-LATEST')
expect(document.body.textContent).not.toContain('OB-STALE')
const candidateLabels = (wrapper.vm as unknown as { linkCandidates: Array<{ label: string }> }).linkCandidates.map((candidate) => candidate.label)
expect(candidateLabels.some((label) => label.includes('OB-LATEST'))).toBe(true)
expect(candidateLabels.some((label) => label.includes('OB-STALE'))).toBe(false)
wrapper.unmount()
})