From b014624fa332fb5430ff484d95b306f68423b013 Mon Sep 17 00:00:00 2001 From: liuyihe <2513762445@qq.com> Date: Fri, 9 Oct 2026 17:28:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/outbound/outbound.vue | 28 +++++++++++++++++++++++++--- tests/fulfillment-workflows.test.mjs | 4 ++-- tests/outbound-lifecycle.test.mjs | 26 ++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/pages/outbound/outbound.vue b/src/pages/outbound/outbound.vue index ee1cf5c..7b120ea 100644 --- a/src/pages/outbound/outbound.vue +++ b/src/pages/outbound/outbound.vue @@ -6,7 +6,7 @@ 出库任务整托扫描托盘码,散箱扫描箱唛;扫描排车业务号会转入“排车拣货” 当前任务出库作业详情 - + 任务号直接恢复;退货整托出库扫托盘码,散箱出库扫箱唛。 @@ -27,12 +27,12 @@ {{ current.taskNo || '—' }}{{ statusLabel(current.status) }}出库单 {{ current.outboundNo || '—' }} · {{ taskType(current) }}{{ plannedPackages }}计划箱数{{ pickedPackages }}已拣箱数{{ remainingPackages }}待拣箱数 - + {{ item.palletNo || '散件出库' }}{{ item.pickedPackages }}/{{ item.plannedPackages }} 箱 {{ lineBusinessCode(position) }}{{ position.inboundCode || '无入仓码' }} · 已拣 {{ position.pickedPackages }} 箱 · 可拣 {{ position.availablePackages }} 箱 - 整托出库请扫描托盘码 {{ item.palletNo }} + 整托出库请扫描托盘号 {{ item.palletNo }} 当前明细缺少可扫码库存业务码,已禁止拣货;请刷新或联系平台确认任务下发。 @@ -68,6 +68,28 @@ components: { PortalHeader, ScanTargetInput }, data() { return { user: session.currentUser, tasks: [], discardTasks: [], current: null, discardCurrent: null, discardTask: null, discardActuals: {}, discardPalletCode: '', discardLoading: false, discardBusy: false, selectedItem: null, selectedPosition: null, selectedScanCode: '', scanCode: '', loading: false, busy: false, busyAction: '', error: null, successMessage: '', bootstrapped: false } }, computed: { + displayItems() { + const items = this.current?.items || [] + if (this.current?.outboundType !== 'RETURN_OUTBOUND') return items + const pallets = new Map() + const rows = [] + for (const item of items) { + if (!item.palletNo) { rows.push(item); continue } + let pallet = pallets.get(item.palletNo) + if (!pallet) { + pallet = { ...item, displayKey: `pallet:${item.palletNo}`, plannedPackages: 0, pickedPackages: 0, positions: [] } + pallets.set(item.palletNo, pallet) + rows.push(pallet) + } + pallet.plannedPackages += Number(item.plannedPackages || 0) + pallet.pickedPackages += Number(item.pickedPackages || 0) + pallet.positions.push(...(item.positions || [])) + } + return rows + }, + hasReturnPallet() { return this.current?.outboundType === 'RETURN_OUTBOUND' && (this.current.items || []).some(item => item.palletNo) }, + scanLabel() { return this.discardCurrent ? '废弃订单托盘码' : this.hasReturnPallet ? '扫描托盘号(退货整托出库)' : '任务号、出库单号、排车单号、托盘号或箱码' }, + scanPlaceholder() { return this.discardCurrent ? '扫描废弃订单对应托盘码' : this.hasReturnPallet ? '扫描托盘号;散箱扫描箱唛' : '扫描任务号 / 出库单号 / 排车单号 / 托盘号 / 箱码' }, recentTaskNo() { return fulfillment.outbound.currentTaskNo || '' }, packages() { return fulfillment.outbound.packages }, plannedPackages() { return (this.current?.items || []).reduce((total, item) => total + item.plannedPackages, 0) }, diff --git a/tests/fulfillment-workflows.test.mjs b/tests/fulfillment-workflows.test.mjs index 00d63c0..348ddac 100644 --- a/tests/fulfillment-workflows.test.mjs +++ b/tests/fulfillment-workflows.test.mjs @@ -66,7 +66,7 @@ test('outbound partial pick submits the selected carton and distinguishes shared assert.deepEqual(outboundPickPayload({ outboundPalletItemId: '13' }, { inventoryPositionId: '23' }, 2).cartonMarks, []) const page = await read('../src/pages/outbound/outbound.vue') assert.match(page, /listOutboundTasks\('PENDING'\)/) - assert.match(page, /:key="item.outboundPalletItemId"/) + assert.match(page, /:key="item.displayKey \|\| item.outboundPalletItemId"/) assert.match(page, /outboundPickPayload\(this.selectedItem, this.selectedPosition, this.packages, this.selectedScanCode\)/) assert.match(page, /pickOutboundTask\(this.current.taskNo, \{ \.\.\.payload, idempotencyKey: key.value \}\)/) assert.match(page, /pickOutboundPallet\(this.current.taskNo, code, \{ idempotencyKey: key.value \}\)/) @@ -78,7 +78,7 @@ test('return outbound preserves its task type and only permits pallet scans for assert.equal(task.outboundType, 'RETURN_OUTBOUND') const page = await read('../src/pages/outbound/outbound.vue') assert.match(page, /this\.current\?\.outboundType === 'RETURN_OUTBOUND' && item\.palletNo/) - assert.match(page, /整托出库请扫描托盘码/) + assert.match(page, /整托出库请扫描托盘号/) const item = { outboundPalletItemId: '12', skuCode: 'SKU-A' } const position = { inventoryPositionId: '', cartonMark: 'RC-1' } assert.deepEqual(outboundPickPayload(item, position, 1, 'SKU-A'), { diff --git a/tests/outbound-lifecycle.test.mjs b/tests/outbound-lifecycle.test.mjs index a77f491..8f86a2e 100644 --- a/tests/outbound-lifecycle.test.mjs +++ b/tests/outbound-lifecycle.test.mjs @@ -18,6 +18,32 @@ function page(overrides = {}) { return { vm, calls } } +test('return pallet rows sum carton counts without changing raw pick lines', () => { + const { vm } = page() + const cartons = Array.from({ length: 5 }, (_, index) => ({ outboundPalletItemId: index + 1, palletNo: 'PALLET', plannedPackages: 1, pickedPackages: index < 3 ? 1 : 0, positions: [] })) + const loose = { outboundPalletItemId: 6, palletNo: '', plannedPackages: 2, pickedPackages: 0, positions: [] } + vm.current = { outboundType: 'RETURN_OUTBOUND', items: [...cartons, loose, { outboundPalletItemId: 7, palletNo: 'OTHER', plannedPackages: 2, pickedPackages: 1, positions: [] }] } + const before = JSON.stringify(vm.current.items) + assert.equal(vm.displayItems.length, 3) + assert.equal(vm.displayItems[0].plannedPackages, 5) + assert.equal(vm.displayItems[0].pickedPackages, 3) + assert.equal(vm.displayItems[1], loose) + assert.equal(vm.displayItems[2].palletNo, 'OTHER') + assert.equal(JSON.stringify(vm.current.items), before) + assert.match(vm.scanLabel, /扫描托盘号/) + assert.match(vm.scanPlaceholder, /扫描托盘号/) + cartons.forEach(item => { item.pickedPackages = 1 }) + assert.equal(vm.displayItems[0].pickedPackages, 5) +}) + +test('other outbound types preserve individual selectable lines', () => { + const { vm } = page() + const items = [{ palletNo: 'PALLET', plannedPackages: 1, pickedPackages: 0, positions: [] }, { palletNo: 'PALLET', plannedPackages: 2, pickedPackages: 0, positions: [] }] + vm.current = { outboundType: 'NORMAL', items } + assert.equal(vm.displayItems, items) + assert.equal(vm.hasReturnPallet, false) +}) + test('completed and cancelled tasks cannot submit pallet picking or task completion', async () => { for (const status of ['COMPLETED', 'CANCELLED']) { const { vm, calls } = page()