111 lines
3.3 KiB
JavaScript
111 lines
3.3 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'
|
|
}
|
|
|
|
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 }
|
|
}
|