docs(phase2e-2): 同步 Task 10-12 + UI 打磨进度至 CURRENT_STATUS / 实施计划 / project-context

- CURRENT_STATUS.md:
  * 头部"最后更新"升级到 2026-04-22
  * 新增完整段落记录 Task 10-12 + 一轮深度 UI 打磨
    (uni-button ::after 全视口遮罩 / toolbar z-index 提升 /
    面板 toggle / 全局 H5 容器铺满 / 静默 stale 清理 /
    视频 HD / 会议聊天真实昵称)
  * 附 Playwright 验证结论与相关 commit 列表

- 2026-04-21-phase2e-2-implementation.plan.md:
  * 顶部状态改为"代码开发中(Task 0-12  / Task 13-16 待执行)"
  * 新增 16 行进度看板表格 + 2026-04-22 UI 打磨专项要点
  * Task 10/11/12 header 标注  完成日期

- .cursor/rules/project-context.mdc:
  * 当前进度条目更新为"Task 0-12 "
  * 新增 Task 10-12 + UI 打磨的独立条目
    完整收录三轮攻坚(uni-button 遮罩两次 + z-index +
    全局容器 + stale 静默 + HD + toggle)的技术细节

Made-with: Cursor
This commit is contained in:
bujinyuan
2026-04-22 16:45:56 +08:00
parent cacf4ae074
commit d218b84843
3 changed files with 127 additions and 8 deletions

View File

@@ -1,11 +1,47 @@
# Phase 2e-2 实施计划:会议 MVP多人音视频
> **状态:** 📋 待执行(设计文档定稿后进入代码开发
> **状态:** 🚧 代码开发中Task 0-12 ✅ / Task 13-16 待执行
> **设计文档:** [Phase 2e-2 设计文档](./2026-04-21-phase2e-2-design.md)
> **上级路线图:** [Phase 2e 整体路线图](./2026-04-20-phase2e-design.md)
> **分支:** `feature/phase2e-2-meeting-mvp`
> **预估总工时:** **约 17 人日**17 个 Task含 PoC 与 UI 打磨)
> **最后更新:** 2026-04-21Task 0-8已落地,会议生命周期状态机 E2E 20/20 PASS下一步 Task 9 前端 mediasoup-client 接入
> **最后更新:** 2026-04-22Task 10-12前端会议 UI 主链路打通;叠加一轮深度 UI 打磨uni-button ::after 全视口遮罩修复、toolbar z-index 提升、面板 toggle、视频 HD、静默 stale 清理。下一步 Task 13 主持人权限全链路
### 进度看板
| Task | 标题 | 状态 | 说明 |
|---|---|---|---|
| Task 0 | mediasoup PoC Spike | ✅ | 2026-04-21 完成 |
| Task 1 | media-server 骨架 | ✅ | Fastify 5 |
| Task 2 | Node 9 个 REST API | ✅ | Router/Transport/Producer/Consumer |
| Task 3 | 数据库 DDL + DAO | ✅ | 3 张表 + 9 索引 |
| Task 4 | Go meeting 骨架 | ✅ | 12 路由 + Wire |
| Task 5 | 会议 REST 接口 | ✅ | 12 接口全量业务 |
| Task 6 | WS 信令处理器 | ✅ | 13 事件 |
| Task 7 | Go↔Node HTTP Client | ✅ | HTTPMediaOrchestrator |
| Task 8 | 生命周期状态机 | ✅ | E2E 20/20 PASS |
| Task 9 | 前端 mediasoup + Store | ✅ | REST/WS/媒体三链路 |
| **Task 10** | **前端预览/创建/加入页** | ✅ | `create.vue` / `join.vue` / `preview.vue` + Hub `index.vue` |
| **Task 11** | **会议室主页 + 核心组件** | ✅ | `room.vue` + VideoGrid/VideoTile/Toolbar/MemberPanel/InviteDialog |
| **Task 12** | **会议内聊天面板** | ✅ | `ChatPanel.vue` + WS `meeting.chat.new` + user_name/avatar 补齐 |
| Task 13 | meeting_invite 通知对接 | ⏳ | 下一步 |
| Task 14 | docker-compose + 双态 | ⏳ | |
| Task 15 | 观测性与告警 | ⏳ | |
| Task 16 | E2E + 文档同步 | ⏳ | |
### 2026-04-22 UI 打磨专项Task 10-12 之后的体验收敛)
这一轮不属于新 Task是对已落地页面的深度打磨统一记录在 CURRENT_STATUS.md 对应段落,要点速览:
1. **uni-button `::after` 全视口遮罩(两处)**
- MeetingToolbar`.btn::after { content:none }` + `.btn { position:relative }` 解除"离开按钮吃掉所有兄弟按钮点击"
- ChatPanel`.btn-send::after { content:none; display:none }` 解除因 `all:unset` 导致 `::after` 回溯到 body 形成全屏遮罩
2. **toolbar z-index 提升至 210**:覆盖 MemberPanel/InviteDialog 的 `.panel-root` (z=200) mask保证抽屉打开时按钮仍可点击 + toggle。
3. **成员/邀请/聊天按钮 toggle**`openMembers/openInvite/openChat` 全部改为取反切换,符合用户"再次点击关闭"的直觉。
4. **H5 全局容器铺满视口**`App.vue``html/body/#app/uni-app/uni-page*` 全部 `width/height: 100%`,修复"整体偏左上角"。
5. **刷新后残留会议的静默清理**`cleanupStaleMeetings` + `joinAndEnter/createAndEnter` 首次静默 + 自动重试;`leaveRoom({silent:true})` 抑制"你不在此会议中"toast。
6. **设备预览 ↔ 会议内同分辨率**:统一 1280×720 / 24-30fps。
7. **会议聊天显示真实昵称**:后端 `ResolveUsersDisplay` 批量补齐 `user_name` / `user_avatar`,前端 ChatPanel 显示昵称而非"用户 54"。
---
@@ -413,7 +449,7 @@ flowchart LR
- 关闭标签后另一端 1 秒内收到 `meeting.member.left`
- **工作量****1.5 人日**
### Task 10前端设备预览页 + 创建页 + 加入页
### Task 10前端设备预览页 + 创建页 + 加入页2026-04-21/22 完成)
- **目标**完成 `/pages/meeting/{create,join,preview}.vue` 3 个页面
- **依赖**T5
@@ -432,7 +468,7 @@ flowchart LR
- 权限被拒绝时给出清晰引导
- **工作量****1 人日**
### Task 11前端会议室主页视频网格 + 工具栏 + 成员面板 + 响应式)
### Task 11前端会议室主页视频网格 + 工具栏 + 成员面板 + 响应式)2026-04-21/22 完成,含一轮 UI 深度打磨)
- **目标**实现 `/pages/meeting/room.vue` + 6 个主要组件
- **依赖**T9
@@ -450,7 +486,7 @@ flowchart LR
- 手机浏览器单列主画面 + 缩略抽屉工作正常
- **工作量****2 人日**
### Task 12会议内聊天面板
### Task 12会议内聊天面板2026-04-21/22 完成)
- **目标**实现 `ChatPanel.vue` + 后端 `meeting_chats` 相关接口
- **依赖**T11

View File

@@ -1,7 +1,7 @@
# EchoChat 项目开发进度
> **最后更新**2026-04-21Phase 2e-2 Task 9 前端 mediasoup-client + Pinia Store 落地REST/WS/媒体三链路打通,`npm run build:h5` 通过
> **当前阶段**Phase 2e-2 会议 MVP **代码开发阶段** 🚧Task 0-9 ✅ / Task 10-16 待执行)
> **最后更新**2026-04-22Phase 2e-2 Task 10-12 前端会议 UI 主链路全部落地 + uni-button H5 遮罩深度修复 + 面板 toggle 交互打磨
> **当前阶段**Phase 2e-2 会议 MVP **代码开发阶段** 🚧Task 0-12 ✅ / Task 13-16 待执行)
> **当前分支**`feature/phase2e-2-meeting-mvp`(从 `feature/phase2c-group-read-receipt` 衍生)
> **Phase 2e 整体设计**`docs/plans/2026-04-20-phase2e-design.md`(三子阶段路线图 + 后续规划清单)
> **Phase 2e-1 专用设计**`docs/plans/2026-04-20-phase2e-1-design.md`(✅ 已完成)
@@ -170,6 +170,88 @@
---
## 🎯 2026-04-22 Phase 2e-2 Task 10-12 + UI 打磨:会议 MVP 前端主链路全部打通
**交付**Task 10创建/加入/设备预览三页、Task 11会议室主页 + 核心组件、Task 12会议内聊天面板顺序落地叠加一轮深度 UI 打磨,解决了 uni-app H5 `<uni-button>` 点击遮罩、全屏面板 z-index 覆盖、刷新后"残留会议"提示、视频清晰度、面板 toggle 交互等一整串体验问题,现前端 → REST → WS → 媒体 → 渲染 → 内置聊天链路全部可用。
### 产出文件(本轮新建 / 改动要点)
| 文件 | 角色 | 作用 |
|---|---|---|
| `frontend/src/pages/meeting/create.vue` (新) | Task 10 | 立即/预约创建表单,校验 + 跳转 preview |
| `frontend/src/pages/meeting/join.vue` (新) | Task 10 | 会议号/密码输入 + 识别 `xxx-yyy-zzz` 格式 |
| `frontend/src/pages/meeting/preview.vue` (新/改) | Task 10 + UI | 设备预览 + 默认启用开关;`getUserMedia` 升级到 1280x720 / 24-30fps和会议内同分辨率统一 |
| `frontend/src/pages/meeting/index.vue` (重写) | UI 打磨 | 从"功能开发中"占位改为 **会议 Hub**:即时创建 + 加入会议双入口卡片 |
| `frontend/src/pages/meeting/room.vue` (新/多轮改) | Task 11 + UI | 视频网格 + 顶部栏 + Toolbar + 抽屉聊天 + 离会弹窗;修复 z-index/刷新/toggle/输入遮挡等 5 个子问题 |
| `frontend/src/components/meeting/MeetingToolbar.vue` (新/改) | Task 11 + UI | 6 个工具按钮;**`.btn::after` 禁用修复点击穿透**`z-index: 210` 浮在成员面板 mask 之上 |
| `frontend/src/components/meeting/VideoGrid.vue` / `VideoTile.vue` (新) | Task 11 | 自适应 1/2/3-4/5-9/10+ 网格 + 本地/远端 tile + 主持人徽章 |
| `frontend/src/components/meeting/MemberPanel.vue` (新) | Task 11 | 右侧抽屉成员列表 + 踢出/转让菜单 |
| `frontend/src/components/meeting/InviteDialog.vue` (新) | Task 11 | 会议号/密码/邀请链接复制 |
| `frontend/src/components/meeting/ChatPanel.vue` (新/多轮改) | Task 12 + UI | 聊天抽屉 → 侧边栏布局,消息流 + 头像聚合 + 懒加载更多;**`.btn-send::after` 彻底 `content:none`** 解决关闭/输入/发送全部被遮挡 |
| `frontend/src/store/meeting.js` (改) | Task 10-12 + UI | 新增 `cleanupStaleMeetings`(静默清理)+ `createAndEnter`/`joinAndEnter` 自动重试 + 视频约束 HD |
| `frontend/src/api/meeting.js` (改) | UI | `createRoom`/`joinRoom`/`leaveRoom` 支持 `options.silent` 透传 |
| `frontend/src/utils/request.js` (改) | UI | 请求层新增 `silent` 选项抑制 toast给 stale 清理等场景用 |
| `frontend/src/App.vue` (改) | UI | H5 全局 CSS`html/body/#app/uni-app/uni-page/uni-page-body` 均 100% 宽高,修复"整体布局偏左上" |
| `backend/go-service/app/meeting/service/meeting_service.go` (改) | UI/Task 12 | `UserDisplayInfo` + `resolveUserDisplay``SendChatMessage` WS 载荷带 `user_name`/`user_avatar` |
| `backend/go-service/app/meeting/controller/meeting_controller.go` (改) | UI/Task 12 | `chatToDTO` 支持 `userMap``SendChat`/`ListChats``ResolveUsersDisplay` |
| `backend/go-service/app/dto/meeting_dto.go` (改) | UI/Task 12 | `MeetingChatDTO` 新增 `UserName` / `UserAvatar` |
### 核心技术决策与攻坚点
1. **uni-app H5 `<uni-button>::after` 点击遮罩**(两轮):
- **第一轮(工具栏)**:原生 `<button>` 被 uni-app 编译为 `<uni-button>`,自动注入 `::after { content:" "; position:absolute; inset:0 -1200px -80px 0 }` 作为点击反馈遮罩2400×160。在 MeetingToolbar 里,最后一个"离开"按钮的 `::after` **横跨整个 toolbar 并 DOM 顺序最上**,导致所有按钮的中心点命中检测都落在"离开"按钮上,表现为"除了离开按钮其他全都点不响应"、"离开弹窗的取消也触发结束会议"。修复:`.btn { position: relative } .btn::after { content: none; display: none }`,同步给 `.leave-btn::after` 加防御。
- **第二轮(聊天面板)**`.btn-send { all: unset }``position` 重置为 `static`,导致 `::after``absolute` 定位沿 DOM 树回溯到 `<body>` 作为 containing block`inset: 0 -1200px -80px 0` 直接形成**覆盖整个视口并向右下溢出的超级遮罩**,关闭按钮 / 输入框 / 发送按钮全部被挡。修复:把原本只 `border: none``.btn-send::after` 升级为 `content: none; display: none`
2. **面板 z-index 冲突**`MemberPanel` / `InviteDialog``.panel-root``position:fixed; inset:0; z-index:200` 的全屏 mask。面板打开时把底部 toolbar 整个遮掉,用户再次点击"成员/邀请"按钮,命中的是 mask 而非按钮toggle 逻辑永远走不到。**修复:`.toolbar { z-index: 210 }`**,使得抽屉打开时 toolbar 浮在 mask 之上(仍低于 `.leave-mask` 的 220同时 `openMembers` / `openInvite` 改为 toggle`openChat` 行为对齐。
3. **`uni-app` 全局容器偏左上**:桌面大窗口下 `uni-app` / `uni-page` 祖先默认不 100% 拉伸,导致 `position: fixed; inset: 0``.room` 相对于偏小的祖先盒子定位,出现"左上角一小块"的 bug。修复`App.vue``/* #ifdef H5 */` 块统一给 `html, body, #app, uni-app, uni-page*` 全部 `width/height: 100%`,并给 `.room``100vw / 100vh / z-index: 1000` 作为二道防御。
4. **刷新后"残留会议"体验**
- `joinAndEnter` / `createAndEnter` 包 try/catch首次调用走 `silent: true`(不弹 toast若后端返回 `staleMeetingHint` 类错误则先调 `cleanupStaleMeetings()` → 再重试一次。
- `cleanupStaleMeetings` 内部调 `meetingApi.leaveRoom({ silent: true })`,把 `400: 你不在此会议中` 这类预期错误静默掉。
- 用户路径:刷新 → 回到 Hub → 再次 Join/Create → 不再看到"你已在其他会议中"或"你不在当前会议中"。
5. **预览/会议内视频画质一致性**`preview.vue``store/meeting.js#startLocalVideo` 原本用 640×480 → 统一改为 `width:{ideal:1280} height:{ideal:720} frameRate:{ideal:24,max:30}`,设备预览看到什么画质,入会后就是什么画质。
6. **会议内聊天**:后端 `SendChatMessage` WS 广播 + REST 列表均通过 `ResolveUsersDisplay` 批量补齐 `user_name/user_avatar`,前端 ChatPanel 显示真实昵称而非"用户 54"`ChatPanel` 由父 `room.vue` 通过 props 受控,消息分组聚合头像,滚动位置保持策略区分"用户上拉中 / 自动贴底"。
### Playwright 验证
- `MeetingToolbar` 每个按钮 `elementFromPoint(center) === 自身``hitSelf=true`)✅
- 离会弹窗"取消" `hitSelf=true`,点击后 `.leave-mask` 消失URL 不跳转 ✅
- 聊天面板关闭按钮、textarea、发送按钮 `hitSelf=true`
- 成员按钮两次点击 → 面板打开 → 面板关闭 ✅
- 聊天按钮 toggle、邀请按钮 toggle 同样生效 ✅
### 已知待改进项
1. **Task 13 管理员权限全链路**(主持人静音他人 / 踢出 / 转让 / 结束)仍需专项 E2E。
2. **Task 14 通知中心邀请接入**:收到 `meeting_invite` notification 直接跳转 Join 页面,待落地。
3. **Task 15 统一观测性**:会议内 RTC 状态、WS 重连、媒体 rtp 状态尚无 dashboard。
4. **Task 16 E2E**Playwright 回归脚本需补 "两用户跨 tab 互看 + 内置聊天 + 主持人操作" 全景脚本。
### 相关提交
```
cacf4ae fix(meeting): 提升 toolbar z-index 确保成员/邀请面板开启时仍可点击
a311c03 fix(meeting): 聊天面板点击失效 & 成员/邀请按钮支持 toggle
3aa8174 fix(meeting): 抹除 uni-button ::after 遮罩修复工具栏点击失效
ff46dc5 fix(phase2e-2): 视频 HD 分辨率 + toolbar 防溢出 + 聊天按钮 toggle
ce09315 feat(phase2e-2): 会议首页落地 "创建 / 加入" 双入口
c529ff4 fix(phase2e-2): 全局 H5 容器铺满视口 + 静默自动清理 stale 会议
0c9f048 fix(phase2e-2): 修复刷新后重入会失败 + 聊天输入区布局防御
16225c4 fix(phase2e-2): 会议内聊天面板 UI 布局优化
1222bf5 feat(phase2e-2): 会议内聊天面板落地Task 12
59f824a feat(phase2e-2): 会议室主页与核心 UI 组件落地Task 11
eb3857a feat(phase2e-2): 前端创建/加入/设备预览 3 页落地Task 10
```
### 下一步
进入 **Task 13主持人权限全链路**(静音他人 / 移除 / 转让 / 结束),前端 MemberPanel 已铺好行尾菜单,后端 REST/WS 事件已就绪,本 Task 聚焦前后端握手 + E2E。
---
## 🎯 2026-04-21 Phase 2e-2 Task 9 前端 mediasoup-client + Pinia Store 落地
**交付**:前端新增 5 个模块(`constants/meeting.js` / `api/meeting.js` / `services/websocket.js``sendWithAck` 扩展 / `utils/mediasoup-client.js` / `store/meeting.js`+ 1 个临时调试页(`pages/meeting/debug.vue`),把 REST12 接口)/ WebSocket14 事件)/ mediasoup 媒体三链路全部汇聚到 Pinia Store 对外提供 ~20 个 action后端补齐 `meeting.consume.resume` WS 事件 + `RouterRtpCapabilities` 透传到 REST 响应;`npm run build:h5` 通过(无本次新增 warning