优化接单模板匹配
This commit is contained in:
@@ -29,7 +29,7 @@ import {
|
||||
getWorkerUserById,
|
||||
getWorkOrderStatistics,
|
||||
getWorkOrderByOrderItemId,
|
||||
getWorkProductRuleByKey,
|
||||
getWorkProductRuleById,
|
||||
listAllWorkCategories,
|
||||
listWorkerFinanceRequests,
|
||||
listWorkOrders,
|
||||
@@ -306,6 +306,11 @@ export async function saveAdminWorkProductRuleMapping(payload: JsonObject = {})
|
||||
mappingType === 'product_default'
|
||||
? ''
|
||||
: String(payload.skuNick ?? payload.sku_nick ?? '').trim()
|
||||
const skuMatchMode =
|
||||
mappingType === 'sku_series' &&
|
||||
String(payload.skuMatchMode ?? payload.sku_match_mode ?? '').trim() === 'exact'
|
||||
? 'exact'
|
||||
: 'fuzzy'
|
||||
const requiresProductScope = mappingType === 'product_default'
|
||||
if (
|
||||
!ruleId ||
|
||||
@@ -357,6 +362,7 @@ export async function saveAdminWorkProductRuleMapping(payload: JsonObject = {})
|
||||
itemTitle,
|
||||
relSkuId,
|
||||
skuNick,
|
||||
skuMatchMode,
|
||||
mappingType,
|
||||
enabled: normalizeBoolean(payload.enabled, true),
|
||||
now: nowIso(),
|
||||
@@ -488,6 +494,7 @@ function mapWorkProductRuleMapping(mapping: WorkProductRuleMappingRow) {
|
||||
itemTitle: String(mapping.item_title || ''),
|
||||
relSkuId: String(mapping.rel_sku_id || ''),
|
||||
skuNick: String(mapping.sku_nick || ''),
|
||||
skuMatchMode: mapping.sku_match_mode === 'exact' ? 'exact' : 'fuzzy',
|
||||
mappingType:
|
||||
mapping.mapping_type === 'sku_series'
|
||||
? 'sku_series'
|
||||
@@ -622,18 +629,16 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
|
||||
}
|
||||
const finalRewardAmount = sharingEnabled ? resolvedSharingTotalAmount : rewardAmount
|
||||
|
||||
const fields = normalizeRequirementFieldsFromPayload(payload)
|
||||
const ruleKey = normalizeSlugKey(
|
||||
payload.ruleKey || payload.rule_key || skuCode || productName || matchedProductName,
|
||||
`rule-${Date.now()}`,
|
||||
)
|
||||
const ruleId = normalizeOptionalId(payload.ruleId ?? payload.rule_id)
|
||||
if (!ruleId && (await getWorkProductRuleByKey(ruleKey))) {
|
||||
throw createHttpError('规则标识已存在,请更换后重试', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_product_rule_key_taken',
|
||||
const existingRule = ruleId ? await getWorkProductRuleById(ruleId) : null
|
||||
if (ruleId && !existingRule) {
|
||||
throw createHttpError('接单模板不存在', {
|
||||
statusCode: 404,
|
||||
errorCode: 'work_product_rule_not_found',
|
||||
})
|
||||
}
|
||||
const fields = normalizeRequirementFieldsFromPayload(payload)
|
||||
const ruleKey = existingRule?.rule_key || randomId('rule-')
|
||||
const rule = await upsertWorkProductRule({
|
||||
ruleKey,
|
||||
provider: String(payload.provider || '').trim(),
|
||||
|
||||
@@ -760,9 +760,8 @@ function scoreWorkProductRuleMapping(
|
||||
if (skuNickMatched) score += 200
|
||||
}
|
||||
if (mappingType === 'sku_series') {
|
||||
const mappedSeries = normalizeSkuSeriesName(mapping.sku_nick)
|
||||
const actualSeries = normalizeSkuSeriesName(context.skuNick)
|
||||
if (!mappedSeries || !actualSeries || actualSeries !== mappedSeries) return null
|
||||
const skuMatchMode = mapping.sku_match_mode === 'exact' ? 'exact' : 'fuzzy'
|
||||
if (!matchSkuSeriesName(context.skuNick, mapping.sku_nick, skuMatchMode)) return null
|
||||
score += 200
|
||||
}
|
||||
return { rule, score, mappingId: Number(mapping.id) }
|
||||
@@ -917,6 +916,21 @@ function normalizeSkuSeriesName(value: unknown) {
|
||||
)
|
||||
}
|
||||
|
||||
function matchSkuSeriesName(actual: unknown, expected: unknown, matchMode: 'fuzzy' | 'exact') {
|
||||
const normalizedActual = normalizeSkuSeriesName(actual)
|
||||
const normalizedExpected = normalizeSkuSeriesName(expected)
|
||||
if (!normalizedActual || !normalizedExpected) return false
|
||||
if (matchMode === 'exact') return normalizedActual === normalizedExpected
|
||||
|
||||
const fuzzyActual = normalizeFuzzySkuSeriesName(normalizedActual)
|
||||
const fuzzyExpected = normalizeFuzzySkuSeriesName(normalizedExpected)
|
||||
return fuzzyActual.includes(fuzzyExpected) || fuzzyExpected.includes(fuzzyActual)
|
||||
}
|
||||
|
||||
function normalizeFuzzySkuSeriesName(value: string) {
|
||||
return value.replace(/秘钥|密匙|秘匙/g, '密钥')
|
||||
}
|
||||
|
||||
export function normalizeWorkProductRuleMatch(payload: JsonObject): JsonObject {
|
||||
const match =
|
||||
payload.match && typeof payload.match === 'object' && !Array.isArray(payload.match)
|
||||
|
||||
@@ -109,6 +109,7 @@ function buildProductMapping(
|
||||
item_title: '和平精英密钥指挥官特种兵侦察兵密钥',
|
||||
rel_sku_id: '',
|
||||
sku_nick: '',
|
||||
sku_match_mode: 'fuzzy',
|
||||
mapping_type: 'product_default',
|
||||
enabled: true,
|
||||
created_at: '2026-08-18T00:00:00.000Z',
|
||||
@@ -253,6 +254,55 @@ test('SKU 数量系列可覆盖多店铺的前后数量规格', () => {
|
||||
assert.equal(decision.rule?.rule_key, 'commander-series')
|
||||
})
|
||||
|
||||
test('SKU 数量系列默认模糊匹配密钥和秘钥', () => {
|
||||
const item = buildOrderItemRow()
|
||||
item.item_snapshot_json = {
|
||||
kuaishouSendCode: {
|
||||
...item.item_snapshot_json.kuaishouSendCode,
|
||||
skuNick: '指挥官秘钥8个',
|
||||
},
|
||||
}
|
||||
const rule = buildProductRule({ product_name: '' })
|
||||
const decision = resolveMatchingProductRuleDecision(
|
||||
buildOrderRow(),
|
||||
item,
|
||||
[rule],
|
||||
[
|
||||
buildProductMapping({
|
||||
mapping_type: 'sku_series',
|
||||
sku_nick: '指挥官密钥',
|
||||
}),
|
||||
],
|
||||
)
|
||||
|
||||
assert.equal(decision.reason, 'matched')
|
||||
})
|
||||
|
||||
test('SKU 数量系列精确匹配不兼容密钥和秘钥', () => {
|
||||
const item = buildOrderItemRow()
|
||||
item.item_snapshot_json = {
|
||||
kuaishouSendCode: {
|
||||
...item.item_snapshot_json.kuaishouSendCode,
|
||||
skuNick: '指挥官秘钥8个',
|
||||
},
|
||||
}
|
||||
const rule = buildProductRule({ product_name: '' })
|
||||
const decision = resolveMatchingProductRuleDecision(
|
||||
buildOrderRow(),
|
||||
item,
|
||||
[rule],
|
||||
[
|
||||
buildProductMapping({
|
||||
mapping_type: 'sku_series',
|
||||
sku_nick: '指挥官密钥',
|
||||
sku_match_mode: 'exact',
|
||||
}),
|
||||
],
|
||||
)
|
||||
|
||||
assert.equal(decision.reason, 'unmatched')
|
||||
})
|
||||
|
||||
test('商品默认映射支持用逗号填写多个关联商品 ID', () => {
|
||||
const item = buildOrderItemRow()
|
||||
item.item_snapshot_json = {
|
||||
|
||||
Reference in New Issue
Block a user