fix(consignment): 手动匹配寄卖后刷新工单列表并展示寄卖价格
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import type { ConsignmentMatchCandidate } from '../types/consignment'
|
||||
|
||||
/** 与寄售仓库「一键查询待匹配订单」同一口径的 0-100 匹配打分。 */
|
||||
export function computeConsignmentMatchScore(
|
||||
item: Pick<ConsignmentMatchCandidate, 'matchType' | 'matchDetails'>,
|
||||
): 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<ConsignmentMatchCandidate, 'matchType' | 'matchReasons'>,
|
||||
): 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<Pick<ConsignmentMatchCandidate, 'inventoryId' | 'remainingQuantity'>>
|
||||
}): {
|
||||
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),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user