481 lines
16 KiB
HTML
481 lines
16 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>GodEye Signal Center - Demo</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
background: #f5f7fa;
|
||
color: #333;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 20px;
|
||
}
|
||
|
||
.header {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 20px;
|
||
border-radius: 10px;
|
||
margin-bottom: 20px;
|
||
text-align: center;
|
||
}
|
||
|
||
.header h1 {
|
||
font-size: 2.5rem;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.tabs {
|
||
display: flex;
|
||
background: white;
|
||
border-radius: 10px;
|
||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||
margin-bottom: 20px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.tab {
|
||
flex: 1;
|
||
padding: 15px 20px;
|
||
text-align: center;
|
||
cursor: pointer;
|
||
background: #f8f9ff;
|
||
border: none;
|
||
font-size: 1rem;
|
||
transition: background-color 0.3s;
|
||
}
|
||
|
||
.tab:hover {
|
||
background: #e8ebff;
|
||
}
|
||
|
||
.tab.active {
|
||
background: #667eea;
|
||
color: white;
|
||
}
|
||
|
||
.tab-content {
|
||
display: none;
|
||
background: white;
|
||
border-radius: 10px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.tab-content.active {
|
||
display: block;
|
||
}
|
||
|
||
.status-card {
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 8px;
|
||
padding: 15px;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.status-connected {
|
||
border-left: 4px solid #28a745;
|
||
}
|
||
|
||
.status-disconnected {
|
||
border-left: 4px solid #dc3545;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.form-group label {
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.form-group input,
|
||
.form-group select,
|
||
.form-group textarea {
|
||
width: 100%;
|
||
padding: 10px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 5px;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.btn {
|
||
background: #667eea;
|
||
color: white;
|
||
border: none;
|
||
padding: 12px 24px;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
font-size: 1rem;
|
||
margin: 5px;
|
||
transition: background-color 0.3s;
|
||
}
|
||
|
||
.btn:hover {
|
||
background: #5a6fd8;
|
||
}
|
||
|
||
.btn:disabled {
|
||
background: #ccc;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.btn-danger {
|
||
background: #dc3545;
|
||
}
|
||
|
||
.btn-danger:hover {
|
||
background: #c82333;
|
||
}
|
||
|
||
.btn-success {
|
||
background: #28a745;
|
||
}
|
||
|
||
.btn-success:hover {
|
||
background: #218838;
|
||
}
|
||
|
||
.device-card, .session-card {
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 8px;
|
||
padding: 15px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.device-online {
|
||
border-left: 4px solid #28a745;
|
||
}
|
||
|
||
.device-offline {
|
||
border-left: 4px solid #6c757d;
|
||
}
|
||
|
||
.session-active {
|
||
border-left: 4px solid #007bff;
|
||
}
|
||
|
||
.session-pending {
|
||
border-left: 4px solid #ffc107;
|
||
}
|
||
|
||
.session-closed {
|
||
border-left: 4px solid #6c757d;
|
||
}
|
||
|
||
.logs {
|
||
background: #1e1e1e;
|
||
color: #f8f8f2;
|
||
padding: 15px;
|
||
border-radius: 5px;
|
||
font-family: 'Courier New', monospace;
|
||
height: 300px;
|
||
overflow-y: auto;
|
||
font-size: 0.9rem;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.log-entry {
|
||
margin-bottom: 5px;
|
||
padding: 2px 0;
|
||
}
|
||
|
||
.log-info { color: #66d9ef; }
|
||
.log-warn { color: #f4bf75; }
|
||
.log-error { color: #f92672; }
|
||
|
||
.grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||
gap: 20px;
|
||
}
|
||
|
||
.stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 15px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.stat-card {
|
||
background: white;
|
||
padding: 20px;
|
||
border-radius: 8px;
|
||
text-align: center;
|
||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.stat-number {
|
||
font-size: 2rem;
|
||
font-weight: bold;
|
||
color: #667eea;
|
||
}
|
||
|
||
.stat-label {
|
||
color: #666;
|
||
font-size: 0.9rem;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.video-container {
|
||
position: relative;
|
||
width: 100%;
|
||
max-width: 640px;
|
||
margin: 20px auto;
|
||
}
|
||
|
||
#localVideo, #remoteVideo {
|
||
width: 100%;
|
||
border-radius: 8px;
|
||
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
||
}
|
||
|
||
.alert {
|
||
padding: 15px;
|
||
margin-bottom: 15px;
|
||
border-radius: 5px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.alert-info {
|
||
background: #d1ecf1;
|
||
color: #0c5460;
|
||
border: 1px solid #bee5eb;
|
||
}
|
||
|
||
.alert-warning {
|
||
background: #fff3cd;
|
||
color: #856404;
|
||
border: 1px solid #ffeaa7;
|
||
}
|
||
|
||
.alert-danger {
|
||
background: #f8d7da;
|
||
color: #721c24;
|
||
border: 1px solid #f5c6cb;
|
||
}
|
||
|
||
.alert-success {
|
||
background: #d4edda;
|
||
color: #155724;
|
||
border: 1px solid #c3e6cb;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.tabs {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.header h1 {
|
||
font-size: 2rem;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="header">
|
||
<h1>🎥 GodEye Signal Center</h1>
|
||
<p>Веб-демонстрация системы удаленного доступа к камерам</p>
|
||
</div>
|
||
|
||
<div class="tabs">
|
||
<button class="tab active" onclick="showTab('overview')">Обзор</button>
|
||
<button class="tab" onclick="showTab('android')">Android Device</button>
|
||
<button class="tab" onclick="showTab('operator')">Operator</button>
|
||
<button class="tab" onclick="showTab('admin')">Admin</button>
|
||
<button class="tab" onclick="showTab('webrtc')">WebRTC Test</button>
|
||
</div>
|
||
|
||
<!-- Overview Tab -->
|
||
<div id="overview" class="tab-content active">
|
||
<h2>Системная статистика</h2>
|
||
<div class="stats-grid" id="stats-grid">
|
||
<div class="stat-card">
|
||
<div class="stat-number" id="stat-devices">-</div>
|
||
<div class="stat-label">Подключенных устройств</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-number" id="stat-operators">-</div>
|
||
<div class="stat-label">Активных операторов</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-number" id="stat-sessions">-</div>
|
||
<div class="stat-label">Активных сессий</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-number" id="stat-uptime">-</div>
|
||
<div class="stat-label">Время работы (мин)</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="status-card" id="connection-status">
|
||
<h3>Состояние подключения</h3>
|
||
<p id="connection-text">Подключение...</p>
|
||
</div>
|
||
|
||
<h3>Логи системы</h3>
|
||
<div class="logs" id="system-logs"></div>
|
||
<button class="btn" onclick="clearLogs()">Очистить логи</button>
|
||
</div>
|
||
|
||
<!-- Android Device Tab -->
|
||
<div id="android" class="tab-content">
|
||
<h2>Симулятор Android устройства</h2>
|
||
|
||
<div class="form-group">
|
||
<label>Device ID:</label>
|
||
<input type="text" id="android-device-id" value="demo-device-001" placeholder="Введите ID устройства">
|
||
</div>
|
||
|
||
<div class="grid">
|
||
<div>
|
||
<h3>Информация об устройстве</h3>
|
||
<div class="form-group">
|
||
<label>Модель:</label>
|
||
<input type="text" id="android-model" value="Samsung Galaxy S21">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Производитель:</label>
|
||
<input type="text" id="android-manufacturer" value="Samsung">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Версия Android:</label>
|
||
<input type="text" id="android-version" value="12">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Доступные камеры:</label>
|
||
<select id="android-cameras" multiple>
|
||
<option value="back" selected>Основная</option>
|
||
<option value="front" selected>Фронтальная</option>
|
||
<option value="ultra_wide">Широкоугольная</option>
|
||
<option value="telephoto">Телеобъектив</option>
|
||
</select>
|
||
</div>
|
||
|
||
<button class="btn btn-success" id="android-connect" onclick="connectAndroid()">
|
||
Подключить устройство
|
||
</button>
|
||
<button class="btn btn-danger" id="android-disconnect" onclick="disconnectAndroid()" disabled>
|
||
Отключить устройство
|
||
</button>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Входящие запросы</h3>
|
||
<div id="android-requests"></div>
|
||
|
||
<h3>Активные сессии</h3>
|
||
<div id="android-sessions"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Operator Tab -->
|
||
<div id="operator" class="tab-content">
|
||
<h2>Панель оператора</h2>
|
||
|
||
<div class="form-group">
|
||
<label>Operator ID:</label>
|
||
<input type="text" id="operator-id" value="demo-operator-001" placeholder="Введите ID оператора">
|
||
</div>
|
||
|
||
<button class="btn btn-success" id="operator-connect" onclick="connectOperator()">
|
||
Подключиться как оператор
|
||
</button>
|
||
<button class="btn btn-danger" id="operator-disconnect" onclick="disconnectOperator()" disabled>
|
||
Отключиться
|
||
</button>
|
||
|
||
<div class="grid">
|
||
<div>
|
||
<h3>Доступные устройства</h3>
|
||
<button class="btn" onclick="refreshDevices()">Обновить список</button>
|
||
<div id="available-devices"></div>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Мои сессии</h3>
|
||
<button class="btn" onclick="refreshSessions()">Обновить сессии</button>
|
||
<div id="operator-sessions"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Admin Tab -->
|
||
<div id="admin" class="tab-content">
|
||
<h2>Административная панель</h2>
|
||
|
||
<div class="grid">
|
||
<div>
|
||
<h3>Управление системой</h3>
|
||
<button class="btn" onclick="getSystemHealth()">Проверить здоровье системы</button>
|
||
<button class="btn" onclick="getSystemStats()">Получить статистику</button>
|
||
<button class="btn btn-danger" onclick="cleanupSystem()">Очистить систему</button>
|
||
|
||
<div id="admin-info"></div>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Все устройства</h3>
|
||
<button class="btn" onclick="getAllDevices()">Загрузить устройства</button>
|
||
<div id="all-devices"></div>
|
||
|
||
<h3>Все сессии</h3>
|
||
<button class="btn" onclick="getAllSessions()">Загрузить сессии</button>
|
||
<div id="all-sessions"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- WebRTC Test Tab -->
|
||
<div id="webrtc" class="tab-content">
|
||
<h2>Тест WebRTC соединения</h2>
|
||
|
||
<div class="alert alert-info">
|
||
<strong>Информация:</strong> Этот раздел демонстрирует WebRTC соединение между устройством и оператором.
|
||
Сначала подключитесь как Android устройство, затем как оператор и создайте сессию.
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Текущая сессия:</label>
|
||
<input type="text" id="current-session-id" placeholder="ID активной сессии" readonly>
|
||
</div>
|
||
|
||
<button class="btn" onclick="startLocalVideo()">Запустить локальное видео</button>
|
||
<button class="btn" onclick="stopLocalVideo()">Остановить видео</button>
|
||
|
||
<div class="video-container">
|
||
<video id="localVideo" autoplay muted playsinline></video>
|
||
<video id="remoteVideo" autoplay playsinline style="display: none;"></video>
|
||
</div>
|
||
|
||
<div id="webrtc-status"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="/socket.io/socket.io.js"></script>
|
||
<script src="demo.js"></script>
|
||
</body>
|
||
</html> |