- 任务详情上传支持"本批素材无条码"开关,跳过条码必填校验 - SKU卡片/主图网格从4列改5列,图片高度压缩,去掉冗余标签和提示 - 详情图/PSD上传区去掉大占位框,改成紧凑按钮+标签 - 补充历史导入相关脚本和工具文件 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
188 lines
4.4 KiB
TypeScript
188 lines
4.4 KiB
TypeScript
/**
|
||
* SPU 型号解析器
|
||
* 从 SPU 型号中自动识别店铺和品类
|
||
*
|
||
* SPU 格式说明:
|
||
* - GBPM-SN0204 → 店铺: 朴美, 品类: 收纳柜斗柜角柜飘窗
|
||
* - XYL-BJ0301 → 店铺: 橡野里, 品类: 边几
|
||
* - SN0204 → 店铺: 用户手动选, 品类: 收纳柜斗柜角柜飘窗
|
||
*/
|
||
|
||
/**
|
||
* SPU 解析结果
|
||
*/
|
||
export interface SPUParseResult {
|
||
/** 是否成功解析到店铺 */
|
||
shopMatched: boolean
|
||
/** 店铺名称(如果识别成功) */
|
||
shopName: string
|
||
/** 是否成功解析到品类 */
|
||
categoryMatched: boolean
|
||
/** 品类名称(如果识别成功) */
|
||
categoryName: string
|
||
/** 品类代码(如 SN, XG 等) */
|
||
categoryCode: string
|
||
}
|
||
|
||
/**
|
||
* 店铺前缀映射表
|
||
* 前缀 → 店铺名称
|
||
*/
|
||
const SHOP_PREFIX_MAP: Record<string, string> = {
|
||
'GBPM': '朴美',
|
||
'GBSFY': '索菲亚',
|
||
'GBGJ': '顾家',
|
||
'GBJP': '顾家',
|
||
'XYL': '橡野里',
|
||
}
|
||
|
||
/**
|
||
* 品类代码映射表
|
||
* 代码 → 品类名称
|
||
*/
|
||
const CATEGORY_CODE_MAP: Record<string, string> = {
|
||
// 收纳类
|
||
'SN': '收纳柜斗柜角柜飘窗',
|
||
'DG': '收纳柜斗柜角柜飘窗',
|
||
|
||
// 柜类
|
||
'XG': '鞋柜',
|
||
'BG': '边柜',
|
||
'SG': '书柜',
|
||
'CBG': '餐边柜',
|
||
|
||
// 桌类
|
||
'CZ': '餐桌',
|
||
'SZ': '书桌',
|
||
'DNZ': '电脑桌',
|
||
'SJZ': '电脑桌',
|
||
'ZDZ': '电脑桌',
|
||
'CBZ': '电脑桌',
|
||
|
||
// 椅凳类
|
||
'CY': '椅子',
|
||
'AD': '椅子',
|
||
'SZD': '椅子',
|
||
'HXD': '换鞋凳',
|
||
|
||
// 架类
|
||
'SJ': '花架书架',
|
||
'ZSJ': '花架书架',
|
||
'ZWJ': '置物架',
|
||
'CFZW': '置物架',
|
||
'YMJ': '衣帽架',
|
||
|
||
// 几类
|
||
'BJ': '边几',
|
||
'CJ': '电视柜茶几',
|
||
'DSG': '电视柜茶几',
|
||
'CTG': '床头柜',
|
||
|
||
// 其他
|
||
'CYJ': '穿衣镜',
|
||
'SZT': '化妆台',
|
||
'XJ': '鞋架',
|
||
'LRSF': '沙发',
|
||
}
|
||
|
||
/**
|
||
* 获取所有店铺前缀(按长度降序排列,优先匹配长前缀)
|
||
*/
|
||
const SHOP_PREFIXES = Object.keys(SHOP_PREFIX_MAP).sort((a, b) => b.length - a.length)
|
||
|
||
/**
|
||
* 获取所有品类代码(按长度降序排列,优先匹配长代码)
|
||
*/
|
||
const CATEGORY_CODES = Object.keys(CATEGORY_CODE_MAP).sort((a, b) => b.length - a.length)
|
||
|
||
/**
|
||
* 解析 SPU 型号,提取店铺和品类信息
|
||
*
|
||
* @param spu SPU 型号字符串
|
||
* @returns 解析结果
|
||
*
|
||
* @example
|
||
* parseSPU('GBPM-SN0204')
|
||
* // { shopMatched: true, shopName: '朴美', categoryMatched: true, categoryName: '收纳柜斗柜角柜飘窗', categoryCode: 'SN' }
|
||
*
|
||
* parseSPU('XYL-BJ0301')
|
||
* // { shopMatched: true, shopName: '橡野里', categoryMatched: true, categoryName: '边几', categoryCode: 'BJ' }
|
||
*
|
||
* parseSPU('SN0204')
|
||
* // { shopMatched: false, shopName: '', categoryMatched: true, categoryName: '收纳柜斗柜角柜飘窗', categoryCode: 'SN' }
|
||
*/
|
||
export function parseSPU(spu: string): SPUParseResult {
|
||
const result: SPUParseResult = {
|
||
shopMatched: false,
|
||
shopName: '',
|
||
categoryMatched: false,
|
||
categoryName: '',
|
||
categoryCode: '',
|
||
}
|
||
|
||
if (!spu || typeof spu !== 'string') {
|
||
return result
|
||
}
|
||
|
||
// 统一转大写处理
|
||
const upperSPU = spu.toUpperCase().trim()
|
||
|
||
if (!upperSPU) {
|
||
return result
|
||
}
|
||
|
||
let remainingPart = upperSPU
|
||
|
||
// 1. 尝试匹配店铺前缀(格式:PREFIX-...)
|
||
for (const prefix of SHOP_PREFIXES) {
|
||
if (upperSPU.startsWith(prefix + '-')) {
|
||
result.shopMatched = true
|
||
result.shopName = SHOP_PREFIX_MAP[prefix]
|
||
remainingPart = upperSPU.substring(prefix.length + 1) // 去掉前缀和连字符
|
||
break
|
||
}
|
||
}
|
||
|
||
// 2. 尝试匹配品类代码(格式:CODE + 数字)
|
||
for (const code of CATEGORY_CODES) {
|
||
// 品类代码后面必须跟数字
|
||
const regex = new RegExp(`^${code}\\d`)
|
||
if (regex.test(remainingPart)) {
|
||
result.categoryMatched = true
|
||
result.categoryName = CATEGORY_CODE_MAP[code]
|
||
result.categoryCode = code
|
||
break
|
||
}
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
/**
|
||
* 获取所有可用的店铺前缀列表(用于提示)
|
||
*/
|
||
export function getShopPrefixes(): string[] {
|
||
return Object.keys(SHOP_PREFIX_MAP)
|
||
}
|
||
|
||
/**
|
||
* 获取所有可用的品类代码列表(用于提示)
|
||
*/
|
||
export function getCategoryCodes(): string[] {
|
||
return Object.keys(CATEGORY_CODE_MAP)
|
||
}
|
||
|
||
/**
|
||
* 获取店铺前缀映射表(用于调试或显示)
|
||
*/
|
||
export function getShopPrefixMap(): Record<string, string> {
|
||
return { ...SHOP_PREFIX_MAP }
|
||
}
|
||
|
||
/**
|
||
* 获取品类代码映射表(用于调试或显示)
|
||
*/
|
||
export function getCategoryCodeMap(): Record<string, string> {
|
||
return { ...CATEGORY_CODE_MAP }
|
||
}
|