import styles from '@/page/Meeting/index.module.scss' import { useEffect, useRef, useState } from "react"; import Operation from '@/components/Operation'; import SpeakerModeModal from '@/components/SpeakerModeModal'; import InvitingPersonnelModal from '@/components/InvitingPersonnelModal'; import { Button, Input, Popover, Modal, Checkbox, message, Popconfirm, notification } from "antd"; import { SearchOutlined, EllipsisOutlined, ExclamationCircleFilled, FullscreenExitOutlined, FullscreenOutlined, QuestionCircleOutlined, CaretLeftOutlined, CaretRightOutlined, CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons'; import { useLocation, useNavigate } from 'react-router-dom'; import { thumbImageBufferToBase64 } from '@/utils/package/base64' import { storage } from '@/utils'; import { GetRoomUser, PostOpenMicr, GetSharedScreen, PostOpenCamera, GetLeaveAll, PostRoomManager, DeleteRoomManager, GetRoomKickout, GetShowUser, PostShowUser, PostMuteAll, GetRoomUserItem, GetApplySpeak, PostSharedScreen } from '@/api/Meeting'; import ImageUrl from '@/utils/package/imageUrl' import { agora } from '@/utils/package/agora' import dayjs from 'dayjs'; import durationPlugin from 'dayjs/plugin/duration'; import { AudioVolumeInfo, ConnectionChangedReasonType, ConnectionStateType, LocalVideoStreamReason, LocalVideoStreamState, RenderModeType, RtcConnection, RtcStats, UserOfflineReasonType, VideoSourceType, VideoStreamType } from 'agora-electron-sdk'; import Avatar from '@/components/Avatar'; import SharedFilesModel from '@/components/SharedFilesModel'; import StupWizard from '@/components/StupWizard'; import EquipmentManagement from '@/components/EquipmentManagement'; import UserVideo from '@/components/UserVideo'; import { role } from '@/config/role'; import { fixWebmDuration } from "webm-duration-fix-buffer"; import { getKeyOpenChildWindow, setKeyOpenChildWindow } from '@/utils/package/public'; import MeetingDisconnected from '@/components/MeetingDisconnected'; import SingIn from '@/components/SingIn'; import UserName from '@/components/UserName'; import { GetRoomRtcToken } from '@/api/Home/Index'; const { setTimeout, setInterval, clearTimeout, clearInterval } = require('timers'); const { confirm } = Modal; const { exec } = require('child_process'); const fs = require('fs').promises; dayjs.extend(durationPlugin); const Meeting: React.FC = () => { const navigate = useNavigate(); const { state } = useLocation(); const speakerModeModalRef = useRef(); const sharedFilesModelRef = useRef(); const invitingPersonnelRef = useRef(); const stupWizardRef = useRef(); const equipmentManagementRef = useRef(); const meetingDisconnectedRef = useRef(); const singInRef = useRef(); const userNameRef = useRef(); const [isClicked, setIsClicked] = useState(false); const [isClickedMediaSteam, setIsClickedMediaSteam] = useState(false); const [statusList, setStatusList] = useState({ userList: false, userChatList: false, userVideo: false, }) const [isSharedScreenModal, setIsSharedScreenModal] = useState(false); const [quitMeetingModal, setQuitMeetingModal] = useState(false); const [user, setUser] = useState({}); const [sharedScreenList, setSharedScreenList] = useState([]); const [sharedScreenItem, setSharedScreenItem] = useState(''); const [textMsg, setTextMsg] = useState(''); const [footerList, setFooterList] = useState([ [ { title: '解除静音', icon: ImageUrl.icon22, iconActive: ImageUrl.icon22Active, active: true, select: false, }, { title: '开启视频', icon: ImageUrl.icon23, iconActive: ImageUrl.icon23Active, active: true, select: false, }, { title: '申请发言', icon: ImageUrl.icon47, iconActive: ImageUrl.icon47Active, active: false, select: false, }, ], [ { title: '共享屏幕', icon: ImageUrl.icon24, iconSelect: ImageUrl.icon24Select, active: false, select: false, }, { title: '共享文件', icon: ImageUrl.icon25, iconSelect: ImageUrl.icon25Select, active: false, select: false, }, { title: '邀请人员', icon: ImageUrl.icon26, iconSelect: ImageUrl.icon26Select, active: false, select: false, }, { title: '录制', icon: ImageUrl.icon27, iconSelect: ImageUrl.icon27Select, iconActive: ImageUrl.icon27Active, active: false, select: false, }, { title: '签到', icon: ImageUrl.icon52, iconSelect: ImageUrl.icon52Select, active: false, select: false, }, { title: '设置', icon: ImageUrl.icon28, iconSelect: ImageUrl.icon28Select, active: false, select: false, }, { title: '结束', icon: ImageUrl.icon29, iconSelect: ImageUrl.icon29Select, active: false, select: false, }, ], [{ title: '会议监控', icon: ImageUrl.icon48, iconSelect: ImageUrl.icon48Select, active: false, select: false, }, { title: '成员列表', icon: ImageUrl.icon30, iconSelect: ImageUrl.icon30Select, active: false, select: false, }, { title: '聊天', icon: ImageUrl.icon31, iconSelect: ImageUrl.icon31Select, active: false, select: false, }, ], ]) const [footerListIndex, setFooterListIndex] = useState({ itemIndex: 0, rowIndex: 0, }); const [roomUserList, setRoomUserList] = useState([]) const [_speackUid, setSpeackUid] = useState([]) const [currentSpeakUser, setCurrentSpeakUser] = useState([]) const [chatList, setChatList] = useState([]) const [isExpand, setIsExpand] = useState(false) const [currentVideoId, setCurrentVideoId] = useState('') const [currentVideoUid, setCurrentVideoUid] = useState('') let [currentSeconds, setCurrentSeconds] = useState(0) const [isNetworkQuality, setIsNetworkQuality] = useState(false) const [currentEffective, setCurrentEffective] = useState(3) const [networkQuality, setNetworkQuality] = useState({ level: '佳', text: '网络质量极好' }) const [networkOther, setNetworkOther] = useState({}) const [isComputerAudio, setIsComputerAudio] = useState(false) const [_isLeave, setIsLeave] = useState(false) const [isScreenCapture, setIsScreenCapture] = useState(false) const [isFluencyPriority, setIsFluencyPriority] = useState(false) const [isClickLock, setIsClickLock] = useState(false) const [open, setOpen] = useState(false) const [modeOpen, setModeOpen] = useState(false) const [meetingMode, setMeetingMode] = useState('') const [userSearchValue, setUserSearchValue] = useState('') const [noViewChatList, setNoViewChatList] = useState(0) const [currentLookUserAccount, setCurrentLookUserAccount] = useState('') const [recorder, setRecorder] = useState('') const [contextMenu, setContextMenu] = useState('') const [contextMenuStyle, setContextMenuStyle] = useState({ top: 0, left: 0, }) const [_currentRequestSpeakType, setCurrentRequestSpeakType] = useState<'video' | 'audio' | ''>('') const [_mediaStream, setMediaStream] = useState([]) const [isShare, setIsShare] = useState(null) const [isSharePopConfirm, setIsSharePopConfirm] = useState(false) const [_isNetworkDisconnected, setIsNetworkDisconnected] = useState(false) const [isAgoraDisconnected, setIsAgoraDisconnected] = useState(false) const [isShareUser, setIsShareUser] = useState(null) const [currentLookUserStatus, setCurrentLookUserStatus] = useState<0 | 1 | 2 | 3 | 4>(1) const [commonlyChatList] = useState([ '能听到我说话吗?', '听得到', '听不到', '我要发言', ]) const [roomUserItem, setRoomUserItem] = useState(null) const [isAdmin, setIsAdmin] = useState(0) const [_socketRemberNumber, setSocketRemberNumber] = useState(0) const [api, contextHolder] = notification.useNotification({ stack: { threshold: 3 } }); const [isVideoFullScreen, setIsVideoFullScreen] = useState(false) const [observer, setObserver] = useState() let userInfo = JSON.parse(storage.getItem('user') as string) const msgTips = '您不是管理员或发言人,无法开启此功能!' const channel = new BroadcastChannel('meeting_channel'); let storeDevice: any; let agoraTime: NodeJS.Timeout; useEffect(() => { window.electron.createChildWindow('hide') let time: NodeJS.Timeout; let refreshTime: NodeJS.Timeout; setUser(userInfo) window.electron.getIsMaximized().then((res: boolean) => { if (!res) { window.electron.setViewStatus('maximize') } }) setKeyOpenChildWindow('shareScreenWindow', false) setMeetingMode('StandardMode'); agoraInit() storage.setItem('noViewChatList', 0) window.addEventListener('customStorageChange', handleCustomStorageChange); const container = document.getElementById('videoView') as HTMLElement; container.addEventListener('wheel', handleWheelChange); channel.onmessage = async function (event) { const { type, shareScreenWindowfooterListsTitle, shareScreenWindowClose, userListWindowPostOpenMicr, userListWindowPostOpenCamera, userListWindowDeleteRoomManager, userListWindowPostRoomManager, userListWindowGetRoomKickout, userListWindowEquipmentManagement, userListWindowSetEquipmentManagement, chatSmallWindowSendChannelMsg, chatBigWindowSetAllUserLook, chatBigWindowDeleteRoomManager, chatBigWindowPostRoomManager, chatBigWindowPostOpenMicr, chatBigWindowPostOpenCamera, chatBigWindowGetRoomKickout, chatBigWindowSendChannelMsg, noticeWindowPostRoomManager } = event.data; switch (type) { case 'shareScreenWindowGetTime': setCurrentSeconds((res => { channel.postMessage({ type: 'time', time: res, }); return res })) break; case 'shareScreenWindowClose': setCurrentSeconds(shareScreenWindowClose) await stopScreenCapture() await allUserLook(userInfo.uid, userInfo.userName) break; case 'shareScreenWindowfooterListsTitle': switch (shareScreenWindowfooterListsTitle) { case '静音': case '解除静音': changeStatusList({ title: shareScreenWindowfooterListsTitle }, 0, 1) break; case '关闭视频': case '开启视频': changeStatusList({ title: shareScreenWindowfooterListsTitle }, 0, 2) break; case '录制': case '录制中': changeStatusList({ title: shareScreenWindowfooterListsTitle }, 1, 3) break; } break; case 'shareScreenWindowGetFooterLists': setFooterList((res: any) => { window.electron.windowHandleMessage({ key: 'shareScreenWindow', parmes: { footerList: res, type: 'footerList' } }) return res }) break; case 'userListWindowEquipmentManagement': await window.electron.onInvoke('getDrivers', { uid: userListWindowEquipmentManagement.uid, }) break; case 'userListWindowSetEquipmentManagement': await window.electron.onInvoke('setDrivers', { uid: userListWindowSetEquipmentManagement.uid, driversJsonString: userListWindowSetEquipmentManagement.driversJsonString }) break; case 'userListWindowPostOpenMicr': postOpenMicr(userListWindowPostOpenMicr.enableMicr, userListWindowPostOpenMicr.uid) break; case 'userListWindowPostOpenCamera': postOpenCamera(userListWindowPostOpenCamera.enableCamera, userListWindowPostOpenCamera.uid) break; case 'userListWindowDeleteRoomManager': DeleteRoomManager({ roomId: state.roomId, roomNum: state.channelId, userId: userListWindowDeleteRoomManager.uid }) break; case 'userListWindowPostRoomManager': postRoomManager({ roomId: state.roomId, roomNum: state.channelId, userId: userListWindowPostRoomManager.uid }) break; case 'userListWindowGetRoomUserList': setRoomUserList(((res: any) => { window.electron.windowHandleMessage({ key: 'userListWindow', parmes: { roomUserList: res, type: 'roomUserList' } }) return res })) break; case 'userListWindowGetRoomKickout': GetRoomKickout(state.channelId, userListWindowGetRoomKickout.uid) break; case 'userListWindowAllPostOpenMicr': postOpenMicr(false, userInfo.id, true) break; case 'chatSmallWindowSendChannelMsg': sendMsg(chatSmallWindowSendChannelMsg.msg) break; case 'chatBigWindowSetAllUserLook': setAllUserLook(chatBigWindowSetAllUserLook.roomUserItem) break; case 'chatBigWindowDeleteRoomManager': DeleteRoomManager({ roomId: state.roomId, roomNum: state.channelId, userId: chatBigWindowDeleteRoomManager.uid }) break; case 'chatBigWindowPostRoomManager': postRoomManager({ roomId: state.roomId, roomNum: state.channelId, userId: chatBigWindowPostRoomManager.uid }) break; case 'chatBigWindowPostOpenMicr': postOpenMicr(chatBigWindowPostOpenMicr.enableMicr, chatBigWindowPostOpenMicr.uid) break; case 'chatBigWindowPostOpenCamera': postOpenCamera(chatBigWindowPostOpenCamera.enableCamera, chatBigWindowPostOpenCamera.uid) break; case 'chatBigWindowGetRoomKickout': GetRoomKickout(state.channelId, chatBigWindowGetRoomKickout.uid) break; case 'chatBigWindowSendChannelMsg': if (chatBigWindowSendChannelMsg.msg) { sendMsg(chatBigWindowSendChannelMsg.msg) } else[ setChatList((res: any) => { window.electron.windowHandleMessage({ key: 'chatBigWindow', parmes: { chatList: res, } }) return res }) ] break; case 'noticeWindowPostRoomManager': postRoomManager({ roomId: state.roomId, roomNum: state.channelId, userId: noticeWindowPostRoomManager.uid }) break; } } time = setInterval(() => { setCurrentSeconds(currentSeconds => { return currentSeconds += 1 }) setSpeackUid((uids: any) => { const usernames: string[] = []; setRoomUserList((res: any) => { uids.forEach((uid: any) => { const user = res.find((item: any) => item.uid == uid); if (user) { usernames.push(user.userName); } }) setCurrentSpeakUser(usernames) return res }); return [] }) }, 1000) refreshTime = setInterval(() => { GetRoomUser(state.channelId).then(res => { if (res.code === 200) { res.data.forEach((item: any) => { setRoomUserList((data: any) => { let row = data.find((row: any) => row.uid == item.uid); if (row) { row.enableCamera = item.enableCamera; row.enableMicr = item.enableMicr; row.isRoomManager = item.isRoomManager; row.isAdmin = role.ID.includes(item.roleId) || item.isRoomManager; } return data }) }); } }) }, 1000 * 30) // 首次加载图标更新 const firstFooterList = [...footerList] firstFooterList[0][0].title = state.enableMicr ? '静音' : '解除静音' firstFooterList[0][0].active = !state.enableMicr firstFooterList[0][1].title = state.enableCamera ? '关闭视频' : '开启视频' firstFooterList[0][1].active = !state.enableCamera setFooterList(firstFooterList) function showSingIn() { if (!role.ID.includes(userInfo.roleId)) { singInRef.current.getModal().then((res: boolean) => { if (!res) { singInRef.current.changeModal() } }) } } setTimeout(async () => { const setting = await JSON.parse(storage.getItem('setting') as string); const stateInfo = await JSON.parse(storage.getItem('stateInfo') as string); if (stateInfo && setting.isRecordingTips && location.href.indexOf('/meeting') !== -1) { setRecorder((data: any) => { if (!data) { setIsScreenCapture(bool => { if (!bool) { if (role.ID.includes(userInfo.roleId)) { confirm({ title: '提示', icon: , content: `是否录制本次会议?`, centered: true, okText: '确定', cancelText: '取消', async onOk() { if (stateInfo) { changeStatusList({ title: '录制' }, 1, 3) } else { message.error('当前不在会议室!') } showSingIn() }, onCancel() { showSingIn() } }) } else { showSingIn() } } return bool }) } return data }) } else { setIsScreenCapture(bool => { if (!bool) { showSingIn() } return bool }) } }, 10000); return () => { window.removeEventListener('customStorageChange', handleCustomStorageChange); window.removeEventListener('wheel', handleWheelChange); clearInterval(time) clearInterval(refreshTime) channel.close(); window.electron.closeChildWindow('shareScreenWindow') }; }, []); useEffect(() => { if (networkOther) { let data = networkOther as any; if (storage.getItem('reconnect') === 'true') { if (data.lastmileDelay < 100) { setNetworkQuality({ level: '佳', text: '网络质量极好' }) setCurrentEffective(3) window.electron.windowHandleMessage({ key: 'shareScreenWindow', parmes: { currentEffective: 3, networkQuality: { level: '佳', text: '网络质量极好' }, networkOther: { lastmileDelay: data.lastmileDelay }, type: 'nnetworkStatus' } }) } else if (data.lastmileDelay > 500) { setNetworkQuality({ level: '非常差', text: '完全无法沟通' }) setIsNetworkQuality(true) setCurrentEffective(1) window.electron.windowHandleMessage({ key: 'shareScreenWindow', parmes: { currentEffective: 1, networkQuality: { level: '非常差', text: '完全无法沟通' }, networkOther: { lastmileDelay: data.lastmileDelay }, type: 'nnetworkStatus' } }) } else if (data.lastmileDelay < 500 && data.lastmileDelay > 100) { setNetworkQuality({ level: '差', text: '勉强能沟通但不顺畅' }) setIsNetworkQuality(true) setCurrentEffective(2) window.electron.windowHandleMessage({ key: 'shareScreenWindow', parmes: { currentEffective: 2, networkQuality: { level: '差', text: '勉强能沟通但不顺畅' }, networkOther: { lastmileDelay: data.lastmileDelay }, type: 'nnetworkStatus' } }) } } else { setNetworkQuality({ level: '断开连接', text: '网络连接断开' }) setCurrentEffective(0) window.electron.windowHandleMessage({ key: 'shareScreenWindow', parmes: { currentEffective: 0, networkQuality: { level: '断开连接', text: '网络连接断开' }, networkOther: { lastmileDelay: data.lastmileDelay }, type: 'nnetworkStatus' } }) } } }, [networkOther]); useEffect(() => { if (chatList.length) { window.electron.windowHandleMessage({ key: 'chatBigWindow', parmes: { chatList, } }) } }, [chatList]); useEffect(() => { let currentVideoUserItem = roomUserList.find((item: any) => item.uid === currentVideoId || item.screenShareId === currentVideoId) if (currentVideoUserItem) { setCurrentLookUserAccount(currentVideoUserItem) } }, [currentVideoId]); useEffect(() => { if (isShare) { const item = roomUserList.find((item: any) => item.screenShareId === String(isShare)) setIsShareUser(item || null) } }, [isShare, roomUserList]); useEffect(() => { roomUserList.forEach(async (item: any) => { if (item.uid === currentVideoId) { await agora.setRemoteVideoStreamType(item.uid, VideoStreamType.VideoStreamHigh, true) } else { await agora.setRemoteVideoStreamType(item.uid, VideoStreamType.VideoStreamLow, true) } }); }, [currentVideoId, roomUserList]); useEffect(() => { let item = roomUserList.find((item: any) => currentVideoId == item.uid) if (item) { if (isShare) { if (Number(item.screenShareId) === Number(isShare)) { agora.muteRemoteVideoStream(Number(isShare), false) } else { agora.muteRemoteVideoStream(Number(isShare), true) } } } }, [currentVideoId, isShare]); useEffect(() => { if (isAgoraDisconnected) { agoraTime = setTimeout(() => { confirm({ keyboard: false, title: '提示', icon: , content: `重连失败,请退出房间重试!`, centered: true, okText: '退出', wrapClassName: 'hideCancelText', cancelText: '', async onOk() { leaveChannel() }, }) clearTimeout(agoraTime) }, 1000 * 60); } else { clearTimeout(agoraTime) } return () => clearTimeout(agoraTime); }, [isAgoraDisconnected]); useEffect(() => { window.electron.onSignalr(async (_e: any, item: any) => { const setting = JSON.parse(storage.getItem('setting') as string) switch (item.key) { // 聊天 case 'ReceiveMessage': let meetingUserChatDom = document.getElementById('meetingUserChat') as HTMLElement; if (!meetingUserChatDom) { let storageNoViewChatList = Number(storage.getItem('noViewChatList')) storage.setItem('noViewChatList', storageNoViewChatList += 1) setNoViewChatList(storageNoViewChatList) } setChatList((newChatList: any) => [...newChatList, item]) window.electron.windowHandleMessage({ key: 'chatSmallWindow', parmes: { chatListIten: item, } }) setStatusList((res: any) => { if (!res.userChatList) { api.open({ message: item.userName + '说:', description: item.message, duration: 3, showProgress: true, }); } return res }) chatScrollBotton() break; // 扩展操作 case 'Operation': switch (item.type) { } break; // 全员离开房间 case 'AllLeave': message.success('管理员已结束会议!') leaveChannel(false) break; // 移出会议 case 'ForceExitRoom': message.success('管理员已将你移出会议!') leaveChannel() break; // 更新视图模式 case 'RefreshView': setMeetingMode(item.type) break; // 全员看他 case 'ShowUser': if (item.operUid && item.operUserName) { if (item.operUid !== userInfo.uid) { if (item.uid === userInfo.uid) { message.success(`${item.operUserName}设置全员看你`) } else { message.success(`${item.operUserName}设置全员看${item.uname}`) } } } getShowUser() break; // 用户加入频道回调 case 'UserJoined': setAllUserListData('UserJoined', item) break; // 用户退出频道回调 case 'UserLeave': setAllUserListData('UserLeave', item) break; // 所有用户开闭麦 case 'OperAllMicr': setAllUserListData('OperAllMicr', item) break; // 用户关闭开启麦克风 case 'OperMicr': if (item.operUid !== userInfo.uid) { if (item.user.uid === userInfo.uid) { message.success(item.user.enableMicr ? '管理员已取消你的静音' : '你已被管理员静音') } } setAllUserListData('OperMicr', item) break; // 用户开启关闭摄像头 case 'OperCamera': if (item.operUid !== userInfo.uid) { if (item.user.uid === userInfo.uid) { message.success(item.user.enableCamera ? '管理员已开启你的摄像头' : '管理员已关闭你摄像头') } } setAllUserListData('OperCamera', item) break; // 发言人用户信息刷新 case 'ManagerRefresh': setAllUserListData('ManagerRefresh', item, async () => { if (item.user.uid === item.uid) { if (item.user.uid === userInfo.uid) { await agora.allLeaveChannelEx() message.success(`操作成功`) await agora.updateChannelMediaOptions(item.user.isRoomManager) await postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false) await postOpenCameraApi(false, userInfo.uid) // 不管身份如何改变都关闭摄像头 await stopScreenCapture() } else { message.success(`${item.user.userName}已结束发言`) } } else { if (item.user.uid === userInfo.uid) { if (item.user.isRoomManager) { await agora.allLeaveChannelEx() } message.success(`管理员${item.user.isRoomManager ? '设置' : '取消'}您为发言人`) await agora.updateChannelMediaOptions(item.user.isRoomManager) setCurrentRequestSpeakType(res => { if (res === 'video') { postOpenCameraApi(item.user.isRoomManager, userInfo.uid) } else if (res === 'audio') { postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false) } else { postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false) postOpenCameraApi(false, userInfo.uid) } return '' }) await stopScreenCapture() } else { message.success(`管理员${item.user.isRoomManager ? '设置' : '取消'}${item.user.userName}为发言人`) } } }) break; // 申请发言 case 'ApplyToSpeak': setIsScreenCapture(bool => { if (bool) { window.electron.setChildWindowShow({ key: 'noticeWindow', bool: true }) channel.postMessage({ type: 'noticeItem', noticeItem: item }); } else { api.open({ message: '', description:
{item.uname}申请发言
, duration: 10, placement: 'bottomRight', showProgress: true, pauseOnHover: false, }); } return bool }) break; // 管理员查看随机用户 case 'Watch': if (!role.ID.includes(userInfo.roleId)) { let userId = item.watchUids.find((uid: any) => uid === userInfo.uid) if (userId) { GetRoomRtcToken(state.channelId + 'a').then(async res => { if (res.code === 200) { await agora.allJoinChannelEx(false, res.data) } }) } else { await agora.allLeaveChannelEx() } } break; // 设备列表 case 'DriverList': Promise.all([ agora.getVideoDeviceManager(), agora.getAudioMediaList(), ]).then((res) => { const data = { videoList: res[0].list.map((row: any) => { return { value: row.deviceId, label: row.deviceName } }), videoDeviceId: res[0].list.find((row: any) => row.deviceId === setting.videoDeviceId) ? setting.videoDeviceId : res[0].list.length ? res[0].list[0].deviceId : null, ecordingList: res[1].ecordingList.map((row: any) => { return { value: row.deviceId, label: row.deviceName } }), ecordingDeviceId: res[1].ecordingList.find((row: any) => row.deviceId === setting.ecordingDeviceId) ? setting.ecordingDeviceId : res[1].ecordingList.length ? res[1].ecordingList[0].deviceId : null, playBackList: res[1].playBackList.map((row: any) => { return { value: row.deviceId, label: row.deviceName } }), playBackDeviceId: res[1].playBackList.find((row: any) => row.deviceId === setting.playBackDeviceId) ? setting.playBackDeviceId : res[1].playBackList.length ? res[1].playBackList[0].deviceId : null, ecordingVolume: res[1].ecordingVolume } window.electron.onInvoke('sendDrivers', { uid: item.callerUid, driversJsonString: JSON.stringify(data) }) }) break; // 设置设备 case 'SaveDriver': if (item.driver) { const data = JSON.parse(item.driver); if (data.videoDeviceId) await agora.setVideoDeviceManager(data.videoDeviceId); if (data.ecordingDeviceId) await agora.setRecordingDevice(data.ecordingDeviceId) if (data.playBackDeviceId) await agora.setPlaybackDevice(data.playBackDeviceId) await agora.setRecordingDeviceVolume(data.ecordingVolume) setting.videoDeviceId = data.videoDeviceId || null; setting.ecordingDeviceId = data.ecordingDeviceId || null; setting.playBackDeviceId = data.playBackDeviceId || null; setting.ecordingVolume = data.ecordingVolume storage.setItem('setting', JSON.stringify(setting)) } break; // 显示设备列表 case 'ShowDriverList': if (item.driversJsonString) { const data = JSON.parse(item.driversJsonString); const isOpen = await getKeyOpenChildWindow('shareScreenWindow') if (isOpen) { channel.postMessage({ type: 'showDriverList', showDriverList: data }) } else { equipmentManagementRef.current.setData(data) } } break; // 修改用户名称 case 'ModifyNickName': setAllUserListData('ModifyNickName', item) break; // 加入房间回调 case 'JoinChannelCallback': if (item.isSuccess) { await getRoomUser() } else { setSocketRemberNumber(res => { if (res >= 3) { confirm({ keyboard: false, title: '提示', icon: , content: `加入房间失败!`, centered: true, okText: '退出', wrapClassName: 'hideCancelText', cancelText: '', async onOk() { leaveChannel() }, }) } else { setTimeout(() => { async function setUserStatus(res: any) { let userItem = res.find((item: any) => item.uid === userInfo.uid) await window.electron.onInvoke('joinChannel', { roomNum: state.channelId, enableMicr: !storeDevice[0][0].active, enableCamera: !storeDevice[0][1].active, isRoomManager: userItem ? userItem.isRoomManager : false, }) } setRoomUserList((res: any) => { setUserStatus(res) return res }) }, 3000); } return res >= 3 ? 3 : res++ }) } break; // 共享 case 'ExitSharedScreen': setIsScreenCapture((res) => { if (res) { changeStatusList({ title: '共享冲突停止共享', }, 1, 0) } return res }) break; } }) return () => { window.electron.offSignalr() } }, []) useEffect(() => { if (recorder) { recorder.start() recorder.onstart = async () => { message.success('开始录制') } recorder.onerror = async () => { setRecorder('') setMediaStream([]) setIsClickedMediaSteam(false) changeStatusList({ title: '录制中' }, 1, 3) message.error('录制失败,请重新录制!') } recorder.onstop = async () => { } recorder.ondataavailable = async (event: any) => { const blob = await fixWebmDuration(event.data); const reader = new FileReader() as any; reader.onload = async () => { const setting = await JSON.parse(storage.getItem('setting') as string) const buffer = Buffer.from(reader.result); const mp4Path = `${setting.recordingFilesPath}会议录制_${state.roomName}_${state.channelId}_${dayjs().format('YYYY年MM月DD日HH时mm分')}.webm`; await fs.writeFile(mp4Path, buffer, {}); setRecorder('') setMediaStream([]) confirm({ title: '提示', icon: , content: `录制成功!文件已保存至:${setting.recordingFilesPath}`, centered: true, okText: '打开文件夹', cancelText: '关闭', async onOk() { await fs.access(setting.recordingFilesPath, fs.constants.F_OK); if (process.platform === 'win32') { exec(`explorer "${setting.recordingFilesPath}"`); } else if (process.platform === 'darwin') { exec(`open "${setting.recordingFilesPath}"`); } }, onCancel() { } }) setIsLeave(bool => { if (bool) { if (userInfo.isAnonymous) { storage.setItem('userLogin', false) } else { navigate('/home/index') } } return false }) }; reader.readAsArrayBuffer(blob); } }; }, [recorder]) useEffect(() => { let timer: NodeJS.Timeout; if (isClicked) { timer = setTimeout(() => { setIsClicked(false); setCurrentRequestSpeakType('') }, 10000); } return () => clearTimeout(timer); }, [isClicked]); useEffect(() => { async function setView() { let uid = currentVideoUid switch (currentLookUserStatus) { case 1: await agora.setupLocalVideo({ uid: Number(uid), view: document.getElementById(`video-source-camera-primary`) as HTMLElement, channelId: state.channelId, sourceType: VideoSourceType.VideoSourceCameraPrimary, renderMode: RenderModeType.RenderModeFit }) setIsClickLock(false) break; case 2: await agora.setupLocalVideo({ uid: Number(uid), view: document.getElementById(`video-source-screen`) as HTMLElement, channelId: state.channelId, sourceType: VideoSourceType.VideoSourceScreen, renderMode: RenderModeType.RenderModeFit }) setIsClickLock(false) break; case 3: await agora.setupRemoteVideoJoin({ uid: Number(uid), view: document.getElementById(`video-source-remote-screen`) as HTMLElement, channelId: state.channelId, renderMode: RenderModeType.RenderModeFit }) setIsClickLock(false) break; case 4: await agora.setupRemoteVideoJoin({ uid: Number(uid), view: document.getElementById(`video-source-remote-camera`) as HTMLElement, channelId: state.channelId, renderMode: RenderModeType.RenderModeFit }) setIsClickLock(false) break; } } if (currentVideoUid) { setTimeout(() => { setView() }, currentVideoId ? 0 : 1500); } }, [currentVideoUid]); useEffect(() => { if (isScreenCapture) { agora.setupLocalVideo({ uid: Number(user.uid), view: document.getElementById(`meetingAbsoluteVideo`) as HTMLElement, channelId: state.channelId, sourceType: VideoSourceType.VideoSourceCameraPrimary, type: true }) } }, [isScreenCapture]); useEffect(() => { let timer: NodeJS.Timeout; if (isClickedMediaSteam) { timer = setTimeout(() => { setIsClickedMediaSteam(false) }, 3000); } return () => clearTimeout(timer); }, [isClickedMediaSteam]); useEffect(() => { const elements = document.querySelectorAll('.intersectionObserver-view'); if (elements.length && currentVideoId) { elements.forEach(element => { observer?.unobserve(element); }); const observerObject = new IntersectionObserver(async (entries: IntersectionObserverEntry[], _observer: IntersectionObserver) => { setIsScreenCapture((bool: boolean) => { entries.forEach(async (entry) => { if (entry.target.id !== user.uid) { await agora.muteRemoteVideoStreamEx(Number(entry.target.id), bool ? true : !entry.isIntersecting) } }); return bool }) setIsScreenCapture((bool: boolean) => { agora.muteRemoteVideoStreamEx(Number(currentVideoId), bool) return bool }) }, { threshold: 0, root: document.getElementById('videoView') }); setObserver(observerObject) elements.forEach(element => { observerObject.observe(element); }); } window.electron.windowHandleMessage({ key: 'shareScreenWindow', parmes: { footerList, type: 'footerList' } }) window.electron.windowHandleMessage({ key: 'shareScreenWindow', parmes: { roomUserList, type: 'roomUserList' } }) window.electron.windowHandleMessage({ key: 'userListWindow', parmes: { roomUserList, type: 'roomUserList' } }) return () => { elements.forEach(element => { observer?.unobserve(element); }); observer?.disconnect(); } }, [roomUserList, currentVideoId, footerList]); // 声网初始化 const agoraInit = async () => { await agora.init(true) await agora.muteLocalVideoStream(userInfo, state.enableMicr, state.enableCamera) await getJoin(state.enableMicr, state.enableCamera) agora.registerEventHandler({ onJoinChannelSuccess: async (connection: RtcConnection, _elapsed: number) => { if (connection.channelId === state.channelId) { if (String(connection.localUid).length !== 9) { setTimeout(async () => { await agora.setupLocalVideo({ uid: Number(connection.localUid), view: document.getElementById(`video-${connection.localUid}`), channelId: connection.channelId, sourceType: VideoSourceType.VideoSourceCameraPrimary, renderMode: RenderModeType.RenderModeFit }) }, 1000); getShowUser(); } } }, onUserJoined: async (connection: RtcConnection, remoteUid: number, _elapsed: number) => { if (connection.channelId === state.channelId) { if (String(remoteUid).length === 9) { setIsShare(remoteUid) } else { setTimeout(async () => { await agora.setupRemoteVideoJoin({ uid: Number(remoteUid), view: document.getElementById(`video-${remoteUid}`), channelId: connection.channelId, renderMode: RenderModeType.RenderModeFit }) }, 1000); } } }, onUserOffline: async (connection: RtcConnection, remoteUid: number, _reason: UserOfflineReasonType) => { await agora.destroyRendererByConfig(Number(remoteUid), connection.channelId) if (connection.channelId === state.channelId) { if (String(remoteUid).length === 9) { setIsShare(null) } await agora.setupRemoteVideo({ uid: Number(remoteUid), view: null, channelId: connection.channelId, renderMode: RenderModeType.RenderModeFit }); setCurrentVideoUid(res => { if (String(remoteUid) === res) { getShowUser(); } return res }) } }, onAudioVolumeIndication: async (speakers: AudioVolumeInfo[]) => { if (speakers.length) { setSpeackUid((res: any) => { return [...new Set([...res, ...(speakers.filter((item: any) => item.volume)).map(item => item.uid || userInfo.uid)])] }) speakers.forEach((item: any) => { let domMe = document.getElementById(`micr-item-${userInfo.uid}`); let dom = document.getElementById(`micr-${item.uid ? item.uid : userInfo.uid}`); if (dom) { const percentage = (item.volume / 255) * 100 dom.style.height = `${percentage}%` } if (!item.uid) { const percentage = (item.volume / 255) * 100 if (domMe) { domMe.style.height = `${percentage}%` } window.electron.windowHandleMessage({ key: 'shareScreenWindow', parmes: { currentSpeakUserMe: percentage, type: 'currentSpeakUserMe' } }) } }); } }, onRtcStats: async (stats: RtcStats) => { setNetworkOther(stats) }, onConnectionStateChanged: async (_connection: RtcConnection, state: ConnectionStateType, reason: ConnectionChangedReasonType) => { const reconnectingCode = [2, 16, 11, 13, 14, 12] if (state === 4 && reconnectingCode.indexOf(reason) >= 0) { } else if (state === 3) { meetingDisconnectedRef.current.changeModal(false) setIsAgoraDisconnected(false) } }, onConnectionLost: () => { meetingDisconnectedRef.current.changeModal(true) setIsAgoraDisconnected(true) setIsScreenCapture(bool => { if (bool) { setIsNetworkDisconnected(true) stopScreenCapture() } return bool }) }, onLocalVideoStateChanged: async (_source: VideoSourceType, _state: LocalVideoStreamState, reason: LocalVideoStreamReason) => { if (reason === 12) { setIsScreenCapture(bool => { if (bool) { stopScreenCapture() setSharedScreenItem('') allUserLook(userInfo.uid, userInfo.userName) } return bool }) } else if (reason === 3 || reason === 4) { message.error({ content:
请检查摄像头是否正常工作,检查摄像头是否被其他应用占用,或者尝试重新加入频道, { stupWizardRef.current.changeModal(1); }}>前往修改摄像头
, duration: 60, key: 'cameraTemporarily' }); } }, onTokenPrivilegeWillExpire: async (connection: RtcConnection, _token: string) => { await GetRoomRtcToken(connection.channelId || '').then(res => { if (res.code === 200) { agora.refreshToken({ token: res.data, connection, }) } }) } }) if (state.enableCamera) { await agora.startCameraCapture() } await agora.setJoinChannel({ channelId: state.channelId, uid: userInfo.uid, screenShareId: userInfo.screenShareId, token: state.token, }) } // 状态更新 const changeAgoraDevice = () => { setRoomUserList((res: any) => { res.forEach(async (item: any) => { if (item.uid === userInfo.uid) { const footerListTemplate = [...footerList] await agora.getVideoDeviceManager().then(async (res) => { getUserRoomInfo().then(async (r) => { if (res.list.length) { footerListTemplate[0][1].title = item.enableCamera ? '关闭视频' : '开启视频' footerListTemplate[0][1].active = !item.enableCamera await agora.muteLocalVideoStream(r, item.enableMicr, item.enableCamera) } else { footerListTemplate[0][1].title = '开启视频' footerListTemplate[0][1].active = true await agora.muteLocalVideoStream(r, item.enableMicr, false) } }) }) await agora.getAudioMediaList().then(async (res) => { getUserRoomInfo().then(async (r) => { if (res.ecordingList.length) { footerListTemplate[0][0].title = item.enableMicr ? '静音' : '解除静音' footerListTemplate[0][0].active = !item.enableMicr await agora.muteLocalAudioStream(r, item.enableMicr, item.enableCamera) } else { footerListTemplate[0][0].title = '解除静音' footerListTemplate[0][0].active = true await agora.muteLocalAudioStream(r, false, item.enableCamera) } }) }) if (!role.ID.includes(userInfo.roleId)) { if (item.isRoomManager) { footerListTemplate[0][2].title = '结束发言' footerListTemplate[0][2].active = true } else { footerListTemplate[0][2].title = '申请发言' footerListTemplate[0][2].active = false } } setFooterList(footerListTemplate) } if (userSearchValue) { if (item.userName.indexOf(userSearchValue) !== -1) { item.isShow = true; } else { item.isShow = false; } } else { item.isShow = true; } }); setIsAdmin(res.filter((item: any) => (role.ID.includes(item.roleId) || item.isRoomManager) && item.isRoom).length) return res }) } // 刷新 const refreshVideoView = async (userItem: any): Promise => { if (userItem.uid === userInfo.uid) { await agora.setupLocalVideo({ uid: Number(userItem.uid), view: document.getElementById(`video-${userItem.uid}`), channelId: state.channelId, sourceType: VideoSourceType.VideoSourceCameraPrimary, renderMode: RenderModeType.RenderModeFit }) } else { await agora.setupRemoteVideoJoin({ uid: Number(userItem.uid), view: document.getElementById(`video-${userItem.uid}`), channelId: state.channelId, renderMode: RenderModeType.RenderModeFit }) } } // 替换数据 const setAllUserListData = async (key: string, item: any, callBack?: Function): Promise => { switch (key) { case 'OperMicr': case 'OperCamera': case 'ManagerRefresh': setRoomUserList((res: any) => { let userItem = res.find((row: any) => row.uid === item.user.uid) if (userItem) { for (const keys in item.user) { if (keys !== 'enableCamera' && keys !== 'enableMicr') { userItem[keys] = item.user[keys]; } } if (key === 'OperCamera') { userItem.enableCamera = item.user.enableCamera; if (userItem.uid === userInfo.uid) { userItem.enableCamera ? agora.startCameraCapture() : agora.stopCameraCapture() } } if (key === 'OperMicr') { userItem.enableMicr = item.user.enableMicr; } userItem.isAdmin = role.ID.includes(item.user.roleId) || item.user.isRoomManager; if (!userItem.isAdmin) { agora.destroyRendererByConfig(Number(userItem.uid), state.channelId) } refreshVideoView(userItem) } if (key === 'ManagerRefresh') { callBack && callBack() } return res }) break; case 'UserJoined': setRoomUserList((res: any) => { let userItem = res.find((row: any) => row.uid === item.user.uid) if (userItem) { for (const key in item.user) { userItem[key] = item.user[key]; } userItem.isRoom = true; userItem.isAdmin = role.ID.includes(item.user.roleId) || item.user.isRoomManager; setTimeout(() => { refreshVideoView(userItem) }, 0); return [...res] } else { item.user.isRoom = true; item.user.isAdmin = role.ID.includes(item.user.roleId) || item.user.isRoomManager; refreshVideoView(item.user) return [...res, item.user] } }) break; case 'UserLeave': setRoomUserList((res: any) => { let userItem = res.find((row: any) => row.uid === item.uid) if (userItem) { userItem.isRoom = false userItem.isAdmin = false } return res }) setCurrentVideoId((res: any) => { if (Number(res) === Number(item.uid)) { getShowUser(); } return res }) break; case 'OperAllMicr': setRoomUserList((res: any) => { res.forEach((row: any) => { if (row.uid !== item.uid) { row.enableMicr = item.enableMicr } }) return res }) break; case 'ModifyNickName': setRoomUserList((res: any) => { let userItem = res.find((row: any) => row.uid == item.uid) if (userItem) { userItem.userName = item.nickName } return res }) break; } changeAgoraDevice() } // 滚动 const handleWheelChange = (e: any): void => { setMeetingMode(res => { if (res === 'StandardMode') { const container = document.getElementById('videoView') as HTMLElement; if (e.wheelDeltaY > 0) { container.scrollLeft -= 100 } else { container.scrollLeft += 100 } } return res }) } // 渲染视频 const renderVideo = async (uid: string = ''): Promise => { if (isClickLock) { return } if (uid) { if (currentVideoId === uid || currentVideoUid === uid) { return } } else { uid = userInfo.uid } await agora.destroyRendererByView(`video-source-camera-primary`) await agora.destroyRendererByView(`video-source-screen`) await agora.destroyRendererByView(`video-source-remote-screen`) await agora.destroyRendererByView(`video-source-remote-camera`) setCurrentLookUserStatus(0) setRoomUserList((res: any) => { let item = res.find((item: any) => item.uid === uid || item.screenShareId === uid) if (item) { setCurrentVideoId(item.uid) } return res }) setIsClickLock(true) setCurrentVideoUid('') if (uid === userInfo.uid || uid === userInfo.screenShareId) { if (String(uid).length === 9) { // 共享屏幕 setCurrentLookUserStatus(2) } else { // 摄像头 setCurrentLookUserStatus(1) } } else { if (String(uid).length === 9) { // 共享屏幕 setCurrentLookUserStatus(3) } else { // 摄像头 setCurrentLookUserStatus(4) } } setTimeout(() => { setCurrentVideoUid(uid) }, 500); } // 全员观看 const getShowUser = async (): Promise => { if (location.href.indexOf('/meeting') !== -1) { await GetShowUser(state.channelId).then(async (res) => { if (res.code === 200 && res.data) { renderVideo(res.data) } }) } } // 加入房间时间 const changeCurrentSeconds = (): string => { const duration = dayjs.duration(currentSeconds, 'seconds'); const hours = duration.hours(); // 整数小时 const minutes = duration.minutes(); // 整数分钟 const secondsRemaining = duration.seconds(); // 剩余的秒数 return `${hours > 9 ? hours : '0' + hours}:${minutes > 9 ? minutes : '0' + minutes}:${secondsRemaining > 9 ? secondsRemaining : '0' + secondsRemaining}` } // 底部按钮点击效果 const changeFooterListSelect = (row: any, itemIndex: number, rowIndex: number, bool: boolean): void => { let arr = ['静音', '解除静音', '关闭视频', '开启视频'] if (arr.indexOf(row.title) === -1) { const footerListTemplate = [...footerList] footerListTemplate[itemIndex][rowIndex].select = bool; setFooterList(footerListTemplate) } } // 操作按钮 const changeStatusList = async (row: any, itemIndex: number, rowIndex: number): Promise => { function requestSpeak() { confirm({ title: '提示', icon: , content: `该操作需向管理员申请发言权限`, centered: true, okText: '申请', cancelText: '取消', async onOk() { GetApplySpeak(state.channelId).then(res => { if (res.code === 200) { setIsClicked(true); message.success('申请发言成功') } }) }, onCancel() { } }) } const footerListTemplate = [...footerList] setFooterListIndex({ itemIndex, rowIndex, }) switch (row.title) { case '成员列表': setStatusList({ userList: statusList.userList ? false : true, userChatList: false, userVideo: false, }) break; case '聊天': setStatusList({ userList: false, userChatList: statusList.userChatList ? false : true, userVideo: false, }) storage.setItem('noViewChatList', 0) setNoViewChatList(0) chatScrollBotton() break; case '共享屏幕': await getUserRoomInfo().then(async (res) => { if (res) { GetSharedScreen(state.channelId).then(req => { if (req.code === 200) { if (res.data) { setIsShare(res.data) } getDesktopCapturerVideo() setIsSharedScreenModal(true) } }) } else { message.error(msgTips) } }) break; case '停止共享': case '共享冲突停止共享': await getUserRoomInfo().then(async (res) => { if (res) { await stopScreenCapture() } else { message.error(msgTips) } }) if (row.title === '停止共享') { await allUserLook(userInfo.uid, userInfo.userName) } break; case '静音': await postOpenMicr(false, userInfo.uid) break; case '解除静音': await getUserRoomInfo().then(async (res) => { if (res) { await postOpenMicr(true, userInfo.uid) } else { if (!isClicked) { setCurrentRequestSpeakType('audio') requestSpeak() } else { message.error('申请太频繁了,请稍后重试!'); } } }) break; case '关闭视频': await postOpenCamera(false, userInfo.uid) break; case '开启视频': await getUserRoomInfo().then(async (res) => { if (res) { await postOpenCamera(true, userInfo.uid) } else { if (!isClicked) { setCurrentRequestSpeakType('video') requestSpeak() } else { message.error('申请太频繁了,请稍后重试!'); } } }) break; case '设置': await getUserRoomInfo().then(async (res) => { stupWizardRef.current.changeModal(0, res) }) break; case '邀请人员': await getUserRoomInfo().then(async (res) => { if (res) { invitingPersonnelRef.current.changeInvitingPersonnelModal() } else { message.error(msgTips) } }) break; case '录制': const setting = await JSON.parse(storage.getItem('setting') as string); try { if (!isClickedMediaSteam) { setIsClickedMediaSteam(true) await fs.access(setting.recordingFilesPath, fs.constants.F_OK); footerListTemplate[itemIndex][rowIndex].title = '录制中'; footerListTemplate[itemIndex][rowIndex].active = true; setFooterList(footerListTemplate); window.electron.getSources().then(async (sources: any) => { const screenId = sources[0].id; const stream = await navigator.mediaDevices.getUserMedia({ audio: { mandatory: { chromeMediaSource: 'desktop', chromeMediaSourceId: screenId, } } as any, video: { mandatory: { chromeMediaSource: 'desktop', chromeMediaSourceId: screenId, } } as any }); // 获取所有音频输入设备 const devices = await navigator.mediaDevices.enumerateDevices(); const audioInputDevices = devices.filter(device => device.kind === 'audioinput' && device.deviceId !== 'default' && device.deviceId !== 'communications'); // 使用Web Audio API来捕获系统声音和麦克风声音,将它们合并到同一个MediaStream中。 const audioCtx = new (window.AudioContext || (window as any).webkitAudioContext)(); const systemSoundSource = audioCtx.createMediaStreamSource(stream); const systemSoundDestination = audioCtx.createMediaStreamDestination(); systemSoundSource.connect(systemSoundDestination); // 录制所有音频输入设备 audioInputDevices.forEach(async device => { const micStream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: device.deviceId } } }); setMediaStream((res: any) => [...res, micStream]); const micSoundSource = audioCtx.createMediaStreamSource(micStream); micSoundSource.connect(systemSoundDestination); }) // 合并音频流与视频流 const combinedSource = new MediaStream([...stream.getVideoTracks(), ...systemSoundDestination.stream.getAudioTracks()]); // 开始录制 const mediaRecorder = new MediaRecorder(combinedSource, { mimeType: 'video/webm;codecs=vp9,opus', videoBitsPerSecond: 1500, }); setRecorder(mediaRecorder); }); } else { message.error('录制太频繁了,请稍后重试!'); } } catch (error: any) { if (error.code === 'ENOENT') { message.error({ content:
文件夹不存在 { stupWizardRef.current.changeModal(3); }}>前往设置
}); return; } else { message.error(error); } } break; case '录制中': if (isClickedMediaSteam) { message.error('录制时长不足3秒,请稍后重试!'); } else { footerListTemplate[itemIndex][rowIndex].title = '录制' footerListTemplate[itemIndex][rowIndex].active = false setFooterList(footerListTemplate) stopRecorderMedia() } break; case '共享文件': sharedFilesModelRef.current.getData() break; case '申请发言': if (!isClicked) { requestSpeak() } else { message.error('申请太频繁了,请稍后重试!'); } break; case '会议监控': if (!statusList.userVideo) { GetRoomRtcToken(state.channelId + 'a').then(async res => { if (res.code === 200) { await agora.allJoinChannelEx(true, res.data) } }) } else { await agora.allLeaveChannelEx() } setStatusList({ userVideo: statusList.userVideo ? false : true, userChatList: false, userList: false, }) storage.setItem('noViewChatList', 0) setNoViewChatList(0) break; case '签到': singInRef.current.changeModal() break; } } // 停止录制 const stopRecorderMedia = async (): Promise => { setRecorder((res: any) => { if (res) { try { res.stop() } catch (error) { } } return res }) setMediaStream((res: any) => { if (res.length) { res.forEach((item: any) => { item.getTracks().forEach((track: any) => { try { track.stop() } catch (error) { } }); }); } return res }) } // 退出房间 const leaveChannel = async (bool: boolean = true): Promise => { setIsLeave(true) await stopScreenCapture() await stopRecorderMedia() if (bool) { await getLeave() } await agora.leaveChannel() setRecorder((res: any) => { if (res) { } else { if (userInfo.isAnonymous) { storage.setItem('userLogin', false) } else { navigate(`/home/index`, { state: { currentSeconds } }) } } return res }) } // 分享屏幕 const clickSharedScreen = async (): Promise => { const elements = document.querySelectorAll('.intersectionObserver-view'); if (elements.length) { elements.forEach(item => { if (item.id !== userInfo.uid) { agora.muteRemoteVideoStreamEx(Number(item.id), true) } }); agora.setSubscribeVideoBlocklist([Number(user.screenShareId)], 1) } GetRoomRtcToken(state.channelId).then(async res => { if (res.code === 200) { await agora.destroyRendererByView(`video-source-camera-primary`) await agora.destroyRendererByView(`video-source-screen`) await agora.destroyRendererByView(`video-source-remote-screen`) await agora.destroyRendererByView(`video-source-remote-camera`) const footerListTemplate = [...footerList] footerListTemplate[footerListIndex.itemIndex][footerListIndex.rowIndex].title = '停止共享' setIsSharedScreenModal(false) await agora.setDesktopCapturerVideo(sharedScreenItem, isComputerAudio, isFluencyPriority, res.data) await allUserLook(user.screenShareId, user.userName) const isOpen = await getKeyOpenChildWindow('shareScreenWindow') setIsScreenCapture(true) if (!isOpen) { window.electron.createChildWindow('show') setKeyOpenChildWindow('shareScreenWindow', true) window.electron.setMainWindowSize({ width: 250, height: 160, }) window.electron.setPosition('right') } } }) } // 获取桌面可共享屏幕的引用 const getDesktopCapturerVideo = (): void => { agora.getDesktopCapturerVideo({ width: 50, height: 50 }, { width: 30, height: 30 }, true).then((res: any) => { res.forEach((item: any, index: number) => { if (item.type === 1) { item.sourceTitle = '桌面' + (index + 1) } if (item.thumbImage.buffer) { item.thumbnailUrl = thumbImageBufferToBase64(item.thumbImage) } if (item.iconImage.buffer) { item.iconDataUrl = thumbImageBufferToBase64(item.iconImage) } }) setSharedScreenList(res) }) }; // 设置全员看谁 const allUserLook = async (uid: string, name: string): Promise => { await PostShowUser(state.channelId, uid, name) } // 设置发言人 const postRoomManager = async (data: any): Promise => { if (isAdmin >= 20) { message.error('设置失败,已达最大发言人20个!') } else { await PostRoomManager({ roomId: data.roomId, roomNum: data.roomNum, userId: data.userId }) } } // 停止共享 const stopScreenCapture = async (): Promise => { await agora.destroyRendererByView(`meetingAbsoluteVideo`) const footerListTemplate = [...footerList] await agora.leaveChannelEx(userInfo.screenShareId) agora.stopScreenCapture() footerListTemplate[1][0].title = '共享屏幕' setFooterList(footerListTemplate) window.electron.createChildWindow('stop') setKeyOpenChildWindow('shareScreenWindow', false) window.electron.setChildWindowShow({ key: 'noticeWindow', bool: false }) setIsScreenCapture(bool => { if (bool) { window.electron.setViewStatus('show') window.electron.getWindowSize().then((res: any) => { window.electron.setMainWindowSize({ width: Math.ceil(res.width / 1.5), height: Math.ceil(res.height / 1.3), }) window.electron.getIsMaximized().then((b: boolean) => { if (!b) { window.electron.setViewStatus('maximize') } }) }) } return false }) } // 获取房间用户 const getRoomUser = async (): Promise => { GetRoomUser(state.channelId).then(res => { if (res.code === 200) { res.data.forEach((item: any) => { item.isShow = true; item.isRoom = true; item.isAdmin = role.ID.includes(item.roleId) || item.isRoomManager }) setRoomUserList(res.data) getUserRoomInfo().then(async (res) => { await agora.updateChannelMediaOptions(res ? true : false) changeAgoraDevice() }) } }) } // 监听缓存变化 const handleCustomStorageChange = async (e: any): Promise => { switch (e.key) { case 'meetingMode': setMeetingMode(e.value) break; case 'quitMeeting': if (e.value) { setQuitMeetingModal(true) } break; case 'reconnect': if (e.value == true) { message.success('网络已连接。') meetingDisconnectedRef.current.changeModal(false) setIsAgoraDisconnected(false) async function setUserStatus(res: any) { let userItem = res.find((item: any) => item.uid === userInfo.uid) await window.electron.onInvoke('joinChannel', { roomNum: state.channelId, enableMicr: !storeDevice[0][0].active, enableCamera: !storeDevice[0][1].active, isRoomManager: userItem ? userItem.isRoomManager : false, }) await getShowUser() if (userItem.isRoomManager) { await postOpenMicr(!storeDevice[0][0].active, userInfo.uid) await postOpenCamera(!storeDevice[0][1].active, userInfo.uid) } setIsNetworkDisconnected(bool => { if (bool) { allUserLook(userItem.uid, userItem.userName) } return false }) setIsScreenCapture(bool => { if (bool) { allUserLook(userItem.screenShareId, userItem.userName) } return bool }) } setRoomUserList((res: any) => { setUserStatus(res) return res }) } else { storeDevice = JSON.parse(JSON.stringify(footerList)) } break; } }; // 聊天发送 const sendMsg = (text?: string): void => { let msg = text ? text : textMsg; if (msg) { window.electron.onInvoke('sendChannelMsg', { roomNum: state.channelId, msg: msg, }) let item = { uid: userInfo.uid, userName: userInfo.userName, message: msg, timestamp: +new Date() } setChatList((newChatList: any) => [...newChatList, item]) window.electron.windowHandleMessage({ key: 'chatSmallWindow', parmes: { chatListIten: item, } }) setTextMsg(''); chatScrollBotton() } else { message.error('请输入内容!') } } // 聊天框滚动到底部 const chatScrollBotton = (): void => { setTimeout(() => { const meetingUserChatContentView = document.getElementById('meetingUserChatContentView') as HTMLElement; if (meetingUserChatContentView) { meetingUserChatContentView.scrollTop = meetingUserChatContentView.scrollHeight; } }, 0); } // 设备管理 const equipmentManagement = async (uid: string, userName: string): Promise => { equipmentManagementRef.current.changeModal(uid, userName) } // 开关麦克风 const postOpenMicr = async (enableMicr: boolean, uid: string, isAll: boolean = false): Promise => { await getUserRoomInfo().then(async (res) => { if (res) { if (!isAll) { let msg = ''; if (uid === user.uid) { await agora.getAudioMediaList().then(res => { if (!res.ecordingList.length) { msg = '未检测到麦克风!' } }) } if (msg) { message.error(msg) return } } if (enableMicr) { const enableMicrLenght = roomUserList.filter((item: any) => item.enableMicr).length if (enableMicrLenght >= 20) { return message.error('房间内最多20个开启麦克风') } } await postOpenMicrApi(enableMicr, uid, isAll, true) } else { message.error(msgTips) } }) } // 开关麦克风 const postOpenMicrApi = async (enableMicr: boolean, uid: string, isAll: boolean, isMessage: boolean = false): Promise => { if (isAll) { await PostMuteAll({ roomNum: state.channelId, enableMicr }) } else { await PostOpenMicr({ roomNum: state.channelId, uid, enableMicr }) } if (isMessage) { // message.success('操作成功') } } // 开关视频 const postOpenCamera = async (enableCamera: boolean, uid: string): Promise => { await getUserRoomInfo().then(async (res) => { if (res) { let msg = ''; if (uid === user.uid) { await agora.getVideoDeviceManager().then(res => { if (!res.list.length) { msg = '未检测到摄像头!' } }) } if (msg) { message.error(msg) return } if (enableCamera) { const enableCameraLenght = roomUserList.filter((item: any) => item.enableCamera).length if (enableCameraLenght >= 20) { return message.error('房间内最多20个开启摄像头') } } await postOpenCameraApi(enableCamera, uid, true) } else { message.error(msgTips) } }) } // 开关视频 const postOpenCameraApi = async (enableCamera: boolean, uid: string, isMessage: boolean = false): Promise => { if (enableCamera) { await agora.startCameraCapture() } else { await agora.stopCameraCapture(); } await PostOpenCamera({ roomNum: state.channelId, uid, enableCamera }) if (isMessage) { // message.success('操作成功') } } // 演讲者模式 // const changeSpeakerMode = (): void => { // speakerModeModalRef.current.changeSpeakerMode() // } // 获取当前用户在房间的角色信息 const getUserRoomInfo = async (): Promise => { return new Promise((resolve, _reject) => { setRoomUserList((res: any) => { let userItem = res.find((item: any) => item.uid === userInfo.uid) if (userItem && (role.ID.includes(userItem.roleId) || userItem.isRoomManager)) { resolve(userItem) } else { resolve('') } return res }) }) } // 获取当前模式样式 const getMeetingContentBodyLeftModeClass = (): string => { switch (meetingMode) { case 'FreedomMode': return styles.meetingContentBodyLeftFreedomMode case 'StandardMode': return styles.meetingContentBodyLeftStandardMode case 'SpeakerMode': return styles.meetingContentBodyLeftSpeakerMode case 'SingleScreenMode': return styles.meetingContentBodyLeftSingleScreenMode case 'DualScreenMode': return styles.meetingContentBodyLeftDualScreenMode case 'FourScreenMode': return styles.meetingContentBodyLeftFourScreenMode } return '' } // 获取当前模式文字 const getMeetingContentBodyLeftModeText = (): string => { switch (meetingMode) { case 'FreedomMode': return '自由者模式' case 'StandardMode': return '标准模式' case 'SpeakerMode': return '演讲模式' case 'SingleScreenMode': return '单画面模式' case 'DualScreenMode': return '二分屏模式' case 'FourScreenMode': return '四分屏模式' } return '' } // 设置单个视频样式 const setMeetingContentSwiperCardClass = (): string => { switch (meetingMode) { case 'StandardMode': return styles.meetingContentSwiperCardStandardMode case 'SpeakerMode': return styles.meetingContentSwiperCardSpeakerMode } return '' } // 视频是否全屏 const setMeetingContentSwiperCardFullScreenClass = (): string => { switch (meetingMode) { case 'StandardMode': return isVideoFullScreen ? styles.meetingContentSwiperCardStandardModeFullScreen : '' case 'SpeakerMode': return isVideoFullScreen ? styles.meetingContentSwiperCardSpeakerModeFullScreen : '' } return '' } // 获取展开折叠按钮 const getSettingIcon = (): any => { switch (meetingMode) { case 'StandardMode': if (isVideoFullScreen) { return
setIsVideoFullScreen(false)}>
//下 } else { return
setIsVideoFullScreen(true)}>
//上 } case 'SpeakerMode': if (isVideoFullScreen) { return
setIsVideoFullScreen(false)}>
//右 } else { return
setIsVideoFullScreen(true)}>
//左 } } } // 加入房间 const getJoin = async (enableMicr: boolean, enableCamera: boolean): Promise => { // await GetJoin({ // roomNum: state.channelId, // enableMicr, // enableCamera // }) await window.electron.onInvoke('joinChannel', { roomNum: state.channelId, enableMicr, enableCamera }) } // 离开房间 const getLeave = async (): Promise => { // await GetLeave({ // roomNum: state.channelId, // }) await window.electron.onInvoke('levelChannel', { roomNum: state.channelId }) } // 设置全员观看 const setAllUserLook = async (item: any): Promise => { if (isShare) { await allUserLook(String(isShare) === item.screenShareId ? item.screenShareId : item.uid, item.userName) } else { await allUserLook(item.uid, item.userName) } message.success('操作成功') } // 移出房间 const getRoomKickout = async (channelId: string, uid: string, userName: string): Promise => { confirm({ title: '移出会议', icon: , content: `确定将用户${userName}移出会议?`, centered: true, okText: '确定', cancelText: '取消', async onOk() { await GetRoomKickout(channelId, uid) message.success('操作成功') }, onCancel() { }, }); } return ( <>
{ setContextMenu('') setIsNetworkQuality(false) }}> {isScreenCapture ?
{currentSpeakUser.length ? '正在说话:' + currentSpeakUser.join(';') : '正在说话:'}
{footerList[0][1].active ?
: null}
{ setIsExpand(!isExpand) window.electron.setChildWindow({ height: isExpand ? 160 : 40, key: 'main' }) }}>{isExpand ? '展开' : '收起'}
: null} {contextMenu ?
{contextMenu.isRoomManager || role.ID.includes(contextMenu.roleId) ? : null} {contextMenu.uid !== user.uid && !role.ID.includes(contextMenu.roleId) ? : null} {contextMenu.isRoomManager ? : null} {contextMenu.isRoomManager ? : null} {contextMenu.uid !== user.uid ? : null} {contextMenu.uid !== user.uid ? : null} {contextMenu.uid !== user.uid ? : null}
: null} {contextHolder}
{isScreenCapture ? null : setIsNetworkQuality(false)}>
网络质量: {networkQuality.level} {networkQuality.text} } title="" >
带宽占用: ↑{networkOther.txKBitRate}kbps ↓{networkOther.rxKBitRate}kbps
丢包率: ↑{networkOther.txPacketLossRate}% ↓{networkOther.rxPacketLossRate}%
延迟: {networkOther.lastmileDelay}ms
} title="" trigger="hover" >
setIsNetworkQuality(true)} > {networkIcon(currentEffective)} 详情
}
{changeCurrentSeconds()}
会议号:{state.channelId} 会议名称:{state.roomName}
{ setModeOpen(false) storage.setItem('meetingMode', 'StandardMode') }}> 标准模式
{ setModeOpen(false) storage.setItem('meetingMode', 'SpeakerMode') }}> 演讲模式
{ setModeOpen(false) }}> 取消
} title="" trigger="click" open={modeOpen} onOpenChange={() => setModeOpen(true)} >
{meetingMode === 'StandardMode' ? : } {getMeetingContentBodyLeftModeText()}
{isAdmin && currentLookUserAccount ? getSettingIcon() : null}
{roomUserList.map((item: any, index: number) => { return (item.isRoom && item.isAdmin ?
{ if (String(isShare) === item.screenShareId) { renderVideo(item.screenShareId) } else { renderVideo(item.uid) } }} onContextMenu={(e: any) => { if (role.ID.includes(userInfo.roleId)) { setContextMenuStyle({ top: e.clientY, left: e.clientX, }) setContextMenu(item) } }} >
{meetingContentUser(item)} {item.enableCamera ? null : meetingContentError(item)} {String(isShare) === item.screenShareId ?
屏幕分享中
: null} {role.ID.includes(user.roleId) ? {item.isRoomManager || role.ID.includes(item.roleId) ? : null} {item.uid !== user.uid && !role.ID.includes(item.roleId) ? : null} {item.isRoomManager ? : null} {item.isRoomManager ? : null} {item.uid !== user.uid ? : null} {item.uid !== user.uid ? : null} {item.uid !== user.uid ? : null}
}>
: null}
: null) } )} {isAdmin > 6 ?
{meetingMode === "StandardMode" ?
{ const container = document.getElementById('videoView') as HTMLElement; container.scrollLeft -= 100 }}>
:
{ const container = document.getElementById('videoView') as HTMLElement; container.scrollTop -= 100 }}>
} {meetingMode === "StandardMode" ?
{ const container = document.getElementById('videoView') as HTMLElement; container.scrollLeft += 100 }}>
:
{ const container = document.getElementById('videoView') as HTMLElement; container.scrollTop += 100 }}>
}
: null} {currentLookUserStatus === 0 ?
{
}
{isVideoFullScreen ? setIsVideoFullScreen(false)} /> : setIsVideoFullScreen(true)} />} {meetingContentUser(currentLookUserAccount, true)}
: null} {currentLookUserStatus === 1 ?
{
}
{isVideoFullScreen ? setIsVideoFullScreen(false)} /> : setIsVideoFullScreen(true)} />} {meetingContentUser(currentLookUserAccount, true)} {currentLookUserAccount.enableCamera ? null : meetingContentError(currentLookUserAccount)}
: null} {currentLookUserStatus === 2 ?
{isVideoFullScreen ? setIsVideoFullScreen(false)} /> : setIsVideoFullScreen(true)} />} {meetingContentUser(currentLookUserAccount, true)}
: null} {currentLookUserStatus === 3 ?
{isVideoFullScreen ? setIsVideoFullScreen(false)} /> : setIsVideoFullScreen(true)} />} {meetingContentUser(currentLookUserAccount, true)}
: null} {currentLookUserStatus === 4 ?
{isVideoFullScreen ? setIsVideoFullScreen(false)} /> : setIsVideoFullScreen(true)} />} {meetingContentUser(currentLookUserAccount, true)} {currentLookUserAccount.enableCamera ? null : meetingContentError(currentLookUserAccount)}
: null} {isAdmin ? null :
}
{ (statusList.userList || statusList.userChatList || statusList.userVideo) ? (
{statusList.userList ?
成员列表 { setStatusList({ userList: false, userChatList: false, userVideo: false, }) }} />
} value={userSearchValue} onChange={(e) => { setUserSearchValue(e.target.value) const newRoomUserList = [...roomUserList] newRoomUserList.forEach(row => { if (e.target.value) { if (row.userName.indexOf(e.target.value) !== -1) { row.isShow = true; } else { row.isShow = false; } } else { row.isShow = true; } }); setRoomUserList(newRoomUserList) }} />
{roomUserList.map((item: any, index: number) => { return ( item.isShow && item.isRoom ?
{item.userName}{item.uid === user.uid ? '(我)' : ''} {role.ID.includes(item.roleId) || item.isRoomManager ? {role.ID.includes(item.roleId) ? '管理员' : '发言人'} : null}
{role.ID.includes(item.roleId) || item.isRoomManager ?
{ postOpenMicr(!item.enableMicr, item.uid) }} title={item.enableMicr ? '静音' : '解除静音'} />
: null} {role.ID.includes(item.roleId) || item.isRoomManager ?
{ postOpenCamera(!item.enableCamera, item.uid) }} title={item.enableCamera ? '关闭视频' : '开启视频'} />
: null} {item.uid !== user.uid && role.ID.includes(user.roleId) ?
}>
: null} {item.uid !== user.uid && !role.ID.includes(item.roleId) && role.ID.includes(user.roleId) ?
{ if (item.isRoomManager) { DeleteRoomManager({ roomId: state.roomId, roomNum: state.channelId, userId: item.uid }) } else { postRoomManager({ roomId: state.roomId, roomNum: state.channelId, userId: item.uid }) } }}> {!item.isRoomManager ? : }
: null}
: null ) } )}
{ await getUserRoomInfo().then(async (res) => { if (res) { invitingPersonnelRef.current.changeInvitingPersonnelModal() } else { message.error(msgTips) } }) }}>邀请
postOpenMicr(false, user.id, true)}>全员静音
: statusList.userChatList ?
聊天 { setStatusList({ userList: false, userChatList: false, userVideo: false, }) }} />
{chatList.map((item: any, index: number) =>
{role.ID.includes(user.roleId) ? { if (e) { GetRoomUserItem(state.channelId, item.uid).then((res: any) => { if (res.code === 200) { setRoomUserItem(res.data) } }) } else { setRoomUserItem(null) } }} content={ roomUserItem ?
{roomUserItem.isRoomManager || role.ID.includes(roomUserItem.roleId) ? : null} {roomUserItem.uid !== user.uid && !role.ID.includes(roomUserItem.roleId) ? : null} {roomUserItem.isRoomManager ? : null} {roomUserItem.isRoomManager ? : null} {roomUserItem.uid !== user.uid ? : null} {roomUserItem.uid !== user.uid ? : null}
:
用户不在房间内
}>
{item.uid !== user.uid ? {item.userName} {dayjs(item.timestamp).format('HH:mm:ss')} : {dayjs(item.timestamp).format('HH:mm:ss')} {item.userName} }
:
{item.uid !== user.uid ? {item.userName}{dayjs(item.timestamp).format('HH:mm:ss')} : {dayjs(item.timestamp).format('HH:mm:ss')} {item.userName} }
}
{item.message}
)}
{ commonlyChatList.map((item: string, index: number) => { return }) }
{ setTextMsg(e.target.value) }}>
:
会议监控 { await agora.allLeaveChannelEx() setStatusList({ userList: false, userChatList: false, userVideo: false, }) }} />
}
) : null } {isScreenCapture ? null :
{footerList.map((item: any, itemIndex: number) => { return (
{item.map((row: any, rowIndex: number) => { switch (row.title) { case '结束': return {role.ID.includes(user.roleId) ? { GetLeaveAll({ roomNum: state.channelId, }) }} onCancel={() => { }} okText="结束" cancelText="取消" >
全员结束会议
: null}
leaveChannel()}>仅自己离开
{ setOpen(false) }}>取消
} title="" trigger="click" open={open} onOpenChange={() => setOpen(true)} >
changeFooterListSelect(row, itemIndex, rowIndex, true)} onMouseUp={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} onMouseLeave={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} > {row.select ? : } {row.title}
case '签到': if (!role.ID.includes(user.roleId)) { return
changeStatusList(row, itemIndex, rowIndex)} onMouseDown={() => changeFooterListSelect(row, itemIndex, rowIndex, true)} onMouseUp={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} onMouseLeave={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} key={rowIndex}> {row.select ? : } {row.title}
} return null case '申请发言': // if (!role.ID.includes(user.roleId)) { // return
changeStatusList(row, itemIndex, rowIndex)} key={rowIndex}> // {row.select ? : } // {row.title} //
// } return null case '结束发言': if (!role.ID.includes(user.roleId)) { return { DeleteRoomManager({ roomId: state.roomId, roomNum: state.channelId, userId: userInfo.uid }) }} okText="确定" cancelText="取消" >
{row.title}
} return null case '会议监控': if (role.ID.includes(user.roleId)) { return
changeStatusList(row, itemIndex, rowIndex)} onMouseDown={() => changeFooterListSelect(row, itemIndex, rowIndex, true)} onMouseUp={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} onMouseLeave={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} key={rowIndex}> {statusList.userVideo ? : row.select ? : } {row.title}
} return null case '成员列表': return
changeStatusList(row, itemIndex, rowIndex)} onMouseDown={() => changeFooterListSelect(row, itemIndex, rowIndex, true)} onMouseUp={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} onMouseLeave={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} key={rowIndex}> {statusList.userList ? : row.select ? : } {row.title} {row.title === '成员列表' ?
{roomUserList.filter((item: any) => item.isRoom).length}
: null}
case '聊天': return
changeStatusList(row, itemIndex, rowIndex)} onMouseDown={() => changeFooterListSelect(row, itemIndex, rowIndex, true)} onMouseUp={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} onMouseLeave={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} key={rowIndex}> {statusList.userChatList ? : row.select ? : } {row.title} {row.title === '聊天' && noViewChatList > 0 ?
{noViewChatList}
: null}
case '静音': case '解除静音': return
changeStatusList(row, itemIndex, rowIndex)} onMouseDown={() => changeFooterListSelect(row, itemIndex, rowIndex, true)} onMouseUp={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} onMouseLeave={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} key={rowIndex}> {row.title}
case '录制': case '录制中': if (role.ID.includes(user.roleId)) { return
changeStatusList(row, itemIndex, rowIndex)} onMouseDown={() => changeFooterListSelect(row, itemIndex, rowIndex, true)} onMouseUp={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} onMouseLeave={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} key={rowIndex}> {row.select ? : } {row.title}
} return null default: return
changeStatusList(row, itemIndex, rowIndex)} onMouseDown={() => changeFooterListSelect(row, itemIndex, rowIndex, true)} onMouseUp={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} onMouseLeave={() => changeFooterListSelect(row, itemIndex, rowIndex, false)} key={rowIndex}> {row.select ? : } {row.title}
} })}
) })} }
{sharedScreenList.map((item: any, index: number) => { return (
{ setSharedScreenItem(item) }}> {item.iconDataUrl ? : ''}
{item.sourceTitle}
) })}
{ setIsComputerAudio(e.target.checked) }} checked={isComputerAudio}>共享电脑音频 { setIsFluencyPriority(e.target.checked) }} checked={isFluencyPriority}>流畅度优先
{isShare && sharedScreenItem ? { let data = sharedScreenList.find((item: any) => item.sourceId === sharedScreenItem.sourceId) if (data) { PostSharedScreen(state.channelId).then(res => { if (res.code === 200) { setIsSharePopConfirm(false) clickSharedScreen() } }) } else { message.error('请选择应用!') } }} onCancel={() => { setIsSharePopConfirm(false) }} okText="是" cancelText="否" > : }
{role.ID.includes(user.roleId) ? { await GetLeaveAll({ roomNum: state.channelId, }) }} onCancel={() => { }} okText="结束" cancelText="取消" >
全员结束会议
: null}
{ await leaveChannel() }}>仅自己离开
{ setQuitMeetingModal(false) }}>取消
) } const meetingContentUser = (item: any, bool?: boolean) => { return ( <>
{role.ID.includes(item.roleId) || item.isRoomManager ?
: null} { bool ? !item.enableMicr ? : '' : } {item.userName} {role.ID.includes(item.roleId) || item.isRoomManager ? role.ID.includes(item.roleId) ? '(管理员)' : '(发言人)' : ''}
) } const meetingContentError = (item: any) => { return ( <>
) } const networkIcon = (network: number) => { switch (network) { case 0: return case 1: return case 2: return case 3: return } } export default Meeting