import type { ConsignmentMatchCandidate } from '../types/consignment' /** 与寄售仓库「一键查询待匹配订单」同一口径的 0-100 匹配打分。 */ export function computeConsignmentMatchScore( item: Pick, ): number { const details = (item.matchDetails || []).filter((detail) => detail.status !== 'ignored') if (details.length === 0) { const type = item.matchType || 'exact' if (type === 'exact') return 100 if (type === 'partial') return 85 if (type === 'unknown') return 50 return 0 } const matched = details.reduce((sum, detail) => { if (detail.status === 'match') return sum + 1 if (detail.status === 'partial') return sum + 0.85 if (detail.status === 'unknown') return sum + 0.5 return sum }, 0) return Math.round((matched / details.length) * 100) } /** 匹配说明:精确 / 高配 / 缺规格 / 冲突原因。 */ export function describeConsignmentMatch( item: Pick, ): string { const type = item.matchType || 'exact' if (type === 'exact') return '规格完全一致' const reasons = (item.matchReasons || []).filter(Boolean) if (reasons.length > 0) { return `${type === 'conflict' ? '不匹配' : '待核对'}:${reasons.join(';')}` } if (type === 'partial') return '规格高于要求(非精确)' return '需人工核对' } /** * 选中的库存是否够一次拼满。 * * - 拼单:按剩余份数累加,必须覆盖「总份数 - 已匹配份数」; * - 整单:只能选一条,且该条剩余数量必须 >= 订单总数量。 */ export function resolveMatchCoverage(input: { sharingEnabled: boolean totalQuantity: number activeQuantity: number selected: Array> }): { requiredQuantity: number selectedQuantity: number sufficient: boolean gap: number } { const total = Math.max(1, Math.round(Number(input.totalQuantity || 0))) const active = Math.max(0, Math.round(Number(input.activeQuantity || 0))) const remaining = input.selected.reduce( (sum, item) => sum + Math.max(0, Math.round(Number(item.remainingQuantity || 0))), 0, ) if (input.sharingEnabled) { const required = Math.max(0, total - active) return { requiredQuantity: required, selectedQuantity: remaining, sufficient: required > 0 && remaining >= required, gap: Math.max(0, required - remaining), } } const selectedQuantity = input.selected.reduce( (max, item) => Math.max(max, Math.round(Number(item.remainingQuantity || 0))), 0, ) return { requiredQuantity: total, selectedQuantity, sufficient: input.selected.length === 1 && selectedQuantity >= total, gap: Math.max(0, total - selectedQuantity), } }