会议监控

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() const cancellationToken = new CancellationToken()
app.allowRendererProcessReuse = false; app.allowRendererProcessReuse = false;
let mainWindow = null; let mainWindow = null;
let newWindow = null;
let isMaximized = false; let isMaximized = false;
let env; let env;
@ -263,46 +262,6 @@ app.on('ready', () => {
const y = Math.round((display.workArea.height - mainWindow.getSize()[1]) / 2); const y = Math.round((display.workArea.height - mainWindow.getSize()[1]) / 2);
mainWindow.setPosition(x, y); 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事件触发后的操作自行编写 // 检测更新在你想要检查更新的时候执行renderer事件触发后的操作自行编写

View File

@ -60,13 +60,5 @@ window.electron = {
// 下载文件 // 下载文件
downFile: (callback) => { downFile: (callback) => {
ipcRenderer.on('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 { agora } from "@/utils/package/agora";
import QuitTips from "@/components/QuitTips"; import QuitTips from "@/components/QuitTips";
import { GetLeave } from "@/api/Meeting"; import { GetLeave } from "@/api/Meeting";
import UserVideo from "./page/UserVideo";
import path from "path"; import path from "path";
const fs = require('fs').promises; const fs = require('fs').promises;
const { exec } = require('child_process'); const { exec } = require('child_process');
@ -33,128 +32,123 @@ const App: React.FC = () => {
}); });
const [spinning, setSpinning] = useState(false); const [spinning, setSpinning] = useState(false);
const [isState, setIsState] = useState(true); const [isState, setIsState] = useState(true);
if (location.href.indexOf('/userVideo') === -1) { useEffect(() => {
useEffect(() => { let userInfo = JSON.parse(storage.getItem('user') as string)
let userInfo = JSON.parse(storage.getItem('user') as string) let loginInfo = JSON.parse(storage.getItem('login') as string)
let loginInfo = JSON.parse(storage.getItem('login') as string) if (userInfo) {
if (userInfo) { if (loginInfo && loginInfo.isAutoLogin) {
if (loginInfo && loginInfo.isAutoLogin) { PostLogin({
PostLogin({ account: loginInfo.account,
account: loginInfo.account, pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex)
pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex) }).then(async (res) => {
}).then(async (res) => { if (res.code === 200) {
if (res.code === 200) { storage.setItem('user', JSON.stringify(res.data))
storage.setItem('user', JSON.stringify(res.data)) toSrc('/home')
toSrc('/home') await startSignalr()
await startSignalr() } else {
} else { toSrc('/login')
toSrc('/login') }
} })
})
} else {
toSrc('/login')
}
} else { } else {
toSrc('/login') toSrc('/login')
} }
window.addEventListener('resize', handleResize); } else {
window.addEventListener('online', handleNetworkChange); toSrc('/login')
window.addEventListener('offline', handleNetworkChange); }
const originalSetItem = window.localStorage.setItem; window.addEventListener('resize', handleResize);
window.localStorage.setItem = function (key, value) { window.addEventListener('online', handleNetworkChange);
originalSetItem.call(this, key, value); window.addEventListener('offline', handleNetworkChange);
const event = new Event('customStorageChange') as any; const originalSetItem = window.localStorage.setItem;
event.key = key window.localStorage.setItem = function (key, value) {
event.value = value originalSetItem.call(this, key, value);
window.dispatchEvent(event); const event = new Event('customStorageChange') as any;
}; event.key = key
window.addEventListener('customStorageChange', handleCustomStorageChange); event.value = value
return () => { window.dispatchEvent(event);
window.removeEventListener('resize', handleResize); };
window.removeEventListener('customStorageChange', handleCustomStorageChange); window.addEventListener('customStorageChange', handleCustomStorageChange);
window.removeEventListener('online', handleNetworkChange); return () => {
window.removeEventListener('offline', handleNetworkChange); window.removeEventListener('resize', handleResize);
}; window.removeEventListener('customStorageChange', handleCustomStorageChange);
}, []); window.removeEventListener('online', handleNetworkChange);
useEffect(() => { window.removeEventListener('offline', handleNetworkChange);
window.electron.downFile(async (_e: any, data: any) => { };
const response = await fetch(data.filePath); }, []);
const arrayBuffer = await response.arrayBuffer(); useEffect(() => {
const buffer = Buffer.from(arrayBuffer); window.electron.downFile(async (_e: any, data: any) => {
fs.writeFile(`${data.downFilePaths}${data.fileName}`, buffer, {}); const response = await fetch(data.filePath);
message.success(`下载成功!文件已保存至:${data.downFilePaths}`) const arrayBuffer = await response.arrayBuffer();
await fs.access(data.downFilePaths, fs.constants.F_OK); const buffer = Buffer.from(arrayBuffer);
if (process.platform === 'win32') { fs.writeFile(`${data.downFilePaths}${data.fileName}`, buffer, {});
exec(`explorer "${data.downFilePaths}"`); message.success(`下载成功!文件已保存至:${data.downFilePaths}`)
} else if (process.platform === 'darwin') { await fs.access(data.downFilePaths, fs.constants.F_OK);
exec(`open "${data.downFilePaths}"`); if (process.platform === 'win32') {
} exec(`explorer "${data.downFilePaths}"`);
}) } else if (process.platform === 'darwin') {
window.electron.onFilePath(async (_e: any, filePath: string, key: string) => { exec(`open "${data.downFilePaths}"`);
const setting = await JSON.parse(storage.getItem('setting') as string) }
if (key === 'recordingFilesPath') { })
setting.recordingFilesPath = filePath 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 { } else {
setting.shareFilesPath = filePath if (storage.getItem('isTips') === 'true') {
} const setting = JSON.parse(storage.getItem('setting') as string)
storage.setItem('setting', JSON.stringify(setting)) if (setting.closeSetting === 'hide') {
}) window.electron.setViewStatus(setting.closeSetting)
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()
}
} else { } else {
quitTipsRef.current.changeModal() window.electron.quit()
} }
} else {
quitTipsRef.current.changeModal()
} }
}) }
} })
storage.setItem('stateInfo', JSON.stringify(state)) }
}, [state]) storage.setItem('stateInfo', JSON.stringify(state))
useEffect(() => { }, [state])
if (location.href.indexOf('/login') !== -1) { useEffect(() => {
onStop() if (location.href.indexOf('/login') !== -1) {
} onStop()
if (location.href.indexOf('/meeting') === -1) { }
window.electron.closeMonitorWindow() }, [navigate])
}
}, [navigate])
}
useEffect(() => { useEffect(() => {
document.addEventListener('keydown', (event) => { document.addEventListener('keydown', (event) => {
if (event.key === 'F11') { if (event.key === 'F11') {
@ -259,7 +253,6 @@ const App: React.FC = () => {
</Route> </Route>
<Route path='/login' element={<Login />} /> <Route path='/login' element={<Login />} />
<Route path='/meeting' element={<Meeting />} /> <Route path='/meeting' element={<Meeting />} />
<Route path='/userVideo' element={<UserVideo />} />
<Route path='*' element={<NotFound />} /> <Route path='*' element={<NotFound />} />
</Routes> </Routes>
<Spin spinning={spinning} fullscreen /> <Spin spinning={spinning} fullscreen />

View File

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

View File

@ -1,13 +1,14 @@
import styles from '@/components/UserVideo/index.module.scss'
import { GetPolling } from '@/api/Meeting'; import { GetPolling } from '@/api/Meeting';
import styles from '@/page/UserVideo/index.module.scss'
import { storage } from '@/utils'; import { storage } from '@/utils';
import { agora } from '@/utils/package/agora'; import { agora } from '@/utils/package/agora';
import { CloseOutlined } from '@ant-design/icons';
import { Button, Empty, Select, message } from 'antd'; import { Button, Empty, Select, message } from 'antd';
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useLocation } from 'react-router';
const UserVideo: React.FC = () => { const UserVideo: React.FC = () => {
let userInfo = JSON.parse(storage.getItem('user') as string) let userInfo = JSON.parse(storage.getItem('user') as string)
const { state } = useLocation();
const [user, setUser] = useState<any>({}); const [user, setUser] = useState<any>({});
const [from, setFrom] = useState<any>({ const [from, setFrom] = useState<any>({
cycleIntervalList: [ 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> => { 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) { if (res.code === 200) {
setUserList(res.data) setUserList(res.data)
} }
@ -94,13 +89,7 @@ const UserVideo: React.FC = () => {
return ( return (
<> <>
<div className={styles.userVideo}> <div className={styles.userVideo}>
<div className={styles.userVideoTitle}> <div className={`${styles.userVideoContent}`}>
<CloseOutlined className='drag' onClick={() => {
window.electron.closeMonitorWindow()
}} />
</div>
<div className={`${styles.userVideoContent} drag`}>
<div className={styles.userVideoContentHeader}> <div className={styles.userVideoContentHeader}>
<div> <div>
<div> <div>
@ -108,6 +97,7 @@ const UserVideo: React.FC = () => {
<Select <Select
placeholder='请选择循环间隔' placeholder='请选择循环间隔'
options={from.cycleIntervalList} options={from.cycleIntervalList}
size={'small'}
value={from.cycleIntervalValue} onChange={(e) => { value={from.cycleIntervalValue} onChange={(e) => {
setFrom({ ...from, cycleIntervalValue: e }) setFrom({ ...from, cycleIntervalValue: e })
setTimeNumber(e) setTimeNumber(e)
@ -118,6 +108,7 @@ const UserVideo: React.FC = () => {
<Select <Select
placeholder='请选择查看人数' placeholder='请选择查看人数'
options={from.viewPeople} options={from.viewPeople}
size={'small'}
value={from.viewPeopleValue} onChange={(e) => { value={from.viewPeopleValue} onChange={(e) => {
setFrom({ ...from, viewPeopleValue: e }) setFrom({ ...from, viewPeopleValue: e })
}} /> }} />
@ -127,6 +118,7 @@ const UserVideo: React.FC = () => {
<span>{timeNumber}</span> <span>{timeNumber}</span>
{timeStatus ? <Button {timeStatus ? <Button
type="primary" type="primary"
size={'small'}
onClick={() => { onClick={() => {
setTimeStatus(!timeStatus) setTimeStatus(!timeStatus)
}} }}
@ -135,6 +127,7 @@ const UserVideo: React.FC = () => {
<Button <Button
type="primary" type="primary"
className='m-ant-btn' className='m-ant-btn'
size={'small'}
onClick={() => { onClick={() => {
setTimeStatus(!timeStatus) setTimeStatus(!timeStatus)
}} }}

View File

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

3
src/render.d.ts vendored
View File

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