From 50532079cf08ecebc153f13007a012c17c63027b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=E6=98=B5=E7=A7=B0=E9=87=8D=E8=A6=81=E5=90=97O?= Date: Sat, 14 Mar 2026 22:54:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(meeting):=20=E4=BC=98=E5=8C=96=E4=BC=9A?= =?UTF-8?q?=E8=AE=AE=E6=88=BF=E9=97=B4=E5=AD=A6=E7=94=9F=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=8E=92=E5=BA=8F=E5=92=8C=E8=A7=86=E9=A2=91=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构学生列表排序逻辑,使用更高效的 map 映射和数组排序方法 - 移除冗余的用户遍历和映射操作,提升性能 - 在会议开始时确保获取学生信息列表,添加明确的注释标识 - 改进声网视频播放逻辑,实现立即播放和重试机制 - 添加视频播放失败时的重试逻辑,最多重试10次间隔100ms - 增强视频播放错误处理和调试信息输出 --- .../meeting-room/meeting-room-monitor.vue | 29 +++++++++---------- .../meeting/meeting-room/useAgoraMeeting.ts | 18 +++++++++--- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/views/meeting/meeting-room/meeting-room-monitor.vue b/src/views/meeting/meeting-room/meeting-room-monitor.vue index a80d407..6ecf769 100644 --- a/src/views/meeting/meeting-room/meeting-room-monitor.vue +++ b/src/views/meeting/meeting-room/meeting-room-monitor.vue @@ -177,24 +177,18 @@ // 按照 studentListForSort 中的顺序重新排列 if (studentListForSort.value.length > 0) { - // 创建 shortId -> user 的映射 - const userMap = new Map(); - filteredUsers.forEach((user) => { - userMap.set(Number(user.uid), user); + // 创建 shortId -> student 的映射 (用于排序) + const studentOrderMap = new Map(); + studentListForSort.value.forEach((student, index) => { + studentOrderMap.set(student.shortId, index); }); - // 按照 studentListForSort 的顺序重新排列 - const sortedUsers: typeof filteredUsers = []; - studentListForSort.value.forEach((student) => { - const user = userMap.get(student.shortId); - if (user) { - sortedUsers.push(user); - userMap.delete(student.shortId); - } + // 按照 studentListForSort 的顺序排序,但只包含实际存在的用户 + return [...filteredUsers].sort((a, b) => { + const aIndex = studentOrderMap.get(Number(a.uid)) ?? Number.MAX_SAFE_INTEGER; + const bIndex = studentOrderMap.get(Number(b.uid)) ?? Number.MAX_SAFE_INTEGER; + return aIndex - bIndex; }); - - // 添加 studentListForSort 中没有的用户 (新加入的学生) - return [...sortedUsers, ...Array.from(userMap.values())]; } return filteredUsers; @@ -371,7 +365,8 @@ if (classStatus.value === 'in_class') { console.log('[监控端] 课程已开始,初始化 Agora...'); await meeting.initAndJoin(roomData); - // 获取学生信息列表 + + // ✅ 获取学生信息列表 await fetchStudentList(); } else { console.log('[监控端] 等待老师上课...'); @@ -433,6 +428,8 @@ shortUid.value = roomData.shortUid; teacherUid.value = roomData.teacherUid; await meeting.initAndJoin(roomData); + + // ✅ 获取学生信息列表 await fetchStudentList(); console.log('[监控端] Agora 初始化完成'); } catch (error) { diff --git a/src/views/meeting/meeting-room/useAgoraMeeting.ts b/src/views/meeting/meeting-room/useAgoraMeeting.ts index 15d5201..ef2103b 100644 --- a/src/views/meeting/meeting-room/useAgoraMeeting.ts +++ b/src/views/meeting/meeting-room/useAgoraMeeting.ts @@ -225,9 +225,11 @@ export function useAgoraMeeting( */ const playRemoteVideo = (user: IAgoraRTCRemoteUser, playerId: string) => { console.log(`【声网】准备播放远程视频 ${playerId}:`, user.uid); - setTimeout(() => { + + // 立即尝试播放 + const tryPlay = (retryCount = 0) => { const playerDiv = document.getElementById(playerId); - console.log('【声网】视频播放元素:', playerDiv, 'videoTrack:', user.videoTrack); + console.log('【声网】视频播放元素:', playerDiv, 'videoTrack:', user.videoTrack, '重试次数:', retryCount); if (playerDiv && user.videoTrack) { try { user.videoTrack.play(playerDiv); @@ -236,9 +238,17 @@ export function useAgoraMeeting( console.warn('【声网】远程视频播放异常:', error); } } else { - console.warn('【声网】视频播放失败:元素或轨道不存在'); + // 如果元素不存在,延迟 100ms 重试,最多重试 10 次 + if (retryCount < 10) { + console.warn(`【声网】视频播放失败:元素或轨道不存在,100ms 后重试 (${retryCount + 1}/10)`); + setTimeout(() => tryPlay(retryCount + 1), 100); + } else { + console.error('【声网】视频播放失败:超过最大重试次数'); + } } - }, 100); + }; + + tryPlay(); }; client.value.on('user-published', async (user: IAgoraRTCRemoteUser, mediaType: 'audio' | 'video') => {