Расширенная Фрамингемская шкала

Расширенная Фрамингемская шкала оценки сердечно-сосудистого риска

Демографические данные

Антропометрические показатели

Артериальное давление

Лабораторные показатели

Факторы риска и анамнез

Образ жизни

5 баллов

Медикаментозная терапия

Результат расчета расширенной Фрамингемской шкалы:

Расширенная Фрамингемская шкала оценки сердечно-сосудистого риска

${resultElement.innerHTML}

Дата расчета: ${new Date().toLocaleDateString('ru-RU')} ${new Date().toLocaleTimeString('ru-RU')}

`); printWindow.document.close(); // Добавляем небольшую задержку перед печатью, чтобы стили успели загрузиться setTimeout(() => { printWindow.print(); // Закрытие окна после печати может не работать во всех браузерах из соображений безопасности. // printWindow.close(); }, 250); // 250ms задержка console.log("Медицинский калькулятор: Запущена печать."); // Отладочное сообщение } // Функция exportResult для экспорта в HTML function exportResult(elementId, filename) { console.log("Медицинский калькулятор: Функция 'Экспорт' вызвана (формат HTML)."); // Отладочное сообщение const resultElement = document.getElementById(elementId); if (!resultElement || resultElement.style.display === 'none') { alert('Сначала выполните расчет!'); console.warn("Медицинский калькулятор: Попытка экспорта до расчета."); // Отладочное сообщение return; } // Получаем HTML-содержимое блока с результатом const resultHTMLContent = resultElement.innerHTML; // Стили для экспортированного HTML - адаптированы из основного CSS const exportStyles = ` body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 20px; color: #333; line-height: 1.6; } h2 { color: #01608c; text-align: center; margin-bottom: 20px; border-bottom: 3px solid #01608c; padding-bottom: 15px; font-size: 28px; font-weight: 700; } .result-container { /* Note: This container div might not be needed in the exported HTML, but keeping for structure */ margin-top: 0; /* Adjust margin for the export file */ padding: 0; /* Adjust padding */ background: none; /* Remove background */ border-left: none; /* Remove border */ } .result-title { font-size: 20px; font-weight: 700; color: #2c3e50; margin-bottom: 15px; } .result-text { font-size: 16px; line-height: 1.6; color: #34495e; } .risk-low { color: #27ae60; font-weight: 600; } .risk-moderate { color: #f39c12; font-weight: 600; } .risk-high { color: #e74c3c; font-weight: 600; } .risk-very-high { color: #c0392b; font-weight: 700; } .score-display { background: #3498db; color: white; padding: 15px; border-radius: 10px; text-align: center; font-size: 24px; font-weight: 700; margin: 15px 0; } .recommendations { background: #e8f4fd; padding: 20px; border-radius: 10px; margin-top: 15px; border-left: 4px solid #3498db; } .recommendations h4 { color: #2c3e50; margin-bottom: 10px; } .recommendations ul { margin-left: 20px; color: #34495e; } .recommendations li { margin-bottom: 5px; } `; // Создаем полный HTML документ для экспорта const htmlContent = ` Результат расчета Фрамингемской шкалы

Расширенная Фрамингемская шкала оценки сердечно-сосудистого риска

${resultHTMLContent}

Дата расчета: ${new Date().toLocaleDateString('ru-RU')} ${new Date().toLocaleTimeString('ru-RU')}

`; // Создаем Blob с типом text/html const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `${filename}_${new Date().toISOString().split('T')[0]}.html`; // Изменяем расширение на .html link.style.display = 'none'; // Скрываем ссылку document.body.appendChild(link); // Добавляем в body (необходимо для click в некоторых браузерах) link.click(); document.body.removeChild(link); // Удаляем ссылку после клика // Освобождаем URL объекта URL.revokeObjectURL(link.href); console.log("Медицинский калькулятор: Запущен экспорт в HTML."); // Отладочное сообщение } // Инициализация слушателей событий const initCalculatorEvents = function() { console.log("Медицинский калькулятор: Инициализация слушателей событий..."); // Отладочное сообщение 5 const container = document.querySelector('.medical-calculator-isolated .calculator-container'); const floatingButtonsContainer = document.querySelector('.floating-buttons'); // Get the floating buttons container if (!container) { console.error('Медицинский калькулятор: Контейнер калькулятора (.medical-calculator-isolated .calculator-container) не найден.'); // Отладочное сообщение 6 // Попробуем переинициализировать через короткое время, если контейнер не найден сразу setTimeout(initCalculatorEvents, 500); // Повторить попытку через 500мс return; } console.log("Медицинский калькулятор: Контейнер калькулятора найден. Привязываю делегированный слушатель к нему:", container); // Отладочное сообщение // --- Делегированный слушатель для кнопок калькулятора --- container.addEventListener('click', function(event) { // console.log("Медицинский калькулятор: Клик внутри контейнера калькулятора.", event.target); // Отладочное сообщение (может быть много!) // Проверяем, была ли нажата кнопка (или элемент внутри кнопки) внутри button-group const clickedButton = event.target.closest('.medical-calculator-isolated .button-group .btn'); if (clickedButton) { // Предотвращаем действие по умолчанию (например, отправку формы, если бы кнопка была внутри
) event.preventDefault(); console.log("Медицинский калькулятор: Нажата кнопка в группе:", clickedButton.textContent.trim()); // Отладочное сообщение // Определяем, какая именно кнопка была нажата по ее data-атрибуту const action = clickedButton.dataset.action; if (action === 'calculate') { calculateFraminghamExtended(); } else if (action === 'clear') { clearFraminghamExtended(); } else if (action === 'print') { printResult('framingham_result'); } else if (action === 'export') { exportResult('framingham_result', 'Фрамингемская_шкала_расширенная'); } } }); console.log("Медицинский калькулятор: Делегированный слушатель на контейнере калькулятора добавлен."); // Отладочное сообщение // --- Слушатели для плавающих кнопок (прямые) --- if (floatingButtonsContainer) { console.log("Медицинский калькулятор: Контейнер плавающих кнопок найден. Привязываю слушатели к ним."); // Отладочное сообщение const scrollUpBtn = floatingButtonsContainer.querySelector('#scrollUpBtn'); const scrollDownBtn = floatingButtonsContainer.querySelector('#scrollDownBtn'); const printFloatingBtn = floatingButtonsContainer.querySelector('#printFloatingBtn'); console.log("Медицинский калькулятор: Плавающие кнопки найдены (или нет):", { scrollUpBtn, scrollDownBtn, printFloatingBtn }); // Отладочное сообщение const scrollStep = window.innerHeight * 0.8; // Прокрутка на 80% высоты окна if (scrollDownBtn) { scrollDownBtn.addEventListener('click', function() { console.log("Медицинский калькулятор: Нажата плавающая кнопка 'Вниз'."); // Отладочное сообщение window.scrollBy({ top: scrollStep, behavior: 'smooth' }); }); console.log("Медицинский калькулятор: Слушатель плавающей 'Вниз' добавлен."); // Отладочное сообщение } else { console.warn('Медицинский калькулятор: Плавающая кнопка #scrollDownBtn не найдена.'); } if (scrollUpBtn) { scrollUpBtn.addEventListener('click', function() { console.log("Медицинский калькулятор: Нажата плавающая кнопка 'Вверх'."); // Отладочное сообщение // Прокрутка к верху страницы или к началу калькулятора const containerTop = container ? container.getBoundingClientRect().top + window.scrollY : 0; window.scrollTo({ top: containerTop, behavior: 'smooth' }); }); // Управление видимостью кнопки "Наверх" const toggleScrollUpButton = function() { if (window.scrollY > (container ? container.offsetTop : 200)) { // Показываем, если прокручено ниже начала калькулятора (или 200px как запасной вариант) scrollUpBtn.classList.remove('hidden'); } else { scrollUpBtn.classList.add('hidden'); } }; // Привязываем слушатель прокрутки к окну window.addEventListener('scroll', toggleScrollUpButton); // Вызываем один раз при загрузке, чтобы установить начальное состояние toggleScrollUpButton(); console.log("Медицинский калькулятор: Слушатель плавающей 'Вверх' и управление видимостью добавлены."); // Отладочное сообщение } else { console.warn('Медицинский калькулятор: Плавающая кнопка #scrollUpBtn не найдена.'); } if (printFloatingBtn) { // Вызываем ту же функцию printResult, что и основная кнопка Печать printFloatingBtn.addEventListener('click', function() { console.log("Медицинский калькулятор: Нажата плавающая кнопка 'Печать'."); // Отладочное сообщение printResult('framingham_result'); }); console.log("Медицинский калькулятор: Слушатель плавающей 'Печать' добавлен."); // Отладочное сообщение } else { console.warn('Медицинский калькулятор: Плавающая кнопка #printFloatingBtn не найдена.'); } } else { console.warn('Медицинский калькулятор: Контейнер плавающих кнопок (.floating-buttons) не найден.'); // Отладочное сообщение } // Убедимся, что ползунок стресса обновляет значение при загрузке страницы const stressInput = container.querySelector('#stress'); if (stressInput) { updateStressValue(stressInput.value); } console.log("Медицинский калькулятор: Инициализация слушателей завершена."); // Отладочное сообщение }; // Запускаем инициализацию слушателей событий. // Попробуем привязать сразу, но в надежде, что контейнеры уже в DOM. // Если контейнеры могут быть добавлены позже (например, AJAX), // возможно, потребуется другая логика ожидания или вызов этой функции после загрузки контента. initCalculatorEvents(); // Также, можно привязаться к DOMContentLoaded как дополнительную гарантию, // если initCalculatorEvents() сработала слишком рано. document.addEventListener('DOMContentLoaded', function() { console.log("Медицинский калькулятор: DOMContentLoaded fired (дополнительная инициализация)."); // Отладочное сообщение // Проверим, был ли уже добавлен слушатель делегирования, чтобы не дублировать const container = document.querySelector('.medical-calculator-isolated .calculator-container'); if (container && !container._eventListenersInitialized) { // Используем флаг на контейнере container._eventListenersInitialized = true; // Устанавливаем флаг initCalculatorEvents(); // Повторно вызываем инициализацию, если не сработало сразу } else if (container && container._eventListenersInitialized) { console.log("Медицинский калькулятор: Слушатели уже были добавлены через DOMContentLoaded."); } else { // Если контейнер не найден даже в DOMContentLoaded, выведем ошибку еще раз if (!container) console.error('Медицинский калькулятор: Контейнер калькулятора не найден после DOMContentLoaded.'); } // Проверим плавающие кнопки отдельно, т.к. они вне основного контейнера const floatingButtonsContainer = document.querySelector('.floating-buttons'); if (floatingButtonsContainer && !floatingButtonsContainer._floatingListenersInitialized) { floatingButtonsContainer._floatingListenersInitialized = true; // Устанавливаем флаг // Повторно вызываем init, чтобы гарантировать привязку плавающих кнопок // Это немного избыточно, т.к. initCalculatorEvents уже это делает, // но может быть полезно, если контейнер калькулятора появился, а плавающие кнопки еще нет (редко) // В данном случае, поскольку они в одном HTML, они, скорее всего, появятся вместе. // Поэтому достаточно одной инициализации. Убираем повторный вызов здесь. console.log("Медицинский калькулятор: Плавающие кнопки найдены в DOMContentLoaded."); } else if (floatingButtonsContainer && floatingButtonsContainer._floatingListenersInitialized) { console.log("Медицинский калькулятор: Плавающие слушатели уже были добавлены."); } else { if (!floatingButtonsContainer) console.warn('Медицинский калькулятор: Контейнер плавающих кнопок не найден после DOMContentLoaded.'); } }); })(); // End of IIFE
Адаптивный футер