Browse Source

【MiniProgram】update Miniprogram

yuanfazheng 1 năm trước cách đây
mục cha
commit
873bd1ff55
80 tập tin đã thay đổi với 650 bổ sung347 xóa
  1. 0 223
      MiniProgram/CHANGELOG.md
  2. 4 4
      MiniProgram/configureProject.js
  3. 3 3
      MiniProgram/configureProject_bin.js
  4. 2 2
      MiniProgram/package.json
  5. 11 9
      MiniProgram/src/locales/en-US.ts
  6. 28 0
      MiniProgram/src/locales/index.ts
  7. 10 9
      MiniProgram/src/locales/zh-CN.ts
  8. 8 0
      MiniProgram/src/manifest.json
  9. 1 0
      MiniProgram/src/pages.json
  10. 1 0
      MiniProgram/src/roomkit/TUIRoom/assets/style/black-theme.scss
  11. 1 0
      MiniProgram/src/roomkit/TUIRoom/assets/style/white-theme.scss
  12. 1 0
      MiniProgram/src/roomkit/TUIRoom/components/Chat/ChatEditor/index.vue
  13. 2 0
      MiniProgram/src/roomkit/TUIRoom/components/Chat/ChatEditor/useChatEditor.ts
  14. 4 0
      MiniProgram/src/roomkit/TUIRoom/components/Chat/util.ts
  15. 1 0
      MiniProgram/src/roomkit/TUIRoom/components/ManageMember/MemberControl/index.vue
  16. 31 4
      MiniProgram/src/roomkit/TUIRoom/components/ManageMember/MemberControl/useMemberControlHooks.ts
  17. 3 2
      MiniProgram/src/roomkit/TUIRoom/components/ManageMember/MemberItem/useMemberItemHooks.ts
  18. 3 0
      MiniProgram/src/roomkit/TUIRoom/components/ManageMember/MemberItemCommon/MemberInfo.vue
  19. 5 2
      MiniProgram/src/roomkit/TUIRoom/components/ManageMember/useIndexHooks.ts
  20. 20 0
      MiniProgram/src/roomkit/TUIRoom/components/RoomContent/StreamContainer/index.vue
  21. 11 0
      MiniProgram/src/roomkit/TUIRoom/components/RoomContent/StreamContainer/useStreamContainerHooks.ts
  22. 2 0
      MiniProgram/src/roomkit/TUIRoom/components/RoomContent/StreamRegion/index.vue
  23. 11 2
      MiniProgram/src/roomkit/TUIRoom/components/RoomFooter/ApplyControl/MemberApplyControl.vue
  24. 12 1
      MiniProgram/src/roomkit/TUIRoom/components/RoomFooter/AudioControl.vue
  25. 3 0
      MiniProgram/src/roomkit/TUIRoom/components/RoomFooter/EndControl/index.vue
  26. 7 0
      MiniProgram/src/roomkit/TUIRoom/components/RoomFooter/ScreenShareControl/Index.vue
  27. 13 1
      MiniProgram/src/roomkit/TUIRoom/components/RoomFooter/VideoControl.vue
  28. 2 2
      MiniProgram/src/roomkit/TUIRoom/components/RoomHeader/RoomInfo/useRoomInfoHooks.ts
  29. 5 0
      MiniProgram/src/roomkit/TUIRoom/components/RoomHeader/UserInfo/useUserInfoHooks.ts
  30. 1 0
      MiniProgram/src/roomkit/TUIRoom/components/RoomLogin/VerifyCode.vue
  31. 4 0
      MiniProgram/src/roomkit/TUIRoom/components/RoomSetting/index.vue
  32. 1 0
      MiniProgram/src/roomkit/TUIRoom/components/RoomSidebar/useSideBarHooks.ts
  33. 1 0
      MiniProgram/src/roomkit/TUIRoom/components/common/ArrowStroke.vue
  34. 6 0
      MiniProgram/src/roomkit/TUIRoom/components/common/AudioMediaControl.vue
  35. 7 0
      MiniProgram/src/roomkit/TUIRoom/components/common/AudioSettingTab.vue
  36. 5 0
      MiniProgram/src/roomkit/TUIRoom/components/common/DeviceSelect.vue
  37. 4 0
      MiniProgram/src/roomkit/TUIRoom/components/common/Logo.vue
  38. 3 0
      MiniProgram/src/roomkit/TUIRoom/components/common/SwitchTheme.vue
  39. 6 0
      MiniProgram/src/roomkit/TUIRoom/components/common/VideoMediaControl.vue
  40. 5 0
      MiniProgram/src/roomkit/TUIRoom/components/common/VideoProfile.vue
  41. 8 0
      MiniProgram/src/roomkit/TUIRoom/components/common/VideoSettingTab.vue
  42. 11 0
      MiniProgram/src/roomkit/TUIRoom/components/common/base/Drawer.vue
  43. 7 0
      MiniProgram/src/roomkit/TUIRoom/components/common/base/IconButton.vue
  44. 1 0
      MiniProgram/src/roomkit/TUIRoom/components/common/base/Select.vue
  45. 7 1
      MiniProgram/src/roomkit/TUIRoom/components/common/base/SvgIcon.vue
  46. 2 2
      MiniProgram/src/roomkit/TUIRoom/constants/room.ts
  47. 1 1
      MiniProgram/src/roomkit/TUIRoom/extension/RoomMessageCard/RoomMessageCard.vue
  48. 5 0
      MiniProgram/src/roomkit/TUIRoom/extension/RoomMessageCard/handleRoomMessage.ts
  49. 30 22
      MiniProgram/src/roomkit/TUIRoom/extension/chatExtension.ts
  50. 2 0
      MiniProgram/src/roomkit/TUIRoom/extension/utils/interact.ts
  51. 1 0
      MiniProgram/src/roomkit/TUIRoom/hooks/useDeviceManager.ts
  52. 42 12
      MiniProgram/src/roomkit/TUIRoom/hooks/useMasterApplyControl.ts
  53. 1 0
      MiniProgram/src/roomkit/TUIRoom/hooks/useMitt.ts
  54. 12 0
      MiniProgram/src/roomkit/TUIRoom/index.vue
  55. 11 9
      MiniProgram/src/roomkit/TUIRoom/locales/en-US.ts
  56. 27 0
      MiniProgram/src/roomkit/TUIRoom/locales/index.ts
  57. 10 9
      MiniProgram/src/roomkit/TUIRoom/locales/zh-CN.ts
  58. 7 3
      MiniProgram/src/roomkit/TUIRoom/services/roomService.ts
  59. 1 0
      MiniProgram/src/roomkit/TUIRoom/stores/chat.ts
  60. 40 2
      MiniProgram/src/roomkit/TUIRoom/stores/room.ts
  61. 8 0
      MiniProgram/src/roomkit/TUIRoom/utils/aegis/config.ts
  62. 2 2
      MiniProgram/src/roomkit/TUIRoom/utils/common.ts
  63. 1 0
      MiniProgram/src/roomkit/TUIRoom/utils/common/logger/index.ts
  64. 8 0
      MiniProgram/src/roomkit/TUIRoom/utils/common/logger/logger-constants.ts
  65. 1 1
      MiniProgram/src/roomkit/TUIRoom/utils/common/logger/logger-utils.ts
  66. 2 2
      MiniProgram/src/roomkit/TUIRoom/utils/constants.ts
  67. 2 0
      MiniProgram/src/roomkit/TUIRoom/utils/environment.ts
  68. 7 0
      MiniProgram/src/roomkit/TUIRoom/utils/mediaAbility.ts
  69. 18 0
      MiniProgram/src/roomkit/TUIRoom/utils/toCanvas.ts
  70. 42 0
      MiniProgram/src/roomkit/TUIRoom/utils/utils.ts
  71. 20 3
      MiniProgram/src/roomkit/config/basic-info-config.js
  72. 13 0
      MiniProgram/src/roomkit/pages/home.vue
  73. 10 1
      MiniProgram/src/roomkit/pages/room.vue
  74. BIN
      MiniProgram/src/static/RTCRoomEngine.wasm.br
  75. BIN
      MiniProgram/src/static/TUIRoomEngine.wasm.br
  76. 38 9
      MiniProgram/src/uni.scss
  77. 1 1
      MiniProgram/wxmini_dev.bat
  78. 1 1
      MiniProgram/wxmini_dev.sh
  79. 1 1
      MiniProgram/wxmini_prod.bat
  80. 1 1
      MiniProgram/wxmini_prod.sh

+ 0 - 223
MiniProgram/CHANGELOG.md

@@ -1,223 +0,0 @@
-## 2024.04.29@2.3.1
-
-**Feature**
-
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v2.3.1 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361);
-
-**Bug Fixed**
-- 修复小程序入会时间展示不全的问题;
-- 修复小程序上台提示信息出现换行的问题;
-- 修复小程序成员管理列表无法滚动问题;
-- 修复小程序创建房间后,点击左上角 home 按钮回到主页,再次新建的房间异常;
-- 修复小程序转交房主之后 icon 无法切换的问题;
-- 修复获取主持人和管理员身份后没有更新申请上麦列表的问题;
-- 修复聊天消息未读数不准确的问题;
-- 修复 Notification 组件收到其他成员处理事件时显隐展示的问题;
-- 修复转交房主或管理员状态下多次点击麦克风和摄像头按钮 disable 状态错误的问题。
-
-## 2024.04.08@2.2.2
-
-**Feature**
-
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v2.2.2 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361);
-
-**Improvement**
-- 优化 onKickedOffLine 回调时清理资源并执行 TRTC 退房操作;
-
-**Bug Fixed**
-- 修复结束屏幕分享摄像头视频流状态异常;
-- 修复收不到 onKickedOffLine 回调;
-- 修复主动调用 logout 退房逻辑异常问题;
-- 修复 isMobile 状态异常问题;
-
-## 2024.03.22@2.2.0
-
-**Feature**
-
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v2.2.0 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361);
-
-**Improvement**
-- 更新聊天组件表情包资源;
-- 优化上台发言房间 UI;
-
-**Bug Fixed**
-- 修复上台发言模式下,普通成员成为新房主,不能处理之前旧房主未处理的上台申请的问题;
-- 修复切换前后置摄像头不生效的问题;
-- 修复上台发言模式二次上台无法打开麦克风的问题;
-- 修复自己发送消息不会跳转到最新的问题;
-
-## 2024.02.29@2.1.0
-
-**Feature**
-
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v2.1.0 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361);
-
-**Improvement**
-- 新增邀请/举手超时处理以及上麦人数超过 20 个限制处理;
-- 优化主持人/管理员重复进行全体静音/禁画的交互体验;
-- 优化登录逻辑;
-- 新增获取上麦请求列表接口 (getSeatApplicationList), 新增信令被处理回调 (onRequestProcessed), 优化主持人和多管理员处理上台申请逻辑;
-- 新增主持人/管理员发送 邀请上台/上麦申请 的 60 秒超时, 普通成员超时未处理弹窗自动消失;
-
-**Bug Fixed**
-- 修复时机问题导致的 trtc 角色未切换问题, 调整 getSeatList 与 takeSeat 的调用顺序;
-- 修复进会人数拉取不准确的问题;
-- 修复创建举手发言房间后不能默认打开摄像头和麦克风的问题;
-- 修复 @tencentcloud/tuiroom-engine-wx 版本与 kit 版本不匹配问题;
-
-## 2024.02.02@2.0.3
-
-**Feature**
-
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v2.0.3 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361);
-
-**Improvement**
-- 优化转交主持人,同意/拒绝上台,请求打开摄像头/麦克风的 toast 展示时机及文案提示;
-
-**Bug Fixed**
-- 修复管理员被撤销后的音视频状态错误问题;
-- 修复普通成员被禁言后未同步给其他管理员的问题;
-- 小程序端不再展示 scheme 邀请链接;
-- 完善 uniapp 打包小程序的拷贝脚本;
-
-## 2024.01.29@2.0.2
-
-**Feature**
-
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v2.0.2 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361);
-- 转交房主新增 Dialog 确认框。
-
-**Bug Fixed**
-
-- 修复移动端小程序 IOS 设备中部分 icon 展示模糊的问题。
-- 修复将远端用户踢出房间后 Dialog 未消失的问题。
-- 修复房主 && 管理员端在上台发言模式下远端用户未上台不展示离开房间选项的问题。
-- 修复举手申请处理端 Toast 展示无法区分角色的问题。
-- 修复全体静音/取消全体静音 && 全体禁画/取消全体禁画 Toast 无法通知到所有成员的问题。
-
-## 2024.01.19@2.0.1
-
-**Feature**
-
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v2.0.1 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361);
-- 被撤销管理员增加相关提示&&视频流区域增加管理员icon.
-
-**Bug Fixed**
-- 发送信令无操作处理时,增加消息提示。
-- 上台发言房间打开邀请摄像头/麦克风文案显示优先级。
-
-## 2024.01.12@2.0.0
-
-**Feature**
-
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v2.0.0 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361)。
-
-**Bug Fixed**
-- 修复小程序头像加载错误没有使用默认头像。
-- 修复小程序端上麦关闭摄像头麦克风其它端无法在麦位列表看到小程序用户。
-- 修复管理员请求打开摄像头的时候,后面几次没有toast提示。
-- 修复英文模式部分文案。
-
-## 2024.01.11@1.7.1
-
-**Feature**
-
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v1.7.1 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361)。
-- 支持设置管理员角色。
-- 优化小程序接口调用逻辑,增加异步任务状态机,提高了推拉流稳定性。
-
-**Bug Fixed**
-- 修复成员被踢出房间时,偶现 dialog 弹框卡住问题。
-- 修复移动端小程序上台申请列表样式问题。
-- 修复移动端小程序有远端屏幕分享时,会多显示一页视频问题。
-- 优化 README.md 文件,简化代码跑通流程。
-- 修复移动端小程序举手管理列表中点击全体同意 & 全体拒绝按钮没有响应的问题。
-- 修复移动端小程序举手发言模式成员管理中,房主针对普通观众操作菜单展示问题。
-- 修复windows 无 bash 环境执行 wxmini_dev.sh 报错,提供 windows 脚本 wxmini_dev.bat。
-
-## 2023.12.18@1.7.0
-
-**Feature**
-
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v1.7.0 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361);
-- 新增会中移交主持人功能。
-- 新增结束会议及踢出房间确认弹窗。
-- 小程序新增视频流懒加载功能。
-- 主持人邀请成员开启视频、麦克风增加消息提示。
-- 移交主持人新增错误信息提示。
-- 优化退房性能。
-
-**Bug Fixed**
-
-- 修复默认头像在小程序无法加载的问题。
-- 修复观众端禁止文字聊天区域的展示交互。
-- 修复上台发言模式下,第二次上麦打不开麦克风问题。
-- 修复被踢出房间 live-pusher 被提前销毁问题。
-- 修复小程序成员列表功能点击失效问题。
-- 修复设备测试区域,切换扬声器和播放设备不生效的问题。
-- 修复移动端小程序镜像设置设置不生效问题。
-- 修复移动端小程序成员管理,操作最后一个成员时,样式异常问题。
-- 修复移动端小程序下 dialog 文案及字体颜色错误问题。
-- 修复移动端小程序点击新的成员管理弹窗,旧弹窗不会被关闭问题。
-- 修复小程序收不到 IM 加入群组事件,无法展示 userName 及无法正常移交主持人问题。
-- 修复会中切换前后置摄像头,然后关闭摄像头后再打开,前后置摄像头状态显示错误问题。
-- 修复小程序首次渲染偶现黑屏问题。
-- 增加小程序回退图标按钮区域大小,修复手指点击无响应问题。
-
-## 2023.11.14@1.6.1
-
-**Feature**
-
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v1.6.1 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361);
-- 新增支持切换黑白主题,更改 svg 的引入方式;
-
-**Bug Fixed**
-
-- 修改举手发言房间名称为上台发言房间;
-- 修复 Message、MessageBox 和 Badge 组件的展示问题;
-- 修复小程序复制 icon 丢失的问题;
-- 修复小程序房间号为空时,未拦截进房问题;
-
-## 2023.10.26@1.6.0
-
-**Feature**
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-js) 到 v1.6.0 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361)。
-- 升级 chat sdk 至 v3 版本。
-
-**Bug Fixed**
-- 修复聊天未读数气泡过大问题;
-- 修复 RoomInfo 动画抖动问题;
-- 修复 chat 模块消息位置显示异常问题;
-- 修复转交主持人列表不能滑动问题;
-- 修复 userName 过长导致成员管理中音视频状态 icon 错位问题;
-- 修复麦克风音量条以及音量高亮区域显示问题;
-
-## 2023.09.25@1.5.1
-
-**Feature**
-- 升级 [@tencentcloud/tuiroom-engine-wx](https://www.npmjs.com/package/@tencentcloud/tuiroom-engine-wx) 到 v1.5.1 版本,详情请查看 [发布日志](https://cloud.tencent.com/document/product/1690/89361)。
-- 优化平滑开关麦克风操作
-
-**Bug Fixed**
-- 修复举手发言模式下,主持人重新进入房间后没有自动上麦的问题;
-- 修复举手发言模式下,主持人侧举手发言列表不是按照举手顺序排列的问题;
-- 修复手机浏览器中,上下操作栏收起时,通知 dialog 不显示的问题;
-- 修复邀请成员和联系他人的字体不一致问题;
-- 修复聊天未读数不居中问题;
-
-## 2023.09.07@Version 1.5.0
-
-**Feature**
-
-- 优化样式细节与 UI 交互
-
-**Bug Fixed**
-
-- 修复偶现推流异常
-- 修复不同设备样式兼容问题
-
-## 2023.08.28@Version 1.0.0
-
-**Feature**
-
-- roomkit 支持微信小程序端(使用 uniapp 框架打包到微信小程序,默认使用分包方案)

+ 4 - 4
MiniProgram/configureProject.js

@@ -126,12 +126,12 @@ class InitProject {
         path.join(this.destBase, file),
       );
     });
-    
-    // Copy TUIRoomEngine.wasm.br file
-    const wasmDest = './static/TUIRoomEngine.wasm.br';
+
+    // Copy RTCRoomEngine.wasm.br file
+    const wasmDest = './static/RTCRoomEngine.wasm.br';
     createDirIfNotExist(path.dirname(wasmDest));
     fs.copyFileSync(
-      './node_modules/@tencentcloud/tuiroom-engine-wx/TUIRoomEngine.wasm.br',
+      './node_modules/@tencentcloud/tuiroom-engine-wx/RTCRoomEngine.wasm.br',
       path.join(this.srcPath, wasmDest),
     );
 

+ 3 - 3
MiniProgram/configureProject_bin.js

@@ -122,11 +122,11 @@ class InitProject {
       );
     });
 
-    // Copy TUIRoomEngine.wasm.br file
-    const wasmDest = './static/TUIRoomEngine.wasm.br';
+    // Copy RTCRoomEngine.wasm.br file
+    const wasmDest = './static/RTCRoomEngine.wasm.br';
     createDirIfNotExist(path.dirname(wasmDest));
     fs.copyFileSync(
-      './node_modules/@tencentcloud/tuiroom-engine-wx/TUIRoomEngine.wasm.br',
+      './node_modules/@tencentcloud/tuiroom-engine-wx/RTCRoomEngine.wasm.br',
       path.join(this.srcPath, wasmDest),
     );
 

+ 2 - 2
MiniProgram/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@tencentcloud/tui-roomkit-uniapp",
-  "version": "2.3.1",
+  "version": "2.4.0",
   "bin": {
     "configureProject": "./configureProject_bin.js"
   },
@@ -60,7 +60,7 @@
     "@tencentcloud/chat": "latest",
     "@tencentcloud/trtc-component-wx": "^0.0.4",
     "@tencentcloud/tui-core": "latest",
-    "@tencentcloud/tuiroom-engine-wx": "^2.3.1",
+    "@tencentcloud/tuiroom-engine-wx": "^2.4.0",
     "@tencentcloud/universal-api": "^2.0.9",
     "axios": "^0.27.2",
     "inquirer": "^9.2.11",

+ 11 - 9
MiniProgram/src/locales/en-US.ts

@@ -62,7 +62,7 @@ export default {
   'Join Room': 'Join Room',
   'Enter room ID': 'Enter room ID',
   'video conferencing': ' \'s video conferencing',
-  'Quick Meeting': ' \'s Quick Meeting',
+  'Quick Conference': ' \'s Quick Conference',
   'Room ID': 'Room ID',
   'Low Definition': 'Low Definition',
   'Standard Definition': 'Standard Definition',
@@ -95,9 +95,9 @@ export default {
   'Full screen': 'Full screen',
   Members: 'Members',
   'Search Member': 'Search Member',
-  'Transfer owner': 'Transfer owner',
+  'Make host': 'Make host',
   'Set as administrator': 'Set as administrator',
-  'Revoke administrator': 'Revoke administrator',
+  'Remove administrator': 'Remove administrator',
   // @ts-ignore
   'The administrator status of sb has been withdrawn': ({ named }) => `The administrator status of ${named('name')} has been withdrawn`,
   // @ts-ignore
@@ -243,9 +243,9 @@ export default {
   'kicked out of the room by other device': 'kicked out of the room by other device',
   'kicked out of the room by serve': 'kicked out of the room by serve',
   // @ts-ignore
-  'Reject sb stage failed, please retry': ({ named }) => `Reject ${named('name')} on Stage failed, please retry`,
+  'Reject sb on stage failed, please retry': ({ named }) => `Reject ${named('name')} on Stage failed, please retry`,
   // @ts-ignore
-  'Agree sb stage failed, please retry': ({ named }) => `Agree ${named('name')} on Stage failed, please retry`,
+  'Agree sb on stage failed, please retry': ({ named }) => `Agree ${named('name')} on Stage failed, please retry`,
   'Has been fully muted and cannot open the microphone': 'Has been fully muted and cannot open the microphone',
   'Has been muted by the host and cannot open the microphone': 'Has been muted by the host and cannot open the microphone',
   'To apply to speak in the room, please raise your hand first to apply for the microphone': 'To apply to speak in the room, please raise your hand first to apply for the microphone',
@@ -273,7 +273,7 @@ export default {
   'An invitation to open the microphone has been sent to sb.': ({ named }) => `An invitation to open the microphone has been sent to ${named('name')}`,
   // @ts-ignore
   'An invitation to open the camera has been sent to sb.': ({ named }) => `An invitation to open the camera has been sent to ${named('name')}`,
-  'Transfer owner failed, please try again.': 'Transfer owner failed, please try again.',
+  'Make host failed, please try again.': 'Make host failed, please try again.',
   // @ts-ignore
   'Sb has been set as an administrator': ({ named }) => `${named('name')} has been set as an administrator.`,
   'Succeed on stage': 'Succeed on stage',
@@ -294,8 +294,7 @@ export default {
   'You are now an administrator': 'You are now an administrator',
   'The RoomOwner has withdrawn your administrator privileges': 'The RoomOwner has withdrawn your administrator privileges',
   'This member has already received the same request, please try again later': 'This member has already received the same request, please try again later',
-  'Failed to go on stage, invitation has timed out': 'Failed to go on stage, invitation has timed out',
-  'The current number of people on stage has reached the limit': 'The current number of people on stage has reached the limit',
+  'The request to go on stage has timed out': 'The request to go on stage has timed out',
   // @ts-ignore
   'The invitation to sb to go on stage has timed out': ({ named }) => `The invitation to ${named('name')} to go on stage has timed out`,
   'Currently no member has applied to go on stage': 'Currently no member has applied to go on stage',
@@ -303,6 +302,8 @@ export default {
   'Stage management': 'Stage management',
   'Already on stage': 'Already on stage',
   'Not on stage': 'Not on stage',
+  'The stage is full, please contact the host': 'The stage is full, please contact the host',
+  'The stage is full': 'The stage is full',
   'To go on stage again, you need to reapply and wait for the roomOwner/administrator to approve': 'To go on stage again, you need to reapply and wait for the roomOwner/administrator to approve',
   'To go on stage again, a new application needs to be initiated': 'To go on stage again, a new application needs to be initiated',
   'The request to go on stage has been sent out, please wait for the roomOwner/administrator to approve it': 'The request to go on stage has been sent out, please wait for the roomOwner/administrator to approve it',
@@ -312,7 +313,8 @@ export default {
   'people applying to stage': 'people applying to stage',
   // @ts-ignore
   'and so on number people applying to stage': ({ named }) => `and so on ${named('number')} people applying to stage`,
-  'quick meeting': 'quick meeting',
+  // Room Chat 融合卡片翻译
+  'quick conference': 'quick conference',
   Meeting: 'Meeting',
   'Meeting in progress': 'Meeting in progress',
   Initiating: 'Initiating',

+ 28 - 0
MiniProgram/src/locales/index.ts

@@ -1,3 +1,30 @@
+/**
+ * i18n 使用说明:
+ *
+ * <script>
+ * import i18n, { useI18n } from '../locale';
+ * const { t } = useI18n();
+ *
+ * // case 1: 翻译文本中没有变量
+ * t('happy');
+ * i18n.t('happy');
+ * // case 2: 翻译文本中存在变量
+ * t('kick sb. out of room', { someOneName: 'xiaoming' });
+ * i18n.t('kick sb. out of room', { someOneName: 'xiaoming' });
+ * </script>
+ *
+ * // 切换语言
+ * switch (i18n.global.locale.value) {
+ *  case 'en-US':
+ *    i18n.global.locale.value = 'zh-CN';
+ *    break;
+ *  case 'zh-CN':
+ *    i18n.global.locale.value = 'en-US';
+ *    break;
+ * }
+ * </script>
+ */
+
 import ZH from './zh-CN';
 import EN from './en-US';
 import { ref } from 'vue';
@@ -31,6 +58,7 @@ class TUIKitI18n {
     return message[key];
   }
 
+  // 兼容 App.use 不报错
   public install() {
   }
 }

+ 10 - 9
MiniProgram/src/locales/zh-CN.ts

@@ -59,7 +59,7 @@ export default {
   'Join Room': '进入房间',
   'Enter room ID': '输入房间号',
   'video conferencing': ' 的视频会议',
-  'Quick Meeting': '的快速会议',
+  'Quick Conference': '的快速会议',
   'Room ID': '房间号',
   'Low Definition': '流畅',
   'Standard Definition': '标清',
@@ -92,9 +92,9 @@ export default {
   'Full screen': '全屏',
   Members: '成员',
   'Search Member': '搜索成员',
-  'Transfer owner': '转交房主',
+  'Make host': '转交房主',
   'Set as administrator': '设为管理员',
-  'Revoke administrator': '撤销管理员',
+  'Remove administrator': '撤销管理员',
   // @ts-ignore
   'The administrator status of sb has been withdrawn': ({ named }) => `已将 ${named('name')} 的管理员身份撤回`,
   // @ts-ignore
@@ -243,9 +243,9 @@ export default {
   'kicked out of the room by other device': '相同账号在其他客户端进入房间',
   'kicked out of the room by serve': '被服务端踢出房间',
   // @ts-ignore
-  'Reject sb stage failed, please retry': ({ named }) => `拒绝 ${named('name')} 上台失败, 请重试`,
+  'Reject sb on stage failed, please retry': ({ named }) => `拒绝 ${named('name')} 上台失败, 请重试`,
   // @ts-ignore
-  'Agree sb stage failed, please retry': ({ named }) => `同意 ${named('name')} 上台失败, 请重试`,
+  'Agree sb on stage failed, please retry': ({ named }) => `同意 ${named('name')} 上台失败, 请重试`,
   'Has been fully muted and cannot open the microphone': '已被全员静音,无法打开麦克风',
   'Has been muted by the host and cannot open the microphone': '已被主持人静音,无法打开麦克风',
   'To apply to speak in the room, please raise your hand first to apply for the microphone': '申请发言房间,请先举手申请上麦',
@@ -273,7 +273,7 @@ export default {
   'An invitation to open the microphone has been sent to sb.': ({ named }) => `已向 ${named('name')} 发出开启麦克风邀请`,
   // @ts-ignore
   'An invitation to open the camera has been sent to sb.': ({ named }) => `已向 ${named('name')} 发出开启摄像头邀请`,
-  'Transfer owner failed, please try again.': '转交房主失败,请重试',
+  'Make host failed, please try again.': '转交房主失败,请重试',
   // @ts-ignore
   'Sb has been set as an administrator': ({ named }) => `已将 ${named('name')} 设为管理员`,
   'Succeed on stage': '上台成功',
@@ -294,8 +294,7 @@ export default {
   'You are now an administrator': '您已成为管理员',
   'The RoomOwner has withdrawn your administrator privileges': '房主已收回您的管理员权限',
   'This member has already received the same request, please try again later': '该成员已收到相同请求,请稍后再试',
-  'Failed to go on stage, invitation has timed out': '上台失败,邀请已超时',
-  'The current number of people on stage has reached the limit': '当前上台人数已达上限',
+  'The request to go on stage has timed out': '上台请求已超时',
   // @ts-ignore
   'The invitation to sb to go on stage has timed out': ({ named }) => `对${named('name')}的上台邀请已超时`,
   'Currently no member has applied to go on stage': '暂无成员申请上台',
@@ -303,6 +302,8 @@ export default {
   'Stage management': '上台管理',
   'Already on stage': '已上台',
   'Not on stage': '未上台',
+  'The stage is full, please contact the host': '台上人数已满,请联系主持人',
+  'The stage is full': '台上人数已满',
   'To go on stage again, you need to reapply and wait for the roomOwner/administrator to approve': '再次上台需重新发起申请,并等待房主/管理员通过',
   'To go on stage again, a new application needs to be initiated': '再次上台需重新发起申请',
   'The request to go on stage has been sent out, please wait for the roomOwner/administrator to approve it': '上台申请已发出,请等待房主/管理员通过',
@@ -313,7 +314,7 @@ export default {
   // @ts-ignore
   'and so on number people applying to stage': ({ named }) => `等 ${named('number')} 人正在申请上台`,
   // Room Chat 融合卡片翻译
-  'quick meeting': '快速会议',
+  'quick conference': '快速会议',
   Meeting: '会议',
   'Meeting in progress': '会议 进行中',
   Initiating: '正在发起',

+ 8 - 0
MiniProgram/src/manifest.json

@@ -5,6 +5,7 @@
   "versionName": "1.0.0",
   "versionCode": "100",
   "transformPx": false,
+  /* 5+App特有相关 */
   "app-plus": {
     "usingComponents": true,
     "nvueStyleCompiler": "uni-app",
@@ -15,8 +16,11 @@
       "autoclose": true,
       "delay": 0
     },
+    /* 模块配置 */
     "modules": {},
+    /* 应用发布信息 */
     "distribute": {
+      /* android打包配置 */
       "android": {
         "permissions": [
           "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
@@ -36,11 +40,15 @@
           "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
         ]
       },
+      /* ios打包配置 */
       "ios": {},
+      /* SDK配置 */
       "sdkConfigs": {}
     }
   },
+  /* 快应用特有相关 */
   "quickapp": {},
+  /* 小程序特有相关 */
   "mp-weixin": {
     "appid": "",
     "setting": {

+ 1 - 0
MiniProgram/src/pages.json

@@ -1,5 +1,6 @@
 {
   "pages": [
+    //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
     {
       "path": "pages/index",
       "style": {

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/assets/style/black-theme.scss

@@ -124,6 +124,7 @@
   --el-message-box-title: #CFD4E6;
   --el-button-text-color: #7C85A6;
   --selected-screen-share-dialog: #006EFF;
+  /* H5新增 */
   --log-out-mobile: rgba(0, 0, 0, 0.7);
   --log-out: #2C2C2E;
   --log-out-cancel: #2C2C2E;

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/assets/style/white-theme.scss

@@ -122,6 +122,7 @@
   --el-message-box-title: #000000;
   --el-button-text-color: #646366;
   --selected-screen-share-dialog: #006EFF;
+  /* H5新增 */
   --log-out-mobile: rgba(0, 0, 0, 0.7);
   --log-out: #F9F9F9C7;
   --log-out-cancel: #FFFFFF;

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/components/Chat/ChatEditor/index.vue

@@ -100,6 +100,7 @@ const {
       justify-content: center;
       align-items: center;
       padding: 5px 0;
+      background-color: var(--background-color-1);
     }
     .emoji-icon{
       width: 20px;

+ 2 - 0
MiniProgram/src/roomkit/TUIRoom/components/Chat/ChatEditor/useChatEditor.ts

@@ -69,6 +69,8 @@ export default function useChatEditor() {
     } catch (e) {
     /**
      * Message delivery failure
+     *
+     * 消息发送失败
     **/
       TUIMessage({ type: 'error', message: t('Failed to send the message') });
     }

+ 4 - 0
MiniProgram/src/roomkit/TUIRoom/components/Chat/util.ts

@@ -1,4 +1,8 @@
 /**
+ * 聊天界面表情输入界面
+ * 需要注意的是, TUIRoomKit 里面的表情包都是有版权限制的,购买的 IM 服务不包括表情包的使用权,请在上线的时候替换成自己的表情包,否则会面临法律风险
+ * 黄脸表情为腾讯云版权所有,如要使用需获得授权,请通过以下链接联系我们。
+ *
  * Emoji input interface in the chat screen.
  * It should be noted that the emoticons in TUIRoomKit are copyrighted. The purchased IM service does not include the
  * right to use the emoticons. Please replace them with your own emoticons when you go online, otherwise you will

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/components/ManageMember/MemberControl/index.vue

@@ -3,6 +3,7 @@
     <div class="member-title">
       <Avatar class="avatar-url" :img-src="userInfo.avatarUrl"></Avatar>
       <div class="member-title-content">{{ userInfo.userName || userInfo.userId }}</div>
+      <!-- TODO: 完善 @tap 的 .stop 修饰符 -->
       <span v-if="isWeChat" @tap.stop="handleCloseControl" class="tab-cancel">{{ t('Cancel') }}</span>
     </div>
     <div

+ 31 - 4
MiniProgram/src/roomkit/TUIRoom/components/ManageMember/MemberControl/useMemberControlHooks.ts

@@ -40,10 +40,18 @@ export default function useMemberControl(props?: any) {
   });
   const kickOffDialogContent = computed(() => t('whether to kick sb off the room', { name: props.userInfo.userName || props.userInfo.userId }));
   const transferOwnerTitle = computed(() => t('Transfer the roomOwner to sb', { name: props.userInfo.userName || props.userInfo.userId }));
-  const { isFreeSpeakMode, isSpeakAfterTakingSeatMode, localUser, isGeneralUser } = storeToRefs(roomStore);
+  const {
+    isFreeSpeakMode,
+    isSpeakAfterTakingSeatMode,
+    localUser,
+    isGeneralUser,
+    anchorUserList,
+    maxSeatCount,
+  } = storeToRefs(roomStore);
   /**
    * Functions related to the Raise Your Hand function
    *
+   * 举手发言功能相关函数
   **/
   const {
     agreeUserOnStage,
@@ -118,14 +126,14 @@ export default function useMemberControl(props?: any) {
   const transferOwner = computed(() => ({
     key: 'transferOwner',
     icon: TransferOwnerIcon,
-    title: t('Transfer owner'),
+    title: t('Make host'),
     func: () => handleOpenDialog('transferOwner'),
   }));
 
   const setOrRevokeAdmin = computed(() => ({
     key: 'setOrRevokeAdmin',
     icon: props.userInfo.userRole === TUIRole.kAdministrator ?  RevokeAdminIcon : SetAdminIcon,
-    title: props.userInfo.userRole === TUIRole.kAdministrator ? t('Revoke administrator') : t('Set as administrator'),
+    title: props.userInfo.userRole === TUIRole.kAdministrator ? t('Remove administrator') : t('Set as administrator'),
     func: handleSetOrRevokeAdmin,
   }));
 
@@ -155,12 +163,21 @@ export default function useMemberControl(props?: any) {
   /**
    * Invitation to the stage/uninvitation to the stage
    *
+   * 邀请上台/取消邀请上台
   **/
   async function toggleInviteUserOnStage(userInfo: UserInfo) {
     const { isInvitingUserToAnchor } = userInfo;
     if (isInvitingUserToAnchor) {
       cancelInviteUserOnStage(userInfo);
     } else {
+      if (anchorUserList.value.length === maxSeatCount.value) {
+        TUIMessage({
+          type: 'warning',
+          message: `${t('The stage is full')}`,
+          duration: MESSAGE_DURATION.NORMAL,
+        });
+        return;
+      }
       inviteUserOnStage(userInfo);
     }
   }
@@ -168,6 +185,7 @@ export default function useMemberControl(props?: any) {
   /**
    * Banning/Unbanning
    *
+   * 禁麦/邀请打开麦克风
   **/
   async function muteUserAudio(userInfo: UserInfo) {
     if (userInfo.hasAudioStream) {
@@ -218,6 +236,7 @@ export default function useMemberControl(props?: any) {
   /**
    * Banned painting/unbanned painting
    *
+   * 禁画/取消禁画
   **/
   async function muteUserVideo(userInfo: UserInfo) {
     if (userInfo.hasVideoStream) {
@@ -267,6 +286,7 @@ export default function useMemberControl(props?: any) {
   /**
    * Allow text chat / Cancel text chat
    *
+   * 允许文字聊天/取消文字聊天
   **/
   function disableUserChat(userInfo: UserInfo) {
     const currentState = userInfo.isChatMutedByMasterOrAdmin;
@@ -280,6 +300,7 @@ export default function useMemberControl(props?: any) {
   /**
    * Kick the user out of the room
    *
+   * 将用户踢出房间
   **/
   async function kickOffUser(userInfo: UserInfo) {
     await roomEngine.instance?.kickRemoteUserOutOfRoom({
@@ -287,6 +308,9 @@ export default function useMemberControl(props?: any) {
     });
   }
 
+  /**
+   * 转移房主给用户
+   */
   async function handleTransferOwner(userInfo: UserInfo) {
     const roomInfo = await roomEngine.instance?.fetchRoomInfo();
     if (roomInfo?.roomOwner === roomStore.localUser.userId) {
@@ -304,13 +328,16 @@ export default function useMemberControl(props?: any) {
       } catch (error) {
         TUIMessage({
           type: 'error',
-          message: t('Transfer owner failed, please try again.'),
+          message: t('Make host failed, please try again.'),
           duration: MESSAGE_DURATION.NORMAL,
         });
       }
     }
   }
 
+  /**
+   * 设置/撤销管理员权限
+   */
   async function handleSetOrRevokeAdmin(userInfo: UserInfo) {
     const newRole = userInfo.userRole === TUIRole.kGeneralUser ? TUIRole.kAdministrator : TUIRole.kGeneralUser;
     await roomEngine.instance?.changeUserRole({

+ 3 - 2
MiniProgram/src/roomkit/TUIRoom/components/ManageMember/MemberItem/useMemberItemHooks.ts

@@ -3,18 +3,19 @@ import { UserInfo, useRoomStore } from '../../../stores/room';
 import { storeToRefs } from 'pinia';
 import { TUIRole } from '@tencentcloud/tuiroom-engine-wx';
 
-const showUserId = ref('');
+const showUserId = ref(''); // 需要展示操作面板的用户id
 
 export default function useMemberItem(userInfo: UserInfo) {
   const roomStore = useRoomStore();
   const { isMaster, isAdmin } = storeToRefs(roomStore);
+  // 是否有权限操作当前用户
   const isCanOperateCurrentMember = computed(() => {
     const isTargetUserRoomOwner = userInfo.userRole === TUIRole.kRoomOwner;
     const isTargetUserGeneral = userInfo.userRole === TUIRole.kGeneralUser;
     return (isMaster.value && !isTargetUserRoomOwner) || (isAdmin.value && isTargetUserGeneral);
   });
   const isMemberControlAccessible = computed(() => (
-    userInfo.userId === showUserId.value) && isCanOperateCurrentMember.value);
+    userInfo.userId === showUserId.value) && isCanOperateCurrentMember.value); // 只有房主或管理员才打开操作面板
 
   function openMemberControl() {
     showUserId.value = userInfo.userId;

+ 3 - 0
MiniProgram/src/roomkit/TUIRoom/components/ManageMember/MemberItemCommon/MemberInfo.vue

@@ -2,8 +2,10 @@
   <!--
       *User base information
       *
+      *用户基础信息
     -->
   <div :class="[isMobile ? 'member-info-mobile' : 'member-info']">
+    <!-- 用户基础信息 -->
     <div :class="!showStateIcon && isTargetUserAdmin ? 'member-basic-info-admin' : 'member-basic-info'">
       <Avatar class="avatar-url" :img-src="userInfo.avatarUrl"></Avatar>
       <div class="user-name">{{ userInfo.userName || userInfo.userId }}</div>
@@ -21,6 +23,7 @@
     <!--
       *User audio and video status information
       *
+      *用户音视频状态信息
     -->
     <div v-if="showStateIcon" class="member-av-state">
       <svg-icon

+ 5 - 2
MiniProgram/src/roomkit/TUIRoom/components/ManageMember/useIndexHooks.ts

@@ -78,6 +78,7 @@ export default function useIndex() {
           ? t('After unlocking, users can freely turn on the microphone')
           : t('Members will not be able to open the microphone');
         stateForAllAudio =  !roomStore.isMicrophoneDisableForAllUser;
+        // 小程序更新视图
         await nextTick();
         dialogActionInfo.value = audioManageInfo.value;
         break;
@@ -88,6 +89,7 @@ export default function useIndex() {
           ? t('After unlocking, users can freely turn on the camera')
           : t('Members will not be able to open the camera');
         stateForAllVideo = !roomStore.isCameraDisableForAllUser;
+        // 小程序更新视图
         await nextTick();
         dialogActionInfo.value = videoManageInfo.value;
         break;
@@ -153,11 +155,12 @@ export default function useIndex() {
   }
 
   const applyToAnchorUserContent = computed(() => {
-    const userName = applyToAnchorList.value[0]?.userName || applyToAnchorList.value[0]?.userId;
+    const lastIndex = applyToAnchorList.value.length - 1;
+    const userName = applyToAnchorList.value[lastIndex]?.userName || applyToAnchorList.value[lastIndex]?.userId;
     if (applyToAnchorList.value.length === 1) {
       return `${userName} ${t('Applying for the stage')}`;
     }
-    return  `${userName} ${t('and so on number people applying to stage', { number: applyToAnchorList.value.length })}`;
+    return `${userName} ${t('and so on number people applying to stage', { number: applyToAnchorList.value.length })}`;
   });
 
   return {

+ 20 - 0
MiniProgram/src/roomkit/TUIRoom/components/RoomContent/StreamContainer/index.vue

@@ -45,6 +45,7 @@
         </div>
       </div>
     </div>
+    <!--左右滑动控制栏 -->
     <div v-if="totalPageNumber > 1" class="swipe">
       <div
         v-for="(item, index) in totalPageNumber"
@@ -148,6 +149,8 @@ const isFirstPageInSixPointLayout: Ref<Boolean> = computed(() => {
 
 /**
  * ----- The following handles the nine-pane page flip logic -----
+ *
+ * ----- 以下处理六宫格翻页逻辑 -----
 **/
 const showStreamList: ComputedRef<StreamInfo[]> = computed(() => {
   if (layout.value === LAYOUT.SIX_EQUAL_POINTS) {
@@ -171,6 +174,8 @@ const showStreamList: ComputedRef<StreamInfo[]> = computed(() => {
 
 /**
  * Show left and right page flip icons
+ *
+ * 显示左右翻页图标
 **/
 const totalPageNumber = computed(() => {
   const videoStreamNumber = onlyVideoStreamList.value.length;
@@ -191,6 +196,7 @@ function isActiveDot(index: number) {
 /**
  * Swipe left to turn the page
  *
+ * 向左滑动翻页
 **/
 async function handleTurnPageLeft() {
   if (currentPageIndex.value === 0) {
@@ -205,6 +211,7 @@ async function handleTurnPageLeft() {
 /**
  * Swipe right to turn the page
  *
+ * 向右滑动翻页
 **/
 async function handleTurnPageRight() {
   if (currentPageIndex.value === totalPageNumber.value - 1) {
@@ -219,6 +226,7 @@ async function handleTurnPageRight() {
 /**
  * ----- The following processing stream layout ---------
  *
+ * ----- 以下处理流布局 ---------
 **/
 const enlargedContainerRef = ref();
 const streamListRef = ref();
@@ -250,9 +258,11 @@ function handleTouchEnd(event:any) {
     return;
   }
   if (moveDirectionX < 0) {
+    // 右滑
     handleTurnPageRight();
   }
   if (moveDirectionX > 0) {
+    // 左滑
     handleTurnPageLeft();
   }
 }
@@ -260,6 +270,7 @@ function handleTouchEnd(event:any) {
 /**
  * --- The following processing stream events ----
  *
+ * --- 以下处理流事件 ----
 **/
 
 
@@ -270,9 +281,12 @@ const onUserVideoStateChanged = async (eventInfo: {
   reason: TUIChangeReason,
 }) => {
   const { userId, streamType, hasVideo, reason } = eventInfo;
+  // 更新 roomStore 流状态数据
   roomStore.updateUserVideoState(userId, streamType, hasVideo);
 
+  // 处理状态变更
   if (userId === basicStore.userId && !hasVideo && reason === TUIChangeReason.kChangedByAdmin) {
+    // 主持人关闭摄像头
     if (streamType === TUIVideoStreamType.kCameraStream) {
       TUIMessage({
         type: 'warning',
@@ -282,8 +296,10 @@ const onUserVideoStateChanged = async (eventInfo: {
       // When the moderator opens the whole staff forbidden to draw,
       // open and then close the single person's camera alone, at this time
       // the corresponding user's camera status for inoperable
+      // 主持人开启全员禁画时,单独打开再关闭单人的摄像头,此时对应用户的摄像头状态为无法操作
       roomStore.setCanControlSelfVideo(!roomStore.isCameraDisableForAllUser);
     }
+    // 主持人关闭屏幕分享
     if (streamType === TUIVideoStreamType.kScreenStream) {
       TUIMessage({
         type: 'warning',
@@ -293,6 +309,7 @@ const onUserVideoStateChanged = async (eventInfo: {
     }
   }
 
+  // 当远端屏幕分享变化的时候,处理流布局
   if (userId !== basicStore.userId && streamType === TUIVideoStreamType.kScreenStream) {
     if (hasVideo) {
       const largeStream = roomStore.remoteStreamObj[`${userId}_${streamType}`] as StreamInfo;
@@ -306,6 +323,7 @@ const onUserVideoStateChanged = async (eventInfo: {
         /**
          * Reset the stream playback layout when the remote screen sharing stream is stopped
          *
+         * 远端屏幕分享流停止的时候,重新设置流播放布局
         **/
         logger.debug(`${logPrefix} onUserVideoStateChanged: stop`, userId, streamType);
         roomEngine.instance?.stopPlayRemoteVideo({
@@ -326,6 +344,7 @@ const onUserVideoStateChanged = async (eventInfo: {
   }
 };
 
+// 计算音量最大的 userId
 function handleLargestVoice(userVolumeList: Array<TRTCVolumeInfo>) {
   if (currentSpeakerUserId.value) {
     const lastSpeakerUserVolumeInfo = userVolumeList.find((item: TRTCVolumeInfo) => (
@@ -353,6 +372,7 @@ function handleLargestVoice(userVolumeList: Array<TRTCVolumeInfo>) {
 
 const handleLargestVoiceThrottle = throttle(handleLargestVoice, 1000);
 
+// 音量变化
 const onUserVoiceVolumeChanged = (eventInfo: {
   userVolumeList: any[],
 }) => {

+ 11 - 0
MiniProgram/src/roomkit/TUIRoom/components/RoomContent/StreamContainer/useStreamContainerHooks.ts

@@ -18,6 +18,7 @@ export default function useStreamContainer() {
   /**
    * --- The following processing stream events ----
    *
+   * --- 以下处理流事件 ----
    **/
   const roomEngine = useGetRoomEngine();
   const basicStore = useBasicStore();
@@ -25,19 +26,23 @@ export default function useStreamContainer() {
   const { t } = useI18n();
   const { deviceManager } = useDeviceManager();
 
+  // 远端用户进入
   const onRemoteUserEnterRoom = (eventInfo: { userInfo: TUIUserInfo }) => {
     roomStore.addRemoteUser(eventInfo.userInfo);
   };
 
+  // 远端用户离开
   const onRemoteUserLeaveRoom = (eventInfo: { userInfo: TUIUserInfo }) => {
     roomStore.removeRemoteUser(eventInfo.userInfo.userId);
   };
 
+  // 麦位变化
   const onSeatListChanged = (eventInfo: { seatList: any[], seatedList: any[], leftList: any[] }) => {
     const { seatedList, leftList } = eventInfo;
     roomStore.updateOnSeatList(seatedList, leftList);
   };
 
+  // 用户音频状态发生改变
   const onUserAudioStateChanged = (eventInfo: {
     userId: string,
     hasAudio: boolean,
@@ -45,7 +50,9 @@ export default function useStreamContainer() {
   }) => {
     const { userId, hasAudio, reason } = eventInfo;
     roomStore.updateUserAudioState(userId, hasAudio);
+    // 处理状态变更
     if (userId === basicStore.userId && !hasAudio && reason === TUIChangeReason.kChangedByAdmin) {
+      // 主持人关闭麦克风
       TUIMessage({
         type: 'warning',
         message: t('Your microphone has been turned off'),
@@ -55,6 +62,7 @@ export default function useStreamContainer() {
        * When the host turns on a full ban, the microphone of a single person is turned on
        * and off separately, and the microphone status of the corresponding user is inoperable at this time
        *
+       * 主持人开启全员禁言时,单独打开再关闭单人的麦克风,此时对应用户的麦克风状态为无法操作
        **/
       roomStore.setCanControlSelfAudio(!roomStore.isMicrophoneDisableForAllUser);
     }
@@ -69,6 +77,7 @@ export default function useStreamContainer() {
       /**
        * Turn on the local camera
        *
+       * 开启本地摄像头
        **/
 
       if (isWeChat) {
@@ -100,6 +109,7 @@ export default function useStreamContainer() {
         /**
          * Set device id
          *
+         * 设置设备id
         **/
         if (!roomStore.currentCameraId) {
           const cameraList = await deviceManager.instance?.getDevicesList({
@@ -116,6 +126,7 @@ export default function useStreamContainer() {
         /**
          * Turn on the local camera
          *
+         * 开启本地摄像头
         **/
         await roomEngine.instance?.setLocalVideoView({
           view: `${roomStore.localStream.userId}_${roomStore.localStream.streamType}`,

+ 2 - 0
MiniProgram/src/roomkit/TUIRoom/components/RoomContent/StreamRegion/index.vue

@@ -183,6 +183,7 @@ onMounted(() => {
  * enlargeUserId The switch requires that both the small window
  * corresponding to the previously played stream and the stream that needs to be newly played be replayed.
  *
+ * enlargeUserId 切换的时候需要让之前播放流对应的小窗口和需要新播放的流都重新播放
 **/
 onMounted(() => {
   watch(
@@ -193,6 +194,7 @@ onMounted(() => {
           /**
            * Replay local video streams only when they are open
            *
+           * 只有当本地视频流是打开状态的时候,才重新播放本地流
           **/
           if (props.stream.hasVideoStream) {
             await roomEngine.instance?.setLocalVideoView({

+ 11 - 2
MiniProgram/src/roomkit/TUIRoom/components/RoomFooter/ApplyControl/MemberApplyControl.vue

@@ -125,6 +125,7 @@ const currentDialogInfo = computed(() => (currentDialogType.value === 'inviteDia
 /**
  * Send a request to be on the mike
  *
+ * 发送上麦申请
 **/
 async function sendSeatApplication() {
   if (isAdmin.value) {
@@ -153,7 +154,7 @@ async function sendSeatApplication() {
           TUIMessage({ type: 'warning', message: t('Application to go on stage was rejected') });
           break;
         case TUIRequestCallbackType.kRequestTimeout:
-          TUIMessage({ type: 'warning', message: t('Failed to go on stage, invitation has timed out') });
+          TUIMessage({ type: 'warning', message: t('The request to go on stage has timed out') });
           break;
       }
     },
@@ -167,7 +168,9 @@ async function sendSeatApplication() {
 /**
  * Cancellation of on-mike application
  *
+ * 处理点击【创建房间】
 **/
+// 取消上麦申请
 async function cancelSeatApplication() {
   TUIMessage({
     type: 'info',
@@ -185,6 +188,7 @@ async function cancelSeatApplication() {
 /**
  * User Down Mack
  *
+ * 用户下麦
 **/
 function handleStepDownDialogVisible() {
   showDialog.value = !showDialog.value;
@@ -210,6 +214,7 @@ function hideApplyAttention() {
 /**
  * Handling host or administrator invitation to on-stage signalling
  *
+ * 处理主持人或管理员邀请上台信令
 **/
 async function onRequestReceived(eventInfo: { request: TUIRequest }) {
   const { request: { userId, requestId, requestAction } } = eventInfo;
@@ -226,6 +231,7 @@ async function onRequestReceived(eventInfo: { request: TUIRequest }) {
 /**
    * The host canceled the invitation to the microphone
    *
+   * 主持人取消邀请上麦
   **/
 function onRequestCancelled(eventInfo: { requestId: string; userId: string }) {
   const { requestId } = eventInfo;
@@ -238,6 +244,7 @@ function onRequestCancelled(eventInfo: { requestId: string; userId: string }) {
 /**
  * User accepts/rejects the presenter's invitation
  *
+ * 用户接受/拒绝主讲人的邀请
 **/
 async function handleInvite(agree: boolean) {
   try {
@@ -247,7 +254,7 @@ async function handleInvite(agree: boolean) {
     });
   } catch (error: any) {
     if (error.code === TUIErrorCode.ERR_ALL_SEAT_OCCUPIED) {
-      TUIMessage({ type: 'warning', message: t('The current number of people on stage has reached the limit') });
+      TUIMessage({ type: 'warning', message: t('The stage is full, please contact the host') });
     } else {
       logger.error('Failure of a user to accept/reject a roomOwner invitation', error);
     }
@@ -258,8 +265,10 @@ async function handleInvite(agree: boolean) {
 
 /**
  * Kicked off the seat by the host
+ * 被主持人踢下麦
  */
 async function onKickedOffSeat() {
+  // 被主持人踢下麦
   TUIMessage({
     type: 'warning',
     message: t('You have been invited by the host to step down, please raise your hand if you need to speak'),

+ 12 - 1
MiniProgram/src/roomkit/TUIRoom/components/RoomFooter/AudioControl.vue

@@ -1,10 +1,15 @@
 <!--
-  * Name: IconButton
+  * 名称: IconButton
   * @param name String required
   * @param size String 'large'|'medium'|'small'
   * Usage:
   * Use <audio-control /> in the template
   *
+  * Name: IconButton
+  * @param name String required
+  * @param size String 'large'|'medium'|'small'
+  * 使用方式:
+  * 在 template 中使用 <audio-control />
 -->
 <template>
   <div>
@@ -102,6 +107,7 @@ async function toggleMuteAudio() {
   }
   if (localStream.value.hasAudioStream) {
     await roomEngine.instance?.muteLocalAudio();
+    // 如果是全员禁言状态下,用户主动关闭麦克风之后不能再自己打开
     if (roomStore.isMicrophoneDisableForAllUser) {
       roomStore.setCanControlSelfAudio(false);
     }
@@ -116,6 +122,7 @@ async function toggleMuteAudio() {
       });
       return;
     }
+    // 有麦克风列表且有权限
     await roomEngine.instance?.unmuteLocalAudio();
     if (!basicStore.isOpenMic) {
       roomEngine.instance?.openLocalMicrophone();
@@ -127,6 +134,7 @@ async function toggleMuteAudio() {
 /**
  * Handling host or administrator turn on/off microphone signalling
  *
+ * 处理主持人或管理员打开/关闭麦克风信令
 **/
 const showRequestOpenMicDialog: Ref<boolean> = ref(false);
 const requestOpenMicRequestId: Ref<string> = ref('');
@@ -139,6 +147,7 @@ async function onRequestReceived(eventInfo: { request: TUIRequest }) {
     showRequestOpenMicDialog.value = true;
   }
 }
+// 接受主持人邀请,打开麦克风
 async function handleAccept() {
   roomStore.setCanControlSelfAudio(true);
   await roomEngine.instance?.responseRemoteRequest({
@@ -149,6 +158,7 @@ async function handleAccept() {
   showRequestOpenMicDialog.value = false;
 }
 
+// 保持静音
 async function handleReject() {
   await roomEngine.instance?.responseRemoteRequest({
     requestId: requestOpenMicRequestId.value,
@@ -158,6 +168,7 @@ async function handleReject() {
   showRequestOpenMicDialog.value = false;
 }
 
+// 请求被取消
 async function onRequestCancelled(eventInfo: { requestId: string }) {
   const { requestId } = eventInfo;
   if (requestOpenMicRequestId.value === requestId) {

+ 3 - 0
MiniProgram/src/roomkit/TUIRoom/components/RoomFooter/EndControl/index.vue

@@ -146,6 +146,7 @@ function handleEndLeaveClick() {
 /**
  * Active room dismissal
  *
+ * 主动解散房间
  **/
 async function dismissRoom() {
   try {
@@ -162,6 +163,7 @@ async function dismissRoom() {
 /**
  * Leave the room voluntarily
  *
+ * 主动离开房间
  **/
 async function leaveRoom() {
   // eslint-disable-line
@@ -199,6 +201,7 @@ async function transferAndLeave() {
 /**
  * notification of room dismissal from the host
  *
+ * 收到主持人解散房间通知
  **/
 const onRoomDismissed = async (eventInfo: { roomId: string }) => {
   try {

+ 7 - 0
MiniProgram/src/roomkit/TUIRoom/components/RoomFooter/ScreenShareControl/Index.vue

@@ -85,6 +85,7 @@ const isSharing: Ref<boolean> = ref(false);
 const dialogVisible: Ref<boolean> = ref(false);
 const isShowFraudDialog: Ref<boolean> = ref(false);
 
+// 麦下用户不能进行屏幕分享
 const screenShareDisabled = computed(() => isAudience.value);
 const title = computed(() => (isSharing.value ? t('End sharing') : t('Share screen')));
 
@@ -138,18 +139,23 @@ async function startScreenShare() {
   } catch (error: any) {
     logger.error(`${logPrefix}startScreenShare error:`, error.name, error.message, error.code);
     let message = '';
+    // 当屏幕分享流初始化失败时, 提醒用户并停止后续进房发布流程
     switch (error.name) {
       case 'NotReadableError':
+        // 提醒用户确保系统允许当前浏览器获取屏幕内容
         message = '系统禁止当前浏览器获取屏幕内容';
         break;
       case 'NotAllowedError':
         if (error.message.includes('Permission denied by system')) {
+          // 提醒用户确保系统允许当前浏览器获取屏幕内容
           message = '系统禁止当前浏览器获取屏幕内容';
         } else {
+          // 用户拒绝/取消屏幕分享
           message = '用户拒绝/取消屏幕分享';
         }
         break;
       default:
+        // 初始化屏幕分享流时遇到了未知错误,提醒用户重试
         message = '屏幕分享遇到未知错误';
         break;
     }
@@ -173,6 +179,7 @@ async function stopScreenShare() {
   }
 }
 
+/** 用户点击浏览器自带的 "停止共享" 按钮*/
 function screenCaptureStopped() {
   isSharing.value = false;
 }

+ 13 - 1
MiniProgram/src/roomkit/TUIRoom/components/RoomFooter/VideoControl.vue

@@ -1,10 +1,15 @@
 <!--
-  * Name: IconButton
+  * 名称: IconButton
   * @param name String required
   * @param size String 'large'|'medium'|'small'
   * Usage:
   * Use <audio-control /> in the template
   *
+  * Name: IconButton
+  * @param name String required
+  * @param size String 'large'|'medium'|'small'
+  * 使用方式:
+  * 在 template 中使用 <audio-control />
 -->
 <template>
   <div>
@@ -99,6 +104,7 @@ async function toggleMuteVideo() {
 
   if (localStream.value.hasVideoStream) {
     await roomEngine.instance?.closeLocalCamera();
+    // 如果是全员禁画状态下,用户主动关闭摄像头之后不能再自己打开
     if (roomStore.isCameraDisableForAllUser) {
       roomStore.setCanControlSelfVideo(false);
     }
@@ -107,6 +113,7 @@ async function toggleMuteVideo() {
       type: TUIMediaDeviceType.kMediaDeviceTypeVideoCamera,
     });
     const hasCameraDevice = cameraList && cameraList.length > 0;
+    // 无摄像头列表
     if (!hasCameraDevice && !isWeChat) {
       TUIMessageBox({
         title: t('Note'),
@@ -115,6 +122,7 @@ async function toggleMuteVideo() {
       });
       return;
     }
+    // 有摄像头列表
     roomEngine.instance?.setLocalVideoView({
       view: `${roomStore.localStream.userId}_${roomStore.localStream.streamType}`,
     });
@@ -135,6 +143,7 @@ async function toggleMuteVideo() {
 /**
  * Handling host or administrator turn on/off camera signalling
  *
+ * 处理主持人或管理员打开/关闭摄像头信令
 **/
 const showRequestOpenCameraDialog: Ref<boolean> = ref(false);
 const requestOpenCameraRequestId: Ref<string> = ref('');
@@ -148,6 +157,7 @@ async function onRequestReceived(eventInfo: { request: TUIRequest }) {
   }
 }
 
+// 接受主持人邀请,打开摄像头
 async function handleAccept() {
   roomStore.setCanControlSelfVideo(true);
   roomEngine.instance?.setLocalVideoView({
@@ -161,6 +171,7 @@ async function handleAccept() {
   showRequestOpenCameraDialog.value = false;
 }
 
+// 保持静音
 async function handleReject() {
   await roomEngine.instance?.responseRemoteRequest({
     requestId: requestOpenCameraRequestId.value,
@@ -170,6 +181,7 @@ async function handleReject() {
   showRequestOpenCameraDialog.value = false;
 }
 
+// 请求被取消
 async function onRequestCancelled(eventInfo: { requestId: string }) {
   const { requestId } = eventInfo;
   if (requestOpenCameraRequestId.value === requestId) {

+ 2 - 2
MiniProgram/src/roomkit/TUIRoom/components/RoomHeader/RoomInfo/useRoomInfoHooks.ts

@@ -14,7 +14,7 @@ export default function useRoomInfo() {
   const basicStore = useBasicStore();
   const roomStore = useRoomStore();
   const { roomId, isRoomLinkVisible } = storeToRefs(basicStore);
-  const { masterUserId } = storeToRefs(roomStore);
+  const { masterUserId, roomName } = storeToRefs(roomStore);
   const { t } = useI18n();
   const isShowRoomInfo = ref(false);
   const roomType = computed(() => (roomStore.isFreeSpeakMode ? t('Free Speech Room') : t('On-stage Speaking Room')));
@@ -25,7 +25,7 @@ export default function useRoomInfo() {
 
   const isShowRoomInfoTitle = computed(() => masterUserName.value);
 
-  const conferenceTitle = computed(() => `${masterUserName.value}${t('Quick Meeting')}`);
+  const conferenceTitle = computed(() => `${roomName.value}`);
 
   const roomInfoTabList = computed(() => [
     { id: 1, title: 'Host', content: masterUserName.value, copyLink: '', isShowCopyIcon: false, visible: true },

+ 5 - 0
MiniProgram/src/roomkit/TUIRoom/components/RoomHeader/UserInfo/useUserInfoHooks.ts

@@ -21,6 +21,7 @@ export default function useUserInfo() {
   /**
      * Whether to display the user information operation box
      *
+     * 是否显示用户信息操作框
     **/
   function handleUserControl() {
     showUserControl.value = !showUserControl.value;
@@ -29,6 +30,7 @@ export default function useUserInfo() {
   /**
      * Hide the user information action box
      *
+     * 隐藏用户信息操作框
     **/
   function hideUserControl(event: Event) {
     if (!userInfoRef.value.contains(event.target)) {
@@ -39,6 +41,7 @@ export default function useUserInfo() {
   /**
      * Show change name dialog
      *
+     * 展示修改名字 dialog
     **/
   function showEditUserNameDialog() {
     showUserNameEdit.value = true;
@@ -48,6 +51,7 @@ export default function useUserInfo() {
   /**
      * Close the modify name dialog
      *
+     * 关闭修改名字的 dialog
     **/
   function closeEditUserNameDialog() {
     showUserNameEdit.value = false;
@@ -56,6 +60,7 @@ export default function useUserInfo() {
   /**
      * Save the new userName
      *
+     * 保存新的 userName
     **/
   async function handleSaveUserName(userName: string) {
     if (userName.length === 0) {

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/components/RoomLogin/VerifyCode.vue

@@ -37,6 +37,7 @@ watch(() => verifyStates.verifyCode, (val) => {
   /**
    * Get the verification code
    *
+   * 获取到验证码
   **/
   emit('update-verify-code', verifyStates.verifyCode);
 });

+ 4 - 0
MiniProgram/src/roomkit/TUIRoom/components/RoomSetting/index.vue

@@ -57,10 +57,14 @@ const { showSettingDialog, activeSettingTab } = storeToRefs(basicStore);
 /**
  * TODO: Refine the rest of the settings Tab
  *
+ * TODO: 完善其余设置 Tab
  **/
 const settingTabsTitleList = computed(() => [
   { label: t('Audio settings'), value: 'audio' },
   { label: t('Camera settings'), value: 'video' },
+  // { label: '美颜和虚拟设置', value: 'beauty' },
+  // { label: '统计功能', value: 'static' },
+  // { label: '录制', value: 'record' },
 ]);
 
 function handleUpdateActiveTab(tabTitle: string) {

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/components/RoomSidebar/useSideBarHooks.ts

@@ -48,6 +48,7 @@ export default function useSideBar() {
     done();
   }
 
+  /** 监听消息接收,放在这里是为了打开 chat 之前只记录消息未读数 */
   const onReceiveMessage = (options: { data: any }) => {
     if (!options || !options.data) {
       return;

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/ArrowStroke.vue

@@ -20,6 +20,7 @@ interface Props {
   strokePosition: string;
   // 'up' | 'down' | 'left' | 'right'
   arrowDirection: string;
+  // 是否展示线条
   hasStroke: boolean,
 }
 

+ 6 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/AudioMediaControl.vue

@@ -6,6 +6,12 @@
   * Usage:
   * Use <audio-media-control /> in the template
   *
+  * 名称: AudioMediaControl 音频媒体操作组件(开关麦克风)
+  * @param hasMore boolean 是否展示【更多】icon, 可以切换麦克风和扬声器
+  * @param isMuted boolean 音频是否被静音状态
+  * @param isDisabled boolean 音频是否 disabled 状态
+  * 使用方式:
+  * 在 template 中使用 <audio-media-control />
 -->
 <template>
   <div>

+ 7 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/AudioSettingTab.vue

@@ -5,6 +5,11 @@
   * Usage:
   * Use <video-tab></video-tab> in the template
   *
+  * 名称: VideoTab
+  * @param name String required
+  * @param size String 'large'|'medium'|'small'
+  * 使用方式:
+  * 在 template 中使用 <video-tab></video-tab>
 -->
 <template>
   <div :class="['audio-setting-tab', themeClass]">
@@ -103,6 +108,7 @@ const isTestingMicrophone = ref(false);
 /**
  * Click on the microphone [Test] button
  *
+ * 点击麦克风【测试】按钮
 **/
 function handleMicrophoneTest() {
   isTestingMicrophone.value = !isTestingMicrophone.value;
@@ -115,6 +121,7 @@ const { t } = useI18n();
 /**
  * Click on the speaker [Test] button
  *
+ * 点击扬声器【测试】按钮
 **/
 async function handleSpeakerTest() {
   const SPEAKER_TEST_URL = 'https://web.sdk.qcloud.com/trtc/electron/download/resources/media/TestSpeaker.mp3';

+ 5 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/DeviceSelect.vue

@@ -5,6 +5,11 @@
   * Usage:
   * Use <device-select></device-select> in template
   *
+  * 名称: DeviceSelect
+  * @param deviceType String required
+  * @param size String 'large'|'medium'|'small'
+  * 使用方式:
+  * 在 template 中使用 <device-select></device-select>
 -->
 <template>
   <tui-select

+ 4 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/Logo.vue

@@ -1,12 +1,15 @@
 <!-- eslint-disable max-len -->
 <template>
   <div class="logo-container">
+    <!-- PC 端中文黑色主题下 logo -->
     <div v-if="!isMobile && isZH && isBlackTheme">
       <svg-icon style="display: flex" :icon="LogoOfPCInChineseBlackIcon"></svg-icon>
     </div>
+    <!-- PC 端中文白色主题下 logo -->
     <div v-if="!isMobile && isZH && isWhiteTheme">
       <svg-icon style="display: flex" :icon="LogoOfPCInChineseWhiteIcon"></svg-icon>
     </div>
+    <!-- 移动端中文黑白主题 logo -->
     <div v-if="isMobile && isZH" class="mobile-zh-logo">
       <span class="logo" :class="isWhiteTheme ? 'white' : 'black'">
         <svg-icon style="display: flex" :icon="LogoOfMobileInChinese"></svg-icon>
@@ -15,6 +18,7 @@
         <svg-icon style="display: flex" :icon="LogoTitleOfMobileInChinese"></svg-icon>
       </span>
     </div>
+    <!-- 英文黑白主题 logo -->
     <div v-if="isEN" :class="['pc-en-logo', { 'mobile': isMobile }]">
       <span class="logo">
         <svg-icon style="display: flex" :icon="LogoInEnglish"></svg-icon>

+ 3 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/SwitchTheme.vue

@@ -3,6 +3,9 @@
   * Usage:
   * Use <switch-theme /> in template
   *
+  * 名称: Switchtheme
+  * 使用方式:
+  * 在 template 中使用 <switch-theme />
 -->
 <template>
   <icon-button

+ 6 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/VideoMediaControl.vue

@@ -6,6 +6,12 @@
   * Usage:
   * Use <video-media-control :isMuted="isMuted" /> in the template
   *
+  * 名称: VideoMediaControl 视频媒体操作组件(开关摄像头)
+  * @param hasMore boolean 是否展示【更多】icon, 可以切换摄像头
+  * @param isMuted boolean 视频是否被静画状态
+  * @param isDisabled boolean 视频是否 disabled 状态
+  * 使用方式:
+  * 在 template 中使用 <video-media-control :isMuted="isMuted" />
 -->
 <template>
   <div>

+ 5 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/VideoProfile.vue

@@ -5,6 +5,11 @@
   * Usage:
   * Use <device-select></device-select> in template
   *
+  * 名称: DeviceSelect
+  * @param deviceType String required
+  * @param size String 'large'|'medium'|'small'
+  * 使用方式:
+  * 在 template 中使用 <device-select></device-select>
 -->
 <template>
   <tui-select

+ 8 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/VideoSettingTab.vue

@@ -5,6 +5,11 @@
   * Usage:
   * Use <video-tab></video-tab> in the template
   *
+  * 名称: VideoTab
+  * @param name String required
+  * @param size String 'large'|'medium'|'small'
+  * 使用方式:
+  * 在 template 中使用 <video-tab></video-tab>
 -->
 <template>
   <div :class="['video-tab', themeClass]">
@@ -27,6 +32,7 @@
       <tui-switch v-model="isLocalStreamMirror"></tui-switch>
     </div>
     <div v-if="withMore" class="item-setting">
+      <!-- TODO: <div class="item">美颜与虚拟背景</div> -->
       <div class="item" @click="handleMoreCameraSetting">{{ t('More Camera Settings') }}</div>
     </div>
   </div>
@@ -76,6 +82,7 @@ const { t } = useI18n();
 /**
  * Click [More Camera Settings].
  *
+ * 点击【更多摄像头设置】
 **/
 function handleMoreCameraSetting() {
   basicStore.setShowSettingDialog(true);
@@ -86,6 +93,7 @@ if (props.withPreview) {
   onMounted(async () => {
     roomEngine.instance?.startCameraDeviceTest({ view: 'test-camera-preview' });
     if (isElectron) {
+      // Electron 需要首次设置 mirrorType
       const trtcCloud = roomEngine.instance?.getTRTCCloud();
       await trtcCloud?.setLocalRenderParams({
         mirrorType: isLocalStreamMirror.value

+ 11 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/base/Drawer.vue

@@ -10,6 +10,17 @@
   * Usage:
   * Use <Drawer title="there is title" v-model="showDrawer"></Drawer> in template
   *
+  * 名称: Drawer
+  * @param title String required [Drawer 的标题]
+  * @param modelValue Boolean [控制是否显示 Drawer]
+  * @param modal Boolean [Drawer 是否有遮罩层]
+  * @param size number | string [Drawer 的宽度]
+  * @param beforeClose (done: DoneFn) => void; [Drawer 关闭前的回调函数]
+  * @param closeOnClickModal Boolean [是否支持点击遮罩层关闭 Drawer]
+  * @param showClose Boolean [是否展示关闭按钮]
+  * @param appendToBody Boolean [是否插入到 body 中]
+  * 使用方式:
+  * 在 template 中使用 <Drawer title="there is title" v-model="showDrawer"></Drawer>
 -->
 <template>
   <div

+ 7 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/base/IconButton.vue

@@ -7,6 +7,13 @@
   * Usage:
   * Use <icon-button :icon="chatIcon"><icon-button> in template
   *
+  * 名称: IconButton
+  * @param title String required
+  * @param hasMore Boolean
+  * @param hideHoverEffect Boolean
+  * @param layout IconButtonLayout.VERTICAl | IconButtonLayout.HORIZONTAL
+  * 使用方式:
+  * 在 template 中使用 <icon-button :icon="chatIcon"><icon-button>
 -->
 <template>
   <div class="icon-button-container">

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/components/common/base/Select.vue

@@ -118,6 +118,7 @@ function handleClickSelect() {
   }
 }
 
+// 根据页面位置确定下拉框的定位
 function handleDropDownPosition() {
   const { top, bottom } = selectContainerRef.value?.getBoundingClientRect();
   const container = roomService.getRoomContainer();

+ 7 - 1
MiniProgram/src/roomkit/TUIRoom/components/common/base/SvgIcon.vue

@@ -1,9 +1,12 @@
 <!--
-  * Name:SvgIcon
+  * 名称:SvgIcon
   * @param name String required
   * @param size String | number
   * Usage:
   * Use <svg-icon><chat-icon></chat-icon></svg-icon> in template
+
+  * 使用方式:
+  * 在 template 中使用 <svg-icon><chat-icon></chat-icon></svg-icon>
 -->
 <template>
   <span class="svg-icon" :class="customClass" :style="customStyle" @click="handleClick">
@@ -40,6 +43,7 @@ const customStyle: Ref<{
   height?: string,
 }> = ref({});
 
+// 从 svg 文件里读取宽高参数
 uni.getFileSystemManager().readFile({
   filePath: props.icon,
   encoding: 'binary',
@@ -91,6 +95,7 @@ const themeColorMap: Record<string, any> = {
 
 watch([defaultTheme, currentColor, () => props.icon], ([theme, currentColor]) => {
   const { baseColor, activeColor } = themeColorMap[theme];
+  // 读取 svg 内容编码为 base64
   uni.getFileSystemManager().readFile({
     filePath: props.icon,
     encoding: 'binary',
@@ -98,6 +103,7 @@ watch([defaultTheme, currentColor, () => props.icon], ([theme, currentColor]) =>
       const baseStr = res.data
         .replace(/currentColor/g, currentColor || baseColor)
         .replace(/var\(--active-color-2\)/g, activeColor);
+      // 将 svg 数据进行 URL 编码
       customStyle.value.backgroundImage = `url("data:image/svg+xml,${encodeURIComponent(baseStr)}");`;
     },
   });

+ 2 - 2
MiniProgram/src/roomkit/TUIRoom/constants/room.ts

@@ -1,8 +1,8 @@
 import { TRTCVideoResolution } from '@tencentcloud/tuiroom-engine-wx';
 
 export enum SpeechMode {
-  FREE_SPEECH = 'FreeSpeech',
-  APPLY_SPEECH = 'ApplySpeech',
+  FREE_SPEECH = 'FreeSpeech', // 自由发言模式
+  APPLY_SPEECH = 'ApplySpeech', // 申请发言模式
 }
 
 export enum IconButtonLayout {

+ 1 - 1
MiniProgram/src/roomkit/TUIRoom/extension/RoomMessageCard/RoomMessageCard.vue

@@ -12,7 +12,7 @@
         </div>
         <div class="content-desc">
           <div class="title">
-            {{ `${roomCardData.ownerName || roomCardData.owner}${t('Quick Meeting')}` }}
+            {{ `${roomCardData.ownerName || roomCardData.owner}${t('Quick Conference')}` }}
           </div>
           <ul class="users">
             <template

+ 5 - 0
MiniProgram/src/roomkit/TUIRoom/extension/RoomMessageCard/handleRoomMessage.ts

@@ -3,6 +3,10 @@ import { Message, Profile } from '@tencentcloud/chat';
 import { getIsRoomCardMessage } from '../utils/judgeRoomMessage';
 
 /**
+ * 渲染卡片需要用到 isRoomMessage、isRoomCreateByMe、userList、isEnterRoom
+ * ChatExtension 提供基础功能 编辑消息 发送消息 消息上屏等
+ * HandleRoomMessage 实现业务功能 发起会议、加入会议、离开会议等
+ *
  * Rendering cards requires isRoomMessage, isRoomCreateByMe, userList, isEnterRoom
  * ChatExtension provides basic functions such as editing messages, sending messages, displaying messages on the screen.
  * HandleRoomMessage implements business functions such as initiating meetings, joining meetings, leaving meetings.
@@ -31,6 +35,7 @@ export class HandleRoomMessage {
     chatExtension.setHistoryMeetingMessageList('delete', { ID: this.message.ID, messageData: this.messageData });
   }
 
+  // 获取卡片信息
   private handleMessage(message: Message) {
     this.message = message;
     const currentUser = chatExtension.chatContext?.userID;

+ 30 - 22
MiniProgram/src/roomkit/TUIRoom/extension/chatExtension.ts

@@ -47,15 +47,15 @@ const getRoomOptions = () => ({
 });
 export interface CustomMessagePayload {
   version: number
-  businessID: string
-  groupId: string
-  messageId: string
-  roomId: string
-  owner: string
-  ownerName: string
-  roomState: RoomState
-  memberCount: 1
-  userList: Array<{ faceUrl: string; nickName: string; userId: string }>
+  businessID: string // 固定值,用于在IM上区分当前消息是哪类自定义消息。
+  groupId: string // 邀请群成员入会时,需要用到groupId来获取群成员列表。
+  messageId: string // 用于观众成为房主后,通过messageId 来查找并更新指定消息。
+  roomId: string // 房间的id,enterRoom 必须的参数
+  owner: string // 房主的userId
+  ownerName: string // 房主的userName
+  roomState: RoomState // 当前的房间状态,有creating/created/destroying/destroyed 四种状态
+  memberCount: 1 // 当前房间内有多少人,需要在ui上展示有多少人在会议中。
+  userList: Array<{ faceUrl: string; nickName: string; userId: string }> // 包括房主在内的被邀请用户的列表,最多展示5个,防止消息长度超出限制。
 }
 export enum RoomState {
   CREATING = 'creating',
@@ -69,6 +69,7 @@ export enum ChatType {
   CUSTOM_SERVICE = 'customerService',
   ROOM = 'room'
 }
+// message 的编辑都交给房主处理,因此需要拿到每条message 然后对比 userid 相同的时候将其赋给message
 export class ChatExtension {
   static instance?: ChatExtension;
   private message = {} as Message;
@@ -225,8 +226,8 @@ export class ChatExtension {
       const [profile] = profileResult.data;
       const { userID, nick } = profile;
       await this.modifyMessage(this.message.ID, {
-        owner: userID,
-        ownerName: nick,
+        owner: userID, // 房主的userId
+        ownerName: nick, // 房主的userName
       });
     }
   }
@@ -237,7 +238,7 @@ export class ChatExtension {
     const chatType: ChatType = params?.chatType;
     const extension: ExtensionInfo = {
       weight: -1,
-      text: this.service?.t('quick meeting') || '快速会议',
+      text: this.service?.t('quick conference') || '快速会议',
       icon: 'https://qcloudimg.tencent-cloud.cn/raw/148ab10dfe654076b41f0d0945bb82e8.png',
       data: {
         name: 'quickRoom',
@@ -248,7 +249,7 @@ export class ChatExtension {
         },
       },
     };
-    if (!chatType) return extension;
+    if (!chatType) return extension; // 老版本 chatType === undefined 忽略配置直接 return
     if (!this.chatExtensionSetting[chatType]) return;
     return extension;
   }
@@ -308,6 +309,7 @@ export class ChatExtension {
   public async onNotifyEvent(eventName: string, subKey: string, params?: Record<string, any>) {
     if (eventName === TUIConstants.TUILogin.EVENT.LOGIN_STATE_CHANGED) {
       if (subKey === TUIConstants.TUILogin.EVENT_SUB_KEY.USER_LOGIN_SUCCESS) {
+        // 收到登录成功时执行自己的业务逻辑处理
         !isMobile && setDragAndResize('#roomContainer');
         TUIRoomEngine?.callExperimentalAPI(JSON.stringify({
           api: 'setFramework',
@@ -344,11 +346,17 @@ export class ChatExtension {
     const { SDKAppID, userID, userSig } = this.chatContext;
     const { nick = '', avatar = defaultAvatarUrl } = this.myProfile;
     this.service && this.service[deep ? 'initRoomKit' : 'storeInit']({
+      // 获取 sdkAppId 请您参考 步骤一
       sdkAppId: SDKAppID,
+      // 用户在您业务中的唯一标示 Id
       userId: userID,
+      // 本地开发调试可在 https://console.cloud.tencent.com/trtc/usersigtool 页面快速生成 userSig, 注意 userSig 与 userId 为一一对应关系
       userSig,
+      // 用户在您业务中使用的昵称
       userName: nick,
+      // 用户在您业务中使用的头像链接
       avatarUrl: avatar,
+      // 用户在您业务中需要的皮肤主题颜色及是否支持切换皮肤主题
       theme: {
         isSupportSwitchTheme: false,
       },
@@ -428,20 +436,20 @@ export class ChatExtension {
       data: JSON.stringify({
         version: 1,
         businessID: 'group_room_message',
-        groupId: conversationID,
-        messageId: '',
-        roomId,
-        owner: userID,
-        ownerName: nick,
-        roomState,
-        memberCount: 1,
+        groupId: conversationID, // todo 当前版本暂不修改,等待im方案
+        messageId: '', // 用于观众成为房主后,通过 messageId 来查找并更新指定消息。
+        roomId, // 房间的id,enterRoom 必须的参数
+        owner: userID, // 房主的userId
+        ownerName: nick, // 房主的userName
+        roomState, // 当前的房间状态,有creating/created/destroying/destroyed 四种状态
+        memberCount: 1, // 当前房间内有多少人,需要在ui上展示有多少人在会议中。
         userList: [
           {
             faceUrl: avatar,
             nickName: nick,
             userId: userID,
           },
-        ],
+        ], // 包括房主在内的被邀请用户的列表,最多展示5个,防止消息长度超出限制。
       }),
     };
     return payload;
@@ -459,7 +467,7 @@ export class ChatExtension {
   private getUserProfile(userIDList: Array<string>) {
     const { chat } = this.chatContext;
     return chat.getUserProfile({
-      userIDList,
+      userIDList, // 请注意:即使只拉取一个用户的资料,也需要用数组类型,例如:userIDList: ['user1']
     });
   }
 

+ 2 - 0
MiniProgram/src/roomkit/TUIRoom/extension/utils/interact.ts

@@ -18,6 +18,7 @@ export const setDragAndResize = (domSelect: string) => {
         let x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
         let y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
 
+        // 限制拖拽边界不超过屏幕
         x = Math.min(screenWidth - target.offsetWidth + minWidth - 100, Math.max(-minWidth + 100, x));
         y = Math.min(screenHeight - target.offsetHeight + minHeight - 100, Math.max(-minHeight + 100, y));
 
@@ -35,6 +36,7 @@ export const setDragAndResize = (domSelect: string) => {
           x = (parseFloat(x) || 0) + event.deltaRect.left;
           y = (parseFloat(y) || 0) + event.deltaRect.top;
 
+          // 限制缩放最小值
           const width = Math.max(minWidth, event.rect.width);
           const height = Math.max(minHeight, event.rect.height);
 

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/hooks/useDeviceManager.ts

@@ -83,6 +83,7 @@ export default function (options?: { listenForDeviceChange: boolean }) {
   /**
    * Device changes: device switching, device plugging and unplugging events
    *
+   * 设备变化:设备切换、设备插拔事件
   **/
   async function onDeviceChanged(eventInfo: {deviceId: string, type: TUIMediaDeviceType, state: TUIMediaDeviceState}) {
     if (!deviceManager.instance) {

+ 42 - 12
MiniProgram/src/roomkit/TUIRoom/hooks/useMasterApplyControl.ts

@@ -1,3 +1,6 @@
+// 举手发言逻辑
+// 主持人:同意/拒绝用户的申请发言,踢人下麦,邀请用户上麦,取消邀请用户上麦
+
 import { onBeforeUnmount, computed, watch } from 'vue';
 import { TUIRoomEngine, TUIRoomEvents, TUIRequestAction, TUIRequest, TUIRequestCallbackType, TUIErrorCode } from '@tencentcloud/tuiroom-engine-wx';
 import useGetRoomEngine from './useRoomEngine';
@@ -23,23 +26,30 @@ export default function () {
   const applyToAnchorUserIdList = computed(() => applyToAnchorList.value.map(item => item.userId));
   const applyToAnchorUserCount = computed(() => applyToAnchorList.value.length);
 
+  // ------ 以下处理普通用户操作 ---------
+
+  // new: 收到来自用户的上麦申请
   function onRequestReceived(eventInfo: { request: TUIRequest }) {
     const { requestAction, requestId, userId, timestamp } = eventInfo.request;
     if (requestAction === TUIRequestAction.kRequestToTakeSeat) {
+      // 用户申请上麦
       userId && roomStore.addApplyToAnchorUser({ userId, requestId, timestamp });
     }
   }
 
+  // 远端用户取消上麦申请
   function onRequestCancelled(eventInfo: { requestId: string, userId: string }) {
     const { requestId } = eventInfo;
     roomStore.removeApplyToAnchorUser(requestId);
   }
 
+  // 远端用户的请求被其他 管理员/房主 处理事件
   function onRequestProcessed(eventInfo: { requestId: string, userId: string }) {
     const { requestId } = eventInfo;
     roomStore.removeApplyToAnchorUser(requestId);
   }
 
+  // 处理用户请求
   async function handleUserApply(applyUserId: string, agree: boolean) {
     try {
       // TUIRoomCore.replySpeechApplication(applyUserId, agree);
@@ -52,17 +62,18 @@ export default function () {
         });
         roomStore.removeApplyToAnchorUser(requestId);
       } else {
-        logger.warn('Failed to process the take stage request, data exception, please try again!', userInfo);
+        logger.warn('处理上台申请失败,数据异常,请重试!', userInfo);
       }
     } catch (error: any) {
       if (error.code === TUIErrorCode.ERR_ALL_SEAT_OCCUPIED) {
-        TUIMessage({ type: 'warning', message: t('The current number of people on stage has reached the limit') });
+        TUIMessage({ type: 'warning', message: t('The stage is full') });
       } else {
         logger.error('Failure to process a user request', error);
       }
     }
   }
 
+  // 同意用户上台
   async function agreeUserOnStage(userInfo: UserInfo) {
     try {
       const requestId = userInfo.applyToAnchorRequestId;
@@ -70,17 +81,18 @@ export default function () {
         await roomEngine.instance?.responseRemoteRequest({ requestId, agree: true });
         roomStore.removeApplyToAnchorUser(requestId);
       } else {
-        logger.warn('Failed to process the take stage request, data exception, please try again!', userInfo);
+        logger.warn('同意上台申请失败,数据异常,请重试!', userInfo);
       }
     } catch (error: any) {
       if (error.code === TUIErrorCode.ERR_ALL_SEAT_OCCUPIED) {
-        TUIMessage({ type: 'warning', message: t('The current number of people on stage has reached the limit') });
+        TUIMessage({ type: 'warning', message: t('The stage is full') });
       } else {
         logger.error('Failed application for consent to go on stage', error);
       }
     }
   }
 
+  // 拒绝用户上台
   async function denyUserOnStage(userInfo: UserInfo) {
     const requestId = userInfo.applyToAnchorRequestId;
     if (requestId) {
@@ -90,11 +102,13 @@ export default function () {
       });
       roomStore.removeApplyToAnchorUser(requestId);
     } else {
-      logger.warn('Failed to process the take stage request, data exception, please try again!', userInfo);
+      logger.warn('拒绝上台申请失败,数据异常,请重试!', userInfo);
     }
   }
 
+  // 处理全部用户上麦请求
   async function handleAllUserApply(isAgreeOrRejectAllUserApply: boolean) {
+    let hasErrorOccurred = false;
     const applyUserList = applyToAnchorList.value.map(item => ({
       userId: item.userId,
       userName: item.userName,
@@ -112,12 +126,15 @@ export default function () {
           roomStore.removeApplyToAnchorUser(applyToAnchorRequestId);
         }
       } catch (error) {
-        logger.error(actionFailedMessage);
-        TUIMessage({
-          type: 'warning',
-          message: t(`${action} sb on stage failed, please retry`, { name: userName || userId }),
-          duration: MESSAGE_DURATION.NORMAL,
-        });
+        if (!hasErrorOccurred) {
+          logger.error(actionFailedMessage);
+          TUIMessage({
+            type: 'warning',
+            message: t('The stage is full'),
+            duration: MESSAGE_DURATION.NORMAL,
+          });
+          hasErrorOccurred = true;
+        }
       }
     }
   }
@@ -134,6 +151,9 @@ export default function () {
     roomEngine.instance?.off(TUIRoomEvents.onRequestProcessed, onRequestProcessed);
   });
 
+  // --------- 以下处理主持人主动操作 ----------
+
+  // 邀请用户上台
   async function inviteUserOnStage(userInfo: UserInfo) {
     const { userId } = userInfo;
     const request = await roomEngine.instance?.takeUserOnSeatByAdmin({
@@ -187,6 +207,7 @@ export default function () {
     }
   }
 
+  // 取消邀请用户上台
   function cancelInviteUserOnStage(userInfo: UserInfo) {
     const { userId, inviteToAnchorRequestId } = userInfo;
     roomStore.removeInviteToAnchorUser(userId);
@@ -195,6 +216,7 @@ export default function () {
     }
   }
 
+  // 邀请下台
   function kickUserOffStage(userInfo: UserInfo) {
     roomEngine.instance?.kickUserOffSeatByAdmin({
       seatIndex: -1,
@@ -237,7 +259,8 @@ export default function () {
       }
       const onlyOneUserTakeStage = newVal.length === 1;
       const firstUser = applyToAnchorList.value[0];
-      const userName = firstUser?.userName || firstUser?.userId;
+      const lastIndex = applyToAnchorList.value.length - 1;
+      const userName = applyToAnchorList.value[lastIndex]?.userName || applyToAnchorList.value[lastIndex]?.userId;
       const message = onlyOneUserTakeStage
         ? `${userName} ${t('Applying for the stage')}`
         : `${userName} ${t('and so on number people applying to stage', { number: applyToAnchorList.value.length })}`;
@@ -256,12 +279,19 @@ export default function () {
     hideApplyList,
     applyToAnchorUserCount,
     applyToAnchorList,
+    // 处理用户上麦申请(同意/拒绝)
     handleUserApply,
+    // 同意普通用户上台
     agreeUserOnStage,
+    // 拒绝普通用户上台
     denyUserOnStage,
+    // 邀请用户上台
     inviteUserOnStage,
+    // 取消邀请用户上台
     cancelInviteUserOnStage,
+    // 将用户踢下麦
     kickUserOffStage,
+    // 处理所有用户请求
     handleAllUserApply,
     handleShowNotification,
   };

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/hooks/useMitt.ts

@@ -1,3 +1,4 @@
+// 事件总线第三方库
 import mitt from 'mitt';
 const bus = mitt();
 export default bus;

+ 12 - 0
MiniProgram/src/roomkit/TUIRoom/index.vue

@@ -58,8 +58,11 @@ const emit = defineEmits([
   'on-enter-room',
   'on-exit-room',
   'on-destroy-room',
+  // 用户被踢出房间
   'on-kicked-out-of-room',
+  // 用户被踢下线
   'on-kicked-off-line',
+  // 用户 userSig 过期
   'on-userSig-expired',
 ]);
 
@@ -132,6 +135,8 @@ watch(
 const tuiRoomClass = computed(() => (isMobile ? ['tui-room', `tui-theme-${roomService.basicStore.defaultTheme}`, 'tui-room-h5'] : ['tui-room', `tui-theme-${roomService.basicStore.defaultTheme}`]));
 /**
  * Handle page mouse hover display toolbar logic
+ *
+ * 处理页面鼠标悬浮显示工具栏逻辑
  **/
 const roomContentRef = ref<InstanceType<typeof RoomContent>>();
 const showRoomTool: Ref<boolean> = ref(true);
@@ -141,6 +146,7 @@ function handleHideRoomTool() {
 }
 
 watch(() => roomRef.value, (newValue, oldValue) => {
+  // PC 端处理 room 控制栏交互
   if (!isWeChat && !isMobile) {
     if (newValue) {
       addRoomContainerEvent(newValue);
@@ -175,6 +181,7 @@ const removeRoomContainerEvent = (container: Node) => {
   container.removeEventListener('mousemove', showToolThrottle);
   container.removeEventListener('mouseleave', hideTool);
 };
+// H5 及小程序端处理 room 控制栏交互
 function handleRoomContentTap() {
   showRoomTool.value = !showRoomTool.value;
   if (showRoomTool.value) {
@@ -222,6 +229,11 @@ async function enterRoom(options: { roomId: string; roomParam?: RoomParam }) {
   });
 }
 
+// To do 临时注释,待放开
+// const onStatistics = (statistics: TRTCStatistics) => {
+//   basicStore.setStatistics(statistics);
+// };
+
 function resetStore() {
   roomService.resetStore();
 }

+ 11 - 9
MiniProgram/src/roomkit/TUIRoom/locales/en-US.ts

@@ -62,7 +62,7 @@ export default {
   'Join Room': 'Join Room',
   'Enter room ID': 'Enter room ID',
   'video conferencing': ' \'s video conferencing',
-  'Quick Meeting': ' \'s Quick Meeting',
+  'Quick Conference': ' \'s Quick Conference',
   'Room ID': 'Room ID',
   'Low Definition': 'Low Definition',
   'Standard Definition': 'Standard Definition',
@@ -95,9 +95,9 @@ export default {
   'Full screen': 'Full screen',
   Members: 'Members',
   'Search Member': 'Search Member',
-  'Transfer owner': 'Transfer owner',
+  'Make host': 'Make host',
   'Set as administrator': 'Set as administrator',
-  'Revoke administrator': 'Revoke administrator',
+  'Remove administrator': 'Remove administrator',
   // @ts-ignore
   'The administrator status of sb has been withdrawn': ({ named }) => `The administrator status of ${named('name')} has been withdrawn`,
   // @ts-ignore
@@ -243,9 +243,9 @@ export default {
   'kicked out of the room by other device': 'kicked out of the room by other device',
   'kicked out of the room by serve': 'kicked out of the room by serve',
   // @ts-ignore
-  'Reject sb stage failed, please retry': ({ named }) => `Reject ${named('name')} on Stage failed, please retry`,
+  'Reject sb on stage failed, please retry': ({ named }) => `Reject ${named('name')} on Stage failed, please retry`,
   // @ts-ignore
-  'Agree sb stage failed, please retry': ({ named }) => `Agree ${named('name')} on Stage failed, please retry`,
+  'Agree sb on stage failed, please retry': ({ named }) => `Agree ${named('name')} on Stage failed, please retry`,
   'Has been fully muted and cannot open the microphone': 'Has been fully muted and cannot open the microphone',
   'Has been muted by the host and cannot open the microphone': 'Has been muted by the host and cannot open the microphone',
   'To apply to speak in the room, please raise your hand first to apply for the microphone': 'To apply to speak in the room, please raise your hand first to apply for the microphone',
@@ -273,7 +273,7 @@ export default {
   'An invitation to open the microphone has been sent to sb.': ({ named }) => `An invitation to open the microphone has been sent to ${named('name')}`,
   // @ts-ignore
   'An invitation to open the camera has been sent to sb.': ({ named }) => `An invitation to open the camera has been sent to ${named('name')}`,
-  'Transfer owner failed, please try again.': 'Transfer owner failed, please try again.',
+  'Make host failed, please try again.': 'Make host failed, please try again.',
   // @ts-ignore
   'Sb has been set as an administrator': ({ named }) => `${named('name')} has been set as an administrator.`,
   'Succeed on stage': 'Succeed on stage',
@@ -294,8 +294,7 @@ export default {
   'You are now an administrator': 'You are now an administrator',
   'The RoomOwner has withdrawn your administrator privileges': 'The RoomOwner has withdrawn your administrator privileges',
   'This member has already received the same request, please try again later': 'This member has already received the same request, please try again later',
-  'Failed to go on stage, invitation has timed out': 'Failed to go on stage, invitation has timed out',
-  'The current number of people on stage has reached the limit': 'The current number of people on stage has reached the limit',
+  'The request to go on stage has timed out': 'The request to go on stage has timed out',
   // @ts-ignore
   'The invitation to sb to go on stage has timed out': ({ named }) => `The invitation to ${named('name')} to go on stage has timed out`,
   'Currently no member has applied to go on stage': 'Currently no member has applied to go on stage',
@@ -303,6 +302,8 @@ export default {
   'Stage management': 'Stage management',
   'Already on stage': 'Already on stage',
   'Not on stage': 'Not on stage',
+  'The stage is full, please contact the host': 'The stage is full, please contact the host',
+  'The stage is full': 'The stage is full',
   'To go on stage again, you need to reapply and wait for the roomOwner/administrator to approve': 'To go on stage again, you need to reapply and wait for the roomOwner/administrator to approve',
   'To go on stage again, a new application needs to be initiated': 'To go on stage again, a new application needs to be initiated',
   'The request to go on stage has been sent out, please wait for the roomOwner/administrator to approve it': 'The request to go on stage has been sent out, please wait for the roomOwner/administrator to approve it',
@@ -312,7 +313,8 @@ export default {
   'people applying to stage': 'people applying to stage',
   // @ts-ignore
   'and so on number people applying to stage': ({ named }) => `and so on ${named('number')} people applying to stage`,
-  'quick meeting': 'quick meeting',
+  // Room Chat 融合卡片翻译
+  'quick conference': 'quick conference',
   Meeting: 'Meeting',
   'Meeting in progress': 'Meeting in progress',
   Initiating: 'Initiating',

+ 27 - 0
MiniProgram/src/roomkit/TUIRoom/locales/index.ts

@@ -1,3 +1,29 @@
+/**
+ * i18n 使用说明:
+ *
+ * <script>
+ * import i18n, { useI18n } from '../locale';
+ * const { t } = useI18n();
+ *
+ * // case 1: 翻译文本中没有变量
+ * t('happy');
+ * i18n.t('happy');
+ * // case 2: 翻译文本中存在变量
+ * t('kick sb. out of room', { someOneName: 'xiaoming' });
+ * i18n.t('kick sb. out of room', { someOneName: 'xiaoming' });
+ *
+ * // 切换语言
+ * switch (i18n.global.locale.value) {
+ *  case 'en-US':
+ *    i18n.global.locale.value = 'zh-CN';
+ *    break;
+ *  case 'zh-CN':
+ *    i18n.global.locale.value = 'en-US';
+ *    break;
+ * }
+ * </script>
+ */
+
 import { getLanguage } from '../utils/common';
 import ZH from './zh-CN';
 import EN from './en-US';
@@ -32,6 +58,7 @@ class TUIKitI18n {
     return message[key];
   }
 
+  // 兼容 App.use 不报错
   public install() {
   }
 }

+ 10 - 9
MiniProgram/src/roomkit/TUIRoom/locales/zh-CN.ts

@@ -59,7 +59,7 @@ export default {
   'Join Room': '进入房间',
   'Enter room ID': '输入房间号',
   'video conferencing': ' 的视频会议',
-  'Quick Meeting': '的快速会议',
+  'Quick Conference': '的快速会议',
   'Room ID': '房间号',
   'Low Definition': '流畅',
   'Standard Definition': '标清',
@@ -92,9 +92,9 @@ export default {
   'Full screen': '全屏',
   Members: '成员',
   'Search Member': '搜索成员',
-  'Transfer owner': '转交房主',
+  'Make host': '转交房主',
   'Set as administrator': '设为管理员',
-  'Revoke administrator': '撤销管理员',
+  'Remove administrator': '撤销管理员',
   // @ts-ignore
   'The administrator status of sb has been withdrawn': ({ named }) => `已将 ${named('name')} 的管理员身份撤回`,
   // @ts-ignore
@@ -243,9 +243,9 @@ export default {
   'kicked out of the room by other device': '相同账号在其他客户端进入房间',
   'kicked out of the room by serve': '被服务端踢出房间',
   // @ts-ignore
-  'Reject sb stage failed, please retry': ({ named }) => `拒绝 ${named('name')} 上台失败, 请重试`,
+  'Reject sb on stage failed, please retry': ({ named }) => `拒绝 ${named('name')} 上台失败, 请重试`,
   // @ts-ignore
-  'Agree sb stage failed, please retry': ({ named }) => `同意 ${named('name')} 上台失败, 请重试`,
+  'Agree sb on stage failed, please retry': ({ named }) => `同意 ${named('name')} 上台失败, 请重试`,
   'Has been fully muted and cannot open the microphone': '已被全员静音,无法打开麦克风',
   'Has been muted by the host and cannot open the microphone': '已被主持人静音,无法打开麦克风',
   'To apply to speak in the room, please raise your hand first to apply for the microphone': '申请发言房间,请先举手申请上麦',
@@ -273,7 +273,7 @@ export default {
   'An invitation to open the microphone has been sent to sb.': ({ named }) => `已向 ${named('name')} 发出开启麦克风邀请`,
   // @ts-ignore
   'An invitation to open the camera has been sent to sb.': ({ named }) => `已向 ${named('name')} 发出开启摄像头邀请`,
-  'Transfer owner failed, please try again.': '转交房主失败,请重试',
+  'Make host failed, please try again.': '转交房主失败,请重试',
   // @ts-ignore
   'Sb has been set as an administrator': ({ named }) => `已将 ${named('name')} 设为管理员`,
   'Succeed on stage': '上台成功',
@@ -294,8 +294,7 @@ export default {
   'You are now an administrator': '您已成为管理员',
   'The RoomOwner has withdrawn your administrator privileges': '房主已收回您的管理员权限',
   'This member has already received the same request, please try again later': '该成员已收到相同请求,请稍后再试',
-  'Failed to go on stage, invitation has timed out': '上台失败,邀请已超时',
-  'The current number of people on stage has reached the limit': '当前上台人数已达上限',
+  'The request to go on stage has timed out': '上台请求已超时',
   // @ts-ignore
   'The invitation to sb to go on stage has timed out': ({ named }) => `对${named('name')}的上台邀请已超时`,
   'Currently no member has applied to go on stage': '暂无成员申请上台',
@@ -303,6 +302,8 @@ export default {
   'Stage management': '上台管理',
   'Already on stage': '已上台',
   'Not on stage': '未上台',
+  'The stage is full, please contact the host': '台上人数已满,请联系主持人',
+  'The stage is full': '台上人数已满',
   'To go on stage again, you need to reapply and wait for the roomOwner/administrator to approve': '再次上台需重新发起申请,并等待房主/管理员通过',
   'To go on stage again, a new application needs to be initiated': '再次上台需重新发起申请',
   'The request to go on stage has been sent out, please wait for the roomOwner/administrator to approve it': '上台申请已发出,请等待房主/管理员通过',
@@ -313,7 +314,7 @@ export default {
   // @ts-ignore
   'and so on number people applying to stage': ({ named }) => `等 ${named('number')} 人正在申请上台`,
   // Room Chat 融合卡片翻译
-  'quick meeting': '快速会议',
+  'quick conference': '快速会议',
   Meeting: '会议',
   'Meeting in progress': '会议 进行中',
   Initiating: '正在发起',

+ 7 - 3
MiniProgram/src/roomkit/TUIRoom/services/roomService.ts

@@ -218,7 +218,7 @@ export class RoomService {
   private onUserSigExpired() {
     this.emit(EventType.ROOM_NOTICE_MESSAGE_BOX, {
       title: t('Note'),
-      message: t('userSig expired'),
+      message: t('userSig 已过期'),
       confirmButtonText: t('Sure'),
       callback: () => {
         this.emit(EventType.ROOM_USER_SIG_EXPIRED, {});
@@ -230,7 +230,7 @@ export class RoomService {
     const { message } = eventInfo;
     this.emit(EventType.ROOM_NOTICE_MESSAGE_BOX, {
       title: t('Note'),
-      message: t('The system has detected that your account has been kicked offline.'),
+      message: t('系统检测到您的账号被踢下线'),
       confirmButtonText: t('Sure'),
       callback: async () => {
         this.emit(EventType.ROOM_KICKED_OFFLINE, { message });
@@ -261,6 +261,7 @@ export class RoomService {
      * If the host lifts the full ban on video, users does not actively turn up the user camera,
      * If the host open and does not actively turn up the user camera
      *
+     * 如果主持人解除全员禁画,不主动调起用户摄像头;如果主持人开启全员禁画,则主动关闭用户摄像头
      **/
     if (isDisableVideo && this.roomStore.localUser.userRole === TUIRole.kGeneralUser) {
       await roomEngine.instance?.closeLocalCamera();
@@ -310,6 +311,7 @@ export class RoomService {
      * If the moderator unmutes the entire staff, users does not actively bring up the user's microphone;
      * if the moderator turns on the full staff mute, users actively turns off the user's microphone
      *
+     * 如果主持人解除全员静音,不主动调起用户麦克风;如果主持人开启全员静音,则主动关闭用户麦克风
      **/
     if (isDisableAudio && this.roomStore.localUser.userRole === TUIRole.kGeneralUser) {
       await roomEngine.instance?.muteLocalAudio();
@@ -389,7 +391,7 @@ export class RoomService {
       logger.debug(`${logPrefix}createRoom:`, roomId, roomMode, roomParam);
       const roomParams = {
         roomId,
-        name: roomName,
+        roomName,
         roomType: TUIRoomType.kConference,
       };
       if (roomMode === 'FreeToSpeak') {
@@ -466,6 +468,7 @@ export class RoomService {
        * setRoomParam must come after setRoomInfo,because roomInfo contains information
        * about whether or not to turn on the no-mac ban.
        *
+       * setRoomParam 必须在 setRoomInfo 之后,因为 roomInfo 中有是否开启全员禁麦禁画的信息
        **/
       this.roomStore.setRoomParam(roomParam);
       TUIRoomAegis.reportEvent({
@@ -482,6 +485,7 @@ export class RoomService {
   public async handleRoomKitOnMounted() {
     const storageCurrentTheme = uni.getStorageSync('tuiRoom-currentTheme');
     storageCurrentTheme && this.basicStore.setDefaultTheme(storageCurrentTheme);
+    // 设置本地视频默认渲染模式
     const trtcCloud = roomEngine.instance?.getTRTCCloud();
     const mirrorType = isMobile
       ? TRTCVideoMirrorType.TRTCVideoMirrorType_Auto

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/stores/chat.ts

@@ -17,6 +17,7 @@ interface ChatState {
   isMessageDisableByAdmin: boolean;
   unReadCount: number;
   isCompleted: boolean;
+  // 是否已经拉完所有消息列表
   // Is the list of all messages pulled
   nextReqMessageId: string;
 }

+ 40 - 2
MiniProgram/src/roomkit/TUIRoom/stores/room.ts

@@ -38,17 +38,29 @@ export type UserInfo = {
   isVideoVisible?: boolean,
   isScreenVisible?: boolean,
   userRole?: TUIRole,
+  // 是否在麦上
   onSeat?: boolean,
   isChatMutedByMasterOrAdmin?: boolean,
+  // 是否正在请求用户打开麦克风
   isRequestingUserOpenMic?: boolean,
+  // 请求用户打开麦克风的 requestId
   requestUserOpenMicRequestId?: string,
+  // 是否正在请求用户打开摄像头
   isRequestingUserOpenCamera?: boolean,
+  // 请求用户打开摄像头的 requestId
   requestUserOpenCameraRequestId?: string,
+  // 用户是否正在申请上麦
   isUserApplyingToAnchor?: boolean,
+  // 用户申请上麦的 requestId
   applyToAnchorRequestId?: string,
+  // 用户申请上麦的时间点
   applyToAnchorTimestamp?: number,
+  // 是否正在邀请用户上麦
   isInvitingUserToAnchor?: boolean,
+  // 邀请用户上麦的 requestId
   inviteToAnchorRequestId?: string,
+  // cameraStreamInfo 和 screenStreamInfo 存在的意义时,流渲染保持使用同一个引用传递的数据
+  // 避免出现大窗口和实际数据显示不一致的问题
   cameraStreamInfo: StreamInfo,
   screenStreamInfo: StreamInfo,
 }
@@ -59,6 +71,7 @@ interface RoomState {
   userVolumeObj: Record<string, number>,
   isDefaultOpenCamera: boolean,
   isDefaultOpenMicrophone: boolean,
+  // 主持人全员禁麦,但是单独取消某个用户音视频禁止状态的时候,是可以自己 unmute audio/video 的
   canControlSelfAudio: boolean,
   canControlSelfVideo: boolean,
   localVideoQuality: TUIVideoQuality,
@@ -75,6 +88,8 @@ interface RoomState {
   isSeatEnabled: boolean,
   seatMode: TUISeatMode,
   maxMembersCount: number,
+  maxSeatCount: number,
+  roomName: string,
   hasVideoStreamObject: Record<string, UserInfo>,
   currentStreamIdListInVisibleView: string[],
   hasOtherScreenShare: boolean,
@@ -129,8 +144,11 @@ export const useRoomStore = defineStore('room', {
     isMessageDisableForAllUser: false,
     isSeatEnabled: false,
     seatMode: TUISeatMode.kFreeToTake,
-    maxMembersCount: 5,
+    maxMembersCount: 5, // 包含本地流和屏幕分享,超过该数目后续都播放小流
+    maxSeatCount: 20,
+    roomName: '',
     hasVideoStreamObject: {},
+    // 可视区域用户流列表
     currentStreamIdListInVisibleView: [],
     hasOtherScreenShare: false,
     isOnStateTabActive: true,
@@ -145,6 +163,7 @@ export const useRoomStore = defineStore('room', {
     isGeneralUser(state) {
       return state.localUser.userRole === TUIRole.kGeneralUser;
     },
+    // 当前用户是否在麦上
     isAnchor(state) {
       if (this.isFreeSpeakMode) {
         return true;
@@ -153,6 +172,7 @@ export const useRoomStore = defineStore('room', {
         return state.localUser.onSeat;
       }
     },
+    // 当前用户是否是在麦下
     isAudience(state) {
       if (this.isFreeSpeakMode) {
         return false;
@@ -168,10 +188,12 @@ export const useRoomStore = defineStore('room', {
       return !this.isSeatEnabled;
     },
     isLocalAudioIconDisable(): boolean {
+      // 全员禁麦状态
       const micForbidden = this.isGeneralUser && !this.canControlSelfAudio;
       return micForbidden as any || this.isAudience;
     },
     isLocalVideoIconDisable(): boolean {
+      // 全员禁画状态
       const cameraForbidden = this.isGeneralUser && !this.canControlSelfVideo;
       return cameraForbidden as any || this.isAudience;
     },
@@ -315,6 +337,7 @@ export const useRoomStore = defineStore('room', {
         }
       });
     },
+    // 远端用户进入房间(IM事件)
     addRemoteUser(userInfo: TUIUserInfo) {
       const { userId } = userInfo;
       const basicStore = useBasicStore();
@@ -363,6 +386,9 @@ export const useRoomStore = defineStore('room', {
         };
       });
     },
+    // 更新 seatList 的变更
+    // 进入房间后会立即通知 onSeatListChanged, onUserVideoAvailable,onUserAudioAvailable 事件,因此先更新到 userMap 中
+    // 等待 getUserList 获取到全部用户列表后再做更新
     updateOnSeatList(seatedList: TUISeatInfo[], leftList: TUISeatInfo[]) {
       seatedList.forEach((seat) => {
         const { userId } = seat;
@@ -397,6 +423,7 @@ export const useRoomStore = defineStore('room', {
     updateUserVideoState(userId: string, streamType: TUIVideoStreamType, hasVideo: boolean) {
       const basicStore = useBasicStore();
       let user = userId === basicStore.userId ? this.localUser : this.remoteUserObj[userId];
+      // 需要判断 hasVideo 是否为 true,避免视频取消事件在 onRemoteUserLeaveRoom 之后抛出的情况
       if (!user && hasVideo) {
         user = this.getNewUserInfo(userId);
         if (isVue3) {
@@ -438,6 +465,7 @@ export const useRoomStore = defineStore('room', {
     updateUserAudioState(userId: string, hasAudio: boolean) {
       const basicStore = useBasicStore();
       let user = userId === basicStore.userId ? this.localUser : this.remoteUserObj[userId];
+      // 需要判断 hasAudio 是否为 true,避免音频取消事件在 onRemoteUserLeaveRoom 之后抛出的情况
       if (!user && hasAudio) {
         user = this.getNewUserInfo(userId);
         if (isVue3) {
@@ -482,6 +510,7 @@ export const useRoomStore = defineStore('room', {
           user.isScreenVisible = true;
         }
       });
+      // 在新的 streamIdList 里面没有的流, isVideoVisible 要设置为 false
       this.currentStreamIdListInVisibleView.forEach((item: string) => {
         const userId = item.slice(0, item.length - 2);
         const streamType = Number(item.slice(-1)) as TUIVideoStreamType;
@@ -544,7 +573,7 @@ export const useRoomStore = defineStore('room', {
       const {
         roomOwner, isMicrophoneDisableForAllUser,
         isCameraDisableForAllUser, isMessageDisableForAllUser,
-        isSeatEnabled, seatMode,
+        isSeatEnabled, seatMode, maxSeatCount, roomName,
       } = roomInfo;
       if (this.localUser.userId === roomOwner) {
         this.localUser.userRole = TUIRole.kRoomOwner;
@@ -558,6 +587,8 @@ export const useRoomStore = defineStore('room', {
       this.seatMode = seatMode;
       this.canControlSelfAudio = !this.isMicrophoneDisableForAllUser;
       this.canControlSelfVideo = !this.isCameraDisableForAllUser;
+      this.maxSeatCount = maxSeatCount;
+      this.roomName = roomName;
     },
     setDisableMicrophoneForAllUserByAdmin(isDisable: boolean) {
       this.isMicrophoneDisableForAllUser = isDisable;
@@ -588,10 +619,12 @@ export const useRoomStore = defineStore('room', {
         this.setCurrentSpeakerId(defaultSpeakerId);
         roomEngine.instance?.setCurrentSpeakerDevice({ deviceId: defaultSpeakerId });
       }
+      // 如果已经开启全员禁言/当前为申请发言模式,则忽略默认打开麦克风的设置
       if (this.isMaster || (!this.isMicrophoneDisableForAllUser
         && this.isFreeSpeakMode)) {
         typeof isOpenMicrophone === 'boolean' && (this.isDefaultOpenMicrophone = isOpenMicrophone);
       }
+      // 如果已经开启全员禁画/当前为申请发言模式,则忽略默认打开摄像头的设置
       if (this.isMaster || (!this.isCameraDisableForAllUser
         && this.isFreeSpeakMode)) {
         typeof isOpenCamera === 'boolean' && (this.isDefaultOpenCamera = isOpenCamera);
@@ -639,12 +672,15 @@ export const useRoomStore = defineStore('room', {
         this.setCurrentSpeakerId(deviceList[0].deviceId);
       }
     },
+    // 全员禁麦/取消禁麦时设置所有人的禁麦状态
     setMicrophoneDisableState(isDisable: boolean) {
       this.isMicrophoneDisableForAllUser = isDisable;
     },
+    // 全员禁画/取消禁画时设置所有人的禁画状态
     setCameraDisableState(isDisable: boolean) {
       this.isCameraDisableForAllUser = isDisable;
     },
+    // 主持人单个修改用户的发文字消息 mute 状态
     setMuteUserChat(userId: string, muted: boolean) {
       const remoteUserInfo = this.remoteUserObj[userId];
       if (remoteUserInfo) {
@@ -764,6 +800,8 @@ export const useRoomStore = defineStore('room', {
       this.hasVideoStreamObject = {};
       this.hasOtherScreenShare = false;
       this.isOnStateTabActive = true;
+      this.maxSeatCount = 20;
+      this.roomName = '';
     },
   },
 });

+ 8 - 0
MiniProgram/src/roomkit/TUIRoom/utils/aegis/config.ts

@@ -1,3 +1,11 @@
+/**
+ * 需要配置 isUploadLoaded, aegisId, projectName
+ * isUploadLoaded: 上传 loaded 事件
+ * isUploadDetailEvent: 上传 loaded 及其他操作事件
+ * aegisId: aegis Id
+ * projectName: 项目名称
+ */
+
 import { isMobile }  from '../environment';
 
 const IS_LOCAL = location?.protocol === 'file:' || location?.hostname === 'localhost' || location?.hostname === '127.0.0.1';

+ 2 - 2
MiniProgram/src/roomkit/TUIRoom/utils/common.ts

@@ -1,7 +1,7 @@
 import { getUrlParam } from './utils';
 
 /**
- * get Language
+ * 获取语言
  * @returns language
  */
 export function getLanguage() {
@@ -17,7 +17,7 @@ export function getLanguage() {
 }
 
 /**
- * Determine if a string is a number
+ * 判断字符串是否是数字
  * @returns boolean
  */
 export function checkNumber(roomId: string) {

+ 1 - 0
MiniProgram/src/roomkit/TUIRoom/utils/common/logger/index.ts

@@ -46,6 +46,7 @@ const logger = {
       );
       currentLogLevel = newLevel;
 
+      // 通知主进程
       if ((window as any).electron?.ipcRenderer) {
         (window as any).electron.ipcRenderer.send(
           EUserEventNames.ON_CHANGE_LOG_LEVEL,

+ 8 - 0
MiniProgram/src/roomkit/TUIRoom/utils/common/logger/logger-constants.ts

@@ -1,3 +1,11 @@
+/**
+ * 这个常量定义模块,即用于 main 目录下各个 ts 模块,也用 main/preload.js 模块,
+ * 此处定义为 node.js module 格式,以上两类模块都可使用。
+ *
+ * 如果此处定义为 ES 6 模块(使用 import/export ),则 preload.js 模块无法使用,
+ * 原因是 preload.js 文件是一个原生 node.js module 执行文件,后续如果 preload.js
+ * 承担职责过多,代码复杂度较大,可以考虑使用。
+ */
 export enum EUserEventNames {
   ON_CHANGE_LOG_LEVEL = 'onChangeLogLevel',
 }

+ 1 - 1
MiniProgram/src/roomkit/TUIRoom/utils/common/logger/logger-utils.ts

@@ -4,7 +4,7 @@ export const LogLevelType = {
   LOG_LEVEL_INFO: 1,
   LOG_LEVEL_WARN: 2,
   LOG_LEVEL_ERROR: 3,
-  LOG_LEVEL_NON_LOGGING: 4,
+  LOG_LEVEL_NON_LOGGING: 4, // 无日志记录级别,将不打印任何日志
 };
 
 export enum LogContext {

+ 2 - 2
MiniProgram/src/roomkit/TUIRoom/utils/constants.ts

@@ -1,9 +1,9 @@
 
 import * as Vue from 'vue';
 
-export const isVue27 = /^2\.7\.*/.test(Vue.version);
+export const isVue27 = /^2\.7\.*/.test(Vue.version); // 是否是 Vue2.7 版本
 
-export const isVue3 = /^3\.*/.test(Vue.version);
+export const isVue3 = /^3\.*/.test(Vue.version);  // 是否是 Vue3 版本
 
 // @ts-ignore
 export const isInnerScene = false;

+ 2 - 0
MiniProgram/src/roomkit/TUIRoom/utils/environment.ts

@@ -14,8 +14,10 @@ export const isApp = getPlatform() === 'app';
 
 export const isUniFrameWork = typeof uni !== 'undefined';
 
+// H5、小程序、app 均认为是手机端产品,如果需要统一手机端 UI 样式,可以直接用 isMobile 控制
 export const isMobile = isH5 || isWeChat || isApp;
 
 export const isElectron = navigator?.userAgent?.toLowerCase().indexOf(' electron/') > -1;
 
+// 微信浏览器
 export const isWeiXinBrowser = navigator && navigator?.userAgent?.toLocaleLowerCase().indexOf('micromessenger') > -1;

+ 7 - 0
MiniProgram/src/roomkit/TUIRoom/utils/mediaAbility.ts

@@ -1,6 +1,8 @@
 import { isElectron, isWeChat, isWeiXinBrowser } from './environment';
 import { isFunction } from './utils';
 
+// 是否支持 getUserMedia 采集音视频流
+// 不支持浏览器:qq 浏览器
 export const isGetUserMediaSupported = (function () {
   if (isElectron || isWeChat) {
     return true;
@@ -8,6 +10,7 @@ export const isGetUserMediaSupported = (function () {
   return navigator && navigator?.mediaDevices && isFunction(navigator?.mediaDevices.getUserMedia);
 }());
 
+// 是否支持 getDisplayMedia 采集屏幕分享
 export const isGetDisplaySupported = (function () {
   if (isElectron || isWeChat) {
     return true;
@@ -15,8 +18,12 @@ export const isGetDisplaySupported = (function () {
   return navigator && navigator?.mediaDevices && isFunction(navigator?.mediaDevices.getDisplayMedia);
 }());
 
+// 是否支持屏幕分享能力
+// 不支持浏览器:mac 360 浏览器
 export const isScreenShareSupported = isGetDisplaySupported && !isWeiXinBrowser;
 
+// 是否支持获取设备列表
+// 不支持浏览器:mac 360 浏览器
 export const isEnumerateDevicesSupported = (function () {
   if (isElectron || isWeChat) {
     return true;

+ 18 - 0
MiniProgram/src/roomkit/TUIRoom/utils/toCanvas.ts

@@ -2,6 +2,19 @@ const { requestAnimationFrame, cancelAnimationFrame } =  window;
 const canvasWidth = 1280;
 const canvasHeight = 720;
 
+/*
+@des 将video内容绘制到canvas上面
+@example
+const video = document?.getElementById('video');
+const canvas = new ToCanvas(video);
+// 获取 canvas element 元素
+const canvasElement = canvas.element;
+// 在用户交互事件的回调中执行play方法
+canvas.play();
+window?.setTimeout(() => {
+  canvas.stop();
+}, 2000);
+*/
 type CanvasImageSource = HTMLImageElement | HTMLVideoElement | HTMLCanvasElement;
 
 export default class ToCanvas {
@@ -47,13 +60,17 @@ export default class ToCanvas {
   }
 }
 
+// 控制requestAnimationFrame的频率
 function setAnimationFrame(render: Function, stepTime = 24) {
+  // 记录每次动画执行结束的时间
   let lastTime = Date.now();
+  // 计时器ID
   let currentTime;
   const timer = {
     id: -1,
   };
   function animeLoop() {
+    // 记录当前时间
     currentTime = Date.now();
     if (currentTime - lastTime > stepTime) {
       lastTime = currentTime;
@@ -66,6 +83,7 @@ function setAnimationFrame(render: Function, stepTime = 24) {
 }
 
 
+// 清除AnimationFrame
 function clearAnimationFrame(timer: any) {
   cancelAnimationFrame(timer.id);
 }

+ 42 - 0
MiniProgram/src/roomkit/TUIRoom/utils/utils.ts

@@ -1,4 +1,11 @@
 
+
+/**
+ * 防抖函数
+ * @param {*} fn 要执行的函数
+ * @param {*} delay 间隔时间
+ * @returns function
+ */
 export function debounce(fn: { apply: (arg0: any, arg1: any) => void; }, delay: number | undefined) {
   let timer: number;
   return function (this:any, ...args: any) {
@@ -12,6 +19,12 @@ export function debounce(fn: { apply: (arg0: any, arg1: any) => void; }, delay:
   };
 }
 
+/**
+ * 节流函数
+ * @param {*} fn 要执行的函数
+ * @param {*} delay 间隔时间
+ * @returns function
+ */
 export function throttle(fn: { apply: (arg0: any, arg1: any[]) => void; }, delay: number) {
   let previousTime = 0;
   return function (this:any, ...args: any[]) {
@@ -24,6 +37,13 @@ export function throttle(fn: { apply: (arg0: any, arg1: any[]) => void; }, delay
   };
 };
 
+/**
+ * 将 dom 元素全屏
+ * @param {dom} element dom元素
+ * @example
+ * setFullscreen(document?.documentElement) // 整个页面进入全屏
+ * setFullscreen(document?.getElementById("id")) // 某个元素进入全屏
+ */
 export function setFullScreen(element: HTMLElement) {
   const fullScreenElement = element as HTMLElement & {
     mozRequestFullScreen(): Promise<void>;
@@ -32,15 +52,23 @@ export function setFullScreen(element: HTMLElement) {
   };
   if (fullScreenElement?.requestFullscreen) {
     fullScreenElement?.requestFullscreen();
+    // 兼容Firefox
   } else if (fullScreenElement?.mozRequestFullScreen) {
     fullScreenElement?.mozRequestFullScreen();
+    // 兼容 chrome,safari,opera等
   } else if (fullScreenElement?.webkitRequestFullScreen) {
     fullScreenElement?.webkitRequestFullScreen();
+    // 兼容IE/Edge
   } else if (fullScreenElement?.msRequestFullscreen) {
     fullScreenElement?.msRequestFullscreen();
   }
 }
 
+/**
+ * 退出全屏
+ * @example
+ * exitFullscreen();
+ */
 export function exitFullScreen() {
   if (!document?.fullscreenElement
     && !(document as any)?.webkitFullscreenElement && !(document as any)?.mozFullScreenElement) {
@@ -62,6 +90,14 @@ export function exitFullScreen() {
   }
 }
 
+
+/**
+ * 从 window?.location?.href 中获取指定key的value
+ * @param {*} key 要获取的 key
+ * @returns window?.location?.href 中指定key对应的value
+ * @example
+ * const value = getUrlParam(key);
+ */
 export function getUrlParam(key: string) {
   const url = window?.location?.href.replace(/^[^?]*\?/, '');
   const regexp = new RegExp(`(^|&)${key}=([^&#]*)(&|$|)`, 'i');
@@ -70,6 +106,12 @@ export function getUrlParam(key: string) {
   return paramMatch ? paramMatch[2] : null;
 }
 
+
+/**
+ * 深拷贝
+ * @param data 任意类型的 data 原数据
+ * @returns 深拷贝之后的数据
+ */
 export function deepClone(data: any) {
   let res: any = null;
   const reference = [Date, RegExp, Set, WeakSet, Map, WeakMap, Error];

+ 20 - 3
MiniProgram/src/roomkit/config/basic-info-config.js

@@ -1,5 +1,6 @@
 /*
  * @Description: Basic information configuration for TUIRoomKit applications
+ * @Description: TUIRoomKit 应用的基础信息配置
  */
 
 import LibGenerateTestUserSig from './lib-generate-test-usersig-es.min';
@@ -10,6 +11,9 @@ import LibGenerateTestUserSig from './lib-generate-test-usersig-es.min';
  * and you will see the SDKAppId.
  * It is a unique identifier used by Tencent Cloud to identify users.
  *
+ * 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。
+ * 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ) 创建应用,即可看到 SDKAppId,
+ * 它是腾讯云用于区分客户的唯一标识。
  */
 
 export const SDKAPPID = 0;
@@ -28,6 +32,14 @@ export const SDKAPPID = 0;
  * unauthorized traffic use caused by the leakage of encryption key.
  * Document: https://intl.cloud.tencent.com/document/product/647/35166#Server
  *
+ * 计算签名用的加密密钥,获取步骤如下:
+ *
+ * step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ),如果还没有应用就创建一个,
+ * step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。
+ * step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中
+ *
+ * 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。
+ * 文档:https://cloud.tencent.com/document/product/647/17275#Server
  */
 export const SDKSECRETKEY = '';
 
@@ -36,18 +48,23 @@ export const SDKSECRETKEY = '';
  * Time unit: second
  * Default time: 7 * 24 * 60 * 60 = 604800 = 7days
  *
+ * 签名过期时间,建议不要设置的过短
+ * 时间单位:秒
+ * 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天
  */
 export const EXPIRETIME = 604800;
 
 /**
  * Set user information on the push side
+ *
+ * 设置推流端用户信息
  */
 export const userInfo = {
-  // userId
+  // 用户Id
   userId: `user_${Math.ceil(Math.random() * 100000)}`,
-  // userName
+  // 用户昵称
   userName: 'myName',
-  // userAvatar
+  // 用户头像
   avatarUrl: '',
 };
 

+ 13 - 0
MiniProgram/src/roomkit/pages/home.vue

@@ -69,12 +69,15 @@ async function checkRoomExistWhenCreateRoom(roomId: string) {
     await tim?.searchGroupByID(roomId);
     isRoomExist = true;
   } catch (error: any) {
+    // 房间不存在
   }
   return isRoomExist;
 }
 
 /**
  * Generate room number when creating a room
+ *
+ * 创建房间时生成房间号
 **/
 async function generateRoomId(): Promise<string> {
   const roomId = String(Math.ceil(Math.random() * 1000000));
@@ -87,6 +90,8 @@ async function generateRoomId(): Promise<string> {
 
 /**
  * Processing Click [Create Room]
+ *
+ * 处理点击【创建房间】
 **/
 async function handleCreateRoom(mode: string) {
   setTUIRoomData('createRoom', mode);
@@ -101,6 +106,8 @@ async function handleCreateRoom(mode: string) {
 
 /**
  * Processing Click [Enter Room]
+ *
+ * 处理点击【进入房间】
 **/
 async function handleEnterRoom(roomId: string) {
   setTUIRoomData('enterRoom');
@@ -124,10 +131,14 @@ function handleUpdateUserName(userName: string) {
 
 /**
  * Processing users click [Logout Login] in the upper left corner of the page
+ *
+ * 处理用户点击页面左上角【退出登录】
 **/
 async function handleLogOut() {
 /**
  * The accessor handles the logout method
+ *
+ * 接入方处理 logout 方法
 **/
 }
 
@@ -148,6 +159,8 @@ async function handleInit() {
   const { sdkAppId, userSig } = currentUserInfo;
   /**
    * TUIRoomCore.checkRoomExistence method can only be used after logging into TUIRoomCore.
+   *
+   * 登录 TUIRoomCore, 只有登录 TUIRoomCore 之后,才可以使用 TUIRoomCore.checkRoomExistence 方法
   **/
   await TUIRoomEngine.login({ sdkAppId, userId: userId.value, userSig });
 }

+ 10 - 1
MiniProgram/src/roomkit/pages/room.vue

@@ -55,7 +55,7 @@ onMounted(async () => {
     });
     if (action === 'createRoom' && !hasCreated) {
       try {
-        await TUIRoomRef.value?.createRoom({ roomId, roomName: roomId, roomMode, roomParam });
+        await TUIRoomRef.value?.createRoom({ roomId, roomName: `${userName || userId}${t('Quick Conference')}`, roomMode, roomParam });
         const newRoomInfo = { action, roomId, roomName: roomId, roomMode, roomParam, hasCreated: true };
         uni.setStorageSync('tuiRoom-roomInfo', JSON.stringify(newRoomInfo));
       } catch (error: any) {
@@ -100,15 +100,18 @@ onMounted(async () => {
 
 /**
  * Processing users click [Logout Login] in the upper left corner of the page
+ * 处理用户点击页面左上角【退出登录】
  **/
 function handleLogOut() {
   /**
    * The accessor handles the logout method
+   * 接入方处理 logout 方法
    **/
 }
 
 /**
  * Hosts create room callbacks
+ * 主持人创建房间回调
  **/
 function onCreateRoom(info: { code: number; message: string }) {
   console.debug('onEnterRoom:', info);
@@ -116,6 +119,7 @@ function onCreateRoom(info: { code: number; message: string }) {
 
 /**
  * Ordinary members enter the room callback
+ * 普通成员进入房间回调
  **/
 function onEnterRoom(info: { code: number; message: string }) {
   console.debug('onCreateRoom:', info);
@@ -123,6 +127,7 @@ function onEnterRoom(info: { code: number; message: string }) {
 
 /**
  * Hosts destroy room callbacks
+ * 主持人销毁房间回调
  **/
 const onDestroyRoom = (info: { code: number; message: string }) => {
   console.debug('onDestroyRoom:', info);
@@ -132,6 +137,7 @@ const onDestroyRoom = (info: { code: number; message: string }) => {
 
 /**
  * Ordinary members exit the room callback
+ * 普通成员退出房间回调
  **/
 const onExitRoom = (info: { code: number; message: string }) => {
   console.debug('onExitRoom:', info);
@@ -141,6 +147,7 @@ const onExitRoom = (info: { code: number; message: string }) => {
 
 /**
  * Ordinary members were kicked out of the room by the host
+ * 普通成员被主持人踢出房间
  **/
 const onKickedOutOfRoom = (info: { roomId: string; message: string }) => {
   console.debug('onKickedOutOfRoom:', info);
@@ -150,6 +157,7 @@ const onKickedOutOfRoom = (info: { roomId: string; message: string }) => {
 
 /**
  * Users are kicked offline
+ * 被踢下线
  */
 const onKickedOffLine = (info: { message: string }) => {
   console.debug('onKickedOffLine:', info);
@@ -159,6 +167,7 @@ const onKickedOffLine = (info: { message: string }) => {
 
 /**
  * Ordinary members were kicked out of the room by the host
+ * userSig 过期,需要获取新的 userSig
  */
 const onUserSigExpired = () => {
   console.debug('onUserSigExpired');

BIN
MiniProgram/src/static/RTCRoomEngine.wasm.br


BIN
MiniProgram/src/static/TUIRoomEngine.wasm.br


+ 38 - 9
MiniProgram/src/uni.scss

@@ -1,47 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+
+/* 颜色变量 */
+
+/* 行为相关颜色 */
 $uni-color-primary: #007aff;
 $uni-color-success: #4cd964;
 $uni-color-warning: #f0ad4e;
 $uni-color-error: #dd524d;
 
-$uni-text-color: #333; 
-$uni-text-color-inverse: #fff; 
-$uni-text-color-grey: #999;
+/* 文字基本颜色 */
+$uni-text-color: #333; // 基本色
+$uni-text-color-inverse: #fff; // 反色
+$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息
 $uni-text-color-placeholder: #808080;
 $uni-text-color-disable: #c0c0c0;
 
+/* 背景颜色 */
 $uni-bg-color: #fff;
 $uni-bg-color-grey: #f8f8f8;
-$uni-bg-color-hover: #f1f1f1; 
-$uni-bg-color-mask: rgba(0, 0, 0, 0.4); 
+$uni-bg-color-hover: #f1f1f1; // 点击状态颜色
+$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色
 
+/* 边框颜色 */
 $uni-border-color: #c8c7cc;
 
+/* 尺寸变量 */
+
+/* 文字尺寸 */
 $uni-font-size-sm: 12px;
 $uni-font-size-base: 14px;
 $uni-font-size-lg: 16;
 
+/* 图片尺寸 */
 $uni-img-size-sm: 20px;
 $uni-img-size-base: 26px;
 $uni-img-size-lg: 40px;
 
+/* Border Radius */
 $uni-border-radius-sm: 2px;
 $uni-border-radius-base: 3px;
 $uni-border-radius-lg: 6px;
 $uni-border-radius-circle: 50%;
 
+/* 水平间距 */
 $uni-spacing-row-sm: 5px;
 $uni-spacing-row-base: 10px;
 $uni-spacing-row-lg: 15px;
 
+/* 垂直间距 */
 $uni-spacing-col-sm: 4px;
 $uni-spacing-col-base: 8px;
 $uni-spacing-col-lg: 12px;
 
-$uni-opacity-disabled: 0.3;
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
 
-$uni-color-title: #2c405a; 
+/* 文章场景相关 */
+$uni-color-title: #2c405a; // 文章标题颜色
 $uni-font-size-title: 20px;
-$uni-color-subtitle: #555;
+$uni-color-subtitle: #555; // 二级标题颜色
 $uni-font-size-subtitle: 18px;
-$uni-color-paragraph: #3f536e;
+$uni-color-paragraph: #3f536e; // 文章段落颜色
 $uni-font-size-paragraph: 15px;

+ 1 - 1
MiniProgram/wxmini_dev.bat

@@ -8,4 +8,4 @@ if exist "dist\dev\mp-weixin" (
   exit /b 1
 )
 
-npm init -y && npm i @tencentcloud/trtc-component-wx && cd roomkit && npm init -y && npm i @tencentcloud/tuiroom-engine-wx@2.3.1
+npm init -y && npm i @tencentcloud/trtc-component-wx && cd roomkit && npm init -y && npm i @tencentcloud/tuiroom-engine-wx@2.4.0

+ 1 - 1
MiniProgram/wxmini_dev.sh

@@ -4,4 +4,4 @@ npm init -y
 npm i @tencentcloud/trtc-component-wx
 cd roomkit
 npm init -y
-npm i @tencentcloud/tuiroom-engine-wx@2.3.1
+npm i @tencentcloud/tuiroom-engine-wx@2.4.0

+ 1 - 1
MiniProgram/wxmini_prod.bat

@@ -8,4 +8,4 @@ if exist "dist\build\mp-weixin" (
   exit /b 1
 )
 
-npm init -y && npm i @tencentcloud/trtc-component-wx && cd roomkit && npm init -y && npm i @tencentcloud/tuiroom-engine-wx@2.3.1
+npm init -y && npm i @tencentcloud/trtc-component-wx && cd roomkit && npm init -y && npm i @tencentcloud/tuiroom-engine-wx@2.4.0

+ 1 - 1
MiniProgram/wxmini_prod.sh

@@ -4,4 +4,4 @@ npm init -y
 npm i @tencentcloud/trtc-component-wx
 cd roomkit
 npm init -y
-npm i @tencentcloud/tuiroom-engine-wx@2.3.1
+npm i @tencentcloud/tuiroom-engine-wx@2.4.0