Files
alpine-router/public/clients.html

162 lines
5.6 KiB
HTML
Raw Normal View History

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">
<title>Клиенты — AlpineRouter</title>
<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>
<h1>AlpineRouter</h1>
</div>
<div class="header-right">
<button class="btn btn-ghost" id="refreshBtn" title="Обновить">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/>
<path d="M3 3v5h5"/>
</svg>
Обновить
</button>
</div>
</header>
<nav class="tab-nav">
<a href="/" class="tab-link">
<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>
<a href="/proxy.html" class="tab-link">
<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"/>
</svg>
Прокси
</a>
</nav>
<main class="clients-main">
<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>
<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">
<div class="form-row" style="flex-direction:row; align-items:center; justify-content:space-between;">
<div>
<div style="font-weight:600;">Доступ в интернет</div>
<div style="font-size:.8rem;color:var(--muted);margin-top:2px;" id="modalBlockHint">Отключите, чтобы запретить устройству выход в интернет</div>
</div>
<label class="toggle-label" id="modalBlockToggle">
<input type="checkbox" id="modalBlocked">
<span class="toggle-slider"></span>
</label>
</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>