DmitrMakeev commited on
Commit
71ded0a
·
verified ·
1 Parent(s): 76dc902

Update nutri_call.html

Browse files
Files changed (1) hide show
  1. nutri_call.html +104 -497
nutri_call.html CHANGED
@@ -29,7 +29,6 @@ body {
29
  background-color: #f0f0f0;
30
  font-family: Arial, sans-serif;
31
  }
32
-
33
  /* Стили для заголовка */
34
  .header-box {
35
  border: 2px solid #2e8b57;
@@ -42,7 +41,6 @@ body {
42
  width: 1000px;
43
  box-sizing: border-box;
44
  }
45
-
46
  /* Общие стили для всех рамок */
47
  fieldset, .calculation-box {
48
  border: 2px solid #2e8b57;
@@ -53,13 +51,11 @@ fieldset, .calculation-box {
53
  width: 1000px;
54
  box-sizing: border-box;
55
  }
56
-
57
  legend {
58
  font-weight: bold;
59
  color: #2e8b57;
60
  padding: 0 10px;
61
  }
62
-
63
  /* Стили для блока профиля */
64
  .main-container {
65
  display: grid;
@@ -68,23 +64,19 @@ legend {
68
  padding: 5px;
69
  margin-left: -50px; /* Сдвигаем блок левее */
70
  }
71
-
72
  .profile-container {
73
  display: contents;
74
  }
75
-
76
  .profile-element {
77
  display: flex;
78
  flex-direction: column;
79
  align-items: center;
80
  gap: 5px;
81
  }
82
-
83
  .profile-label {
84
  font-weight: bold;
85
  font-size: 0.9em;
86
  }
87
-
88
  .profile-element input {
89
  width: 80px;
90
  padding: 5px;
@@ -92,7 +84,6 @@ legend {
92
  border-radius: 4px;
93
  text-align: center;
94
  }
95
-
96
  .nitrogen-container {
97
  grid-column: 1 / -1;
98
  display: flex;
@@ -100,25 +91,21 @@ legend {
100
  padding-left: 40px;
101
  margin-top: 5px;
102
  }
103
-
104
  .nitrogen-group {
105
  display: flex;
106
  align-items: center;
107
  gap: 5px;
108
  }
109
-
110
  .nitrogen-group label {
111
  font-weight: bold;
112
  font-size: 0.9em;
113
  }
114
-
115
  .nitrogen-group input {
116
  width: 60px;
117
  padding: 5px;
118
  border: 1px solid #ccc;
119
  border-radius: 4px;
120
  }
121
-
122
  /* Стили для nitrogen */
123
  .nitrogen-container {
124
  display: flex;
@@ -127,14 +114,12 @@ legend {
127
  margin-left: 20px; /* Сдвигаем блок правее */
128
  margin-top: 10px; /* Отступ сверху */
129
  }
130
-
131
  .nitrogen-column {
132
  display: flex;
133
  flex-direction: column;
134
  gap: 10px;
135
  align-items: center; /* Центрируем содержимое колонки */
136
  }
137
-
138
  .column-header {
139
  font-weight: bold;
140
  font-size: 0.8em;
@@ -142,12 +127,10 @@ legend {
142
  text-align: center;
143
  width: 100%;
144
  }
145
-
146
  .nitrogen-group {
147
  display: flex;
148
  justify-content: center; /* Центрируем поля ввода */
149
  }
150
-
151
  .nitrogen-group input {
152
  width: 80px;
153
  padding: 5px;
@@ -155,7 +138,6 @@ legend {
155
  border-radius: 4px;
156
  }
157
  .square-button {
158
-
159
  width: 60px;
160
  height: 30px;
161
  font-size: 18px; /* Увеличенный размер текста */
@@ -170,8 +152,6 @@ legend {
170
  margin-bottom: 10px; /* Отступ снизу */
171
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* Тень для объема */
172
  }
173
-
174
-
175
  /* Стили для контейнера первого блока (NPK) */
176
  .npk-container {
177
  display: flex;
@@ -181,7 +161,6 @@ legend {
181
  margin-left: 15px; /* Общий отступ слева */
182
  margin-top: 10px; /* Отступ сверху */
183
  }
184
-
185
  /* Стили для заголовка NPK */
186
  .header-npk {
187
  font-weight: bold;
@@ -192,7 +171,6 @@ legend {
192
  margin-left: -5px; /* Сдвигаем строки влево */
193
  margin-bottom: 5px; /* Отступ между заголовком и основным блоком */
194
  }
195
-
196
  /* Стили для основного блока NPK */
197
  .block-npk {
198
  display: flex;
@@ -205,7 +183,6 @@ legend {
205
  border-radius: 8px;
206
  width: 65px; /* Ширина блока */
207
  }
208
-
209
  /* Стили для внутреннего контейнера строк (NPK) */
210
  .inner-block-npk {
211
  display: flex;
@@ -216,23 +193,19 @@ legend {
216
  margin-right: 0px; /* Добавляем внешний отступ справа */
217
  padding-bottom: 26px; /* Добавляем внешний отступ справа */
218
  }
219
-
220
  .row-npk {
221
  display: flex;
222
  align-items: center;
223
  gap: 5px;
224
  }
225
-
226
  .label-npk {
227
  font-weight: bold;
228
  min-width: 50px; /* Минимальная ширина меток */
229
  text-align: right;
230
  }
231
-
232
  .row-npk span {
233
  font-size: 0.9em;
234
  }
235
-
236
  /* Стили для контейнера второго блока (Ca-Mg-S) */
237
  .camgs-container {
238
  display: flex;
@@ -242,7 +215,6 @@ legend {
242
  margin-left: 8px; /* Общий отступ слева */
243
  margin-top: 10px; /* Отступ сверху */
244
  }
245
-
246
  /* Стили для заголовка Ca-Mg-S */
247
  .header-camgs {
248
  font-weight: bold;
@@ -251,7 +223,6 @@ legend {
251
  width: 75px; /* Ширина заголовка совпадает с шириной блока */
252
  margin-bottom: 5px; /* Отступ между заголовком и основным блоком */
253
  }
254
-
255
  /* Стили для основного блока Ca-Mg-S */
256
  .block-camgs {
257
  display: flex;
@@ -264,7 +235,6 @@ legend {
264
  border-radius: 8px;
265
  width: 85px; /* Ширина блока */
266
  }
267
-
268
  /* Стили для внутреннего контейнера строк (Ca-Mg-S) */
269
  .inner-block-camgs {
270
  display: flex;
@@ -275,26 +245,19 @@ legend {
275
  margin-right: 0px; /* Добавляем внешний отступ справа */
276
  padding-bottom: 26px; /* Добавляем внешний отступ*/
277
  }
278
-
279
  .row-camgs {
280
  display: flex;
281
  align-items: center;
282
  gap: 5px;
283
  }
284
-
285
  .label-camgs {
286
  font-weight: bold;
287
  min-width: 65px; /* Минимальная ширина меток */
288
  text-align: right;
289
  }
290
-
291
  .row-camgs span {
292
  font-size: 0.9em;
293
  }
294
-
295
-
296
-
297
-
298
  /* Стили для контейнера блока N1 */
299
  .n1-container {
300
  display: flex;
@@ -304,7 +267,6 @@ legend {
304
  margin-left: 8px; /* Общий отступ слева */
305
  margin-top: 10px; /* Отступ сверху */
306
  }
307
-
308
  /* Стили для заголовка N1 */
309
  .header-n1 {
310
  font-weight: bold;
@@ -313,17 +275,14 @@ legend {
313
  width: 100%; /* Ширина заголовка */
314
  margin-bottom: 5px; /* Отступ между заголовком и основным блоком */
315
  }
316
-
317
  .header-n1 span {
318
  margin-right: 5px; /* Отступ между "N1=" и значением */
319
  }
320
-
321
  #n1-value {
322
  font-weight: normal;
323
  color: #333;
324
  min-width: 100px; /* Место для значения */
325
  }
326
-
327
  /* Стили для основного блока N1 */
328
  .block-n1 {
329
  display: flex;
@@ -336,7 +295,6 @@ legend {
336
  border-radius: 8px;
337
  width: 200px; /* Ширина блока */
338
  }
339
-
340
  /* Стили для строки с меткой и индикатором */
341
  .n1-row {
342
  display: flex;
@@ -345,14 +303,12 @@ legend {
345
  gap: 5px;
346
  width: 100%;
347
  }
348
-
349
  .label-n1 {
350
  font-weight: bold;
351
  font-size: 0.9em;
352
  text-align: left;
353
  width: 100%;
354
  }
355
-
356
  /* Стили для контейнера индикатора */
357
  .indicator-container {
358
  width: 150px; /* Ширина индикатора */
@@ -362,7 +318,6 @@ legend {
362
  overflow: hidden;
363
  position: relative;
364
  }
365
-
366
  /* Стили для индикатора */
367
  .indicator {
368
  height: 100%;
@@ -371,20 +326,12 @@ legend {
371
  left: 0;
372
  transition: width 0.3s ease; /* Плавное изменение ширины */
373
  }
374
-
375
  .red-indicator {
376
  background-color: red;
377
  }
378
-
379
  .blue-indicator {
380
  background-color: blue;
381
  }
382
-
383
-
384
-
385
-
386
-
387
-
388
 
389
 
390
 
@@ -394,13 +341,11 @@ legend {
394
  flex-direction: column;
395
  margin-left: 20px; /* Сдвигаем блок */
396
  }
397
-
398
  .fert-row {
399
  display: flex;
400
  align-items: center;
401
  margin-bottom: 8px;
402
  }
403
-
404
  .fert-header {
405
  font-weight: bold;
406
  text-align: center;
@@ -408,21 +353,18 @@ legend {
408
  padding: 5px;
409
  font-size: 0.9em;
410
  }
411
-
412
  .fert-name {
413
  font-weight: bold;
414
  width: 120px;
415
  text-align: left;
416
  font-size: 0.9em;
417
  }
418
-
419
  .fert-cell {
420
  text-align: center;
421
  width: 80px;
422
  padding: 5px;
423
  font-size: 0.9em;
424
  }
425
-
426
  .fert-input {
427
  width: 70px;
428
  padding: 5px;
@@ -432,15 +374,12 @@ legend {
432
  margin: 0 5px;
433
  font-size: 0.9em;
434
  }
435
-
436
  /* Стили для блока расчета */
437
-
438
  .calculation-container {
439
  display: flex;
440
  gap: 40px; /* Расстояние между левым и правым блоками */
441
  align-items: flex-start;
442
  }
443
-
444
  /* Левый блок */
445
  .left-section {
446
  display: flex;
@@ -448,24 +387,20 @@ legend {
448
  gap: 20px; /* Расстояние между элементами */
449
  width: 100%; /* Занимает всю ширину */
450
  }
451
-
452
  .left-section label {
453
  font-weight: bold;
454
  font-size: 0.9em;
455
  }
456
-
457
  .left-section select {
458
  width: 100%; /* Выпадающий список занимает всю ширину */
459
  padding: 5px;
460
  border: 1px solid #ccc;
461
  border-radius: 4px;
462
  }
463
-
464
  .button-group {
465
  display: flex;
466
  gap: 10px; /* Расстояние между кнопками */
467
  }
468
-
469
  .button-group button {
470
  flex: 1; /* Кнопки занимают одинаковое пространство */
471
  padding: 8px;
@@ -475,44 +410,37 @@ legend {
475
  font-weight: bold;
476
  transition: background-color 0.3s;
477
  }
478
-
479
  #save-profile {
480
  background-color: #28a745; /* Зелёная кнопка */
481
  color: white;
482
  }
483
-
484
  #delete-profile {
485
  background-color: #dc3545; /* Красная кнопка */
486
  color: white;
487
  }
488
-
489
  /* Правый блок */
490
  .right-section {
491
  display: flex;
492
  flex-direction: column;
493
  gap: 10px;
494
  }
495
-
496
  .input-group {
497
  display: flex;
498
  align-items: center;
499
  gap: 10px;
500
  }
501
-
502
  .input-group label {
503
  width: 120px; /* Ширина меток */
504
  text-align: right;
505
  font-weight: bold;
506
  font-size: 0.9em;
507
  }
508
-
509
  .input-group input {
510
  width: 70px;
511
  padding: 5px;
512
  border: 1px solid #ccc;
513
  border-radius: 4px;
514
  }
515
-
516
  #calculate-btn {
517
  background-color: #2e8b57;
518
  color: white;
@@ -525,31 +453,25 @@ legend {
525
  margin-bottom: 5px;
526
  font-weight: bold;
527
  }
528
-
529
  #calculate-btn:hover {
530
  background-color: #3cb371;
531
  }
532
-
533
  /* micro контейнер */
534
  .micro-container {
535
  padding: 10px;
536
  }
537
-
538
  .micro-row {
539
  display: flex;
540
  gap: 20px;
541
  }
542
-
543
  .micro-group {
544
  display: flex;
545
  align-items: center;
546
  gap: 5px;
547
  }
548
-
549
  .micro-group label {
550
  min-width: 120px;
551
  }
552
-
553
  .micro-group input {
554
  width: 80px;
555
  text-align: right;
@@ -737,7 +659,7 @@ vkBridge.send('VKWebAppInit');
737
  <span class="fert-header">Ca</span>
738
  <span class="fert-header">Mg</span>
739
  <span class="fert-header">S</span>
740
- <span class="fert-header">Ca</span>
741
  <span class="fert-header">Грамм</span>
742
  </div>
743
 
@@ -819,19 +741,6 @@ vkBridge.send('VKWebAppInit');
819
  <span class="fert-cell">-</span>
820
  <input class="fert-input" type="number" step="0.001" id="potassium_sulfate" readonly style="background-color: #d4f5d4;" />
821
  </div>
822
-
823
- <div class="fert-row">
824
- <span class="fert-name">(ЭДТА Ca)</span>
825
- <span class="fert-cell">-</span>
826
- <span class="fert-cell">-</span>
827
- <span class="fert-cell">-</span>
828
- <span class="fert-cell">-</span>
829
- <span class="fert-cell">-</span>
830
- <span class="fert-cell">-</span>
831
- <span class="fert-cell">-</span>
832
- <span class="fert-cell">-</span>
833
- <input class="fert-input" type="number" step="0.001" id="potassium_sulfate" readonly style="background-color: #d4f5d4;" />
834
- </div>
835
  </div>
836
  </fieldset>
837
 
@@ -842,7 +751,6 @@ vkBridge.send('VKWebAppInit');
842
 
843
 
844
 
845
-
846
  <fieldset>
847
  <legend>Микроэлементы в мг/л (ppm)</legend>
848
  <div class="fertilisers-container">
@@ -955,7 +863,7 @@ vkBridge.send('VKWebAppInit');
955
  </div>
956
  <div class="input-group">
957
  <label for="rounding-precision">Точность:</label>
958
- <input type="number" id="rounding-precision" value="3" min="0" max="6" step="1">
959
  </div>
960
  <button id="calculate-btn">Рассчитать</button>
961
  </div>
@@ -991,27 +899,116 @@ vkBridge.send('VKWebAppInit');
991
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/toastify-js"></script>
992
  <script>
993
  let call_data;
994
-
995
  const ecConstants = {
996
  'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
997
  'Ca': 0.0016, 'S': 0.0014,
998
  'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
999
  };
1000
-
1001
-
1002
-
1003
-
1004
-
1005
-
1006
-
1007
-
1008
-
1009
 
1010
-
1011
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1012
  function data_out(data) {
1013
  console.log("=== ЗАПИСЬ ДАННЫХ В ФОРМУ ===");
1014
-
1015
  // Сопоставление названий удобрений с их идентификаторами
1016
  const fertilizerIdMap = {
1017
  "Кальциевая селитра": "calcium_nitrate",
@@ -1021,7 +1018,6 @@ function data_out(data) {
1021
  "Монофосфат калия": "monopotassium_phosphate",
1022
  "Калий сернокислый": "potassium_sulfate"
1023
  };
1024
-
1025
  // Записываем массы удобрений
1026
  for (const [fertilizer, grams] of Object.entries(data.fertilizers)) {
1027
  const inputId = fertilizerIdMap[fertilizer];
@@ -1033,35 +1029,20 @@ function data_out(data) {
1033
  console.warn(`Поле для удобрения ${fertilizer} не найдено`);
1034
  }
1035
  }
1036
-
1037
  // Логика для CaCl больше не нужна
1038
  console.log("Логика для Кальция хлористого удалена.");
1039
  }
1040
-
1041
-
1042
-
1043
-
1044
-
1045
  function updateNitrogenFields(data) {
1046
  console.log("=== ОБНОВЛЕНИЕ ЗНАЧЕНИЙ NH4 И NO3 ===");
1047
-
1048
  // Извлекаем значения NH4 и NO3 из actual_profile
1049
  const nh4Value = data.actual_profile["N (NH4+)"] || 0;
1050
  const no3Value = data.actual_profile["N (NO3-)"] || 0;
1051
-
1052
  // Обновляем поля NH4
1053
  document.getElementById("calculated_nh4").value = nh4Value.toFixed(3); // Расчетное значение NH4
1054
-
1055
  // Обновляем поля NO3
1056
  document.getElementById("calculated_no3").value = no3Value.toFixed(3); // Расчетное значение NO3
1057
-
1058
  console.log(`Значения NH4 и NO3 обновлены: NH4=${nh4Value}, NO3=${no3Value}`);
1059
  }
1060
-
1061
-
1062
-
1063
-
1064
-
1065
 
1066
  function calculateAndUpdate(data) {
1067
  console.log("=== РАСЧЕТ И ОБНОВЛЕНИЕ ДАННЫХ ===");
@@ -1104,14 +1085,8 @@ function calculateAndUpdate(data) {
1104
  document.getElementById("caMaS-mg-value").textContent = mgPercent.toFixed(2);
1105
  document.getElementById("caMaS-so-value").textContent = sPercent.toFixed(2);
1106
  }
1107
-
1108
-
1109
-
1110
-
1111
-
1112
  function calculateCationsAndAnions() {
1113
  console.log("=== ДИНАМИЧЕСКИЙ РАСЧЕТ КАТИОНОВ И АНИОНОВ ===");
1114
-
1115
  // 1. Получаем текущие значения из формы
1116
  const getValue = (id) => parseFloat(document.getElementById(id).value) || 0;
1117
  const profile = {
@@ -1124,7 +1099,6 @@ function calculateCationsAndAnions() {
1124
  'S': getValue('profile_s')
1125
  // Убрали 'Cl', так как больше не учитываем кальций хлористый
1126
  };
1127
-
1128
  // 2. Константы из вашей формы (упрощенные)
1129
  const FERTILIZER_CONSTANTS = {
1130
  'Кальциевая селитра': { 'N (NO3-)': 0.11863, 'Ca': 0.16972 },
@@ -1135,7 +1109,6 @@ function calculateCationsAndAnions() {
1135
  'Калий сернокислый': { 'K': 0.44874, 'S': 0.18401 }
1136
  // Убрали 'Кальций хлорид'
1137
  };
1138
-
1139
  // 3. Молярные массы и валентности
1140
  const ION_DATA = {
1141
  'Ca': { mass: 40.08, charge: 2 },
@@ -1147,10 +1120,8 @@ function calculateCationsAndAnions() {
1147
  'H2PO4': { mass: 96.99, charge: 1 }
1148
  // Убрали 'Cl', так как больше не учитываем хлор
1149
  };
1150
-
1151
  // 4. Пересчет серы (S → SO4²⁻)
1152
  const so4 = profile['S'] * (96.06 / 32.06);
1153
-
1154
  // 5. Расчет mEq/L для каждого иона
1155
  const ions = {
1156
  'Ca': profile['Ca'] * ION_DATA['Ca'].charge / ION_DATA['Ca'].mass,
@@ -1162,50 +1133,37 @@ function calculateCationsAndAnions() {
1162
  'H2PO4': profile['P'] * ION_DATA['H2PO4'].charge / ION_DATA['H2PO4'].mass
1163
  // Убрали 'Cl', так как больше не учитываем хлор
1164
  };
1165
-
1166
  // 6. Суммирование
1167
  const totalCations = ions['Ca'] + ions['Mg'] + ions['K'] + ions['NH4'];
1168
  const totalAnions = ions['NO3'] + ions['SO4'] + ions['H2PO4'];
1169
  // Убрали 'Cl' из суммы анионов
1170
-
1171
  // 7. Расчет процентов
1172
  const total = totalCations + totalAnions;
1173
  const cationPercent = total > 0 ? (totalCations / total * 100).toFixed(1) : 0;
1174
  const anionPercent = total > 0 ? (totalAnions / total * 100).toFixed(1) : 0;
1175
-
1176
  // 8. Вывод результатов
1177
  console.log(`Катионы: ${totalCations.toFixed(2)} mEq/L (${cationPercent}%)`);
1178
  console.log(`Анионы: ${totalAnions.toFixed(2)} mEq/L (${anionPercent}%)`);
1179
  console.log(`Дисбаланс: ${(totalCations - totalAnions).toFixed(2)} mEq/L`);
1180
-
1181
  // 9. Обновление UI
1182
  document.getElementById("n1-value").textContent =
1183
  `Катионы: ${totalCations.toFixed(2)} mEq/L | Анионы: ${totalAnions.toFixed(2)} mEq/L`;
1184
-
1185
  // Обновление ширины индикаторов
1186
  document.getElementById("cation-indicator").style.width = `${cationPercent}%`;
1187
  document.getElementById("anion-indicator").style.width = `${anionPercent}%`;
1188
  }
1189
-
1190
-
1191
-
1192
 
1193
 
1194
-
1195
  function calculateEC(data, temperature, alpha = 0.019) {
1196
  console.log("=== РАСЧЕТ ЭЛЕКТРОПРОВОДНОСТИ (EC) ===");
1197
-
1198
  const profile = data.actual_profile;
1199
  let totalEC = 0;
1200
-
1201
  const ecConstants = {
1202
  'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
1203
  'Ca': 0.0016, 'S': 0.0014,
1204
  'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
1205
  };
1206
-
1207
  const significantElements = Object.keys(ecConstants);
1208
-
1209
  for (const element of significantElements) {
1210
  const ppm = profile[element] || 0;
1211
  const ecFactor = ecConstants[element];
@@ -1213,22 +1171,11 @@ function calculateEC(data, temperature, alpha = 0.019) {
1213
  totalEC += elementEC;
1214
  console.log(`EC для ${element}: ${elementEC.toFixed(5)} (ppm=${ppm}, const=${ecFactor})`);
1215
  }
1216
-
1217
  console.log(`Общая EC без компенсации: ${totalEC.toFixed(5)}`);
1218
-
1219
  const compensatedEC = totalEC * (1 + alpha * (temperature - 25));
1220
  console.log(`Компенсированная EC: ${compensatedEC.toFixed(5)} (T=${temperature}°C, α=${alpha})`);
1221
-
1222
  return compensatedEC;
1223
  }
1224
-
1225
-
1226
-
1227
-
1228
-
1229
-
1230
-
1231
-
1232
  function calculateMicroElements() {
1233
  // 1. Получаем объем раствора (в литрах)
1234
  const litersInput = document.getElementById('liters-input');
@@ -1241,7 +1188,6 @@ function calculateMicroElements() {
1241
  alert("Введите корректный объем раствора!");
1242
  return;
1243
  }
1244
-
1245
  // 2. Получаем массы удобрений (в граммах)
1246
  const feChelateInput = document.getElementById('fert_fe_chelate_mass');
1247
  const complexPowderInput = document.getElementById('fert_fe_complex_mass');
@@ -1251,12 +1197,10 @@ function calculateMicroElements() {
1251
  }
1252
  const feChelateMass = parseFloat(feChelateInput.value) || 0;
1253
  const complexPowderMass = parseFloat(complexPowderInput.value) || 0;
1254
-
1255
  // 3. Содержание микроэлементов в удобрениях (%)
1256
  const feChelateContent = {
1257
  Fe: 0.11 // Хелат железа (11%)
1258
  };
1259
-
1260
  const complexPowderContent = {
1261
  Fe: 0.0384, // Fe (ДТПА + ЭДТА) = 3.84%
1262
  Zn: 0.0053, // Zn (ЭДТА) = 0.53%
@@ -1265,7 +1209,6 @@ function calculateMicroElements() {
1265
  B: 0.0052, // B = 0.52%
1266
  Mo: 0.0013 // Mo = 0.13%
1267
  };
1268
-
1269
  // 4. Рассчитываем чистые количества микроэлементов (в граммах)
1270
  const pureElements = {
1271
  Fe: (feChelateMass * feChelateContent.Fe) + (complexPowderMass * complexPowderContent.Fe),
@@ -1275,13 +1218,11 @@ function calculateMicroElements() {
1275
  B: complexPowderMass * complexPowderContent.B,
1276
  Mo: complexPowderMass * complexPowderContent.Mo
1277
  };
1278
-
1279
  // 5. Рассчитываем концентрации в PPM (мг/л)
1280
  const ppm = {};
1281
  for (const element in pureElements) {
1282
  ppm[element] = (pureElements[element] * 1000) / solutionVolume; // Переводим граммы в мг/л
1283
  }
1284
-
1285
  // 6. Выводим результаты в соответствующие поля матрицы
1286
  const outputFields = ['ppm_fe', 'ppm_zn', 'ppm_cu', 'ppm_mn', 'ppm_b', 'ppm_mo'];
1287
  outputFields.forEach((field, index) => {
@@ -1292,38 +1233,26 @@ function calculateMicroElements() {
1292
  console.error(`Элемент с id='${field}' не найден!`);
1293
  }
1294
  });
1295
-
1296
  console.log("=== РАСЧЕТ PPM ===", ppm);
1297
  }
1298
-
1299
-
1300
-
1301
-
1302
  // Функция для расчета соотношений и формирования строки
1303
  function calculateN1Ratio(data) {
1304
  // Получаем значения элементов из ответа сервера
1305
  const { actual_profile, total_ppm } = data;
1306
  const { P, K, Ca, Mg, S } = actual_profile;
1307
-
1308
  // Общий азот (N_total) = N (NH4+) + N (NO3-)
1309
  const N_total = actual_profile["N (NH4+)"] + actual_profile["N (NO3-)"];
1310
-
1311
  // Вычисляем соотношения относительно общего азота (принимаем его за единицу)
1312
  const P_ratio = (P / N_total).toFixed(2);
1313
  const K_ratio = (K / N_total).toFixed(2);
1314
  const CaO_ratio = (Ca / N_total).toFixed(2); // Предполагается, что Ca - это оксид кальция
1315
  const MgO_ratio = (Mg / N_total).toFixed(2); // Предполагается, что Mg - это оксид магния
1316
  const SO_ratio = (S / N_total).toFixed(2); // Предполагается, что S - это оксид серы
1317
-
1318
  // Формируем строку в требуемом формате
1319
  const n1String = `${P_ratio}:${K_ratio}:${CaO_ratio}:${MgO_ratio}:${SO_ratio} PPM=${total_ppm.toFixed(2)}`;
1320
-
1321
  // Вставляем строку в HTML
1322
  document.getElementById("n1-value").textContent = n1String;
1323
  }
1324
-
1325
-
1326
-
1327
 
1328
  </script>
1329
 
@@ -1341,7 +1270,6 @@ const notyf = new Notyf({
1341
  {type: 'error', background: '#F44336'}
1342
  ]
1343
  });
1344
-
1345
  // Модифицированная функция
1346
  function showCalculationStatus(response) {
1347
  if (Object.keys(response.deficits || {}).length === 0) {
@@ -1363,7 +1291,6 @@ function showCalculationStatus(response) {
1363
  "profile_n", "profile_p", "profile_k",
1364
  "profile_ca", "profile_mg", "profile_s"
1365
  ];
1366
-
1367
  fields.forEach(id => {
1368
  const input = document.getElementById(id);
1369
  let value = parseFloat(input.value); // Берём текущее значение
@@ -1373,14 +1300,12 @@ function showCalculationStatus(response) {
1373
  }
1374
  });
1375
  }
1376
-
1377
  // Функция для уменьшения значений на 10%
1378
  function decreaseValues() {
1379
  const fields = [
1380
  "profile_n", "profile_p", "profile_k",
1381
  "profile_ca", "profile_mg", "profile_s"
1382
  ];
1383
-
1384
  fields.forEach(id => {
1385
  const input = document.getElementById(id);
1386
  let value = parseFloat(input.value); // Берём текущее значение
@@ -1391,7 +1316,6 @@ function showCalculationStatus(response) {
1391
  }
1392
  });
1393
  }
1394
-
1395
  // Привязываем функции к кнопкам
1396
  document.getElementById("plus-button").addEventListener("click", increaseValues);
1397
  document.getElementById("minus-button").addEventListener("click", decreaseValues);
@@ -1466,21 +1390,17 @@ const predefinedProfiles = {
1466
  }
1467
  ]
1468
  };
1469
-
1470
  // Загрузка всех профилей (предустановленные + пользовательские)
1471
  function loadAllProfiles() {
1472
  const userProfiles = JSON.parse(localStorage.getItem("userProfiles")) || [];
1473
  return [...predefinedProfiles.profiles, ...userProfiles];
1474
  }
1475
-
1476
  // Создание выпадающего списка
1477
  function populateProfileSelector() {
1478
  const profiles = loadAllProfiles();
1479
  const selector = document.getElementById("profile-selector");
1480
-
1481
  // Очищаем предыдущие опции
1482
  selector.innerHTML = "";
1483
-
1484
  // Добавляем предустановленные профили
1485
  const predefinedGroup = document.createElement("optgroup");
1486
  predefinedGroup.label = "Предустановленные профили";
@@ -1491,7 +1411,6 @@ function populateProfileSelector() {
1491
  predefinedGroup.appendChild(option);
1492
  });
1493
  selector.appendChild(predefinedGroup);
1494
-
1495
  // Добавляем пользовательские профили
1496
  const userProfiles = JSON.parse(localStorage.getItem("userProfiles")) || [];
1497
  if (userProfiles.length > 0) {
@@ -1505,14 +1424,12 @@ function populateProfileSelector() {
1505
  });
1506
  selector.appendChild(userGroup);
1507
  }
1508
-
1509
  // Выбираем первый профиль по умолчанию
1510
  if (profiles.length > 0) {
1511
  selector.value = profiles[0].name;
1512
  updateProfileFields(profiles[0]);
1513
  }
1514
  }
1515
-
1516
  // Обновление полей при выб��ре профиля
1517
  function updateProfileFields(selectedProfile) {
1518
  document.getElementById("profile_p").value = selectedProfile.values.profile_p || 0;
@@ -1527,18 +1444,15 @@ function updateProfileFields(selectedProfile) {
1527
  document.getElementById("fert_fe_chelate_mass").value = selectedProfile.values.fert_fe_chelate_mass || 0;
1528
  document.getElementById("fert_fe_complex_mass").value = selectedProfile.values.fert_fe_complex_mass || 0;
1529
  }
1530
-
1531
  // Слушатель события изменения выбранного профиля
1532
  document.getElementById("profile-selector").addEventListener("change", function () {
1533
  const selectedProfileName = this.value;
1534
  const allProfiles = loadAllProfiles();
1535
  const selectedProfile = allProfiles.find(profile => profile.name === selectedProfileName);
1536
-
1537
  if (selectedProfile) {
1538
  updateProfileFields(selectedProfile);
1539
  }
1540
  });
1541
-
1542
  // Сохранение нового профиля
1543
  document.getElementById("save-profile").addEventListener("click", async function () {
1544
  // Используем SweetAlert2 для ввода имени профиля
@@ -1557,9 +1471,7 @@ document.getElementById("save-profile").addEventListener("click", async function
1557
  }
1558
  }
1559
  });
1560
-
1561
  if (!profileName) return;
1562
-
1563
  // Создаём новый профиль
1564
  const newProfile = {
1565
  name: profileName,
@@ -1577,16 +1489,13 @@ document.getElementById("save-profile").addEventListener("click", async function
1577
  fert_fe_complex_mass: parseFloat(document.getElementById("fert_fe_complex_mass").value) || 0
1578
  }
1579
  };
1580
-
1581
  // Добавляем профиль в localStorage
1582
  let userProfiles = JSON.parse(localStorage.getItem("userProfiles")) || [];
1583
  userProfiles.push(newProfile);
1584
  localStorage.setItem("userProfiles", JSON.stringify(userProfiles));
1585
-
1586
  // Обновляем выпадающий список
1587
  populateProfileSelector();
1588
  });
1589
-
1590
  // Удаление выбранного профиля
1591
  document.getElementById("delete-profile").addEventListener("click", async function () {
1592
  const selectedProfileName = document.getElementById("profile-selector").value;
@@ -1598,11 +1507,9 @@ document.getElementById("delete-profile").addEventListener("click", async functi
1598
  });
1599
  return;
1600
  }
1601
-
1602
  // Находим индекс профиля в localStorage
1603
  let userProfiles = JSON.parse(localStorage.getItem("userProfiles")) || [];
1604
  const profileIndex = userProfiles.findIndex(profile => profile.name === selectedProfileName);
1605
-
1606
  if (profileIndex === -1) {
1607
  Swal.fire({
1608
  icon: "error",
@@ -1611,7 +1518,6 @@ document.getElementById("delete-profile").addEventListener("click", async functi
1611
  });
1612
  return;
1613
  }
1614
-
1615
  // Показываем SweetAlert2 для подтверждения удаления
1616
  const result = await Swal.fire({
1617
  title: "Вы уверены?",
@@ -1624,22 +1530,18 @@ document.getElementById("delete-profile").addEventListener("click", async functi
1624
  cancelButtonColor: "#28a745", // Зелёная кнопка
1625
  reverseButtons: true
1626
  });
1627
-
1628
  if (result.isConfirmed) {
1629
  // Удаляем профиль
1630
  userProfiles.splice(profileIndex, 1);
1631
  localStorage.setItem("userProfiles", JSON.stringify(userProfiles));
1632
-
1633
  // Обновляем выпадающий список
1634
  populateProfileSelector();
1635
-
1636
  // Выбираем первый профиль по умолчанию
1637
  const allProfiles = loadAllProfiles();
1638
  if (allProfiles.length > 0) {
1639
  document.getElementById("profile-selector").value = allProfiles[0].name;
1640
  updateProfileFields(allProfiles[0]);
1641
  }
1642
-
1643
  // Показываем сообщение об успешном удалении
1644
  Swal.fire({
1645
  title: "Удалено!",
@@ -1655,309 +1557,14 @@ document.getElementById("delete-profile").addEventListener("click", async functi
1655
  });
1656
  }
1657
  });
1658
-
1659
  // Инициализация выпадающего списка при загрузке страницы
1660
  populateProfileSelector();
1661
  </script>
1662
 
1663
 
1664
- <script>
1665
- class NutrientCalculator {
1666
- constructor(inputData) {
1667
- this.fertilizers = inputData.fertilizerConstants;
1668
- this.profile = inputData.profileSettings;
1669
- this.volume = this.profile.liters;
1670
- this.roundingPrecision = this.profile.rounding_precision;
1671
-
1672
- const totalParts = this.profile.NO3_RAT + 1;
1673
- this.target = {
1674
- 'P': this.profile.P,
1675
- 'K': this.profile.K,
1676
- 'Mg': this.profile.Mg,
1677
- 'Ca': this.profile.Ca,
1678
- 'S': this.profile.S,
1679
- 'N (NO3-)': this.profile.TOTAL_NITROG * (this.profile.NO3_RAT / totalParts),
1680
- 'N (NH4+)': this.profile.TOTAL_NITROG * (1 / totalParts)
1681
- };
1682
-
1683
- this.actual = Object.fromEntries(Object.keys(this.target).map(k => [k, 0.0]));
1684
- this.results = Object.fromEntries(Object.keys(this.fertilizers).map(fert => [fert, {}]));
1685
- this.elementContributions = {};
1686
- }
1687
-
1688
- calculate() {
1689
- // Добавляем аммонийный азот
1690
- this._applyFertilizer("Аммоний азотнокислый", "N (NH4+)", this.target["N (NH4+)"]);
1691
-
1692
- // Добавляем фосфор
1693
- this._applyFertilizer("Монофосфат калия", "P", this.target.P);
1694
-
1695
- // Добавляем магний
1696
- this._applyFertilizer("Сульфат магния", "Mg", this.target.Mg);
1697
-
1698
- // Балансируем калий и серу
1699
- this._balanceKS();
1700
-
1701
- // Распределяем кальций
1702
- this._distributeCalcium();
1703
-
1704
- // Балансируем нитратный азот
1705
- const no3Needed = this.target["N (NO3-)"] - this.actual["N (NO3-)"];
1706
- if (no3Needed > 0) {
1707
- this._applyFertilizer("Калий азотнокислый", "N (NO3-)", no3Needed);
1708
- }
1709
-
1710
- return this._generateOutput();
1711
- }
1712
-
1713
- _applyFertilizer(name, element, targetPPM) {
1714
- if (!this.fertilizers[name]) {
1715
- throw new Error(`Удобрение '${name}' не найдено!`);
1716
- }
1717
- const content = this.fertilizers[name][element] || 0;
1718
- if (content === 0) {
1719
- console.warn(`ПРЕДУПРЕЖДЕНИЕ: Удобрение '${name}' не содержит элемент '${element}'`);
1720
- return;
1721
- }
1722
- const grams = (targetPPM * this.volume) / (content * 1000);
1723
- this.results[name].граммы = parseFloat(grams.toFixed(this.roundingPrecision));
1724
-
1725
- this.elementContributions[name] = {};
1726
- for (const [el, val] of Object.entries(this.fertilizers[name])) {
1727
- const addedPPM = (grams * val * 1000) / this.volume;
1728
- this.elementContributions[name][el] = parseFloat(addedPPM.toFixed(this.roundingPrecision));
1729
- if (el in this.actual) {
1730
- this.actual[el] = parseFloat((this.actual[el] + addedPPM).toFixed(this.roundingPrecision));
1731
- }
1732
- }
1733
- }
1734
-
1735
- _balanceKS() {
1736
- let kNeeded = this.target.K - this.actual.K;
1737
- let sNeeded = this.target.S - this.actual.S;
1738
-
1739
- if (kNeeded > 0 && sNeeded > 0) {
1740
- const kFraction = this.fertilizers["Калий сернокислый"]["K"] || 0;
1741
- const sFraction = this.fertilizers["Калий сернокислый"]["S"] || 0;
1742
- if (kFraction === 0 || sFraction === 0) {
1743
- console.warn("ПРЕДУПРЕЖДЕНИЕ: Удобрение 'Калий сернокислый' содержит нулевые значения!");
1744
- return;
1745
- }
1746
- const kFromK2SO4 = Math.min(kNeeded, sNeeded * kFraction / sFraction);
1747
- this._applyFertilizer("Калий сернокислый", "K", kFromK2SO4);
1748
- }
1749
-
1750
- const remainingK = this.target.K - this.actual.K;
1751
- if (remainingK > 0) {
1752
- this._applyFertilizer("Калий азотнокислый", "K", remainingK);
1753
- }
1754
- }
1755
-
1756
- _distributeCalcium() {
1757
- const caTarget = this.target.Ca; // Целевой уровень кальция
1758
- const no3Ratio = this.profile.NO3_RAT;
1759
- const activationCacl = this.profile.activation_cacl;
1760
- const enhancementCacl = this.profile.enhancement_cacl;
1761
-
1762
- if (no3Ratio >= activationCacl) {
1763
- console.log(`Соотношение NO3/NH4 >= ${activationCacl}. Хелат кальция не добавляется.`);
1764
- // Всё кальций берётся из кальциевой селитры
1765
- this._applyFertilizer("Кальциевая селитра", "Ca", caTarget);
1766
- } else {
1767
- // Часть кальция берётся из хелата кальция
1768
- const caclTarget = caTarget * enhancementCacl;
1769
- if (caclTarget > 0) {
1770
- this._applyFertilizer("Хелат кальция", "Ca", caclTarget);
1771
- }
1772
- // Оставшийся кальций берётся из кальциевой селитры
1773
- const remainingCa = caTarget - caclTarget;
1774
- if (remainingCa > 0) {
1775
- this._applyFertilizer("Кальциевая селитра", "Ca", remainingCa);
1776
- }
1777
- }
1778
- }
1779
-
1780
-
1781
-
1782
-
1783
-
1784
- _generateOutput() {
1785
- const deficits = {};
1786
- for (const el in this.target) {
1787
- const diff = this.target[el] - this.actual[el];
1788
- if (Math.abs(diff) > 0.1) {
1789
- deficits[el] = parseFloat(diff.toFixed(this.roundingPrecision));
1790
- }
1791
- }
1792
-
1793
- // Гарантируем, что в fertilizers всегда 7 элементов
1794
- const fertilizers = {
1795
- "Аммоний азотнокислый": this.results["Аммоний азотнокислый"]?.граммы || 0,
1796
- "Монофосфат калия": this.results["Монофосфат калия"]?.граммы || 0,
1797
- "Сульфат магния": this.results["Сульфат маг��ия"]?.граммы || 0,
1798
- "Калий сернокислый": this.results["Калий сернокислый"]?.граммы || 0,
1799
- "Хелат кальция": this.results["Хелат кальция"]?.граммы || 0, // Всегда присутствует
1800
- "Кальциевая селитра": this.results["Кальциевая селитра"]?.граммы || 0,
1801
- "Калий азотнокислый": this.results["Калий азотнокислый"]?.граммы || 0
1802
- };
1803
-
1804
- return {
1805
- actual_profile: this.actual,
1806
- deficits: deficits,
1807
- element_contributions: this.elementContributions,
1808
- fertilizers: fertilizers,
1809
- nitrogen_ratios: {
1810
- NH4_RATIO: this.profile.NO3_RAT,
1811
- NO3_RATIO: 1,
1812
- TOTAL_NITROGEN: this.profile.TOTAL_NITROG
1813
- },
1814
- total_ppm: parseFloat(Object.values(this.actual).reduce((sum, val) => sum + val, 0).toFixed(this.roundingPrecision))
1815
- };
1816
- }
1817
- }
1818
-
1819
-
1820
-
1821
- const INPUT_DATA = {
1822
- fertilizerConstants: {
1823
- "Кальциевая селитра": { "N (NO3-)": 0.11863, "Ca": 0.16972 },
1824
- "Калий азотнокислый": { "N (NO3-)": 0.13854, "K": 0.36672 },
1825
- "Аммоний азотнокислый": { "N (NO3-)": 0.17499, "N (NH4+)": 0.17499 },
1826
- "Сульфат магния": { "Mg": 0.10220, "S": 0.13483 },
1827
- "Монофосфат калия": { "P": 0.22761, "K": 0.28731 },
1828
- "Калий сернокислый": { "K": 0.44874, "S": 0.18401 }
1829
- },
1830
- profileSettings: {
1831
- P: 31,
1832
- K: 210,
1833
- Mg: 24,
1834
- Ca: 82,
1835
- S: 57.5,
1836
- NO3_RAT: 6, // Соотношение NO3/NH4
1837
- TOTAL_NITROG: 125, // Общее количество азота
1838
- liters: 100, // Объём раствора
1839
- rounding_precision: 3, // Точность округления
1840
- activation_cacl: 5, // Порог активации хелата кальция
1841
- enhancement_cacl: 0.1 // Доля кальция из хелата
1842
- }
1843
- };
1844
-
1845
- // Создаем экземпляр калькулятора
1846
- const calculator = new NutrientCalculator(INPUT_DATA);
1847
-
1848
- // Запускаем расчет
1849
- const results = calculator.calculate();
1850
- console.log(JSON.stringify(results, null, 2));
1851
-
1852
-
1853
-
1854
-
1855
-
1856
- </script>
1857
-
1858
-
1859
-
1860
-
1861
-
1862
-
1863
- <script>
1864
- document.getElementById('calculate-btn').addEventListener('click', function () {
1865
- console.log("=== НАЧАЛО ОБРАБОТКИ ===");
1866
-
1867
- // 1. Получаем значение точности округления
1868
- const roundingInput = document.getElementById('rounding-precision');
1869
- const initialRounding = parseInt(roundingInput.value);
1870
- const roundingPrecision = Math.min(Math.max(initialRounding || 3, 0), 6);
1871
-
1872
- // 2. Функция для безопасного получения числового значения
1873
- const getValue = (id) => {
1874
- const element = document.getElementById(id);
1875
- if (!element) {
1876
- console.error(`Элемент с ID ${id} не найден!`);
1877
- return 0;
1878
- }
1879
- const value = parseFloat(element.value);
1880
- return isNaN(value) ? 0 : value;
1881
- };
1882
-
1883
- // 3. Формируем данные для расчёта
1884
- const fertilizerConstants = {
1885
- "Кальциевая селитра": {
1886
- "N (NO3-)": getValue('fert_ca_no3') / 100,
1887
- "Ca": getValue('fert_ca_ca') / 100
1888
- },
1889
- "Калий азотнокислый": {
1890
- "N (NO3-)": getValue('fert_kno3_no3') / 100,
1891
- "K": getValue('fert_kno3_k') / 100
1892
- },
1893
- "Аммоний азотнокислый": {
1894
- "N (NO3-)": getValue('fert_nh4no3_no3') / 100,
1895
- "N (NH4+)": getValue('fert_nh4no3_nh4') / 100
1896
- },
1897
- "Сульфат магния": {
1898
- "Mg": getValue('fert_mgso4_mg') / 100,
1899
- "S": getValue('fert_mgso4_s') / 100
1900
- },
1901
- "Монофосфат калия": {
1902
- "P": getValue('fert_kh2po4_p') / 100,
1903
- "K": getValue('fert_kh2po4_k') / 100
1904
- },
1905
- "Калий сернокислый": {
1906
- "K": getValue('fert_k2so4_k') / 100,
1907
- "S": getValue('fert_k2so4_s') / 100
1908
- }
1909
- };
1910
-
1911
- const profileSettings = {
1912
- 'P': getValue('profile_p'),
1913
- 'K': getValue('profile_k'),
1914
- 'Mg': getValue('profile_mg'),
1915
- 'Ca': getValue('profile_ca'),
1916
- 'S': getValue('profile_s'),
1917
- 'NO3_RAT': getValue('profile_no3'),
1918
- 'TOTAL_NITROG': getValue('profile_n'),
1919
- 'liters': parseInt(document.getElementById('liters-input').value) || 1,
1920
- 'rounding_precision': roundingPrecision
1921
- };
1922
 
1923
- const requestData = {
1924
- fertilizerConstants: fertilizerConstants,
1925
- profileSettings: profileSettings
1926
- };
1927
 
1928
- console.log("=== ПОЛНЫЙ ОБЪЕКТ ДЛЯ РАСЧЁТА ===", JSON.stringify(requestData, null, 2));
1929
-
1930
- // 4. Локальн��й расчёт с использованием NutrientCalculator
1931
- try {
1932
- const calculator = new NutrientCalculator(requestData);
1933
- const results = calculator.calculate();
1934
-
1935
- console.log("=== УСПЕШНЫЙ РАСЧЁТ ===", results);
1936
-
1937
- // Обновляем интерфейс
1938
- data_out(results); // Выводим результаты
1939
- updateNitrogenFields(results); // Обновляем поля NH4 и NO3
1940
- showCalculationStatus(results); // Показываем статус расчёта
1941
- calculateCationsAndAnions(results); // Рассчитываем катионы и анионы
1942
- calculateAndUpdate(results); // Обновляем дополнительные данные
1943
- calculateMicroElements(); // Рассчитываем микроэлементы
1944
- calculateN1Ratio(results); // Рассчитываем соотношение N1
1945
-
1946
- // Рассчитываем EC
1947
- const temperature = parseFloat(document.getElementById('profile_temp').value) || 25;
1948
- const ecValue = calculateEC(results, temperature);
1949
- const ecInput = document.getElementById('profile_ec');
1950
- if (ecInput) {
1951
- ecInput.value = ecValue.toFixed(2);
1952
- console.log(`Установлено значение EC: ${ecValue.toFixed(2)}`);
1953
- }
1954
- } catch (error) {
1955
- console.error("=== ОШИБКА ПРИ РАСЧЁТЕ ===", error);
1956
- alert("Ошибка при расчете: " + error.message);
1957
- }
1958
- });
1959
 
1960
- </script>
1961
 
1962
 
1963
 
 
29
  background-color: #f0f0f0;
30
  font-family: Arial, sans-serif;
31
  }
 
32
  /* Стили для заголовка */
33
  .header-box {
34
  border: 2px solid #2e8b57;
 
41
  width: 1000px;
42
  box-sizing: border-box;
43
  }
 
44
  /* Общие стили для всех рамок */
45
  fieldset, .calculation-box {
46
  border: 2px solid #2e8b57;
 
51
  width: 1000px;
52
  box-sizing: border-box;
53
  }
 
54
  legend {
55
  font-weight: bold;
56
  color: #2e8b57;
57
  padding: 0 10px;
58
  }
 
59
  /* Стили для блока профиля */
60
  .main-container {
61
  display: grid;
 
64
  padding: 5px;
65
  margin-left: -50px; /* Сдвигаем блок левее */
66
  }
 
67
  .profile-container {
68
  display: contents;
69
  }
 
70
  .profile-element {
71
  display: flex;
72
  flex-direction: column;
73
  align-items: center;
74
  gap: 5px;
75
  }
 
76
  .profile-label {
77
  font-weight: bold;
78
  font-size: 0.9em;
79
  }
 
80
  .profile-element input {
81
  width: 80px;
82
  padding: 5px;
 
84
  border-radius: 4px;
85
  text-align: center;
86
  }
 
87
  .nitrogen-container {
88
  grid-column: 1 / -1;
89
  display: flex;
 
91
  padding-left: 40px;
92
  margin-top: 5px;
93
  }
 
94
  .nitrogen-group {
95
  display: flex;
96
  align-items: center;
97
  gap: 5px;
98
  }
 
99
  .nitrogen-group label {
100
  font-weight: bold;
101
  font-size: 0.9em;
102
  }
 
103
  .nitrogen-group input {
104
  width: 60px;
105
  padding: 5px;
106
  border: 1px solid #ccc;
107
  border-radius: 4px;
108
  }
 
109
  /* Стили для nitrogen */
110
  .nitrogen-container {
111
  display: flex;
 
114
  margin-left: 20px; /* Сдвигаем блок правее */
115
  margin-top: 10px; /* Отступ сверху */
116
  }
 
117
  .nitrogen-column {
118
  display: flex;
119
  flex-direction: column;
120
  gap: 10px;
121
  align-items: center; /* Центрируем содержимое колонки */
122
  }
 
123
  .column-header {
124
  font-weight: bold;
125
  font-size: 0.8em;
 
127
  text-align: center;
128
  width: 100%;
129
  }
 
130
  .nitrogen-group {
131
  display: flex;
132
  justify-content: center; /* Центрируем поля ввода */
133
  }
 
134
  .nitrogen-group input {
135
  width: 80px;
136
  padding: 5px;
 
138
  border-radius: 4px;
139
  }
140
  .square-button {
 
141
  width: 60px;
142
  height: 30px;
143
  font-size: 18px; /* Увеличенный размер текста */
 
152
  margin-bottom: 10px; /* Отступ снизу */
153
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* Тень для объема */
154
  }
 
 
155
  /* Стили для контейнера первого блока (NPK) */
156
  .npk-container {
157
  display: flex;
 
161
  margin-left: 15px; /* Общий отступ слева */
162
  margin-top: 10px; /* Отступ сверху */
163
  }
 
164
  /* Стили для заголовка NPK */
165
  .header-npk {
166
  font-weight: bold;
 
171
  margin-left: -5px; /* Сдвигаем строки влево */
172
  margin-bottom: 5px; /* Отступ между заголовком и основным блоком */
173
  }
 
174
  /* Стили для основного блока NPK */
175
  .block-npk {
176
  display: flex;
 
183
  border-radius: 8px;
184
  width: 65px; /* Ширина блока */
185
  }
 
186
  /* Стили для внутреннего контейнера строк (NPK) */
187
  .inner-block-npk {
188
  display: flex;
 
193
  margin-right: 0px; /* Добавляем внешний отступ справа */
194
  padding-bottom: 26px; /* Добавляем внешний отступ справа */
195
  }
 
196
  .row-npk {
197
  display: flex;
198
  align-items: center;
199
  gap: 5px;
200
  }
 
201
  .label-npk {
202
  font-weight: bold;
203
  min-width: 50px; /* Минимальная ширина меток */
204
  text-align: right;
205
  }
 
206
  .row-npk span {
207
  font-size: 0.9em;
208
  }
 
209
  /* Стили для контейнера второго блока (Ca-Mg-S) */
210
  .camgs-container {
211
  display: flex;
 
215
  margin-left: 8px; /* Общий отступ слева */
216
  margin-top: 10px; /* Отступ сверху */
217
  }
 
218
  /* Стили для заголовка Ca-Mg-S */
219
  .header-camgs {
220
  font-weight: bold;
 
223
  width: 75px; /* Ширина заголовка совпадает с шириной блока */
224
  margin-bottom: 5px; /* Отступ между заголовком и основным блоком */
225
  }
 
226
  /* Стили для основного блока Ca-Mg-S */
227
  .block-camgs {
228
  display: flex;
 
235
  border-radius: 8px;
236
  width: 85px; /* Ширина блока */
237
  }
 
238
  /* Стили для внутреннего контейнера строк (Ca-Mg-S) */
239
  .inner-block-camgs {
240
  display: flex;
 
245
  margin-right: 0px; /* Добавляем внешний отступ справа */
246
  padding-bottom: 26px; /* Добавляем внешний отступ*/
247
  }
 
248
  .row-camgs {
249
  display: flex;
250
  align-items: center;
251
  gap: 5px;
252
  }
 
253
  .label-camgs {
254
  font-weight: bold;
255
  min-width: 65px; /* Минимальная ширина меток */
256
  text-align: right;
257
  }
 
258
  .row-camgs span {
259
  font-size: 0.9em;
260
  }
 
 
 
 
261
  /* Стили для контейнера блока N1 */
262
  .n1-container {
263
  display: flex;
 
267
  margin-left: 8px; /* Общий отступ слева */
268
  margin-top: 10px; /* Отступ сверху */
269
  }
 
270
  /* Стили для заголовка N1 */
271
  .header-n1 {
272
  font-weight: bold;
 
275
  width: 100%; /* Ширина заголовка */
276
  margin-bottom: 5px; /* Отступ между заголовком и основным блоком */
277
  }
 
278
  .header-n1 span {
279
  margin-right: 5px; /* Отступ между "N1=" и значением */
280
  }
 
281
  #n1-value {
282
  font-weight: normal;
283
  color: #333;
284
  min-width: 100px; /* Место для значения */
285
  }
 
286
  /* Стили для основного блока N1 */
287
  .block-n1 {
288
  display: flex;
 
295
  border-radius: 8px;
296
  width: 200px; /* Ширина блока */
297
  }
 
298
  /* Стили для строки с меткой и индикатором */
299
  .n1-row {
300
  display: flex;
 
303
  gap: 5px;
304
  width: 100%;
305
  }
 
306
  .label-n1 {
307
  font-weight: bold;
308
  font-size: 0.9em;
309
  text-align: left;
310
  width: 100%;
311
  }
 
312
  /* Стили для контейнера индикатора */
313
  .indicator-container {
314
  width: 150px; /* Ширина индикатора */
 
318
  overflow: hidden;
319
  position: relative;
320
  }
 
321
  /* Стили для индикатора */
322
  .indicator {
323
  height: 100%;
 
326
  left: 0;
327
  transition: width 0.3s ease; /* Плавное изменение ширины */
328
  }
 
329
  .red-indicator {
330
  background-color: red;
331
  }
 
332
  .blue-indicator {
333
  background-color: blue;
334
  }
 
 
 
 
 
 
335
 
336
 
337
 
 
341
  flex-direction: column;
342
  margin-left: 20px; /* Сдвигаем блок */
343
  }
 
344
  .fert-row {
345
  display: flex;
346
  align-items: center;
347
  margin-bottom: 8px;
348
  }
 
349
  .fert-header {
350
  font-weight: bold;
351
  text-align: center;
 
353
  padding: 5px;
354
  font-size: 0.9em;
355
  }
 
356
  .fert-name {
357
  font-weight: bold;
358
  width: 120px;
359
  text-align: left;
360
  font-size: 0.9em;
361
  }
 
362
  .fert-cell {
363
  text-align: center;
364
  width: 80px;
365
  padding: 5px;
366
  font-size: 0.9em;
367
  }
 
368
  .fert-input {
369
  width: 70px;
370
  padding: 5px;
 
374
  margin: 0 5px;
375
  font-size: 0.9em;
376
  }
 
377
  /* Стили для блока расчета */
 
378
  .calculation-container {
379
  display: flex;
380
  gap: 40px; /* Расстояние между левым и правым блоками */
381
  align-items: flex-start;
382
  }
 
383
  /* Левый блок */
384
  .left-section {
385
  display: flex;
 
387
  gap: 20px; /* Расстояние между элементами */
388
  width: 100%; /* Занимает всю ширину */
389
  }
 
390
  .left-section label {
391
  font-weight: bold;
392
  font-size: 0.9em;
393
  }
 
394
  .left-section select {
395
  width: 100%; /* Выпадающий список занимает всю ширину */
396
  padding: 5px;
397
  border: 1px solid #ccc;
398
  border-radius: 4px;
399
  }
 
400
  .button-group {
401
  display: flex;
402
  gap: 10px; /* Расстояние между кнопками */
403
  }
 
404
  .button-group button {
405
  flex: 1; /* Кнопки занимают одинаковое пространство */
406
  padding: 8px;
 
410
  font-weight: bold;
411
  transition: background-color 0.3s;
412
  }
 
413
  #save-profile {
414
  background-color: #28a745; /* Зелёная кнопка */
415
  color: white;
416
  }
 
417
  #delete-profile {
418
  background-color: #dc3545; /* Красная кнопка */
419
  color: white;
420
  }
 
421
  /* Правый блок */
422
  .right-section {
423
  display: flex;
424
  flex-direction: column;
425
  gap: 10px;
426
  }
 
427
  .input-group {
428
  display: flex;
429
  align-items: center;
430
  gap: 10px;
431
  }
 
432
  .input-group label {
433
  width: 120px; /* Ширина меток */
434
  text-align: right;
435
  font-weight: bold;
436
  font-size: 0.9em;
437
  }
 
438
  .input-group input {
439
  width: 70px;
440
  padding: 5px;
441
  border: 1px solid #ccc;
442
  border-radius: 4px;
443
  }
 
444
  #calculate-btn {
445
  background-color: #2e8b57;
446
  color: white;
 
453
  margin-bottom: 5px;
454
  font-weight: bold;
455
  }
 
456
  #calculate-btn:hover {
457
  background-color: #3cb371;
458
  }
 
459
  /* micro контейнер */
460
  .micro-container {
461
  padding: 10px;
462
  }
 
463
  .micro-row {
464
  display: flex;
465
  gap: 20px;
466
  }
 
467
  .micro-group {
468
  display: flex;
469
  align-items: center;
470
  gap: 5px;
471
  }
 
472
  .micro-group label {
473
  min-width: 120px;
474
  }
 
475
  .micro-group input {
476
  width: 80px;
477
  text-align: right;
 
659
  <span class="fert-header">Ca</span>
660
  <span class="fert-header">Mg</span>
661
  <span class="fert-header">S</span>
662
+ <span class="fert-header">Cl</span>
663
  <span class="fert-header">Грамм</span>
664
  </div>
665
 
 
741
  <span class="fert-cell">-</span>
742
  <input class="fert-input" type="number" step="0.001" id="potassium_sulfate" readonly style="background-color: #d4f5d4;" />
743
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
744
  </div>
745
  </fieldset>
746
 
 
751
 
752
 
753
 
 
754
  <fieldset>
755
  <legend>Микроэлементы в мг/л (ppm)</legend>
756
  <div class="fertilisers-container">
 
863
  </div>
864
  <div class="input-group">
865
  <label for="rounding-precision">Точность:</label>
866
+ <input type="number" id="rounding-precision" value="3" min="0" max="3" step="1">
867
  </div>
868
  <button id="calculate-btn">Рассчитать</button>
869
  </div>
 
899
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/toastify-js"></script>
900
  <script>
901
  let call_data;
 
902
  const ecConstants = {
903
  'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
904
  'Ca': 0.0016, 'S': 0.0014,
905
  'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
906
  };
 
 
 
 
 
 
 
 
 
907
 
908
+ document.getElementById('calculate-btn').addEventListener('click', function () {
909
+ console.log("=== НАЧАЛО ОБРАБОТКИ ===");
910
+ // 1. Получаем значение точности округления
911
+ const roundingInput = document.getElementById('rounding-precision');
912
+ const initialRounding = parseInt(roundingInput.value);
913
+ const roundingPrecision = Math.min(Math.max(initialRounding || 3, 0), 6);
914
+ // 2. Функция для безопасного получения числового значения
915
+ const getValue = (id) => {
916
+ const element = document.getElementById(id);
917
+ if (!element) {
918
+ console.error(`Элемент с ID ${id} не найден!`);
919
+ return 0;
920
+ }
921
+ const value = parseFloat(element.value);
922
+ return isNaN(value) ? 0 : value;
923
+ };
924
+ // 3. Формируем данные для сервера
925
+ const fertilizerConstants = {
926
+ "Кальциевая селитра": {
927
+ "N (NO3-)": getValue('fert_ca_no3') / 100,
928
+ "Ca": getValue('fert_ca_ca') / 100
929
+ },
930
+ "Калий азотнокислый": {
931
+ "N (NO3-)": getValue('fert_kno3_no3') / 100,
932
+ "K": getValue('fert_kno3_k') / 100
933
+ },
934
+ "Аммоний азотнокислый": {
935
+ "N (NO3-)": getValue('fert_nh4no3_no3') / 100,
936
+ "N (NH4+)": getValue('fert_nh4no3_nh4') / 100
937
+ },
938
+ "Сульфат магния": {
939
+ "Mg": getValue('fert_mgso4_mg') / 100,
940
+ "S": getValue('fert_mgso4_s') / 100
941
+ },
942
+ "Монофосфат калия": {
943
+ "P": getValue('fert_kh2po4_p') / 100,
944
+ "K": getValue('fert_kh2po4_k') / 100
945
+ },
946
+ "Калий сернокислый": {
947
+ "K": getValue('fert_k2so4_k') / 100,
948
+ "S": getValue('fert_k2so4_s') / 100
949
+ }
950
+ };
951
+ const profileSettings = {
952
+ 'P': getValue('profile_p'),
953
+ 'K': getValue('profile_k'),
954
+ 'Mg': getValue('profile_mg'),
955
+ 'Ca': getValue('profile_ca'),
956
+ 'S': getValue('profile_s'),
957
+ 'NO3_RAT': getValue('profile_no3'),
958
+ 'TOTAL_NITROG': getValue('profile_n'),
959
+ 'liters': parseInt(document.getElementById('liters-input').value) || 1,
960
+ 'rounding_precision': roundingPrecision
961
+ };
962
+ const requestData = {
963
+ fertilizerConstants: fertilizerConstants,
964
+ profileSettings: profileSettings
965
+ };
966
+ console.log("=== ПОЛНЫЙ ОБЪЕКТ ДЛЯ ОТПРАВКИ ===", JSON.stringify(requestData, null, 2));
967
+ // 4. Отправка данных на сервер
968
+ fetch('/calculation', {
969
+ method: 'POST',
970
+ headers: {
971
+ 'Content-Type': 'application/json',
972
+ },
973
+ body: JSON.stringify(requestData),
974
+ })
975
+ .then(response => {
976
+ console.log("Получен ответ от сервера. Статус:", response.status);
977
+ if (!response.ok) {
978
+ throw new Error(`HTTP error! status: ${response.status}`);
979
+ }
980
+ return response.json();
981
+ })
982
+ .then(data => {
983
+ call_data = data;
984
+ console.log("=== УСПЕШНЫЙ ОТВЕТ ОТ СЕРВЕРА ===", call_data);
985
+ // Обновляем только поля вывода
986
+ data_out(call_data);
987
+ // Обновляем поля NH4 и NO3
988
+ updateNitrogenFields(call_data);
989
+ // Показываем статус расчёта
990
+ showCalculationStatus(call_data);
991
+ // Вызываем функцию для расчета катионов и анионов
992
+ calculateCationsAndAnions(data);
993
+ calculateAndUpdate(call_data);
994
+ calculateMicroElements();
995
+ calculateN1Ratio(call_data);
996
+ // Рассчитываем EC
997
+ const temperature = parseFloat(document.getElementById('profile_temp').value) || 25;
998
+ const ecValue = calculateEC(call_data, temperature);
999
+ const ecInput = document.getElementById('profile_ec');
1000
+ if (ecInput) {
1001
+ ecInput.value = ecValue.toFixed(2);
1002
+ console.log(`Установлено значение EC: ${ecValue.toFixed(2)}`);
1003
+ }
1004
+ })
1005
+ .catch(error => {
1006
+ console.error("=== ОШИБКА ПРИ ОБРАБОТКЕ ===", error);
1007
+ alert("Ошибка при расчете: " + error.message);
1008
+ });
1009
+ });
1010
  function data_out(data) {
1011
  console.log("=== ЗАПИСЬ ДАННЫХ В ФОРМУ ===");
 
1012
  // Сопоставление названий удобрений с их идентификаторами
1013
  const fertilizerIdMap = {
1014
  "Кальциевая селитра": "calcium_nitrate",
 
1018
  "Монофосфат калия": "monopotassium_phosphate",
1019
  "Калий сернокислый": "potassium_sulfate"
1020
  };
 
1021
  // Записываем массы удобрений
1022
  for (const [fertilizer, grams] of Object.entries(data.fertilizers)) {
1023
  const inputId = fertilizerIdMap[fertilizer];
 
1029
  console.warn(`Поле для удобрения ${fertilizer} не найдено`);
1030
  }
1031
  }
 
1032
  // Логика для CaCl больше не нужна
1033
  console.log("Логика для Кальция хлористого удалена.");
1034
  }
 
 
 
 
 
1035
  function updateNitrogenFields(data) {
1036
  console.log("=== ОБНОВЛЕНИЕ ЗНАЧЕНИЙ NH4 И NO3 ===");
 
1037
  // Извлекаем значения NH4 и NO3 из actual_profile
1038
  const nh4Value = data.actual_profile["N (NH4+)"] || 0;
1039
  const no3Value = data.actual_profile["N (NO3-)"] || 0;
 
1040
  // Обновляем поля NH4
1041
  document.getElementById("calculated_nh4").value = nh4Value.toFixed(3); // Расчетное значение NH4
 
1042
  // Обновляем поля NO3
1043
  document.getElementById("calculated_no3").value = no3Value.toFixed(3); // Расчетное значение NO3
 
1044
  console.log(`Значения NH4 и NO3 обновлены: NH4=${nh4Value}, NO3=${no3Value}`);
1045
  }
 
 
 
 
 
1046
 
1047
  function calculateAndUpdate(data) {
1048
  console.log("=== РАСЧЕТ И ОБНОВЛЕНИЕ ДАННЫХ ===");
 
1085
  document.getElementById("caMaS-mg-value").textContent = mgPercent.toFixed(2);
1086
  document.getElementById("caMaS-so-value").textContent = sPercent.toFixed(2);
1087
  }
 
 
 
 
 
1088
  function calculateCationsAndAnions() {
1089
  console.log("=== ДИНАМИЧЕСКИЙ РАСЧЕТ КАТИОНОВ И АНИОНОВ ===");
 
1090
  // 1. Получаем текущие значения из формы
1091
  const getValue = (id) => parseFloat(document.getElementById(id).value) || 0;
1092
  const profile = {
 
1099
  'S': getValue('profile_s')
1100
  // Убрали 'Cl', так как больше не учитываем кальций хлористый
1101
  };
 
1102
  // 2. Константы из вашей формы (упрощенные)
1103
  const FERTILIZER_CONSTANTS = {
1104
  'Кальциевая селитра': { 'N (NO3-)': 0.11863, 'Ca': 0.16972 },
 
1109
  'Калий сернокислый': { 'K': 0.44874, 'S': 0.18401 }
1110
  // Убрали 'Кальций хлорид'
1111
  };
 
1112
  // 3. Молярные массы и валентности
1113
  const ION_DATA = {
1114
  'Ca': { mass: 40.08, charge: 2 },
 
1120
  'H2PO4': { mass: 96.99, charge: 1 }
1121
  // Убрали 'Cl', так как больше не учитываем хлор
1122
  };
 
1123
  // 4. Пересчет серы (S → SO4²⁻)
1124
  const so4 = profile['S'] * (96.06 / 32.06);
 
1125
  // 5. Расчет mEq/L для каждого иона
1126
  const ions = {
1127
  'Ca': profile['Ca'] * ION_DATA['Ca'].charge / ION_DATA['Ca'].mass,
 
1133
  'H2PO4': profile['P'] * ION_DATA['H2PO4'].charge / ION_DATA['H2PO4'].mass
1134
  // Убрали 'Cl', так как больше не учитываем хлор
1135
  };
 
1136
  // 6. Суммирование
1137
  const totalCations = ions['Ca'] + ions['Mg'] + ions['K'] + ions['NH4'];
1138
  const totalAnions = ions['NO3'] + ions['SO4'] + ions['H2PO4'];
1139
  // Убрали 'Cl' из суммы анионов
 
1140
  // 7. Расчет процентов
1141
  const total = totalCations + totalAnions;
1142
  const cationPercent = total > 0 ? (totalCations / total * 100).toFixed(1) : 0;
1143
  const anionPercent = total > 0 ? (totalAnions / total * 100).toFixed(1) : 0;
 
1144
  // 8. Вывод результатов
1145
  console.log(`Катионы: ${totalCations.toFixed(2)} mEq/L (${cationPercent}%)`);
1146
  console.log(`Анионы: ${totalAnions.toFixed(2)} mEq/L (${anionPercent}%)`);
1147
  console.log(`Дисбаланс: ${(totalCations - totalAnions).toFixed(2)} mEq/L`);
 
1148
  // 9. Обновление UI
1149
  document.getElementById("n1-value").textContent =
1150
  `Катионы: ${totalCations.toFixed(2)} mEq/L | Анионы: ${totalAnions.toFixed(2)} mEq/L`;
 
1151
  // Обновление ширины индикаторов
1152
  document.getElementById("cation-indicator").style.width = `${cationPercent}%`;
1153
  document.getElementById("anion-indicator").style.width = `${anionPercent}%`;
1154
  }
 
 
 
1155
 
1156
 
 
1157
  function calculateEC(data, temperature, alpha = 0.019) {
1158
  console.log("=== РАСЧЕТ ЭЛЕКТРОПРОВОДНОСТИ (EC) ===");
 
1159
  const profile = data.actual_profile;
1160
  let totalEC = 0;
 
1161
  const ecConstants = {
1162
  'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
1163
  'Ca': 0.0016, 'S': 0.0014,
1164
  'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
1165
  };
 
1166
  const significantElements = Object.keys(ecConstants);
 
1167
  for (const element of significantElements) {
1168
  const ppm = profile[element] || 0;
1169
  const ecFactor = ecConstants[element];
 
1171
  totalEC += elementEC;
1172
  console.log(`EC для ${element}: ${elementEC.toFixed(5)} (ppm=${ppm}, const=${ecFactor})`);
1173
  }
 
1174
  console.log(`Общая EC без компенсации: ${totalEC.toFixed(5)}`);
 
1175
  const compensatedEC = totalEC * (1 + alpha * (temperature - 25));
1176
  console.log(`Компенсированная EC: ${compensatedEC.toFixed(5)} (T=${temperature}°C, α=${alpha})`);
 
1177
  return compensatedEC;
1178
  }
 
 
 
 
 
 
 
 
1179
  function calculateMicroElements() {
1180
  // 1. Получаем объем раствора (в литрах)
1181
  const litersInput = document.getElementById('liters-input');
 
1188
  alert("Введите корректный объем раствора!");
1189
  return;
1190
  }
 
1191
  // 2. Получаем массы удобрений (в граммах)
1192
  const feChelateInput = document.getElementById('fert_fe_chelate_mass');
1193
  const complexPowderInput = document.getElementById('fert_fe_complex_mass');
 
1197
  }
1198
  const feChelateMass = parseFloat(feChelateInput.value) || 0;
1199
  const complexPowderMass = parseFloat(complexPowderInput.value) || 0;
 
1200
  // 3. Содержание микроэлементов в удобрениях (%)
1201
  const feChelateContent = {
1202
  Fe: 0.11 // Хелат железа (11%)
1203
  };
 
1204
  const complexPowderContent = {
1205
  Fe: 0.0384, // Fe (ДТПА + ЭДТА) = 3.84%
1206
  Zn: 0.0053, // Zn (ЭДТА) = 0.53%
 
1209
  B: 0.0052, // B = 0.52%
1210
  Mo: 0.0013 // Mo = 0.13%
1211
  };
 
1212
  // 4. Рассчитываем чистые количества микроэлементов (в граммах)
1213
  const pureElements = {
1214
  Fe: (feChelateMass * feChelateContent.Fe) + (complexPowderMass * complexPowderContent.Fe),
 
1218
  B: complexPowderMass * complexPowderContent.B,
1219
  Mo: complexPowderMass * complexPowderContent.Mo
1220
  };
 
1221
  // 5. Рассчитываем концентрации в PPM (мг/л)
1222
  const ppm = {};
1223
  for (const element in pureElements) {
1224
  ppm[element] = (pureElements[element] * 1000) / solutionVolume; // Переводим граммы в мг/л
1225
  }
 
1226
  // 6. Выводим результаты в соответствующие поля матрицы
1227
  const outputFields = ['ppm_fe', 'ppm_zn', 'ppm_cu', 'ppm_mn', 'ppm_b', 'ppm_mo'];
1228
  outputFields.forEach((field, index) => {
 
1233
  console.error(`Элемент с id='${field}' не найден!`);
1234
  }
1235
  });
 
1236
  console.log("=== РАСЧЕТ PPM ===", ppm);
1237
  }
 
 
 
 
1238
  // Функция для расчета соотношений и формирования строки
1239
  function calculateN1Ratio(data) {
1240
  // Получаем значения элементов из ответа сервера
1241
  const { actual_profile, total_ppm } = data;
1242
  const { P, K, Ca, Mg, S } = actual_profile;
 
1243
  // Общий азот (N_total) = N (NH4+) + N (NO3-)
1244
  const N_total = actual_profile["N (NH4+)"] + actual_profile["N (NO3-)"];
 
1245
  // Вычисляем соотношения относительно общего азота (принимаем его за единицу)
1246
  const P_ratio = (P / N_total).toFixed(2);
1247
  const K_ratio = (K / N_total).toFixed(2);
1248
  const CaO_ratio = (Ca / N_total).toFixed(2); // Предполагается, что Ca - это оксид кальция
1249
  const MgO_ratio = (Mg / N_total).toFixed(2); // Предполагается, что Mg - это оксид магния
1250
  const SO_ratio = (S / N_total).toFixed(2); // Предполагается, что S - это оксид серы
 
1251
  // Формируем строку в требуемом формате
1252
  const n1String = `${P_ratio}:${K_ratio}:${CaO_ratio}:${MgO_ratio}:${SO_ratio} PPM=${total_ppm.toFixed(2)}`;
 
1253
  // Вставляем строку в HTML
1254
  document.getElementById("n1-value").textContent = n1String;
1255
  }
 
 
 
1256
 
1257
  </script>
1258
 
 
1270
  {type: 'error', background: '#F44336'}
1271
  ]
1272
  });
 
1273
  // Модифицированная функция
1274
  function showCalculationStatus(response) {
1275
  if (Object.keys(response.deficits || {}).length === 0) {
 
1291
  "profile_n", "profile_p", "profile_k",
1292
  "profile_ca", "profile_mg", "profile_s"
1293
  ];
 
1294
  fields.forEach(id => {
1295
  const input = document.getElementById(id);
1296
  let value = parseFloat(input.value); // Берём текущее значение
 
1300
  }
1301
  });
1302
  }
 
1303
  // Функция для уменьшения значений на 10%
1304
  function decreaseValues() {
1305
  const fields = [
1306
  "profile_n", "profile_p", "profile_k",
1307
  "profile_ca", "profile_mg", "profile_s"
1308
  ];
 
1309
  fields.forEach(id => {
1310
  const input = document.getElementById(id);
1311
  let value = parseFloat(input.value); // Берём текущее значение
 
1316
  }
1317
  });
1318
  }
 
1319
  // Привязываем функции к кнопкам
1320
  document.getElementById("plus-button").addEventListener("click", increaseValues);
1321
  document.getElementById("minus-button").addEventListener("click", decreaseValues);
 
1390
  }
1391
  ]
1392
  };
 
1393
  // Загрузка всех профилей (предустановленные + пользовательские)
1394
  function loadAllProfiles() {
1395
  const userProfiles = JSON.parse(localStorage.getItem("userProfiles")) || [];
1396
  return [...predefinedProfiles.profiles, ...userProfiles];
1397
  }
 
1398
  // Создание выпадающего списка
1399
  function populateProfileSelector() {
1400
  const profiles = loadAllProfiles();
1401
  const selector = document.getElementById("profile-selector");
 
1402
  // Очищаем предыдущие опции
1403
  selector.innerHTML = "";
 
1404
  // Добавляем предустановленные профили
1405
  const predefinedGroup = document.createElement("optgroup");
1406
  predefinedGroup.label = "Предустановленные профили";
 
1411
  predefinedGroup.appendChild(option);
1412
  });
1413
  selector.appendChild(predefinedGroup);
 
1414
  // Добавляем пользовательские профили
1415
  const userProfiles = JSON.parse(localStorage.getItem("userProfiles")) || [];
1416
  if (userProfiles.length > 0) {
 
1424
  });
1425
  selector.appendChild(userGroup);
1426
  }
 
1427
  // Выбираем первый профиль по умолчанию
1428
  if (profiles.length > 0) {
1429
  selector.value = profiles[0].name;
1430
  updateProfileFields(profiles[0]);
1431
  }
1432
  }
 
1433
  // Обновление полей при выб��ре профиля
1434
  function updateProfileFields(selectedProfile) {
1435
  document.getElementById("profile_p").value = selectedProfile.values.profile_p || 0;
 
1444
  document.getElementById("fert_fe_chelate_mass").value = selectedProfile.values.fert_fe_chelate_mass || 0;
1445
  document.getElementById("fert_fe_complex_mass").value = selectedProfile.values.fert_fe_complex_mass || 0;
1446
  }
 
1447
  // Слушатель события изменения выбранного профиля
1448
  document.getElementById("profile-selector").addEventListener("change", function () {
1449
  const selectedProfileName = this.value;
1450
  const allProfiles = loadAllProfiles();
1451
  const selectedProfile = allProfiles.find(profile => profile.name === selectedProfileName);
 
1452
  if (selectedProfile) {
1453
  updateProfileFields(selectedProfile);
1454
  }
1455
  });
 
1456
  // Сохранение нового профиля
1457
  document.getElementById("save-profile").addEventListener("click", async function () {
1458
  // Используем SweetAlert2 для ввода имени профиля
 
1471
  }
1472
  }
1473
  });
 
1474
  if (!profileName) return;
 
1475
  // Создаём новый профиль
1476
  const newProfile = {
1477
  name: profileName,
 
1489
  fert_fe_complex_mass: parseFloat(document.getElementById("fert_fe_complex_mass").value) || 0
1490
  }
1491
  };
 
1492
  // Добавляем профиль в localStorage
1493
  let userProfiles = JSON.parse(localStorage.getItem("userProfiles")) || [];
1494
  userProfiles.push(newProfile);
1495
  localStorage.setItem("userProfiles", JSON.stringify(userProfiles));
 
1496
  // Обновляем выпадающий список
1497
  populateProfileSelector();
1498
  });
 
1499
  // Удаление выбранного профиля
1500
  document.getElementById("delete-profile").addEventListener("click", async function () {
1501
  const selectedProfileName = document.getElementById("profile-selector").value;
 
1507
  });
1508
  return;
1509
  }
 
1510
  // Находим индекс профиля в localStorage
1511
  let userProfiles = JSON.parse(localStorage.getItem("userProfiles")) || [];
1512
  const profileIndex = userProfiles.findIndex(profile => profile.name === selectedProfileName);
 
1513
  if (profileIndex === -1) {
1514
  Swal.fire({
1515
  icon: "error",
 
1518
  });
1519
  return;
1520
  }
 
1521
  // Показываем SweetAlert2 для подтверждения удаления
1522
  const result = await Swal.fire({
1523
  title: "Вы уверены?",
 
1530
  cancelButtonColor: "#28a745", // Зелёная кнопка
1531
  reverseButtons: true
1532
  });
 
1533
  if (result.isConfirmed) {
1534
  // Удаляем профиль
1535
  userProfiles.splice(profileIndex, 1);
1536
  localStorage.setItem("userProfiles", JSON.stringify(userProfiles));
 
1537
  // Обновляем выпадающий список
1538
  populateProfileSelector();
 
1539
  // Выбираем первый профиль по умолчанию
1540
  const allProfiles = loadAllProfiles();
1541
  if (allProfiles.length > 0) {
1542
  document.getElementById("profile-selector").value = allProfiles[0].name;
1543
  updateProfileFields(allProfiles[0]);
1544
  }
 
1545
  // Показываем сообщение об успешном удалении
1546
  Swal.fire({
1547
  title: "Удалено!",
 
1557
  });
1558
  }
1559
  });
 
1560
  // Инициализация выпадающего списка при загрузке страницы
1561
  populateProfileSelector();
1562
  </script>
1563
 
1564
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1565
 
 
 
 
 
1566
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1567
 
 
1568
 
1569
 
1570