优化
This commit is contained in:
@@ -1127,7 +1127,7 @@
|
|||||||
const serverPartialQuantities = {}
|
const serverPartialQuantities = {}
|
||||||
this.currentBox.items.forEach((item) => {
|
this.currentBox.items.forEach((item) => {
|
||||||
if (item.itemStatus === 'PICKED') serverStates[item.id] = ITEM_STATUS.PICKED
|
if (item.itemStatus === 'PICKED') serverStates[item.id] = ITEM_STATUS.PICKED
|
||||||
else if (item.itemStatus === 'PARTIAL') {
|
else if (item.itemStatus === 'PICKING' || item.itemStatus === 'PARTIAL') {
|
||||||
serverStates[item.id] = ITEM_STATUS.PARTIAL
|
serverStates[item.id] = ITEM_STATUS.PARTIAL
|
||||||
serverPartialQuantities[item.id] = Number(item.pickedPackageCount ?? item.finalPickedPackageCount ?? 0)
|
serverPartialQuantities[item.id] = Number(item.pickedPackageCount ?? item.finalPickedPackageCount ?? 0)
|
||||||
} else if (item.itemStatus === 'SKIPPED') serverStates[item.id] = ITEM_STATUS.SKIPPED
|
} else if (item.itemStatus === 'SKIPPED') serverStates[item.id] = ITEM_STATUS.SKIPPED
|
||||||
@@ -1529,6 +1529,64 @@
|
|||||||
this.showToast(`已部分拣货:${value}/${item.qty} ${item.unit}`, 'success')
|
this.showToast(`已部分拣货:${value}/${item.qty} ${item.unit}`, 'success')
|
||||||
this.persistSession()
|
this.persistSession()
|
||||||
},
|
},
|
||||||
|
async submitImmediateItemAction(item, action, payload = {}) {
|
||||||
|
if (this.submitting) { this.showToast('上一笔拣货正在提交,请稍候', 'warning'); return false }
|
||||||
|
if (!this.remoteTaskId || !this.currentBox.warehouseId || this.pickingVersion === null) {
|
||||||
|
this.showToast('任务状态尚未同步,请刷新重试', 'warning')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const itemId = item.taskItemId ?? item.remoteItemId ?? item.id
|
||||||
|
const identity = stableTaskOperationIdentity(this.draftIdentity())
|
||||||
|
const operationId = stableOperationId(`item-${action.toLowerCase()}`, identity, {
|
||||||
|
itemId, itemVersion: item.version, taskVersion: this.pickingVersion, ...payload
|
||||||
|
})
|
||||||
|
const common = { warehouseId: this.currentBox.warehouseId, version: Number(item.version || 0), operationId }
|
||||||
|
this.submitting = true
|
||||||
|
this.remoteError = ''
|
||||||
|
try {
|
||||||
|
let task
|
||||||
|
if (action === 'PICK') task = await pickContainerItem(this.remoteTaskId, itemId, { ...common, pickedPackageCount: payload.pickedPackageCount })
|
||||||
|
else if (action === 'PARTIAL') task = await partialContainerItem(this.remoteTaskId, itemId, { ...common, finalPickedPackageCount: payload.finalPickedPackageCount })
|
||||||
|
else if (action === 'SKIP') task = await skipContainerItem(this.remoteTaskId, itemId, { ...common, reason: payload.reason })
|
||||||
|
else task = await pickContainerPallet(this.remoteTaskId, { warehouseId: this.currentBox.warehouseId, palletNo: payload.palletNo, expectedTaskVersion: Number(this.pickingVersion), operationId })
|
||||||
|
this.applyImmediateTaskResult(task)
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
if (this.isTaskConflict(error)) await this.refreshAfterTaskConflict(sanitizeUserMessage(error.message, '装柜明细已变化,请刷新后重试'))
|
||||||
|
else {
|
||||||
|
this.remoteError = error.network ? '网络失败,本次拣货未提交' : this.remoteFailureMessage(error, '拣货提交失败')
|
||||||
|
this.showToast('拣货未提交,请重试', 'error')
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
} finally {
|
||||||
|
this.submitting = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
applyImmediateTaskResult(result) {
|
||||||
|
if (!result) return
|
||||||
|
const task = normalizePickingTask({ ...this.remotePick, ...result })
|
||||||
|
this.remotePick = task
|
||||||
|
this.pickingVersion = task.pickingVersion ?? task.version ?? this.pickingVersion
|
||||||
|
const remoteItems = Array.isArray(result.items) ? result.items : []
|
||||||
|
const byId = new Map(remoteItems.map((item) => [String(item.id ?? item.itemId), item]))
|
||||||
|
this.currentBox.items = this.currentBox.items.map((item) => {
|
||||||
|
const remote = byId.get(String(item.taskItemId ?? item.remoteItemId ?? item.id))
|
||||||
|
return remote ? { ...item, ...remote, id: item.id, taskItemId: remote.id ?? remote.itemId ?? item.taskItemId } : item
|
||||||
|
})
|
||||||
|
const nextStates = { ...this.itemStates }
|
||||||
|
const nextPartial = { ...this.partialQuantities }
|
||||||
|
this.currentBox.items.forEach((item) => {
|
||||||
|
const count = Number(item.pickedPackageCount || 0)
|
||||||
|
if (item.itemStatus === 'PICKED') nextStates[item.id] = ITEM_STATUS.PICKED
|
||||||
|
else if (item.itemStatus === 'PICKING' || item.itemStatus === 'PARTIAL') {
|
||||||
|
nextStates[item.id] = ITEM_STATUS.PARTIAL
|
||||||
|
nextPartial[item.id] = count
|
||||||
|
} else if (item.itemStatus === 'SKIPPED') nextStates[item.id] = ITEM_STATUS.SKIPPED
|
||||||
|
})
|
||||||
|
this.itemStates = nextStates
|
||||||
|
this.partialQuantities = nextPartial
|
||||||
|
this.evidenceIdentity = this.captureEvidenceIdentity()
|
||||||
|
},
|
||||||
availablePickQuantity(item) {
|
availablePickQuantity(item) {
|
||||||
if (!item) return null
|
if (!item) return null
|
||||||
if (item.locationAvailable === false || item.locationStatus === 'DISABLED') return 0
|
if (item.locationAvailable === false || item.locationStatus === 'DISABLED') return 0
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ test('picking scan results use the shared success and error audio feedback', asy
|
|||||||
assert.match(audio, /export function playErrorSound\(\)/)
|
assert.match(audio, /export function playErrorSound\(\)/)
|
||||||
assert.match(picking, /import \{ playErrorSound, playSuccessSound \} from '@\/utils\/audio-feedback\.js'/)
|
assert.match(picking, /import \{ playErrorSound, playSuccessSound \} from '@\/utils\/audio-feedback\.js'/)
|
||||||
assert.match(picking, /result\.type === 'unknown'[\s\S]*?playErrorSound\(\)/)
|
assert.match(picking, /result\.type === 'unknown'[\s\S]*?playErrorSound\(\)/)
|
||||||
assert.match(picking, /playSuccessSound\(\)[\s\S]*?this\.pickScannedBox\(result\.item, value\)/)
|
assert.match(picking, /await this\.pickScannedBox\(result\.item, value\)[\s\S]*?if \(submitted\) playSuccessSound\(\)/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('reusable scan target input separates field selection from page-level broadcast handling', async () => {
|
test('reusable scan target input separates field selection from page-level broadcast handling', async () => {
|
||||||
|
|||||||
@@ -109,6 +109,8 @@ test('PDA cabinet picking adapter claims online and submits one atomic batch', (
|
|||||||
assert.doesNotMatch(source, /query\.push\(`cabinetNo=/)
|
assert.doesNotMatch(source, /query\.push\(`cabinetNo=/)
|
||||||
assert.doesNotMatch(source, /query\.push\(`loadingPlanId=/)
|
assert.doesNotMatch(source, /query\.push\(`loadingPlanId=/)
|
||||||
assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\/claim/)
|
assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\/claim/)
|
||||||
|
assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\/items\/\$\{encodeURIComponent\(itemId\)\}\/\$\{path\}/)
|
||||||
|
assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\/pallets\/pick/)
|
||||||
assert.match(source, /tasks\/\$\{encodeURIComponent\(task\.taskId\)\}\/batch/)
|
assert.match(source, /tasks\/\$\{encodeURIComponent\(task\.taskId\)\}\/batch/)
|
||||||
assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\/inventory-snapshot\?warehouseId=/)
|
assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\/inventory-snapshot\?warehouseId=/)
|
||||||
assert.match(source, /submitContainerPickingBatch/)
|
assert.match(source, /submitContainerPickingBatch/)
|
||||||
@@ -116,6 +118,12 @@ test('PDA cabinet picking adapter claims online and submits one atomic batch', (
|
|||||||
assert.match(source, /Math\.imul\(hash, 16777619\)/)
|
assert.match(source, /Math\.imul\(hash, 16777619\)/)
|
||||||
assert.match(source, /slice\(0, 128\)/)
|
assert.match(source, /slice\(0, 128\)/)
|
||||||
assert.match(page, /claimContainerPickingTask\(/)
|
assert.match(page, /claimContainerPickingTask\(/)
|
||||||
|
assert.match(page, /submitImmediateItemAction\(item, 'PICK'/)
|
||||||
|
assert.match(page, /submitImmediateItemAction\(item, 'PARTIAL'/)
|
||||||
|
assert.match(page, /submitImmediateItemAction\(item, 'SKIP'/)
|
||||||
|
assert.match(page, /submitImmediateItemAction\(item, 'PICK_PALLET'/)
|
||||||
|
assert.match(page, /item\.itemStatus === 'PICKING' \|\| item\.itemStatus === 'PARTIAL'/)
|
||||||
|
assert.doesNotMatch(page, /@tap="undoItem\(item\.id\)"/)
|
||||||
assert.match(page, /submitContainerPickingBatch\(/)
|
assert.match(page, /submitContainerPickingBatch\(/)
|
||||||
assert.match(source, /palletNo: action\.type === 'PICK_PALLET' \? action\.palletNo : null/)
|
assert.match(source, /palletNo: action\.type === 'PICK_PALLET' \? action\.palletNo : null/)
|
||||||
assert.match(page, /type: 'PICK_PALLET'[\s\S]*?palletNo: item\.palletNo/)
|
assert.match(page, /type: 'PICK_PALLET'[\s\S]*?palletNo: item\.palletNo/)
|
||||||
|
|||||||
Reference in New Issue
Block a user