const MODE_LABELS = { auto: 'Автономный', manual: 'Ручной', assist: 'Ассистированный', standby: 'Ожидание', }; const STATUS_LABELS = { online: 'ONLINE', idle: 'IDLE', offline: 'OFFLINE', emergency: 'E-STOP', }; let currentUser = null; let ROBOTS = []; let selectedRobotId = null; let saveTimer = null; const $ = (sel) => document.querySelector(sel); const $$ = (sel) => document.querySelectorAll(sel); async function init() { try { currentUser = await API.me(); } catch { window.location.href = '/login'; return; } $('#header-user').textContent = currentUser.email; initNavigation(); initLogout(); await loadRobots(); initControls(); initProfile(); initFooterClock(); addLog('Система инициализирована', 'success'); } async function loadRobots() { const data = await API.getRobots(); ROBOTS = data.robots; selectedRobotId = data.selected_robot_id || ROBOTS[0]?.id; ROBOTS.forEach(applySettingsToRobot); initRobotList(); selectRobot(selectedRobotId, { skipSave: true }); $('#robot-count').textContent = ROBOTS.length; } function applySettingsToRobot(robot) { if (robot.emergency) { robot.speed = 0; robot.status = 'emergency'; robot.temperature = Math.round((robot.baseTemp || 30) + 5); robot.sensorAccuracy = 0; return; } if (robot.mode === 'standby') { robot.speed = 0; robot.status = 'idle'; robot.temperature = Math.round(robot.baseTemp || 30); robot.sensorAccuracy = Math.round(robot.sensitivity * 0.5); return; } const maxSpeed = robot.maxSpeed || 2; robot.speed = +(maxSpeed * robot.speedSetting / 100).toFixed(1); robot.sensorAccuracy = robot.sensitivity; robot.temperature = Math.round( (robot.baseTemp || 30) + robot.speedSetting * 0.12 + robot.sensitivity * 0.06 ); if (robot.battery < 15) { robot.status = 'offline'; robot.speed = 0; } else { robot.status = 'online'; } } function readControlsToRobot(robot) { robot.mode = $('#ctrl-mode').value; robot.speedSetting = parseInt($('#ctrl-speed').value, 10); robot.sensitivity = parseInt($('#ctrl-sensitivity').value, 10); robot.emergency = $('#ctrl-emergency').checked; robot.nightMode = $('#ctrl-night').checked; } async function persistRobots() { await API.saveRobots({ robots: ROBOTS, selected_robot_id: selectedRobotId, }); } function scheduleSave() { clearTimeout(saveTimer); saveTimer = setTimeout(async () => { try { await persistRobots(); } catch (err) { showToast(err.message); } }, 500); } async function saveCurrentRobotSettings({ silent = false } = {}) { const robot = ROBOTS.find((r) => r.id === selectedRobotId); if (!robot) return; readControlsToRobot(robot); applySettingsToRobot(robot); refreshRobotListItem(robot); syncRobotUI(robot); try { await persistRobots(); if (!silent) { addLog(`Настройки применены: ${robot.name}`, 'success'); showToast('Настройки сохранены'); } } catch (err) { showToast(err.message); } } function initNavigation() { $$('.nav__btn').forEach((btn) => { btn.addEventListener('click', async () => { const page = btn.dataset.page; const activePage = $('.page--active')?.id; if (activePage === 'page-dashboard') { await saveCurrentRobotSettings({ silent: true }); } if (activePage === 'page-profile') { await loadProfile(); } $$('.nav__btn').forEach((b) => b.classList.remove('nav__btn--active')); btn.classList.add('nav__btn--active'); $$('.page').forEach((p) => p.classList.remove('page--active')); $(`#page-${page}`).classList.add('page--active'); if (page === 'profile') await loadProfile(); if (page === 'dashboard') { const robot = ROBOTS.find((r) => r.id === selectedRobotId); if (robot) syncRobotUI(robot); } }); }); } function initLogout() { $('#btn-logout').addEventListener('click', async () => { await API.logout(); window.location.href = '/login'; }); } function initRobotList() { const list = $('#robot-list'); list.innerHTML = ROBOTS.map((r) => renderRobotListItem(r)).join(''); list.querySelectorAll('.robot-item').forEach((item) => { item.addEventListener('click', async () => { if (item.dataset.id !== selectedRobotId) { await saveCurrentRobotSettings({ silent: true }); } selectRobot(item.dataset.id, { skipSave: true }); }); }); } function renderRobotListItem(robot) { const statusClass = robot.status === 'emergency' ? 'emergency' : robot.status; return `
Нет активных сессий
'; } function initProfile() { $('#profile-form').addEventListener('submit', async (e) => { e.preventDefault(); try { currentUser = await API.updateProfile({ firstname: $('#field-firstname').value, lastname: $('#field-lastname').value, patronymic: $('#field-patronymic').value, age: parseInt($('#field-age').value, 10) || null, phone: $('#field-phone').value, }); updateProfileDisplay(); $('#profile-rating').textContent = currentUser.rating.toFixed(1); $('#profile-points').textContent = currentUser.points; addLog('Профиль обновлён', 'success'); showToast('Профиль сохранён'); } catch (err) { showToast(err.message); } }); $('#btn-cancel-profile').addEventListener('click', () => loadProfile()); } function updateProfileDisplay() { const parts = [currentUser.lastname, currentUser.firstname, currentUser.patronymic].filter(Boolean); $('#profile-fullname').textContent = parts.length ? parts.join(' ') : currentUser.email; } function formatDate(iso) { return new Date(iso).toLocaleString('ru-RU'); } function addLog(message, type = 'info') { const log = $('#event-log'); const time = new Date().toLocaleTimeString('ru-RU'); const entry = document.createElement('div'); entry.className = `log__entry log__entry--${type}`; entry.innerHTML = `