适配PDA稳定柜次身份契约
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
<view class="work-content">
|
||||
<view class="box-select-wrap">
|
||||
<button class="box-select-btn" @tap="toggleBoxDropdown">
|
||||
<text>{{ currentBox.boxNo }} · 订单 {{ currentBox.orderNo }}</text>
|
||||
<text>{{ currentBox.boxNo }}<template v-if="currentBox.currentContainerNo"> · 当前柜号 {{ currentBox.currentContainerNo }}</template> · 订单 {{ currentBox.orderNo }}</text>
|
||||
<text class="box-chevron" :class="{ open: boxDropdownOpen }">▼</text>
|
||||
</button>
|
||||
<view v-if="boxDropdownOpen" class="box-dropdown">
|
||||
@@ -328,6 +328,7 @@
|
||||
import { createEvidenceUploadQueue } from '@/utils/evidence-upload-queue.js'
|
||||
import { isOnline } from '@/utils/network.js'
|
||||
import { stableOperationId } from '@/utils/idempotency.js'
|
||||
import { stableTaskOperationIdentity } from '@/utils/task-identity.js'
|
||||
import ScanTargetInput from '@/components/ScanTargetInput.vue'
|
||||
import PopupHeader from '@/components/PopupHeader.vue'
|
||||
|
||||
@@ -452,9 +453,10 @@
|
||||
},
|
||||
onLoad(options = {}) {
|
||||
if (!requireSession()) return
|
||||
if (options.containerNo) {
|
||||
if (options.taskId && (options.cabinetNo || options.containerNo)) {
|
||||
this.boxes = [{
|
||||
boxNo: String(options.containerNo), orderNo: String(options.orderNo || options.inboundCode || ''),
|
||||
boxNo: String(options.cabinetNo || options.containerNo), cabinetNo: String(options.cabinetNo || options.containerNo), currentContainerNo: options.currentContainerNo ? String(options.currentContainerNo) : null, orderNo: String(options.orderNo || options.inboundCode || ''),
|
||||
taskId: String(options.taskId), loadingPlanId: options.loadingPlanId ? String(options.loadingPlanId) : null, containerBookingId: options.containerBookingId ? String(options.containerBookingId) : null,
|
||||
inboundId: options.inboundId ? String(options.inboundId) : null,
|
||||
inboundVersion: options.inboundVersion == null ? null : Number(options.inboundVersion),
|
||||
warehouseId: options.warehouseId ? String(options.warehouseId) : null,
|
||||
@@ -489,7 +491,7 @@
|
||||
},
|
||||
draftIdentity() {
|
||||
const operatorId = session.currentUser?.id || session.currentUser?.userId || session.currentUser?.accountId
|
||||
return { operatorId, taskId: this.remoteTaskId || this.currentBox.taskId || this.currentBox.inboundId, containerNo: this.currentBox.boxNo, warehouseId: this.currentBox.warehouseId || session.currentUser?.warehouseId || session.currentUser?.warehouse }
|
||||
return { operatorId, taskId: this.remoteTaskId || this.currentBox.taskId, loadingPlanId: this.currentBox.loadingPlanId || this.remotePick?.loadingPlanId, containerBookingId: this.currentBox.containerBookingId || this.remotePick?.containerBookingId, warehouseId: this.currentBox.warehouseId || session.currentUser?.warehouseId || session.currentUser?.warehouse }
|
||||
},
|
||||
restoreRemoteDraft() {
|
||||
const restored = restorePickingSession(this.draftIdentity())
|
||||
@@ -672,7 +674,7 @@
|
||||
this.remoteError = ''
|
||||
try {
|
||||
const warehouseId = this.currentBox.warehouseId || session.currentUser?.warehouseId || session.currentUser?.warehouse
|
||||
const task = await getContainerPickingTask(this.currentBox.boxNo, warehouseId)
|
||||
const task = await getContainerPickingTask({ taskId: this.remoteTaskId || this.currentBox.taskId, cabinetNo: this.currentBox.cabinetNo, loadingPlanId: this.currentBox.loadingPlanId, containerNo: this.currentBox.currentContainerNo }, warehouseId)
|
||||
if (!task) throw new Error('未找到当前柜次的拣货任务')
|
||||
const remoteItems = task.items || task.pickItems || task.details || task.lines
|
||||
if (Array.isArray(remoteItems) && remoteItems.length) {
|
||||
@@ -703,7 +705,12 @@
|
||||
this.remoteTaskId = task.taskId ?? task.id
|
||||
if (!this.remoteTaskId) throw new Error('服务端任务缺少 taskId,无法开始拣货')
|
||||
this.assignmentVersion = task.assignmentVersion ?? task.version ?? 0
|
||||
const operationId = `claim-${session.currentUser?.id || 'operator'}-${this.remoteTaskId}-${this.currentBox.boxNo}`
|
||||
this.currentBox.loadingPlanId = task.loadingPlanId
|
||||
this.currentBox.containerBookingId = task.containerBookingId
|
||||
this.currentBox.cabinetNo = task.cabinetNo
|
||||
this.currentBox.boxNo = task.cabinetNo
|
||||
this.currentBox.currentContainerNo = task.currentContainerNo
|
||||
const operationId = `claim-${session.currentUser?.id || 'operator'}-${this.remoteTaskId}-${task.loadingPlanId}-${task.containerBookingId}`
|
||||
const claimed = await claimContainerPickingTask(this.remoteTaskId, this.assignmentVersion, operationId)
|
||||
this.remotePick = normalizePickingTask({ ...task, ...(claimed || {}) })
|
||||
this.pickingVersion = this.remotePick.pickingVersion ?? this.remotePick.version ?? null
|
||||
@@ -937,7 +944,8 @@
|
||||
try {
|
||||
if (!this.remoteTaskId) throw new Error('尚未进入服务端拣货任务,请联网刷新后重试')
|
||||
if (this.pickingVersion === null) throw new Error('缺少拣货版本号 pickingVersion,无法提交')
|
||||
const submitId = this.submitId || stableOperationId('submit', `${session.currentUser?.id || 'operator'}-${this.remoteTaskId}-${this.currentBox.boxNo}`, { itemStates: this.itemStates, partialQuantities: this.partialQuantities, incompleteReason })
|
||||
const operationIdentity = stableTaskOperationIdentity(this.draftIdentity())
|
||||
const submitId = this.submitId || stableOperationId('submit', operationIdentity, { itemStates: this.itemStates, partialQuantities: this.partialQuantities, incompleteReason })
|
||||
this.submitId = submitId
|
||||
const warehouseId = this.currentBox.warehouseId || session.currentUser?.warehouseId || session.currentUser?.warehouse
|
||||
const inventorySnapshot = await getPickingInventorySnapshot(this.remoteTaskId, warehouseId)
|
||||
@@ -950,7 +958,7 @@
|
||||
if (incompleteReason) return { type: 'SKIP', itemId, reason: `${incompleteReason}(提交时确认未拣)`, version: Number(item.version || 0) }
|
||||
return null
|
||||
}).filter(Boolean)
|
||||
await submitContainerPickingBatch({ taskId: this.remoteTaskId, containerNo: this.currentBox.boxNo, version: Number(this.pickingVersion) }, actions, { warehouseId, operationId: submitId, inventorySnapshotToken: inventorySnapshot?.snapshotToken })
|
||||
await submitContainerPickingBatch({ taskId: this.remoteTaskId, loadingPlanId: this.currentBox.loadingPlanId, containerBookingId: this.currentBox.containerBookingId, version: Number(this.pickingVersion) }, actions, { warehouseId, operationId: submitId, inventorySnapshotToken: inventorySnapshot?.snapshotToken })
|
||||
// Legacy inbound completePicking(expectedVersion: Number(this.pickingVersion)) remains adapter-only; cabinet tasks use item actions.
|
||||
} catch (error) {
|
||||
const versionConflict = error.code === 'A0409' || error.statusCode === 409
|
||||
|
||||
@@ -9,11 +9,12 @@
|
||||
<view v-if="error" class="task-error" role="alert">{{ error }}</view>
|
||||
<view v-if="loading" class="task-state">正在加载真实任务...</view>
|
||||
<view v-else-if="!tasks.length && !error" class="task-state">暂无待处理拣货任务</view>
|
||||
<view v-for="task in tasks" :key="task.id || task.inboundId || task.displayNo" class="task-card">
|
||||
<view class="task-card-head"><text class="task-code">{{ task.containerNo || '待分配柜次' }}</text><text class="task-status">{{ statusLabel(task.workflowStatus) }}</text></view>
|
||||
<view v-for="task in tasks" :key="task.taskId" class="task-card">
|
||||
<view class="task-card-head"><text class="task-code">{{ task.cabinetNo || '待分配柜次' }}</text><text class="task-status">{{ statusLabel(task.workflowStatus) }}</text></view>
|
||||
<text v-if="task.currentContainerNo" class="task-order">当前真实柜号 {{ task.currentContainerNo }}</text>
|
||||
<text class="task-order">{{ task.displayNo || '未命名订单' }}</text>
|
||||
<text class="task-meta">{{ task.warehouseName || (task.warehouseId ? `仓库 ${task.warehouseId}` : '缺少仓库信息') }} · 待处理 {{ task.pendingItemCount ?? task.itemCount ?? 0 }} 项</text>
|
||||
<button class="task-enter" :disabled="!task.containerNo || !task.warehouseId" @tap="enterTask(task)">{{ task.containerNo && task.warehouseId ? '进入并开始拣货' : '缺少任务信息' }}</button>
|
||||
<button class="task-enter" :disabled="!isTaskReady(task)" @tap="enterTask(task)">{{ isTaskReady(task) ? '进入并开始拣货' : '任务暂不可进入' }}</button>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="toast.visible" class="app-toast" :class="toast.type" role="status">{{ toast.message }}</view>
|
||||
@@ -34,19 +35,20 @@
|
||||
onUnload() { if (this._stopNetwork) this._stopNetwork(); clearTimeout(this._toastTimer) },
|
||||
methods: {
|
||||
statusLabel(status) { return status === 'IN_PROGRESS' ? '拣货中' : '待领取' },
|
||||
isTaskReady(task) { return Boolean(task.taskId && task.loadingPlanId && task.containerBookingId && task.cabinetNo && task.warehouseId && task.taskStatus === 'LOADING' && ['UNASSIGNED', 'IN_PROGRESS'].includes(task.workflowStatus)) },
|
||||
async loadTasks() {
|
||||
if (!isOnline()) { this.error = '当前网络不可用,请联网后刷新'; return }
|
||||
this.loading = true; this.error = ''
|
||||
try {
|
||||
const result = await listLoadingOrders({ page: 1, size: 50 })
|
||||
this.tasks = (result.records || []).filter((task) => task.containerNo || task.taskId || task.inboundId)
|
||||
this.tasks = (result.records || []).filter((task) => task.taskId)
|
||||
} catch (error) {
|
||||
this.error = error.network ? '当前网络不可用,请联网后刷新' : (error.message || '任务加载失败')
|
||||
} finally { this.loading = false }
|
||||
},
|
||||
enterTask(task) {
|
||||
if (!task.containerNo || !task.warehouseId) { this.showToast('任务缺少柜号或仓库标识,无法开始', 'error'); return }
|
||||
uni.navigateTo({ url: `/pages/picking/picking?containerNo=${encodeURIComponent(task.containerNo)}&warehouseId=${encodeURIComponent(task.warehouseId)}&inboundId=${encodeURIComponent(task.inboundId || '')}&inboundVersion=${encodeURIComponent(task.inboundVersion ?? '')}&tenantId=${encodeURIComponent(task.tenantId || '')}&taskId=${encodeURIComponent(task.taskId || '')}&orderNo=${encodeURIComponent(task.displayNo || '')}` })
|
||||
if (!this.isTaskReady(task)) { this.showToast('任务尚未满足后端进入条件', 'error'); return }
|
||||
uni.navigateTo({ url: `/pages/picking/picking?cabinetNo=${encodeURIComponent(task.cabinetNo)}¤tContainerNo=${encodeURIComponent(task.currentContainerNo || '')}&loadingPlanId=${encodeURIComponent(task.loadingPlanId)}&containerBookingId=${encodeURIComponent(task.containerBookingId)}&warehouseId=${encodeURIComponent(task.warehouseId)}&taskId=${encodeURIComponent(task.taskId)}&orderNo=${encodeURIComponent(task.displayNo || '')}` })
|
||||
},
|
||||
showToast(message, type) { clearTimeout(this._toastTimer); this.toast = { visible: true, message, type }; this._toastTimer = setTimeout(() => { this.toast.visible = false }, 2200) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user