优化
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
import { shallowMount, flushPromises } from '@vue/test-utils'
|
||||||
|
import { beforeEach, expect, it, vi } from 'vitest'
|
||||||
|
import Dialog from './LooseboardCargoDialog.vue'
|
||||||
|
import { candidate, detail } from '../../overseas-warehouse/dispatchTestFixtures'
|
||||||
|
import * as api from '@/modules/overseas-warehouse'
|
||||||
|
|
||||||
|
vi.mock('@/modules/overseas-warehouse', async () => ({
|
||||||
|
getDispatch: vi.fn(), listLooseboardCargo: vi.fn(), addLooseboardCargo: vi.fn(),
|
||||||
|
expandSelectionGroups: (await import('../../overseas-warehouse/dispatchContracts')).expandSelectionGroups,
|
||||||
|
}))
|
||||||
|
vi.mock('element-plus', () => ({ ElMessage: { success: vi.fn() } }))
|
||||||
|
beforeEach(() => { vi.clearAllMocks() })
|
||||||
|
|
||||||
|
it('selects one looseboard order and submits all original pallet selections together', async () => {
|
||||||
|
const first = candidate({ orderNo: 'LB1', availablePackages: 9 })
|
||||||
|
const second = candidate({ sourceKey: 'source-2', sourceVersion: 'version-2', selection: { ...first.selection, planPalletId: '2', sourceVersion: 'version-2' } })
|
||||||
|
first.selectionGroup = { ...first.selectionGroup, sources: [...first.selectionGroup.sources, ...second.selectionGroup.sources], pallets: [...first.selectionGroup.pallets, { warehousePalletId: null, palletNo: 'P2', sourceKeys: [second.sourceKey], packageCount: 2 }] }
|
||||||
|
const dispatch = detail(); dispatch.actions.ADD_CARGO = { allowed: true, blockCode: null, blockReason: null }
|
||||||
|
vi.mocked(api.getDispatch).mockResolvedValue(dispatch)
|
||||||
|
vi.mocked(api.listLooseboardCargo).mockResolvedValue({ candidates: [first], total: 1, page: 1, size: 20, pages: 1, complete: true, snapshotAt: '2026-11-05T00:00:00Z' })
|
||||||
|
const wrapper = shallowMount(Dialog, { props: { modelValue: false, dispatchNo: 'PC/1' }, global: { renderStubDefaultSlot: true, stubs: { ElAlert: true } } })
|
||||||
|
await wrapper.setProps({ modelValue: true }); await flushPromises()
|
||||||
|
const table = wrapper.getComponent({ name: 'DataTable' })
|
||||||
|
expect(table.props('data')).toHaveLength(1)
|
||||||
|
expect(table.props('columns').map((column: { label?: string }) => column.label)).toContain('托数')
|
||||||
|
expect(table.props('columns').map((column: { label?: string }) => column.label)).not.toContain('计划 / 实物托盘')
|
||||||
|
table.vm.$emit('selection-change', [first]); await flushPromises()
|
||||||
|
wrapper.getComponent({ name: 'AppDialog' }).vm.$emit('confirm'); await flushPromises()
|
||||||
|
expect(api.addLooseboardCargo).toHaveBeenCalledWith('PC/1', expect.objectContaining({ cargo: [first.selection, second.selection] }))
|
||||||
|
expect(wrapper.emitted('update:modelValue')).toEqual([[false]])
|
||||||
|
wrapper.unmount()
|
||||||
|
})
|
||||||
@@ -15,7 +15,7 @@ const page=ref(1), size=ref(20), total=ref(0), loading=ref(false), saving=ref(fa
|
|||||||
const columns:DataTableColumn[]=[
|
const columns:DataTableColumn[]=[
|
||||||
{key:'selection',type:'selection',width:45}, {key:'orderNo',label:'订单号',minWidth:180},
|
{key:'selection',type:'selection',width:45}, {key:'orderNo',label:'订单号',minWidth:180},
|
||||||
{key:'customerName',label:'客户',minWidth:140}, {key:'inboundCode',label:'入仓号',minWidth:150},
|
{key:'customerName',label:'客户',minWidth:140}, {key:'inboundCode',label:'入仓号',minWidth:150},
|
||||||
{key:'sourceStage',label:'货物阶段',width:110,formatter:(row:Candidate)=>!row.selection.warehousePalletId ? '申报待到仓' : '已实收'}, {key:'palletNo',label:'计划 / 实物托盘',minWidth:150}, {key:'destination',label:'目的地',minWidth:180,formatter:(row:Candidate)=>row.destination.warehouseCode || row.destination.address || '—'},
|
{key:'sourceStage',label:'货物阶段',width:110,formatter:(row:Candidate)=>row.selectionGroup?.sources.every(source=>source.selection.warehousePalletId) ? '已实收' : '申报待到仓'}, {key:'palletCount',label:'托数',width:80,formatter:(row:Candidate)=>row.selectionGroup?.pallets.length ?? '—'}, {key:'destination',label:'目的地',minWidth:180,formatter:(row:Candidate)=>row.destination.warehouseCode || row.destination.address || '—'},
|
||||||
{key:'availablePackages',label:'计划 / 可用箱数',width:100},
|
{key:'availablePackages',label:'计划 / 可用箱数',width:100},
|
||||||
{key:'blockReasons',label:'资格',minWidth:200,formatter:(row:Candidate)=>row.blockReasons.length?row.blockReasons.join(';'):'可添加'},
|
{key:'blockReasons',label:'资格',minWidth:200,formatter:(row:Candidate)=>row.blockReasons.length?row.blockReasons.join(';'):'可添加'},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ it('hides the single delivery selector and saves receipt files to that delivery
|
|||||||
await wrapper.get('.save').trigger('click'); await flushPromises()
|
await wrapper.get('.save').trigger('click'); await flushPromises()
|
||||||
expect(saveDeliveryDocuments).toHaveBeenCalledWith('DL-1', '101', expect.objectContaining({ bolNo: 'BOL-ORIGINAL', documents: [{ category: 'LOADING_PHOTO', fileIds: [] }, { category: 'BOL', fileIds: [] }, { category: 'RECEIPT', fileIds: ['99'] }] }))
|
expect(saveDeliveryDocuments).toHaveBeenCalledWith('DL-1', '101', expect.objectContaining({ bolNo: 'BOL-ORIGINAL', documents: [{ category: 'LOADING_PHOTO', fileIds: [] }, { category: 'BOL', fileIds: [] }, { category: 'RECEIPT', fileIds: ['99'] }] }))
|
||||||
expect(wrapper.emitted('saved')).toHaveLength(1)
|
expect(wrapper.emitted('saved')).toHaveLength(1)
|
||||||
expect(wrapper.getComponent(DeliveryDocumentsDialog).props('modelValue')).toBe(true)
|
expect(wrapper.emitted('update:modelValue')).toEqual([[false]])
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
it('switches customer scope exactly and keeps unsaved delivery edits when switching tabs', async () => {
|
it('switches customer scope exactly and keeps unsaved delivery edits when switching tabs', async () => {
|
||||||
@@ -91,6 +91,18 @@ it('switches customer scope exactly and keeps unsaved delivery edits when switch
|
|||||||
expect(saveDeliveryDocuments).not.toHaveBeenCalled()
|
expect(saveDeliveryDocuments).not.toHaveBeenCalled()
|
||||||
confirmation.mockRestore(); wrapper.unmount()
|
confirmation.mockRestore(); wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
it('keeps the management dialog and draft open when saving fails', async () => {
|
||||||
|
vi.mocked(saveDeliveryDocuments).mockRejectedValue(new Error('保存失败'))
|
||||||
|
const wrapper = setup(); await flushPromises()
|
||||||
|
const receipt = wrapper.getComponent(DeliveryDocumentsDialog)
|
||||||
|
await receipt.findAll('button').find(button => button.text() === '删除')!.trigger('click')
|
||||||
|
await wrapper.get('.save').trigger('click'); await flushPromises()
|
||||||
|
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
||||||
|
expect(wrapper.emitted('saved')).toBeUndefined()
|
||||||
|
expect(receipt.text()).not.toContain('existing-pod.pdf')
|
||||||
|
expect(wrapper.text()).toContain('保存失败')
|
||||||
|
wrapper.unmount()
|
||||||
|
})
|
||||||
it('does not request delivery documents without delivery list permission', async () => {
|
it('does not request delivery documents without delivery list permission', async () => {
|
||||||
can.mockImplementation((value?: string) => value !== 'platform:overseas-warehouse:delivery:list')
|
can.mockImplementation((value?: string) => value !== 'platform:overseas-warehouse:delivery:list')
|
||||||
const wrapper = setup(); await flushPromises()
|
const wrapper = setup(); await flushPromises()
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ async function canLeave() {
|
|||||||
async function selectDelivery(value: string) { if (value !== selected.value && await canLeave()) selected.value = value }
|
async function selectDelivery(value: string) { if (value !== selected.value && await canLeave()) selected.value = value }
|
||||||
async function beforeClose(done: () => void) { if (await canLeave()) done() }
|
async function beforeClose(done: () => void) { if (await canLeave()) done() }
|
||||||
function selectTab(value: string) { if (!busy.value) { tab.value = value } }
|
function selectTab(value: string) { if (!busy.value) { tab.value = value } }
|
||||||
function saved() { emit('saved') }
|
function saved() { open.value = false; emit('saved') }
|
||||||
function pickupCompleted() { open.value = false; emit('saved') }
|
function pickupCompleted() { open.value = false; emit('saved') }
|
||||||
async function loadingSaved() { emit('saved'); await load() }
|
async function loadingSaved() { emit('saved'); await load() }
|
||||||
watch(() => [open.value, props.dispatchNo] as const, ([visible]) => {
|
watch(() => [open.value, props.dispatchNo] as const, ([visible]) => {
|
||||||
|
|||||||
@@ -58,6 +58,19 @@ describe('DeliveryOrderDetailView', () => {
|
|||||||
expect(wrapper.findComponent({ name: 'BusinessDocumentFees' }).exists()).toBe(false)
|
expect(wrapper.findComponent({ name: 'BusinessDocumentFees' }).exists()).toBe(false)
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
})
|
})
|
||||||
|
it('renders document and receipt operation nodes in Chinese', async () => {
|
||||||
|
const value = await vi.mocked(getDeliveryOrder)('DEL/1', '100')
|
||||||
|
value.operations = ['FIRSTLEG_COMPLETION_PENDING', 'SAVE_DOCUMENTS', 'RECEIPT_AUTO_COMPLETE'].map((operationNode, index) => ({ id: String(index), operationNode, operatedAt: '2026-11-05T16:59:55', result: '已保存' }))
|
||||||
|
vi.mocked(getDeliveryOrder).mockResolvedValue(value)
|
||||||
|
const wrapper = mount(DeliveryOrderDetailView, { global: { plugins: [ElementPlus] } })
|
||||||
|
await flushPromises()
|
||||||
|
await wrapper.find('.el-tabs__item:nth-child(4)').trigger('click')
|
||||||
|
expect(wrapper.text()).toContain('来源货物签收待齐')
|
||||||
|
expect(wrapper.text()).toContain('保存派送资料')
|
||||||
|
expect(wrapper.text()).toContain('签收文件自动完成派送')
|
||||||
|
for (const operation of value.operations) expect(wrapper.text()).not.toContain(operation.operationNode)
|
||||||
|
wrapper.unmount()
|
||||||
|
})
|
||||||
it('shows frozen original coverage separately from new fees', async () => {
|
it('shows frozen original coverage separately from new fees', async () => {
|
||||||
const value = await vi.mocked(getDeliveryOrder)('DEL/1', '100')
|
const value = await vi.mocked(getDeliveryOrder)('DEL/1', '100')
|
||||||
value.feeCoverage = { cargoHash: 'hash', cargo: [], confirmedAt: '2026-10-03T00:00:00Z', references: [{
|
value.feeCoverage = { cargoHash: 'hash', cargo: [], confirmedAt: '2026-10-03T00:00:00Z', references: [{
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const methodLabels: Record<string, string> = { PICKUP: '普通自提', AMAZON_PI
|
|||||||
const pickupLabels: Record<string, string> = { ONE_PICKUP_ONE_DROP: '一提一卸', ONE_PICKUP_MULTI_DROP: '一提多卸', MULTI_PICKUP_ONE_DROP: '多提一卸', MULTI_PICKUP_MULTI_DROP: '多提多卸', WAREHOUSE_PICKUP: '仓库自提', DOOR_PICKUP: '上门提货', SELF_PICKUP: '自提' }
|
const pickupLabels: Record<string, string> = { ONE_PICKUP_ONE_DROP: '一提一卸', ONE_PICKUP_MULTI_DROP: '一提多卸', MULTI_PICKUP_ONE_DROP: '多提一卸', MULTI_PICKUP_MULTI_DROP: '多提多卸', WAREHOUSE_PICKUP: '仓库自提', DOOR_PICKUP: '上门提货', SELF_PICKUP: '自提' }
|
||||||
const loadingLabels: Record<string, string> = { PALLET: '托盘', FLOOR: '地板', MIXED: '混装', CARTON: '散箱' }
|
const loadingLabels: Record<string, string> = { PALLET: '托盘', FLOOR: '地板', MIXED: '混装', CARTON: '散箱' }
|
||||||
const feeLabels: Record<string, string> = { DELIVERY_FEE: '派送费用', PRIVATE_LAST_MILE_DELIVERY: '私人仓尾程派送费', EXPRESS_FEE: '快递费用', LOADING_FEE: '装车费', APPOINTMENT_FEE: '买约费用', OTHER: '其他费用' }
|
const feeLabels: Record<string, string> = { DELIVERY_FEE: '派送费用', PRIVATE_LAST_MILE_DELIVERY: '私人仓尾程派送费', EXPRESS_FEE: '快递费用', LOADING_FEE: '装车费', APPOINTMENT_FEE: '买约费用', OTHER: '其他费用' }
|
||||||
const operationLabels: Record<string, string> = { CREATE_DELIVERY: '创建派送单', ASSIGN_VEHICLE: '车队分配', DISPATCH: '开始派送', SIGN: '签收', COMPLETE_DELIVERY: '完成派送', UPDATE_DELIVERY_STATUS: '更新派送状态', CUSTOMER_VISIT: '客户回访', MARK_RETURN: '标记退货', CANCEL_OUTBOUND: '取消出库', CANCEL_OUTBOUND_REASON: '取消原因', CONFIRM_EXTERNAL_FREIGHT: '确认外接运费' }
|
const operationLabels: Record<string, string> = { CREATE_DELIVERY: '创建派送单', ASSIGN_VEHICLE: '车队分配', DISPATCH: '开始派送', SIGN: '签收', COMPLETE_DELIVERY: '完成派送', UPDATE_DELIVERY_STATUS: '更新派送状态', CUSTOMER_VISIT: '客户回访', MARK_RETURN: '标记退货', CANCEL_OUTBOUND: '取消出库', CANCEL_OUTBOUND_REASON: '取消原因', CONFIRM_EXTERNAL_FREIGHT: '确认外接运费', SAVE_DOCUMENTS: '保存派送资料', RECEIPT_AUTO_COMPLETE: '签收文件自动完成派送', FIRSTLEG_COMPLETION_PENDING: '来源货物签收待齐' }
|
||||||
const resultLabels: Record<string, string> = { CREATED: '已创建' }
|
const resultLabels: Record<string, string> = { CREATED: '已创建' }
|
||||||
|
|
||||||
function show(value: unknown) { const text = String(value ?? '').trim(); return text || '—' }
|
function show(value: unknown) { const text = String(value ?? '').trim(); return text || '—' }
|
||||||
|
|||||||
Reference in New Issue
Block a user