会议监控

This commit is contained in:
yj 2024-08-29 13:38:41 +08:00
parent 3998bed6ff
commit 47c4626171
8 changed files with 363 additions and 377 deletions

41
main.js
View File

@ -16,7 +16,6 @@ const { autoUpdater, CancellationToken } = require('electron-updater');
const cancellationToken = new CancellationToken()
app.allowRendererProcessReuse = false;
let mainWindow = null;
let newWindow = null;
let isMaximized = false;
let env;
@ -263,46 +262,6 @@ app.on('ready', () => {
const y = Math.round((display.workArea.height - mainWindow.getSize()[1]) / 2);
mainWindow.setPosition(x, y);
});
// 打开新窗口
ipcMain.handle('oepnWindow', (event, data) => {
if (newWindow) {
newWindow.focus();
} else {
newWindow = new BrowserWindow({
width: 1200,
height: 800,
minWidth: 1200,
minHeight: 800,
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
enableRemoteModule: true,
nodeIntegrationInWorker: true,
allowMediaDevices: true,
preload: path.join(__dirname, 'preload.js')
},
frame: false,
backgroundColor: '#00000000',
transparent: true,
});
newWindow.loadURL(data.url);
newWindow.focus();
newWindow.webContents.on('before-input-event', (event, input) => {
if (env === 'development') {
if (input.key === 'F12') {
newWindow.webContents.openDevTools()
}
}
});
}
});
// 关闭会议监控窗口
ipcMain.handle('closeMonitorWindow', () => {
if (newWindow) {
newWindow.close();
newWindow = null
}
});
}
});
// 检测更新在你想要检查更新的时候执行renderer事件触发后的操作自行编写

View File

@ -60,13 +60,5 @@ window.electron = {
// 下载文件
downFile: (callback) => {
ipcRenderer.on('downFile', callback)
},
// 打开新窗口
oepnWindow: (data) => {
ipcRenderer.invoke('oepnWindow', data)
},
// 关闭会议监控窗口
closeMonitorWindow: () => {
ipcRenderer.invoke('closeMonitorWindow')
}
}

View File

@ -17,7 +17,6 @@ import { PostLogin } from "@/api/Login";
import { agora } from "@/utils/package/agora";
import QuitTips from "@/components/QuitTips";
import { GetLeave } from "@/api/Meeting";
import UserVideo from "./page/UserVideo";
import path from "path";
const fs = require('fs').promises;
const { exec } = require('child_process');
@ -33,128 +32,123 @@ const App: React.FC = () => {
});
const [spinning, setSpinning] = useState(false);
const [isState, setIsState] = useState(true);
if (location.href.indexOf('/userVideo') === -1) {
useEffect(() => {
let userInfo = JSON.parse(storage.getItem('user') as string)
let loginInfo = JSON.parse(storage.getItem('login') as string)
if (userInfo) {
if (loginInfo && loginInfo.isAutoLogin) {
PostLogin({
account: loginInfo.account,
pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex)
}).then(async (res) => {
if (res.code === 200) {
storage.setItem('user', JSON.stringify(res.data))
toSrc('/home')
await startSignalr()
} else {
toSrc('/login')
}
})
} else {
toSrc('/login')
}
useEffect(() => {
let userInfo = JSON.parse(storage.getItem('user') as string)
let loginInfo = JSON.parse(storage.getItem('login') as string)
if (userInfo) {
if (loginInfo && loginInfo.isAutoLogin) {
PostLogin({
account: loginInfo.account,
pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex)
}).then(async (res) => {
if (res.code === 200) {
storage.setItem('user', JSON.stringify(res.data))
toSrc('/home')
await startSignalr()
} else {
toSrc('/login')
}
})
} else {
toSrc('/login')
}
window.addEventListener('resize', handleResize);
window.addEventListener('online', handleNetworkChange);
window.addEventListener('offline', handleNetworkChange);
const originalSetItem = window.localStorage.setItem;
window.localStorage.setItem = function (key, value) {
originalSetItem.call(this, key, value);
const event = new Event('customStorageChange') as any;
event.key = key
event.value = value
window.dispatchEvent(event);
};
window.addEventListener('customStorageChange', handleCustomStorageChange);
return () => {
window.removeEventListener('resize', handleResize);
window.removeEventListener('customStorageChange', handleCustomStorageChange);
window.removeEventListener('online', handleNetworkChange);
window.removeEventListener('offline', handleNetworkChange);
};
}, []);
useEffect(() => {
window.electron.downFile(async (_e: any, data: any) => {
const response = await fetch(data.filePath);
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
fs.writeFile(`${data.downFilePaths}${data.fileName}`, buffer, {});
message.success(`下载成功!文件已保存至:${data.downFilePaths}`)
await fs.access(data.downFilePaths, fs.constants.F_OK);
if (process.platform === 'win32') {
exec(`explorer "${data.downFilePaths}"`);
} else if (process.platform === 'darwin') {
exec(`open "${data.downFilePaths}"`);
}
})
window.electron.onFilePath(async (_e: any, filePath: string, key: string) => {
const setting = await JSON.parse(storage.getItem('setting') as string)
if (key === 'recordingFilesPath') {
setting.recordingFilesPath = filePath
} else {
toSrc('/login')
}
window.addEventListener('resize', handleResize);
window.addEventListener('online', handleNetworkChange);
window.addEventListener('offline', handleNetworkChange);
const originalSetItem = window.localStorage.setItem;
window.localStorage.setItem = function (key, value) {
originalSetItem.call(this, key, value);
const event = new Event('customStorageChange') as any;
event.key = key
event.value = value
window.dispatchEvent(event);
};
window.addEventListener('customStorageChange', handleCustomStorageChange);
return () => {
window.removeEventListener('resize', handleResize);
window.removeEventListener('customStorageChange', handleCustomStorageChange);
window.removeEventListener('online', handleNetworkChange);
window.removeEventListener('offline', handleNetworkChange);
};
}, []);
useEffect(() => {
window.electron.downFile(async (_e: any, data: any) => {
const response = await fetch(data.filePath);
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
fs.writeFile(`${data.downFilePaths}${data.fileName}`, buffer, {});
message.success(`下载成功!文件已保存至:${data.downFilePaths}`)
await fs.access(data.downFilePaths, fs.constants.F_OK);
if (process.platform === 'win32') {
exec(`explorer "${data.downFilePaths}"`);
} else if (process.platform === 'darwin') {
exec(`open "${data.downFilePaths}"`);
}
})
window.electron.onFilePath(async (_e: any, filePath: string, key: string) => {
const setting = await JSON.parse(storage.getItem('setting') as string)
if (key === 'recordingFilesPath') {
setting.recordingFilesPath = filePath
} else {
setting.shareFilesPath = filePath
}
storage.setItem('setting', JSON.stringify(setting))
})
window.electron.quitAndInstall(async (_e: any) => {
leaveChannel()
})
}, [])
useEffect(() => {
window.electron.onUpdate((_e: any, data: any) => {
if (location.hash.indexOf('/meeting') === -1) {
updateModalRef.current.changeModal(data)
}
})
if (!storage.getItem('setting')) {
storage.setItem('setting', JSON.stringify({
videoDeviceId: '', //摄像头id
ecordingDeviceId: "", //输入设备id
playBackDeviceId: "", //输出设备id
ecordingVolume: '', //输入音量
playBackVolume: '', //输出音量
autoEcordingVolume: true, //是否自动调整麦克风音量
recordingFilesPath: path.resolve(__dirname, '../../Downloads') + '\\', //本地录制保存路径
shareFilesPath: path.resolve(__dirname, '../../Downloads/') + '\\', //共享文件保存路径
isShareSavePath: true, //是否下载钱询问每个文件保存的位置
closeSetting: 'hide', //关闭按钮设置
}))
}
}, [])
useEffect(() => {
if (isState) {
setIsState(false)
window.electron.onQuit(async () => {
if (location.hash.indexOf('/login') === 1) {
window.electron.quit()
} else {
setting.shareFilesPath = filePath
}
storage.setItem('setting', JSON.stringify(setting))
})
window.electron.quitAndInstall(async (_e: any) => {
leaveChannel()
})
}, [])
useEffect(() => {
window.electron.onUpdate((_e: any, data: any) => {
if (location.hash.indexOf('/meeting') === -1) {
updateModalRef.current.changeModal(data)
}
})
if (!storage.getItem('setting')) {
storage.setItem('setting', JSON.stringify({
videoDeviceId: '', //摄像头id
ecordingDeviceId: "", //输入设备id
playBackDeviceId: "", //输出设备id
ecordingVolume: '', //输入音量
playBackVolume: '', //输出音量
autoEcordingVolume: true, //是否自动调整麦克风音量
recordingFilesPath: path.resolve(__dirname, '../../Downloads') + '\\', //本地录制保存路径
shareFilesPath: path.resolve(__dirname, '../../Downloads/') + '\\', //共享文件保存路径
isShareSavePath: true, //是否下载钱询问每个文件保存的位置
closeSetting: 'hide', //关闭按钮设置
}))
}
}, [])
useEffect(() => {
if (isState) {
setIsState(false)
window.electron.onQuit(async () => {
if (location.hash.indexOf('/login') === 1) {
window.electron.quit()
} else {
if (storage.getItem('isTips') === 'true') {
const setting = JSON.parse(storage.getItem('setting') as string)
if (setting.closeSetting === 'hide') {
window.electron.setViewStatus(setting.closeSetting)
} else {
window.electron.quit()
}
if (storage.getItem('isTips') === 'true') {
const setting = JSON.parse(storage.getItem('setting') as string)
if (setting.closeSetting === 'hide') {
window.electron.setViewStatus(setting.closeSetting)
} else {
quitTipsRef.current.changeModal()
window.electron.quit()
}
} else {
quitTipsRef.current.changeModal()
}
})
}
storage.setItem('stateInfo', JSON.stringify(state))
}, [state])
useEffect(() => {
if (location.href.indexOf('/login') !== -1) {
onStop()
}
if (location.href.indexOf('/meeting') === -1) {
window.electron.closeMonitorWindow()
}
}, [navigate])
}
}
})
}
storage.setItem('stateInfo', JSON.stringify(state))
}, [state])
useEffect(() => {
if (location.href.indexOf('/login') !== -1) {
onStop()
}
}, [navigate])
useEffect(() => {
document.addEventListener('keydown', (event) => {
if (event.key === 'F11') {
@ -259,7 +253,6 @@ const App: React.FC = () => {
</Route>
<Route path='/login' element={<Login />} />
<Route path='/meeting' element={<Meeting />} />
<Route path='/userVideo' element={<UserVideo />} />
<Route path='*' element={<NotFound />} />
</Routes>
<Spin spinning={spinning} fullscreen />

View File

@ -2,40 +2,24 @@
width: 100%;
height: 100%;
background-color: rgb(7, 9, 11);
padding: 20px;
box-sizing: border-box;
display: flex;
flex-direction: column;
.userVideoTitle {
text-align: center;
color: white;
font-size: 20px;
flex-shrink: 0;
position: relative;
>span {
cursor: pointer;
position: absolute;
right: 20px;
top: 50%;
transform: translate(0, -50%);
}
}
.userVideoContent {
flex-grow: 1;
display: flex;
flex-direction: column;
padding: 20px 40px 0;
.userVideoContentHeader {
flex-shrink: 0;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
margin-bottom: 10px;
padding: 0 10px;
padding: 10px;
box-sizing: border-box;
>div:nth-child(1) {
display: flex;
@ -45,12 +29,16 @@
background-color: #181A1D;
border-radius: 4px;
padding: 4px 10px;
box-sizing: border-box;
margin: 0 10px 0 0;
display: flex;
align-items: center;
>span {
color: #EEEEEE;
font-size: 14px;
margin-right: 10px;
font-size: 12px;
white-space: nowrap;
margin-right: 4px;
}
}
}
@ -61,8 +49,8 @@
>span {
color: #EEEEEE;
font-size: 14px;
margin-right: 10px;
font-size: 12px;
margin-right: 4px;
}
}
}
@ -78,7 +66,7 @@
.userVideoContentListItem {
height: 20%;
width: calc(100% / 4 - 20px);
width: calc(100% / 3 - 20px);
padding: 10px;
.userVideoContentListItemVideo {

View File

@ -1,13 +1,14 @@
import styles from '@/components/UserVideo/index.module.scss'
import { GetPolling } from '@/api/Meeting';
import styles from '@/page/UserVideo/index.module.scss'
import { storage } from '@/utils';
import { agora } from '@/utils/package/agora';
import { CloseOutlined } from '@ant-design/icons';
import { Button, Empty, Select, message } from 'antd';
import { useEffect, useState } from "react";
import { useLocation } from 'react-router';
const UserVideo: React.FC = () => {
let userInfo = JSON.parse(storage.getItem('user') as string)
const { state } = useLocation();
const [user, setUser] = useState<any>({});
const [from, setFrom] = useState<any>({
cycleIntervalList: [
@ -77,15 +78,9 @@ const UserVideo: React.FC = () => {
}
};
// 获取地址栏参数
const getQueryParameterRegex = (name: string): string | null => {
const reg = new RegExp(`[?&]${name}=([^&#]*)`);
const results = window.location.href.match(reg);
return results === null ? null : results[1];
}
// 获取轮训用户
const getPolling = async (): Promise<void> => {
GetPolling(getQueryParameterRegex('channelId')?.split('1')[0] as string, from.viewPeopleValue).then((res: any) => {
GetPolling(state.channelId?.split('1')[0] as string, from.viewPeopleValue).then((res: any) => {
if (res.code === 200) {
setUserList(res.data)
}
@ -94,13 +89,7 @@ const UserVideo: React.FC = () => {
return (
<>
<div className={styles.userVideo}>
<div className={styles.userVideoTitle}>
<CloseOutlined className='drag' onClick={() => {
window.electron.closeMonitorWindow()
}} />
</div>
<div className={`${styles.userVideoContent} drag`}>
<div className={`${styles.userVideoContent}`}>
<div className={styles.userVideoContentHeader}>
<div>
<div>
@ -108,6 +97,7 @@ const UserVideo: React.FC = () => {
<Select
placeholder='请选择循环间隔'
options={from.cycleIntervalList}
size={'small'}
value={from.cycleIntervalValue} onChange={(e) => {
setFrom({ ...from, cycleIntervalValue: e })
setTimeNumber(e)
@ -118,6 +108,7 @@ const UserVideo: React.FC = () => {
<Select
placeholder='请选择查看人数'
options={from.viewPeople}
size={'small'}
value={from.viewPeopleValue} onChange={(e) => {
setFrom({ ...from, viewPeopleValue: e })
}} />
@ -127,6 +118,7 @@ const UserVideo: React.FC = () => {
<span>{timeNumber}</span>
{timeStatus ? <Button
type="primary"
size={'small'}
onClick={() => {
setTimeStatus(!timeStatus)
}}
@ -135,6 +127,7 @@ const UserVideo: React.FC = () => {
<Button
type="primary"
className='m-ant-btn'
size={'small'}
onClick={() => {
setTimeStatus(!timeStatus)
}}

View File

@ -343,6 +343,7 @@
}
}
.meetingContentSwiperCardFullScreenIcon {
position: absolute;
z-index: 3;
@ -416,11 +417,11 @@
}
.meetingContentBodyRight {
width: 300px;
flex-shrink: 0;
height: 100%;
.meetingUserList {
width: 300px;
height: 100%;
padding: 10px 0 20px;
box-sizing: border-box;
@ -535,6 +536,7 @@
}
.meetingUserChat {
width: 300px;
height: 100%;
background-color: #16191E;
display: flex;
@ -653,6 +655,40 @@
border-top: 1px solid #23272E;
}
}
.meetingUserVideoList {
width: 500px;
padding: 10px 10px 10px;
box-sizing: border-box;
height: 100%;
background-color: #16191E;
display: flex;
flex-direction: column;
.meetingUserVideoListTitle {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
>span {
color: #EEEEEE;
font-size: 18px;
}
>img {
cursor: pointer;
}
}
.meetingUserVideoListContent {
flex-grow: 1;
height: 0px;
overflow-y: auto;
box-sizing: border-box;
}
}
}
}

View File

@ -18,6 +18,7 @@ import { VideoSourceType } from 'agora-electron-sdk';
import Avatar from '@/components/Avatar';
import SharedFilesModel from '@/components/SharedFilesModel';
import StupWizard from '@/components/StupWizard';
import UserVideo from '@/components/UserVideo';
const { confirm } = Modal;
const { exec } = require('child_process');
const fs = require('fs').promises;
@ -33,6 +34,7 @@ const Meeting: React.FC = () => {
const [statusList, setStatusList] = useState({
userList: false,
userChatList: false,
userVideo: false,
})
const [isSharedScreenModal, setIsSharedScreenModal] = useState(false);
const [user, setUser] = useState<any>({});
@ -85,13 +87,6 @@ const Meeting: React.FC = () => {
active: false,
select: false,
},
// {
// title: '会议监控',
// icon: ImageUrl.icon48,
// iconSelect: ImageUrl.icon48Select,
// active: false,
// select: false,
// },
{
title: '录制',
icon: ImageUrl.icon27,
@ -115,21 +110,27 @@ const Meeting: React.FC = () => {
select: false,
},
],
[
{
title: '成员列表',
icon: ImageUrl.icon30,
iconSelect: ImageUrl.icon30Select,
active: false,
select: false,
},
{
title: '聊天',
icon: ImageUrl.icon31,
iconSelect: ImageUrl.icon31Select,
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<any>({
@ -494,6 +495,7 @@ const Meeting: React.FC = () => {
await agora.init(true)
agora.registerEventHandler({
onJoinChannelSuccess: async (info: any, _elapsed: any) => {
console.log(info, '本地');
if (info.channelId === state.channelId) {
if (String(info.localUid).length !== 9) {
await getJoin(state.enableMicr, state.enableCamera)
@ -510,6 +512,7 @@ const Meeting: React.FC = () => {
}
},
onUserJoined: async (info: any, remoteUid: any, _elapsed: any) => {
console.log(info, remoteUid, '远端');
if (info.channelId === state.channelId) {
if (String(remoteUid).length === 9) {
setIsShare(remoteUid)
@ -525,6 +528,7 @@ const Meeting: React.FC = () => {
}
},
onUserOffline: async (info: any, remoteUid: any, _reason: any) => {
console.log(info, remoteUid, '离开');
if (info.channelId === state.channelId) {
if (String(remoteUid).length === 9) {
setIsShare(null)
@ -561,7 +565,7 @@ const Meeting: React.FC = () => {
uid: userInfo.uid,
screenShareId: userInfo.screenShareId,
token: state.token,
// tokenA: state.tokenA,
tokenA: state.tokenA,
})
}
// 状态更新
@ -838,6 +842,7 @@ const Meeting: React.FC = () => {
setStatusList({
userList: statusList.userList ? false : true,
userChatList: false,
userVideo: false,
})
storage.setItem('noViewChatList', 0)
setNoViewChatList(0)
@ -846,6 +851,7 @@ const Meeting: React.FC = () => {
setStatusList({
userList: false,
userChatList: statusList.userChatList ? false : true,
userVideo: false,
})
storage.setItem('noViewChatList', 0)
setNoViewChatList(0)
@ -960,9 +966,13 @@ const Meeting: React.FC = () => {
}
break;
case '会议监控':
window.electron.oepnWindow({
url: location.origin + `/#/userVideo?channelId=${state.channelId + '1'}&token=${state.tokenA}`
setStatusList({
userVideo: statusList.userVideo ? false : true,
userChatList: false,
userList: false,
})
storage.setItem('noViewChatList', 0)
setNoViewChatList(0)
break;
}
}
@ -1555,7 +1565,7 @@ const Meeting: React.FC = () => {
</div>
</div>
{
(statusList.userList || statusList.userChatList) ? (
(statusList.userList || statusList.userChatList || statusList.userVideo) ? (
<div className={`${styles.meetingContentBodyRight} drag`}>
{statusList.userList ?
<div className={styles.meetingUserList}>
@ -1565,6 +1575,7 @@ const Meeting: React.FC = () => {
setStatusList({
userList: false,
userChatList: false,
userVideo: false,
})
}} />
</div>
@ -1676,152 +1687,169 @@ const Meeting: React.FC = () => {
<div onClick={() => postOpenMicr(false, user.id, true)}></div>
</div>
</div>
:
<div className={styles.meetingUserChat} id='meetingUserChat'>
<div className={styles.meetingUserChatTitle}>
<span></span>
<img src={ImageUrl.icon18} alt="" onClick={() => {
setStatusList({
userList: false,
userChatList: false,
})
}} />
</div>
<div className={styles.meetingUserChatContent} id='meetingUserChatContentView'>
{chatList.map((item: any, index: number) =>
<div
key={index}
className={`${item.uid !== user.uid ? styles.meetingUserChatContentLeft : styles.meetingUserChatContentRight}`}>
{user.roleId === '1' ? <Popover
placement="bottom"
title={''}
onOpenChange={(e: boolean) => {
if (e) {
GetRoomUserItem(state.channelId, item.uid).then((res: any) => {
if (res.code === 200) {
setRoomUserItem(res.data)
}
})
} else {
setRoomUserItem(null)
}
}}
content={
roomUserItem ? <div className={styles.meetingContentSwiperCardPopover}>
{roomUserItem.isRoomManager || roomUserItem.roleId === '1' ? <Button
type="primary"
className='m-ant-btn'
size={'small'}
onClick={(event) => {
event.stopPropagation();
setAllUserLook(roomUserItem)
}}
>Ta</Button> : null}
{roomUserItem.uid !== user.uid && roomUserItem.roleId !== '1' ? <Button
type="primary"
className='m-ant-btn'
size={'small'}
onClick={async (event) => {
event.stopPropagation();
if (roomUserItem.isRoomManager) {
await DeleteRoomManager({
roomId: state.roomId,
roomNum: state.channelId,
userId: roomUserItem.uid
})
} else {
await postRoomManager({
roomId: state.roomId,
roomNum: state.channelId,
userId: roomUserItem.uid
})
: statusList.userChatList ?
<div className={styles.meetingUserChat} id='meetingUserChat'>
<div className={styles.meetingUserChatTitle}>
<span></span>
<img src={ImageUrl.icon18} alt="" onClick={() => {
setStatusList({
userList: false,
userChatList: false,
userVideo: false,
})
}} />
</div>
<div className={styles.meetingUserChatContent} id='meetingUserChatContentView'>
{chatList.map((item: any, index: number) =>
<div
key={index}
className={`${item.uid !== user.uid ? styles.meetingUserChatContentLeft : styles.meetingUserChatContentRight}`}>
{user.roleId === '1' ? <Popover
placement="bottom"
title={''}
onOpenChange={(e: boolean) => {
if (e) {
GetRoomUserItem(state.channelId, item.uid).then((res: any) => {
if (res.code === 200) {
setRoomUserItem(res.data)
}
await GetRoomUserItem(state.channelId, item.uid).then((res: any) => {
if (res.code === 200) {
setRoomUserItem(res.data)
})
} else {
setRoomUserItem(null)
}
}}
content={
roomUserItem ? <div className={styles.meetingContentSwiperCardPopover}>
{roomUserItem.isRoomManager || roomUserItem.roleId === '1' ? <Button
type="primary"
className='m-ant-btn'
size={'small'}
onClick={(event) => {
event.stopPropagation();
setAllUserLook(roomUserItem)
}}
>Ta</Button> : null}
{roomUserItem.uid !== user.uid && roomUserItem.roleId !== '1' ? <Button
type="primary"
className='m-ant-btn'
size={'small'}
onClick={async (event) => {
event.stopPropagation();
if (roomUserItem.isRoomManager) {
await DeleteRoomManager({
roomId: state.roomId,
roomNum: state.channelId,
userId: roomUserItem.uid
})
} else {
await postRoomManager({
roomId: state.roomId,
roomNum: state.channelId,
userId: roomUserItem.uid
})
}
})
}}
>{roomUserItem.isRoomManager ? '取消发言人' : '设为发言人'}</Button> : null}
{roomUserItem.isRoomManager ? <Button
type="primary"
className='m-ant-btn'
size={'small'}
onClick={async (event) => {
event.stopPropagation();
await postOpenMicr(!roomUserItem.enableMicr, roomUserItem.uid)
await GetRoomUserItem(state.channelId, item.uid).then((res: any) => {
if (res.code === 200) {
setRoomUserItem(res.data)
}
})
}}
>{roomUserItem.enableMicr ? '静音' : '解除静音'}</Button> : null}
{roomUserItem.isRoomManager ? <Button
type="primary"
className='m-ant-btn'
size={'small'}
onClick={async (event) => {
event.stopPropagation();
await postOpenCamera(!roomUserItem.enableCamera, roomUserItem.uid)
await GetRoomUserItem(state.channelId, item.uid).then((res: any) => {
if (res.code === 200) {
setRoomUserItem(res.data)
}
})
}}
>{roomUserItem.enableCamera ? '关闭视频' : '打开视频'}</Button> : null}
{roomUserItem.uid !== user.uid ? <Button
type="primary"
style={{ backgroundColor: '#EC3C3C' }}
size={'small'}
onClick={(event) => {
event.stopPropagation();
getRoomKickout(state.channelId, roomUserItem.uid, roomUserItem.userName)
}}
></Button> : null}
</div> : <div style={{ color: 'white' }}></div>
}>
<div>
await GetRoomUserItem(state.channelId, item.uid).then((res: any) => {
if (res.code === 200) {
setRoomUserItem(res.data)
}
})
}}
>{roomUserItem.isRoomManager ? '取消发言人' : '设为发言人'}</Button> : null}
{roomUserItem.isRoomManager ? <Button
type="primary"
className='m-ant-btn'
size={'small'}
onClick={async (event) => {
event.stopPropagation();
await postOpenMicr(!roomUserItem.enableMicr, roomUserItem.uid)
await GetRoomUserItem(state.channelId, item.uid).then((res: any) => {
if (res.code === 200) {
setRoomUserItem(res.data)
}
})
}}
>{roomUserItem.enableMicr ? '静音' : '解除静音'}</Button> : null}
{roomUserItem.isRoomManager ? <Button
type="primary"
className='m-ant-btn'
size={'small'}
onClick={async (event) => {
event.stopPropagation();
await postOpenCamera(!roomUserItem.enableCamera, roomUserItem.uid)
await GetRoomUserItem(state.channelId, item.uid).then((res: any) => {
if (res.code === 200) {
setRoomUserItem(res.data)
}
})
}}
>{roomUserItem.enableCamera ? '关闭视频' : '打开视频'}</Button> : null}
{roomUserItem.uid !== user.uid ? <Button
type="primary"
style={{ backgroundColor: '#EC3C3C' }}
size={'small'}
onClick={(event) => {
event.stopPropagation();
getRoomKickout(state.channelId, roomUserItem.uid, roomUserItem.userName)
}}
></Button> : null}
</div> : <div style={{ color: 'white' }}></div>
}>
<div>
<div><Avatar name={item.userName} /></div>
{item.uid !== user.uid ?
<span>{item.userName} <span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
<span> <span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
}
</div>
</Popover> : <div>
<div><Avatar name={item.userName} /></div>
{item.uid !== user.uid ?
<span>{item.userName} <span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
<span> <span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
<span>{item.userName}<span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
<span><span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
}
</div>
</Popover> : <div>
<div><Avatar name={item.userName} /></div>
{item.uid !== user.uid ?
<span>{item.userName}<span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
<span><span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
}
</div>}
<div>{item.message}</div>
</div>
)}
</div>}
<div>{item.message}</div>
</div>
)}
</div>
<div className={`${styles.meetingUserChatButton}`}>
{
commonlyChatList.map((item: string, index: number) => {
return <Button
key={index}
type="primary"
className='m-ant-btn'
onClick={() => {
sendMsg(item)
}}
>{item}</Button>
})
}
</div>
<div className={`${styles.meetingUserChatInput}`}>
<Input.TextArea placeholder="请输入消息" value={textMsg} style={{ flexGrow: 1 }} onChange={(e) => {
setTextMsg(e.target.value)
}}></Input.TextArea>
<Button type="primary" className='m-ant-btn' style={{ flexShrink: 0, marginTop: '4px' }} onClick={() => sendMsg()}></Button>
</div>
</div>
<div className={`${styles.meetingUserChatButton}`}>
{
commonlyChatList.map((item: string, index: number) => {
return <Button
key={index}
type="primary"
className='m-ant-btn'
onClick={() => {
sendMsg(item)
}}
>{item}</Button>
})
}
:
<div className={styles.meetingUserVideoList}>
<div className={styles.meetingUserVideoListTitle}>
<span></span>
<img src={ImageUrl.icon18} alt="" onClick={() => {
setStatusList({
userList: false,
userChatList: false,
userVideo: false,
})
}} />
</div>
<div className={styles.meetingUserVideoListContent}>
<UserVideo />
</div>
</div>
<div className={`${styles.meetingUserChatInput}`}>
<Input.TextArea placeholder="请输入消息" value={textMsg} style={{ flexGrow: 1 }} onChange={(e) => {
setTextMsg(e.target.value)
}}></Input.TextArea>
<Button type="primary" className='m-ant-btn' style={{ flexShrink: 0, marginTop: '4px' }} onClick={() => sendMsg()}></Button>
</div>
</div>
}
</div>
) : null
@ -1914,7 +1942,7 @@ const Meeting: React.FC = () => {
onMouseUp={() => changeFooterListSelect(row, itemIndex, rowIndex, false)}
onMouseLeave={() => changeFooterListSelect(row, itemIndex, rowIndex, false)}
key={rowIndex}>
{row.select ? <img src={row.iconSelect} alt="" /> : <img src={row.active ? row.iconActive : row.icon} alt="" />}
{statusList.userVideo ? <img src={row.iconSelect} alt="" /> : row.select ? <img src={row.iconSelect} alt="" /> : <img src={row.active ? row.iconActive : row.icon} alt="" />}
<span>{row.title}</span>
</div>
}

3
src/render.d.ts vendored
View File

@ -15,9 +15,6 @@ export interface IElectronAPI {
downFile: (callBack: Function) => void;
quitAndInstall: (callBack: Function) => void;
getVersion: () => Promise<string>;
oepnWindow: (data: any) => any;
closeMonitorWindow: () => void
}
declare global {