// Глобальный объект для состояния системы let systemStatus = { medods: { configured: false, details: {} }, n3health: { configured: false, details: {} }, password: { configured: true } }; // Глобальные переменные для статистики сотрудников let expirationAlertDays = 0; let allPractitioners = []; // Загрузка состояния системы async function loadSystemStatus() { try { const response = await fetch('/settings/get', { method: 'GET', headers: { 'Content-Type': 'application/json' } }); if (response.ok) { const data = await response.json(); // Сохраняем порог предупреждения expirationAlertDays = data.expirationAlert || 0; // Обновляем статус Медодс const medodsConfigured = data.medodsApiHost && data.medodsApiPort && data.medodsApiIdentity && data.medodsApiSecretKey; systemStatus.medods.configured = medodsConfigured; systemStatus.medods.details = { host: data.medodsApiHost || 'Не задан', port: data.medodsApiPort || 'Не задан', hasCredentials: !!(data.medodsApiIdentity && data.medodsApiSecretKey) }; // Обновляем статус N3Health const n3healthConfigured = data.n3healthHost && data.n3healthAutorization && data.n3healthXIdLpu; systemStatus.n3health.configured = n3healthConfigured; systemStatus.n3health.details = { host: data.n3healthHost || 'Не задан', hasToken: !!data.n3healthAutorization, hasLpuId: !!data.n3healthXIdLpu }; // Обновляем UI updateStatusUI(); updateReadinessIndicator(); } } catch (error) { console.error('Ошибка при загрузке статуса:', error); } } // Загрузка данных сотрудников async function loadStaffData() { try { const response = await fetch('/staff/getAll', { method: 'GET', headers: { 'Content-Type': 'application/json' } }); const respJson = await response.json(); if (response.ok && respJson.status === "ok") { allPractitioners = respJson.data || []; updateStaffStatistics(); } else { allPractitioners = []; console.error('Ошибка при загрузке сотрудников:', respJson.message); } } catch (error) { console.error('Ошибка при загрузке сотрудников:', error); allPractitioners = []; } } // Расчет дней до истечения function getDaysUntilExpiry(expiryDate) { const now = new Date(); const expiry = new Date(expiryDate); const diffTime = expiry - now; return Math.ceil(diffTime / (1000 * 60 * 60 * 24)); } // Форматирование даты function formatDate(dateString) { const date = new Date(dateString); return date.toLocaleDateString('ru-RU'); } // Обновление статистики сотрудников function updateStaffStatistics() { // Общая статистика const totalCount = allPractitioners.length; const ukepCount = allPractitioners.filter(p => p.esiaAuth).length; const mchdCount = allPractitioners.filter(p => !p.esiaAuth).length; // Сотрудники с истекающими подписями const expiringEmployees = allPractitioners.filter(p => { if (!p.expired_at) return false; const daysLeft = getDaysUntilExpiry(p.expired_at); return daysLeft <= expirationAlertDays && daysLeft >= 0; }).sort((a, b) => { const daysA = getDaysUntilExpiry(a.expired_at); const daysB = getDaysUntilExpiry(b.expired_at); return daysA - daysB; }); const expiringCount = expiringEmployees.length; // Обновляем счетчики document.getElementById('totalEmployeesCount').textContent = totalCount; document.getElementById('ukepEmployeesCount').textContent = ukepCount; document.getElementById('mchdEmployeesCount').textContent = mchdCount; document.getElementById('expiringEmployeesCount').textContent = expiringCount; // Обновляем контейнер с истекающими сотрудниками const container = document.getElementById('expiringEmployeesContainer'); const noExpiringMessage = document.getElementById('noExpiringEmployeesMessage'); const thresholdDaysSpan = document.getElementById('expiringThresholdDays'); const noExpiringThresholdSpan = document.getElementById('noExpiringThresholdDays'); // Обновляем отображение порога предупреждения const daysText = expirationAlertDays % 10 === 1 && expirationAlertDays % 100 !== 11 ? 'день' : expirationAlertDays % 10 >= 2 && expirationAlertDays % 10 <= 4 && (expirationAlertDays % 100 < 10 || expirationAlertDays % 100 >= 20) ? 'дня' : 'дней'; thresholdDaysSpan.textContent = `(менее ${expirationAlertDays} ${daysText})`; noExpiringThresholdSpan.textContent = expirationAlertDays; if (expiringCount > 0) { // Показываем таблицу container.style.display = 'block'; noExpiringMessage.style.display = 'none'; // Заполняем таблицу const tbody = document.getElementById('expiringEmployeesTableBody'); let rows = ''; expiringEmployees.forEach(p => { const daysLeft = getDaysUntilExpiry(p.expired_at); const signatureType = p.esiaAuth ? 'УКЭП' : 'МЧД'; let badgeClass = 'bg-warning'; if (daysLeft < 0) { badgeClass = 'bg-danger'; } else if (daysLeft <= 3) { badgeClass = 'bg-danger'; } else if (daysLeft <= 7) { badgeClass = 'bg-warning'; } else { badgeClass = 'bg-info'; } rows += `