170 lines
3.6 KiB
JavaScript
170 lines
3.6 KiB
JavaScript
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;
|
||
}
|