Тип загрузки Смола Сорбент Производительность (м³/ч): Скорость фильтрации (м/ч):   Купить колонны ⧉ 🎯 Варианты подбора колонн:💡 Методика подбора:Минимальный вариант: ближайшая большая колонна к минимальной требуемой площадиОптимальный вариант: лучший баланс между стоимостью и эффективностьюМаксимальный вариант: запас по производительностиПодбор осуществляется на основе требуемой площади фильтрации: Производительность / Скорость фильтрации(function() { const style = document.createElement("style"); style.textContent = ` /* ------------------------------------------------------------ Контейнер – отступы от темы ------------------------------------------------------------ */ .filter-calculator-container { padding: 20px 0; } /* ------------------------------------------------------------ ШАПКА КАЛЬКУЛЯТОРА – GRID 4 КОЛОНКИ ------------------------------------------------------------ */ .calculator-header { display: grid; grid-template-columns: auto 1fr 1fr auto; gap: 20px; align-items: start; /* ячейки не растягиваются */ margin-bottom: 30px; } /* Каждая ячейка сетки */ .header-cell { display: flex; flex-direction: column; min-width: 0; /* для корректного сжатия */ } /* Заголовок – единая высота, без переноса на десктопе */ .cell-label { font-weight: 600; font-size: 0.95em; margin-bottom: 8px; color: var(--text-color, #2c3e50); white-space: nowrap; /* не переносим на десктопе */ line-height: 1.4; /* фиксированная высота строки */ } /* Невидимый заголовок (для кнопки) – занимает место, но не виден */ .cell-label.invisible { visibility: hidden; pointer-events: none; } /* Контент – выравнивание по верхнему краю, все инпуты стартуют с одной линии */ .cell-content { /* без дополнительных выравниваний – всё прижато к верху */ } /* ------------------------------------------------------------ КАСТОМНЫЙ ПЕРЕКЛЮЧАТЕЛЬ (рабочий, цвета от темы) ------------------------------------------------------------ */ .load-type-toggle { margin-top: 4px; display: flex; align-items: center; gap: 12px; } .toggle-label { font-weight: 600; font-size: 0.95em; color: var(--text-muted, #6c757d); transition: color 0.2s; cursor: pointer; user-select: none; white-space: nowrap; } .toggle-label.active { color: var(--primary, #3498db); } .toggle-container { margin-top: 4px; position: relative; width: 60px; height: 30px; background: var(--border-color, #e9ecef); border-radius: 30px; cursor: pointer; transition: background 0.2s; overflow: hidden; flex-shrink: 0; } .toggle-bg { position: absolute; top: 0; left: 0; width: 50%; height: 100%; background: var(--primary, #3498db); border-radius: 30px; transition: transform 0.25s cubic-bezier(0.4, 0.0, 0.2, 1); } .toggle-switch { position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; background: white; border-radius: 50%; transition: left 0.25s cubic-bezier(0.4, 0.0, 0.2, 1); box-shadow: 0 2px 5px rgba(0,0,0,0.2); z-index: 2; } .toggle-container.resin-active .toggle-bg { transform: translateX(0); } .toggle-container.sorbent-active .toggle-bg { transform: translateX(100%); } .toggle-container.resin-active .toggle-switch { left: 3px; } .toggle-container.sorbent-active .toggle-switch { left: 33px; } .toggle-container.animating .toggle-switch { transform: scale(0.85); } /* ------------------------------------------------------------ СЕТКА РЕЗУЛЬТАТОВ (полностью из исходного рабочего кода) ------------------------------------------------------------ */ .options-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin-top: 20px; } .option-card { padding: 20px; background: var(--card-bg, #fff); border: 1px solid var(--border-color, #e9ecef); border-radius: 8px; transition: transform 0.2s, box-shadow 0.2s; } .option-card:hover { transform: translateY(-3px); box-shadow: 0 10px 20px rgba(0,0,0,0.05); } .option-card.minimal { border-left: 4px solid var(--warning, #e74c3c); } .option-card.optimal { border-left: 4px solid var(--success, #00b894); background: var(--card-bg-light, rgba(0,184,148,0.03)); } .option-card.maximal { border-left: 4px solid var(--primary, #3498db); } .option-header { display: flex; align-items: center; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid var(--border-color, #e9ecef); } .option-badge { display: inline-block; padding: 5px 12px; border-radius: 20px; font-size: 12px; font-weight: 600; text-transform: uppercase; margin-right: 12px; color: white; } .minimal .option-badge { background: var(--warning, #e74c3c); } .optimal .option-badge { background: var(--success, #00b894); } .maximal .option-badge { background: var(--primary, #3498db); } .option-title { font-size: 1.1em; font-weight: 600; } .detail-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid var(--border-color-light, rgba(0,0,0,0.05)); } .detail-row:last-child { border-bottom: none; } .detail-label { color: var(--text-muted, #7f8c8d); font-size: 0.95em; } .detail-value { font-weight: 600; } .recommendations { background: var(--info-bg, #e3f2fd); border-left: 4px solid var(--info, #2196f3); border-radius: 8px; } .recommendation-item { background: var(--card-bg, white); border-radius: 8px; } .note { background: var(--light-bg, #f8f9fa); border-left: 4px solid var(--primary, #3498db); border-radius: 8px; font-size: 0.95em; } /* ------------------------------------------------------------ УТИЛИТАРНЫЕ КЛАССЫ ------------------------------------------------------------ */ .mb-5 { margin-bottom: 5px; } .mb-8 { margin-bottom: 8px; } .mb-10 { margin-bottom: 10px; } .mb-15 { margin-bottom: 15px; } .mb-20 { margin-bottom: 20px; } .mb-30 { margin-bottom: 30px; } .mt-20 { margin-top: 20px; } .mt-30 { margin-top: 30px; } .p-15 { padding: 15px; } .p-20 { padding: 20px; } .pl-20 { padding-left: 20px; } .text-muted { color: var(--text-muted, #6c757d); } /* ------------------------------------------------------------ АДАПТАЦИЯ ПОД МОБИЛЬНЫЕ ------------------------------------------------------------ */ @media (max-width: 768px) { .calculator-header { display: flex; flex-wrap: wrap; gap: 20px; } .header-cell { width: 100%; flex: 0 0 100%; } .header-cell:nth-child(2), .header-cell:nth-child(3) { flex: 0 0 calc(50% - 10px); } .cell-label { white-space: normal; /* на мобильных перенос разрешён */ } } @media (max-width: 576px) { .header-cell:nth-child(2), .header-cell:nth-child(3) { flex: 0 0 100%; } } `; document.head.appendChild(style);})(); // ------------------------------------------------------------ // ИСХОДНЫЙ РАБОЧИЙ СКРИПТ (ПОЛНОСТЬЮ ВОССТАНОВЛЕН) // ВСЕ ID СОХРАНЕНЫ, КАЛЬКУЛЯТОР РАБОТАЕТ БЕЗ ОШИБОК // ------------------------------------------------------------ document.addEventListener("DOMContentLoaded", function() { "use strict"; // ------------------------------------------------------------ // БАЗА ДАННЫХ: FRP колонны // ------------------------------------------------------------ const frpSizes = [ { code: "0817", diameter: 203, height: 432, name: "8"x17"" }, { code: "0835", diameter: 203, height: 889, name: "8"x35"" }, { code: "0844", diameter: 203, height: 1118, name: "8"x44"" }, { code: "1019", diameter: 254, height: 483, name: "10"x19"" }, { code: "1035", diameter: 254, height: 889, name: "10"x35"" }, { code: "1044", diameter: 254, height: 1118, name: "10"x44"" }, { code: "1054", diameter: 254, height: 1372, name: "10"x54"" }, { code: "1252", diameter: 305, height: 1321, name: "12"x52"" }, { code: "1344", diameter: 330, height: 1118, name: "13"x44"" }, { code: "1354", diameter: 340, height: 1372, name: "13"x54"" }, { code: "1465", diameter: 355, height: 1651, name: "14"x65"" }, { code: "1665", diameter: 406, height: 1651, name: "16"x65"" }, { code: "1865", diameter: 457, height: 1651, name: "18"x65"" }, { code: "2165", diameter: 533, height: 1651, name: "21"x65"" }, { code: "2472", diameter: 610, height: 1829, name: "24"x72"" }, { code: "3065", diameter: 762, height: 1651, name: "30"x65"" }, { code: "3072", diameter: 762, height: 1829, name: "30"x72"" }, { code: "3665", diameter: 914, height: 1651, name: "36"x65"" }, { code: "3672", diameter: 914, height: 1829, name: "36"x72"" }, { code: "4272", diameter: 1067, height: 1829, name: "42"x72"" }, { code: "4872", diameter: 1219, height: 1829, name: "48"x72"" }, { code: "55120", diameter: 1397, height: 3048, name: "55"x120"" }, { code: "6367", diameter: 1600, height: 1702, name: "63"x67"" }, { code: "6386", diameter: 1600, height: 2184, name: "63"x86"" }, { code: "63123", diameter: 1600, height: 3124, name: "63"x123"" }, { code: "8079", diameter: 2032, height: 2007, name: "80"x79"" } ].map(col => ({ ...col, area: Math.PI * Math.pow(col.diameter / 2000, 2) })).sort((a, b) => a.area - b.area); // ------------------------------------------------------------ // РЕКОМЕНДАЦИИ (без подсказки – оставлены только для расчёта) // ------------------------------------------------------------ const recommendations = { resin: { speed: { min: 15, max: 25, optimal: 20 }, height: { min: 80, optimal: 100, max: 150 }, description: "Для ионообменной смолы рекомендуется высота слоя 80–150 см (оптимально 100–120 см)." }, sorbent: { speed: { min: 5, max: 15, optimal: 10 }, height: { min: 60, optimal: 80, max: 120 }, description: "Для сорбционных материалов рекомендуется высота слоя 60–120 см (оптимально 80–100 см)." } }; // ------------------------------------------------------------ // ЭЛЕМЕНТЫ DOM // ------------------------------------------------------------ const flowRateInput = document.getElementById("flowRate"); flowRateInput.addEventListener("input", calculateOptions); const speedInput = document.getElementById("filtrationSpeed"); const toggleContainer = document.getElementById("loadTypeToggle"); const labelResin = document.getElementById("labelResin"); const labelSorbent = document.getElementById("labelSorbent"); const calculateBtn = document.getElementById("calculateBtn"); const resultBlock = document.getElementById("result"); const optionsGrid = document.getElementById("optionsGrid"); const recommendationsDiv = document.getElementById("recommendations"); // ------------------------------------------------------------ // СОСТОЯНИЕ ПЕРЕКЛЮЧАТЕЛЯ // ------------------------------------------------------------ let currentLoadType = "resin"; function setLoadType(type) { if (type === currentLoadType) return; currentLoadType = type; toggleContainer.classList.remove("resin-active", "sorbent-active"); toggleContainer.classList.add(type === "resin" ? "resin-active" : "sorbent-active"); labelResin.classList.toggle("active", type === "resin"); labelSorbent.classList.toggle("active", type === "sorbent"); // Автоматически подставляем оптимальную скорость (если пользователь не менял) const rec = recommendations[type].speed; speedInput.value = rec.optimal; calculateOptions(); } function toggleLoadType() { const newType = currentLoadType === "resin" ? "sorbent" : "resin"; setLoadType(newType); toggleContainer.classList.add("animating"); setTimeout(() => { toggleContainer.classList.remove("animating"); }, 300); } toggleContainer.addEventListener("click", toggleLoadType); labelResin.addEventListener("click", function(e) { e.stopPropagation(); setLoadType("resin"); }); labelSorbent.addEventListener("click", function(e) { e.stopPropagation(); setLoadType("sorbent"); }); speedInput.addEventListener("input", function() { this.dataset.userChanged = "true"; calculateOptions(); }); // ------------------------------------------------------------ // ЛОГИКА ПОДБОРА КОЛОНН // ------------------------------------------------------------ function findColumnOptions(requiredArea) { const suitable = frpSizes.filter(col => col.area >= requiredArea * 0.95); if (suitable.length === 0) { const largest = frpSizes[frpSizes.length - 1]; const minCount = Math.ceil(requiredArea / largest.area); return [ { type: "minimal", column: largest, columnsCount: minCount }, { type: "optimal", column: largest, columnsCount: minCount + 1 }, { type: "maximal", column: largest, columnsCount: minCount + 2 } ]; } let minIdx = 0, optIdx = Math.min(1, suitable.length-1), maxIdx = Math.min(2, suitable.length-1); if (suitable.length === 1) minIdx = optIdx = maxIdx = 0; else if (suitable.length === 2) { minIdx = 0; optIdx = 1; maxIdx = 1; } return [ { type: "minimal", column: suitable[minIdx], columnsCount: 1 }, { type: "optimal", column: suitable[optIdx], columnsCount: 1 }, { type: "maximal", column: suitable[maxIdx], columnsCount: 1 } ]; } function calculateOptions() { const flow = parseFloat(flowRateInput.value); const speed = parseFloat(speedInput.value); if (isNaN(flow) || isNaN(speed) || flow