Files
mikrotik-proxy-api/static/js/app.js
T

242 lines
9.4 KiB
JavaScript

// Элементы DOM
const statusIndicator = document.getElementById('statusIndicator');
const statusInfo = document.getElementById('statusInfo');
const btnOn = document.getElementById('btnOn');
const btnOff = document.getElementById('btnOff');
const notification = document.getElementById('notification');
const notificationMessage = document.getElementById('notificationMessage');
// Конфигурация API
const API_BASE_URL = window.location.origin;
const API_STATUS_ENDPOINT = `${API_BASE_URL}/api/v1/client/status`;
const API_TOGGLE_ENDPOINT = `${API_BASE_URL}/api/v1/client/toggle`;
// Переменные состояния
let currentStatus = null;
let isRequestInProgress = false;
let hasIntegration = false;
// Инициализация при загрузке страницы
document.addEventListener('DOMContentLoaded', function () {
loadInitialStatus();
btnOn.addEventListener('click', () => sendCommand(true));
btnOff.addEventListener('click', () => sendCommand(false));
});
// Функция загрузки начального статуса
async function loadInitialStatus() {
try {
updateUIForLoading();
const response = await fetch(API_STATUS_ENDPOINT);
const data = await response.json();
if (data.success) {
hasIntegration = true;
currentStatus = data.data.enabled;
updateUIForStatus(currentStatus);
showNotification(`Доступ разрешен. Ваш IP: ${data.data.ip}.`, 'success', true);
} else {
hasIntegration = false;
updateUIForNoIntegration(data.error || 'Нет интеграции с сервисом');
}
} catch (error) {
console.error('Ошибка при загрузке статуса:', error);
updateUIForError('Ошибка соединения с сервером API');
}
}
// Функция отправки команды на сервер
async function sendCommand(enabled) {
if (!hasIntegration || isRequestInProgress) return;
// Прерываем, если запрашиваемое состояние уже активно
if (enabled === currentStatus) return;
isRequestInProgress = true;
const action = enabled ? 'включения' : 'выключения';
updateUIForSendingCommand(enabled);
try {
const response = await fetch(API_TOGGLE_ENDPOINT, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' }
});
const data = await response.json();
if (data.success) {
currentStatus = data.data.enabled;
updateUIForStatus(currentStatus);
showNotification(`Команда ${action} успешно выполнена.`, 'success');
provideVisualFeedback(currentStatus);
} else {
showNotification(`Ошибка: ${data.error}`, 'error');
updateUIForStatus(currentStatus);
}
} catch (error) {
console.error('Ошибка при отправке команды:', error);
showNotification('Ошибка сети при отправке команды', 'error');
updateUIForStatus(currentStatus);
} finally {
isRequestInProgress = false;
}
}
// Обновление UI при загрузке
function updateUIForLoading() {
statusIndicator.className = 'status-indicator status-loading';
statusIndicator.innerHTML = '<i class="fas fa-sync-alt fa-spin"></i> Загрузка...';
statusInfo.textContent = 'Получение текущего состояния с сервера...';
btnOn.classList.add('btn-disabled');
btnOff.classList.add('btn-disabled');
btnOn.disabled = true;
btnOff.disabled = true;
}
// Обновление UI на основе текущего статуса
function updateUIForStatus(enabled) {
if (enabled) {
statusIndicator.className = 'status-indicator status-on';
statusIndicator.innerHTML = '<i class="fas fa-check-circle"></i> Включено';
statusInfo.textContent = 'Устройство активно и работает в нормальном режиме';
btnOn.classList.add('btn-disabled');
btnOn.disabled = true;
btnOff.classList.remove('btn-disabled');
btnOff.disabled = false;
} else {
statusIndicator.className = 'status-indicator status-off';
statusIndicator.innerHTML = '<i class="fas fa-power-off"></i> Выключено';
statusInfo.textContent = 'Устройство отключено и не выполняет свои функции';
btnOff.classList.add('btn-disabled');
btnOff.disabled = true;
btnOn.classList.remove('btn-disabled');
btnOn.disabled = false;
}
}
// Обновление UI при отсутствии интеграции
function updateUIForNoIntegration(message) {
statusIndicator.className = 'status-indicator status-disabled';
statusIndicator.innerHTML = '<i class="fas fa-ban"></i> Нет доступа';
statusInfo.textContent = 'Ваш IP-адрес не найден в списке доверенных адресов';
btnOn.classList.add('btn-disabled');
btnOff.classList.add('btn-disabled');
btnOn.disabled = true;
btnOff.disabled = true;
showNotification(message, 'error', true);
}
// Обновление UI при ошибке
function updateUIForError(errorMessage) {
statusIndicator.className = 'status-indicator status-disabled';
statusIndicator.innerHTML = '<i class="fas fa-exclamation-triangle"></i> Ошибка';
statusInfo.textContent = 'Не удалось получить информацию о статусе устройства';
btnOn.classList.add('btn-disabled');
btnOff.classList.add('btn-disabled');
btnOn.disabled = true;
btnOff.disabled = true;
showNotification(errorMessage, 'error', true);
}
// Обновление UI при отправке команды
function updateUIForSendingCommand(enabled) {
const action = enabled ? 'включения' : 'выключения';
statusIndicator.className = 'status-indicator status-loading';
statusIndicator.innerHTML = '<i class="fas fa-sync-alt fa-spin"></i> Отправка...';
statusInfo.textContent = `Отправка команды ${action} на сервер...`;
btnOn.classList.add('btn-disabled');
btnOff.classList.add('btn-disabled');
btnOn.disabled = true;
btnOff.disabled = true;
showNotification(`Отправка команды ${action}...`, 'warning');
}
// Переменные для управления уведомлениями
let baseNotificationContent = null;
let notificationTimeout = null;
// Показать уведомление
function showNotification(message, type = 'info', isPersistent = false) {
if (notificationTimeout) {
clearTimeout(notificationTimeout);
notificationTimeout = null;
}
notification.className = 'notification';
let icon = 'fa-info-circle';
let title = 'Информация:';
if (type === 'error') {
notification.classList.add('notification-error');
icon = 'fa-exclamation-circle';
title = 'Ошибка:';
} else if (type === 'success') {
notification.classList.add('notification-success');
icon = 'fa-check-circle';
title = 'Успешно:';
} else if (type === 'warning') {
notification.classList.add('notification-warning');
icon = 'fa-sync-alt fa-spin';
title = 'Обработка:';
}
const content = `<h3><i class="fas ${icon}"></i> ${title}</h3><div class="notification-message">${message}</div>`;
notification.innerHTML = content;
if (isPersistent) {
baseNotificationContent = content;
}
notification.style.opacity = '0';
notification.style.display = 'block';
// Плавное появление
setTimeout(() => {
notification.style.transition = 'opacity 0.3s ease';
notification.style.opacity = '1';
}, 10);
// Авто-возврат к базовому уведомлению через 5 секунд (если это не само базовое и не "в обработке")
if (!isPersistent && baseNotificationContent && type !== 'warning') {
notificationTimeout = setTimeout(() => {
notification.style.opacity = '0';
setTimeout(() => {
notification.className = 'notification';
notification.innerHTML = baseNotificationContent;
notification.style.opacity = '1';
}, 300);
}, 5000);
}
}
// Визуальная обратная связь
function provideVisualFeedback(enabled) {
if (enabled) {
document.body.style.background = 'linear-gradient(135deg, #2ecc71 0%, #27ae60 100%)';
setTimeout(() => {
document.body.style.background = 'linear-gradient(135deg, #1a2980 0%, #26d0ce 100%)';
}, 800);
} else {
document.body.style.background = 'linear-gradient(135deg, #e74c3c 0%, #c0392b 100%)';
setTimeout(() => {
document.body.style.background = 'linear-gradient(135deg, #1a2980 0%, #26d0ce 100%)';
}, 800);
}
}
// Дополнительная функция для ручного обновления статуса
function refreshStatus() {
if (!isRequestInProgress) {
loadInitialStatus();
}
}
statusIndicator.addEventListener('dblclick', refreshStatus);