From 214b58b642dfd24f5b7d40752082ed7a4549d3ab Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sat, 10 Oct 2026 08:11:13 +0800 Subject: [PATCH] fix(procurement): render file download actions --- .../pages/OverseasBusinessViews.test.ts | 28 +++++++++++++++++++ .../pages/PurchaseOrderDetailView.vue | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/modules/overseas-business/pages/OverseasBusinessViews.test.ts b/src/modules/overseas-business/pages/OverseasBusinessViews.test.ts index bc6163fb..e54023ae 100644 --- a/src/modules/overseas-business/pages/OverseasBusinessViews.test.ts +++ b/src/modules/overseas-business/pages/OverseasBusinessViews.test.ts @@ -10,6 +10,7 @@ import { useAccessPreviewStore } from '@/core/access/accessPreview' import { useAuthStore } from '@/core/auth/auth' import { listPlatformTenants } from '@/modules/iam' import type { PlatformProcurement } from '../procurementTypes' +import { downloadProcurementFile } from '../api/procurementCommands' import type { FleetArrangement } from '../fleetArrangement' import type { LocalLooseboardDetail, LocalLooseboardOrder, LocalTransportDetail, LocalTransportOrder } from '../types' import { @@ -29,6 +30,10 @@ const purchaseDetailSource = readFileSync(resolve(process.cwd(), 'src/modules/ov const routing = vi.hoisted(() => ({ push: vi.fn(), route: { params: {} as Record, query: {} as Record } })) vi.mock('vue-router', () => ({ useRoute: () => routing.route, useRouter: () => ({ push: routing.push }) })) vi.mock('@/modules/iam', () => ({ listPlatformTenants: vi.fn() })) +vi.mock('../api/procurementCommands', async importOriginal => ({ + ...await importOriginal(), + downloadProcurementFile: vi.fn(), +})) vi.mock('../api/platformOverseasBusiness', () => ({ listOverseasPurchases: vi.fn(), getOverseasPurchase: vi.fn(), getOverseasPurchaseEditor: vi.fn(), updateOverseasPurchase: vi.fn(), listOverseasPurchaseCustomerOptions: vi.fn(), listOverseasPurchaseWarehouseOptions: vi.fn(), listUsTruckOrders: vi.fn(), getUsTruckOrder: vi.fn(), createUsTruckOrder: vi.fn(), updateUsTruckOrder: vi.fn(), @@ -64,6 +69,7 @@ describe('overseas business mounted pages', () => { beforeEach(() => { vi.stubGlobal('ResizeObserver', ResizeObserverStub); vi.stubGlobal('localStorage', memoryStorage()); vi.stubGlobal('sessionStorage', memoryStorage()); document.body.innerHTML = '' routing.push.mockReset(); routing.route.params = {}; routing.route.query = {} + vi.mocked(downloadProcurementFile).mockReset() vi.mocked(listOverseasPurchases).mockReset().mockResolvedValue({ records: [purchase], page: 1, size: 20, total: 1, pages: 1 }); vi.mocked(getOverseasPurchase).mockReset().mockResolvedValue(procurementDetail()); vi.mocked(updateOverseasPurchase).mockReset().mockResolvedValue({ ...purchase, version: 4 }) vi.mocked(getOverseasPurchaseEditor).mockReset().mockResolvedValue({ customerView: { order: { orderNo: purchase.orderNo, customerId: purchase.customerId, productName: purchase.productName, purchaseQuantity: purchase.purchaseQuantity, version: purchase.version } }, internalRemark: purchase.remark }) vi.mocked(listOverseasPurchaseCustomerOptions).mockReset().mockResolvedValue([{ customerId: '10001', customerName: '客户甲' }]); vi.mocked(listOverseasPurchaseWarehouseOptions).mockReset().mockResolvedValue([{ warehouseId: '20001', warehouseCode: 'LAX', warehouseName: '洛杉矶采购仓', countryCode: 'US' }]) @@ -166,6 +172,28 @@ describe('overseas business mounted pages', () => { expect(routing.push).toHaveBeenCalledWith({ name: 'overseas-business-purchases' }) }) + it('downloads procurement files with list access and prevents duplicate pending downloads', async () => { + routing.route.params = { purchaseId: 'OP-100' }; routing.route.query = { customerId: '10001' } + const result = procurementDetail() + result.files = [{ id: '9007199254741000', fileId: '9007199254741001', category: 'LABEL', fileName: 'label.pdf', contentType: 'application/pdf', sizeBytes: 123, createdAt: '2026-10-10T10:00:00' }] + vi.mocked(getOverseasPurchase).mockResolvedValue(result) + let rejectDownload!: (error: Error) => void + vi.mocked(downloadProcurementFile).mockImplementation(() => new Promise((_resolve, reject) => { rejectDownload = reject })) + const wrapper = mountPage(PurchaseOrderDetailView) + useAuthStore().permissions = ['platform:overseas-business:purchase:list'] + await flushPromises() + const button = wrapper.findAll('.el-table__body-wrapper button').find(item => item.text() === '下载') + expect(button).toBeDefined() + await button!.trigger('click'); await flushPromises() + expect(downloadProcurementFile).toHaveBeenCalledWith('OP-100', '10001', '9007199254741001') + expect(button!.attributes('disabled')).toBeDefined() + await button!.trigger('click') + expect(downloadProcurementFile).toHaveBeenCalledTimes(1) + rejectDownload(new Error('TEST download unavailable')); await flushPromises() + expect(button!.attributes('disabled')).toBeUndefined() + expect(document.body.textContent).toContain('文件下载失败') + }) + it('renders estimate holds separately from actual payment without claiming inbound settlement', async () => { routing.route.params = { purchaseId: 'OP-100' }; routing.route.query = { customerId: '10001' } const result = procurementDetail() diff --git a/src/modules/overseas-business/pages/PurchaseOrderDetailView.vue b/src/modules/overseas-business/pages/PurchaseOrderDetailView.vue index 75e43af1..5224c530 100644 --- a/src/modules/overseas-business/pages/PurchaseOrderDetailView.vue +++ b/src/modules/overseas-business/pages/PurchaseOrderDetailView.vue @@ -110,7 +110,7 @@ const correctionColumns: DataTableColumn[] = [ { key: 'feeNos', label: '关联实际费用或调整', minWidth: 240, formatter: (row: PlatformProcurement['feeCorrections'][number]) => row.feeNos.join(';') || '无资金差额' }, ] const fileColumns: DataTableColumn[] = [ - { key: 'actions', label: '操作', width: 90, fixed: 'left' }, { key: 'fileName', prop: 'fileName', label: '文件名', minWidth: 250 }, + { key: 'actions', slotName: 'actions', label: '操作', width: 90, fixed: 'left' }, { key: 'fileName', prop: 'fileName', label: '文件名', minWidth: 250 }, { key: 'category', label: '用途', width: 120, formatter: (row: ProcurementFile) => fileLabels[row.category] || '待核对' }, { key: 'createdAt', label: '上传时间', minWidth: 160, formatter: (row: ProcurementFile) => dateTime(row.createdAt) }, ]