本篇文档将指导您如何管理房间内的参会者。Atomicx 提供了开箱即用的列表组件
RoomParticipantList 用于快速集成,并暴露了 useRoomParticipantState Hook,方便您实现自定义的成员控制逻辑。功能介绍
成员管理模块涵盖了房间内用户信息展示以及权限处理的全套能力:
实时列表展示:动态呈现房间内所有成员的昵称、角色、音视频状态及音量波动。
权限控制:支持房主或管理员执行踢人、全员禁言、转让房主等管理操作。
分级管理:支持对房主、管理员及普通成员实现差异化的权限策略。
前提条件
用户已经通过 useLoginState 完成登录鉴权,请参考 接入概览。
用户已经通过 useRoomState 进入房间,请参考 房间管理。
集成成员管理组件
如果您需要快速构建成员列表界面,推荐直接使用
RoomParticipantList 组件。RoomParticipantList 是一个开箱即用的参会者列表组件,内置了完整的成员管理 UI 和交互。
集成
RoomParticipantList 组件示例代码:<template><div class="room-page"><!-- 参会者列表侧边栏 --><aside class="sidebar"><div class="sidebar-header"><span>参会者 ({{ currentRoom.participantCount }})</span><IconClose /></div><!-- 参会者列表组件 --><RoomParticipantList /></aside></div></template><script setup lang="ts">import { ref } from 'vue';import { IconClose } from '@tencentcloud/uikit-base-component-vue3';import {RoomView,RoomParticipantList,useRoomState,useRoomParticipantState} from 'tuikit-atomicx-vue3/room';const { currentRoom } = useRoomState();const { participantList } = useRoomParticipantState();</script><style scope>.room-page {width: 100vw;height: 100vh;min-width: 1150px;display: flex;flex-direction: row;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;position: relative;overflow: hidden;}.sidebar {position: absolute;top: 0;right: 0;width: 400px;height: 100%;box-sizing: border-box;}.sidebar-header {display: flex;height: 60px;justify-content: space-between;align-items: center;padding: 0px 20px;}</style>
说明:
RoomParticipantList 会自动占满父容器的高度和宽度,请确保其父容器具备明确的尺寸。使用
RoomParticipantList 组件请确保在 App.vue 中配置全局 UIKitProvider,具体请参考 配置 App.vue。实现成员管理功能
步骤1:获取成员列表
import { useRoomState, useRoomParticipantState } from 'tuikit-atomicx-vue3/room';const { currentRoom } = useRoomState();const { participantList, participantListCursor, getParticipantList } = useRoomParticipantState();// 在进房成功之后获取房间内用户列表watch(() => currentRoom.value?.roomId, async () => {await getParticipantList();})// 当列表滚动到底部时,加载更多用户const handleLoadMore = async () => {if (participantListCursor.value) {await getParticipantList({ cursor: participantListCursor.value });}};
说明:
getParticipantList 接口拉取成功的数据会自动维护在 participantList 中,UI 只需要渲染 participantList 的数据即可。步骤2:渲染参会者信息
<template><div class="participant-list"><div class="list-header"><h3>参会者 ({{ participantList.length }})</h3><button @click="handleRefresh"><IconRefresh /></button></div><div class="list-content"><divv-for="participant in participantList":key="participant.userId"class="participant-item"><!-- 头像 --><Avatar:user-id="participant.userId":avatar-url="participant.avatarUrl"/><!-- 用户信息 --><div class="user-info"><div class="user-name"><span>{{ participant.userName }}</span><span v-if="participant.userId === localParticipant.userId" class="badge">我</span><spanv-if="participant.role === RoomParticipantRole.Owner"class="role-badge owner">房主</span><spanv-else-if="participant.role === RoomParticipantRole.Admin"class="role-badge admin">管理员</span></div></div><!-- 设备状态 --><div class="device-status"><IconMicOnsize="20"v-if="participant.microphoneStatus === DeviceStatus.On"class="icon-on"/><IconMicOff size="20" v-else class="icon-off" /><IconCameraOnsize="20"v-if="participant.cameraStatus === DeviceStatus.On"class="icon-on"/><IconCameraOff size="20" v-else class="icon-off" /></div></div></div></div></template><script setup lang="ts">import { computed } from 'vue';import { IconRefresh, IconMicOn, IconMicOff, IconCameraOn, IconCameraOff } from '@tencentcloud/uikit-base-component-vue3';import {useRoomParticipantState,Avatar,RoomParticipantRole,DeviceStatus} from 'tuikit-atomicx-vue3/room';const {localParticipant,participantList,getParticipantList,transferOwner} = useRoomParticipantState();const handleRefresh = async () => {await getParticipantList({ cursor: '' });};</script><style scoped>.participant-list { display: flex; flex-direction: column; width: 400px; height: 100%; background-color: white;}.list-header { display: flex; align-items: center; justify-content: space-between; padding: 16px; border-bottom: 1px solid #e0e0e0;}.list-header h3 { margin: 0; font-size: 16px; font-weight: 600;}.list-content { flex: 1; overflow-y: auto; padding: 8px;}.participant-item { display: flex; align-items: center; gap: 12px; padding: 12px; border-radius: 8px; transition: background-color 0.2s;}.participant-item:hover { background-color: #f5f5f5;}.participant-item.is-local { background-color: #e3f2fd;}.user-info { flex: 1; min-width: 0;}.user-name { display: flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 500;}.badge { padding: 2px 6px; background-color: #4caf50; color: white; border-radius: 3px; font-size: 12px;}.role-badge { padding: 2px 6px; border-radius: 3px; font-size: 12px;}.role-badge.owner { background-color: #ff9800; color: white;}.role-badge.admin { background-color: #2196f3; color: white;}.device-status { display: flex; gap: 8px;}.icon-on { color: #4caf50;}.icon-off { color: #999;}.action-button { padding: 4px 8px; background: transparent; border: none; cursor: pointer; border-radius: 4px; color: #666;}.action-button:hover { background-color: #f0f0f0;}</style>
步骤3:设置用户自定义信息
开发者可以使用 updateParticipantMetaData 接口设置用户的自定义数据,用于实现职务、购买状态等能力。更新之后
metaData 信息将被维护在 participantList 对应用户的响应式数据中。<template><div v-for="participant in participantList" :key="participant.userId"><span>{{ participant.userName }}</span><span v-if="participant.metaData">{{ JSON.parse(participant.metaData).level }}</span></div></template><script setup lang="ts">import { computed } from 'vue';import { IconRefresh, IconMicOn, IconMicOff, IconCameraOn, IconCameraOff } from '@tencentcloud/uikit-base-component-vue3';import {useRoomParticipantState,} from 'tuikit-atomicx-vue3/room';const {updateParticipantMetaData,} = useRoomParticipantState();await updateParticipantMetaData({userId: '', // 指定用户 idmetaData: JSON.stringify({ level: 1 }), // 业务自定义信息})</script>
步骤4:管理成员身份
const { setAdmin, revokeAdmin } = useRoomParticipantState();// 将普通用户设置为管理员await setAdmin({ userId });// 将管理员设置为普通用户await revokeAdmin({ userId });
步骤5:管理成员媒体设备
import { useRoomParticipantState, DeviceType } from 'tuikit-atomicx-vue3/room';const { closeParticipantDevice } = useRoomParticipantState();// 强制关闭指定成员的麦克风async function handleCloseUserMicrophone(userId: string) {await closeParticipantDevice({userId,deviceType: DeviceType.Microphone,});}// 强制关闭指定成员的摄像头async function handleCloseUserCamera(userId: string) {await closeParticipantDevice({userId,deviceType: DeviceType.Camera,});}
步骤6:开启全局状态管理
禁用房间内所有普通用户的媒体设备
import { useRoomParticipantState, DeviceType } from 'tuikit-atomicx-vue3/room';const { closeParticipantDevice } = useRoomParticipantState();// 强制关闭所有普通成员的麦克风async function handleDisableAllMicrophone() {await disableAllDevices({deviceType: DeviceType.Microphone,disable: true,});}// 解除全员麦克风禁用async function handleEnableAllMicrophone() {await disableAllDevices({deviceType: DeviceType.Microphone,disable: false,});}// 强制关闭所有普通成员的摄像头async function handleDisableAllCamera() {await disableAllDevices({deviceType: DeviceType.Camera,disable: true,});}// 解除全员摄像头禁用async function handleEnableAllCamera() {await disableAllDevices({deviceType: DeviceType.Camera,disable: false,});}
禁用房间内所有普通用户的会中聊天
import { useRoomParticipantState, DeviceType } from 'tuikit-atomicx-vue3/room';const { disableAllMessages } = useRoomParticipantState();// 强制禁用所有普通成员的聊天能力async function handleDisableAllMessage() {await disableAllMessages({disable: true,});}
步骤7:监控成员发言状态
const { speakingUsers } = useRoomParticipantState();// 判断用户是否正在说话const isSpeaking = (userId: string) => speakingUsers.value.has(userId);// 获取用户实时音量 (0-100)const getVolume = (userId: string) => speakingUsers.value.get(userId) || 0;
步骤8:踢出房间内成员
const { kickParticipant } = useRoomParticipantState();// 将用户踢出房间await kickParticipant({ userId });
步骤9:邀请其他人加入房间
API 文档
State/Component | 功能描述 | API 文档 |
useRoomParticipantState | 包含房间内用户数据,用户管理接口。 |
开发建议
权限校验:在 UI 层建议通过
participant.role 判断当前用户的操作权限,对不具备管理权限的用户隐藏踢人或禁言按钮。<script setup>import { RoomParticipantRole } from 'tuikit-atomicx-vue3/room';const { localParticipant } = useRoomParticipantState();// 判断当前用户是否有管理权限const hasAdminPermission = computed(() => {return localParticipant.value.role === RoomParticipantRole.Owner ||localParticipant.value.role === RoomParticipantRole.Admin;});</script>// 在模板中使用<template><button v-if="hasAdminPermission" @click="handleKick">踢出</button><template>