const PRODUCT_MODEL_ALLOWED_CHARACTERS = /^[A-Z0-9][A-Z0-9+_.-]*[A-Z0-9]$/ /** * SPU 唯一允许的自动格式化是转成大写。空格、中文和其它非法字符必须 * 原样留在输入框里交给校验提示,不能静默删除后把另一个型号写入数据库。 */ export function normalizeSpuProductModel(value: unknown): string { return typeof value === 'string' ? value.replace(/[a-z]/g, character => character.toUpperCase()) : '' } export const SPU_PRODUCT_MODEL_FORMAT_HINT = '必须同时包含英文字母和数字,只能使用字母、数字及 +、-、_、.,且不能以符号开头或结尾' export function getSpuProductModelValidationError(value: unknown): string | null { const normalized = normalizeSpuProductModel(value) if (!normalized) return '请填写真实 SPU,例如 DF-A3DZ0008' if (normalized.length > 100) return 'SPU 不能超过 100 个字符' if (normalized !== normalized.trim()) return 'SPU 前后不能包含空格' if (!/[A-Z]/.test(normalized) || !/\d/.test(normalized)) { return 'SPU 必须同时包含英文字母和数字' } if (!PRODUCT_MODEL_ALLOWED_CHARACTERS.test(normalized)) { return `SPU ${SPU_PRODUCT_MODEL_FORMAT_HINT}` } return null } /** * 这里只拒绝可以明确判定不是 SPU 的值,不假设所有业务线都使用同一套编码。 * 现有合法型号包含 DF-A3DZ0008、GBPM-SN0204、626DNZ0385-1 等多种格式; * 共同边界是包含英文字母和数字,且不能以分隔符开头或结尾。 */ export function isPlausibleSpuProductModel(value: unknown): boolean { return getSpuProductModelValidationError(value) === null } /** * 从文件名中只提取“有明确型号结构”的 SPU;无法确认时必须返回空值, * 交给上传人填写,不能再把中文被剔除后的数字尾号冒充为 SPU。 */ export function extractPlausibleSpuFromFileName(filename: string): string { const nameWithoutExtension = normalizeSpuProductModel(filename.replace(/\.[^/.]+$/, '')) // 只接受整个文件名(不含扩展名)就是合法 SPU;带说明文字或额外字符时留空, // 由上传人确认填写,绝不从文件名中截取一段并冒充用户的 SPU。 return isPlausibleSpuProductModel(nameWithoutExtension) ? nameWithoutExtension : '' }