fix(phase2e-2): 视频 HD 分辨率 + toolbar 防溢出 + 聊天按钮 toggle
问题
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
This commit is contained in:
@@ -123,6 +123,11 @@ const emitIf = (name) => {
|
|||||||
background: rgba(17, 24, 39, 0.88);
|
background: rgba(17, 24, 39, 0.88);
|
||||||
backdrop-filter: blur(16px);
|
backdrop-filter: blur(16px);
|
||||||
border-top: 1rpx solid rgba(255, 255, 255, 0.08);
|
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 {
|
.btn {
|
||||||
|
|||||||
@@ -197,8 +197,8 @@ const startPreview = async () => {
|
|||||||
const constraints = {
|
const constraints = {
|
||||||
audio: selectedAudioId.value ? { deviceId: { exact: selectedAudioId.value } } : true,
|
audio: selectedAudioId.value ? { deviceId: { exact: selectedAudioId.value } } : true,
|
||||||
video: selectedVideoId.value
|
video: selectedVideoId.value
|
||||||
? { deviceId: { exact: selectedVideoId.value }, width: 640, height: 480 }
|
? { deviceId: { exact: selectedVideoId.value }, width: { ideal: 1280 }, height: { ideal: 720 }, frameRate: { ideal: 24, max: 30 } }
|
||||||
: { width: 640, height: 480 }
|
: { width: { ideal: 1280 }, height: { ideal: 720 }, frameRate: { ideal: 24, max: 30 } }
|
||||||
}
|
}
|
||||||
previewStream = await navigator.mediaDevices.getUserMedia(constraints)
|
previewStream = await navigator.mediaDevices.getUserMedia(constraints)
|
||||||
hasPermission.value = true
|
hasPermission.value = true
|
||||||
|
|||||||
@@ -379,6 +379,11 @@ const onCamToggle = async () => {
|
|||||||
const openInvite = () => { inviteVisible.value = true }
|
const openInvite = () => { inviteVisible.value = true }
|
||||||
const openMembers = () => { memberVisible.value = true }
|
const openMembers = () => { memberVisible.value = true }
|
||||||
const openChat = () => {
|
const openChat = () => {
|
||||||
|
// 点击工具栏聊天按钮时进行切换:已打开 → 关闭;未打开 → 打开并标记已读
|
||||||
|
if (chatVisible.value) {
|
||||||
|
chatVisible.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
chatVisible.value = true
|
chatVisible.value = true
|
||||||
meetingStore.markChatsRead()
|
meetingStore.markChatsRead()
|
||||||
}
|
}
|
||||||
@@ -555,6 +560,7 @@ onUnload(() => {
|
|||||||
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0));
|
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0));
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-left {
|
.top-left {
|
||||||
|
|||||||
@@ -648,9 +648,11 @@ export const useMeetingStore = defineStore('meeting', () => {
|
|||||||
const startLocalVideo = async (deviceId) => {
|
const startLocalVideo = async (deviceId) => {
|
||||||
if (!_engine) throw new Error('未连接')
|
if (!_engine) throw new Error('未连接')
|
||||||
if (localProducers.video) return
|
if (localProducers.video) return
|
||||||
|
// 与预览页保持一致的 HD 分辨率(ideal 1280x720,允许浏览器在设备不支持时降级)
|
||||||
const videoConstraints = {
|
const videoConstraints = {
|
||||||
width: 640,
|
width: { ideal: 1280 },
|
||||||
height: 480,
|
height: { ideal: 720 },
|
||||||
|
frameRate: { ideal: 24, max: 30 },
|
||||||
...(deviceId ? { deviceId: { exact: deviceId } } : {})
|
...(deviceId ? { deviceId: { exact: deviceId } } : {})
|
||||||
}
|
}
|
||||||
const stream = await navigator.mediaDevices.getUserMedia({ video: videoConstraints })
|
const stream = await navigator.mediaDevices.getUserMedia({ video: videoConstraints })
|
||||||
|
|||||||
Reference in New Issue
Block a user