2026-04-13 09:46:02 +03:00
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="ru">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
2026-04-15 11:38:26 +03:00
|
|
|
<title>Клиенты — NanoRouter</title>
|
2026-04-13 09:46:02 +03:00
|
|
|
<link rel="stylesheet" href="style.css">
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
|
|
|
|
|
<header>
|
|
|
|
|
<div class="header-left">
|
|
|
|
|
<svg class="logo" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
|
|
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
|
|
|
|
|
<path d="M2 17l10 5 10-5"/>
|
|
|
|
|
<path d="M2 12l10 5 10-5"/>
|
|
|
|
|
</svg>
|
2026-04-15 11:38:26 +03:00
|
|
|
<h1>NanoRouter</h1>
|
2026-04-13 09:46:02 +03:00
|
|
|
</div>
|
|
|
|
|
<div class="header-right">
|
|
|
|
|
</div>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<nav class="tab-nav">
|
2026-04-15 11:38:26 +03:00
|
|
|
<a href="/home.html" class="tab-link">
|
|
|
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15">
|
|
|
|
|
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
|
|
|
|
<polyline points="9 22 9 12 15 12 15 22"/>
|
|
|
|
|
</svg>
|
|
|
|
|
Главная
|
|
|
|
|
</a>
|
|
|
|
|
<a href="/ifaces.html" class="tab-link">
|
2026-04-13 09:46:02 +03:00
|
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15">
|
|
|
|
|
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
|
|
|
|
|
<path d="M2 17l10 5 10-5"/>
|
|
|
|
|
<path d="M2 12l10 5 10-5"/>
|
|
|
|
|
</svg>
|
|
|
|
|
Интерфейсы
|
|
|
|
|
</a>
|
|
|
|
|
<a href="/dhcp.html" class="tab-link">
|
|
|
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15">
|
|
|
|
|
<path d="M5 12h14M12 5l7 7-7 7"/>
|
|
|
|
|
</svg>
|
|
|
|
|
DHCP сервер
|
|
|
|
|
</a>
|
|
|
|
|
<a href="/clients.html" class="tab-link active">
|
|
|
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15">
|
|
|
|
|
<circle cx="9" cy="7" r="4"/><path d="M3 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2"/>
|
|
|
|
|
<path d="M16 3.13a4 4 0 0 1 0 7.75M21 21v-2a4 4 0 0 0-3-3.87"/>
|
|
|
|
|
</svg>
|
|
|
|
|
Клиенты
|
|
|
|
|
</a>
|
2026-04-13 12:40:49 +03:00
|
|
|
<a href="/firewall.html" class="tab-link">
|
2026-04-13 09:46:02 +03:00
|
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15">
|
|
|
|
|
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
|
2026-04-13 12:40:49 +03:00
|
|
|
<path d="M9 12l2 2 4-4"/>
|
|
|
|
|
</svg>
|
|
|
|
|
Файрвол
|
|
|
|
|
</a>
|
|
|
|
|
<a href="/proxy.html" class="tab-link">
|
|
|
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15">
|
|
|
|
|
<circle cx="12" cy="12" r="3"/>
|
|
|
|
|
<path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/>
|
2026-04-13 09:46:02 +03:00
|
|
|
</svg>
|
|
|
|
|
Прокси
|
|
|
|
|
</a>
|
2026-04-15 11:38:26 +03:00
|
|
|
<a href="/profile.html" class="tab-link">
|
|
|
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15">
|
|
|
|
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
|
|
|
|
|
<circle cx="12" cy="7" r="4"/>
|
|
|
|
|
</svg>
|
|
|
|
|
Профиль
|
|
|
|
|
</a>
|
2026-04-13 09:46:02 +03:00
|
|
|
</nav>
|
|
|
|
|
|
|
|
|
|
<main class="clients-main">
|
2026-04-15 11:38:26 +03:00
|
|
|
<!-- Policy management panel -->
|
|
|
|
|
<div class="policy-panel">
|
|
|
|
|
<div class="policy-section">
|
|
|
|
|
<div class="policy-section-label">
|
|
|
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="13" height="13">
|
|
|
|
|
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
|
|
|
|
|
</svg>
|
|
|
|
|
Политика для новых устройств
|
|
|
|
|
</div>
|
|
|
|
|
<div class="segmented" id="defaultPolicySelector">
|
|
|
|
|
<button type="button" class="seg-btn" data-val="disabled">Отключён</button>
|
|
|
|
|
<button type="button" class="seg-btn" data-val="direct">Напрямую</button>
|
|
|
|
|
<button type="button" class="seg-btn active" data-val="vpn">Через VPN</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="policy-divider"></div>
|
|
|
|
|
<div class="policy-section">
|
|
|
|
|
<div class="policy-section-label">Применить ко всем</div>
|
|
|
|
|
<div class="policy-apply-all">
|
|
|
|
|
<button type="button" class="btn btn-ghost btn-sm policy-all-btn" data-val="disabled">Отключить всех</button>
|
|
|
|
|
<button type="button" class="btn btn-ghost btn-sm policy-all-btn" data-val="direct">Напрямую</button>
|
|
|
|
|
<button type="button" class="btn btn-primary btn-sm policy-all-btn" data-val="vpn">Через VPN</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-04-13 09:46:02 +03:00
|
|
|
|
|
|
|
|
<div class="clients-toolbar">
|
|
|
|
|
<div class="clients-summary" id="clientsSummary"></div>
|
|
|
|
|
<input type="search" id="clientsSearch" class="clients-search" placeholder="Поиск по хосту, IP, MAC…">
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div id="loading" class="loading">
|
|
|
|
|
<div class="spinner"></div>
|
|
|
|
|
<span>Загрузка...</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div id="emptyState" class="empty-state hidden">
|
|
|
|
|
Нет подключённых устройств
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div id="clientsTableWrap" class="clients-table-wrap hidden">
|
|
|
|
|
<table class="clients-table">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th></th>
|
|
|
|
|
<th>Хост</th>
|
|
|
|
|
<th>IP-адрес</th>
|
|
|
|
|
<th>MAC-адрес</th>
|
|
|
|
|
<th>Интерфейс</th>
|
|
|
|
|
<th>Тип</th>
|
2026-04-15 11:38:26 +03:00
|
|
|
<th>Маршрут</th>
|
2026-04-13 09:46:02 +03:00
|
|
|
<th class="col-tx">↑ Отправлено</th>
|
|
|
|
|
<th class="col-rx">↓ Получено</th>
|
|
|
|
|
<th>Активность</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody id="clientsBody"></tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</main>
|
|
|
|
|
|
|
|
|
|
<div id="clientModal" class="modal hidden">
|
|
|
|
|
<div class="modal-backdrop" id="modalBackdrop"></div>
|
|
|
|
|
<div class="modal-box">
|
|
|
|
|
<div class="modal-header">
|
|
|
|
|
<h2 id="modalTitle">Устройство</h2>
|
|
|
|
|
<button class="btn-icon" id="modalClose" title="Закрыть">
|
|
|
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><path d="M18 6L6 18M6 6l12 12"/></svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<form id="clientForm" autocomplete="off">
|
|
|
|
|
<div class="form-row">
|
|
|
|
|
<label>Имя устройства</label>
|
|
|
|
|
<input type="text" id="modalHostname" placeholder="Например: Ноутбук Анны">
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<hr class="form-divider">
|
|
|
|
|
|
|
|
|
|
<div class="form-row">
|
|
|
|
|
<label>IP-адрес</label>
|
|
|
|
|
<div class="ip-info-row">
|
|
|
|
|
<span class="form-val mono" id="modalIP">—</span>
|
|
|
|
|
<span class="ip-current-label" id="modalIPCurrent"></span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-row">
|
|
|
|
|
<label for="modalStaticIP">Фиксированный IP</label>
|
|
|
|
|
<input type="text" id="modalStaticIP" placeholder="Например: 192.168.1.100">
|
|
|
|
|
<span class="form-hint" id="modalStaticHint">Оставьте пустым для динамического назначения через DHCP</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-row">
|
|
|
|
|
<label>MAC-адрес</label>
|
|
|
|
|
<span class="form-val mono" id="modalMAC">—</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-row">
|
|
|
|
|
<label>Интерфейс</label>
|
|
|
|
|
<span class="form-val" id="modalIface">—</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<hr class="form-divider">
|
|
|
|
|
|
2026-04-15 11:38:26 +03:00
|
|
|
<div class="form-row form-row--col">
|
|
|
|
|
<label>Выход в интернет</label>
|
|
|
|
|
<div class="segmented" id="modalPolicySelector">
|
|
|
|
|
<button type="button" class="seg-btn" data-val="disabled">Отключён</button>
|
|
|
|
|
<button type="button" class="seg-btn" data-val="direct">Напрямую</button>
|
|
|
|
|
<button type="button" class="seg-btn" data-val="vpn">Через VPN</button>
|
2026-04-13 09:46:02 +03:00
|
|
|
</div>
|
2026-04-15 11:38:26 +03:00
|
|
|
<span class="form-hint" id="modalPolicyHint">Пусто = использовать политику по умолчанию</span>
|
2026-04-13 09:46:02 +03:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="modal-footer" style="padding:18px 0 0;">
|
|
|
|
|
<button type="button" class="btn btn-ghost" id="modalCancel">Отмена</button>
|
|
|
|
|
<button type="submit" class="btn btn-primary" id="modalSave">Сохранить</button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div id="toast" class="toast hidden"></div>
|
|
|
|
|
|
|
|
|
|
<script src="clients.js"></script>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|