Release/test #4
@@ -28,7 +28,7 @@
|
||||
<view v-if="isReturnBulk" class="item-list section-gap"><view v-for="group in returnBulkSkuGroups" :key="group.key" class="item-card" :class="{ done: group.remaining === 0 }">
|
||||
<view class="row-head"><view><text class="business-code">{{ group.skuCode }}</text><text class="meta-line">FBA 目的仓:{{ group.destinationFbaWarehouseCode || '—' }}</text></view><text class="status-pill">剩余 {{ group.remaining }} 件</text></view>
|
||||
<view class="metric-row"><view class="metric"><strong>{{ group.expectedPackages }}</strong><text>贴标预报</text></view><view class="metric"><strong>{{ group.relabelledPackages }}</strong><text>已贴</text></view></view>
|
||||
<view class="source-allocation"><text class="source-title">来源托盘{{ isReturnBulk ? '换标数量' : '拆箱数量' }}</text><view v-for="source in group.sources" :key="source.itemId" class="source-row"><text>{{ source.palletCode || '未记录托盘' }}</text><strong>{{ isReturnBulk ? '换标' : '拆箱' }} {{ source.expectedPackages }} 件</strong></view><view class="source-total"><text>合计{{ isReturnBulk ? '换标' : '拆箱' }}</text><strong>{{ group.expectedPackages }} 件</strong></view></view>
|
||||
<view class="source-allocation"><text v-if="isReturnBulk" class="source-title">来源托盘换标数量</text><text v-else class="source-title">来源托盘拆箱数量</text><view v-for="source in group.sources" :key="source.itemId" class="source-row"><text>{{ source.palletCode || '未记录托盘' }}</text><strong>{{ isReturnBulk ? '换标' : '拆箱' }} {{ source.expectedPackages }} 件</strong></view><view class="source-total"><text>合计{{ isReturnBulk ? '换标' : '拆箱' }}</text><strong>{{ group.expectedPackages }} 件</strong></view></view>
|
||||
<view v-if="group.remaining > 0"><input v-model="bulkQuantities[group.key]" class="bulk-quantity" type="number" :placeholder="`本次贴标数量(默认剩余 ${group.remaining} 件)`" /><button class="primary bulk-total-button" :disabled="busy || verifiedReturnSkuKey !== group.key || returnSkuCode.trim().toUpperCase() !== group.skuCode.toUpperCase()" @tap="completeBulkSku(group)">{{ busyAction === 'return-bulk-sku' ? '提交中…' : `登记本次贴标(默认 ${group.remaining} 件)` }}</button></view>
|
||||
</view></view>
|
||||
<view v-if="taskTab === 'carton' && !isReturnBulk" class="section-gap"><ScanTargetInput name="quickCarton" v-model="quickCarton" label="仓库唛头" placeholder="扫描或输入箱唛" :active="activeTarget === 'quick-carton'" @activate="activeTarget = 'quick-carton'" @submit="submitCarton" /><button class="primary" :disabled="busy || !quickCarton.trim()" @tap="submitCarton(quickCarton)">确认本箱</button></view>
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
<view v-if="detailLoading" class="transfer-empty"><text class="empty-title">正在读取转运明细</text><text>请稍候,不要重复选择</text></view>
|
||||
<template v-if="selected && !detailLoading">
|
||||
<view class="operation-detail-heading"><button class="back-to-list" @tap="backToCandidates">‹ 返回待测列表</button><view><text class="operation-detail-title">作业详情</text><text class="operation-detail-subtitle">进入后完成当前转运单的测量、打托和拍照</text></view></view>
|
||||
<view v-if="isInventoryTransfer" class="transfer-success inventory-transfer-panel"><text class="feedback-title">库存转运 · 无需测量</text><text>该单来源于仓库现有库存,不需要重复测量或上传现场照片。请进入托盘作业,按来源托盘执行整托转运、拆托重打,或与相同目的仓合托。</text><button class="transfer-primary" @tap="openPalletOperations">进入托盘作业</button></view>
|
||||
<template v-if="!isInventoryTransfer">
|
||||
<view v-if="isMeasurementComplete" class="transfer-success"><text class="feedback-title">测量已完成</text><text>该转运单已完成 PDA 测量,不再重复进入测量或托盘作业。</text></view>
|
||||
<view v-else-if="isInventoryTransfer" class="transfer-success inventory-transfer-panel"><text class="feedback-title">库存转运 · 无需测量</text><text>该单来源于仓库现有库存,不需要重复测量或上传现场照片。请进入托盘作业,按来源托盘执行整托转运、拆托重打,或与相同目的仓合托。</text><button class="transfer-primary" @tap="openPalletOperations">进入托盘作业</button></view>
|
||||
<template v-if="!isInventoryTransfer && !isMeasurementComplete">
|
||||
<view class="order-summary">
|
||||
<view><text class="summary-eyebrow">当前测量任务</text><text class="summary-no">{{ selected.transferNo }}</text></view>
|
||||
<view class="summary-count"><strong>{{ totalCartons }}</strong><text>实收箱</text></view>
|
||||
@@ -94,8 +95,8 @@ const newPallet = () => ({ key: `${Date.now()}-${Math.random()}`, cartonCount: 0
|
||||
const restoredPallet = (value, index) => ({
|
||||
key: `server-${value.draftId || value.id || index}`,
|
||||
cartonCount: Number(value.cartonCount || 0), lengthCm: value.lengthCm, widthCm: value.widthCm, heightCm: value.heightCm, grossWeightKg: value.grossWeightKg,
|
||||
generated: Boolean(value.palletNo), bound: Boolean(value.boundAt || value.status === 'BOUND'), collapsed: Boolean(value.boundAt || value.status === 'BOUND'),
|
||||
palletNo: String(value.palletNo || ''), fbaWarehouseCode: String(value.fbaWarehouseCode || ''), labelDownloadPath: String(value.labelDownloadPath || ''), bindCode: '', busy: false,
|
||||
generated: Boolean(value.palletNo), bound: Boolean(value.boundAt || value.status === 'BOUND'), collapsed: Boolean(value.boundAt || value.status === 'BOUND'),
|
||||
palletNo: String(value.palletNo || ''), fbaWarehouseCode: String(value.fbaWarehouseCode || ''), labelDownloadPath: String(value.labelDownloadPath || ''), bindCode: String(value.palletNo || ''), busy: false,
|
||||
draftId: value.draftId || value.id, version: value.version
|
||||
})
|
||||
|
||||
@@ -106,7 +107,8 @@ export default {
|
||||
completedDestinationLabel() { return this.destinationLabel({ fbaWarehouseCode: this.completedDestination, destinationType: this.completedDestinationType }) },
|
||||
totalCartons() { return this.pallets.reduce((sum, pallet) => sum + Math.max(0, Number(pallet.cartonCount) || 0), 0) },
|
||||
cartonDifference() { return this.totalCartons - Number(this.selected?.packageCount || 0) },
|
||||
isInventoryTransfer() { return Boolean(this.selected && this.selected.inboundCode && this.selected.inboundCode !== this.selected.transferNo) },
|
||||
isInventoryTransfer() { return Boolean(this.selected && this.selected.status === 'WAIT_PDA_RECEIVING' && this.selected.inboundCode && this.selected.inboundCode !== this.selected.transferNo) },
|
||||
isMeasurementComplete() { return Boolean(this.selected && !['WAIT_PDA_RECEIVING', 'PARTIALLY_RECEIVED'].includes(String(this.selected.status))) },
|
||||
totalVolume() { return this.pallets.reduce((sum, pallet) => sum + this.rawPalletVolume(pallet), 0).toFixed(3) },
|
||||
totalWeight() { return this.pallets.reduce((sum, pallet) => sum + Math.max(0, Number(pallet.grossWeightKg) || 0), 0).toFixed(2) },
|
||||
validationMessage() {
|
||||
@@ -126,7 +128,7 @@ export default {
|
||||
watch: {
|
||||
pallets: { deep: true, handler() { if (!this.submitting) this.pendingKey = '' } }
|
||||
},
|
||||
onShow() { if (requireSession()) { this.user = session.currentUser; restoreWarehouseWork(`${this.user.id}:${this.user.warehouseId}`); this.startScanner(); this.loadCandidates().then(() => { const activeNo = String(warehouseWork.warehouseTransfer.currentNo || ''); const taskNo = this.pendingTaskNo || activeNo; if (this.entryMode === 'work' && taskNo) { const active = this.candidates.find((item) => String(item.transferNo) === taskNo); if (active) { this.pendingTaskNo = ''; void this.select(active) } } }) } },
|
||||
onShow() { if (requireSession()) { this.user = session.currentUser; restoreWarehouseWork(`${this.user.id}:${this.user.warehouseId}`); this.startScanner(); this.loadCandidates().then(() => { const activeNo = String(warehouseWork.warehouseTransfer.currentNo || ''); const taskNo = this.pendingTaskNo || activeNo; if (this.entryMode === 'work' && taskNo) { const active = this.candidates.find((item) => String(item.transferNo) === taskNo); if (active) { const fromExplicitTask = Boolean(this.pendingTaskNo); this.pendingTaskNo = ''; void this.select(active, fromExplicitTask) } } }) } },
|
||||
onLoad(options) { this.entryMode = options?.mode === 'list' ? 'list' : 'work'; this.pendingTaskNo = String(options?.task || '') },
|
||||
onHide() { this.stopScanner() },
|
||||
beforeUnmount() { this.stopScanner() },
|
||||
@@ -163,12 +165,28 @@ export default {
|
||||
catch (error) { this.error = error; pallet.busy = false }
|
||||
},
|
||||
async printDraftPallet(pallet) { if (!pallet.labelDownloadPath) { this.error = new Error('服务端未返回托盘标签下载地址'); return }; await this.openLabelPdf(() => downloadWarehouseTransferPalletLabel(pallet.labelDownloadPath)) },
|
||||
async loadCandidates() { this.loading = true; this.error = null; try { const activeNo = String(warehouseWork.warehouseTransfer.currentNo || ''); this.candidates = (await listWarehouseTransferCandidates()).map((item) => String(item.transferNo) === activeNo && item.status === 'WAIT_PDA_RECEIVING' ? { ...item, status: 'PARTIALLY_RECEIVED' } : item) } catch (e) { this.error = e } finally { this.loading = false } },
|
||||
async select(item) {
|
||||
async loadCandidates() {
|
||||
this.loading = true; this.error = null
|
||||
try {
|
||||
const activeNo = String(warehouseWork.warehouseTransfer.currentNo || '')
|
||||
const measuredStatuses = new Set(['WAIT_PDA_RECEIVING', 'PARTIALLY_RECEIVED'])
|
||||
this.candidates = (await listWarehouseTransferCandidates()).map((item) => String(item.transferNo) === activeNo && item.status === 'WAIT_PDA_RECEIVING' ? { ...item, status: 'PARTIALLY_RECEIVED' } : item)
|
||||
this.candidates = this.candidates.filter((item) => measuredStatuses.has(String(item.status)))
|
||||
// 服务端已完成当前单但设备在提交响应前断网时,本地 currentNo 会遗留。
|
||||
// 候选已成功读取且当前单不再可测,清掉本地锁,允许继续下一票。
|
||||
if (activeNo && !this.candidates.some((item) => String(item.transferNo) === activeNo && measuredStatuses.has(String(item.status)))) {
|
||||
resetWarehouseDomain('warehouseTransfer')
|
||||
}
|
||||
if (this.selected && !this.candidates.some((item) => String(item.transferNo) === String(this.selected.transferNo))) {
|
||||
this.selected = null; this.pallets = [newPallet()]; this.photoFileIds = []; this.photoUrls = {}; this.photoNames = []
|
||||
}
|
||||
} catch (e) { this.error = e } finally { this.loading = false }
|
||||
},
|
||||
async select(item, fromExplicitTask = false) {
|
||||
if (this.detailLoading || this.submitting) return
|
||||
const requestedNo = String(item?.transferNo || '')
|
||||
const activeNo = String(warehouseWork.warehouseTransfer.currentNo || '')
|
||||
if (!activeNo) {
|
||||
if (!activeNo && !fromExplicitTask) {
|
||||
const result = await new Promise((resolve) => uni.showModal({ title: '开始测量', content: `确认开始测量转运单 ${requestedNo} 吗?开始后本设备需先完成该单,才能选择下一单。`, confirmText: '确认开始', cancelText: '取消', success: resolve, fail: () => resolve({ confirm: false }) }))
|
||||
if (!result.confirm) return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user