main commit

This commit is contained in:
2025-10-04 11:55:55 +09:00
parent c8c3274527
commit 4ceccae6ce
678 changed files with 95975 additions and 185 deletions

View File

@@ -61,6 +61,40 @@ function initializeSocket() {
socket.on('device:disconnected', (data) => {
logMessage('warn', `Устройство отключено: ${data.deviceId}`);
});
// Обработчики событий сессий
socket.on('session:created', (data) => {
logMessage('info', `Сессия создана: ${data.sessionId} для устройства ${data.deviceId}`);
updateOperatorSessions();
});
socket.on('session:accepted', (data) => {
logMessage('info', `Сессия принята: ${data.sessionId}`);
currentSessionId = data.sessionId;
document.getElementById('current-session-id').value = currentSessionId;
// Показываем кнопку веб-камеры для оператора
showOperatorWebcamButton();
updateOperatorSessions();
showAlert('Сессия принята! Можно начинать WebRTC соединение.', 'success');
});
socket.on('session:rejected', (data) => {
logMessage('warn', `Сессия отклонена: ${data.sessionId} - ${data.error}`);
updateOperatorSessions();
showAlert(`Сессия отклонена: ${data.error}`, 'warning');
});
socket.on('session:ended', (data) => {
logMessage('info', `Сессия завершена: ${data.sessionId}`);
updateOperatorSessions();
// Скрываем элементы веб-камеры
hideOperatorWebcamButton();
const webcamVideo = document.getElementById('operatorWebcam');
if (webcamVideo) webcamVideo.style.display = 'none';
});
}
// Обновление статуса подключения
@@ -300,6 +334,14 @@ function connectOperator() {
document.getElementById('operator-disconnect').disabled = false;
showAvailableDevices(data.availableDevices || []);
updateOperatorSessions(); // Обновляем список сессий после подключения
// Автоматическое обновление сессий каждые 3 секунды
setInterval(() => {
if (operatorSocket && operatorSocket.connected) {
updateOperatorSessions();
}
}, 3000);
});
operatorSocket.on('device:connected', (data) => {
@@ -310,6 +352,12 @@ function connectOperator() {
operatorSocket.on('camera:stream-ready', (data) => {
logMessage('info', `Камера готова: ${data.sessionId}`);
showOperatorSession(data.sessionId, 'active');
updateOperatorSessions();
});
operatorSocket.on('camera:request-sent', (data) => {
logMessage('info', `Запрос отправлен: ${data.sessionId}`);
updateOperatorSessions();
});
operatorSocket.on('camera:denied', (data) => {
@@ -497,26 +545,7 @@ async function endOperatorSession(sessionId) {
}
async function refreshSessions() {
const operatorId = document.getElementById('operator-id').value;
if (!operatorId) return;
try {
const response = await fetch('/api/operators/sessions', {
headers: { 'X-Operator-Id': operatorId }
});
if (response.ok) {
const data = await response.json();
const container = document.getElementById('operator-sessions');
container.innerHTML = '';
data.sessions.forEach(session => {
showOperatorSession(session.sessionId, session.status);
});
}
} catch (error) {
logMessage('error', 'Ошибка загрузки сессий: ' + error.message);
}
updateOperatorSessions();
}
// === ADMIN FUNCTIONS ===
@@ -780,9 +809,95 @@ function stopLocalVideo() {
}
}
// Вспомогательная функция для показа уведомлений
function showAlert(type, message) {
// Создаем временное уведомление
// Обновление списка сессий оператора
function updateOperatorSessions() {
console.log('updateOperatorSessions called, operatorSocket:', operatorSocket);
if (!operatorSocket) {
console.log('No operatorSocket, returning');
return;
}
if (!operatorSocket.connected) {
console.log('operatorSocket not connected, returning');
return;
}
console.log('Requesting sessions list...');
operatorSocket.emit('sessions:list', {}, (sessions) => {
console.log('Received sessions:', sessions);
const container = document.getElementById('operator-sessions');
if (!container) {
console.log('No operator-sessions container found');
return;
}
container.innerHTML = '';
if (!sessions || sessions.length === 0) {
container.innerHTML = '<p>Нет активных сессий</p>';
console.log('No sessions to display');
return;
}
console.log('Displaying', sessions.length, 'sessions');
sessions.forEach(session => {
const sessionCard = document.createElement('div');
sessionCard.className = `session-card session-${session.status}`;
const statusText = {
'pending': 'Ожидание',
'active': 'Активна',
'rejected': 'Отклонена',
'ended': 'Завершена'
};
sessionCard.innerHTML = `
<h4>Сессия: ${session.sessionId ? session.sessionId.substr(0, 8) : session.id ? session.id.substr(0, 8) : 'N/A'}...</h4>
<p><strong>Устройство:</strong> ${session.deviceId}</p>
<p><strong>Камера:</strong> ${session.cameraType}</p>
<p><strong>Статус:</strong> ${statusText[session.status] || session.status}</p>
<p><strong>Создана:</strong> ${new Date(session.createdAt).toLocaleString()}</p>
${session.status === 'active' ? `
<button class="btn" onclick="switchCamera('${session.sessionId || session.id}', 'front')">Фронтальная</button>
<button class="btn" onclick="switchCamera('${session.sessionId || session.id}', 'back')">Основная</button>
<button class="btn btn-danger" onclick="endSession('${session.sessionId || session.id}')">Завершить</button>
` : ''}
`;
container.appendChild(sessionCard);
});
});
}
// Завершение сессии
function endSession(sessionId) {
if (!operatorSocket) {
showAlert('Не подключен как оператор', 'danger');
return;
}
operatorSocket.emit('session:end', { sessionId });
logMessage('info', `Завершаем сессию: ${sessionId}`);
}
// Переключение камеры
function switchCamera(sessionId, cameraType) {
if (!operatorSocket) {
showAlert('Не подключен как оператор', 'danger');
return;
}
operatorSocket.emit('camera:switch', {
sessionId,
cameraType
});
logMessage('info', `Переключаем камеру: ${sessionId} на ${cameraType}`);
}
// Показ уведомления
function showAlert(message, type) {
const alert = document.createElement('div');
alert.className = `alert alert-${type}`;
alert.textContent = message;
@@ -794,7 +909,6 @@ function showAlert(type, message) {
document.body.appendChild(alert);
// Удаляем через 5 секунд
setTimeout(() => {
if (document.body.contains(alert)) {
document.body.removeChild(alert);