Files
video_socket-server/client/public/main.js

334 lines
10 KiB
JavaScript
Raw Normal View History

2026-04-29 15:18:30 +08:00
/**
* 主入口文件
* 初始化应用连接各个模块
2026-05-16 21:26:19 +08:00
* SPA架构connect视图和call视图在同一页面切换
2026-04-29 15:18:30 +08:00
*/
import store from './store.js';
import UIRenderer from './renderer.js';
2026-05-17 20:59:34 +08:00
import { showNotification, randomMeetingId } from './utils.js';
2026-04-29 15:18:30 +08:00
import chatMessage from './chatmessage.js';
2026-05-16 21:26:19 +08:00
import {
bindConnectViewEvents,
initWebSocket,
loadUserSettings
} from './connectview.js';
2026-04-29 15:18:30 +08:00
// 全局变量
let connectionId = "";
2026-05-16 21:26:19 +08:00
// 当前视图状态:'connect' 或 'call'(可用于未来扩展)
let currentView = 'connect';
2026-05-18 21:18:55 +08:00
function getInvitePayloadFromUrl() {
const params = new URLSearchParams(window.location.search);
if (params.get('invite') !== '1') {
return null;
}
return {
name: params.get('callerName') || '邀请方',
avatar: params.get('callerAvatar') || '/images/p2.png',
connectionId: params.get('connectionId') || ''
};
}
function showCallRequestDialog(caller = {}) {
const dialog = document.getElementById('callRequestDialog');
if (!dialog) {
return;
}
const callerName = caller.name || '邀请方';
const callerAvatar = caller.avatar || '/images/p2.png';
const targetConnectionId = caller.connectionId || '';
if (document.getElementById('callRequestName')) {
document.getElementById('callRequestName').textContent = callerName;
}
if (document.getElementById('callRequestAvatar')) {
document.getElementById('callRequestAvatar').src = callerAvatar;
}
if (document.getElementById('callRequestText')) {
document.getElementById('callRequestText').textContent = targetConnectionId
? `正在邀请您加入通话 (${targetConnectionId})`
: '正在请求与您进行视频通话';
}
if (targetConnectionId) {
connectionId = targetConnectionId;
localStorage.setItem('connectionId', targetConnectionId);
}
dialog.classList.remove('hidden');
}
function bindInviteDialogEvents() {
window.showCallRequest = function (caller) {
showCallRequestDialog(caller);
};
window.rejectCall = function () {
const dialog = document.getElementById('callRequestDialog');
if (dialog) {
dialog.classList.add('hidden');
}
showNotification('已拒绝通话请求');
};
window.acceptCall = async function () {
const dialog = document.getElementById('callRequestDialog');
if (dialog) {
dialog.classList.add('hidden');
}
const targetConnectionId =
connectionId ||
localStorage.getItem('connectionId') ||
new URLSearchParams(window.location.search).get('connectionId');
if (!targetConnectionId) {
showNotification('缺少连接ID无法接受邀请', 'error');
return;
}
connectionId = targetConnectionId;
localStorage.setItem('connectionId', targetConnectionId);
showNotification('已接受通话请求');
if (currentView !== 'call') {
await switchToCallView(targetConnectionId);
}
};
const rejectCall = document.getElementById('rejectCall');
const acceptCall = document.getElementById('acceptCall');
if (rejectCall && !rejectCall.dataset.bound) {
rejectCall.addEventListener('click', window.rejectCall);
rejectCall.dataset.bound = 'true';
}
if (acceptCall && !acceptCall.dataset.bound) {
acceptCall.addEventListener('click', window.acceptCall);
acceptCall.dataset.bound = 'true';
}
}
2026-05-16 21:26:19 +08:00
/**
* 切换到call视图创建/加入通话后
* @param {string} connectionId - 连接ID
*/
async function switchToCallView(connectionId) {
const connectView = document.getElementById('connectView');
const callView = document.getElementById('callView');
if (connectView) connectView.classList.add('hidden');
if (callView) callView.classList.remove('hidden');
currentView = 'call';
try {
// 初始化渲染器
const renderer = new UIRenderer(store);
// 加入通话
await store.joinCall(connectionId);
// 设置WebRTC连接
await store.setUp(connectionId);
renderer.renderHeaderTitle();
// 绑定DOM事件
bindCallViewDomEvents();
console.log('Video call app initialized successfully');
} catch (error) {
console.error('Error initializing app:', error);
showNotification('初始化失败,请刷新页面重试', 'error');
}
}
/**
* 处理加入通话
* @param {string} connectionId - 连接ID
*/
async function handleJoinCall(connectionId) {
showNotification(`正在加入通话 (${connectionId})`);
localStorage.setItem('connectionId', connectionId);
await switchToCallView(connectionId);
}
2026-04-29 15:18:30 +08:00
/**
2026-05-16 21:26:19 +08:00
* 处理创建通话
2026-04-29 15:18:30 +08:00
*/
2026-05-16 21:26:19 +08:00
async function handleCreateCall() {
showNotification('正在创建通话...');
2026-05-17 20:59:34 +08:00
//const connectionId = 'conn_' + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
const connectionId = randomMeetingId();
2026-05-16 21:26:19 +08:00
localStorage.setItem('connectionId', connectionId);
await switchToCallView(connectionId);
}
/**
* 绑定call视图DOM事件
*/
function bindCallViewDomEvents() {
2026-04-29 15:18:30 +08:00
// 切换侧边栏
window.toggleSidebar = function () {
chatMessage.toggleSidebar();
};
// 切换麦克风
window.toggleMute = function (button) {
const state = store.getState();
const currentState = state.session.localUser.mediaState.audio;
store.updateLocalMedia('audio', !currentState);
};
// 切换视频
window.toggleVideo = function (button) {
const state = store.getState();
const currentState = state.session.localUser.mediaState.video;
store.updateLocalMedia('video', !currentState);
};
// 切换本地视频(用于悬停控制)
window.toggleLocalVideo = function () {
window.toggleVideo();
};
// 切换录屏
window.toggleRecording = function (button) {
const state = store.getState();
const currentState = state.session.localUser.mediaState.recording || false;
store.updateLocalMedia('recording', !currentState);
// 显示录制状态通知
if (!currentState) {
showNotification('开始录制');
} else {
showNotification('停止录制');
}
};
// 更多选项菜单切换
window.toggleMoreOptions = function () {
const menu = document.getElementById('moreOptionsMenu');
if (menu) {
menu.classList.toggle('hidden');
}
};
// 切换视频分辨率
window.changeResolution = function (width, height) {
store.changeResolution(width, height);
// 关闭菜单
const menu = document.getElementById('moreOptionsMenu');
if (menu) {
menu.classList.add('hidden');
}
};
// 结束通话
window.endCall = function () {
// 显示确认对话框
document.getElementById('endCallDialog').classList.remove('hidden');
};
// 取消结束通话
window.cancelEndCall = function () {
document.getElementById('endCallDialog').classList.add('hidden');
};
// 确认结束通话
window.confirmEndCall = function () {
document.getElementById('endCallDialog').classList.add('hidden');
store.endCall();
showNotification('通话已结束');
};
// 绑定消息相关事件
chatMessage.bindMessageEvents();
// 键盘快捷键
document.addEventListener('keydown', (event) => {
// 空格键静音
if (event.code === 'Space' && !event.target.matches('input, textarea')) {
event.preventDefault();
window.toggleMute();
}
// Ctrl+V 切换视频
if (event.ctrlKey && event.key === 'v') {
event.preventDefault();
window.toggleVideo();
}
});
// 绑定对话框事件
2026-05-16 21:26:19 +08:00
const cancelEndCall = document.getElementById('cancelEndCall');
const confirmEndCall = document.getElementById('confirmEndCall');
if (cancelEndCall) cancelEndCall.addEventListener('click', window.cancelEndCall);
if (confirmEndCall) confirmEndCall.addEventListener('click', window.confirmEndCall);
2026-04-29 15:18:30 +08:00
// 更多选项按钮事件
const moreOptionsBtn = document.getElementById('moreOptionsBtn');
if (moreOptionsBtn) {
moreOptionsBtn.addEventListener('click', window.toggleMoreOptions);
}
// 点击外部关闭更多选项菜单
document.addEventListener('click', function(event) {
const moreOptionsMenu = document.getElementById('moreOptionsMenu');
const moreOptionsBtnEl = document.getElementById('moreOptionsBtn');
if (moreOptionsMenu && moreOptionsBtnEl &&
!moreOptionsMenu.contains(event.target) &&
!moreOptionsBtnEl.contains(event.target)) {
moreOptionsMenu.classList.add('hidden');
}
});
2026-05-18 21:18:55 +08:00
bindInviteDialogEvents();
2026-04-29 15:18:30 +08:00
}
2026-05-16 21:26:19 +08:00
// 页面加载完成后初始化SPA入口
2026-04-29 15:18:30 +08:00
window.addEventListener('DOMContentLoaded', async () => {
try {
2026-05-16 21:26:19 +08:00
// 显示connect视图隐藏call视图
const connectView = document.getElementById('connectView');
const callView = document.getElementById('callView');
if (connectView) connectView.classList.remove('hidden');
if (callView) callView.classList.add('hidden');
currentView = 'connect';
// 加载用户设置
loadUserSettings();
// 初始化WebSocket连接在connect视图就建立WebSocket
await initWebSocket();
// 绑定connect视图事件加入通话、创建通话等
bindConnectViewEvents(handleJoinCall, handleCreateCall);
2026-05-18 21:18:55 +08:00
bindInviteDialogEvents();
2026-05-16 21:26:19 +08:00
// 检查是否有保存的连接ID填入输入框
const savedConnectionId = localStorage.getItem('connectionId');
if (savedConnectionId) {
2026-05-18 21:18:55 +08:00
connectionId = savedConnectionId;
2026-05-16 21:26:19 +08:00
const connectionIdInput = document.getElementById('connectionIdInput');
if (connectionIdInput) connectionIdInput.value = savedConnectionId;
2026-04-29 15:18:30 +08:00
}
2026-05-18 21:18:55 +08:00
const invitePayload = getInvitePayloadFromUrl();
if (invitePayload) {
window.showCallRequest(invitePayload);
}
2026-05-16 21:26:19 +08:00
console.log('SPA initialized, showing connect view');
2026-04-29 15:18:30 +08:00
} catch (error) {
2026-05-16 21:26:19 +08:00
console.error('Error initializing SPA:', error);
2026-04-29 15:18:30 +08:00
showNotification('初始化失败,请刷新页面重试', 'error');
}
});
// 导出全局变量
export { store };