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,

499 lines (498 loc) 17.4 kB
import { ref, reactive, computed } from "vue"; import { useI18n } from "../../../locales/index.mjs"; import { useRoomStore } from "../../../stores/room.mjs"; import useRoomEngine from "../../../hooks/useRoomEngine.mjs"; import { useBasicStore } from "../../../stores/basic.mjs"; import useMasterApplyControl from "../../../hooks/useMasterApplyControl.mjs"; import { TUIRole, TUIMediaDevice, TUIRequestCallbackType, TUIErrorCode } from "@tencentcloud/tuiroom-engine-js"; import { storeToRefs } from "pinia"; import { MESSAGE_DURATION } from "../../../constants/message.mjs"; import bus from "../../../hooks/useMitt.mjs"; import useMemberItem from "../MemberItem/useMemberItemHooks.mjs"; import "../../../services/main.mjs"; import { roomService } from "../../../services/roomService.mjs"; import { isMobile } from "../../../utils/environment.mjs"; import { calculateByteLength } from "../../../utils/utils.mjs"; import "mitt"; import "../../../services/manager/roomActionManager.mjs"; import "@tencentcloud/tui-core"; import { IconAudioOpen, IconVideoOpen, IconChatForbidden, IconTransferOwner, IconRevokeAdmin, IconSetAdmin, IconKickOut, IconDenyOnStage, IconInviteOnStage, IconOnStage, IconOffStage, IconEditNameCard, TUIToast, TOAST_TYPE } from "@tencentcloud/uikit-base-component-vue3"; function useMemberControl(props) { const roomEngine = useRoomEngine(); const { t } = useI18n(); const basicStore = useBasicStore(); const roomStore = useRoomStore(); const isDialogVisible = ref(false); const isShowInput = ref(false); const editorInputEle = ref(); const editorInputEleContainer = ref(); const tempUserName = ref(""); const dialogData = reactive({ title: "", content: "", confirmText: "", actionType: "", showInput: false, isConfirmButtonDisable: false }); const kickOffDialogContent = computed( () => t("whether to kick sb off the room", { name: roomService.getDisplayName(props.userInfo) }) ); const transferOwnerTitle = computed( () => t("Transfer the roomOwner to sb", { name: roomService.getDisplayName(props.userInfo) }) ); const { isFreeSpeakMode, isSpeakAfterTakingSeatMode, localUser, isGeneralUser, anchorUserList, maxSeatCount } = storeToRefs(roomStore); const { agreeUserOnStage, denyUserOnStage, inviteUserOnStage, cancelInviteUserOnStage, kickUserOffStage } = useMasterApplyControl(); const { isCanOperateMySelf } = useMemberItem(props.userInfo); const isMe = computed(() => basicStore.userId === props.userInfo.userId); const isTargetUserAnchor = computed(() => props.userInfo.onSeat === true); const isTargetUserAudience = computed(() => props.userInfo.onSeat !== true); const controlList = computed(() => { if (isCanOperateMySelf.value) { return [changeUserNameCard.value]; } const agreeOrDenyStageList = props.userInfo.isUserApplyingToAnchor ? [agreeOnStage.value, denyOnStage.value] : []; const inviteStageList = isTargetUserAudience.value && !props.userInfo.isUserApplyingToAnchor ? [inviteOnStage.value] : []; const onStageControlList = isTargetUserAnchor.value ? [audioControl.value, videoControl.value, makeOffStage.value] : []; const controlListObj = { freeSpeak: { [TUIRole.kRoomOwner]: [ audioControl.value, videoControl.value, chatControl.value, setOrRevokeAdmin.value, transferOwner.value, kickUser.value, changeUserNameCard.value ], [TUIRole.kAdministrator]: [ audioControl.value, videoControl.value, chatControl.value, changeUserNameCard.value ] }, speakAfterTakeSeat: { [TUIRole.kRoomOwner]: [ ...inviteStageList, ...onStageControlList, ...agreeOrDenyStageList, setOrRevokeAdmin.value, transferOwner.value, chatControl.value, kickUser.value, changeUserNameCard.value ], [TUIRole.kAdministrator]: [ ...inviteStageList, ...onStageControlList, ...agreeOrDenyStageList, chatControl.value, changeUserNameCard.value ] } }; if (isFreeSpeakMode.value) { return controlListObj.freeSpeak[localUser.value.userRole] || []; } if (isSpeakAfterTakingSeatMode.value) { return controlListObj.speakAfterTakeSeat[localUser.value.userRole] || []; } return []; }); const audioControl = computed(() => ({ key: "audioControl", icon: IconAudioOpen, title: props.userInfo.hasAudioStream ? t("Mute") : t("Unmute"), func: muteUserAudio })); const videoControl = computed(() => { const videoControlTitle = props.userInfo.hasVideoStream ? t("Disable video") : t("Enable video"); return { key: "videoControl", icon: IconVideoOpen, title: videoControlTitle, func: muteUserVideo }; }); const chatControl = computed(() => ({ key: "chatControl", icon: IconChatForbidden, title: props.userInfo.isMessageDisabled ? t("Enable chat") : t("Disable chat"), func: disableUserChat })); const transferOwner = computed(() => ({ key: "transferOwner", icon: IconTransferOwner, title: t("Make host"), func: () => handleOpenDialog("transferOwner") })); const setOrRevokeAdmin = computed(() => ({ key: "setOrRevokeAdmin", icon: props.userInfo.userRole === TUIRole.kAdministrator ? IconRevokeAdmin : IconSetAdmin, title: props.userInfo.userRole === TUIRole.kAdministrator ? t("Remove administrator") : t("Set as administrator"), func: handleSetOrRevokeAdmin })); const kickUser = computed(() => ({ key: "kickUser", icon: IconKickOut, title: t("Kick out"), func: () => handleOpenDialog("kickUser") })); const inviteOnStage = computed(() => ({ key: "inviteOnStage", icon: props.userInfo.isInvitingUserToAnchor ? IconDenyOnStage : IconInviteOnStage, title: props.userInfo.isInvitingUserToAnchor ? t("Cancel stage") : t("Invite stage"), func: toggleInviteUserOnStage })); const agreeOnStage = computed(() => ({ key: "agreeOnStage", icon: IconOnStage, title: t("Agree to the stage"), func: agreeUserOnStage })); const denyOnStage = computed(() => ({ key: "denyOnStage", icon: IconDenyOnStage, title: t("Refuse stage"), func: denyUserOnStage })); const makeOffStage = computed(() => ({ key: "makeOffStage", icon: IconOffStage, title: t("Step down"), func: kickUserOffStage })); const changeUserNameCard = computed(() => ({ key: "changeUserNameCard", icon: IconEditNameCard, title: t("change name"), func: () => handleOpenDialog("changeUserNameCard") })); async function toggleInviteUserOnStage(userInfo) { const { isInvitingUserToAnchor } = userInfo; if (isInvitingUserToAnchor) { cancelInviteUserOnStage(userInfo); } else { if (anchorUserList.value.length === maxSeatCount.value) { TUIToast({ type: TOAST_TYPE.WARNING, message: `${t("The stage is full")}`, duration: MESSAGE_DURATION.NORMAL }); return; } inviteUserOnStage(userInfo); } } async function muteUserAudio(userInfo) { var _a, _b; if (userInfo.hasAudioStream) { await ((_a = roomEngine.instance) == null ? void 0 : _a.closeRemoteDeviceByAdmin({ userId: userInfo.userId, device: TUIMediaDevice.kMicrophone })); } else { if (userInfo.isRequestingUserOpenMic) { TUIToast({ type: TOAST_TYPE.INFO, message: `${t("An invitation to open the microphone has been sent to sb.", { name: roomService.getDisplayName(userInfo) })}`, duration: MESSAGE_DURATION.NORMAL }); return; } const request = await ((_b = roomEngine.instance) == null ? void 0 : _b.openRemoteDeviceByAdmin({ userId: userInfo.userId, device: TUIMediaDevice.kMicrophone, timeout: 0, requestCallback: (callbackInfo) => { roomStore.setRequestUserOpenMic({ userId: userInfo.userId, isRequesting: false }); const { requestCallbackType, code } = callbackInfo; switch (requestCallbackType) { 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; } } })); TUIToast({ type: TOAST_TYPE.INFO, message: `${t("An invitation to open the microphone has been sent to sb.", { name: roomService.getDisplayName(userInfo) })}`, duration: MESSAGE_DURATION.NORMAL }); if (request && request.requestId) { roomStore.setRequestUserOpenMic({ userId: userInfo.userId, isRequesting: true, requestId: request.requestId }); } } } async function muteUserVideo(userInfo) { var _a, _b; if (userInfo.hasVideoStream) { await ((_a = roomEngine.instance) == null ? void 0 : _a.closeRemoteDeviceByAdmin({ userId: userInfo.userId, device: TUIMediaDevice.kCamera })); } else { if (userInfo.isRequestingUserOpenCamera) { TUIToast({ type: TOAST_TYPE.INFO, message: `${t("An invitation to open the camera has been sent to sb.", { name: roomService.getDisplayName(userInfo) })}`, duration: MESSAGE_DURATION.NORMAL }); return; } const request = await ((_b = roomEngine.instance) == null ? void 0 : _b.openRemoteDeviceByAdmin({ userId: userInfo.userId, device: TUIMediaDevice.kCamera, timeout: 0, requestCallback: (callbackInfo) => { roomStore.setRequestUserOpenCamera({ userId: userInfo.userId, isRequesting: false }); const { requestCallbackType, code } = callbackInfo; switch (requestCallbackType) { 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; } } })); TUIToast({ type: TOAST_TYPE.INFO, message: `${t("An invitation to open the camera has been sent to sb.", { name: roomService.getDisplayName(userInfo) })}`, duration: MESSAGE_DURATION.NORMAL }); if (request && request.requestId) { roomStore.setRequestUserOpenCamera({ userId: userInfo.userId, isRequesting: true, requestId: request.requestId }); } } } async function disableUserChat(userInfo) { var _a; const { isMessageDisabled } = userInfo; try { await ((_a = roomEngine.instance) == null ? void 0 : _a.disableSendingMessageByAdmin({ userId: userInfo.userId, isDisable: !isMessageDisabled })); roomStore.setMuteUserChat(userInfo.userId, !isMessageDisabled); } catch (error) { TUIToast({ type: TOAST_TYPE.ERROR, message: t("Failed to disable chat"), duration: MESSAGE_DURATION.NORMAL }); } } async function kickOffUser(userInfo) { var _a; await ((_a = roomEngine.instance) == null ? void 0 : _a.kickRemoteUserOutOfRoom({ userId: userInfo.userId })); roomStore.removeUserInfo(userInfo.userId); } async function handleTransferOwner(userInfo) { var _a, _b; const roomInfo = await ((_a = roomEngine.instance) == null ? void 0 : _a.fetchRoomInfo()); if ((roomInfo == null ? void 0 : roomInfo.roomOwner) === roomStore.localUser.userId) { try { if (roomStore.localUser.hasScreenStream && roomStore.isScreenShareDisableForAllUser) { bus.emit("ScreenShare:stopScreenShare"); } await ((_b = roomEngine.instance) == null ? void 0 : _b.changeUserRole({ userId: userInfo.userId, userRole: TUIRole.kRoomOwner })); roomStore.setMasterUserId(userInfo.userId); TUIToast({ type: TOAST_TYPE.SUCCESS, message: t("The room owner has been transferred to sb", { name: roomService.getDisplayName(userInfo) }), duration: MESSAGE_DURATION.NORMAL }); } catch (error) { TUIToast({ type: TOAST_TYPE.ERROR, message: t("Make host failed, please try again."), duration: MESSAGE_DURATION.NORMAL }); } } } async function handleSetOrRevokeAdmin(userInfo) { var _a, _b; const newRole = userInfo.userRole === TUIRole.kGeneralUser ? TUIRole.kAdministrator : TUIRole.kGeneralUser; await ((_a = roomEngine.instance) == null ? void 0 : _a.changeUserRole({ userId: userInfo.userId, userRole: newRole })); const updatedUserName = roomStore.getUserName(userInfo.userId); const tipMessage = newRole === TUIRole.kAdministrator ? `${t("sb has been set as administrator", { name: updatedUserName })}` : `${t("The administrator status of sb has been withdrawn", { name: updatedUserName })}`; TUIToast({ type: TOAST_TYPE.SUCCESS, message: tipMessage }); roomStore.setRemoteUserRole(userInfo.userId, newRole); if (newRole === TUIRole.kGeneralUser && userInfo.hasScreenStream) { await ((_b = roomEngine.instance) == null ? void 0 : _b.closeRemoteDeviceByAdmin({ userId: userInfo.userId, device: TUIMediaDevice.kScreen })); } } function handleOpenDialog(action) { var _a; switch (action) { case "kickUser": isDialogVisible.value = true; Object.assign(dialogData, { title: t("Note"), content: kickOffDialogContent.value, confirmText: t("Confirm"), actionType: action, showInput: false, isConfirmButtonDisable: false }); break; case "transferOwner": isDialogVisible.value = true; Object.assign(dialogData, { title: transferOwnerTitle.value, content: t( "After transfer the room owner, you will become a general user" ), confirmText: t("Confirm transfer"), actionType: action, showInput: false, isConfirmButtonDisable: false }); break; case "changeUserNameCard": tempUserName.value = props.userInfo.nameCard || props.userInfo.userName; if (isMobile) { isShowInput.value = true; (_a = document == null ? void 0 : document.body) == null ? void 0 : _a.appendChild(editorInputEleContainer.value); } else { isDialogVisible.value = true; } Object.assign(dialogData, { title: t("change name"), content: "", confirmText: t("Confirm"), actionType: action, showInput: true, isConfirmButtonDisable: computed(() => tempUserName.value === "") }); break; } } const nameCardCheck = () => { const result = calculateByteLength(tempUserName.value) <= 32; !result && TUIToast({ type: TOAST_TYPE.WARNING, message: t("The user name cannot exceed 32 characters"), duration: MESSAGE_DURATION.NORMAL }); return result; }; async function handleChangeUserNameCard(userInfo) { var _a; if (!nameCardCheck()) return; try { await ((_a = roomEngine.instance) == null ? void 0 : _a.changeUserNameCard({ userId: userInfo.userId, nameCard: tempUserName.value })); TUIToast({ type: TOAST_TYPE.SUCCESS, message: t("Name changed successfully"), duration: MESSAGE_DURATION.NORMAL }); } catch (error) { TUIToast({ type: TOAST_TYPE.ERROR, message: t("change name failed, please try again."), duration: MESSAGE_DURATION.NORMAL }); } } function handleAction(userInfo) { switch (dialogData.actionType) { case "kickUser": kickOffUser(userInfo); break; case "transferOwner": handleTransferOwner(userInfo); break; case "changeUserNameCard": handleChangeUserNameCard(userInfo); isShowInput.value = false; } isDialogVisible.value = false; } function handleCancelDialog() { tempUserName.value = props.userInfo.nameCard || props.userInfo.userName; isDialogVisible.value = false; } return { props, isMe, isGeneralUser, controlList, kickOffDialogContent, handleCancelDialog, handleAction, isDialogVisible, dialogData, tempUserName, isShowInput, editorInputEle, editorInputEleContainer }; } export { useMemberControl as default };