gongxiangp2/lib/spu-parser.ts
chenpei 752b7bf999 fix: 修复批量上传和视频扩展名问题
主要修复:

- 修复批量上传闭包陷阱,防止文件丢失

- 添加 fileName 参数传递原始文件名,保留正确扩展名

- 添加取消检查回调,改进批量上传取消功能

其他改进:

- 优化搜索功能和管理后台

- 添加 FRP 故障诊断文档

- 更新环境验证和网络检测
2026-02-03 11:12:50 +08:00

187 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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': '顾家',
'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 }
}