duoaohui
|
2410f5e2e9
|
运营数据
|
2026-06-06 11:18:31 +08:00 |
|
duoaohui
|
cae3876d8b
|
电话咨询
|
2026-06-04 15:52:22 +08:00 |
|
duoaohui
|
3ffdaa30d9
|
电话咨询
|
2026-06-04 14:58:03 +08:00 |
|
duoaohui
|
46afcfe350
|
电话咨询
|
2026-06-04 12:26:22 +08:00 |
|
duoaohui
|
3b51aba8ec
|
电话咨询
|
2026-06-04 12:23:14 +08:00 |
|
duoaohui
|
96fca438f4
|
视频连线
|
2026-05-28 10:15:07 +08:00 |
|
duoaohui
|
a3f19c6245
|
视频连线
|
2026-05-27 15:04:50 +08:00 |
|
duoaohui
|
db7ea0b44a
|
视频连线
|
2026-05-27 14:38:55 +08:00 |
|
duoaohui
|
ac8ec4c903
|
视频会议保存
|
2026-05-18 19:42:55 +08:00 |
|
bujinyuan
|
c35097a0d8
|
fix(meeting): Task 16 修复 code-reviewer 审计 P2 七项 + Nit 七项
覆盖 Phase 2e-2 代码审查报告(docs/reviews/2026-04-23-phase2e-2-code-review.md)
P2/Nit 收尾批次,均在本仓库完成闭环;剩余 5 项登记推迟至 Phase 2f/3。
===== P2 七项 =====
- P2-1 cleanupUserResources 补 transport 清理
· media-server 新增 DELETE /internal/v1/transports/:id + transport.service.closeTransport
· Go MediaOrchestrator 接口新增 CloseTransport;HTTP 实现按 doCloseRequest 走 4xx 幂等 + 指数退避
· meeting_signal_service.cleanupUserResources 新增 "transport:<id>" 分支
- P2-2 preview.vue 快速切设备竞态
· previewSeq 序号 + nextTick 后 stale 判断,丢弃过期结果
· onVideoChange/onAudioChange 走 scheduleRestartPreview 200ms 防抖
· onBeforeUnmount 清理 changeDebounceTimer
- P2-3 room.vue onLoad redirectTo 后补 return
· 引入 redirectingToJoin 守卫,跳转页不再执行 onMounted 初始化
- P2-6 generateUniqueRoomCode 重试上限监控
· 重试后成功:Warn 日志(码空间健康度告警)
· 重试耗尽:Error 日志 + ErrRoomCodeConflict
· 修正 logs.Error 调用签名(去掉多余的 nil)
- P2-7 SendChatMessage 服务端长度 + 频率限制
· 新增 ErrChatContentEmpty / ErrChatContentTooLong / ErrChatRateLimited
· utf8.RuneCountInString 校验 500 字符上限
· Redis INCR + EXPIRE 滑动窗口(30 条/60s,首次写入 EXPIRE 兜底)
· controller.handleError 映射为 HTTP 400
- P2-8 MEETING_ENDED_REASON_LABEL 覆盖复核
· 新增前端专属常量 MEETING_ENDED_REASON_KICKED + 文案
· store/meeting.js _onMemberKicked 使用常量
· 同步修复后端 OnWSDisconnect 硬编码 "ws_disconnect" → constants.MeetingLeftReasonDisconnect
- P2 已修 P2-1/2/3/6/7/8;P2-4(WS token 迁出 URL query)与 P2-5(Chat 服务拆分)登记推迟
===== Nit 七项 =====
- Nit: kind:id 解析改用 strings.SplitN
· cleanupUserResources / pushExistingRoomState 两处同步
- Nit: resourceTTL 中央化
· 新增 constants.MeetingResourceTrackTTLSeconds(3600)
· meeting_signal_service.go resourceTTL 由 const 改 var 并引用常量
- Nit: ws/handler.go CheckOrigin 白名单
· NewHandler 新增 serverCfg 依赖;checkOrigin 支持同源放行 / dev 模式放行 / release 模式白名单严格匹配
· config.ServerConfig 新增 WSAllowedOrigins(逗号分隔)+ AllowedOrigins() / IsRelease() 辅助方法
· provider.go 新增 provideServerConfig,wire_gen.go 同步
- Nit: http_media_orchestrator.go 超时 + CreateRouter 重试
· 默认 TimeoutMS 5000→10000ms 兼容 Worker 冷启动
· 新增 CreateRouterRetry(默认 1 次,300ms 退避),仅对非 404 错误重试
· config.dev.yaml / config.docker.yaml 同步写入显式配置
- Nit: deploy-public.sh REDIS_PASSWORD × redis.conf 联动校验
· 检测 REDIS_PASSWORD 与 redis.conf 的 requirepass 配对一致性
· redis.conf 增加公网部署 requirepass 使用说明
- Nit: media-server internal-auth isPrivatePath 按 path 匹配
· 剔除 query/hash 后再与白名单 startsWith,避免 "?" 语义混淆
- Nit: mediasoup-client.js in-flight 锁走读确认
· finally 分支已覆盖 resolve/reject 两路,追加注释强化语义
- Nit 走读复核:_onMemberLeft 整槽关闭 vs _onProducerNew(closed=true) 精确匹配 producerId
· 粒度正确,无需改动(登记结论)
===== 构建验证 =====
- go vet ./... / go build ./... 通过
- frontend npm run build:h5 通过(仅 uni-app legacy warning,无 error)
- media-server npx tsc --noEmit 通过
===== 审查追踪小节 =====
docs/reviews/2026-04-23-phase2e-2-code-review.md 追加 "Task 16 修复追踪(2026-04-24 更新)":
- 已修复一览(本批次 14 处 + 历次 commit cdaa39d / ea2bf96 / f5ae095 / 5ed14c2)
- 推迟登记表(P2-4 / P2-5 / 端口收敛 / appData 校验 / RFC3339 时间格式,共 5 项)
Made-with: Cursor
|
2026-04-23 17:45:03 +08:00 |
|
bujinyuan
|
f5ae095033
|
fix(meeting): Task 16 会议销毁路径资源清理专项
前端修复:
- _onRoomEnded 保留结束页数据,新增 exitEndedRoom() 动作
room.vue onUnload 在 ENDED 状态调用,释放 currentRoom / participants / chatMessages 等 pinia state
- endMeeting() API 成功后立即触发 _onRoomEnded 本地兜底,不再依赖 room.ended 广播
避免 API 成功但 WS 抖动导致 engine / timer / AudioContext 泄漏
- 新增 _pendingBroadcastTimers 集合收纳 _broadcastSelfState 的 setTimeout 句柄
_cleanupMedia 统一 clearTimeout,避免会议结束后 stale 重试逻辑排队
后端修复:
- MeetingLifecycleService.OnRoomEnded 统一生命周期收尾
取消 graceTimers / emptyTTLTimers + Pipeline DEL host_grace / empty_ttl / 两个 handling 锁 key
- EndRoom 事务提交后遍历 activesBefore 调 cleanupRoomRedisResidual
批量 DEL 每个前任活跃成员的 resourceTrackKey + memberStateKey
补调 lifecycleSvc.OnRoomEnded 清理自身 timer + keys
- HandleEmptyRoomExpired MarkEnded 后补调 cleanupRoomRedisResidual + 清 host_grace 残留
验证:go vet + go build + npm run build:h5 全部通过
Made-with: Cursor
|
2026-04-23 17:12:38 +08:00 |
|
bujinyuan
|
790996feaf
|
feat(meeting): Task 15 UI 打磨 + 主持人四件套 + 媒体层稳定性回归修复
- Task 15 UI:6 项原创特色(说话者流光 / 柔性网格 / 自视频浮窗 / 静音氛围色 / 入会滑入 / NetworkBadge 3 条波浪)+ 说话者双源探测(RTP audioLevel + WebAudio RMS)+ 主持人四件套(静音/开麦/转让/踢出)
- 新增 SelfVideoFloat 浮窗组件 + 4 份 design-system 页面文档(home / preview / room / invite)
- 媒体回归补丁(手工联调触发):
* 后端 signal_service 在 OnRoomJoin 追加 pushExistingRoomState → 向新加入者补发历史 producers + 历史成员 audio/video 状态
* 新增 Redis Hash memberStateKey 持久化成员 audio/video enabled,OnMemberStateChanged 落盘、cleanupUserResources 清理
* 前端 _broadcastSelfState 在本地音视频开关末尾同步 state.changed;_afterJoined 先 getRoom 再 room.join 修复后入者成员状态时序;_onMemberStateChanged 占位兜底
* _cleanupRemoteProducer 改为按 producerId 精准清理(修复 "关音频误关视频")
* _onRoomEnded + createAndEnter/joinAndEnter 强化 reset(修复重入会看不到自己画面)
* mediasoup-client ensureSend/RecvTransport 引入 in-flight Promise 锁防并发重复建连
- 文档同步:CURRENT_STATUS.md / Task 15 plan / phase2e-2 implementation plan
Made-with: Cursor
|
2026-04-23 16:04:46 +08:00 |
|
bujinyuan
|
a311c03a21
|
fix(meeting): 聊天面板点击失效 & 成员/邀请按钮支持 toggle
ChatPanel 的 .btn-send 使用了 all:unset 导致 position 变为 static,
其 uni-app 自动注入的 ::after 伪元素(inset: 0 -1200px -80px 0)
absolute 定位会回溯到 body 作为 containing block,
形成一个覆盖几乎整个视口的隐形遮罩层,导致聊天面板的关闭按钮 (.btn-close)、
输入框 (textarea) 甚至发送按钮本身周围区域都无法点击/输入。
修复:
1. ChatPanel 的 .btn-send::after 从仅 border:none 升级为
content:none + display:none,彻底抹除遮罩
2. room.vue 中 openMembers / openInvite 改为 toggle 切换,
解决"再次点击成员按钮面板不会关闭"的问题
验证:Playwright 真实 DOM 命中测试 close/textarea/send 全部 hitSelf=true,
成员按钮二次点击面板正常关闭。
Made-with: Cursor
|
2026-04-22 16:34:30 +08:00 |
|
bujinyuan
|
3aa8174bc0
|
fix(meeting): 抹除 uni-button ::after 遮罩修复工具栏点击失效
uni-app H5 会给每个 <button> 编译后的 <uni-button> 自动注入一个
::after 伪元素作为点击态反馈遮罩,其 inset 为 0 -1200px -80px 0
(即 2400px × 160px),向按钮右侧扩展 1200px,下方扩展 80px。
这导致会议工具栏(MeetingToolbar)里每个按钮的 ::after 都横跨整个
toolbar,最后一个"离开"按钮 DOM 顺序最上,其 ::after 覆盖了所有
兄弟按钮的命中区域:点击"静音/视频/邀请/成员/聊天"时实际都命中
"离开"按钮的 ::after,触发离开弹窗;且弹窗中的"取消"按钮同样被
右侧"结束会议"按钮的 ::after 遮挡,点击取消反而会触发结束会议。
修复:在 .btn 和 .leave-btn 上显式设置 ::after { content: none;
display: none },并把按钮设为 position: relative 固化堆叠上下文。
验证:Playwright 真实点击各按钮 hitSelf=true,取消按钮不再
错误触发结束会议逻辑。
Made-with: Cursor
|
2026-04-22 16:27:16 +08:00 |
|
bujinyuan
|
ff46dc5f76
|
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
|
2026-04-22 16:13:25 +08:00 |
|
bujinyuan
|
c529ff4689
|
fix(phase2e-2): 全局 H5 容器铺满视口 + 静默自动清理 stale 会议
问题
1. 桌面浏览器大窗口下所有页面内容偏左上、右下大片空白:
uni-app H5 的 html/body/#app/uni-page-* 默认不显式 100% 高度,
且 .room 仅靠 position:fixed inset:0 在某些模式下可能被祖先
容器尺寸限制,导致 toolbar / tabBar 不贴底、内容挤在左上角
2. 刷新会议后再次加入会触发 toast "你不在当前会议中":
cleanupStaleMeetings 对列表里已过期的会议调 leave 必然返回 400,
被全局 request 拦截器误报给用户
3. 会议界面部分按钮点击无反应:
根因同 #1,布局错位后按钮视觉位置与 hit box 不一致
修复
- App.vue: H5 条件编译注入全局基础样式,强制 html/body/#app/uni-app/
uni-page/uni-page-wrapper/uni-page-body 宽高铺满,min-height 100%
- room.vue: .room 追加 width/height/min-width/min-height: 100vw/100vh 冗余
+ z-index:10,彻底兜底 position:fixed 失效场景
- request.js: 新增 options.silent 选项,业务错误 / 401 / 403 / 500 /
网络异常均根据 silent 决定是否弹 toast;401 仍会跳登录
- api/meeting.js: createRoom / joinRoom / leaveRoom 均接受 options 参数
- store/meeting.js:
· cleanupStaleMeetings 内 leave 传 silent:true 忽略幂等错误
· joinAndEnter / createAndEnter 首次尝试(未重试时)传 silent:true,
若命中 staleMeetingHint 自动清理重试,对用户完全无感;重试仍失败
的真实错误走正常 toast
验证
- Playwright 1024x576:room 页 / profile 页 / chat 列表 / 刷新后重新加入
流程截图均显示全屏铺满、tabBar/toolbar 贴底、无误报 toast
- 刷新 → join → 预览 → 加入 日志:首次 400 静默 → 自动清理 → 重试加入
成功,MediaEngine 正常建立
Made-with: Cursor
|
2026-04-22 16:00:12 +08:00 |
|
bujinyuan
|
16225c413d
|
fix(phase2e-2): 会议内聊天面板 UI 布局优化
问题修复:
- 原遮罩式抽屉覆盖底部 toolbar,导致按钮不可点击
- 发送按钮过小不显眼
- 聊天面板打开时视频区被遮挡出现大片空白
改进:
- room.vue 主区改为 flex-row 布局:视频列 + 聊天列并排,聊天打开时视频自动收窄
- ChatPanel 去除全屏遮罩,作为侧边栏嵌入 chat-col,保留过渡动画
- 发送按钮增加纸飞机图标并采用渐变背景,hover / active / disabled 状态清晰
- msg-list 使用 flex:1 + min-height:0 + height:0 修复 scroll-view 高度撑破问题,保证输入区始终固定在底部
- 小屏(<750px)自动回退为全屏浮层,避免挤压视频
Made-with: Cursor
|
2026-04-22 15:32:10 +08:00 |
|
bujinyuan
|
1222bf551d
|
feat(phase2e-2): 会议内聊天面板落地(Task 12)
- 新增 ChatPanel 组件:右侧抽屉式聊天 UI,支持发送/加载更早消息/未读清零
- store/meeting.js:扩展 chatHasMore/chatUnreadCount/chatHistoryLoaded 等状态与 loadMoreChats/markChatsRead 动作;WS 消息到达时按 id 去重
- room.vue:替换临时 toast 占位为 ChatPanel,绑定未读徽标、成员展示名映射;watch unread 自动在面板打开时清零
- 后端:SendChat WS 广播与 REST 响应补充 user_name/user_avatar,聊天面板无需额外查询即可展示昵称
Made-with: Cursor
|
2026-04-22 15:16:17 +08:00 |
|
bujinyuan
|
59f824ad27
|
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
|
2026-04-22 14:41:27 +08:00 |
|