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()