init commit

This commit is contained in:
2025-09-28 22:00:44 +09:00
commit 25cb9d9c8f
5877 changed files with 582116 additions and 0 deletions

481
backend/public/index.html Normal file
View File

@@ -0,0 +1,481 @@
<!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>