成员管理(Web)

最近更新时间:2025-12-29 17:09:52

我的收藏
本篇文档将指导您如何管理房间内的参会者。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

实现成员管理功能

如果您需要自定义成员列表 UI 或在特定业务中触发管理行为,请使用 useRoomParticipantState

步骤1:获取成员列表

通过 getParticipantList 获取响应式的成员数据 participantList
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:渲染参会者信息

开发者可以使用 participantList 数据自定义渲染用户信息列表。
<template>
<div class="participant-list">
<div class="list-header">
<h3>参会者 ({{ participantList.length }})</h3>
<button @click="handleRefresh">
<IconRefresh />
</button>
</div>
<div class="list-content">
<div
v-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>
<span
v-if="participant.role === RoomParticipantRole.Owner"
class="role-badge owner"
>
房主
</span>
<span
v-else-if="participant.role === RoomParticipantRole.Admin"
class="role-badge admin"
>
管理员
</span>
</div>
</div>

<!-- 设备状态 -->
<div class="device-status">
<IconMicOn
size="20"
v-if="participant.microphoneStatus === DeviceStatus.On"
class="icon-on"
/>
<IconMicOff size="20" v-else class="icon-off" />
<IconCameraOn
size="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: '', // 指定用户 id
metaData: JSON.stringify({ level: 1 }), // 业务自定义信息
})
</script>

步骤4:管理成员身份

房主可以通过 setAdmin 接口变更用户角色为管理员, 通过 revokeAdmin 方法撤销用户管理员身份。
const { setAdmin, revokeAdmin } = useRoomParticipantState();

// 将普通用户设置为管理员
await setAdmin({ userId });

// 将管理员设置为普通用户
await revokeAdmin({ userId });

步骤5:管理成员媒体设备

房主及管理员可以通过 closeParticipantDevice 接口远程控制其他成员的媒体设备,以维持会议环境的安静及有序。
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:开启全局状态管理

房主及管理员可通过 disableAllDevicesdisableAllMessages 接口开启房间全局状态管理。

禁用房间内所有普通用户的媒体设备

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:监控成员发言状态

通过 speakingUsers 可以实时获取房间内正在说话的用户及其音量大小。
const { speakingUsers } = useRoomParticipantState();

// 判断用户是否正在说话
const isSpeaking = (userId: string) => speakingUsers.value.has(userId);
// 获取用户实时音量 (0-100)
const getVolume = (userId: string) => speakingUsers.value.get(userId) || 0;

步骤8:踢出房间内成员

房主及管理员可以通过 kickParticipant 接口将用户移出房间。
const { kickParticipant } = useRoomParticipantState();

// 将用户踢出房间
await kickParticipant({ userId });

步骤9:邀请其他人加入房间

实际业务中,您可能需要向未进房的用户发起呼叫邀请。Atomicx 提供了完整的呼叫系统支持,请查看 会中呼叫

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>