SKU判别支持MKH等业务前缀无连字符拼接品类码

This commit is contained in:
chenpei 2026-08-26 09:23:14 +08:00
parent ec782a914e
commit 8bb0fc5c47
2 changed files with 11 additions and 6 deletions

View File

@ -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) => {

View File

@ -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')