feat(phase2e-2): 会议室主页与核心 UI 组件落地(Task 11)
新增页面: - pages/meeting/room.vue:会议主容器,组装 VideoGrid/Toolbar/MemberPanel/InviteDialog * 顶部条:标题/会议号/复制、连接状态 pill、网络徽标、计时器 * 主区:按成员数自适应网格渲染 VideoTile * 底部:麦/摄/邀请/成员/聊天/挂断工具条 * 离会确认弹窗:主持人可选"结束会议 / 仅自己离开" * onUnload 兜底调用 leave 避免脏状态残留 新增组件(components/meeting/): - VideoTile.vue:原生 video/audio 挂载(H5)+ 名字/静音/主持人/说话者边框 - VideoGrid.vue:1/2/3-4/5-9/10+ 响应式 CSS Grid 布局 - MeetingToolbar.vue:6 按钮工具条,loading 态 + 徽标 - MemberPanel.vue:右侧滑入抽屉,主持人可转让/踢出 - InviteDialog.vue:居中弹窗,一键复制会议号/链接/邀请文案 - NetworkBadge.vue:4 格信号柱,level 0-4 分色 配套改动: - preview.vue:入会成功后跳 /pages/meeting/room?code=xxx(原先指向 debug) - pages.json:注册 room 路由,navigationStyle=custom 隐藏默认导航 - store/meeting.js:remoteConsumers 外层 slot 解除 markRaw,使 slot.audio/slot.video 赋值能驱动 VideoTile 响应式重渲染 验证:Playwright E2E 完成 create → preview → room 全链路 - 视频块、会议号、连接状态、计时器、工具条渲染正确 - 邀请弹窗、成员抽屉、静音切换、离会确认均工作正常 Made-with: Cursor
This commit is contained in:
@@ -306,11 +306,13 @@ export const useMeetingStore = defineStore('meeting', () => {
|
||||
try {
|
||||
const consumer = await _engine.consume({ producerId: data.producer_id })
|
||||
if (!remoteConsumers[data.user_id]) {
|
||||
remoteConsumers[data.user_id] = markRaw({
|
||||
// 外层 slot 保持 reactive 以便 slot.audio/slot.video 赋值能驱动 VideoTile 重渲染;
|
||||
// 仅 Consumer 实例和 Set 本身用 markRaw 隔离 Vue 代理
|
||||
remoteConsumers[data.user_id] = {
|
||||
audio: null,
|
||||
video: null,
|
||||
producerIds: new Set()
|
||||
})
|
||||
producerIds: markRaw(new Set())
|
||||
}
|
||||
}
|
||||
const slot = remoteConsumers[data.user_id]
|
||||
slot[consumer.kind] = markRaw(consumer)
|
||||
|
||||
Reference in New Issue
Block a user