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
|
d6fb7ce291
|
feat(meeting): Task 13 完成 meeting_invite 通知卡片对接
## 后端
- MeetingService.InviteUsers 的 PushPayload.Extra 补齐设计 §10.1 要求字段:
inviter_id / inviter_name / inviter_avatar / expired_at(Unix 秒,
与 Redis TTL MeetingInviteTokenTTL=600s 对齐)
## 前端
- constants/notify.js:supportsInlineAction 扩展支持 meeting_invite;
新增 NOTIFY_INLINE_ACTION_LABEL 映射(meeting_invite → 立即加入/稍后)
+ NOTIFY_INLINE_ACTION_DEFAULT 兜底
- components/notify/NotifyItem.vue:
* 按 type 动态渲染按钮文案(actionLabel 计算属性)
* isExpired 计算属性:meeting_invite 比对 extra.expired_at * 1000
* 过期态合并为单个 disabled 的"邀请已过期"按钮
* 新增 .notify-btn--expired 灰显样式
- pages/notify/index.vue:
* handleAccept / handleReject / _navigateByNotify 增加 meeting_invite 分支
* 新增 _navigateToMeetingInvite 辅助:跳 /pages/meeting/preview?mode=join&code=xxx
* 过期时 toast "邀请已过期"不跳转,"稍后"仅 markRead 不发接口
## 文档
- docs/plans/2026-04-21-phase2e-2-implementation.plan.md:Task 13 标 ✅ + 详细产出
- docs/progress/CURRENT_STATUS.md:新增 Task 13 专节(关键技术点 / 验证记录 / 下一步)
- .cursor/rules/project-context.mdc:2e-2 进度刷 Task 0-13 ✅
## 验证
后端 curl 双角色端到端(testuser1 创会 → 邀请 testuser2 → 拉通知列表):
- type=meeting_invite,extra 8 字段齐全
- expired_at = invited_at + 600,与 Redis TTL 对齐
Made-with: Cursor
|
2026-04-22 17:26:31 +08:00 |
|
bujinyuan
|
cacf4ae074
|
fix(meeting): 提升 toolbar z-index 确保成员/邀请面板开启时仍可点击
MemberPanel 和 InviteDialog 的 .panel-root 使用了 position:fixed; inset:0;
z-index:200 的全屏遮罩,当面板打开时会覆盖整个视口,包括底部 toolbar。
这导致:
- 用户再次点击 toolbar 的"成员"/"邀请"按钮时,命中的是 mask 而非按钮
- mask 的 @click.self 虽然也会关闭面板(通过点击空白区域),
但与 toolbar 按钮 toggle 的用户预期行为不一致
修复:把 MeetingToolbar .toolbar 的 z-index 从 15 提升到 210,
确保其高于 .panel-root (z:200) 而低于 .leave-mask (z:220)。
验证:Playwright 实测点击成员按钮 hitSelf=true,打开后再次点击正常关闭。
Made-with: Cursor
|
2026-04-22 16:39:41 +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
|
0c9f0483e5
|
fix(phase2e-2): 修复刷新后重入会失败 + 聊天输入区布局防御
问题
- 刷新会议页面被踢回 join 页,再次加入报"已在会议中"
- 极窄聊天面板下,发送按钮在 uni-app H5 渲染为 uni-button 时可能被默认
width:100% 样式撑满导致"竖排变形"
修复
1. meeting store: joinAndEnter / createAndEnter 捕获 staleMeetingHint 时自动
调用 cleanupStaleMeetings 清理后端残留的僵尸活跃成员记录,并重试一次;
日志链路:加入失败 → 检测僵尸 → 自动清理 → 重试加入
2. ChatPanel: input-area 显式声明 flex-direction:row + flex-wrap:nowrap;
.btn-send 追加 width:auto / line-height:1 / box-sizing,并通过 ::v-deep
复位 uni-app 内部 <uni-button> 默认 width,彻底避免按钮独占一行变形
验证
- Playwright 刷新 room 页 → 回 join → 预览 → 加入会议:日志显示自动清理僵尸
"581-702-753"、重试加入 "925-409-354" 成功,MediaEngine 正常建立
- 1024x576 视口下 toolbar 完整可见,聊天面板并排无右侧留白,发送按钮在
输入框右侧
Made-with: Cursor
|
2026-04-22 15:45:56 +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 |
|
bujinyuan
|
f1853f125d
|
feat: Phase 2e-1 统一通知中心 + 我的 TabBar 聚合未读红点
后端(notify 模块)
- 新增 notify 模块:DAO/Service/Pusher 接口/Controller/Router/CleanupTask
- 数据库 DDL:notify_notifications 表 + 3 索引(user+created/user+is_read/user+category)
- 11 种 type 枚举(好友/群聊 9 种 + meeting_* 2 种预留)+ 4 种 category
- 跨模块集成:contact 3 处 Pusher(friend_request/accepted/rejected)
- 跨模块集成:group 6 处 Pusher(invite/join_request/approved/rejected/kicked/role_changed)
- WS handler 断线补偿:连接建立即推送 notify.unread.total
- 5 REST API(4 用户 + 1 管理员广播)+ 2 WS 事件(notify.new / notify.unread.total)
- 30 天已读通知定时清理(未读永久保留)
- Provider/Wire 依赖注入(NotifyPusher、NotifyConnectHook、UserInfoResolver 接口)
前端
- 新增 notify 模块:API/Pinia Store(5 分类分页缓存 + 未读数 + WS 事件)/NotifyItem/通知中心主页
- profile 入口:铃铛 badge + 菜单项 badge + 数字显示
- App.vue/login 初始化 notifyStore WS 监听;logout 调用 notifyStore.reset() 清缓存
- 清理 contact.js/group.js 中散落 toast 与冗余 notify.friend.request/group.join.request 处理
- CustomTabBar 新增 hasDot() 聚合指示器:我的 Tab 显示纯红点(无数字),
当前聚合 notifyStore.unreadTotal,未来可扩展「资料待完善/安全提醒/新版本」等
文档
- 新增 Phase 2e 整体路线图 docs/plans/2026-04-20-phase2e-design.md
- 新增 Phase 2e-1 专用设计 docs/plans/2026-04-20-phase2e-1-design.md(§6.4 TabBar 聚合红点)
- 新增 Phase 2e-1 实施计划 docs/plans/2026-04-20-phase2e-1-implementation.plan.md
- 新增 E2E 验证报告 test-report-phase2e-1-notification.md(含 Playwright MCP 2 个现场 Bug 修复记录)
- 更新 docs/progress/CURRENT_STATUS.md、docs/api/README.md、docs/api/frontend/notify.md
- 更新 .cursor/rules/project-context.mdc、docs/plans/2026-02-27-echochat-system-design.md
其他
- .gitignore 排除 .playwright-mcp/ MCP 临时快照
架构决策
- 单端 WS 连接:沿用现有 ws.Hub,多端已读同步推迟到 Phase 2f/二期
- 跨模块依赖:contact/group → notify 严格单向(接口注入模式)
- 降级策略:Pusher 先入库后推送;WS 失败不回滚入库;入库失败仅 Warn 不影响业务
Playwright MCP 回归(4 类场景全通)
- 实时推送(admin 广播 → 1s 内前端自动插入 + 角标 +1)
- Deep-link 跳转(好友申请通知 → contact/request 页)
- 批量清零(全部已读按钮)
- TabBar 聚合红点(有未读亮/全部已读灭)与 notifyStore.unreadTotal 三层同步
Made-with: Cursor
|
2026-04-21 10:21:01 +08:00 |
|
bujinyuan
|
ccfceefdaf
|
feat:聊天页面相关功能优化,提供用户体验感
|
2026-04-20 15:40:16 +08:00 |
|
bujinyuan
|
0c1540bdee
|
feat:聊天信息支持 文件、图片、语音发送,增加一键启停脚本
|
2026-04-20 11:53:27 +08:00 |
|
bujinyuan
|
8ee870636c
|
feat:群聊问题修复+相关项目文档更新
|
2026-03-05 09:24:49 +08:00 |
|
bujinyuan
|
35788f6d2f
|
style(frontend): ui-ux-pro-max 规范改造 — chat 页面 + CustomTabBar
改造内容:
- 安装 @dcloudio/uni-ui + sass,配置 easycom 自动引入 uni-icons
- 4 个 chat 页面:emoji/HTML 实体 → uni-icons 组件(跨平台兼容)
- CustomTabBar:emoji → uni-icons(chatbubble/contact/videocam/person)
- 选中态使用 filled 变体,未选中态使用轮廓图标
- 所有可交互元素添加 :active 按压反馈 + transition (150-200ms)
- 触控目标保证 ≥ 88rpx (44px)
- input-bar/tab-bar 适配 safe-area-inset-bottom
设计规范文件:
- MASTER.md 修正为项目蓝色色板 (#2563EB) + 移动聊天应用规范
- 新增 4 个页面覆盖规范:chat-index/conversation/settings/search.md
- Pre-Delivery Checklist 全部通过
- npm run build:h5 编译验证通过
Made-with: Cursor
|
2026-03-03 11:23:11 +08:00 |
|
bujinyuan
|
780dea3c31
|
feat(frontend): Task 6 - Chat Store + API + WS 事件 + TabBar badge
API (api/im.js):
- getConversations / getHistoryMessages / pinConversation
- deleteConversation / clearHistory / searchMessages / getTotalUnread
Chat Store (store/chat.js):
- 会话列表管理 + 排序(置顶优先)
- 消息缓存 + 三态确认(sending/sent/failed)
- 全局未读数管理(Redis 同步)
- WS 事件监听:im.message.new/recalled/send.ack/offline.sync/typing
- 工具方法:游标分页加载、typing 超时清除
CustomTabBar:
- 消息 Tab 显示全局未读 badge(>99 显示 99+)
Made-with: Cursor
|
2026-03-03 10:58:35 +08:00 |
|
bujinyuan
|
4d03215fe4
|
feat: Phase 1 完成 — 基础设施 + 用户认证 + 管理端 + 端到端验证
Phase 1 (基础设施与用户认证) 全部 11 个 Task 开发完成:
后端 (Go):
- Auth 模块: 注册/登录/JWT(有状态)/Profile/密码修改
- Admin 模块: 用户列表/详情/禁用/启用/角色分配/创建用户
- 中间件: JWT认证 + RBAC角色权限 + 请求日志 + CORS + Panic恢复
- Dockerfile 多阶段构建 + Docker Compose 全栈部署
前台 (uni-app):
- 登录/注册页面 + 自定义 TabBar + 个人中心
- 请求封装 + 状态管理 (Pinia)
管理端 (Vue 3 + Element Plus):
- 登录/仪表盘/用户列表/用户详情
- Axios 封装 + 路由守卫 + Pinia 状态管理
验证:
- 全流程 API 端到端测试通过
- Playwright 页面自动化验证通过
- code-reviewer 代码审查通过
Made-with: Cursor
|
2026-03-02 11:31:24 +08:00 |
|