优化接单商品匹配

This commit is contained in:
yml2213
2026-08-18 12:05:12 +08:00
parent 41b39bc5a0
commit f2c95bc3c8
15 changed files with 1756 additions and 96 deletions
@@ -204,6 +204,7 @@ export async function listKuaishouIndustryVouchersByOid(
export type KuaishouIndustryVoucherWorkOrderSyncSource = {
oid: string
raw_payload_json: string | Record<string, unknown>
updated_at: string
}
export async function listKuaishouIndustryVoucherWorkOrderSyncSources(
@@ -211,7 +212,7 @@ export async function listKuaishouIndustryVoucherWorkOrderSyncSources(
): Promise<KuaishouIndustryVoucherWorkOrderSyncSource[]> {
const result = await query<KuaishouIndustryVoucherWorkOrderSyncSource>(
`
SELECT oid, raw_payload_json
SELECT oid, raw_payload_json, updated_at
FROM (
SELECT DISTINCT ON (oid) oid, raw_payload_json, updated_at, id
FROM kuaishou_industry_vouchers
@@ -2,4 +2,5 @@ export * from './types.js'
export * from './shared.js'
export * from './worker-repo.js'
export * from './work-order-repo.js'
export * from './product-match-repo.js'
export * from './sms-code-repo.js'
@@ -0,0 +1,181 @@
import { query } from '../../db/client.js'
import type { WorkProductMatchLogRow, WorkProductRuleMappingRow } from './types.js'
const MAPPING_SELECT = `
SELECT
wprm.*,
wpr.rule_key,
wpr.product_name
FROM work_product_rule_mappings wprm
INNER JOIN work_product_rules wpr ON wpr.id = wprm.rule_id
`
export async function listWorkProductRuleMappings(
input: {
enabled?: boolean | null
sellerId?: string
} = {},
): Promise<WorkProductRuleMappingRow[]> {
const conditions: string[] = []
const params: unknown[] = []
if (input.enabled !== undefined && input.enabled !== null) {
params.push(input.enabled)
conditions.push(`wprm.enabled = $${params.length}`)
}
const sellerId = String(input.sellerId || '')
.trim()
.toLowerCase()
if (sellerId) {
params.push(sellerId)
conditions.push(`wprm.seller_ids_json ? $${params.length}`)
}
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''
const result = await query<WorkProductRuleMappingRow>(
`${MAPPING_SELECT}
${where}
ORDER BY wprm.seller_ids_json::text ASC, wprm.rel_item_id ASC, wprm.item_title ASC,
CASE WHEN wprm.mapping_type = 'product_default' THEN 0 ELSE 1 END ASC,
wprm.id ASC`,
params,
)
return result.rows
}
export async function upsertWorkProductRuleMapping(input: {
mappingId?: number | null
ruleId: number
sellerIds: string[]
relItemId: string
itemTitle: string
relSkuId: string
skuNick: string
mappingType: 'product_default' | 'sku_exact' | 'sku_series'
enabled: boolean
now: string
}): Promise<WorkProductRuleMappingRow | null> {
if (input.mappingId) {
const result = await query<WorkProductRuleMappingRow>(
`
UPDATE work_product_rule_mappings
SET
rule_id = $2,
seller_ids_json = $3::jsonb,
rel_item_id = $4,
item_title = $5,
rel_sku_id = $6,
sku_nick = $7,
mapping_type = $8,
enabled = $9,
updated_at = $10
WHERE id = $1
RETURNING *
`,
[
input.mappingId,
input.ruleId,
JSON.stringify(input.sellerIds),
input.relItemId,
input.itemTitle,
input.relSkuId,
input.skuNick,
input.mappingType,
input.enabled,
input.now,
],
)
return result.rows[0] || null
}
const result = await query<WorkProductRuleMappingRow>(
`
INSERT INTO work_product_rule_mappings (
rule_id, seller_ids_json, rel_item_id, item_title, rel_sku_id, sku_nick,
mapping_type, enabled, created_at, updated_at
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $9)
RETURNING *
`,
[
input.ruleId,
JSON.stringify(input.sellerIds),
input.relItemId,
input.itemTitle,
input.relSkuId,
input.skuNick,
input.mappingType,
input.enabled,
input.now,
],
)
return result.rows[0] || null
}
export async function deleteWorkProductRuleMapping(mappingId: number | string) {
const result = await query<{ id: number }>(
'DELETE FROM work_product_rule_mappings WHERE id = $1 RETURNING id',
[Number(mappingId)],
)
return { deleted: Boolean(result.rows[0]) }
}
export async function createWorkProductMatchLog(input: {
orderId?: number | null
orderItemId?: number | null
source: string
sellerId: string
relItemId: string
itemTitle: string
relSkuId: string
skuNick: string
matchStatus: 'matched' | 'unmatched' | 'ambiguous'
ruleId?: number | null
mappingId?: number | null
candidatesJson: string
rawPayloadJson: string
now: string
}): Promise<WorkProductMatchLogRow | null> {
const result = await query<WorkProductMatchLogRow>(
`
INSERT INTO work_product_match_logs (
order_id, order_item_id, source, seller_id, rel_item_id, item_title,
rel_sku_id, sku_nick, match_status, rule_id, mapping_id,
candidates_json, raw_payload_json, created_at
) VALUES (
$1, $2, $3, $4, $5, $6,
$7, $8, $9, $10, $11,
$12::jsonb, $13::jsonb, $14
)
RETURNING *
`,
[
input.orderId || null,
input.orderItemId || null,
input.source,
input.sellerId,
input.relItemId,
input.itemTitle,
input.relSkuId,
input.skuNick,
input.matchStatus,
input.ruleId || null,
input.mappingId || null,
input.candidatesJson,
input.rawPayloadJson,
input.now,
],
)
return result.rows[0] || null
}
export async function listWorkProductMatchLogs(limit = 100): Promise<WorkProductMatchLogRow[]> {
const result = await query<WorkProductMatchLogRow>(
`
SELECT wpml.*, wpr.rule_key, wpr.product_name
FROM work_product_match_logs wpml
LEFT JOIN work_product_rules wpr ON wpr.id = wpml.rule_id
ORDER BY wpml.created_at DESC, wpml.id DESC
LIMIT $1
`,
[Math.min(500, Math.max(1, Math.floor(Number(limit) || 100)))],
)
return result.rows
}
@@ -160,6 +160,42 @@ export type WorkProductRuleRow = {
category_name?: string
}
export type WorkProductRuleMappingRow = {
id: number
rule_id: number
seller_ids_json: string | string[]
rel_item_id: string
item_title: string
rel_sku_id: string
sku_nick: string
mapping_type: 'product_default' | 'sku_exact' | 'sku_series' | string
enabled: boolean
created_at: string
updated_at: string
rule_key?: string
product_name?: string
}
export type WorkProductMatchLogRow = {
id: number
order_id: number | null
order_item_id: number | null
source: string
seller_id: string
rel_item_id: string
item_title: string
rel_sku_id: string
sku_nick: string
match_status: 'matched' | 'unmatched' | 'ambiguous' | string
rule_id: number | null
mapping_id: number | null
candidates_json: string | Record<string, unknown> | unknown[]
raw_payload_json: string | Record<string, unknown>
created_at: string
rule_key?: string
product_name?: string
}
export type WorkOrderShareRow = {
id: number
work_order_id: number