feat(pda): prefer business identifiers
This commit is contained in:
+30
-27
@@ -14,7 +14,7 @@
|
||||
<view class="work-content" :class="{ 'evidence-active': activeStage === 'evidence' }">
|
||||
<view class="box-select-wrap">
|
||||
<button class="box-select-btn" @tap="toggleBoxDropdown">
|
||||
<text class="box-select-summary">集装箱号 {{ currentBox.currentContainerNo || '同步中' }} · 柜次号 {{ currentBox.cabinetNo || '同步中' }} · 订单 {{ currentBox.orderNo }}</text>
|
||||
<text class="box-select-summary">集装箱号 {{ displayBusinessValue(currentBox.currentContainerNo) }} · 柜次号 {{ displayBusinessValue(currentBox.cabinetNo) }} · {{ businessReference(currentBox) }}</text>
|
||||
<text class="box-chevron" :class="{ open: boxDropdownOpen }">▼</text>
|
||||
</button>
|
||||
<view v-if="boxDropdownOpen" class="box-dropdown">
|
||||
@@ -25,7 +25,7 @@
|
||||
:class="{ active: index === currentBoxIndex, completed: completedBoxes[index] }"
|
||||
@tap="requestBoxSwitch(index)"
|
||||
>
|
||||
<view><text class="box-option-number">{{ box.currentContainerNo || '集装箱号同步中' }}</text><text class="box-option-order">柜次号 {{ box.cabinetNo || '同步中' }} · {{ box.orderNo }}</text></view>
|
||||
<view><text class="box-option-number">集装箱号 {{ displayBusinessValue(box.currentContainerNo) }}</text><text class="box-option-order">柜次号 {{ displayBusinessValue(box.cabinetNo) }} · {{ businessReference(box) }}</text></view>
|
||||
<text v-if="completedBoxes[index]" class="box-option-state">已完成</text>
|
||||
<text v-else-if="hasBoxDraft(index)" class="box-option-state draft">有草稿</text>
|
||||
</view>
|
||||
@@ -78,7 +78,7 @@
|
||||
:class="itemState(item)"
|
||||
>
|
||||
<view class="pick-item-row1">
|
||||
<text class="pick-item-sku">{{ item.inboundCode || item.orderNo || '箱级拣货明细' }}</text>
|
||||
<text class="pick-item-sku">{{ itemBusinessReference(item) }}</text>
|
||||
<view class="pick-item-meta">
|
||||
<text v-if="itemState(item) === ITEM_STATUS.PICKED" class="pick-status-tag tag-picked">已拣 ✓</text>
|
||||
<text v-else-if="itemState(item) === ITEM_STATUS.PARTIAL" class="pick-status-tag tag-partial">
|
||||
@@ -190,7 +190,7 @@
|
||||
@tap="selectBoxFromList(entry)"
|
||||
>
|
||||
<view class="box-list-info">
|
||||
<text class="box-list-number">{{ entry.box.boxNo }}{{ entry.index === currentBoxIndex ? '(当前)' : '' }}</text>
|
||||
<text class="box-list-number">集装箱号 {{ displayBusinessValue(entry.box.currentContainerNo || entry.box.boxNo) }}{{ entry.index === currentBoxIndex ? '(当前)' : '' }}</text>
|
||||
<text class="box-list-detail">{{ boxListDetail(entry) }}</text>
|
||||
</view>
|
||||
<text class="box-list-tag" :class="boxListType === 'done' ? 'box-list-tag-done' : 'box-list-tag-pending'">
|
||||
@@ -299,7 +299,7 @@
|
||||
<view class="complete-modal" role="dialog" aria-modal="true" aria-label="拣货完成" @tap.stop>
|
||||
<PopupHeader title="拣货完成" @close="closeOverlay" />
|
||||
<view class="complete-icon">✓</view>
|
||||
<text class="complete-desc">集装箱号 {{ currentBox.currentContainerNo }} · 柜次号 {{ currentBox.cabinetNo }} · 订单 {{ currentBox.orderNo }}</text>
|
||||
<text class="complete-desc">集装箱号 {{ displayBusinessValue(currentBox.currentContainerNo) }} · 柜次号 {{ displayBusinessValue(currentBox.cabinetNo) }} · {{ businessReference(currentBox) }}</text>
|
||||
<view class="complete-evidence-status">
|
||||
<text>装柜照片已拍 {{ evidenceCapturedTypeCount }}/{{ evidenceSlots.length }} 类</text>
|
||||
<text>{{ sealNo ? '封签号已填写' : '封签号未填写' }}</text>
|
||||
@@ -347,6 +347,7 @@
|
||||
import { stableOperationId } from '@/utils/idempotency.js'
|
||||
import { stableTaskOperationIdentity } from '@/utils/task-identity.js'
|
||||
import { COMPLETION_PHASE, resolveCompletionPhase, shouldReconcileCompletion } from '@/utils/loading-completion-state.js'
|
||||
import { businessReference, displayBusinessValue, formatApiError, sanitizeUserMessage } from '@/utils/user-facing.js'
|
||||
import ScanTargetInput from '@/components/ScanTargetInput.vue'
|
||||
import PopupHeader from '@/components/PopupHeader.vue'
|
||||
|
||||
@@ -396,7 +397,7 @@
|
||||
},
|
||||
computed: {
|
||||
currentBox() {
|
||||
return this.boxes[this.currentBoxIndex] || { boxNo: '', orderNo: '', items: [] }
|
||||
return this.boxes[this.currentBoxIndex] || { boxNo: '', orderNo: '', inboundCode: '', items: [] }
|
||||
},
|
||||
summary() {
|
||||
return getPickSummary(this.currentBox.items, this.itemStates, this.partialQuantities)
|
||||
@@ -519,7 +520,7 @@
|
||||
// canonical server detail decides whether this task is complete.
|
||||
this.completedBoxes = {}
|
||||
this.boxes = [{
|
||||
boxNo: '同步中', cabinetNo: null, currentContainerNo: null, orderNo: '',
|
||||
boxNo: '', cabinetNo: null, currentContainerNo: null, orderNo: '', inboundCode: '',
|
||||
taskId: String(options.taskId), loadingPlanId: null, containerBookingId: null,
|
||||
inboundId: null, inboundVersion: null,
|
||||
warehouseId: options.warehouseId ? String(options.warehouseId) : null,
|
||||
@@ -561,6 +562,13 @@
|
||||
return false
|
||||
},
|
||||
methods: {
|
||||
displayBusinessValue,
|
||||
businessReference,
|
||||
itemBusinessReference(item) {
|
||||
if (String(item?.inboundCode ?? '').trim()) return `入仓码 ${item.inboundCode}`
|
||||
if (String(item?.orderNo ?? '').trim()) return `订单号 ${item.orderNo}`
|
||||
return '业务编号未关联'
|
||||
},
|
||||
isSelectableTask(task) {
|
||||
return Boolean(task?.recordStatus === 'ACTIVE'
|
||||
&& !task?.mergedIntoContainerBookingId
|
||||
@@ -575,10 +583,11 @@
|
||||
},
|
||||
boxFromTask(task, existing = null) {
|
||||
return {
|
||||
boxNo: String(task.currentContainerNo || existing?.boxNo || task.cabinetNo || '同步中'),
|
||||
boxNo: String(task.currentContainerNo || existing?.boxNo || ''),
|
||||
cabinetNo: task.cabinetNo ? String(task.cabinetNo) : (existing?.cabinetNo || null),
|
||||
currentContainerNo: task.currentContainerNo ? String(task.currentContainerNo) : (existing?.currentContainerNo || null),
|
||||
orderNo: String(task.displayNo || task.orderNo || existing?.orderNo || ''),
|
||||
orderNo: String(task.orderNo || existing?.orderNo || ''),
|
||||
inboundCode: String(task.inboundCode || existing?.inboundCode || ''),
|
||||
taskId: String(task.taskId),
|
||||
loadingPlanId: task.loadingPlanId || existing?.loadingPlanId || null,
|
||||
containerBookingId: task.containerBookingId || existing?.containerBookingId || null,
|
||||
@@ -647,14 +656,7 @@
|
||||
return String(error?.code || '') === 'A0409' || Number(error?.statusCode) === 409
|
||||
},
|
||||
remoteFailureMessage(error, fallback = '操作失败') {
|
||||
const raw = String(error?.message || '').trim()
|
||||
const message = /^internal server error$/i.test(raw)
|
||||
? '服务端处理异常,请联系管理员'
|
||||
: (raw || fallback)
|
||||
const code = String(error?.code || '').trim()
|
||||
const reference = String(error?.requestId || error?.traceId || '').trim()
|
||||
const meta = [code ? `错误码:${code}` : '', reference ? `请求编号:${reference}` : ''].filter(Boolean)
|
||||
return meta.length ? `${message}(${meta.join(';')})` : message
|
||||
return formatApiError(error, fallback)
|
||||
},
|
||||
async refreshAfterTaskConflict(message) {
|
||||
const requestedTaskId = this.remoteTaskId || this.currentBox.taskId
|
||||
@@ -1118,7 +1120,8 @@
|
||||
const firstItem = this.currentBox.items[0]
|
||||
const evidenceItem = this.currentBox.items.find((item) => String(item.inboundId || '') === String(task.inboundId))
|
||||
if (!evidenceItem) throw new Error('任务明细与入库单关联不一致,请返回刷新')
|
||||
this.currentBox.orderNo = firstItem.orderNo || firstItem.inboundCode || this.currentBox.orderNo
|
||||
this.currentBox.orderNo = firstItem.orderNo || task.orderNo || this.currentBox.orderNo
|
||||
this.currentBox.inboundCode = firstItem.inboundCode || task.inboundCode || this.currentBox.inboundCode
|
||||
this.currentBox.inboundId = task.inboundId
|
||||
this.currentBox.tenantId = evidenceItem.tenantId || null
|
||||
const serverStates = createItemStates(this.currentBox.items)
|
||||
@@ -1209,7 +1212,7 @@
|
||||
await this.flushPendingEvidence()
|
||||
} catch (error) {
|
||||
if (!this.isEvidenceContextActive(contextId, identity)) return
|
||||
this.remoteError = error.network ? '网络失败,装柜证据未加载,请刷新重试' : (error.message || '装柜证据加载失败')
|
||||
this.remoteError = error.network ? '网络失败,装柜证据未加载,请刷新重试' : this.remoteFailureMessage(error, '装柜证据加载失败')
|
||||
}
|
||||
},
|
||||
async loadEvidencePreviews(contextId, identity) {
|
||||
@@ -1348,10 +1351,10 @@
|
||||
} catch (error) {
|
||||
if (!this.isEvidenceContextActive(contextId, identity)) return
|
||||
if (this.isTaskConflict(error)) {
|
||||
await this.refreshAfterTaskConflict(error.message || '任务内容已更新,请完成新增待拣项后重试')
|
||||
await this.refreshAfterTaskConflict(sanitizeUserMessage(error.message, '任务内容已更新,请完成新增待拣项后重试'))
|
||||
return
|
||||
}
|
||||
this.remoteError = error.network ? '网络失败,证据未提交,请重试' : (error.message || '证据保存失败')
|
||||
this.remoteError = error.network ? '网络失败,证据未提交,请重试' : this.remoteFailureMessage(error, '证据保存失败')
|
||||
this.showToast('证据保存失败', 'error')
|
||||
}
|
||||
},
|
||||
@@ -1385,10 +1388,10 @@
|
||||
} catch (error) {
|
||||
if (!this.isEvidenceContextActive(contextId, identity)) return
|
||||
if (this.isTaskConflict(error)) {
|
||||
await this.refreshAfterTaskConflict(error.message || '任务内容已更新,请刷新后重试')
|
||||
await this.refreshAfterTaskConflict(sanitizeUserMessage(error.message, '任务内容已更新,请刷新后重试'))
|
||||
return
|
||||
}
|
||||
this.remoteError = error.network ? '网络失败,照片未作废,请重试' : (error.message || '照片作废失败')
|
||||
this.remoteError = error.network ? '网络失败,照片未作废,请重试' : this.remoteFailureMessage(error, '照片作废失败')
|
||||
this.showToast('照片作废失败', 'error')
|
||||
}
|
||||
},
|
||||
@@ -1445,7 +1448,7 @@
|
||||
return
|
||||
}
|
||||
if (this.isTaskConflict(error)) {
|
||||
await this.refreshAfterTaskConflict(error.message || '订舱、装柜关联或证据状态已变化,请刷新后重试')
|
||||
await this.refreshAfterTaskConflict(sanitizeUserMessage(error.message, '订舱、装柜关联或证据状态已变化,请刷新后重试'))
|
||||
return
|
||||
}
|
||||
this.debugSubmit('complete.error', { message: error.message || '', code: error.code || '', statusCode: error.statusCode || '', requestIdFromServer: error.requestId || '', traceId: error.traceId || '' })
|
||||
@@ -1562,11 +1565,11 @@
|
||||
const processed = draft
|
||||
? Object.values(draft.itemStates).filter((status) => status !== ITEM_STATUS.PENDING).length
|
||||
: 0
|
||||
return `${entry.box.orderNo} · 已处理${processed}件 · 待拣${entry.box.items.length - processed}件`
|
||||
return `${businessReference(entry.box)} · 已处理${processed}件 · 待拣${entry.box.items.length - processed}件`
|
||||
}
|
||||
const picked = entry.box.items.filter((item) => item.finalState === ITEM_STATUS.PICKED).length
|
||||
const partial = entry.box.items.filter((item) => item.finalState === ITEM_STATUS.PARTIAL).length
|
||||
return `${entry.box.orderNo} · 拣出${picked}件${partial ? ` · 部分拣${partial}件` : ''}`
|
||||
return `${businessReference(entry.box)} · 拣出${picked}件${partial ? ` · 部分拣${partial}件` : ''}`
|
||||
},
|
||||
selectBoxFromList(entry) {
|
||||
if (this.boxListType === 'done' || entry.index === this.currentBoxIndex) return
|
||||
@@ -1651,7 +1654,7 @@
|
||||
await this.refreshAfterTaskConflict(conflictMessage)
|
||||
return
|
||||
}
|
||||
this.remoteError = error.network ? '网络失败,拣货完成未提交,请重试' : (error.message || '拣货完成失败')
|
||||
this.remoteError = error.network ? '网络失败,拣货完成未提交,请重试' : this.remoteFailureMessage(error, '拣货完成失败')
|
||||
this.showToast('拣货完成未提交,请查看错误提示', 'error')
|
||||
return
|
||||
} finally { this.submitting = false }
|
||||
|
||||
Reference in New Issue
Block a user