优化
This commit is contained in:
@@ -31,7 +31,12 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="stage-switch" role="tablist" aria-label="作业阶段">
|
||||||
|
<button class="stage-tab" :class="{ active: activeStage === 'picking' }" role="tab" :aria-selected="activeStage === 'picking'" @tap="selectStage('picking')">拣货作业</button>
|
||||||
|
<button class="stage-tab" :class="{ active: activeStage === 'evidence', locked: !loadingStageReady }" role="tab" :aria-selected="activeStage === 'evidence'" :aria-disabled="!loadingStageReady" @tap="selectStage('evidence')">装柜取证<text v-if="!loadingStageReady" class="stage-tab-hint">完成拣货后开放</text></button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="activeStage === 'picking' || !loadingStageReady" class="picking-stage">
|
||||||
<view class="scan-section">
|
<view class="scan-section">
|
||||||
<view class="scan-row">
|
<view class="scan-row">
|
||||||
<ScanTargetInput v-model="scanValue" name="boxCode" label="箱码扫码框" placeholder="扫描或输入箱唛标签码" :active="activeScanField === 'boxCode'" @activate="setScanTarget" @submit="handleManualSubmit" />
|
<ScanTargetInput v-model="scanValue" name="boxCode" label="箱码扫码框" placeholder="扫描或输入箱唛标签码" :active="activeScanField === 'boxCode'" @activate="setScanTarget" @submit="handleManualSubmit" />
|
||||||
@@ -115,9 +120,10 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="loadingStageReady" class="loading-evidence-section">
|
<view v-if="loadingStageReady && activeStage === 'evidence'" class="loading-evidence-section">
|
||||||
<view class="section-heading-row">
|
<view class="section-heading-row">
|
||||||
<view><text class="section-title">装柜证据</text><text class="section-subtitle">空仓、半仓、满仓、锁仓及带锁码照</text></view>
|
<view><text class="section-title">装柜证据</text><text class="section-subtitle">空仓、半仓、满仓、锁仓及带锁码照</text></view>
|
||||||
<text class="sync-state" :class="remoteSyncState.tone">{{ remoteSyncState.label }}</text>
|
<text class="sync-state" :class="remoteSyncState.tone">{{ remoteSyncState.label }}</text>
|
||||||
@@ -152,7 +158,7 @@
|
|||||||
<button class="evidence-retry-btn" :disabled="remoteLoading" @tap="refreshTask">刷新任务</button>
|
<button class="evidence-retry-btn" :disabled="remoteLoading" @tap="refreshTask">刷新任务</button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="submit-section">
|
<view v-if="activeStage === 'picking' || !loadingStageReady" class="submit-section">
|
||||||
<view class="submit-info">
|
<view class="submit-info">
|
||||||
<view class="submit-pending"><text class="submit-pending-number">{{ summary.pending }}</text><text class="submit-pending-label"> 箱待拣</text></view>
|
<view class="submit-pending"><text class="submit-pending-number">{{ summary.pending }}</text><text class="submit-pending-label"> 箱待拣</text></view>
|
||||||
<text class="submit-status-hint">{{ submitStatusHint }}</text>
|
<text class="submit-status-hint">{{ submitStatusHint }}</text>
|
||||||
@@ -363,6 +369,7 @@
|
|||||||
incompleteReasons: INCOMPLETE_REASONS,
|
incompleteReasons: INCOMPLETE_REASONS,
|
||||||
...getPickingSession(),
|
...getPickingSession(),
|
||||||
activeScanField: 'boxCode',
|
activeScanField: 'boxCode',
|
||||||
|
activeStage: 'picking',
|
||||||
partialFocused: false,
|
partialFocused: false,
|
||||||
boxDropdownOpen: false,
|
boxDropdownOpen: false,
|
||||||
activeOverlay: '',
|
activeOverlay: '',
|
||||||
@@ -516,6 +523,13 @@
|
|||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
selectStage(stage) {
|
||||||
|
if (stage === 'evidence' && !this.loadingStageReady) {
|
||||||
|
this.showToast('请先完成拣货并刷新任务', 'warning')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.activeStage = stage
|
||||||
|
},
|
||||||
debugEvidence(event, payload = {}) {
|
debugEvidence(event, payload = {}) {
|
||||||
try { console.info(`[PDA] evidence.${event}`, payload) } catch (_) { /* console may be unavailable on a device */ }
|
try { console.info(`[PDA] evidence.${event}`, payload) } catch (_) { /* console may be unavailable on a device */ }
|
||||||
},
|
},
|
||||||
@@ -692,6 +706,7 @@
|
|||||||
this.taskRequestId += 1
|
this.taskRequestId += 1
|
||||||
this.submitting = false
|
this.submitting = false
|
||||||
this.currentBoxIndex = index
|
this.currentBoxIndex = index
|
||||||
|
this.activeStage = 'picking'
|
||||||
this.currentBox.inboundId = null
|
this.currentBox.inboundId = null
|
||||||
this.currentBox.inboundVersion = null
|
this.currentBox.inboundVersion = null
|
||||||
this.remoteTaskId = null
|
this.remoteTaskId = null
|
||||||
|
|||||||
@@ -289,6 +289,47 @@
|
|||||||
transition: transform 160ms ease-out;
|
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 {
|
.box-chevron.open {
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { readFile } from 'node:fs/promises'
|
|||||||
const page = await readFile(new URL('../pages/picking/picking.vue', import.meta.url), 'utf8')
|
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', () => {
|
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, /isPickingCompleteTask\(task\)[\s\S]*?AWAITING_REVIEW[\s\S]*?COMPLETED/)
|
||||||
assert.match(page, /pickingCompleted\(\)[\s\S]*?completedBoxes\[this\.currentBoxIndex\][\s\S]*?isPickingCompleteTask\(this\.remotePick\)/)
|
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"/)
|
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\(\)/)
|
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', () => {
|
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, /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/)
|
assert.match(page, /isSameEvidenceIdentity\(left, right\)[\s\S]*?taskId[\s\S]*?inboundId[\s\S]*?loadingPlanId[\s\S]*?containerBookingId/)
|
||||||
|
|||||||
Reference in New Issue
Block a user