(function (global) { "use strict"; /** Показатели для зоотех-расчёта рациона (weighted average). */ const NUTRIENT_ROWS = [ { label: "Осн. корм", unit: "г/кг СВ", keys: ["Осн.Корм"], hint: "СВ этого сырья, учитываемое как объёмный (основной) корм в норме dm_main. 0 — концентрат/добавка.", }, { label: "Сыр. протеин", unit: "г/кг", keys: ["Сыр. Протеин"] }, { label: "уСП", unit: "г/кг", keys: ["уСП"] }, { label: "RNB", unit: "г/кг", keys: ["RNB", "БРА", " БРА "] }, { label: "ЧЭЛ — КРС", unit: "МДж/кг", keys: ["ЧЭЛ- КРС", " ЧЭЛ- КРС"] }, { label: "ОЭ — КРС", unit: "МДж/кг", keys: ["ОЭ-КРС", " ОЭ-КРС"] }, { label: "Сырая клетчатка", unit: "г/кг", keys: ["Сырая клетч", "Сырая клетчатка"] }, { label: "Структур. клетч.", unit: "г/кг", keys: ["Структур клетч", "Структур. клетч", "Структур. клетчатка"] }, { label: "Сырой жир", unit: "г/кг", keys: ["Сырой жир"] }, ]; /** Лаб. ввод для native derive (см. LAB_FORMULAS.md). СВ — только component.dry_matter (%). */ const LAB_INPUT_ROWS = [ { label: "Сырая зола", unit: "г/кг", keys: ["Сырая зола"] }, { label: "ВРХ орг. вещ.", unit: "%", keys: ["ВРХ Орг Вещ"], hint: "Обязательно для грубых и сочных кормов. Без значения подставится дефолт WESP (65% / 72%).", }, { label: "уСП в ОР", unit: "г/кг", keys: ["уСП в ОР", "уСП в ОВ"], hint: "Лабораторное уСП: при значении > 1 заменяет расчёт по формуле Lebzien.", }, { label: "КРС протеин", unit: "%", keys: ["КРС Протеин"] }, { label: "КРС сырой жир", unit: "%", keys: ["КРС Сырой жир"] }, { label: "КРС сырая клетч.", unit: "%", keys: ["КРС Сырая клетч"] }, { label: "КРС БЭВ", unit: "%", keys: ["КРС БЭВ"] }, { label: "НДК", unit: "г/кг", keys: ["НДК", "НДК Общ"] }, { label: "NFC", unit: "г/кг", keys: ["NFC", "БЕР"] }, ]; /** Минералы, аминокислоты и прочий лаб. ввод из AgroStar / импорта. */ const EXTRA_LAB_ROWS = [ { label: "КДК (ADF)", unit: "г/кг", keys: ["КДК", "КДК общ"] }, { label: "Ca", unit: "г/кг", keys: ["Ca"] }, { label: "P", unit: "г/кг", keys: ["P"] }, { label: "Mg", unit: "г/кг", keys: ["Mg"] }, { label: "K", unit: "г/кг", keys: ["K"] }, { label: "S", unit: "г/кг", keys: ["S"] }, { label: "Cl", unit: "г/кг", keys: ["CL", "Cl"] }, { label: "Сахар", unit: "г/кг", keys: ["Сахар"] }, { label: "Крахмал", unit: "г/кг", keys: ["Крахмал"] }, { label: "Нераств. протеин", unit: "%", keys: ["% нераствор протеин"] }, { label: "Лизин", unit: "г/кг", keys: ["Лизин"] }, { label: "Метионин", unit: "г/кг", keys: ["Метионин"] }, { label: "Лейцин", unit: "г/кг", keys: ["Лейцин"] }, { label: "Изолейцин", unit: "г/кг", keys: ["Изолейцин"] }, { label: "Валин", unit: "г/кг", keys: ["Валин"] }, ]; const ALL_FORM_ROWS = [...NUTRIENT_ROWS, ...LAB_INPUT_ROWS, ...EXTRA_LAB_ROWS]; const CARD_INFO_COLUMNS = [ { label: "Сухое вещество", value(component) { const dm = component.dryMatter ?? component.dry_matter; return dm == null || dm === "" ? "—" : `${dm}%`; }, }, { label: "№ справочника", value(component) { const n = component.externalNo ?? component.external_no; return n == null || n === "" ? "—" : String(n); }, }, { label: "Цена", value(component) { const price = component.price; return price == null || price === "" ? "—" : `${price} руб/кг`; }, }, { label: "Осн. корм", value(_component, nutrients) { const val = readNutrientValue(nutrients, ["Осн.Корм"]); return val == null ? "—" : `${val} г/кг`; }, }, { label: "Сыр. протеин", value(_component, nutrients) { const val = readNutrientValue(nutrients, ["Сыр. Протеин"]); return val == null ? "—" : `${val} г/кг`; }, }, { label: "ОЭ — КРС", value(_component, nutrients) { const val = readNutrientValue(nutrients, ["ОЭ-КРС", " ОЭ-КРС"]); return val == null ? "—" : `${val} МДж/кг`; }, }, { label: "СВ (расч.)", value(component) { const dm = component.dryMatter ?? component.dry_matter; if (dm == null || dm === "") return "—"; const n = Number(dm); if (Number.isNaN(n)) return "—"; return `${(n * 10).toFixed(1)} г/кг`; }, }, { label: "Показателей", value(_component, nutrients) { return String(Object.keys(nutrients || {}).length); }, }, ]; function normalizeKey(s) { return String(s || "") .replace(/\s+/g, " ") .trim() .toLowerCase(); } function parseNutrients(raw) { if (!raw) return {}; if (typeof raw === "object") return { ...raw }; try { return JSON.parse(raw) || {}; } catch (_) { return {}; } } function readNutrientValue(nutrients, keys) { const map = nutrients || {}; for (const search of keys) { const target = normalizeKey(search); for (const [k, v] of Object.entries(map)) { if (normalizeKey(k) !== target) continue; const n = Number(v); if (!Number.isNaN(n)) return n; } } return null; } function canonicalKey(keys) { return keys[0]; } function buildNutrientsPayload(root) { const payload = {}; if (!root) return payload; root.querySelectorAll("[data-nutrient-key]").forEach((input) => { const key = input.getAttribute("data-nutrient-key"); const val = input.value.trim(); if (key && val !== "") payload[key] = Number(val); }); return payload; } function rowFieldsHtml(rows, nutrients) { return rows .map((row) => { const key = canonicalKey(row.keys); const val = readNutrientValue(nutrients, row.keys); const hint = row.hint ? ` title="${row.hint}"` : ""; return ( `