kpi-dashboard / static /js /main.js
Admin
Initial HF deploy
04477e7
Raw
History Blame
4.37 kB
document.addEventListener('DOMContentLoaded', function() {
initTheme();
initNotifications();
});
function initTheme() {
const savedTheme = getCookie('theme') || 'light';
document.documentElement.setAttribute('data-bs-theme', savedTheme);
const toggle = document.getElementById('theme-toggle');
if (toggle) {
toggle.addEventListener('click', function(e) {
e.preventDefault();
const current = document.documentElement.getAttribute('data-bs-theme');
const next = current === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-bs-theme', next);
setCookie('theme', next, 365);
const icon = this.querySelector('i');
const text = this.querySelector('span');
if (next === 'dark') {
icon.className = 'bi bi-sun-fill me-2';
text.textContent = 'Светлая тема';
} else {
icon.className = 'bi bi-moon-stars-fill me-2';
text.textContent = 'Тёмная тема';
}
});
}
}
function initNotifications() {
loadNotifications();
setInterval(loadNotificationCount, 30000);
}
function loadNotifications() {
const notifList = document.getElementById('notif-list');
if (!notifList) return;
fetch('/api/notifications/latest')
.then(r => r.json())
.then(data => {
if (data.length === 0) {
notifList.innerHTML = '<div class="text-center py-3" style="color: var(--apple-gray-400); font-size: 13px;">Нет новых уведомлений</div>';
return;
}
let html = '';
data.forEach(n => {
html += '<a href="' + n.link + '" class="dropdown-item border-bottom py-2" style="border-color: rgba(0,0,0,0.04) !important;">' +
'<div class="d-flex" style="gap: 8px;">' +
'<div>' + getNotifIcon(n.type) + '</div>' +
'<div>' +
'<div style="font-size: 13px;">' + n.message + '</div>' +
'<small style="color: var(--apple-gray-400);">' + getTimeAgo(n.time_ago) + '</small>' +
'</div></div></a>';
});
notifList.innerHTML = html;
})
.catch(() => {
notifList.innerHTML = '<div class="text-center py-3" style="color: var(--apple-gray-400); font-size: 13px;">Ошибка загрузки</div>';
});
}
function loadNotificationCount() {
fetch('/api/notifications/count')
.then(r => r.json())
.then(data => {
const badge = document.getElementById('notif-badge-top');
if (data.count > 0) {
if (badge) { badge.textContent = data.count; badge.style.display = ''; }
} else {
if (badge) badge.style.display = 'none';
}
})
.catch(() => {});
}
function getNotifIcon(type) {
const icons = {
'success': '<i class="bi bi-check-circle-fill" style="color: var(--apple-green);"></i>',
'danger': '<i class="bi bi-exclamation-circle-fill" style="color: var(--apple-red);"></i>',
'warning': '<i class="bi bi-exclamation-triangle-fill" style="color: var(--apple-orange);"></i>',
'info': '<i class="bi bi-info-circle-fill" style="color: var(--apple-blue);"></i>',
};
return icons[type] || icons.info;
}
function getTimeAgo(seconds) {
if (!seconds) return 'только что';
const mins = Math.floor(seconds / 60);
if (mins < 1) return 'только что';
if (mins < 60) return mins + ' мин. назад';
const hours = Math.floor(mins / 60);
if (hours < 24) return hours + ' ч. назад';
const days = Math.floor(hours / 24);
return days + ' дн. назад';
}
function getCookie(name) {
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
return match ? decodeURIComponent(match[2]) : null;
}
function setCookie(name, value, days) {
let expires = '';
if (days) {
const d = new Date();
d.setTime(d.getTime() + days * 24 * 60 * 60 * 1000);
expires = '; expires=' + d.toUTCString();
}
document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/';
}