feat(worker-platform): 增加寄卖匹配品类隔离门禁,杜绝手枪跨品类误匹配密钥礼盒
1. 新增 detectItemCategory 与 formatItemCategoryLabel 品类主体识别器(覆盖苏尔南手枪/枪皮、特种兵密钥、爆破型肩炮、专属礼盒、改名卡、点券等类目); 2. 寄卖匹配比对中引入强品类隔离门禁,在宽松模式下亦严禁跨品类误判为非精确匹配; 3. describeConsignmentSpecDifferences 补充品类级差异冲突说明,非同品类订单自动沉底; 4. 补充专项单测并保证全量测试与构建通过。
This commit is contained in:
@@ -600,3 +600,46 @@ test('发布寄卖建议价:号主钻级比后台配置高时,按已配置
|
||||
null,
|
||||
)
|
||||
})
|
||||
|
||||
test('品类隔离门禁:苏尔南手枪现货绝不匹配特种兵密钥、爆破型肩炮、专属礼盒等无关商品', () => {
|
||||
const invPistol = buildInventory({
|
||||
item_name: '苹果QQ区怒嚎3钻2璀璨 苏尔南',
|
||||
system: '苹果',
|
||||
server_zone: 'QQ区',
|
||||
series: '怒嚎',
|
||||
diamond_level: 3,
|
||||
brilliance_count: 2,
|
||||
})
|
||||
|
||||
// 1. 特种兵密钥
|
||||
const keyOrder = extractPeacekeeperSpecs('特种兵密钥1个')
|
||||
assert.equal(matchPeacekeeperOrderWithInventory(keyOrder, invPistol), null)
|
||||
assert.equal(
|
||||
matchPeacekeeperOrderWithInventory(keyOrder, invPistol, { allowUnspecifiedSpecs: true }),
|
||||
null,
|
||||
'宽松模式下也必须拒绝跨品类',
|
||||
)
|
||||
|
||||
// 2. 爆破型肩炮
|
||||
const cannonOrder = extractPeacekeeperSpecs('全新版【金色带特效】爆破型肩炮')
|
||||
assert.equal(matchPeacekeeperOrderWithInventory(cannonOrder, invPistol), null)
|
||||
assert.equal(
|
||||
matchPeacekeeperOrderWithInventory(cannonOrder, invPistol, { allowUnspecifiedSpecs: true }),
|
||||
null,
|
||||
)
|
||||
|
||||
// 3. 专属礼盒
|
||||
const boxOrder = extractPeacekeeperSpecs('1个精致荣耀专属礼盒')
|
||||
assert.equal(matchPeacekeeperOrderWithInventory(boxOrder, invPistol), null)
|
||||
assert.equal(
|
||||
matchPeacekeeperOrderWithInventory(boxOrder, invPistol, { allowUnspecifiedSpecs: true }),
|
||||
null,
|
||||
)
|
||||
|
||||
// 4. 正确的苏尔南手枪单子正常命中
|
||||
const pistolOrder = extractPeacekeeperSpecs('苹果QQ区怒嚎3钻 苏尔南手枪')
|
||||
const matched = matchPeacekeeperOrderWithInventory(pistolOrder, invPistol)
|
||||
assert.ok(matched)
|
||||
assert.equal(matched.matchType, 'partial') // 2璀璨充0璀璨
|
||||
})
|
||||
|
||||
|
||||
@@ -64,6 +64,85 @@ export function normalizePeacekeeperSeries(value: string): string {
|
||||
return extractPeacekeeperSeries(value) || String(value || '').trim()
|
||||
}
|
||||
|
||||
/** 常见商品品类主体定义 */
|
||||
export type ItemCategoryType =
|
||||
| 'pistol_skin' // 手枪/苏尔南/枪皮
|
||||
| 'key_secret' // 特种兵密钥/钥匙
|
||||
| 'cannon' // 爆破型肩炮/肩甲
|
||||
| 'gift_box' // 专属礼盒/宝箱/福袋
|
||||
| 'rename_card' // 改名卡/更名卡
|
||||
| 'diamond_topup' // 钻石/点券/充值
|
||||
| 'other'
|
||||
|
||||
export function detectItemCategory(text: string): ItemCategoryType {
|
||||
const normalized = String(text || '').toLowerCase()
|
||||
if (!normalized) return 'other'
|
||||
|
||||
// 1. 手枪/枪皮/苏尔南系列
|
||||
if (
|
||||
normalized.includes('苏尔南') ||
|
||||
normalized.includes('手枪') ||
|
||||
normalized.includes('暗潮') ||
|
||||
normalized.includes('怒嚎') ||
|
||||
normalized.includes('怒号') ||
|
||||
normalized.includes('血宴') ||
|
||||
normalized.includes('枪皮')
|
||||
) {
|
||||
return 'pistol_skin'
|
||||
}
|
||||
|
||||
// 2. 密钥/特种兵密钥
|
||||
if (
|
||||
normalized.includes('密钥') ||
|
||||
normalized.includes('密匙') ||
|
||||
normalized.includes('特种兵密钥') ||
|
||||
normalized.includes('钥匙')
|
||||
) {
|
||||
return 'key_secret'
|
||||
}
|
||||
|
||||
// 3. 肩炮
|
||||
if (normalized.includes('肩炮') || normalized.includes('爆破型肩炮')) {
|
||||
return 'cannon'
|
||||
}
|
||||
|
||||
// 4. 专属礼盒/宝箱
|
||||
if (normalized.includes('礼盒') || normalized.includes('宝箱') || normalized.includes('福袋')) {
|
||||
return 'gift_box'
|
||||
}
|
||||
|
||||
// 5. 改名卡
|
||||
if (normalized.includes('改名') || normalized.includes('更名')) {
|
||||
return 'rename_card'
|
||||
}
|
||||
|
||||
// 6. 钻石/点券充值
|
||||
if (normalized.includes('点券') || normalized.includes('代充') || normalized.includes('充值')) {
|
||||
return 'diamond_topup'
|
||||
}
|
||||
|
||||
return 'other'
|
||||
}
|
||||
|
||||
export function formatItemCategoryLabel(type: ItemCategoryType): string {
|
||||
switch (type) {
|
||||
case 'pistol_skin':
|
||||
return '苏尔南手枪/枪皮'
|
||||
case 'key_secret':
|
||||
return '特种兵密钥'
|
||||
case 'cannon':
|
||||
return '爆破型肩炮'
|
||||
case 'gift_box':
|
||||
return '专属礼盒'
|
||||
case 'rename_card':
|
||||
return '改名卡'
|
||||
case 'diamond_topup':
|
||||
return '点券/充值'
|
||||
default:
|
||||
return '其它类目'
|
||||
}
|
||||
}
|
||||
|
||||
function parseSpecsFromText(rawText: string): Omit<ParsedOrderSpecs, 'rawText'> {
|
||||
const text = String(rawText || '').trim()
|
||||
|
||||
@@ -167,6 +246,29 @@ export function matchPeacekeeperOrderWithInventory(
|
||||
return null
|
||||
}
|
||||
|
||||
// 1. 品类与物品主体强隔离门禁(防跨品类误判为非精确匹配)
|
||||
const orderCat = detectItemCategory(order.rawText)
|
||||
const invCat = detectItemCategory(
|
||||
`${inventory.item_name} ${inventory.series} ${inventory.category_name || ''}`,
|
||||
)
|
||||
|
||||
// 若两端均能识别出品类且不一致(如订单是密钥/肩炮/礼盒,现货是手枪/枪皮),直接拒绝
|
||||
if (orderCat !== 'other' && invCat !== 'other' && orderCat !== invCat) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 若现货明确为手枪/枪皮类目,订单不能是无任何手枪特征的其他商品
|
||||
if (invCat === 'pistol_skin') {
|
||||
const orderHasPistolSignal =
|
||||
Boolean(order.series) ||
|
||||
order.rawText.includes('苏尔南') ||
|
||||
order.rawText.includes('手枪') ||
|
||||
order.rawText.includes('枪皮')
|
||||
if (!orderHasPistolSignal) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const invSystem = normalizePeacekeeperSystem(inventory.system)
|
||||
const invZone = normalizePeacekeeperServerZone(inventory.server_zone)
|
||||
const invSeries = normalizePeacekeeperSeries(inventory.series)
|
||||
@@ -281,6 +383,26 @@ export function describeConsignmentSpecDifferences(
|
||||
inventory: ConsignmentInventoryRow,
|
||||
): string[] {
|
||||
const diffs: string[] = []
|
||||
|
||||
const orderCat = detectItemCategory(order.rawText)
|
||||
const invCat = detectItemCategory(
|
||||
`${inventory.item_name} ${inventory.series} ${inventory.category_name || ''}`,
|
||||
)
|
||||
if (orderCat !== 'other' && invCat !== 'other' && orderCat !== invCat) {
|
||||
diffs.push(
|
||||
`品类:订单「${formatItemCategoryLabel(orderCat)}」/ 现货「${formatItemCategoryLabel(invCat)}」`,
|
||||
)
|
||||
} else if (invCat === 'pistol_skin') {
|
||||
const orderHasPistolSignal =
|
||||
Boolean(order.series) ||
|
||||
order.rawText.includes('苏尔南') ||
|
||||
order.rawText.includes('手枪') ||
|
||||
order.rawText.includes('枪皮')
|
||||
if (!orderHasPistolSignal) {
|
||||
diffs.push(`品类:订单商品非手枪/枪皮 / 现货「苏尔南手枪/枪皮」`)
|
||||
}
|
||||
}
|
||||
|
||||
const compare = (
|
||||
label: string,
|
||||
orderValue: string,
|
||||
|
||||
Reference in New Issue
Block a user