From f7166f2ebadad36830cb95a14c7e092acff406ef Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sat, 15 Aug 2026 11:51:18 +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 --- pages/picking/picking.vue | 19 +++++++++++-- styles/pda.scss | 41 +++++++++++++++++++++++++++ tests/picking-evidence-stage.test.mjs | 10 ++++++- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/pages/picking/picking.vue b/pages/picking/picking.vue index 941bd90..d788f2c 100644 --- a/pages/picking/picking.vue +++ b/pages/picking/picking.vue @@ -31,7 +31,12 @@ + + + + + @@ -115,9 +120,10 @@ + - + 装柜证据空仓、半仓、满仓、锁仓及带锁码照 {{ remoteSyncState.label }} @@ -152,7 +158,7 @@ - + {{ summary.pending }} 箱待拣 {{ submitStatusHint }} @@ -363,6 +369,7 @@ incompleteReasons: INCOMPLETE_REASONS, ...getPickingSession(), activeScanField: 'boxCode', + activeStage: 'picking', partialFocused: false, boxDropdownOpen: false, activeOverlay: '', @@ -516,6 +523,13 @@ return false }, methods: { + selectStage(stage) { + if (stage === 'evidence' && !this.loadingStageReady) { + this.showToast('请先完成拣货并刷新任务', 'warning') + return + } + this.activeStage = stage + }, debugEvidence(event, payload = {}) { try { console.info(`[PDA] evidence.${event}`, payload) } catch (_) { /* console may be unavailable on a device */ } }, @@ -692,6 +706,7 @@ this.taskRequestId += 1 this.submitting = false this.currentBoxIndex = index + this.activeStage = 'picking' this.currentBox.inboundId = null this.currentBox.inboundVersion = null this.remoteTaskId = null diff --git a/styles/pda.scss b/styles/pda.scss index 5d58aa9..c131b4a 100644 --- a/styles/pda.scss +++ b/styles/pda.scss @@ -289,6 +289,47 @@ transition: transform 160ms ease-out; } + .stage-switch { + display: flex; + gap: 4px; + margin: 0 12px 10px; + padding: 4px; + border: 1px solid $border; + border-radius: 10px; + background: #eef2f7; + } + + .stage-tab { + flex: 1; + min-height: 42px; + padding: 0 8px; + border: 0; + border-radius: 7px; + color: $text-secondary; + font-size: 13px; + font-weight: 600; + line-height: 42px; + background: transparent; + } + + .stage-tab.active { + color: $primary; + background: #ffffff; + box-shadow: 0 1px 4px rgba(31, 41, 55, 0.12); + } + + .stage-tab.locked { + color: #9aa5b1; + } + + .stage-tab-hint { + display: block; + margin-top: -9px; + font-size: 9px; + font-weight: 400; + line-height: 12px; + } + .box-chevron.open { transform: rotate(180deg); } diff --git a/tests/picking-evidence-stage.test.mjs b/tests/picking-evidence-stage.test.mjs index d4199e0..8b33b01 100644 --- a/tests/picking-evidence-stage.test.mjs +++ b/tests/picking-evidence-stage.test.mjs @@ -5,7 +5,7 @@ import { readFile } from 'node:fs/promises' const page = await readFile(new URL('../pages/picking/picking.vue', import.meta.url), 'utf8') test('loading evidence is mounted only after the current picking task is complete', () => { - assert.match(page, /v-if="loadingStageReady" class="loading-evidence-section"/) + assert.match(page, /v-if="loadingStageReady && activeStage === 'evidence'" class="loading-evidence-section"/) assert.match(page, /isPickingCompleteTask\(task\)[\s\S]*?AWAITING_REVIEW[\s\S]*?COMPLETED/) assert.match(page, /pickingCompleted\(\)[\s\S]*?completedBoxes\[this\.currentBoxIndex\][\s\S]*?isPickingCompleteTask\(this\.remotePick\)/) assert.doesNotMatch(page, /class="loading-evidence-section" v-if="currentBox\.inboundId"/) @@ -33,6 +33,14 @@ test('AWAITING_REVIEW alone cannot mount or request evidence without a server lo assert.doesNotMatch(page, /if \(this\.pickingCompleted\) await this\.loadLoadingEvidence\(\)/) }) +test('picking and evidence are separate operator-selected stages', () => { + assert.match(page, /class="stage-switch" role="tablist"/) + assert.match(page, /@tap="selectStage\('picking'\)"/) + assert.match(page, /@tap="selectStage\('evidence'\)"/) + assert.match(page, /selectStage\(stage\)[\s\S]*?stage === 'evidence'[\s\S]*?!this\.loadingStageReady[\s\S]*?请先完成拣货并刷新任务/) + assert.match(page, /activeStage === 'picking' \|\| !loadingStageReady/) +}) + test('evidence identity is bound to task, inbound, loading plan and container booking', () => { assert.match(page, /captureEvidenceIdentity\(\)[\s\S]*?taskId:[\s\S]*?inboundId:[\s\S]*?loadingPlanId:[\s\S]*?containerBookingId:/) assert.match(page, /isSameEvidenceIdentity\(left, right\)[\s\S]*?taskId[\s\S]*?inboundId[\s\S]*?loadingPlanId[\s\S]*?containerBookingId/)