const CHINESE_CODE_INITIALS = { 产: "C", 品: "P", 原: "Y", 料: "L", 本: "B", 体: "T", 垃: "L", 圾: "J", 桶: "T", 垫: "D", 电: "D", 脑: "N", 支: "Z", 架: "J", 钢: "G", 板: "B", 卷: "J", 铝: "L", 合: "H", 金: "J", 铁: "T", 铜: "T", 不: "B", 锈: "X", 冷: "L", 热: "R", 轧: "Z", 镀: "D", 锌: "X", 冲: "C", 压: "Y", 件: "J", 片: "P", 管: "G", 棒: "B", 圆: "Y", 方: "F", 型: "X", 材: "C", 外: "W", 壳: "K", 底: "D", 座: "Z", 盖: "G", 盒: "H", 箱: "X", 门: "M", 锁: "S", 扣: "K", 连: "L", 接: "J" }; function normalizeText(value) { return String(value || "").trim(); } export function normalizeCodeToken(value, maxLength = 24) { const text = normalizeText(value).toUpperCase(); if (!text) { return ""; } const chunks = []; let current = ""; let currentKind = ""; const flushCurrent = () => { if (current) { chunks.push(current); } current = ""; currentKind = ""; }; for (const char of text.replaceAll("×", "X").replaceAll("*", "X")) { let kind = ""; let tokenChar = ""; if (/^[A-Z0-9.]$/.test(char)) { kind = "LATIN"; tokenChar = char; } else if (/^[\u4e00-\u9fff]$/.test(char)) { const mapped = CHINESE_CODE_INITIALS[char]; if (mapped) { kind = "CJK"; tokenChar = mapped; } else { kind = "CJK_RAW"; tokenChar = char; } } else { flushCurrent(); continue; } if (currentKind && currentKind !== kind) { flushCurrent(); } currentKind = kind; current += tokenChar; } flushCurrent(); return chunks.join("-").slice(0, maxLength).replace(/^[.-]+|[.-]+$/g, ""); } function buildCodePrefix(parts, maxLength = 42) { const tokens = parts.map((part) => normalizeCodeToken(part)).filter(Boolean); if (!tokens.length) { return ""; } return tokens.join("-").slice(0, maxLength).replace(/^[.-]+|[.-]+$/g, ""); } export function buildNextProductSpecCode(products = []) { let maxNo = 0; for (const product of products || []) { const code = normalizeText(product?.item_code); const match = code.match(/^产品需规(\d{5})$/); if (match) { maxNo = Math.max(maxNo, Number(match[1])); } } return `产品需规${String(maxNo + 1).padStart(5, "0")}`; } export function buildProductCodePreview(form, savedCode = "", nextCode = "") { if (normalizeText(savedCode)) { return savedCode; } return normalizeText(nextCode) || "产品需规00001"; } export function buildNextMaterialCode(materials = []) { let maxNo = 0; for (const material of materials || []) { const code = normalizeText(material?.item_code); const match = code.match(/^原材料(\d{5})$/); if (match) { maxNo = Math.max(maxNo, Number(match[1])); } } return `原材料${String(maxNo + 1).padStart(5, "0")}`; } export function buildMaterialCodePreview(form, savedCode = "", nextCode = "") { if (normalizeText(savedCode)) { return savedCode; } return normalizeText(nextCode) || "原材料00001"; } export function buildBomCodePreview(productCode, savedCode = "") { if (normalizeText(savedCode)) { return savedCode; } const prefix = buildCodePrefix(["BOM", productCode || "产品编码"], 50) || "BOM-产品编码"; return prefix; } export function buildRouteCodePreview(productCode, savedCode = "") { if (normalizeText(savedCode)) { return savedCode; } const prefix = buildCodePrefix(["ROUTE", productCode || "产品编码"], 50) || "ROUTE-产品编码"; return prefix; }