Files
medods_to_n3_health/src/app/static/js/index.js
T
2026-02-15 17:02:40 +03:00

283 lines
12 KiB
JavaScript

// Глобальный объект для состояния системы
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 ?
'<span class="badge bg-success">УКЭП</span>' :
'<span class="badge bg-warning text-dark">МЧД</span>';
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 += `
<tr>
<td>${p.name}</td>
<td>${signatureType}</td>
<td>${formatDate(p.expired_at)}</td>
<td>
<span class="badge ${badgeClass}">${daysLeft} дн.</span>
</td>
</tr>
`;
});
tbody.innerHTML = rows;
} else {
// Показываем сообщение об отсутствии
container.style.display = 'none';
noExpiringMessage.style.display = 'block';
}
}
// Обновление UI на основе статуса
function updateStatusUI() {
// Медодс
const medodsBadge = document.getElementById('medodsStatusBadge');
const medodsDetails = document.getElementById('medodsDetails');
if (systemStatus.medods.configured) {
medodsBadge.className = 'badge bg-success';
medodsBadge.textContent = 'Настроено';
medodsDetails.innerHTML = `
<div class="text-success mb-1"><i class="bi bi-check-circle"></i> Хост: ${systemStatus.medods.details.host}</div>
<div class="text-success mb-1"><i class="bi bi-check-circle"></i> Порт: ${systemStatus.medods.details.port}</div>
<div class="text-success"><i class="bi bi-check-circle"></i> Учетные данные: есть</div>
`;
} else {
medodsBadge.className = 'badge bg-danger';
medodsBadge.textContent = 'Требуется настройка';
medodsDetails.innerHTML = `
<div class="text-danger mb-1"><i class="bi bi-exclamation-circle"></i> Хост: ${systemStatus.medods.details.host}</div>
<div class="text-danger mb-1"><i class="bi bi-exclamation-circle"></i> Порт: ${systemStatus.medods.details.port}</div>
<div class="text-danger"><i class="bi bi-exclamation-circle"></i> Учетные данные: нет</div>
`;
}
// N3Health
const n3healthBadge = document.getElementById('n3healthStatusBadge');
const n3healthDetails = document.getElementById('n3healthDetails');
if (systemStatus.n3health.configured) {
n3healthBadge.className = 'badge bg-success';
n3healthBadge.textContent = 'Настроено';
n3healthDetails.innerHTML = `
<div class="text-success mb-1"><i class="bi bi-check-circle"></i> Хост: ${systemStatus.n3health.details.host}</div>
<div class="text-success mb-1"><i class="bi bi-check-circle"></i> Токен доступа: есть</div>
<div class="text-success"><i class="bi bi-check-circle"></i> Идентификатор МО: есть</div>
`;
} else {
n3healthBadge.className = 'badge bg-danger';
n3healthBadge.textContent = 'Требуется настройка';
n3healthDetails.innerHTML = `
<div class="text-danger mb-1"><i class="bi bi-exclamation-circle"></i> Хост: ${systemStatus.n3health.details.host}</div>
<div class="text-danger mb-1"><i class="bi bi-exclamation-circle"></i> Токен доступа: нет</div>
<div class="text-danger"><i class="bi bi-exclamation-circle"></i> Идентификатор МО: нет</div>
`;
}
}
// Обновление индикатора готовности и управление кнопкой
function updateReadinessIndicator() {
const progressBar = document.querySelector('#systemReadiness .progress-bar');
const readinessDesc = document.getElementById('readinessDescription');
const settingsButtonContainer = document.getElementById('settingsButtonContainer');
let configuredCount = 0;
if (systemStatus.password.configured) configuredCount++;
if (systemStatus.medods.configured) configuredCount++;
if (systemStatus.n3health.configured) configuredCount++;
const readinessPercentage = Math.round((configuredCount / 3) * 100);
progressBar.style.width = `${readinessPercentage}%`;
progressBar.setAttribute('aria-valuenow', readinessPercentage);
progressBar.textContent = `${readinessPercentage}%`;
// Обновляем цвет прогресс-бара
if (readinessPercentage === 100) {
progressBar.className = 'progress-bar progress-bar-striped progress-bar-animated bg-success';
readinessDesc.textContent = 'Все системы настроены и готовы к работе!';
// Скрываем кнопку настроек при 100% готовности
settingsButtonContainer.style.display = 'none';
} else if (readinessPercentage >= 66) {
progressBar.className = 'progress-bar progress-bar-striped progress-bar-animated bg-info';
readinessDesc.textContent = 'Большинство систем настроены';
settingsButtonContainer.style.display = 'block';
} else if (readinessPercentage >= 33) {
progressBar.className = 'progress-bar progress-bar-striped progress-bar-animated bg-warning';
readinessDesc.textContent = 'Требуется дополнительная настройка';
settingsButtonContainer.style.display = 'block';
} else {
progressBar.className = 'progress-bar progress-bar-striped progress-bar-animated bg-danger';
readinessDesc.textContent = 'Все интеграции требуют настройки';
settingsButtonContainer.style.display = 'block';
}
}
// Инициализация при загрузке страницы
document.addEventListener('DOMContentLoaded', function () {
// Загружаем статус системы и данные сотрудников
Promise.all([
loadSystemStatus(),
loadStaffData()
]).then(() => {
// Обновляем статистику после загрузки всех данных
updateStaffStatistics();
});
// Обновляем индикатор готовности и управление кнопкой
updateReadinessIndicator();
});