feat(consignment): 匹配日志新增寄卖单号列并中文化原因

This commit is contained in:
2026-11-14 16:06:59 +08:00
parent e2863286c3
commit 5ff0ddb58e
6 changed files with 293 additions and 13 deletions
@@ -512,7 +512,12 @@ export async function tryAutoMatchBeforeHall(
reasonText: `没有库存能一次满足订单数量 ${requiredQuantity}`,
candidateCount: candidates.length,
durationMs: Date.now() - startedAt,
payload: { phase: 'before_hall', requiredQuantity },
// 记录候选库存 ID,日志弹窗才能反查出试过哪些寄卖单号。
payload: {
phase: 'before_hall',
requiredQuantity,
inventoryIds: candidates.map(({ inventory }) => Number(inventory.id)),
},
})
return false
}
@@ -92,6 +92,51 @@ export async function recordConsignmentMatchLog(
}
}
type ConsignmentInventoryNoRow = {
id: number | string
inventory_no: string
source_submission_no: string | null
}
type ConsignmentNoEntry = { inventoryNo: string; consignmentNo: string }
/** 日志写入时只记库存 ID,展示时再反查单号,历史日志也能补齐。 */
function resolvePayloadInventoryIds(payload: Record<string, unknown>): number[] {
const ids: number[] = []
const push = (value: unknown) => {
const id = Number(value)
if (Number.isInteger(id) && id > 0 && !ids.includes(id)) ids.push(id)
}
push(payload.inventoryId)
const list = payload.inventoryIds
if (Array.isArray(list)) list.forEach(push)
return ids
}
/** 寄卖单号口径与前端一致:来源提报单号优先,客服手工入库的现货回退库存号。 */
async function loadConsignmentNoMap(inventoryIds: number[]) {
const map = new Map<number, ConsignmentNoEntry>()
if (inventoryIds.length === 0) return map
const rows = await query<ConsignmentInventoryNoRow>(
`
SELECT i.id, i.inventory_no, cs.submission_no AS source_submission_no
FROM consignment_inventories i
LEFT JOIN consignment_submissions cs ON cs.id = i.source_submission_id
WHERE i.id = ANY($1::bigint[])
`,
[inventoryIds],
).catch(() => null)
for (const row of rows?.rows || []) {
const inventoryNo = String(row.inventory_no || '').trim()
const sourceSubmissionNo = String(row.source_submission_no || '').trim()
map.set(Number(row.id), {
inventoryNo,
consignmentNo: sourceSubmissionNo || inventoryNo,
})
}
return map
}
function mapLog(row: ConsignmentMatchLogRow) {
let payload: Record<string, unknown> = {}
if (row.payload_json && typeof row.payload_json === 'object') {
@@ -124,6 +169,10 @@ function mapLog(row: ConsignmentMatchLogRow) {
actorId: row.actor_id || '',
durationMs: Number(row.duration_ms || 0),
payload,
/** 本次日志涉及的寄卖单号(提报单号优先,无则库存号),由 payload 中的库存 ID 反查。 */
consignmentNos: [] as string[],
/** 对应库存号,前端用于悬浮提示。 */
inventoryNos: [] as string[],
createdAt: row.created_at,
}
}
@@ -195,8 +244,26 @@ export async function listConsignmentMatchLogs(
listValues,
)
const items = rows.rows.map(mapLog)
const inventoryIds = [
...new Set(items.flatMap((item) => resolvePayloadInventoryIds(item.payload))),
]
const consignmentNoMap = await loadConsignmentNoMap(inventoryIds)
for (const item of items) {
for (const inventoryId of resolvePayloadInventoryIds(item.payload)) {
const entry = consignmentNoMap.get(inventoryId)
if (!entry) continue
if (entry.consignmentNo && !item.consignmentNos.includes(entry.consignmentNo)) {
item.consignmentNos.push(entry.consignmentNo)
}
if (entry.inventoryNo && !item.inventoryNos.includes(entry.inventoryNo)) {
item.inventoryNos.push(entry.inventoryNo)
}
}
}
return {
items: rows.rows.map(mapLog),
items,
total,
page,
pageSize,