UNPKG

@tencentcloud/roomkit-web-vue3

Version:

<h1 align="center"> TUIRoomKit</h1> Conference (TUIRoomKit) is a product suitable for multi-person audio and video conversation scenarios such as business meetings, webinars, and online education. By integrating this product, you can add room management,

379 lines (357 loc) 12 kB
// Raise hands to speak logic import { onBeforeUnmount, computed, watch } from 'vue'; import TUIRoomEngine, { TUIRoomEvents, TUIRequestAction, TUIRequest, TUIRequestCallbackType, TUIErrorCode, } from '@tencentcloud/tuiroom-engine-js'; import useGetRoomEngine from './useRoomEngine'; import { TUIToast, TOAST_TYPE } from '@tencentcloud/uikit-base-component-vue3'; import { MESSAGE_DURATION } from '../constants/message'; import { useRoomStore, UserInfo } from '../stores/room'; import { storeToRefs } from 'pinia'; import { useI18n } from '../locales'; import logger from '../utils/common/logger'; import { useBasicStore } from '../stores/basic'; import TUINotification from '../components/common/base/Notification'; import { isMobile } from '../utils/environment'; import { arrayIsEqual } from '../utils/utils'; const roomEngine = useGetRoomEngine(); export default function () { const roomStore = useRoomStore(); const basicStore = useBasicStore(); const { applyToAnchorList } = storeToRefs(roomStore); const { showApplyUserList } = storeToRefs(basicStore); const { t } = useI18n(); let notification: { close: () => void } | null; const applyToAnchorUserIdList = computed(() => applyToAnchorList.value.map(item => item.userId) ); const applyToAnchorUserCount = computed(() => applyToAnchorList.value.length); // ------ The following handles common user operations --------- // new: Receive an application from a user function onRequestReceived(eventInfo: { request: TUIRequest }) { const { requestAction, requestId, userId, timestamp } = eventInfo.request; if (requestAction === TUIRequestAction.kRequestToTakeSeat) { // User application for stage userId && roomStore.addApplyToAnchorUser({ userId, requestId, timestamp }); } } // The remote user cancels the application to connect to the stage function onRequestCancelled(eventInfo: { requestId: string; userId: string; }) { const { requestId } = eventInfo; roomStore.removeApplyToAnchorUser(requestId); } // The remote user's request is handled by other administrators/hosts. function onRequestProcessed(eventInfo: { requestId: string; userId: string; }) { const { requestId } = eventInfo; roomStore.removeApplyToAnchorUser(requestId); } // Handle user requests async function handleUserApply(applyUserId: string, agree: boolean) { try { // TUIRoomCore.replySpeechApplication(applyUserId, agree); const userInfo = roomStore.userInfoObj[applyUserId]; const requestId = userInfo.applyToAnchorRequestId; if (requestId) { await roomEngine.instance?.responseRemoteRequest({ requestId, agree, }); roomStore.removeApplyToAnchorUser(requestId); } else { logger.warn( 'Failed to process the stage application. The data is abnormal. Please try again!', userInfo ); } } catch (error: any) { if (error.code === TUIErrorCode.ERR_ALL_SEAT_OCCUPIED) { TUIToast({ type: TOAST_TYPE.WARNING, message: t('The stage is full'), }); } else { logger.error('Failure to process a user request', error); } } } // agree user to stage async function agreeUserOnStage(userInfo: UserInfo) { try { const requestId = userInfo.applyToAnchorRequestId; if (requestId) { await roomEngine.instance?.responseRemoteRequest({ requestId, agree: true, }); roomStore.removeApplyToAnchorUser(requestId); } else { logger.warn( 'Failed to process the stage application. The data is abnormal. Please try again!', userInfo ); } } catch (error: any) { if (error.code === TUIErrorCode.ERR_ALL_SEAT_OCCUPIED) { TUIToast({ type: TOAST_TYPE.WARNING, message: t('The stage is full'), }); } else { logger.error('Failed application for consent to go on stage', error); } } } // reject user to stage async function denyUserOnStage(userInfo: UserInfo) { const requestId = userInfo.applyToAnchorRequestId; if (requestId) { await roomEngine.instance?.responseRemoteRequest({ requestId, agree: false, }); roomStore.removeApplyToAnchorUser(requestId); } else { logger.warn( 'Failed to process the stage application. The data is abnormal. Please try again!', userInfo ); } } // Process all users’ requests to access the microphone async function handleAllUserApply(isAgreeOrRejectAllUserApply: boolean) { let hasErrorOccurred = false; const applyUserList = applyToAnchorList.value.map(item => ({ userId: item.userId, userName: item.nameCard || item.userName, applyToAnchorRequestId: item.applyToAnchorRequestId, })); for (const { applyToAnchorRequestId } of applyUserList) { const action = isAgreeOrRejectAllUserApply ? 'Agree' : 'Reject'; const actionFailedMessage = `${action} sb on stage failed, please retry`; try { if (applyToAnchorRequestId) { await roomEngine.instance?.responseRemoteRequest({ requestId: applyToAnchorRequestId, agree: isAgreeOrRejectAllUserApply, }); roomStore.removeApplyToAnchorUser(applyToAnchorRequestId); } } catch (error) { if (!hasErrorOccurred) { logger.error(actionFailedMessage); TUIToast({ type: TOAST_TYPE.WARNING, message: t('The stage is full'), duration: MESSAGE_DURATION.NORMAL, }); hasErrorOccurred = true; } } } } TUIRoomEngine.once('ready', () => { roomEngine.instance?.on(TUIRoomEvents.onRequestReceived, onRequestReceived); roomEngine.instance?.on( TUIRoomEvents.onRequestCancelled, onRequestCancelled ); roomEngine.instance?.on( TUIRoomEvents.onRequestProcessed, onRequestProcessed ); }); onBeforeUnmount(() => { roomEngine.instance?.off( TUIRoomEvents.onRequestReceived, onRequestReceived ); roomEngine.instance?.off( TUIRoomEvents.onRequestCancelled, onRequestCancelled ); roomEngine.instance?.off( TUIRoomEvents.onRequestProcessed, onRequestProcessed ); }); // --------- The following handles the moderator’s active operations ---------- // Invite users to the stage async function inviteUserOnStage(userInfo: UserInfo) { const { userId } = userInfo; const request = await roomEngine.instance?.takeUserOnSeatByAdmin({ seatIndex: -1, userId, timeout: 60, requestCallback: (callbackInfo: { requestCallbackType: TUIRequestCallbackType; userId: string; code: TUIErrorCode; }) => { const { requestCallbackType, userId, code } = callbackInfo; const userName = roomStore.getUserName(userId); roomStore.removeInviteToAnchorUser(userId); switch (requestCallbackType) { case TUIRequestCallbackType.kRequestAccepted: TUIToast({ type: TOAST_TYPE.SUCCESS, message: `${userName || userId} ${t('accepted the invitation to the stage')}`, duration: MESSAGE_DURATION.NORMAL, }); break; case TUIRequestCallbackType.kRequestRejected: TUIToast({ type: TOAST_TYPE.WARNING, message: `${userName || userId} ${t('declined the invitation to the stage')}`, duration: MESSAGE_DURATION.NORMAL, }); break; case TUIRequestCallbackType.kRequestTimeout: TUIToast({ type: TOAST_TYPE.WARNING, message: t('The invitation to sb to go on stage has timed out', { name: userName || userId, }), duration: MESSAGE_DURATION.NORMAL, }); break; case TUIRequestCallbackType.kRequestError: if (code === TUIErrorCode.ERR_REQUEST_ID_REPEAT) { TUIToast({ type: TOAST_TYPE.WARNING, message: t( 'This member has already received the same request, please try again later' ), duration: MESSAGE_DURATION.NORMAL, }); } break; default: break; } }, }); if (request && request.requestId) { roomStore.addInviteToAnchorUser({ userId, requestId: request.requestId }); } } // Cancel invite users to the stage function cancelInviteUserOnStage(userInfo: UserInfo) { const { userId, inviteToAnchorRequestId } = userInfo; roomStore.removeInviteToAnchorUser(userId); if (inviteToAnchorRequestId) { roomEngine.instance?.cancelRequest({ requestId: inviteToAnchorRequestId, }); } } // Invite to step down function kickUserOffStage(userInfo: UserInfo) { roomEngine.instance?.kickUserOffSeatByAdmin({ seatIndex: -1, userId: userInfo.userId, }); } const handleConfirm = async ( onlyOneUserTakeStage: boolean, userId: string ) => { if (isMobile) { basicStore.setSidebarOpenStatus(true); basicStore.setSidebarName('apply'); } else { if (onlyOneUserTakeStage) { handleUserApply(userId, true); } else { basicStore.setShowApplyUserList(true); } } }; const handleCancel = async ( onlyOneUserTakeStage: boolean, userId: string ) => { if (!isMobile && onlyOneUserTakeStage) { handleUserApply(userId, false); } }; function hideApplyList() { basicStore.setShowApplyUserList(false); } function handleShowNotification() { watch(applyToAnchorUserIdList, (newVal, oldVal) => { if (arrayIsEqual(newVal, oldVal)) { return; } if (newVal.length === 0) { notification && notification.close(); notification = null; return; } const onlyOneUserTakeStage = newVal.length === 1; const firstUser = applyToAnchorList.value[0]; const lastIndex = applyToAnchorList.value.length - 1; const userName = applyToAnchorList.value[lastIndex]?.nameCard || 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 })}`; const confirmButtonText = isMobile ? t('Check') : onlyOneUserTakeStage ? t('Agree to the stage') : t('Check'); const cancelButtonText = isMobile ? undefined : onlyOneUserTakeStage ? t('Reject') : t('Neglect'); const confirm = () => handleConfirm(onlyOneUserTakeStage, firstUser?.userId); const cancel = () => handleCancel(onlyOneUserTakeStage, firstUser?.userId); notification = TUINotification({ message, confirmButtonText, cancelButtonText, confirm, cancel, }); }); } return { t, roomStore, showApplyUserList, hideApplyList, applyToAnchorUserCount, applyToAnchorList, // Process the user's application for accessing the stage (agree/reject) handleUserApply, // Allow ordinary users to take the stage agreeUserOnStage, // Reject ordinary users to take the stage denyUserOnStage, // Invite users to the stage inviteUserOnStage, // Cancel invite users to the stage cancelInviteUserOnStage, // Kick the user off the stage kickUserOffStage, // Handle all user requests handleAllUserApply, handleShowNotification, }; }