62 lines
2.5 KiB
TypeScript
62 lines
2.5 KiB
TypeScript
/**
|
||
* SKU 图文件名 → SKU 编号 / 产品条码 自动判别
|
||
*
|
||
* 依据生产数据的稳定结构(配合 lib/spu-parser.ts 的品类字典):
|
||
* - SKU 编号: [前缀-?]品类码 + 纯数字,如 DNZ038521、AD033601、GBSFY-AD0360、MKHDNZ0409260600987
|
||
* - 产品条码: SKU 编号 + N数字(V数字)? 段,如 DNZ038521N1280V01、CY001306N35V01
|
||
* - 其余(纯序号、02-1、复合串、含中文等)判别不出,交给人工填写
|
||
*
|
||
* 前缀连字符可选: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 }
|
||
|
||
function escapeRegExp(value: string): string {
|
||
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||
}
|
||
|
||
function buildPattern(kind: 'barcode' | 'skuCode'): RegExp {
|
||
// 长前缀/长品类码放在 alternation 前面,避免短码抢先匹配(如 AD 抢掉 ADX 前缀的场景)。
|
||
const shops = [...getShopPrefixes(), ...EXTRA_NAKED_PREFIXES]
|
||
.map(escapeRegExp)
|
||
.sort((a, b) => b.length - a.length)
|
||
.join('|')
|
||
const categories = getCategoryCodes()
|
||
.map(escapeRegExp)
|
||
.sort((a, b) => b.length - a.length)
|
||
.join('|')
|
||
|
||
const shopPart = shops ? `(?:(?:${shops})-?)?` : ''
|
||
// N 段必有,V 段可省(生产数据存在 cy001301N35 这种无 V 段的真实条码)。
|
||
const tail = kind === 'barcode' ? 'N\\d+(?:V\\d+)?' : ''
|
||
return new RegExp(`^${shopPart}(?:${categories})\\d+${tail}$`, 'i')
|
||
}
|
||
|
||
const BARCODE_PATTERN = buildPattern('barcode')
|
||
const SKU_CODE_PATTERN = buildPattern('skuCode')
|
||
|
||
/**
|
||
* 判别一个 SKU 图文件名(应先剥掉图片后缀)。
|
||
* 返回 null 表示命名不规范,不自动填,由上传人员人工填写。
|
||
*/
|
||
export function detectSkuOrBarcodeName(name: string): SkuOrBarcodeDetection | null {
|
||
const trimmed = String(name || '').trim()
|
||
if (!trimmed) return null
|
||
|
||
// 整串锚定:两条规则天然互斥(skuCode 规则的 \d+$ 不容 N/V 段),顺序无关。
|
||
if (BARCODE_PATTERN.test(trimmed)) {
|
||
return { type: 'barcode', value: trimmed }
|
||
}
|
||
if (SKU_CODE_PATTERN.test(trimmed)) {
|
||
return { type: 'skuCode', value: trimmed }
|
||
}
|
||
return null
|
||
}
|