优化
This commit is contained in:
@@ -175,7 +175,7 @@ describe('ContainersView', () => {
|
||||
expect(getTerminalDrayage).not.toHaveBeenCalled()
|
||||
if (missing === 'historical unloaded snapshot') {
|
||||
const fleet = wrapper.findAllComponents({ name: 'ElSelect' }).find((select) =>
|
||||
select.props('placeholder') === '请选择车队' && select.element.closest('.el-table__body'),
|
||||
select.props('placeholder') === '输入车队名称或联系人搜索' && select.element.closest('.el-table__body'),
|
||||
)
|
||||
expect(fleet).toBeDefined()
|
||||
expect(fleet!.props('disabled')).toBe(false)
|
||||
@@ -469,6 +469,7 @@ describe('ContainersView', () => {
|
||||
|
||||
const vm = wrapper.vm as unknown as {
|
||||
rows: Array<Record<string, unknown>>
|
||||
searchTerminalFleets: (keyword?: string) => Promise<void>
|
||||
selectRowFleet: (row: Record<string, unknown>, supplierId: string) => Promise<void>
|
||||
openDrayageAction: (row: Record<string, unknown>, action: 'RECORD_EMPTY_RETURN') => void
|
||||
drayageActionAt: string
|
||||
@@ -476,6 +477,7 @@ describe('ContainersView', () => {
|
||||
}
|
||||
const beforeFleet = await listContainers({ page: 1, size: 20 }, 'OVERSEAS')
|
||||
vi.mocked(listContainers).mockResolvedValueOnce({ ...beforeFleet, records: beforeFleet.records.map((row) => ({ ...row, terminalDrayage: { ...drayage, version: 4, fleetSupplierId: '502', allowedActions: [...drayage.allowedActions] } })) })
|
||||
await vm.searchTerminalFleets('新车队')
|
||||
await vm.selectRowFleet(vm.rows[0], '502')
|
||||
expect(selectTerminalDrayageFleet).toHaveBeenCalledWith('9001', { expectedVersion: 3, fleetSupplierId: '502', fleetSupplierName: '新车队' })
|
||||
|
||||
@@ -489,6 +491,33 @@ describe('ContainersView', () => {
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('searches active terminal fleets remotely and ignores an older response', async () => {
|
||||
const router = createTestRouter()
|
||||
await router.push('/'); await router.isReady()
|
||||
const wrapper = mount(ContainersView, { props: { workbench: 'OVERSEAS' }, global: { plugins: [ElementPlus, router] } })
|
||||
await flushPromises()
|
||||
let resolveOld!: (value: Awaited<ReturnType<typeof listSuppliers>>) => void
|
||||
let resolveLatest!: (value: Awaited<ReturnType<typeof listSuppliers>>) => void
|
||||
vi.mocked(listSuppliers).mockReset()
|
||||
.mockReturnValueOnce(new Promise((resolve) => { resolveOld = resolve }))
|
||||
.mockReturnValueOnce(new Promise((resolve) => { resolveLatest = resolve }))
|
||||
const vm = wrapper.vm as unknown as {
|
||||
terminalFleetOptions: Array<{ id: string; name: string }>
|
||||
searchTerminalFleets: (keyword?: string) => Promise<void>
|
||||
}
|
||||
|
||||
const oldSearch = vm.searchTerminalFleets('旧关键词')
|
||||
const latestSearch = vm.searchTerminalFleets('新车队')
|
||||
expect(listSuppliers).toHaveBeenNthCalledWith(1, { page: 1, size: 20, category: 'TRUCKING', status: 'ACTIVE', keyword: '旧关键词' })
|
||||
expect(listSuppliers).toHaveBeenNthCalledWith(2, { page: 1, size: 20, category: 'TRUCKING', status: 'ACTIVE', keyword: '新车队' })
|
||||
resolveLatest({ records: [{ id: '503', name: '新车队', category: 'TRUCKING', status: 'ACTIVE' } as never], page: 1, size: 20, total: 1, pages: 1 })
|
||||
await latestSearch
|
||||
resolveOld({ records: [{ id: '502', name: '旧车队', category: 'TRUCKING', status: 'ACTIVE' } as never], page: 1, size: 20, total: 1, pages: 1 })
|
||||
await oldSearch
|
||||
expect(vm.terminalFleetOptions).toEqual([expect.objectContaining({ id: '503', name: '新车队' })])
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('loads terminal drayage detail and history only when requested', async () => {
|
||||
vi.mocked(getTerminalDrayageHistory).mockResolvedValueOnce([{ action: 'SELECT_FLEET', fromStatus: 'ARRIVED', toStatus: 'ARRIVED', fromVersion: 0, toVersion: 1, reason: '到港安排', operatorId: '88', operatorName: '管理员', createdAt: '2026-09-07T08:00:00' }])
|
||||
const router = createTestRouter()
|
||||
@@ -802,7 +831,10 @@ describe('ContainersView trucking supplier contract', () => {
|
||||
it('uses active TRUCKING suppliers without allowing free-text carrier names', () => {
|
||||
const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/ContainersView.vue'), 'utf8')
|
||||
expect(source).toContain("listSuppliers({ page: 1, size: 200, category: 'TRUCKING', status: 'ACTIVE' })")
|
||||
expect(source).toContain("page: 1, size: 20, category: 'TRUCKING', status: 'ACTIVE', keyword: keyword.trim() || undefined")
|
||||
expect(source).toContain("supplier.category === 'TRUCKING' && supplier.status === 'ACTIVE'")
|
||||
expect(source).toContain('filterable remote reserve-keyword remote-show-suffix')
|
||||
expect(source).toContain(':remote-method="searchTerminalFleets"')
|
||||
expect(source).toContain('selectTruckingSupplier')
|
||||
expect(source).toContain('请选择有效的合作中拖车供应商')
|
||||
expect(source).not.toContain('allow-create')
|
||||
|
||||
@@ -52,6 +52,8 @@ const warehouses = ref<PlatformWarehouseSummaryResource[]>([])
|
||||
const destinationWarehouses = ref<PlatformWarehouseSummaryResource[]>([])
|
||||
const partners = ref<PlatformPartnerResource[]>([])
|
||||
const truckingSuppliers = ref<Supplier[]>([])
|
||||
const terminalFleetOptions = ref<Supplier[]>([])
|
||||
const terminalFleetLoading = ref(false)
|
||||
const oceanBookings = ref<OceanBookingResource[]>([])
|
||||
const loading = ref(false)
|
||||
const warehouseLoading = ref(false)
|
||||
@@ -161,6 +163,7 @@ let warehouseOptionsPromise: Promise<void> | null = null
|
||||
let partnersLoaded = false
|
||||
let truckingSuppliersLoaded = false
|
||||
let truckingSuppliersPromise: Promise<Supplier[]> | null = null
|
||||
let terminalFleetSearchSequence = 0
|
||||
let oceanBookingsLoaded = false
|
||||
let businessOptionsPromise: Promise<void> | null = null
|
||||
|
||||
@@ -473,10 +476,26 @@ async function loadTruckingSuppliers(): Promise<Supplier[]> {
|
||||
try { return await truckingSuppliersPromise }
|
||||
finally { truckingSuppliersPromise = null }
|
||||
}
|
||||
async function ensureTruckingSuppliers(open: unknown = true) {
|
||||
if (!open) return false
|
||||
try { await loadTruckingSuppliers(); return true }
|
||||
catch (error) { ElMessage.error(getApiErrorDetails(error, '拖车供应商加载失败').message); return false }
|
||||
async function searchTerminalFleets(keyword = '') {
|
||||
const sequence = ++terminalFleetSearchSequence
|
||||
terminalFleetLoading.value = true
|
||||
try {
|
||||
const result = await listSuppliers({
|
||||
page: 1, size: 20, category: 'TRUCKING', status: 'ACTIVE', keyword: keyword.trim() || undefined,
|
||||
})
|
||||
if (sequence !== terminalFleetSearchSequence) return
|
||||
terminalFleetOptions.value = result.records.filter((supplier) => supplier.category === 'TRUCKING' && supplier.status === 'ACTIVE')
|
||||
} catch (error) {
|
||||
if (sequence !== terminalFleetSearchSequence) return
|
||||
terminalFleetOptions.value = []
|
||||
ElMessage.error(getApiErrorDetails(error, '码头车队搜索失败').message)
|
||||
} finally {
|
||||
if (sequence === terminalFleetSearchSequence) terminalFleetLoading.value = false
|
||||
}
|
||||
}
|
||||
function handleTerminalFleetVisible(open: boolean) {
|
||||
if (open) void searchTerminalFleets()
|
||||
else { terminalFleetSearchSequence++; terminalFleetLoading.value = false }
|
||||
}
|
||||
async function loadAllPartners() {
|
||||
const firstPage = await listPlatformPartners({ page: 1, size: 200, status: 'ACTIVE' })
|
||||
@@ -562,8 +581,9 @@ async function refreshDrayage(containerBookingId: string) {
|
||||
async function selectRowFleet(source: object, supplierIdValue: unknown) {
|
||||
const row = source as ContainerBookingResource
|
||||
const current = drayageFor(row.id)
|
||||
if (!(await ensureTruckingSuppliers())) return
|
||||
const supplier = truckingCompanies.value.find((item) => item.id === String(supplierIdValue || ''))
|
||||
const supplierId = String(supplierIdValue || '')
|
||||
const supplier = terminalFleetOptions.value.find((item) => item.id === supplierId)
|
||||
|| truckingCompanies.value.find((item) => item.id === supplierId)
|
||||
if (!current || !supplier || !canDrayage(row, 'SELECT_FLEET') || drayageSavingIds.value.includes(row.id)) return
|
||||
drayageSavingIds.value = [...drayageSavingIds.value, row.id]
|
||||
try {
|
||||
@@ -759,7 +779,7 @@ onMounted(async () => {
|
||||
<template #cabinet="{ row }"><strong>{{ row.cabinetNo }}</strong><small>系统生成</small></template>
|
||||
<template #oceanBooking="{ row }"><span v-if="row.oceanBookingId"><strong>{{ row.billOfLadingNo || '已关联订舱' }}</strong><small>{{ row.containerNo ? `集装箱号:${row.containerNo}` : '集装箱号:待补录' }}</small></span><span v-else>未关联</span></template>
|
||||
<template #containerNo="{ row }">{{ row.containerNo || '待补录' }}</template>
|
||||
<template #terminalTruckingCompany="{ row }"><el-select class="fleet-select" :model-value="drayageFor(row.id)?.fleetSupplierId || ''" filterable placeholder="请选择车队" :loading="drayageSavingIds.includes(row.id)" :disabled="!canDrayage(row as ContainerBookingResource, 'SELECT_FLEET') || drayageSavingIds.includes(row.id)" @visible-change="ensureTruckingSuppliers" @update:model-value="selectRowFleet(row, $event)"><el-option v-if="drayageFor(row.id)?.fleetSupplierName && !truckingCompanies.some((item) => item.id === drayageFor(row.id)?.fleetSupplierId)" :label="drayageFor(row.id)?.fleetSupplierName || '原码头车队'" :value="drayageFor(row.id)?.fleetSupplierId || ''" disabled /><el-option v-for="supplier in truckingCompanies" :key="supplier.id" :label="supplier.name" :value="supplier.id" /></el-select></template>
|
||||
<template #terminalTruckingCompany="{ row }"><el-select class="fleet-select" :model-value="drayageFor(row.id)?.fleetSupplierId || ''" filterable remote reserve-keyword remote-show-suffix placeholder="输入车队名称或联系人搜索" :remote-method="searchTerminalFleets" :loading="terminalFleetLoading || drayageSavingIds.includes(row.id)" :disabled="!canDrayage(row as ContainerBookingResource, 'SELECT_FLEET') || drayageSavingIds.includes(row.id)" no-data-text="未找到合作中的码头车队" @visible-change="handleTerminalFleetVisible" @update:model-value="selectRowFleet(row, $event)"><el-option v-if="drayageFor(row.id)?.fleetSupplierName && !terminalFleetOptions.some((item) => item.id === drayageFor(row.id)?.fleetSupplierId)" :label="drayageFor(row.id)?.fleetSupplierName || '原码头车队'" :value="drayageFor(row.id)?.fleetSupplierId || ''" disabled /><el-option v-for="supplier in terminalFleetOptions" :key="supplier.id" :label="supplier.name" :value="supplier.id" /></el-select></template>
|
||||
<template #pickupAppointmentAt="{ row }">{{ formatTime(drayageFor(row.id)?.pickupAppointmentAt) }}</template>
|
||||
<template #actualPickupAt="{ row }">{{ formatTime(drayageFor(row.id)?.actualPickupAt) }}</template>
|
||||
<template #estimatedEmptyReturnAt="{ row }">{{ formatTime(drayageFor(row.id)?.estimatedEmptyReturnAt) }}</template>
|
||||
|
||||
Reference in New Issue
Block a user