Spaces:
Running
Running
| <html lang="ru"> | |
| <head> | |
| <!-- Основные стили PNotify --> | |
| <link href="https://cdn.jsdelivr.net/npm/notyf@3/notyf.min.css" rel="stylesheet"> | |
| <script src="https://cdn.jsdelivr.net/npm/notyf@3/notyf.min.js"></script> | |
| <meta charset="UTF-8"> | |
| <title>Калькулятор удобрений</title> | |
| <style> | |
| /* Общие стили */ | |
| body { | |
| margin: 0 auto; | |
| width: 1000px; | |
| padding: 1em; | |
| background-color: #f0f0f0; | |
| font-family: Arial, sans-serif; | |
| } | |
| /* Стили для заголовка */ | |
| .header-box { | |
| border: 2px solid #2e8b57; | |
| background-color: #2e8b57; | |
| color: white; | |
| text-align: center; | |
| padding: 1em; | |
| border-radius: 10px; | |
| margin-bottom: 20px; | |
| width: 1000px; | |
| box-sizing: border-box; | |
| } | |
| /* Общие стили для всех рамок */ | |
| fieldset, .calculation-box { | |
| border: 2px solid #2e8b57; | |
| background-color: #eaffea; | |
| padding: 1em; | |
| margin-bottom: 20px; | |
| border-radius: 8px; | |
| width: 1000px; | |
| box-sizing: border-box; | |
| } | |
| legend { | |
| font-weight: bold; | |
| color: #2e8b57; | |
| padding: 0 10px; | |
| } | |
| /* Стили для блока профиля */ | |
| .main-container { | |
| display: grid; | |
| grid-template-columns: 40px repeat(7, 110px); | |
| gap: 10px; | |
| padding: 10px; | |
| margin-left: -50px; /* Сдвигаем блок левее */ | |
| } | |
| .profile-container { | |
| display: contents; | |
| } | |
| .profile-element { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 5px; | |
| } | |
| .profile-label { | |
| font-weight: bold; | |
| font-size: 0.9em; | |
| } | |
| .profile-element input { | |
| width: 80px; | |
| padding: 5px; | |
| border: 1px solid #ccc; | |
| border-radius: 4px; | |
| text-align: center; | |
| } | |
| .nitrogen-container { | |
| grid-column: 1 / -1; | |
| display: flex; | |
| gap: 20px; | |
| padding-left: 40px; | |
| margin-top: 5px; | |
| } | |
| .nitrogen-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 5px; | |
| } | |
| .nitrogen-group label { | |
| font-weight: bold; | |
| font-size: 0.9em; | |
| } | |
| .nitrogen-group input { | |
| width: 60px; | |
| padding: 5px; | |
| border: 1px solid #ccc; | |
| border-radius: 4px; | |
| } | |
| /* Стили для колонок азотных элементов */ | |
| .nitrogen-container { | |
| display: flex; | |
| gap: 20px; | |
| align-items: flex-start; | |
| margin-left: 20px; /* Сдвигаем блок правее */ | |
| } | |
| .nitrogen-column { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 10px; | |
| align-items: center; /* Центрируем содержимое колонки */ | |
| } | |
| .column-header { | |
| font-weight: bold; | |
| font-size: 0.8em; | |
| margin-bottom: 5px; | |
| text-align: center; | |
| width: 100%; | |
| } | |
| .nitrogen-group { | |
| display: flex; | |
| justify-content: center; /* Центрируем поля ввода */ | |
| } | |
| .nitrogen-group input { | |
| width: 80px; | |
| padding: 5px; | |
| border: 1px solid #ccc; | |
| border-radius: 4px; | |
| } | |
| /* Стили для контейнера первого блока (NPK) */ | |
| .npk-container { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 10px; /* Отступ между заголовком и основным блоком */ | |
| margin-left: 15px; /* Общий отступ слева */ | |
| margin-top: 10px; /* Отступ сверху */ | |
| } | |
| /* Стили для заголовка NPK */ | |
| .header-npk { | |
| font-weight: bold; | |
| font-size: 0.9em; | |
| text-align: center; | |
| width: 65px; /* Ширина заголовка совпадает с шириной блока */ | |
| margin-bottom: 5px; /* Отступ между заголовком и основным блоком */ | |
| margin-left: -5px; /* Сдвигаем строки влево */ | |
| margin-bottom: 5px; /* Отступ между заголовком и основным блоком */ | |
| } | |
| /* Стили для основного блока NPK */ | |
| .block-npk { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 5px; | |
| padding: 10px; | |
| background-color: #eaffea; | |
| border: 1px solid #2e8b57; | |
| border-radius: 8px; | |
| width: 65px; /* Ширина блока */ | |
| } | |
| /* Стили для внутреннего контейнера строк (NPK) */ | |
| .inner-block-npk { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 5px; | |
| margin-left: -33px; /* Сдвигаем строки влево */ | |
| margin-right: 0px; /* Добавляем внешний отступ справа */ | |
| padding-bottom: 26px; /* Добавляем внешний отступ справа */ | |
| } | |
| .row-npk { | |
| display: flex; | |
| align-items: center; | |
| gap: 5px; | |
| } | |
| .label-npk { | |
| font-weight: bold; | |
| min-width: 50px; /* Минимальная ширина меток */ | |
| text-align: right; | |
| } | |
| .row-npk span { | |
| font-size: 0.9em; | |
| } | |
| /* Стили для контейнера второго блока (Ca-Mg-S) */ | |
| .camgs-container { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 10px; /* Отступ между заголовком и основным блоком */ | |
| margin-left: 8px; /* Общий отступ слева */ | |
| margin-top: 10px; /* Отступ сверху */ | |
| } | |
| /* Стили для заголовка Ca-Mg-S */ | |
| .header-camgs { | |
| font-weight: bold; | |
| font-size: 0.9em; | |
| text-align: center; | |
| width: 75px; /* Ширина заголовка совпадает с шириной блока */ | |
| margin-bottom: 5px; /* Отступ между заголовком и основным блоком */ | |
| } | |
| /* Стили для основного блока Ca-Mg-S */ | |
| .block-camgs { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 5px; | |
| padding: 10px; | |
| background-color: #eaffea; | |
| border: 1px solid #2e8b57; | |
| border-radius: 8px; | |
| width: 85px; /* Ширина блока */ | |
| } | |
| /* Стили для внутреннего контейнера строк (Ca-Mg-S) */ | |
| .inner-block-camgs { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 5px; | |
| margin-left: -31px; /* Сдвигаем строки влево */ | |
| margin-right: 0px; /* Добавляем внешний отступ справа */ | |
| padding-bottom: 26px; /* Добавляем внешний отступ*/ | |
| } | |
| .row-camgs { | |
| display: flex; | |
| align-items: center; | |
| gap: 5px; | |
| } | |
| .label-camgs { | |
| font-weight: bold; | |
| min-width: 65px; /* Минимальная ширина меток */ | |
| text-align: right; | |
| } | |
| .row-camgs span { | |
| font-size: 0.9em; | |
| } | |
| /* Стили для контейнера блока N1 */ | |
| .n1-container { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 10px; /* Отступ между заголовком и основным блоком */ | |
| margin-left: 8px; /* Общий отступ слева */ | |
| margin-top: 10px; /* Отступ сверху */ | |
| } | |
| /* Стили для заголовка N1 */ | |
| .header-n1 { | |
| font-weight: bold; | |
| font-size: 0.9em; | |
| text-align: left; | |
| width: 100%; /* Ширина заголовка */ | |
| margin-bottom: 5px; /* Отступ между заголовком и основным блоком */ | |
| } | |
| .header-n1 span { | |
| margin-right: 5px; /* Отступ между "N1=" и значением */ | |
| } | |
| #n1-value { | |
| font-weight: normal; | |
| color: #333; | |
| min-width: 100px; /* Место для значения */ | |
| } | |
| /* Стили для основного блока N1 */ | |
| .block-n1 { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 5px; | |
| padding: 10px; | |
| background-color: #eaffea; | |
| border: 1px solid #2e8b57; | |
| border-radius: 8px; | |
| width: 200px; /* Ширина блока */ | |
| } | |
| /* Стили для строки с меткой и индикатором */ | |
| .n1-row { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 5px; | |
| width: 100%; | |
| } | |
| .label-n1 { | |
| font-weight: bold; | |
| font-size: 0.9em; | |
| text-align: left; | |
| width: 100%; | |
| } | |
| /* Стили для контейнера индикатора */ | |
| .indicator-container { | |
| width: 150px; /* Ширина индикатора */ | |
| height: 10px; /* Высота индикатора */ | |
| background-color: #f0f0f0; /* Фон индикатора */ | |
| border-radius: 5px; | |
| overflow: hidden; | |
| position: relative; | |
| } | |
| /* Стили для индикатора */ | |
| .indicator { | |
| height: 100%; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| transition: width 0.3s ease; /* Плавное изменение ширины */ | |
| } | |
| .red-indicator { | |
| background-color: red; | |
| } | |
| .blue-indicator { | |
| background-color: blue; | |
| } | |
| /* Стили для таблицы удобрений */ | |
| .fertilisers-container { | |
| display: flex; | |
| flex-direction: column; | |
| margin-left: 40px; /* Сдвигаем блок */ | |
| } | |
| .fert-row { | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 8px; | |
| } | |
| .fert-header { | |
| font-weight: bold; | |
| text-align: center; | |
| width: 80px; | |
| padding: 5px; | |
| font-size: 0.9em; | |
| } | |
| .fert-name { | |
| font-weight: bold; | |
| width: 120px; | |
| text-align: left; | |
| font-size: 0.9em; | |
| } | |
| .fert-cell { | |
| text-align: center; | |
| width: 80px; | |
| padding: 5px; | |
| font-size: 0.9em; | |
| } | |
| .fert-input { | |
| width: 70px; | |
| padding: 5px; | |
| border: 1px solid #ccc; | |
| border-radius: 4px; | |
| text-align: center; | |
| margin: 0 5px; | |
| font-size: 0.9em; | |
| } | |
| /* Стили для блока расчета */ | |
| .calculation-container { | |
| display: flex; | |
| gap: 40px; | |
| align-items: flex-start; | |
| } | |
| .compensation-section { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 10px; | |
| } | |
| .enhancement-title { | |
| font-weight: bold; | |
| color: #2e8b57; | |
| margin-bottom: 5px; | |
| } | |
| .compensation-weights { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .weight-input-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .weight-input-group label { | |
| width: 80px; | |
| text-align: right; | |
| font-weight: bold; | |
| font-size: 0.9em; | |
| } | |
| .weight-input-group input { | |
| width: 70px; | |
| padding: 5px; | |
| border: 1px solid #ccc; | |
| border-radius: 4px; | |
| } | |
| .input-column { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 10px; | |
| } | |
| #calculate-btn { | |
| background-color: #2e8b57; | |
| color: white; | |
| border: none; | |
| padding: 8px 16px; | |
| font-size: 16px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| transition: background-color 0.3s; | |
| margin-bottom: 5px; | |
| font-weight: bold; | |
| } | |
| #calculate-btn:hover { | |
| background-color: #3cb371; | |
| } | |
| .input-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .input-group label { | |
| width: 80px; | |
| text-align: right; | |
| font-weight: bold; | |
| font-size: 0.9em; | |
| } | |
| .input-group input { | |
| width: 70px; | |
| padding: 5px; | |
| border: 1px solid #ccc; | |
| border-radius: 4px; | |
| } | |
| .micro-container { | |
| padding: 10px; | |
| } | |
| .micro-row { | |
| display: flex; | |
| gap: 20px; | |
| } | |
| .micro-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 5px; | |
| } | |
| .micro-group label { | |
| min-width: 120px; | |
| } | |
| .micro-group input { | |
| width: 80px; | |
| text-align: right; | |
| } | |
| </style> | |
| <body> | |
| <div class="header-box"> | |
| <h1>Калькулятор удобрений</h1> | |
| </div> | |
| <fieldset> | |
| <legend>Макропрофиль в мг/л (ppm)</legend> | |
| <div class="main-container"> | |
| <!-- Основные элементы --> | |
| <div class="profile-container"> | |
| <div class="profile-element" style="grid-column: 2"> | |
| <span class="profile-label">N</span> | |
| <input id="profile_n" type="number" value="125.000" step="0.001"/> | |
| </div> | |
| <div class="profile-element" style="grid-column: 3"> | |
| <span class="profile-label">P</span> | |
| <input id="profile_p" type="number" value="31.000" step="0.001"/> | |
| </div> | |
| <div class="profile-element" style="grid-column: 4"> | |
| <span class="profile-label">K</span> | |
| <input id="profile_k" type="number" value="210.000" step="0.001"/> | |
| </div> | |
| <div class="profile-element" style="grid-column: 5"> | |
| <span class="profile-label">Ca</span> | |
| <input id="profile_ca" type="number" value="82.000" step="0.001"/> | |
| </div> | |
| <div class="profile-element" style="grid-column: 6"> | |
| <span class="profile-label">Mg</span> | |
| <input id="profile_mg" type="number" value="24.000" step="0.001"/> | |
| </div> | |
| <div class="profile-element" style="grid-column: 7"> | |
| <span class="profile-label">S</span> | |
| <input id="profile_s" type="number" value="57.49" step="0.001"/> | |
| </div> | |
| <div class="profile-element" style="grid-column: 8"> | |
| <span class="profile-label">EC</span> | |
| <input id="profile_ec" type="number" value="0.0" step="0.001"/> | |
| </div> | |
| <div class="profile-element" style="grid-column: 9"> | |
| <span class="profile-label">t°C</span> | |
| <input id="profile_temp" type="number" value="25.0" step="0.01"/> | |
| </div> | |
| </div> | |
| <!-- Азотные элементы и блок NPK --> | |
| <div style="display: flex; align-items: flex-start; gap: 20px;"> | |
| <!-- Колонки азотных элементов --> | |
| <div class="nitrogen-container" style="margin-top: 10px; display: flex; gap: 20px;"> | |
| <!-- Колонка 1: NH4 --> | |
| <div class="nitrogen-column"> | |
| <div class="column-header">NH4</div> | |
| <div class="nitrogen-group"> | |
| <input id="profile_nh4" type="number" value="1.0" step="1.0" readonly style="background-color: #f0f0f0; color: #666;"> | |
| </div> | |
| <div class="nitrogen-group"> | |
| <input id="calculated_nh4" type="number" value="0.000" step="0.001" readonly style="background-color: #f0f0f0; color: #666;"> | |
| </div> | |
| </div> | |
| <!-- Колонка 2: NO3 --> | |
| <div class="nitrogen-column"> | |
| <div class="column-header">NO3</div> | |
| <div class="nitrogen-group"> | |
| <input id="profile_no3" type="number" value="8.25" step="0.01" min="0" max="100.001"/> | |
| </div> | |
| <div class="nitrogen-group"> | |
| <input id="calculated_no3" type="number" value="0.000" step="0.001" readonly style="background-color: #f0f0f0; color: #666;"> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Первый блок NPK --> | |
| <div class="npk-container"> | |
| <!-- Заголовок NPK --> | |
| <div class="header-npk">N-P-K</div> | |
| <!-- Основной блок с содержимым --> | |
| <div class="block-npk"> | |
| <!-- Дополнительный контейнер для строк --> | |
| <div class="inner-block-npk"> | |
| <div class="row-npk"> | |
| <span class="label-npk">N:</span> | |
| <span id="npk-n-value">0</span> | |
| </div> | |
| <div class="row-npk"> | |
| <span class="label-npk">P:</span> | |
| <span id="npk-p-value">0</span> | |
| </div> | |
| <div class="row-npk"> | |
| <span class="label-npk">K:</span> | |
| <span id="npk-k-value">0</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Второй блок Ca-Mg-S --> | |
| <div class="camgs-container"> | |
| <!-- Заголовок Ca-Mg-S --> | |
| <div class="header-camgs">Ca-Mg-S</div> | |
| <!-- Основной блок с содержимым --> | |
| <div class="block-camgs"> | |
| <!-- Дополнительный контейнер для строк --> | |
| <div class="inner-block-camgs"> | |
| <div class="row-camgs"> | |
| <span class="label-camgs">CaO:</span> | |
| <span id="caMaS-ca-value">0</span> | |
| </div> | |
| <div class="row-camgs"> | |
| <span class="label-camgs">MgO:</span> | |
| <span id="caMaS-mg-value">0</span> | |
| </div> | |
| <div class="row-camgs"> | |
| <span class="label-camgs">SO:</span> | |
| <span id="caMaS-so-value">0</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Блок N1 --> | |
| <div class="n1-container"> | |
| <!-- Заголовок N1 --> | |
| <div class="header-n1"> | |
| <span>N1:</span> | |
| <span id="n1-value">0.25:1.88:0.67:0.19:0.45 PPM=528.35</span> | |
| </div> | |
| <!-- Основной блок с содержимым --> | |
| <div class="block-n1"> | |
| <!-- Катионы --> | |
| <div class="n1-row"> | |
| <span class="label-n1">Катионы:</span> | |
| <div class="indicator-container"> | |
| <div class="indicator red-indicator" id="cation-indicator"></div> | |
| </div> | |
| </div> | |
| <!-- Анионы --> | |
| <div class="n1-row"> | |
| <span class="label-n1">Анионы:</span> | |
| <div class="indicator-container"> | |
| <div class="indicator blue-indicator" id="anion-indicator"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </fieldset> | |
| <fieldset> | |
| <legend>Составы солей</legend> | |
| <div class="fertilisers-container"> | |
| <!-- Заголовки --> | |
| <div class="fert-row"> | |
| <span class="fert-name">Удобрение</span> | |
| <span class="fert-header">NH4</span> | |
| <span class="fert-header">NO3</span> | |
| <span class="fert-header">P</span> | |
| <span class="fert-header">K</span> | |
| <span class="fert-header">Ca</span> | |
| <span class="fert-header">Mg</span> | |
| <span class="fert-header">S</span> | |
| <span class="fert-header">Грамм</span> | |
| </div> | |
| <!-- Строки с удобрениями --> | |
| <div class="fert-row"> | |
| <span class="fert-name">CaN2O6</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" value="11.863" step="0.001" id="fert_ca_no3"/> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" value="16.972" step="0.001" id="fert_ca_ca"/> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" step="0.001" id="calcium_nitrate"/> | |
| </div> | |
| <div class="fert-row"> | |
| <span class="fert-name">KNO3</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" value="13.854" step="0.001" id="fert_kno3_no3"/> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" value="36.672" step="0.001" id="fert_kno3_k"/> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" step="0.001" id="potassium_nitrate"/> | |
| </div> | |
| <div class="fert-row"> | |
| <span class="fert-name">NH4NO3</span> | |
| <input class="fert-input" type="number" value="17.499" step="0.001" id="fert_nh4no3_nh4"/> | |
| <input class="fert-input" type="number" value="17.499" step="0.001" id="fert_nh4no3_no3"/> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" step="0.001" id="ammonium_nitrate"/> | |
| </div> | |
| <div class="fert-row"> | |
| <span class="fert-name">MgSO4</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" value="10.22" step="0.001" id="fert_mgso4_mg"/> | |
| <input class="fert-input" type="number" value="13.483" step="0.001" id="fert_mgso4_s"/> | |
| <input class="fert-input" type="number" step="0.001" id="magnesium_sulfate"/> | |
| </div> | |
| <div class="fert-row"> | |
| <span class="fert-name">KH2PO4</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" value="22.761" step="0.001" id="fert_kh2po4_p"/> | |
| <input class="fert-input" type="number" value="28.731" step="0.001" id="fert_kh2po4_k"/> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" step="0.001" id="monopotassium_phosphate"/> | |
| </div> | |
| <div class="fert-row"> | |
| <span class="fert-name">K2SO4</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" value="44.874" step="0.001" id="fert_k2so4_k"/> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" value="18.401" step="0.001" id="fert_k2so4_s"/> | |
| <input class="fert-input" type="number" step="0.001" id="potassium_sulfate"/> | |
| </div> | |
| <!-- Добавленные строки для Fe и Micro --> | |
| <div class="fert-row"> | |
| <span class="fert-name">Fe</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" step="0.001" id="iron_amount"> | |
| </div> | |
| <div class="fert-row"> | |
| <span class="fert-name">Micro</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <span class="fert-cell">-</span> | |
| <input class="fert-input" type="number" step="0.001" id="micro_amount"> | |
| </div> | |
| </div> | |
| </fieldset> | |
| <fieldset class="calculation-box"> | |
| <legend>Расчёт удобрений</legend> | |
| <div class="calculation-container"> | |
| <div class="compensation-section"> | |
| <div class="input-column"> | |
| <button id="calculate-btn">Рассчитать</button> | |
| <div class="input-group"> | |
| <label for="liters-input">Литры:</label> | |
| <input type="number" id="liters-input" value="100" min="1" step="1"> | |
| </div> | |
| <div class="input-group"> | |
| <label for="rounding-precision">Точность:</label> | |
| <input type="number" id="rounding-precision" value="3" min="0" max="3" step="1"> | |
| </div> | |
| </div> | |
| </div> | |
| </fieldset> | |
| <!-- Кастомные стили --> | |
| <style> | |
| .pnotify-success { | |
| background: linear-gradient(135deg, #4CAF50, #2E7D32) ; | |
| border-left: 5px solid #1B5E20 ; | |
| } | |
| .pnotify-error { | |
| background: linear-gradient(135deg, #F44336, #C62828) ; | |
| border-left: 5px solid #B71C1C ; | |
| } | |
| .deficit-item { | |
| margin: 8px 0; | |
| display: flex; | |
| align-items: center; | |
| } | |
| .deficit-item i { | |
| margin-right: 10px; | |
| font-size: 1.2em; | |
| } | |
| </style> | |
| <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/toastify-js"></script> | |
| <script> | |
| let call_data; | |
| const ecConstants = { | |
| 'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015, | |
| 'Ca': 0.0016, 'S': 0.0014, | |
| 'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019 | |
| }; | |
| document.getElementById('calculate-btn').addEventListener('click', function() { | |
| console.log("=== НАЧАЛО ОБРАБОТКИ ==="); | |
| // 1. Получаем значение точности округления с подробным логированием | |
| const roundingInput = document.getElementById('rounding-precision'); | |
| console.log("Значение поля rounding-precision (raw):", roundingInput.value); | |
| const initialRounding = parseInt(roundingInput.value); | |
| console.log("Парсинг значения rounding (после parseInt):", initialRounding); | |
| const roundingPrecision = Math.min(Math.max(initialRounding || 3, 0), 6); | |
| console.log("Финальное значение точности (0-6):", roundingPrecision); | |
| // 2. Улучшенная функция для безопасного получения числового значения с логированием | |
| const getValue = (id) => { | |
| const element = document.getElementById(id); | |
| if (!element) { | |
| console.error(`Элемент с ID ${id} не найден!`); | |
| return 0; | |
| } | |
| console.log(`Значение поля ${id}:`, element.value); | |
| const value = parseFloat(element.value); | |
| const result = isNaN(value) ? 0 : value; | |
| console.log(`Парсинг значения ${id}:`, result); | |
| return result; | |
| }; | |
| // 3. Формируем данные для сервера с пошаговым логированием | |
| console.log("=== ФОРМИРОВАНИЕ ДАННЫХ ДЛЯ СЕРВЕРА ==="); | |
| const fertilizerConstants = { | |
| "Кальциевая селитра": { | |
| "N (NO3-)": getValue('fert_ca_no3') / 100, | |
| "Ca": getValue('fert_ca_ca') / 100 | |
| }, | |
| "Калий азотнокислый": { | |
| "N (NO3-)": getValue('fert_kno3_no3') / 100, | |
| "K": getValue('fert_kno3_k') / 100 | |
| }, | |
| "Аммоний азотнокислый": { | |
| "N (NO3-)": getValue('fert_nh4no3_no3') / 100, | |
| "N (NH4+)": getValue('fert_nh4no3_nh4') / 100 | |
| }, | |
| "Сульфат магния": { | |
| "Mg": getValue('fert_mgso4_mg') / 100, | |
| "S": getValue('fert_mgso4_s') / 100 | |
| }, | |
| "Монофосфат калия": { | |
| "P": getValue('fert_kh2po4_p') / 100, | |
| "K": getValue('fert_kh2po4_k') / 100 | |
| }, | |
| "Калий сернокислый": { | |
| "K": getValue('fert_k2so4_k') / 100, | |
| "S": getValue('fert_k2so4_s') / 100 | |
| } | |
| }; | |
| const profileSettings = { | |
| 'P': getValue('profile_p'), | |
| 'K': getValue('profile_k'), | |
| 'Mg': getValue('profile_mg'), | |
| 'Ca': getValue('profile_ca'), | |
| 'S': getValue('profile_s'), | |
| 'NO3_RAT': getValue('profile_no3'), | |
| 'TOTAL_NITROG': getValue('profile_n'), | |
| 'liters': parseInt(document.getElementById('liters-input').value) || 1, | |
| 'rounding_precision': roundingPrecision | |
| }; | |
| const requestData = { | |
| fertilizerConstants: fertilizerConstants, | |
| profileSettings: profileSettings | |
| }; | |
| console.log("=== ПОЛНЫЙ ОБЪЕКТ ДЛЯ ОТПРАВКИ ===", JSON.stringify(requestData, null, 2)); | |
| // 4. Проверка данных с подробным выводом | |
| console.log("=== ПРОВЕРКА ДАННЫХ ==="); | |
| const requiredFertilizers = ["Кальциевая селитра", "Калий азотнокислый", "Аммоний азотнокислый", | |
| "Сульфат магния", "Монофосфат калия", "Калий сернокислый"]; | |
| let hasErrors = false; | |
| for (const fert of requiredFertilizers) { | |
| if (!requestData.fertilizerConstants[fert]) { | |
| console.error(`ОШИБКА: Отсутствует удобрение: ${fert}`); | |
| hasErrors = true; | |
| } else { | |
| console.log(`Удобрение ${fert} присутствует`); | |
| } | |
| } | |
| const requiredProfileFields = ['P', 'K', 'Mg', 'Ca', 'S', 'NO3_RAT', 'TOTAL_NITROG']; | |
| for (const field of requiredProfileFields) { | |
| if (isNaN(requestData.profileSettings[field])) { | |
| console.error(`ОШИБКА: Некорректное значение для параметра ${field}`); | |
| hasErrors = true; | |
| } else { | |
| console.log(`Параметр ${field} в порядке:`, requestData.profileSettings[field]); | |
| } | |
| } | |
| console.log("Параметр rounding_precision:", requestData.profileSettings.rounding_precision); | |
| if (hasErrors) { | |
| const errorMsg = "Пожалуйста, проверьте введенные данные. Обнаружены ошибки в форме. Смотрите консоль для деталей."; | |
| console.error(errorMsg); | |
| alert(errorMsg); | |
| return; | |
| } | |
| // 5. Отправка данных на сервер с полным логированием | |
| console.log("=== ОТПРАВКА ДАННЫХ НА СЕРВЕР ==="); | |
| fetch('/calculation', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(requestData), | |
| }) | |
| .then(response => { | |
| console.log("Получен ответ от сервера. Статус:", response.status); | |
| if (!response.ok) { | |
| console.error("ОШИБКА СЕРВЕРА. Полный ответ:", response); | |
| throw new Error(`HTTP error! status: ${response.status}`); | |
| } | |
| return response.json(); | |
| }) | |
| .then(data => { | |
| call_data = data; | |
| console.log("=== УСПЕШНЫЙ ОТВЕТ ОТ СЕРВЕРА ===", call_data); | |
| // Выводим данные в форму | |
| data_out(call_data); | |
| // Показываем статус расчёта | |
| showCalculationStatus(call_data); | |
| // Вызываем функцию для расчета катионов и анионов | |
| calculateCationsAndAnions(data); | |
| // Обновляем поля NH4 и NO3 | |
| updateNitrogenFields(call_data); | |
| // Обновляем значения NPK | |
| calculateAndUpdate(call_data); | |
| // Получаем температуру из формы | |
| const temperature = parseFloat(document.getElementById('profile_temp').value) || 25; | |
| // Рассчитываем EC | |
| const ecValue = calculateEC(call_data, temperature); | |
| // Обновляем поле EC | |
| const ecInput = document.getElementById('profile_ec'); | |
| if (ecInput) { | |
| ecInput.value = ecValue.toFixed(2); | |
| console.log(`Установлено значение EC: ${ecValue.toFixed(2)}`); | |
| } | |
| }) | |
| .catch(error => { | |
| console.error("=== ОШИБКА ПРИ ОБРАБОТКЕ ===", error); | |
| alert("Ошибка при расчете: " + error.message); | |
| }) | |
| .finally(() => { | |
| console.log("=== ЗАВЕРШЕНИЕ ОБРАБОТКИ ==="); | |
| }); | |
| }); | |
| function data_out(response) { | |
| console.log("Обработка ответа сервера:", response); | |
| // Соответствие названий удобрений и ID полей | |
| const fertilizerMap = { | |
| "Кальциевая селитра": "calcium_nitrate", | |
| "Калий азотнокислый": "potassium_nitrate", | |
| "Аммоний азотнокислый": "ammonium_nitrate", | |
| "Сульфат магния": "magnesium_sulfate", | |
| "Монофосфат калия": "monopotassium_phosphate", | |
| "Калий сернокислый": "potassium_sulfate" | |
| }; | |
| // Заполняем граммы для каждого удобрения | |
| for (const [fertName, fieldId] of Object.entries(fertilizerMap)) { | |
| const value = response.fertilizers[fertName]; | |
| if (value !== undefined) { | |
| const input = document.getElementById(fieldId); | |
| if (input) { | |
| input.value = typeof value === 'number' | |
| ? value.toFixed(3) | |
| : value.граммы?.toFixed(3) || '0.000'; | |
| console.log(`Установлено ${fertName}: ${input.value}`); | |
| } else { | |
| console.error(`Не найден элемент: ${fieldId}`); | |
| } | |
| } | |
| } | |
| console.log("Данные успешно обновлены"); | |
| } | |
| function updateNitrogenFields(data) { | |
| console.log("=== ОБНОВЛЕНИЕ ЗНАЧЕНИЙ NH4 И NO3 ==="); | |
| // Извлекаем значения NH4 и NO3 из actual_profile | |
| const nh4Value = data.actual_profile["N (NH4+)"] || 0; | |
| const no3Value = data.actual_profile["N (NO3-)"] || 0; | |
| // Обновляем поля NH4 | |
| document.getElementById("calculated_nh4").value = nh4Value.toFixed(3); // Расчетное значение NH4 | |
| // Обновляем поля NO3 | |
| document.getElementById("calculated_no3").value = no3Value.toFixed(3); // Расчетное значение NO3 | |
| console.log(`Значения NH4 и NO3 обновлены: NH4=${nh4Value}, NO3=${no3Value}`); | |
| } | |
| function calculateAndUpdate(data) { | |
| console.log("=== РАСЧЕТ И ОБНОВЛЕНИЕ ДАННЫХ ==="); | |
| // Извлекаем значения из actual_profile | |
| const nValue = (data.actual_profile["N (NH4+)"] || 0) + (data.actual_profile["N (NO3-)"] || 0); | |
| const pValue = data.actual_profile["P"] || 0; | |
| const kValue = data.actual_profile["K"] || 0; | |
| const caValue = data.actual_profile["Ca"] || 0; | |
| const mgValue = data.actual_profile["Mg"] || 0; | |
| const sValue = data.actual_profile["S"] || 0; | |
| // Динамический расчет процента азота | |
| const totalNitrogen = data.nitrogen_ratios.TOTAL_NITROGEN || 0; // Берем TOTAL_NITROGEN из ответа | |
| const nPercent = totalNitrogen / 10; // Делим на 10, как предложено | |
| // Рассчитываем общую массу раствора | |
| const totalMass = nValue / (nPercent / 100); // Общая масса = N / (nPercent / 100) | |
| // Переводим элементы в оксидную форму | |
| const pOxide = pValue * 2.29; // P → P2O5 | |
| const kOxide = kValue * 1.2; // K → K2O | |
| const caOxide = caValue * 1.4; // Ca → CaO | |
| const mgOxide = mgValue * 1.67; // Mg → MgO | |
| const sOxide = sValue * 2.5; // S → SO3 | |
| // Рассчитываем проценты от общей массы | |
| const pPercent = (pOxide / totalMass) * 100; | |
| const kPercent = (kOxide / totalMass) * 100; | |
| const caPercent = (caOxide / totalMass) * 100; | |
| const mgPercent = (mgOxide / totalMass) * 100; | |
| const sPercent = (sOxide / totalMass) * 100; | |
| console.log(`Результаты расчета: | |
| N: ${nPercent.toFixed(2)}%, | |
| P2O5: ${pPercent.toFixed(2)}%, | |
| K2O: ${kPercent.toFixed(2)}%, | |
| CaO: ${caPercent.toFixed(2)}%, | |
| MgO: ${mgPercent.toFixed(2)}%, | |
| SO3: ${sPercent.toFixed(2)}%`); | |
| // Обновляем HTML-элементы | |
| document.getElementById("npk-n-value").textContent = nPercent.toFixed(2); | |
| document.getElementById("npk-p-value").textContent = pPercent.toFixed(2); | |
| document.getElementById("npk-k-value").textContent = kPercent.toFixed(2); | |
| document.getElementById("caMaS-ca-value").textContent = caPercent.toFixed(2); | |
| document.getElementById("caMaS-mg-value").textContent = mgPercent.toFixed(2); | |
| document.getElementById("caMaS-so-value").textContent = sPercent.toFixed(2); | |
| } | |
| function calculateCationsAndAnions(data) { | |
| console.log("=== ТОЧНЫЙ РАСЧЕТ КАТИОНОВ И АНИОНОВ ==="); | |
| // Молярные массы и валентности элементов | |
| const ION_DATA = { | |
| // Катионы | |
| 'Ca': { mass: 40.08, charge: 2 }, | |
| 'Mg': { mass: 24.305, charge: 2 }, | |
| 'K': { mass: 39.098, charge: 1 }, | |
| 'NH4': { mass: 18.038, charge: 1 }, | |
| // Анионы | |
| 'NO3': { mass: 62.004, charge: 1 }, | |
| 'SO4': { mass: 96.06, charge: 2 }, | |
| 'H2PO4': { mass: 96.99, charge: 1 } | |
| }; | |
| // Получаем данные профиля | |
| const profile = data.actual_profile; | |
| // Рассчитываем миллиэквиваленты (meq/L) для каждого иона | |
| const ions = { | |
| // Катионы | |
| 'Ca': (profile['Ca'] || 0) * 2 / 40.08, | |
| 'Mg': (profile['Mg'] || 0) * 2 / 24.305, | |
| 'K': (profile['K'] || 0) * 1 / 39.098, | |
| 'NH4': (profile['N (NH4+)'] || 0) * 1 / 18.038, | |
| // Анионы | |
| 'NO3': (profile['N (NO3-)'] || 0) * 1 / 62.004, | |
| 'SO4': (profile['S'] || 0) * 2 / 96.06, | |
| 'H2PO4': (profile['P'] || 0) * 1 / 96.99 | |
| }; | |
| // Суммируем катионы и анионы | |
| const totalCations = ions['Ca'] + ions['Mg'] + ions['K'] + ions['NH4']; | |
| const totalAnions = ions['NO3'] + ions['SO4'] + ions['H2PO4']; | |
| // Рассчитываем процентное соотношение | |
| const total = totalCations + totalAnions; | |
| const cationPercent = (totalCations / total * 100).toFixed(1); | |
| const anionPercent = (totalAnions / total * 100).toFixed(1); | |
| console.log(`Катионы: ${totalCations.toFixed(2)} mEq/L (${cationPercent}%)`); | |
| console.log(`Анионы: ${totalAnions.toFixed(2)} mEq/L (${anionPercent}%)`); | |
| console.log(`Дисбаланс: ${(totalCations - totalAnions).toFixed(2)} mEq/L`); | |
| // Обновляем UI | |
| document.getElementById("n1-value").textContent = | |
| `Катионы: ${totalCations.toFixed(2)} mEq/L | Анионы: ${totalAnions.toFixed(2)} mEq/L`; | |
| // Обновляем индикаторы | |
| document.getElementById("cation-indicator").style.width = `${cationPercent}%`; | |
| document.getElementById("anion-indicator").style.width = `${anionPercent}%`; | |
| } | |
| function calculateEC(data, temperature, alpha = 0.019) { | |
| console.log("=== РАСЧЕТ ЭЛЕКТРОПРОВОДНОСТИ (EC) ==="); | |
| const profile = data.actual_profile; | |
| let totalEC = 0; | |
| const ecConstants = { | |
| 'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015, | |
| 'Ca': 0.0016, 'S': 0.0014, | |
| 'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019 | |
| }; | |
| const significantElements = Object.keys(ecConstants); | |
| for (const element of significantElements) { | |
| const ppm = profile[element] || 0; | |
| const ecFactor = ecConstants[element]; | |
| const elementEC = ppm * ecFactor; | |
| totalEC += elementEC; | |
| console.log(`EC для ${element}: ${elementEC.toFixed(5)} (ppm=${ppm}, const=${ecFactor})`); | |
| } | |
| console.log(`Общая EC без компенсации: ${totalEC.toFixed(5)}`); | |
| const compensatedEC = totalEC * (1 + alpha * (temperature - 25)); | |
| console.log(`Компенсированная EC: ${compensatedEC.toFixed(5)} (T=${temperature}°C, α=${alpha})`); | |
| return compensatedEC; | |
| } | |
| </script> | |
| <script> | |
| // Инициализация | |
| const notyf = new Notyf({ | |
| duration: 5000, | |
| position: {x: 'right', y: 'top'}, | |
| types: [ | |
| {type: 'success', background: '#4CAF50'}, | |
| {type: 'error', background: '#F44336'} | |
| ] | |
| }); | |
| // Модифицированная функция | |
| function showCalculationStatus(response) { | |
| if (Object.keys(response.deficits || {}).length === 0) { | |
| notyf.success('Расчёт успешен! Все элементы сбалансированы'); | |
| } else { | |
| notyf.error('Дефициты: ' + | |
| Object.entries(response.deficits) | |
| .map(([el, val]) => `${el}: ${val.toFixed(2)} ppm`) | |
| .join(', ')); | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> |