会议监控
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()
|
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事件触发后的操作自行编写
|
||||||
|
|
|
||||||
|
|
@ -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')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
227
src/App.tsx
227
src/App.tsx
|
|
@ -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 />
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -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)
|
||||||
}}
|
}}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue