fix(consignment): 手动匹配寄卖后刷新工单列表并展示寄卖价格

This commit is contained in:
2026-11-07 15:57:39 +08:00
parent 8920afa0e5
commit 0e9087c8bb
11 changed files with 712 additions and 75 deletions
@@ -46,7 +46,7 @@ export const WORKER_PLATFORM_TAB_QUERY_KEYS: Record<string, string[][]> = {
['admin-consignment-submissions'],
['admin-consignment-submissions-pending-total'],
],
orders: [['admin-work-orders'], ['admin-work-orders-stats']],
orders: [['admin-worker-platform-orders'], ['admin-worker-platform-summary']],
'cancel-requests': [['admin-work-order-cancel-requests']],
'after-sales': [['admin-after-sales-orders'], ['admin-after-sales-stats']],
feedbacks: [['admin-feedbacks']],
@@ -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),
}
}