- {!item.active ?
+ {!item.active ?
: ''}
{item.select ?

:

}
diff --git a/src/page/Meeting/index.module.scss b/src/page/Meeting/index.module.scss
index f3a07c0..53680e0 100644
--- a/src/page/Meeting/index.module.scss
+++ b/src/page/Meeting/index.module.scss
@@ -303,7 +303,7 @@
// 演讲者模式
.meetingContentBodyLeftSpeakerMode {
- width: 18%;
+ width: 270px;
overflow-y: auto;
height: 100%;
@@ -312,7 +312,7 @@
}
.meetingContentSwiperCard {
- height: calc(100% / 6);
+ height: 160px;
}
}
@@ -379,7 +379,7 @@
right: 0;
bottom: 0;
height: 100% !important;
- width: calc(100% - 18%) !important;
+ width: calc(100% - 270px) !important;
z-index: 2;
}
@@ -390,7 +390,7 @@
.meetingContentSwiperCard {
height: 160px;
- width: calc(100% / 6);
+ width: 270px;
border-radius: 10px;
overflow: hidden;
position: relative;
@@ -444,8 +444,8 @@
color: white;
border: 1px white solid;
font-size: 20px;
- width: 30px;
- height: 30px;
+ width: 25px;
+ height: 25px;
display: flex;
justify-content: center;
align-items: center;
@@ -549,6 +549,8 @@
font-size: 14px;
color: #F3F3F5;
margin-left: 4px;
+ display: flex;
+ align-items: center;
}
>div {
@@ -660,6 +662,8 @@
font-size: 14px;
color: #F3F3F5;
margin-left: 4px;
+ display: flex;
+ align-items: center;
}
}
@@ -689,6 +693,8 @@
>span {
font-size: 14px;
color: #F3F3F5;
+ display: flex;
+ align-items: center;
}
>div {
@@ -798,7 +804,7 @@
}
>img {
- height: 50px;
+ height: 35px;
}
>span {
@@ -820,8 +826,8 @@
}
>label {
- height: 50px;
- height: 50px;
+ height: 35px;
+ height: 35px;
cursor: pointer;
position: relative;
diff --git a/src/page/Meeting/index.tsx b/src/page/Meeting/index.tsx
index f5afd9b..0a62747 100644
--- a/src/page/Meeting/index.tsx
+++ b/src/page/Meeting/index.tsx
@@ -8,12 +8,12 @@ import { SearchOutlined, EllipsisOutlined, ExclamationCircleFilled, FullscreenEx
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 { GetRoomUser, PostOpenMicr, GetSharedScreen, PostOpenCamera, GetLeaveAll, PostRoomManager, DeleteRoomManager, GetRoomKickout, GetShowUser, PostShowUser, PostMuteAll, GetRoomUserItem, GetApplySpeak, PostSharedScreen, PostStopSharedScreen } 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 { AudioVolumeInfo, ConnectionChangedReasonType, ConnectionStateType, LocalVideoStreamReason, LocalVideoStreamState, RenderModeType, RtcConnection, RtcStats, StreamPublishState, UserOfflineReasonType, VideoSourceType, VideoStreamType } from 'agora-electron-sdk';
import Avatar from '@/components/Avatar';
import SharedFilesModel from '@/components/SharedFilesModel';
import StupWizard from '@/components/StupWizard';
@@ -26,6 +26,7 @@ import MeetingDisconnected from '@/components/MeetingDisconnected';
import SingIn from '@/components/SingIn';
import UserName from '@/components/UserName';
import { GetRoomRtcToken } from '@/api/Home/Index';
+import Code from '@/components/Code';
const { setTimeout, setInterval, clearTimeout, clearInterval } = require('timers');
const { confirm } = Modal;
const { exec } = require('child_process');
@@ -158,6 +159,8 @@ const Meeting: React.FC = () => {
itemIndex: 0,
rowIndex: 0,
});
+ const [_audioStatus, setAudioStatus] = useState
(1);
+ const [_videoStatus, setVideoStatus] = useState(1);
const [roomUserList, setRoomUserList] = useState([])
const [_speackUid, setSpeackUid] = useState([])
const [currentSpeakUser, setCurrentSpeakUser] = useState([])
@@ -215,6 +218,7 @@ const Meeting: React.FC = () => {
});
const [isVideoFullScreen, setIsVideoFullScreen] = useState(false)
const [observer, setObserver] = useState()
+ const [_activeSpeaker, setActiveSpeaker] = useState('')
let userInfo = JSON.parse(storage.getItem('user') as string)
const msgTips = '您不是管理员或发言人,无法开启此功能!'
const channel = new BroadcastChannel('meeting_channel');
@@ -272,7 +276,7 @@ const Meeting: React.FC = () => {
case 'shareScreenWindowClose':
setCurrentSeconds(shareScreenWindowClose)
await stopScreenCapture()
- await allUserLook(userInfo.uid, userInfo.userName)
+ await allUserLook(userInfo.uid, userInfo.userName, true)
break;
case 'shareScreenWindowfooterListsTitle':
switch (shareScreenWindowfooterListsTitle) {
@@ -719,7 +723,7 @@ const Meeting: React.FC = () => {
break;
// 扩展操作
case 'Operation':
- switch (item.type) {
+ switch (item.contentString) {
}
break;
@@ -782,6 +786,14 @@ const Meeting: React.FC = () => {
break;
// 发言人用户信息刷新
case 'ManagerRefresh':
+ if (!item.user.isRoomManager) {
+ setCurrentVideoId((res: any) => {
+ if (res === String(item.user.uid)) {
+ getShowUser()
+ }
+ return res
+ })
+ }
setAllUserListData('ManagerRefresh', item, async () => {
if (item.user.uid === item.uid) {
if (item.user.uid === userInfo.uid) {
@@ -821,73 +833,14 @@ const Meeting: React.FC = () => {
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
+ window.electron.setChildWindowShow({
+ key: 'noticeWindow',
+ bool: true
})
+ channel.postMessage({
+ type: 'noticeItem',
+ noticeItem: item
+ });
break;
// 管理员查看随机用户
case 'Watch':
@@ -932,7 +885,7 @@ const Meeting: React.FC = () => {
}
}),
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
+ ecordingVolume: setting.ecordingVolume
}
window.electron.onInvoke('sendDrivers', {
uid: item.callerUid,
@@ -1023,10 +976,35 @@ const Meeting: React.FC = () => {
return res
})
break;
- // 共享
+ // 设置发言人
case 'SetSpeaker':
window.electron.onInvoke('SetSpeakerCallback', item.RoomManagerInputDTO)
break;
+ // 扩展参数
+ case 'ReceivedOperation':
+ try {
+ const temp = JSON.parse(item.contentString)
+ if (temp.type === 'audio') {
+ await PostOpenMicr({
+ roomNum: temp.roomNum,
+ uid: temp.uid,
+ enableMicr: temp.enableMicr
+ })
+ } else {
+ await PostOpenCamera({
+ roomNum: temp.roomNum,
+ uid: temp.uid,
+ enableCamera: temp.enableCamera
+ })
+ }
+ } catch (error) {
+
+ }
+ break;
+ // 共享人取消共享屏幕
+ case 'StopedSharedScreen':
+ setVideoUser()
+ break;
}
})
return () => {
@@ -1182,6 +1160,61 @@ const Meeting: React.FC = () => {
return () => clearTimeout(timer);
}, [isClickedMediaSteam]);
+ // useEffect(() => {
+ // let timer: NodeJS.Timeout | string = '';
+ // if (audioStatus === 1 && videoStatus === 1) {
+ // if (timer) {
+ // clearTimeout(timer)
+ // timer = ''
+ // }
+ // timer = setTimeout(() => {
+ // setIsShare((req: any) => {
+ // if (!req) {
+ // setRoomUserList((res: any) => {
+ // let userItem = res.find((item: any) => item.uid === userInfo.uid)
+ // if (!role.ID.includes(userInfo.roleId) && userItem && userItem.isRoomManager) {
+ // DeleteRoomManager({
+ // roomId: state.roomId,
+ // roomNum: state.channelId,
+ // userId: userInfo.uid
+ // })
+ // confirm({
+ // title: '提示',
+ // icon: ,
+ // content: `由于您长时间未发言,已自动取消发言权限,是否重新申请发言?`,
+ // centered: true,
+ // okText: '确定',
+ // cancelText: '取消',
+ // async onOk() {
+ // GetApplySpeak(state.channelId).then(res => {
+ // if (res.code === 200) {
+ // setIsClicked(true);
+ // message.success('申请发言成功')
+ // }
+ // })
+ // },
+ // onCancel() {
+
+ // }
+ // })
+ // }
+ // clearTimeout(timer)
+ // timer = ''
+ // return res
+ // })
+ // }
+ // return req
+ // })
+ // }, 1000 * 60 * 5);
+ // } else {
+ // if (timer) {
+ // clearTimeout(timer)
+ // timer = ''
+ // }
+ // }
+ // return () => timer ? clearTimeout(timer) : '';
+ // }, [audioStatus, videoStatus]);
+
useEffect(() => {
let timer: NodeJS.Timeout | undefined;
if (timer) {
@@ -1313,6 +1346,32 @@ const Meeting: React.FC = () => {
channelId: connection.channelId,
renderMode: RenderModeType.RenderModeFit
})
+ setCurrentVideoId((res: any) => {
+ if (res === String(remoteUid)) {
+ let dom: any;
+ setCurrentLookUserStatus(req => {
+ switch (req) {
+ case 1:
+ dom = document.getElementById(`video-source-camera-primary`) as HTMLElement
+ break;
+ case 2:
+ dom = document.getElementById(`video-source-screen`) as HTMLElement;
+ break;
+ case 3:
+ dom = document.getElementById(`video-source-remote-screen`) as HTMLElement
+ break;
+ case 4:
+ dom = document.getElementById(`video-source-remote-camera`) as HTMLElement
+ break;
+ }
+ if (dom && dom.childNodes.length === 1) {
+ renderVideo(String(remoteUid))
+ }
+ return req
+ })
+ }
+ return res
+ })
}, 1000);
}
}
@@ -1369,6 +1428,20 @@ const Meeting: React.FC = () => {
} else if (state === 3) {
meetingDisconnectedRef.current.changeModal(false)
setIsAgoraDisconnected(false)
+ } else if (state === 5) {
+ confirm({
+ keyboard: false,
+ title: '提示',
+ icon: ,
+ content: `重连失败,请退出房间重试!`,
+ centered: true,
+ okText: '退出',
+ wrapClassName: 'hideCancelText',
+ cancelText: '',
+ async onOk() {
+ leaveChannel()
+ },
+ })
}
},
onConnectionLost: () => {
@@ -1388,18 +1461,33 @@ const Meeting: React.FC = () => {
if (bool) {
stopScreenCapture()
setSharedScreenItem('')
- allUserLook(userInfo.uid, userInfo.userName)
+ allUserLook(userInfo.uid, userInfo.userName, true)
}
return bool
})
} else if (reason === 3 || reason === 4) {
message.error({
- content: 请检查摄像头是否正常工作,检查摄像头是否被其他应用占用,或者尝试重新加入频道,
{
+ content: 检查摄像头是否正常、未被占用,或尝试重新加入频道。 {
stupWizardRef.current.changeModal(1);
}}>前往修改摄像头
,
- duration: 60,
+ duration: 15,
key: 'cameraTemporarily'
});
+ } else if (_state === 3) {
+ if (!stupWizardRef.current.getStupWizardModal()) {
+ await PostOpenCamera({
+ roomNum: state.channelId,
+ uid: userInfo.uid,
+ enableCamera: false
+ })
+ message.error({
+ content: 检查摄像头是否正常、未被占用,或尝试重新加入频道。 {
+ stupWizardRef.current.changeModal(1);
+ }}>前往修改摄像头
,
+ duration: 15,
+ key: 'cameraTemporarily'
+ });
+ }
}
},
onTokenPrivilegeWillExpire: async (connection: RtcConnection, _token: string) => {
@@ -1411,6 +1499,23 @@ const Meeting: React.FC = () => {
})
}
})
+ },
+ onVideoPublishStateChanged: (_source: VideoSourceType, _channel: string, _oldState: StreamPublishState, newState: StreamPublishState, _elapseSinceLastState: number) => {
+ setVideoStatus(newState)
+ },
+ onAudioPublishStateChanged: (_channel: string, _oldState: StreamPublishState, newState: StreamPublishState, _elapseSinceLastState: number) => {
+ setAudioStatus(newState)
+ },
+ onActiveSpeaker: (_connection: RtcConnection, uid: number) => {
+ if (String(uid).length !== 9) {
+ setActiveSpeaker(String(uid))
+ }
+ setIsShare((res: any) => {
+ if (!res && String(uid).length !== 9) {
+ renderVideo(String(uid))
+ }
+ return res
+ })
}
})
if (state.enableCamera) {
@@ -1664,6 +1769,20 @@ const Meeting: React.FC = () => {
})
}
}
+ const setVideoUser = () => {
+ setRoomUserList((newChatList: any) => {
+ setActiveSpeaker(res => {
+ let item = newChatList.find((item: any) => item.uid === res)
+ if (item && item.isRoom && item.isAdmin) {
+ renderVideo(res)
+ } else {
+ getShowUser()
+ }
+ return res
+ })
+ return newChatList
+ })
+ }
// 加入房间时间
const changeCurrentSeconds = (): string => {
const duration = dayjs.duration(currentSeconds, 'seconds');
@@ -1731,8 +1850,8 @@ const Meeting: React.FC = () => {
if (res) {
GetSharedScreen(state.channelId).then(req => {
if (req.code === 200) {
- if (res.data) {
- setIsShare(res.data)
+ if (req.data) {
+ setIsShare(req.data)
}
getDesktopCapturerVideo()
setIsSharedScreenModal(true)
@@ -1753,7 +1872,7 @@ const Meeting: React.FC = () => {
}
})
if (row.title === '停止共享') {
- await allUserLook(userInfo.uid, userInfo.userName)
+ await allUserLook(userInfo.uid, userInfo.userName, true)
}
break;
case '静音':
@@ -2020,8 +2139,12 @@ const Meeting: React.FC = () => {
})
};
// 设置全员看谁
- const allUserLook = async (uid: string, name: string): Promise => {
- await PostShowUser(state.channelId, uid, name)
+ const allUserLook = async (uid: string, name: string, bool?: boolean): Promise => {
+ if (bool) {
+ await PostStopSharedScreen(state.channelId)
+ } else {
+ await PostShowUser(state.channelId, uid, name)
+ }
}
// 设置发言人
const postRoomManager = async (data: any): Promise => {
@@ -2083,7 +2206,25 @@ const Meeting: React.FC = () => {
item.isRoom = true;
item.isAdmin = role.ID.includes(item.roleId) || item.isRoomManager
})
- setRoomUserList(res.data)
+ setRoomUserList((req: any) => {
+ if (req.length) {
+ let arr: any = []
+ res.data.forEach((item: any) => {
+ let userItem = req.find((row: any) => row.uid == item.uid);
+ if (userItem) {
+ userItem.enableCamera = item.enableCamera;
+ userItem.enableMicr = item.enableMicr;
+ userItem.isRoomManager = item.isRoomManager;
+ userItem.isAdmin = role.ID.includes(item.roleId) || item.isRoomManager;
+ } else {
+ arr.push(item)
+ }
+ });
+ return [...req, ...arr]
+ } else {
+ return res.data
+ }
+ })
getUserRoomInfo().then(async (res) => {
await agora.updateChannelMediaOptions(res ? true : false)
changeAgoraDevice()
@@ -2115,7 +2256,7 @@ const Meeting: React.FC = () => {
enableCamera: !storeDevice[0][1].active,
isRoomManager: userItem ? userItem.isRoomManager : false,
})
- await getShowUser()
+ setVideoUser()
if (userItem.isRoomManager) {
await postOpenMicr(!storeDevice[0][0].active, userInfo.uid)
await postOpenCamera(!storeDevice[0][1].active, userInfo.uid)
@@ -2147,25 +2288,28 @@ const Meeting: React.FC = () => {
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,
+ setRoomUserList((res: any) => {
+ let row = res.find((item: any) => item.uid === userInfo.uid)
+ window.electron.onInvoke('sendChannelMsg', {
+ roomNum: state.channelId,
+ msg: msg,
+ })
+ let item = {
+ uid: userInfo.uid,
+ userName: row.userName,
+ message: msg,
+ timestamp: +new Date()
}
+ setChatList((newChatList: any) => [...newChatList, item])
+ window.electron.windowHandleMessage({
+ key: 'chatSmallWindow',
+ parmes: {
+ chatListIten: item,
+ }
+ })
+ chatScrollBotton()
+ return res
})
- setTextMsg('');
- chatScrollBotton()
} else {
message.error('请输入内容!')
}
@@ -2213,8 +2357,6 @@ const Meeting: React.FC = () => {
}
})
}
-
-
// 开关麦克风
const postOpenMicrApi = async (enableMicr: boolean, uid: string, isAll: boolean, isMessage: boolean = false): Promise => {
if (isAll) {
@@ -2223,11 +2365,20 @@ const Meeting: React.FC = () => {
enableMicr
})
} else {
- await PostOpenMicr({
- roomNum: state.channelId,
+ await window.electron.onInvoke('sendOper2User', {
uid,
- enableMicr
+ contentString: JSON.stringify({
+ roomNum: state.channelId,
+ uid,
+ enableMicr,
+ type: 'audio'
+ })
})
+ // await PostOpenMicr({
+ // roomNum: state.channelId,
+ // uid,
+ // enableMicr
+ // })
}
if (isMessage) {
// message.success('操作成功')
@@ -2268,11 +2419,20 @@ const Meeting: React.FC = () => {
} else {
await agora.stopCameraCapture();
}
- await PostOpenCamera({
- roomNum: state.channelId,
+ await window.electron.onInvoke('sendOper2User', {
uid,
- enableCamera
+ contentString: JSON.stringify({
+ roomNum: state.channelId,
+ uid,
+ enableCamera,
+ type: 'video'
+ })
})
+ // await PostOpenCamera({
+ // roomNum: state.channelId,
+ // uid,
+ // enableCamera
+ // })
if (isMessage) {
// message.success('操作成功')
}
@@ -2376,7 +2536,7 @@ const Meeting: React.FC = () => {
//右
} else {
- return setIsVideoFullScreen(true)}>
+ return
setIsVideoFullScreen(true)}>
@@ -2415,6 +2575,14 @@ const Meeting: React.FC = () => {
}
message.success('操作成功')
}
+ // 判断是否出现滚动条
+ const hasScrollbar = () => {
+ let element = document.getElementById('videoView') as HTMLDivElement
+ if (element) {
+ return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
+ }
+ return false
+ }
// 移出房间
const getRoomKickout = async (channelId: string, uid: string, userName: string): Promise
=> {
confirm({
@@ -2601,7 +2769,9 @@ const Meeting: React.FC = () => {
}
{changeCurrentSeconds()}
-
会议号:{state.channelId} 会议名称:{state.roomName}
+
会议号:{state.channelId} 会议名称:{state.roomName}
+
+
: null)
}
)}
- {isAdmin > 6 ?
+ {hasScrollbar() ?
{meetingMode === "StandardMode" ?
{
const container = document.getElementById('videoView') as HTMLElement;
container.scrollLeft -= 100
}}>
-
:
{
+
:
{
const container = document.getElementById('videoView') as HTMLElement;
container.scrollTop -= 100
}}>
@@ -2786,7 +2956,7 @@ const Meeting: React.FC = () => {
container.scrollLeft += 100
}}>
-
:
{
+
:
{
const container = document.getElementById('videoView') as HTMLElement;
container.scrollTop += 100
}}>
@@ -2900,7 +3070,7 @@ const Meeting: React.FC = () => {
- {item.userName}{item.uid === user.uid ? '(我)' : ''}
+ {item.userName}{item.uid === user.uid ? '(我)' : ''}
{role.ID.includes(item.roleId) || item.isRoomManager ?
{role.ID.includes(item.roleId) ? '管理员' : '发言人'}
@@ -3120,19 +3290,30 @@ const Meeting: React.FC = () => {
>移出会议 : null}
:
用户不在房间内
}>
-
+
{item.uid !== user.uid ?
-
{item.userName} {dayjs(item.timestamp).format('HH:mm:ss')} :
-
{dayjs(item.timestamp).format('HH:mm:ss')} {item.userName}
+
+ {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.userName}
+ {dayjs(item.timestamp).format('HH:mm:ss')}
+ :
+
+ {dayjs(item.timestamp).format('HH:mm:ss')}
+ {item.userName}
+
}
}
{item.message}
@@ -3157,7 +3338,10 @@ const Meeting: React.FC = () => {
{
setTextMsg(e.target.value)
}}>
-
+
:
@@ -3327,7 +3511,7 @@ const Meeting: React.FC = () => {
key={rowIndex}>