会议监控
This commit is contained in:
parent
3998bed6ff
commit
47c4626171
41
main.js
41
main.js
|
|
@ -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事件触发后的操作自行编写
|
||||
|
|
|
|||
|
|
@ -60,13 +60,5 @@ window.electron = {
|
|||
// 下载文件
|
||||
downFile: (callback) => {
|
||||
ipcRenderer.on('downFile', callback)
|
||||
},
|
||||
// 打开新窗口
|
||||
oepnWindow: (data) => {
|
||||
ipcRenderer.invoke('oepnWindow', data)
|
||||
},
|
||||
// 关闭会议监控窗口
|
||||
closeMonitorWindow: () => {
|
||||
ipcRenderer.invoke('closeMonitorWindow')
|
||||
}
|
||||
}
|
||||
|
|
|
|||
227
src/App.tsx
227
src/App.tsx
|
|
@ -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 />
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
@ -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)
|
||||
}}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue