优化
This commit is contained in:
+108
-14
@@ -33,8 +33,9 @@
|
||||
</view>
|
||||
<view class="stage-switch" role="tablist" aria-label="作业阶段">
|
||||
<button class="stage-tab" :class="{ active: activeStage === 'picking' }" role="tab" :aria-selected="activeStage === 'picking'" @tap="selectStage('picking')">拣货作业</button>
|
||||
<button class="stage-tab" :class="{ active: activeStage === 'evidence' }" role="tab" :aria-selected="activeStage === 'evidence'" @tap="selectStage('evidence')">装柜取证<text v-if="!loadingStageReady" class="stage-tab-hint">照片可先暂存</text></button>
|
||||
<button class="stage-tab" :class="{ active: activeStage === 'evidence' }" :disabled="!loadingStageReady" role="tab" :aria-selected="activeStage === 'evidence'" @tap="selectStage('evidence')">装柜取证</button>
|
||||
</view>
|
||||
<view v-if="!loadingStageReady" class="evidence-stage-hint" role="status">请先处理并提交全部待拣明细;任务增量更新后,已拍证据会按当前柜次保留。</view>
|
||||
|
||||
<view v-if="activeStage === 'picking'" class="picking-stage">
|
||||
<view class="scan-section">
|
||||
@@ -123,7 +124,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="activeStage === 'evidence'" class="loading-evidence-section">
|
||||
<view v-if="activeStage === 'evidence' && loadingStageReady" class="loading-evidence-section">
|
||||
<view class="section-heading-row">
|
||||
<view><text class="section-title">装柜证据</text><text class="section-subtitle">空仓、半仓、满仓、锁仓及带锁码照</text></view>
|
||||
<text class="sync-state" :class="remoteSyncState.tone">{{ remoteSyncState.label }}</text>
|
||||
@@ -148,9 +149,8 @@
|
||||
<input v-model="sealNo" class="seal-input" placeholder="输入封签号(必填)" maxlength="64" />
|
||||
<button class="evidence-btn seal-btn" @tap="saveSealNo">保存封签</button>
|
||||
</view>
|
||||
<view v-if="!loadingStageReady" class="evidence-stage-hint" role="status">当前可先拍照留存;拣货完成并同步装柜状态后,照片会自动上传绑定。</view>
|
||||
<view v-if="remoteError" class="remote-error-row"><text class="remote-error" role="alert">{{ remoteError }}</text><button class="evidence-retry-btn" :disabled="remoteLoading" @tap="refreshTask">刷新任务</button></view>
|
||||
<button class="loading-complete-btn" :disabled="submitting || pickingVersion === null || loadingVersion === null || !evidenceComplete" @tap="completeLoadingTask">确认装柜完成</button>
|
||||
<button class="loading-complete-btn" :disabled="submitting || !loadingStageReady || pickingVersion === null || loadingVersion === null || !evidenceComplete" @tap="completeLoadingTask">确认装柜完成</button>
|
||||
<view v-if="loadingVersion === null" class="remote-error-row">
|
||||
<text class="version-hint" role="status">状态尚未同步,请刷新重试</text>
|
||||
<button class="evidence-retry-btn" :disabled="remoteLoading" @tap="refreshTask">刷新任务</button>
|
||||
@@ -421,8 +421,11 @@
|
||||
return this.boxes.length - this.completedCount
|
||||
},
|
||||
pickingCompleted() {
|
||||
if (this.remotePick) {
|
||||
const hasServerPending = this.currentBox.items.some((item) => ['PENDING', 'PICKING'].includes(item.itemStatus))
|
||||
return isPickingCompleteTask(this.remotePick) && !hasServerPending
|
||||
}
|
||||
return Boolean(this.completedBoxes[this.currentBoxIndex])
|
||||
|| isPickingCompleteTask(this.remotePick)
|
||||
},
|
||||
pickingOperationReady() {
|
||||
return this.remotePick?.workflowStatus === 'IN_PROGRESS'
|
||||
@@ -543,6 +546,10 @@
|
||||
},
|
||||
methods: {
|
||||
selectStage(stage) {
|
||||
if (stage === 'evidence' && !this.loadingStageReady) {
|
||||
this.showToast('请先完成新增待拣明细', 'warning')
|
||||
return
|
||||
}
|
||||
this.activeStage = stage
|
||||
},
|
||||
debugEvidence(event, payload = {}) {
|
||||
@@ -563,6 +570,32 @@
|
||||
})
|
||||
} catch (_) { /* console may be unavailable on a device */ }
|
||||
},
|
||||
isTaskConflict(error) {
|
||||
return String(error?.code || '') === 'A0409' || Number(error?.statusCode) === 409
|
||||
},
|
||||
async refreshAfterTaskConflict(message) {
|
||||
const requestedTaskId = this.remoteTaskId || this.currentBox.taskId
|
||||
this.submitId = ''
|
||||
this.submitting = false
|
||||
this.remoteError = message
|
||||
this.showToast(message, 'warning')
|
||||
await this.syncRemoteTask()
|
||||
if (String(this.remoteTaskId || '') === String(requestedTaskId || '') && this.remotePick?.taskStatus === 'LOADING') {
|
||||
try { await this.refreshInventorySnapshot() } catch (error) { this.debugSubmit('refresh.inventory-error', { message: error?.message || '', code: error?.code || '' }) }
|
||||
}
|
||||
if (String(this.remoteTaskId || '') === String(requestedTaskId || '') && !this.remoteError) this.remoteError = message
|
||||
},
|
||||
async refreshInventorySnapshot() {
|
||||
const warehouseId = this.currentBox.warehouseId || session.currentUser?.warehouseId || session.currentUser?.warehouse
|
||||
const snapshot = await getPickingInventorySnapshot(this.remoteTaskId, warehouseId)
|
||||
if (!snapshot?.snapshotToken) throw new Error('库存快照未同步,请刷新任务后重试')
|
||||
if (this.pickingVersion !== null && String(snapshot.version) !== String(this.pickingVersion)) {
|
||||
const error = new Error('库存已变化,请刷新后重试')
|
||||
error.code = 'A0409'
|
||||
throw error
|
||||
}
|
||||
return snapshot
|
||||
},
|
||||
captureEvidenceIdentity() {
|
||||
return {
|
||||
taskId: this.remoteTaskId || this.currentBox.taskId || null,
|
||||
@@ -699,11 +732,26 @@
|
||||
const restored = restorePickingSession(this.draftIdentity())
|
||||
if (!restored) return false
|
||||
const itemIds = new Set(this.currentBox.items.map((item) => String(item.id)))
|
||||
this.itemStates = Object.fromEntries(Object.entries(restored.itemStates || {}).filter(([id]) => itemIds.has(String(id))))
|
||||
this.partialQuantities = Object.fromEntries(Object.entries(restored.partialQuantities || {}).filter(([id]) => itemIds.has(String(id))))
|
||||
this.scannedBoxCodes = { ...(restored.scannedBoxCodes || {}) }
|
||||
const serverStates = { ...this.itemStates }
|
||||
const serverPartialQuantities = { ...this.partialQuantities }
|
||||
Object.entries(restored.itemStates || {}).forEach(([id, status]) => {
|
||||
if (!itemIds.has(String(id)) || serverStates[id] !== ITEM_STATUS.PENDING || status === ITEM_STATUS.PENDING) return
|
||||
const item = this.currentBox.items.find((entry) => String(entry.id) === String(id))
|
||||
const partial = Number(restored.partialQuantities?.[id] || 0)
|
||||
if (status === ITEM_STATUS.PARTIAL && (!partial || partial >= Number(item?.qty || 0))) return
|
||||
serverStates[id] = status
|
||||
if (partial > 0) serverPartialQuantities[id] = partial
|
||||
})
|
||||
this.itemStates = serverStates
|
||||
this.partialQuantities = serverPartialQuantities
|
||||
this.scannedBoxCodes = Object.fromEntries(Object.entries(restored.scannedBoxCodes || {}).filter(([, id]) => itemIds.has(String(id))))
|
||||
this.boxDrafts = restored.boxDrafts || {}
|
||||
this.completedBoxes = restored.completedBoxes || {}
|
||||
if (this.remotePick && !isPickingCompleteTask(this.remotePick)) {
|
||||
const completedBoxes = { ...this.completedBoxes }
|
||||
delete completedBoxes[this.currentBoxIndex]
|
||||
this.completedBoxes = completedBoxes
|
||||
}
|
||||
this.scanHistory = this.normalizeScanHistory(restored.scanHistory)
|
||||
return true
|
||||
},
|
||||
@@ -911,6 +959,13 @@
|
||||
if (!requestedTaskId) { this.remoteError = '当前没有可进入的拣货任务,请返回任务列表刷新'; return }
|
||||
this.rememberEvidenceDraft()
|
||||
const previousIdentity = this.draftIdentity()
|
||||
const previousTaskVersion = this.pickingVersion
|
||||
const previousItemIds = new Set(this.currentBox.items.map((item) => String(item.id)))
|
||||
const previousEvidenceState = {
|
||||
identity: this.evidenceIdentity ? { ...this.evidenceIdentity } : null,
|
||||
files: Object.fromEntries(Object.entries(this.evidenceFiles).map(([type, entries]) => [type, (Array.isArray(entries) ? entries : [entries]).map((entry) => ({ ...entry }))])),
|
||||
sealNo: this.sealNo
|
||||
}
|
||||
const requestId = ++this.taskRequestId
|
||||
const selector = { taskId: requestedTaskId }
|
||||
this.currentBox.inboundId = null
|
||||
@@ -1004,9 +1059,26 @@
|
||||
this.loadingVersion = this.remotePick.inboundVersion ?? this.remotePick.loadingVersion ?? null
|
||||
this.evidenceIdentity = this.captureEvidenceIdentity()
|
||||
this.restoreEvidenceDraft()
|
||||
if (this.isSameEvidenceIdentity(previousEvidenceState.identity, this.evidenceIdentity)) {
|
||||
this.evidenceFiles = { ...this.evidenceFiles, ...previousEvidenceState.files }
|
||||
if (previousEvidenceState.sealNo) this.sealNo = previousEvidenceState.sealNo
|
||||
}
|
||||
this.debugSubmit('refresh.ready', { requestId, workflowStatus: this.remotePick.workflowStatus, taskStatus: this.remotePick.taskStatus, assignmentVersion: this.assignmentVersion, loadingVersion: this.loadingVersion, evidenceIdentity: this.evidenceIdentity })
|
||||
this.assignmentVersion = this.remotePick.assignment?.version ?? this.remotePick.assignmentVersion ?? this.assignmentVersion
|
||||
if (!this.pickingCompleted) this.restoreRemoteDraft()
|
||||
if (!this.pickingCompleted) {
|
||||
const completedBoxes = { ...this.completedBoxes }
|
||||
delete completedBoxes[this.currentBoxIndex]
|
||||
this.completedBoxes = completedBoxes
|
||||
this.activeStage = 'picking'
|
||||
this.completionSummary = { picked: 0, partial: 0, skipped: 0, autoSkipped: 0 }
|
||||
}
|
||||
const addedItemIds = this.currentBox.items.map((item) => String(item.id)).filter((id) => !previousItemIds.has(id))
|
||||
const taskVersionChanged = previousTaskVersion !== null && String(previousTaskVersion) !== String(this.pickingVersion)
|
||||
if (taskVersionChanged || addedItemIds.length) {
|
||||
this.debugSubmit('refresh.incremental', { previousTaskVersion, taskVersion: this.pickingVersion, addedItemIds, pickingCompleted: this.pickingCompleted })
|
||||
if (addedItemIds.length) this.showToast(`已同步 ${addedItemIds.length} 条新增待拣明细`, 'warning')
|
||||
}
|
||||
if (this.loadingStageReady) await this.loadLoadingEvidence()
|
||||
} catch (error) {
|
||||
if (requestId !== this.taskRequestId) return
|
||||
@@ -1119,8 +1191,12 @@
|
||||
},
|
||||
async flushPendingEvidence() {
|
||||
if (!this.loadingStageReady) return
|
||||
const pending = this.evidenceSlots.flatMap((slot) => this.evidenceEntries(slot.type).filter((entry) => entry.localPath && !entry.fileId).map((entry) => ({ type: slot.type, path: entry.localPath })))
|
||||
for (const item of pending) await this.queueEvidenceUpload(item.type, item.path)
|
||||
const pending = this.evidenceSlots.flatMap((slot) => this.evidenceEntries(slot.type).filter((entry) => !entry.id && entry.localPath).map((entry) => ({ type: slot.type, path: entry.localPath, fileId: entry.fileId })))
|
||||
for (const item of pending) {
|
||||
if (!this.loadingStageReady) return
|
||||
if (item.fileId) await this.saveEvidence(item.type, null, item.path)
|
||||
else await this.queueEvidenceUpload(item.type, item.path)
|
||||
}
|
||||
},
|
||||
async retryEvidence(type) {
|
||||
if (!this.requireEvidenceStage()) return
|
||||
@@ -1161,6 +1237,10 @@
|
||||
this.showToast(`${type === 'SEAL' ? '封签' : '照片'}已保存`, 'success')
|
||||
} catch (error) {
|
||||
if (!this.isEvidenceContextActive(contextId, identity)) return
|
||||
if (this.isTaskConflict(error)) {
|
||||
await this.refreshAfterTaskConflict(error.message || '任务内容已更新,请完成新增待拣项后重试')
|
||||
return
|
||||
}
|
||||
this.remoteError = error.network ? '网络失败,证据未提交,请重试' : (error.message || '证据保存失败')
|
||||
this.showToast('证据保存失败', 'error')
|
||||
}
|
||||
@@ -1186,6 +1266,10 @@
|
||||
this.showToast('照片已作废,可重新拍摄', 'success')
|
||||
} catch (error) {
|
||||
if (!this.isEvidenceContextActive(contextId, identity)) return
|
||||
if (this.isTaskConflict(error)) {
|
||||
await this.refreshAfterTaskConflict(error.message || '任务内容已更新,请刷新后重试')
|
||||
return
|
||||
}
|
||||
this.remoteError = error.network ? '网络失败,照片未作废,请重试' : (error.message || '照片作废失败')
|
||||
this.showToast('照片作废失败', 'error')
|
||||
}
|
||||
@@ -1220,6 +1304,10 @@
|
||||
this.showToast('已确认装柜完成', 'success')
|
||||
} catch (error) {
|
||||
if (!this.isEvidenceContextActive(contextId, identity)) return
|
||||
if (this.isTaskConflict(error)) {
|
||||
await this.refreshAfterTaskConflict(error.message || '装柜前置条件已变化,请刷新后重试')
|
||||
return
|
||||
}
|
||||
this.remoteError = error.network ? '网络失败,装柜完成未提交' : (error.message || '装柜完成失败')
|
||||
this.showToast('装柜完成失败', 'error')
|
||||
}
|
||||
@@ -1377,10 +1465,11 @@
|
||||
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)
|
||||
const inventorySnapshot = await this.refreshInventorySnapshot()
|
||||
this.debugSubmit('submit.inventory-snapshot', { snapshotTokenLength: inventorySnapshot?.snapshotToken ? String(inventorySnapshot.snapshotToken).length : 0, taskVersion: inventorySnapshot?.version ?? null })
|
||||
if (!inventorySnapshot?.snapshotToken) throw new Error('库存快照未同步,请刷新任务后重试')
|
||||
const actions = this.currentBox.items.map((item) => {
|
||||
if (item.itemStatus && !['PENDING', 'PICKING'].includes(item.itemStatus)) return null
|
||||
const status = this.itemState(item)
|
||||
const itemId = item.taskItemId ?? item.remoteItemId ?? item.id
|
||||
if (status === ITEM_STATUS.PICKED) return { type: 'PICK', itemId, pickedPackageCount: Number(item.qty || 0), locationIds: item.locationIds || [], version: Number(item.version || 0) }
|
||||
@@ -1394,17 +1483,22 @@
|
||||
this.debugSubmit('submit.success', { itemCount: actions.length, workflowStatus: submittedTask?.workflowStatus || null, taskStatus: submittedTask?.taskStatus || null })
|
||||
if (submittedTask) {
|
||||
this.remotePick = normalizePickingTask({ ...this.remotePick, ...submittedTask })
|
||||
this.pickingVersion = this.remotePick.pickingVersion ?? this.remotePick.version ?? this.pickingVersion
|
||||
this.loadingVersion = submittedTask.inboundVersion ?? submittedTask.loadingVersion ?? this.remotePick.inboundVersion ?? this.remotePick.loadingVersion ?? this.loadingVersion
|
||||
this.evidenceIdentity = this.captureEvidenceIdentity()
|
||||
}
|
||||
// Legacy inbound completePicking(expectedVersion: Number(this.pickingVersion)) remains adapter-only; cabinet tasks use item actions.
|
||||
} catch (error) {
|
||||
this.debugSubmit('submit.error', { message: error.message || '', code: error.code || '', statusCode: error.statusCode || '', requestIdFromServer: error.requestId || '', traceId: error.traceId || '', network: Boolean(error.network) })
|
||||
const versionConflict = error.code === 'A0409' || error.statusCode === 409
|
||||
const versionConflict = this.isTaskConflict(error)
|
||||
const inventoryConflict = versionConflict && /库存/.test(error.message || '')
|
||||
const conflictMessage = inventoryConflict ? '库存已变化,请刷新后重试' : '任务版本已变化,请刷新后重试'
|
||||
this.remoteError = versionConflict ? conflictMessage : (error.network ? '网络失败,拣货完成未提交,请重试' : (error.message || '拣货完成失败'))
|
||||
this.showToast(versionConflict ? conflictMessage : '拣货完成未提交,请查看错误提示', 'error')
|
||||
if (versionConflict) {
|
||||
await this.refreshAfterTaskConflict(conflictMessage)
|
||||
return
|
||||
}
|
||||
this.remoteError = error.network ? '网络失败,拣货完成未提交,请重试' : (error.message || '拣货完成失败')
|
||||
this.showToast('拣货完成未提交,请查看错误提示', 'error')
|
||||
return
|
||||
} finally { this.submitting = false }
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ import { readFile } from 'node:fs/promises'
|
||||
const page = await readFile(new URL('../pages/picking/picking.vue', import.meta.url), 'utf8')
|
||||
|
||||
test('picking and photo workspaces are independently selectable', () => {
|
||||
assert.match(page, /v-if="activeStage === 'evidence'" class="loading-evidence-section"/)
|
||||
assert.match(page, /v-if="activeStage === 'evidence' && loadingStageReady" class="loading-evidence-section"/)
|
||||
assert.match(page, /isPickingCompleteTask\(task\)[\s\S]*?AWAITING_REVIEW[\s\S]*?COMPLETED/)
|
||||
assert.match(page, /pickingCompleted\(\)[\s\S]*?completedBoxes\[this\.currentBoxIndex\][\s\S]*?isPickingCompleteTask\(this\.remotePick\)/)
|
||||
assert.match(page, /照片可先暂存/)
|
||||
assert.match(page, /pickingCompleted\(\)[\s\S]*?if \(this\.remotePick\)[\s\S]*?hasServerPending[\s\S]*?isPickingCompleteTask\(this\.remotePick\) && !hasServerPending/)
|
||||
assert.match(page, /请先处理并提交全部待拣明细/)
|
||||
})
|
||||
|
||||
test('loading evidence is not requested before picking completion', () => {
|
||||
@@ -36,17 +36,49 @@ test('AWAITING_REVIEW alone cannot request or mutate server evidence without a s
|
||||
assert.doesNotMatch(page, /if \(this\.pickingCompleted\) await this\.loadLoadingEvidence\(\)/)
|
||||
})
|
||||
|
||||
test('picking and evidence are separate operator-selected stages', () => {
|
||||
test('dynamic pending items withdraw evidence until the server task is picking-complete again', () => {
|
||||
assert.match(page, /class="stage-switch" role="tablist"/)
|
||||
assert.match(page, /@tap="selectStage\('picking'\)"/)
|
||||
assert.match(page, /@tap="selectStage\('evidence'\)"/)
|
||||
assert.match(page, /selectStage\(stage\) \{[\s\S]*?this\.activeStage = stage/)
|
||||
assert.match(page, /selectStage\(stage\) \{[\s\S]*?stage === 'evidence' && !this\.loadingStageReady[\s\S]*?请先完成新增待拣明细[\s\S]*?return[\s\S]*?this\.activeStage = stage/)
|
||||
assert.match(page, /class="stage-tab"[\s\S]*?:disabled="!loadingStageReady"[\s\S]*?装柜取证/)
|
||||
assert.match(page, /activeStage === 'picking'/)
|
||||
assert.doesNotMatch(page, /activeStage === 'picking' \|\| !loadingStageReady/)
|
||||
assert.match(page, /requireEvidenceCapture\(\)[\s\S]*?evidenceIdentity\?\.inboundId/)
|
||||
assert.match(page, /if \(this\.loadingStageReady\) this\.queueEvidenceUpload/)
|
||||
assert.match(page, /照片已暂存,装柜状态同步后自动上传/)
|
||||
assert.match(page, /本地暂存,待自动上传/)
|
||||
assert.match(page, /:disabled="submitting \|\| !loadingStageReady \|\| pickingVersion === null/)
|
||||
})
|
||||
|
||||
test('incremental refresh merges new pending items without overwriting submitted server results', () => {
|
||||
const restore = page.match(/restoreRemoteDraft\(\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
|
||||
assert.match(restore, /const serverStates = \{ \.\.\.this\.itemStates \}/)
|
||||
assert.match(restore, /serverStates\[id\] !== ITEM_STATUS\.PENDING/)
|
||||
assert.match(restore, /status === ITEM_STATUS\.PARTIAL[\s\S]*?partial >= Number\(item\?\.qty/)
|
||||
assert.match(restore, /this\.remotePick && !isPickingCompleteTask\(this\.remotePick\)[\s\S]*?delete completedBoxes\[this\.currentBoxIndex\]/)
|
||||
assert.match(page, /const previousTaskVersion = this\.pickingVersion/)
|
||||
assert.match(page, /const previousItemIds = new Set/)
|
||||
assert.match(page, /previousEvidenceState[\s\S]*?isSameEvidenceIdentity\(previousEvidenceState\.identity, this\.evidenceIdentity\)[\s\S]*?this\.evidenceFiles = \{ \.\.\.this\.evidenceFiles, \.\.\.previousEvidenceState\.files \}/)
|
||||
assert.match(page, /if \(!this\.pickingCompleted\)[\s\S]*?delete completedBoxes\[this\.currentBoxIndex\][\s\S]*?this\.activeStage = 'picking'/)
|
||||
assert.match(page, /refresh\.incremental[\s\S]*?addedItemIds/)
|
||||
})
|
||||
|
||||
test('incremental batch submits only current server-pending items and refreshes stale inventory conflicts', () => {
|
||||
const submit = page.match(/async performSubmit\([^)]*\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
|
||||
assert.match(submit, /item\.itemStatus && !\['PENDING', 'PICKING'\]\.includes\(item\.itemStatus\)\) return null/)
|
||||
assert.match(submit, /const versionConflict = this\.isTaskConflict\(error\)/)
|
||||
assert.match(submit, /await this\.refreshAfterTaskConflict\(conflictMessage\)/)
|
||||
assert.match(submit, /const inventorySnapshot = await this\.refreshInventorySnapshot\(\)/)
|
||||
assert.match(page, /refreshAfterTaskConflict\(message\)[\s\S]*?this\.submitId = ''[\s\S]*?await this\.syncRemoteTask\(\)[\s\S]*?await this\.refreshInventorySnapshot\(\)/)
|
||||
assert.match(page, /refreshInventorySnapshot\(\)[\s\S]*?getPickingInventorySnapshot\(this\.remoteTaskId, warehouseId\)[\s\S]*?String\(snapshot\.version\) !== String\(this\.pickingVersion\)[\s\S]*?error\.code = 'A0409'/)
|
||||
assert.match(page, /this\.pickingVersion = this\.remotePick\.pickingVersion \?\? this\.remotePick\.version/)
|
||||
})
|
||||
|
||||
test('final completion preserves backend gate errors and refreshes after an atomic A0409', () => {
|
||||
const complete = page.match(/async completeLoadingTask\(\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
|
||||
assert.match(complete, /this\.isTaskConflict\(error\)[\s\S]*?await this\.refreshAfterTaskConflict\(error\.message \|\| '装柜前置条件已变化,请刷新后重试'\)/)
|
||||
const save = page.match(/async saveEvidence\([^)]*\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
|
||||
assert.match(save, /this\.isTaskConflict\(error\)[\s\S]*?refreshAfterTaskConflict/)
|
||||
const flush = page.match(/async flushPendingEvidence\(\) \{[\s\S]*?\n\t\t\t\},/)?.[0] || ''
|
||||
assert.match(flush, /!entry\.id && entry\.localPath/)
|
||||
assert.match(flush, /if \(item\.fileId\) await this\.saveEvidence\(item\.type, null, item\.path\)/)
|
||||
assert.match(flush, /else await this\.queueEvidenceUpload\(item\.type, item\.path\)/)
|
||||
})
|
||||
|
||||
test('evidence identity is bound to task, inbound, loading plan and container booking', () => {
|
||||
|
||||
Reference in New Issue
Block a user