feat: gate PDA loading evidence by ready task

This commit is contained in:
2026-08-15 17:04:00 +08:00
parent 207c872dff
commit 3bb5da8ae7
6 changed files with 147 additions and 79 deletions
+7 -1
View File
@@ -43,6 +43,12 @@ test('picking task list uses remote loading orders and never falls back to demo
assert.match(tasks, /listLoadingOrders/)
assert.match(tasks, /当前网络不可用,请联网后刷新/)
assert.match(tasks, /进入并开始拣货/)
assert.match(tasks, /暂无可领取的拣货任务/)
assert.match(tasks, /集装箱号 \{\{ task\.currentContainerNo \}\}/)
assert.match(tasks, /柜次号 \{\{ task\.cabinetNo \}\}/)
assert.match(tasks, /records\.filter\(\(task\) => this\.isTaskReady\(task\)\)/)
assert.match(tasks, /task\.taskId[\s\S]*?task\.loadingPlanId[\s\S]*?task\.containerBookingId[\s\S]*?task\.currentContainerNo[\s\S]*?task\.version[\s\S]*?task\.assignmentVersion/)
assert.doesNotMatch(tasks, /task\.taskStatus === 'LOADING'/)
assert.doesNotMatch(tasks, /demo-data|DEMO_/)
assert.match(home, /pages\/tasks\/tasks/)
assert.match(modulePage, /pages\/tasks\/tasks/)
@@ -105,7 +111,7 @@ test('picking page keeps scan, draft and risky transition contracts', async () =
assert.match(page, /<ScanTargetInput v-model="scanValue" name="boxCode"[\s\S]*?:active="activeScanField === 'boxCode'"[\s\S]*?@activate="setScanTarget"[\s\S]*?@submit="handleManualSubmit"/)
assert.match(page, /beforeUnmount\(\)/)
assert.match(page, /startScanBroadcast/)
assert.match(page, /onHide\(\) \{ this\.stopHardwareScanner\(\) \}/)
assert.match(page, /onHide\(\) \{[\s\S]*?this\.stopHardwareScanner\(\)[\s\S]*?\}/)
assert.match(page, /handleHardwareScan\(value\)[\s\S]*?this\.scanValue = value[\s\S]*?this\.processScannedValue\(value, 'broadcast'\)/)
assert.match(page, /handleManualSubmit\(value\)[\s\S]*?\.trim\(\)\.toUpperCase\(\)[\s\S]*?this\.processScannedValue\(normalizedValue, 'manual'\)/)
assert.match(page, /recordScanResult\(type, title, boxCode, detail\)/)
+5 -5
View File
@@ -41,7 +41,7 @@ test('C02 identifiers and separate picking/inbound versions are normalized expli
assert.match(page, /item\.itemStatus === 'PICKED'/)
assert.match(page, /item\.itemStatus === 'PARTIAL'/)
assert.match(page, /pickingCompleted \|\| !summary\.canSubmit/)
assert.match(page, /this\.loadingVersion = task\.inboundVersion \?\? task\.loadingVersion/)
assert.match(page, /this\.loadingVersion = this\.remotePick\.inboundVersion \?\? this\.remotePick\.loadingVersion/)
assert.match(page, /状态尚未同步,请刷新重试/)
})
@@ -80,7 +80,8 @@ test('PDA downloads authenticated evidence previews returned by the backend', ()
test('PDA cabinet picking adapter claims online and submits one atomic batch', () => {
assert.match(source, /\/first-leg\/pda-loading\/tasks\/pending/)
assert.match(source, /\/first-leg\/pda-loading\/tasks\?/)
assert.doesNotMatch(source, /query\.push\(`cabinetNo=/)
assert.doesNotMatch(source, /query\.push\(`loadingPlanId=/)
assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\/claim/)
assert.match(source, /tasks\/\$\{encodeURIComponent\(task\.taskId\)\}\/batch/)
assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\/inventory-snapshot\?warehouseId=/)
@@ -92,8 +93,6 @@ test('PDA cabinet picking adapter claims online and submits one atomic batch', (
assert.match(page, /submitContainerPickingBatch\(/)
assert.match(page, /任务版本已变化,请刷新后重试/)
assert.match(source, /data: \{ warehouseId, loadingPlanId: task\.loadingPlanId, containerBookingId: task\.containerBookingId, expectedVersion, inventorySnapshotToken, items \}/)
assert.match(source, /cabinetNo=/)
assert.match(source, /loadingPlanId=/)
assert.doesNotMatch(source, /query\.push\(`containerNo=/)
assert.doesNotMatch(page, /getContainerPickingTask\([^\n]*containerNo:/)
assert.match(source, /tasks\/\$\{encodeURIComponent\(taskId\)\}\?warehouseId=/)
@@ -110,7 +109,8 @@ test('PDA cabinet picking adapter claims online and submits one atomic batch', (
assert.match(page, /remoteError && !pickingCompleted/)
assert.match(page, /库存快照未同步,请刷新任务后重试/)
assert.match(page, /拣货完成未提交,请查看错误提示/)
assert.match(page, /if \(!isPickingCompleteTask\(remoteTask\)\)[\s\S]*claimContainerPickingTask/)
assert.match(page, /if \(remoteTask\.workflowStatus === 'UNASSIGNED'\)[\s\S]*claimContainerPickingTask/)
assert.match(page, /this\.loadingVersion = this\.remotePick\.inboundVersion \?\? this\.remotePick\.loadingVersion/)
assert.match(page, /taskRequestId/)
assert.match(page, /resetEvidenceState/)
assert.match(page, /availablePickQuantity/)
+24 -3
View File
@@ -49,8 +49,10 @@ test('picking and evidence are separate operator-selected stages', () => {
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, /isSameEvidenceIdentity\(left, right\)[\s\S]*?taskId[\s\S]*?inboundId[\s\S]*?loadingPlanId[\s\S]*?containerBookingId/)
assert.match(page, /this\.currentBox\.inboundId = firstItem\.inboundId/)
assert.doesNotMatch(page, /firstItem\.inboundId \|\| this\.currentBox\.inboundId/)
assert.match(page, /this\.currentBox\.inboundId = task\.inboundId/)
assert.match(page, /String\(detailTaskId \|\| ''\) !== String\(requestedTaskId\)/)
assert.match(page, /!task\.inboundId \|\| !task\.loadingPlanId \|\| !task\.containerBookingId/)
assert.match(page, /evidenceItem[\s\S]*?String\(task\.inboundId\)/)
assert.match(page, /this\.evidenceIdentity = this\.captureEvidenceIdentity\(\)/)
})
@@ -114,6 +116,15 @@ test('returning from the camera does not refresh and invalidate the active evide
assert.match(chooser, /fail: \(error\) => \{[\s\S]*?this\.cameraPicking = false/)
})
test('returning from an image preview does not refresh the picking task', () => {
assert.match(page, /evidencePreviewOpening: false, evidencePreviewReturning: false/)
assert.match(page, /onShow\(\) \{[\s\S]*?if \(this\.evidencePreviewReturning\)[\s\S]*?preview\.resume[\s\S]*?return[\s\S]*?this\.syncRemoteTask\(\)/)
assert.match(page, /onHide\(\) \{[\s\S]*?if \(this\.evidencePreviewOpening\)[\s\S]*?this\.evidencePreviewReturning = true/)
const preview = page.match(/previewEvidencePhoto\(photo, type\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
assert.match(preview, /this\.evidencePreviewOpening = true/)
assert.match(preview, /uni\.previewImage\(\{ current, urls, fail:/)
})
test('evidence save, void and loading completion ignore stale cabinet responses', () => {
for (const [method, awaitedCall] of [
['saveEvidence', 'upsertEvidence'],
@@ -132,6 +143,16 @@ test('evidence save, void and loading completion ignore stale cabinet responses'
test('completed server tasks restore evidence stage without being claimed again', () => {
assert.match(page, /const remoteTask = normalizePickingTask\(task\)/)
assert.match(page, /if \(!isPickingCompleteTask\(remoteTask\)\) \{[\s\S]*?claimContainerPickingTask/)
assert.match(page, /if \(remoteTask\.workflowStatus === 'UNASSIGNED'\) \{[\s\S]*?claimContainerPickingTask/)
assert.match(page, /else if \(!isPickingCompleteTask\(remoteTask\)\)/)
assert.match(page, /if \(this\.loadingStageReady\) await this\.loadLoadingEvidence\(\)/)
})
test('picking mutations stay closed until the canonical task has been claimed', () => {
assert.match(page, /pickingOperationReady\(\)[\s\S]*?workflowStatus === 'IN_PROGRESS'[\s\S]*?remoteTaskId[\s\S]*?inboundId[\s\S]*?loadingPlanId[\s\S]*?containerBookingId/)
assert.match(page, /requirePickingOperation\(\)[\s\S]*?任务尚未领取完成/)
for (const method of ['processScannedValue', 'pickItem', 'openSkip', 'openPartial', 'submitPicking']) {
const body = page.match(new RegExp(`${method}\\([^)]*\\) \\{[\\s\\S]*?\\n\\t\\t\\t\\},`))?.[0] || ''
assert.match(body, /if \(!this\.requirePickingOperation\(\)\) return/, `${method} should wait for claim`)
}
})