import ElementPlus, { ElMessageBox } from 'element-plus' import { defineComponent, h } from 'vue' import { flushPromises, mount } from '@vue/test-utils' import { beforeEach, expect, it, vi } from 'vitest' import DispatchDocumentsDialog from './DispatchDocumentsDialog.vue' import DeliveryDocumentsDialog from './DeliveryDocumentsDialog.vue' import { detail } from '../dispatchTestFixtures' import { getDispatch } from '../api/dispatches' import { deliveryDocumentCategories, getDeliveryDocuments, saveDeliveryDocuments, type DeliveryDocuments } from '../api/deliveryDocuments' const can = vi.hoisted(() => vi.fn(() => true)) vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can }) })) vi.mock('../api/dispatches', () => ({ getDispatch: vi.fn() })) vi.mock('../api/deliveryDocuments', async original => ({ ...await original(), getDeliveryDocuments: vi.fn(), saveDeliveryDocuments: vi.fn() })) const dialogStub = defineComponent({ props: ['modelValue', 'showConfirm'], emits: ['confirm'], setup(props, { slots, emit }) { return () => props.modelValue ? h('section', [slots.default?.(), props.showConfirm ? h('button', { class: 'save', onClick: () => emit('confirm') }, '保存资料') : null]) : null } }) function documents(no = 'DL-1', customerId = '101'): DeliveryDocuments { return { deliveryNo: no, customerId, version: 1, bolNo: 'BOL-ORIGINAL', uploadedCategoryCount: 1, totalCategoryCount: 3, allowedActions: ['MANAGE_DOCUMENTS'], replayed: false, categories: deliveryDocumentCategories.map(item => ({ category: item.category, status: item.category === 'RECEIPT' ? 'UPLOADED' : 'MISSING', fileCount: item.category === 'RECEIPT' ? 1 : 0, files: item.category === 'RECEIPT' ? [{ fileId: '99', fileName: 'existing-pod.pdf', contentType: 'application/pdf', sizeBytes: 10, uploadedAt: '2026-10-21T00:00:00' }] : [] })) } } function setup() { return mount(DispatchDocumentsDialog, { props: { modelValue: true, dispatchNo: 'PC/1' }, global: { plugins: [ElementPlus], stubs: { AppDialog: dialogStub, DispatchVehicleDocuments: true, DispatchLoadingDocuments: true, DispatchEvidenceFiles: true } } }) } beforeEach(() => { vi.clearAllMocks(); can.mockReturnValue(true) const value = detail(); value.stage = 'DELIVERING' value.documents.deliveries = [ { deliveryNo: 'DL-1', customerId: '101', customerName: '客户甲', groupKey: 'A', outboundNo: 'OB-1', destination: { key: 'FBA:A', type: 'FBA', warehouseId: null, warehouseCode: 'A', warehouseName: null, address: null, postalCode: null, contactName: null, contactPhone: null }, status: 'DELIVERING', packageCount: 1, palletCount: 1 }, { deliveryNo: 'DL-2', customerId: '102', customerName: '客户乙', groupKey: 'B', outboundNo: 'OB-2', destination: { key: 'FBA:B', type: 'FBA', warehouseId: null, warehouseCode: 'B', warehouseName: null, address: null, postalCode: null, contactName: null, contactPhone: null }, status: 'DELIVERING', packageCount: 1, palletCount: 1 }, ] vi.mocked(getDispatch).mockResolvedValue(value) vi.mocked(getDeliveryDocuments).mockImplementation(async (no, customer) => documents(no, customer)) vi.mocked(saveDeliveryDocuments).mockResolvedValue({ ...documents(), version: 2 }) }) it.each(['LOADING', 'AFTER_LOADING'] as const)('opens loading documents in %s before delivery orders exist and without delivery-list permission', async stage => { vi.mocked(getDispatch).mockResolvedValue(detail({ stage })) can.mockImplementation((value?: string) => value !== 'platform:overseas-warehouse:delivery:list') const wrapper = setup(); await flushPromises() expect(wrapper.find('dispatch-loading-documents-stub').exists()).toBe(true) expect(wrapper.findAll('[role="tab"]').find(tab => tab.text() === '装车资料')!.attributes('aria-selected')).toBe('true') expect(getDeliveryDocuments).not.toHaveBeenCalled(); wrapper.unmount() }) it('reads existing delivery files in one dialog and saves receipt without requiring loading or BOL files', async () => { const wrapper = setup(); await flushPromises() expect(getDeliveryDocuments).toHaveBeenCalledWith('DL-1', '101') expect(wrapper.text()).toContain('existing-pod.pdf') expect(wrapper.findAllComponents(DeliveryDocumentsDialog)).toHaveLength(1) 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(wrapper.emitted('saved')).toHaveLength(1) expect(wrapper.getComponent(DeliveryDocumentsDialog).props('modelValue')).toBe(true) wrapper.unmount() }) it('switches customer scope exactly and keeps unsaved delivery edits when switching tabs', async () => { const wrapper = setup(); await flushPromises() await wrapper.findAll('[role="tab"]').find(tab => tab.text() === '装车资料')!.trigger('click') expect(wrapper.getComponent(DeliveryDocumentsDialog).props('categories')).toEqual(['LOADING_PHOTO', 'BOL']) await wrapper.getComponent(DeliveryDocumentsDialog).find('input').setValue('BOL-CHANGED') await wrapper.findAll('[role="tab"]').find(tab => tab.text() === '油耗图片')!.trigger('click') expect(getDeliveryDocuments).toHaveBeenCalledTimes(1) const confirmation = vi.spyOn(ElMessageBox, 'confirm').mockRejectedValue('cancel') wrapper.getComponent({ name: 'ElSelect' }).vm.$emit('update:modelValue', 'DL-2'); await flushPromises() expect(getDeliveryDocuments).toHaveBeenCalledTimes(1) confirmation.mockResolvedValue('confirm' as Awaited>) wrapper.getComponent({ name: 'ElSelect' }).vm.$emit('update:modelValue', 'DL-2'); await flushPromises() expect(getDeliveryDocuments).toHaveBeenLastCalledWith('DL-2', '102') expect(saveDeliveryDocuments).not.toHaveBeenCalled() confirmation.mockRestore(); wrapper.unmount() }) it('does not request delivery documents without delivery list permission', async () => { can.mockImplementation((value?: string) => value !== 'platform:overseas-warehouse:delivery:list') const wrapper = setup(); await flushPromises() expect(getDeliveryDocuments).not.toHaveBeenCalled() expect(wrapper.text()).toContain('当前账号无派送资料查看权限') wrapper.unmount() })