/** * 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 = { 'GBPM': '朴美', 'GBSFY': '索菲亚', 'GBGJ': '顾家', 'GBJP': '顾家', 'XYL': '橡野里', } /** * 品类代码映射表 * 代码 → 品类名称 */ const CATEGORY_CODE_MAP: Record = { // 收纳类 '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 { return { ...SHOP_PREFIX_MAP } } /** * 获取品类代码映射表(用于调试或显示) */ export function getCategoryCodeMap(): Record { return { ...CATEGORY_CODE_MAP } }