fix: align appointment viewing and fleet follow-up navigation
This commit is contained in:
@@ -281,4 +281,17 @@ describe('overseas business mounted pages', () => {
|
||||
it('keeps looseboard edit form and version unchanged after a 409', async () => { routing.route.params = { orderId: 'LB-300' }; routing.route.query = { customerId: '10003' }; vi.mocked(updateLocalLooseboardOrder).mockRejectedValue(new ApiResponseError('订单版本冲突', 'B0409', 409)); const wrapper = mountPage(TransportOrderFormView, { domain: 'looseboard' }); await flushPromises(); const destination = wrapper.find('input[placeholder="城市 / 州"]'); await destination.setValue('ONT-MARKER-EDIT'); await wrapper.findAll('button').find((button) => button.text().includes('保存修改'))?.trigger('click'); await flushPromises(); expect(updateLocalLooseboardOrder).toHaveBeenCalledWith('LB-300', '10003', expect.objectContaining({ version: 0, destination: 'ONT-MARKER-EDIT' })); expect((destination.element as HTMLInputElement).value).toBe('ONT-MARKER-EDIT'); expect(document.body.textContent).toContain('订单版本冲突'); expect(routing.push).not.toHaveBeenCalled() })
|
||||
it('mounts looseboard create without a detail route or pending notice', async () => { const wrapper = mountPage(TransportOrderFormView, { domain: 'looseboard' }); await flushPromises(); expect(wrapper.text()).toContain('客户信息'); expect(wrapper.text()).toContain('请选择客户'); expect(wrapper.text()).not.toContain('接口能力待后端补齐'); expect(wrapper.findAll('button').find((button) => button.text().includes('提交订单'))?.attributes('disabled')).toBeUndefined() })
|
||||
it('reuses one idempotency key and preserves looseboard create input after retries fail', async () => { vi.mocked(createLocalLooseboardOrder).mockRejectedValue(new ApiResponseError('temporary failure', 'S0500', 500)); const wrapper = mountPage(TransportOrderFormView, { domain: 'looseboard' }); await flushPromises(); const selects = wrapper.findAllComponents({ name: 'ElSelect' }); selects[0].vm.$emit('update:modelValue', '10001'); const groups = wrapper.findAllComponents({ name: 'ElRadioGroup' }); groups[0].vm.$emit('update:modelValue', 'SHARED_TRUCK'); groups[1].vm.$emit('update:modelValue', 'YES'); groups[2].vm.$emit('update:modelValue', 'WAREHOUSE_TO_WAREHOUSE'); const origin = wrapper.find('input[placeholder="城市 / 港口 / 州"]'); const destination = wrapper.find('input[placeholder="城市 / 州"]'); await origin.setValue('LA-MARKER'); await destination.setValue('ONT-MARKER'); await wrapper.findAll('.el-form-item').find((item) => item.text().startsWith('总重量'))!.find('input').setValue('80'); await wrapper.findAll('.el-form-item').find((item) => item.text().startsWith('总体积'))!.find('input').setValue('1.8'); await wrapper.vm.$nextTick(); const submit = wrapper.findAll('button').find((button) => button.text().includes('提交订单')); await submit?.trigger('click'); await flushPromises(); await submit?.trigger('click'); await flushPromises(); expect(createLocalLooseboardOrder).toHaveBeenCalledTimes(2); const keys = vi.mocked(createLocalLooseboardOrder).mock.calls.map((call) => call[1].idempotencyKey); expect(keys[0]).toBeTruthy(); expect(keys[1]).toBe(keys[0]); expect((origin.element as HTMLInputElement).value).toBe('LA-MARKER'); expect((destination.element as HTMLInputElement).value).toBe('ONT-MARKER'); expect(routing.push).not.toHaveBeenCalled() })
|
||||
it.each([true, false])('opens only the matching pool order read-only arrangement: %s', matching => {
|
||||
routing.route.query = { orderNo: truck.orderNo, fleetSource: 'inquiry', fleetOfferNo: 'FO-1', fleetBookingNo: matching ? arrangement.bookingNo : 'FB-OTHER' }
|
||||
vi.mocked(listUsTruckOrders).mockResolvedValue({ records: [{ ...truck, fleetArrangement: arrangement }], page: 1, size: 20, total: 1, pages: 1 })
|
||||
return (async () => {
|
||||
const wrapper = mountPage(TransportOrdersView, { domain: 'truck' }); await flushPromises()
|
||||
const dialog = wrapper.findAllComponents(AppDialog).find(item => item.props('title') === '承运安排')!
|
||||
expect(dialog.props('modelValue')).toBe(matching); expect(dialog.props('showConfirm')).toBe(false)
|
||||
await wrapper.findAll('button').find(item => item.text() === '返回原拼车登记')!.trigger('click')
|
||||
expect(routing.push).toHaveBeenCalledWith({ name: 'overseas-master-data-capacity-offer-detail', params: { offerNo: 'FO-1' }, query: { inquiry: matching ? arrangement.bookingNo : 'FB-OTHER' } })
|
||||
expect(updateUsTruckOrder).not.toHaveBeenCalled()
|
||||
})()
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import '@/styles/adminDensity.css'
|
||||
import { TransportRouteDialog, routeLocation, type RouteLocation } from '@/modules/overseas-master-data'
|
||||
import { inquiryReturnTarget, TransportRouteDialog, routeLocation, type RouteLocation } from '@/modules/overseas-master-data'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { Plus } from '@lucide/vue'
|
||||
@@ -76,6 +76,9 @@ const columns = computed(() => {
|
||||
})
|
||||
function formatDateTime(value?: string | null) { return value ? value.replace('T', ' ').slice(0, 16) : '—' }
|
||||
async function load() {
|
||||
const sourceBooking = route.query.fleetBookingNo
|
||||
const sourceOrder = route.query.orderNo
|
||||
arrangementOpen.value = false; arrangement.value = null
|
||||
rows.value = []; total.value = 0; loadError.value = null; loading.value = true
|
||||
try {
|
||||
if (isLooseboard.value) {
|
||||
@@ -85,6 +88,10 @@ async function load() {
|
||||
const result = await listUsTruckOrders({ page: page.value, size: pageSize.value, orderNo: String(applied.value.orderNo || ''), routeKeyword: String(applied.value.routeKeyword || ''), status: String(applied.value.status || '') as LocalTransportStatus | '' } satisfies LocalTransportQuery)
|
||||
rows.value = result.records; total.value = result.total
|
||||
}
|
||||
if (inquiryReturnTarget(route.query) && route.query.fleetBookingNo === sourceBooking && route.query.orderNo === sourceOrder) {
|
||||
const target = rows.value.find(row => row.orderNo === sourceOrder && row.fleetArrangement?.bookingNo === sourceBooking)
|
||||
if (target) showArrangement(target)
|
||||
}
|
||||
} catch (error) { loadError.value = getApiErrorDetails(error, `${domainLabel.value}订单加载失败,请稍后重试`) } finally { loading.value = false }
|
||||
}
|
||||
function search(model: QueryModel) { applied.value = { ...model }; if (page.value === 1) void load(); else page.value = 1 }
|
||||
@@ -99,7 +106,7 @@ watch([page, pageSize], () => { void load() }); watch([isLooseboard, () => route
|
||||
|
||||
|
||||
<section><DataTable appearance="integrated" :stripe="false" column-settings-mode="show" :results-visible="!loadError" v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :loading="loading" :total="total" :preference-key="`overseas-business-${domain}`" row-key="id" :empty-text="`暂无符合筛选条件的${domainLabel}订单`">
|
||||
<template #toolbar-start><h1>{{ domainLabel }}</h1></template>
|
||||
<template #toolbar-start><el-button v-if="inquiryReturnTarget(route.query)" link @click="router.push(inquiryReturnTarget(route.query)!)">返回原拼车登记</el-button><h1>{{ domainLabel }}</h1></template>
|
||||
<template #filters><QueryToolbar v-model="filters" :fields="fields" :ariaLabel="`${domainLabel}订单筛选`" :preference-key="queryPreferenceKey" @search="search" /></template>
|
||||
<template #notices><template v-if="loadError"><LoadErrorState :title="`${domainLabel}订单暂时无法加载`" :message="loadError.message" :loading="loading" @retry="load"><template #details><ApiErrorMeta :details="loadError" /></template></LoadErrorState></template></template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user