diff --git a/lib/__tests__/sku-barcode-detector.test.ts b/lib/__tests__/sku-barcode-detector.test.ts index 8a827ac0..0ec098c2 100644 --- a/lib/__tests__/sku-barcode-detector.test.ts +++ b/lib/__tests__/sku-barcode-detector.test.ts @@ -19,6 +19,8 @@ describe('detectSkuOrBarcodeName(SKU 图文件名判别)', () => { ['DNZ038521', 'skuCode'], ['AD033601', 'skuCode'], ['GBSFY-AD0360', 'skuCode'], // 带店铺前缀 + ['MKHDNZ0409260600987', 'skuCode'], // MKH=模块化前缀,无连字符直接拼品类码(测试人员真实用例) + ['GBSFYAD0360', 'skuCode'], // 店铺前缀无连字符形态 ])('%s → %s', (input, expected) => { expect(detectSkuOrBarcodeName(input)?.type).toBe(expected) }) @@ -30,7 +32,6 @@ describe('detectSkuOrBarcodeName(SKU 图文件名判别)', () => { ['02-1'], ['MKH-DNZ038528N1280V01-1-GBGJ-DNZ038415N1261V01-5'], // 复合串 ['GBPM-BJ019201N1280V01场景'], // 含中文 - ['GBSFYAD0360'], // 店铺前缀无连字符,无法区分前缀与品类码,从严不填 ['随便起的名字'], [''], ])('%s → 不填(null)', (input) => { diff --git a/lib/sku-barcode-detector.ts b/lib/sku-barcode-detector.ts index b4562db6..7f41c91c 100644 --- a/lib/sku-barcode-detector.ts +++ b/lib/sku-barcode-detector.ts @@ -2,14 +2,18 @@ * SKU 图文件名 → SKU 编号 / 产品条码 自动判别 * * 依据生产数据的稳定结构(配合 lib/spu-parser.ts 的品类字典): - * - SKU 编号: 品类码 + 纯数字,如 DNZ038521、AD033601,可带店铺前缀 GBSFY-AD0360 - * - 产品条码: SKU 编号 + N数字V数字 段,如 DNZ038521N1280V01、CY001306N35V01 + * - SKU 编号: [前缀-?]品类码 + 纯数字,如 DNZ038521、AD033601、GBSFY-AD0360、MKHDNZ0409260600987 + * - 产品条码: SKU 编号 + N数字(V数字)? 段,如 DNZ038521N1280V01、CY001306N35V01 * - 其余(纯序号、02-1、复合串、含中文等)判别不出,交给人工填写 * - * 判定从严:两条规则都是整串锚定匹配,同时命中或都不命中一律返回 null,绝不猜。 + * 前缀连字符可选:MKH(模块化)等业务前缀直接无连字符拼接品类码; + * MKH 不在品类字典中,词典层面无歧义。判定的其余部分整串锚定,绝不猜。 */ import { getCategoryCodes, getShopPrefixes } from '@/lib/spu-parser' +/** 直接拼接在品类码前的业务前缀(无连字符形态),与店铺前缀一并剥离判定。 */ +const EXTRA_NAKED_PREFIXES = ['MKH'] + export type SkuOrBarcodeDetection = | { type: 'barcode'; value: string } | { type: 'skuCode'; value: string } @@ -20,7 +24,7 @@ function escapeRegExp(value: string): string { function buildPattern(kind: 'barcode' | 'skuCode'): RegExp { // 长前缀/长品类码放在 alternation 前面,避免短码抢先匹配(如 AD 抢掉 ADX 前缀的场景)。 - const shops = getShopPrefixes() + const shops = [...getShopPrefixes(), ...EXTRA_NAKED_PREFIXES] .map(escapeRegExp) .sort((a, b) => b.length - a.length) .join('|') @@ -29,7 +33,7 @@ function buildPattern(kind: 'barcode' | 'skuCode'): RegExp { .sort((a, b) => b.length - a.length) .join('|') - const shopPart = shops ? `(?:(?:${shops})-)?` : '' + const shopPart = shops ? `(?:(?:${shops})-?)?` : '' // N 段必有,V 段可省(生产数据存在 cy001301N35 这种无 V 段的真实条码)。 const tail = kind === 'barcode' ? 'N\\d+(?:V\\d+)?' : '' return new RegExp(`^${shopPart}(?:${categories})\\d+${tail}$`, 'i')