Files
pda-uniapp/utils/picking-state.js
T
2026-09-11 18:44:04 +08:00

113 lines
3.4 KiB
JavaScript

export const ITEM_STATUS = Object.freeze({
PENDING: 'pending',
PICKED: 'picked',
PARTIAL: 'partial',
SKIPPED: 'skipped'
})
export function isSealedPalletItem(item) {
return item?.unitType === 'SEALED_PALLET'
|| item?.palletId !== null && item?.palletId !== undefined
|| item?.indivisible === true
}
export function summarizeInventoryResources(resources) {
const list = Array.isArray(resources) ? resources : []
const locationCodes = [...new Set(list
.map((resource) => String(resource?.locationCode || '').trim())
.filter(Boolean))]
const availableCounts = list
.map((resource) => resource?.availablePackageCount)
.filter((value) => value !== null && value !== undefined && value !== '')
.map(Number)
.filter(Number.isFinite)
return {
location: locationCodes.join('、'),
availablePackageCount: availableCounts.length
? availableCounts.reduce((total, value) => total + Math.max(0, value), 0)
: null
}
}
export function createItemStates(items) {
return items.reduce((states, item) => {
states[item.id] = ITEM_STATUS.PENDING
return states
}, {})
}
export function getPickSummary(items, states, partialQuantities = {}) {
const summary = {
total: items.length,
picked: 0,
partial: 0,
skipped: 0,
pending: 0
}
items.forEach((item) => {
const status = states[item.id] || ITEM_STATUS.PENDING
const quantity = Math.max(1, Number(item.qty || 1))
summary.total += quantity - 1
summary[status] += status === ITEM_STATUS.PARTIAL
? Math.max(0, Number(partialQuantities[item.id] || 0))
: quantity
})
summary.processed = summary.picked + summary.partial + summary.skipped
summary.progress = summary.total
? Math.round(summary.processed / summary.total * 100)
: 0
summary.canSubmit = summary.total > 0 && (
summary.pending === 0 || summary.picked > 0 || summary.partial > 0
)
summary.buttonText = '提交拣货完成'
return summary
}
export function submitStates(items, states) {
const nextStates = { ...states }
const autoSkippedIds = []
items.forEach((item) => {
const status = nextStates[item.id] || ITEM_STATUS.PENDING
if (status === ITEM_STATUS.PENDING) {
nextStates[item.id] = ITEM_STATUS.SKIPPED
autoSkippedIds.push(item.id)
}
})
return {
states: nextStates,
autoSkippedIds
}
}
export function classifyScan(items, states, scanCode, scannedBoxCodes = {}) {
const palletItem = items.find((entry) => isSealedPalletItem(entry) && entry.palletNo === scanCode) || null
if (palletItem) {
const status = states[palletItem.id] || ITEM_STATUS.PENDING
if (scannedBoxCodes[scanCode] || status === ITEM_STATUS.PICKED) {
return { type: 'processed', item: palletItem, status }
}
return { type: 'pallet', item: palletItem }
}
const item = items.find((entry) => (entry.boxCodes || []).includes(scanCode)) || null
if (!item) return { type: 'unknown', item: null }
if (isSealedPalletItem(item)) {
const status = states[item.id] || ITEM_STATUS.PENDING
if (scannedBoxCodes[scanCode] || status === ITEM_STATUS.PICKED) {
return { type: 'processed', item, status }
}
return { type: 'pallet', item, matchedBy: 'carton' }
}
if (scannedBoxCodes[scanCode]) return { type: 'processed', item, status: states[item.id] || ITEM_STATUS.PARTIAL }
const status = states[item.id] || ITEM_STATUS.PENDING
if (status !== ITEM_STATUS.PICKED && status !== ITEM_STATUS.SKIPPED) return { type: 'pending', item }
return { type: 'processed', item, status }
}