diff --git a/src/modules/inbounds/core/api.test.ts b/src/modules/inbounds/core/api.test.ts index d6af6e6a..0e3074b6 100644 --- a/src/modules/inbounds/core/api.test.ts +++ b/src/modules/inbounds/core/api.test.ts @@ -1,14 +1,21 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { http } from '@/shared/api/http' -import { getPlatformInbound, listPlatformInbounds } from './api' +import { downloadInboundCartonLabels, getPlatformInbound, listPlatformInbounds } from './api' vi.mock('@/shared/api/http', () => ({ - http: { get: vi.fn() }, + ApiResponseError: class ApiResponseError extends Error { + code: string + constructor(message: string, code: string) { super(message); this.code = code } + }, + http: { get: vi.fn(), post: vi.fn() }, unwrapApiResponse: (response: { data: T }) => response.data, })) describe('platform inbound query API', () => { - beforeEach(() => vi.mocked(http.get).mockReset()) + beforeEach(() => { + vi.mocked(http.get).mockReset() + vi.mocked(http.post).mockReset() + }) it('omits the backend tenant filter for an all-customer list query', async () => { vi.mocked(http.get).mockResolvedValue({ @@ -83,4 +90,22 @@ describe('platform inbound query API', () => { }, }) }) + + it('downloads stable carton labels and rejects JSON business errors', async () => { + const pdf = new Blob(['pdf'], { type: 'application/pdf' }) + vi.mocked(http.post).mockResolvedValueOnce(pdf) + + await expect(downloadInboundCartonLabels('10001', '19001', [1, 3])).resolves.toBe(pdf) + expect(http.post).toHaveBeenCalledWith('/platform/inbounds/19001/carton-label-pdf', null, { + params: { tenantId: '10001', cartonIndex: [1, 3] }, responseType: 'blob', timeout: 60_000, + }) + + vi.mocked(http.post).mockResolvedValueOnce({ + type: 'application/json', + text: async () => JSON.stringify({ code: 'A0422', message: '箱号映射不完整' }), + } as Blob) + await expect(downloadInboundCartonLabels('10001', '19001')).rejects.toMatchObject({ + message: '箱号映射不完整', code: 'A0422', + }) + }) }) diff --git a/src/modules/inbounds/pages/InboundOrdersView.test.ts b/src/modules/inbounds/pages/InboundOrdersView.test.ts index d11aa950..f7fda4c6 100644 --- a/src/modules/inbounds/pages/InboundOrdersView.test.ts +++ b/src/modules/inbounds/pages/InboundOrdersView.test.ts @@ -9,10 +9,11 @@ import { listPlatformTenants, type PlatformTenantResource } from '@/modules/iam' import QueryToolbar from '@/shared/components/QueryToolbar.vue' import DataTable from '@/shared/components/DataTable.vue' import { listPlatformWarehouses } from '@/modules/warehouses' -import { getPlatformInbound, listPlatformInbounds } from '../core/api' +import { downloadInboundCartonLabels, getPlatformInbound, listPlatformInbounds } from '../core/api' import type { InboundOrderDetail, InboundOrderSummary } from '../core/types' vi.mock('../core/api', () => ({ + downloadInboundCartonLabels: vi.fn(), getPlatformInbound: vi.fn(), listPlatformInbounds: vi.fn(), })) @@ -74,6 +75,7 @@ describe('InboundOrdersView', () => { setActivePinia(createPinia()) vi.mocked(listPlatformInbounds).mockResolvedValue({ records: [summary], page: 1, size: 20, total: 1, pages: 1 }) vi.mocked(getPlatformInbound).mockResolvedValue(detail) + vi.mocked(downloadInboundCartonLabels).mockResolvedValue(new Blob(['pdf'], { type: 'application/pdf' })) vi.mocked(listPlatformTenants).mockResolvedValue({ records: customers, page: 1, size: 200, total: 2, pages: 1 }) vi.mocked(listPlatformWarehouses).mockResolvedValue({ records: [ @@ -171,6 +173,25 @@ describe('InboundOrdersView', () => { wrapper.unmount() }) + it('downloads carton labels from the stable server-side mapping', async () => { + const createObjectURL = vi.fn(() => 'blob:labels') + const revokeObjectURL = vi.fn() + vi.stubGlobal('URL', { createObjectURL, revokeObjectURL }) + const click = vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(() => {}) + const wrapper = mountPage() + await flushPromises() + + await wrapper.findAll('button').find((button) => button.text().includes('打印箱唛'))?.trigger('click') + await flushPromises() + + expect(downloadInboundCartonLabels).toHaveBeenCalledWith('10002', '19001') + expect(createObjectURL).toHaveBeenCalledOnce() + expect(revokeObjectURL).toHaveBeenCalledWith('blob:labels') + expect(click).toHaveBeenCalledOnce() + click.mockRestore() + vi.unstubAllGlobals() + }) + it('uses the app header as the page title and exposes compact accessible status tabs', async () => { const wrapper = mountPage() await flushPromises() diff --git a/src/modules/inbounds/pages/InboundOrdersView.vue b/src/modules/inbounds/pages/InboundOrdersView.vue index 509fa0d6..6a25412e 100644 --- a/src/modules/inbounds/pages/InboundOrdersView.vue +++ b/src/modules/inbounds/pages/InboundOrdersView.vue @@ -1,7 +1,8 @@