From ff46dc5f7614b64f25e38706c5e5848628aaf07f Mon Sep 17 00:00:00 2001 From: bujinyuan Date: Wed, 22 Apr 2026 16:13:25 +0800 Subject: [PATCH] =?UTF-8?q?fix(phase2e-2):=20=E8=A7=86=E9=A2=91=20HD=20?= =?UTF-8?q?=E5=88=86=E8=BE=A8=E7=8E=87=20+=20toolbar=20=E9=98=B2=E6=BA=A2?= =?UTF-8?q?=E5=87=BA=20+=20=E8=81=8A=E5=A4=A9=E6=8C=89=E9=92=AE=20toggle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题 1. 进入会议后视频比预览页更"近、更糊" · 预览 / startLocalVideo 均固定 640x480,mediasoup 视频轨清晰度偏低 · 进房后 videoTile cover 裁切在大画布更明显 → 观感"放大" 2. 会议内聊天 / 邀请 / 成员按钮"点击无反应" · 核心:.body flex 子内容过高时 toolbar 未固定收缩,被挤出视口 下方 (y > vh),用户点击位置在屏幕外 · 次要:openChat 仅 set true,已打开状态下再次点击无视觉反馈 3. 聊天按钮无法关闭面板:只有面板内 × 按钮能关 修复 - store/meeting.js startLocalVideo + preview.vue getUserMedia 统一 改为 ideal 1280x720 + frameRate ideal 24 / max 30,浏览器在设备不 支持时自动降级;进房与预览视觉表现一致 - components/meeting/MeetingToolbar.vue .toolbar 加 flex-shrink:0 + position:relative + z-index:15,保证 toolbar 永远贴底不被 body 压缩,且点击层级高于 ChatPanel 背景 - pages/meeting/room.vue .top-bar 加 flex-shrink:0,避免 body 溢出 时顶栏压缩引发整体错位 - pages/meeting/room.vue openChat 改 toggle:已打开则关闭,未打开则 展开并 markChatsRead,交互更符合直觉 验证(Playwright 1024x576) - 预览 getVideoTracks()[0].getSettings() → 1280x720 / 24fps ✓ - 进房后 localVideo settings 同样 1280x720 ✓ - 聊天按钮 boundingRect y=505 bottom=567 ≤ vh 576,inViewport=true ✓ - 点击聊天 → chat-col.open=true 宽度 320.5px;再点击 → open=false ✓ - 截图 room-hd-chat-open.png:视频清晰、聊天面板展开、toolbar 贴底 Made-with: Cursor --- frontend/src/components/meeting/MeetingToolbar.vue | 5 +++++ frontend/src/pages/meeting/preview.vue | 4 ++-- frontend/src/pages/meeting/room.vue | 6 ++++++ frontend/src/store/meeting.js | 6 ++++-- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/meeting/MeetingToolbar.vue b/frontend/src/components/meeting/MeetingToolbar.vue index 9337b97..03a6fe0 100644 --- a/frontend/src/components/meeting/MeetingToolbar.vue +++ b/frontend/src/components/meeting/MeetingToolbar.vue @@ -123,6 +123,11 @@ const emitIf = (name) => { background: rgba(17, 24, 39, 0.88); backdrop-filter: blur(16px); border-top: 1rpx solid rgba(255, 255, 255, 0.08); + /* flex-shrink:0 保证 body 内容高度过大时不会把 toolbar 挤出视口; + position:relative + z-index 提升按钮点击层级,避免 ChatPanel 遮挡 */ + flex-shrink: 0; + position: relative; + z-index: 15; } .btn { diff --git a/frontend/src/pages/meeting/preview.vue b/frontend/src/pages/meeting/preview.vue index a0dfd0d..f1b953e 100644 --- a/frontend/src/pages/meeting/preview.vue +++ b/frontend/src/pages/meeting/preview.vue @@ -197,8 +197,8 @@ const startPreview = async () => { const constraints = { audio: selectedAudioId.value ? { deviceId: { exact: selectedAudioId.value } } : true, video: selectedVideoId.value - ? { deviceId: { exact: selectedVideoId.value }, width: 640, height: 480 } - : { width: 640, height: 480 } + ? { deviceId: { exact: selectedVideoId.value }, width: { ideal: 1280 }, height: { ideal: 720 }, frameRate: { ideal: 24, max: 30 } } + : { width: { ideal: 1280 }, height: { ideal: 720 }, frameRate: { ideal: 24, max: 30 } } } previewStream = await navigator.mediaDevices.getUserMedia(constraints) hasPermission.value = true diff --git a/frontend/src/pages/meeting/room.vue b/frontend/src/pages/meeting/room.vue index b93e42f..bd5cf7d 100644 --- a/frontend/src/pages/meeting/room.vue +++ b/frontend/src/pages/meeting/room.vue @@ -379,6 +379,11 @@ const onCamToggle = async () => { const openInvite = () => { inviteVisible.value = true } const openMembers = () => { memberVisible.value = true } const openChat = () => { + // 点击工具栏聊天按钮时进行切换:已打开 → 关闭;未打开 → 打开并标记已读 + if (chatVisible.value) { + chatVisible.value = false + return + } chatVisible.value = true meetingStore.markChatsRead() } @@ -555,6 +560,7 @@ onUnload(() => { background: linear-gradient(to bottom, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0)); position: relative; z-index: 5; + flex-shrink: 0; } .top-left { diff --git a/frontend/src/store/meeting.js b/frontend/src/store/meeting.js index 8399baf..00ec01f 100644 --- a/frontend/src/store/meeting.js +++ b/frontend/src/store/meeting.js @@ -648,9 +648,11 @@ export const useMeetingStore = defineStore('meeting', () => { const startLocalVideo = async (deviceId) => { if (!_engine) throw new Error('未连接') if (localProducers.video) return + // 与预览页保持一致的 HD 分辨率(ideal 1280x720,允许浏览器在设备不支持时降级) const videoConstraints = { - width: 640, - height: 480, + width: { ideal: 1280 }, + height: { ideal: 720 }, + frameRate: { ideal: 24, max: 30 }, ...(deviceId ? { deviceId: { exact: deviceId } } : {}) } const stream = await navigator.mediaDevices.getUserMedia({ video: videoConstraints })