Merge pull request 'yangjie' (#22) from yangjie into master
Reviewed-on: #22
This commit is contained in:
commit
d536e5f100
183
main.js
183
main.js
|
|
@ -52,23 +52,6 @@ class AppWindow extends BrowserWindow {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showWindow() {
|
|
||||||
// 如果主窗口已经存在但被最小化了,则恢复显示
|
|
||||||
if (mainWindow && mainWindow.isMinimized()) {
|
|
||||||
mainWindow.show();
|
|
||||||
}
|
|
||||||
// 如果主窗口已存在但不是焦点窗口,则将其置为焦点
|
|
||||||
if (mainWindow && !mainWindow.isFocused()) {
|
|
||||||
mainWindow.show();
|
|
||||||
mainWindow.focus();
|
|
||||||
}
|
|
||||||
// 如果主窗口还没有被创建,则创建它
|
|
||||||
if (!mainWindow) {
|
|
||||||
createWindow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function quit() {
|
function quit() {
|
||||||
app.quit()
|
app.quit()
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +63,7 @@ function createTray() {
|
||||||
const contextMenu = Menu.buildFromTemplate([
|
const contextMenu = Menu.buildFromTemplate([
|
||||||
{
|
{
|
||||||
label: '打开', click: () => {
|
label: '打开', click: () => {
|
||||||
showWindow()
|
mainWindow.webContents.send('isOpenWindows');
|
||||||
},
|
},
|
||||||
// icon: iconPath,
|
// icon: iconPath,
|
||||||
},
|
},
|
||||||
|
|
@ -100,11 +83,7 @@ function createTray() {
|
||||||
tray.setToolTip('智汇享');
|
tray.setToolTip('智汇享');
|
||||||
tray.setContextMenu(contextMenu);
|
tray.setContextMenu(contextMenu);
|
||||||
tray.on('click', () => {
|
tray.on('click', () => {
|
||||||
if (mainWindow.isVisible()) {
|
mainWindow.webContents.send('isOpenWindows');
|
||||||
mainWindow.hide()
|
|
||||||
} else {
|
|
||||||
mainWindow.show()
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,11 +92,6 @@ function createWindow() {
|
||||||
mainWindow.focus();
|
mainWindow.focus();
|
||||||
}
|
}
|
||||||
const additionalData = { myKey: 'myValue' }
|
const additionalData = { myKey: 'myValue' }
|
||||||
// 退出房间
|
|
||||||
app.on('will-quit', async (event) => {
|
|
||||||
await mainWindow.webContents.send('quitAndInstall');
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('ready', () => {
|
app.on('ready', () => {
|
||||||
const gotTheLock = app.requestSingleInstanceLock(additionalData)
|
const gotTheLock = app.requestSingleInstanceLock(additionalData)
|
||||||
if (gotTheLock) {
|
if (gotTheLock) {
|
||||||
|
|
@ -161,7 +135,6 @@ app.on('ready', () => {
|
||||||
mainWindow.on('move', () => {
|
mainWindow.on('move', () => {
|
||||||
// 如果是全屏自动恢复到上次窗口大小
|
// 如果是全屏自动恢复到上次窗口大小
|
||||||
if (isMaximized) {
|
if (isMaximized) {
|
||||||
mainWindow.setResizable(true)
|
|
||||||
mainWindow.unmaximize()
|
mainWindow.unmaximize()
|
||||||
isMaximized = false;
|
isMaximized = false;
|
||||||
}
|
}
|
||||||
|
|
@ -177,10 +150,8 @@ app.on('ready', () => {
|
||||||
break;
|
break;
|
||||||
case 'maximize':
|
case 'maximize':
|
||||||
mainWindow.maximize()
|
mainWindow.maximize()
|
||||||
mainWindow.setResizable(false)
|
|
||||||
break;
|
break;
|
||||||
case 'unmaximize':
|
case 'unmaximize':
|
||||||
mainWindow.setResizable(true)
|
|
||||||
mainWindow.unmaximize()
|
mainWindow.unmaximize()
|
||||||
break;
|
break;
|
||||||
case 'minimize':
|
case 'minimize':
|
||||||
|
|
@ -189,6 +160,10 @@ app.on('ready', () => {
|
||||||
case 'hide':
|
case 'hide':
|
||||||
mainWindow.hide()
|
mainWindow.hide()
|
||||||
break;
|
break;
|
||||||
|
case 'show':
|
||||||
|
mainWindow.show()
|
||||||
|
mainWindow.focus();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 导出是否全屏
|
// 导出是否全屏
|
||||||
|
|
@ -199,6 +174,10 @@ app.on('ready', () => {
|
||||||
ipcMain.handle('getVersion', () => {
|
ipcMain.handle('getVersion', () => {
|
||||||
return app.getVersion();
|
return app.getVersion();
|
||||||
});
|
});
|
||||||
|
// 获取窗口是否显示
|
||||||
|
ipcMain.handle('isVisible', () => {
|
||||||
|
return mainWindow.isVisible();
|
||||||
|
});
|
||||||
// 获取共享屏幕列表
|
// 获取共享屏幕列表
|
||||||
ipcMain.handle('getSources', async () => {
|
ipcMain.handle('getSources', async () => {
|
||||||
return await desktopCapturer.getSources({
|
return await desktopCapturer.getSources({
|
||||||
|
|
@ -210,9 +189,12 @@ app.on('ready', () => {
|
||||||
clipboard.writeText(text)
|
clipboard.writeText(text)
|
||||||
});
|
});
|
||||||
// 退出
|
// 退出
|
||||||
ipcMain.handle('quit', async (event) => {
|
ipcMain.handle('quit', async (event, bool) => {
|
||||||
await mainWindow.webContents.send('quitAndInstall');
|
if (bool) {
|
||||||
quit()
|
quit()
|
||||||
|
} else {
|
||||||
|
await mainWindow.webContents.send('quitAndInstall');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// 加入房间通知
|
// 加入房间通知
|
||||||
ipcMain.handle('joinNotification', (event, user) => {
|
ipcMain.handle('joinNotification', (event, user) => {
|
||||||
|
|
@ -273,10 +255,7 @@ app.on('ready', () => {
|
||||||
// 设置窗口尺寸
|
// 设置窗口尺寸
|
||||||
mainWindow.setSize(config.width, config.height)
|
mainWindow.setSize(config.width, config.height)
|
||||||
// 设置窗口位置使其居中于当前屏幕
|
// 设置窗口位置使其居中于当前屏幕
|
||||||
const display = screen.getDisplayMatching({ ...mainWindow.getBounds() });
|
mainWindowCenter()
|
||||||
const x = Math.round((display.workArea.width - mainWindow.getSize()[0]) / 2);
|
|
||||||
const y = Math.round((display.workArea.height - mainWindow.getSize()[1]) / 2);
|
|
||||||
mainWindow.setPosition(x, y);
|
|
||||||
});
|
});
|
||||||
// 写入注册表
|
// 写入注册表
|
||||||
ipcMain.handle('setRegistry', (event, uuid) => {
|
ipcMain.handle('setRegistry', (event, uuid) => {
|
||||||
|
|
@ -319,19 +298,90 @@ app.on('ready', () => {
|
||||||
width: config.width,
|
width: config.width,
|
||||||
height: config.height,
|
height: config.height,
|
||||||
})
|
})
|
||||||
child.loadURL(config.url)
|
if (env === 'development') {
|
||||||
|
// 开发
|
||||||
|
child.loadURL(config.url)
|
||||||
|
} else {
|
||||||
|
// 测试 | 生产
|
||||||
|
child.loadURL(`file://${path.join(__dirname, './dist/index.html')}#/${config.key}`);
|
||||||
|
}
|
||||||
childWindow[config.key] = child
|
childWindow[config.key] = child
|
||||||
child.once('ready-to-show', () => {
|
child.once('ready-to-show', () => {
|
||||||
child.show()
|
if (config.show) {
|
||||||
if (config.key === 'shareScreenWindow') {
|
childWindow[config.key].show()
|
||||||
const display = screen.getDisplayMatching({ ...child.getBounds() });
|
|
||||||
const x = Math.round((display.workArea.width - child.getSize()[0]) / 2);
|
|
||||||
child.setPosition(x, 0);
|
|
||||||
child.setResizable(false)
|
|
||||||
child.setMovable(false)
|
|
||||||
mainWindow.setPosition(-999999, -999999);
|
|
||||||
}
|
}
|
||||||
|
childWindow[config.key].setAlwaysOnTop(true, 'screen-saver')
|
||||||
|
childWindow[config.key].setSkipTaskbar(true)
|
||||||
|
windowOperation(config)
|
||||||
})
|
})
|
||||||
|
child.webContents.on('before-input-event', (event, input) => {
|
||||||
|
// if (env === 'development') {
|
||||||
|
if (input.key === 'F12') {
|
||||||
|
child.webContents.openDevTools()
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// 关闭子窗口
|
||||||
|
ipcMain.handle('closeChildWindow', (event, key) => {
|
||||||
|
if (key === 'shareScreenWindow') {
|
||||||
|
for (const k in childWindow) {
|
||||||
|
if (childWindow[k]) {
|
||||||
|
childWindow[k].close()
|
||||||
|
childWindow[k] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mainWindowCenter()
|
||||||
|
} else {
|
||||||
|
childWindow[key].close()
|
||||||
|
childWindow[key] = ""
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 设置子窗口
|
||||||
|
ipcMain.handle('setChildWindow', (event, config) => {
|
||||||
|
switch (config.key) {
|
||||||
|
case 'shareScreenWindow':
|
||||||
|
childWindow[config.key].setBounds({ width: config.width })
|
||||||
|
break;
|
||||||
|
case 'chatSmallWindow':
|
||||||
|
childWindow[config.key].setBounds({ height: config.height })
|
||||||
|
break;
|
||||||
|
case 'noticeWindow':
|
||||||
|
childWindow[config.key].setBounds({ width: config.width, height: config.height })
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 隐藏显示子窗口
|
||||||
|
ipcMain.handle('setChildWindowShow', (event, config) => {
|
||||||
|
if (config.key === 'noticeWindow') {
|
||||||
|
if (config.bool) {
|
||||||
|
childWindow[config.key].show()
|
||||||
|
} else {
|
||||||
|
if (childWindow[config.key].isVisible()) {
|
||||||
|
childWindow[config.key].hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (childWindow[config.key].isVisible()) {
|
||||||
|
childWindow[config.key].hide()
|
||||||
|
} else {
|
||||||
|
childWindow[config.key].show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 隐藏主窗口
|
||||||
|
ipcMain.handle('mainWindowHide', () => {
|
||||||
|
mainWindowHide()
|
||||||
|
});
|
||||||
|
// 居中主窗口
|
||||||
|
ipcMain.handle('mainWindowCenter', () => {
|
||||||
|
mainWindowCenter()
|
||||||
|
});
|
||||||
|
// 窗口通信
|
||||||
|
ipcMain.handle('windowHandleMessage', (event, data) => {
|
||||||
|
if (childWindow[data.key]) {
|
||||||
|
childWindow[data.key].webContents.send('windowHandleMessageCallBack', data)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -401,3 +451,42 @@ function cancleDownloadUpdate() {
|
||||||
function quitAndInstall() {
|
function quitAndInstall() {
|
||||||
autoUpdater.quitAndInstall();
|
autoUpdater.quitAndInstall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function windowOperation(config) {
|
||||||
|
const child = childWindow[config.key];
|
||||||
|
const display = screen.getDisplayMatching({ ...child.getBounds() });
|
||||||
|
const { width, height } = display.size
|
||||||
|
let x, y;
|
||||||
|
child.setResizable(false)
|
||||||
|
switch (config.key) {
|
||||||
|
case 'shareScreenWindow':
|
||||||
|
x = Math.round((display.workArea.width - child.getSize()[0]) / 2);
|
||||||
|
child.setPosition(x, 0);
|
||||||
|
mainWindowHide()
|
||||||
|
break;
|
||||||
|
case 'chatSmallWindow':
|
||||||
|
y = height - child.getSize()[1];
|
||||||
|
child.setPosition(40, y - 200);
|
||||||
|
break;
|
||||||
|
case 'currentSpeakUserWindow':
|
||||||
|
x = width - child.getSize()[0];
|
||||||
|
child.setPosition(x - 40, 40);
|
||||||
|
break;
|
||||||
|
case 'noticeWindow':
|
||||||
|
x = width - child.getSize()[0];
|
||||||
|
y = height - child.getSize()[1];
|
||||||
|
child.setPosition(x, y - 80);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 主窗口居中
|
||||||
|
function mainWindowCenter() {
|
||||||
|
const display = screen.getDisplayMatching({ ...mainWindow.getBounds() });
|
||||||
|
const x = Math.round((display.workArea.width - mainWindow.getSize()[0]) / 2);
|
||||||
|
const y = Math.round((display.workArea.height - mainWindow.getSize()[1]) / 2);
|
||||||
|
mainWindow.setPosition(x, y);
|
||||||
|
}
|
||||||
|
// 主窗口隐藏
|
||||||
|
function mainWindowHide() {
|
||||||
|
mainWindow.setPosition(-999999, -999999);
|
||||||
|
}
|
||||||
40
preload.js
40
preload.js
|
|
@ -21,6 +21,10 @@ window.electron = {
|
||||||
getVersion: () => {
|
getVersion: () => {
|
||||||
return ipcRenderer.invoke('getVersion')
|
return ipcRenderer.invoke('getVersion')
|
||||||
},
|
},
|
||||||
|
// 获取窗口是否显示
|
||||||
|
isVisible: () => {
|
||||||
|
return ipcRenderer.invoke('isVisible')
|
||||||
|
},
|
||||||
// 获取共享屏幕列表
|
// 获取共享屏幕列表
|
||||||
getSources: () => {
|
getSources: () => {
|
||||||
return ipcRenderer.invoke('getSources')
|
return ipcRenderer.invoke('getSources')
|
||||||
|
|
@ -38,8 +42,8 @@ window.electron = {
|
||||||
ipcRenderer.on('onQuit', callback)
|
ipcRenderer.on('onQuit', callback)
|
||||||
},
|
},
|
||||||
// 退出房间
|
// 退出房间
|
||||||
quit: () => {
|
quit: (bool) => {
|
||||||
return ipcRenderer.invoke('quit')
|
return ipcRenderer.invoke('quit', bool)
|
||||||
},
|
},
|
||||||
// 监听更新
|
// 监听更新
|
||||||
onUpdate: (callback) => {
|
onUpdate: (callback) => {
|
||||||
|
|
@ -49,6 +53,10 @@ window.electron = {
|
||||||
quitAndInstall: (callback) => {
|
quitAndInstall: (callback) => {
|
||||||
ipcRenderer.on('quitAndInstall', callback)
|
ipcRenderer.on('quitAndInstall', callback)
|
||||||
},
|
},
|
||||||
|
// 点击任务栏图标是否打开窗口
|
||||||
|
isOpenWindows: (callback) => {
|
||||||
|
ipcRenderer.on('isOpenWindows', callback)
|
||||||
|
},
|
||||||
// 通知下载最新的包
|
// 通知下载最新的包
|
||||||
onDownload: (type) => {
|
onDownload: (type) => {
|
||||||
ipcRenderer.invoke('updateDownload', type)
|
ipcRenderer.invoke('updateDownload', type)
|
||||||
|
|
@ -77,4 +85,32 @@ window.electron = {
|
||||||
createChildWindow: (config) => {
|
createChildWindow: (config) => {
|
||||||
ipcRenderer.invoke('createChildWindow', config)
|
ipcRenderer.invoke('createChildWindow', config)
|
||||||
},
|
},
|
||||||
|
// 关闭子窗口
|
||||||
|
closeChildWindow: (key) => {
|
||||||
|
ipcRenderer.invoke('closeChildWindow', key)
|
||||||
|
},
|
||||||
|
// 设置子窗口
|
||||||
|
setChildWindow: (config) => {
|
||||||
|
ipcRenderer.invoke('setChildWindow', config)
|
||||||
|
},
|
||||||
|
// 隐藏主窗口
|
||||||
|
setChildWindowShow: (config) => {
|
||||||
|
ipcRenderer.invoke('setChildWindowShow', config)
|
||||||
|
},
|
||||||
|
// 隐藏主窗口
|
||||||
|
mainWindowHide: () => {
|
||||||
|
ipcRenderer.invoke('mainWindowHide')
|
||||||
|
},
|
||||||
|
// 居中主窗口
|
||||||
|
mainWindowCenter: () => {
|
||||||
|
ipcRenderer.invoke('mainWindowCenter')
|
||||||
|
},
|
||||||
|
// 窗口通信传参
|
||||||
|
windowHandleMessage: (data) => {
|
||||||
|
ipcRenderer.invoke('windowHandleMessage', data)
|
||||||
|
},
|
||||||
|
// 窗口通信回调
|
||||||
|
windowHandleMessageCallBack: (callback) => {
|
||||||
|
ipcRenderer.on('windowHandleMessageCallBack', callback)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
55
src/App.tsx
55
src/App.tsx
|
|
@ -18,7 +18,13 @@ 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 path from "path";
|
import path from "path";
|
||||||
import ShareScreenWindow from "./page/ShareScreenWindow";
|
import ShareScreenWindow from "@/page/Meeting/ShareScreenWindow";
|
||||||
|
import UserListWindow from "@/page/Meeting/UserListWindow";
|
||||||
|
import ChatSmallWindow from "@/page/Meeting/ChatSmallWindow";
|
||||||
|
import ChatBigWindow from "@/page/Meeting/ChatBigWindow";
|
||||||
|
import CurrentSpeakUserWindow from "@/page/Meeting/CurrentSpeakUserWindow";
|
||||||
|
import NoticeWindow from "@/page/Meeting/NoticeWindow";
|
||||||
|
import { getKeyOpenChildWindow, setKeyOpenChildWindow } from "./utils/package/public";
|
||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
const { exec } = require('child_process');
|
const { exec } = require('child_process');
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
|
|
@ -33,7 +39,8 @@ 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.hash.indexOf('shareScreenWindow') == -1) {
|
const urlHashArr = ['#/userListWindow', '#/shareScreenWindow', '#/chatSmallWindow', '#/chatBigWindow', '#/currentSpeakUserWindow', '#/noticeWindow']
|
||||||
|
if (urlHashArr.indexOf(location.hash) == -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)
|
||||||
|
|
@ -97,7 +104,22 @@ const App: React.FC = () => {
|
||||||
storage.setItem('setting', JSON.stringify(setting))
|
storage.setItem('setting', JSON.stringify(setting))
|
||||||
})
|
})
|
||||||
window.electron.quitAndInstall(async (_e: any) => {
|
window.electron.quitAndInstall(async (_e: any) => {
|
||||||
leaveChannel()
|
let bool = await window.electron.isVisible()
|
||||||
|
if (bool) {
|
||||||
|
storage.setItem('quitMeeting', true)
|
||||||
|
window.electron.setViewStatus('show')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
window.electron.isOpenWindows(async (_e: any) => {
|
||||||
|
let bool = await window.electron.isVisible()
|
||||||
|
if (location.hash.indexOf('/meeting') === -1) {
|
||||||
|
window.electron.setViewStatus(bool ? 'hide' : 'show')
|
||||||
|
} else {
|
||||||
|
let shareScreenWindow = await getKeyOpenChildWindow('shareScreenWindow')
|
||||||
|
if (!shareScreenWindow) {
|
||||||
|
window.electron.setViewStatus(bool ? 'hide' : 'show')
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -120,22 +142,26 @@ const App: React.FC = () => {
|
||||||
closeSetting: 'hide', //关闭按钮设置
|
closeSetting: 'hide', //关闭按钮设置
|
||||||
isAINoiseReduction: true, //是否开启ai降噪
|
isAINoiseReduction: true, //是否开启ai降噪
|
||||||
aINoiseReduction: 1, // 降噪模式
|
aINoiseReduction: 1, // 降噪模式
|
||||||
|
isRecordingTips: true, //是否开启录制提示
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
if (!storage.getItem('openChildWindow')) {
|
||||||
|
storage.setItem('openChildWindow', JSON.stringify({}))
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isState) {
|
if (isState) {
|
||||||
setIsState(false)
|
setIsState(false)
|
||||||
window.electron.onQuit(async () => {
|
window.electron.onQuit(async () => {
|
||||||
if (location.hash.indexOf('/login') === 1) {
|
if (location.hash.indexOf('/login') === 1) {
|
||||||
window.electron.quit()
|
window.electron.quit(location.hash.indexOf('/meeting') === -1)
|
||||||
} else {
|
} else {
|
||||||
if (storage.getItem('isTips') === 'true') {
|
if (storage.getItem('isTips') === 'true') {
|
||||||
const setting = JSON.parse(storage.getItem('setting') as string)
|
const setting = JSON.parse(storage.getItem('setting') as string)
|
||||||
if (setting.closeSetting === 'hide') {
|
if (setting.closeSetting === 'hide') {
|
||||||
window.electron.setViewStatus(setting.closeSetting)
|
window.electron.setViewStatus(setting.closeSetting)
|
||||||
} else {
|
} else {
|
||||||
window.electron.quit()
|
window.electron.quit(location.hash.indexOf('/meeting') === -1)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quitTipsRef.current.changeModal()
|
quitTipsRef.current.changeModal()
|
||||||
|
|
@ -208,6 +234,20 @@ const App: React.FC = () => {
|
||||||
};
|
};
|
||||||
const leaveChannel = async (bool?: boolean): Promise<void> => {
|
const leaveChannel = async (bool?: boolean): Promise<void> => {
|
||||||
if (location.hash.indexOf('/meeting') === 1) {
|
if (location.hash.indexOf('/meeting') === 1) {
|
||||||
|
window.electron.closeChildWindow('shareScreenWindow')
|
||||||
|
setKeyOpenChildWindow('shareScreenWindow', false)
|
||||||
|
window.electron.setViewStatus('show')
|
||||||
|
window.electron.getWindowSize().then((res: any) => {
|
||||||
|
window.electron.setMainWindowSize({
|
||||||
|
width: Math.ceil(res.width / 1.5),
|
||||||
|
height: Math.ceil(res.height / 1.3),
|
||||||
|
})
|
||||||
|
window.electron.getIsMaximized().then((b: boolean) => {
|
||||||
|
if (!b) {
|
||||||
|
window.electron.setViewStatus('maximize')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
const data = JSON.parse(localStorage.stateInfo);
|
const data = JSON.parse(localStorage.stateInfo);
|
||||||
if (!bool) {
|
if (!bool) {
|
||||||
await GetLeave({
|
await GetLeave({
|
||||||
|
|
@ -243,6 +283,11 @@ const App: React.FC = () => {
|
||||||
<Route path='/login' element={<Login />} />
|
<Route path='/login' element={<Login />} />
|
||||||
<Route path='/meeting' element={<Meeting />} />
|
<Route path='/meeting' element={<Meeting />} />
|
||||||
<Route path='/shareScreenWindow' element={<ShareScreenWindow />} />
|
<Route path='/shareScreenWindow' element={<ShareScreenWindow />} />
|
||||||
|
<Route path='/userListWindow' element={<UserListWindow />} />
|
||||||
|
<Route path='/chatSmallWindow' element={<ChatSmallWindow />} />
|
||||||
|
<Route path='/chatBigWindow' element={<ChatBigWindow />} />
|
||||||
|
<Route path='/currentSpeakUserWindow' element={<CurrentSpeakUserWindow />} />
|
||||||
|
<Route path='/noticeWindow' element={<NoticeWindow />} />
|
||||||
<Route path='*' element={<NotFound />} />
|
<Route path='*' element={<NotFound />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
<Spin spinning={spinning} fullscreen />
|
<Spin spinning={spinning} fullscreen />
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 430 B |
Binary file not shown.
|
After Width: | Height: | Size: 349 B |
|
|
@ -1,15 +1,21 @@
|
||||||
import styles from '@/components/EquipmentManagement/index.module.scss'
|
import styles from '@/components/EquipmentManagement/index.module.scss'
|
||||||
|
import { getKeyOpenChildWindow } from '@/utils/package/public';
|
||||||
import { onInvoke } from '@/utils/package/signalr';
|
import { onInvoke } from '@/utils/package/signalr';
|
||||||
import { Button, Modal, Select, Slider, message } from 'antd';
|
import { Button, Modal, Select, Slider, message } from 'antd';
|
||||||
import { useState, useImperativeHandle, forwardRef } from "react";
|
import { useState, useImperativeHandle, forwardRef } from "react";
|
||||||
const EquipmentManagement = forwardRef((_props: any, ref: any) => {
|
const EquipmentManagement = forwardRef((props: any, ref: any) => {
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
changeModal: async (uid: string, userName: string) => {
|
changeModal: async (uid: string, userName: string) => {
|
||||||
setCallerUid(uid)
|
setCallerUid(uid)
|
||||||
setDeviceInfo({})
|
setDeviceInfo({})
|
||||||
await onInvoke('getDrivers', {
|
let isOpen = await getKeyOpenChildWindow('shareScreenWindow')
|
||||||
uid
|
if (isOpen) {
|
||||||
})
|
props.getDriver?.(uid)
|
||||||
|
} else {
|
||||||
|
await onInvoke('getDrivers', {
|
||||||
|
uid
|
||||||
|
})
|
||||||
|
}
|
||||||
setUserName(userName)
|
setUserName(userName)
|
||||||
setEquipmentManagementModal(true)
|
setEquipmentManagementModal(true)
|
||||||
},
|
},
|
||||||
|
|
@ -21,6 +27,9 @@ const EquipmentManagement = forwardRef((_props: any, ref: any) => {
|
||||||
const [callerUid, setCallerUid] = useState('')
|
const [callerUid, setCallerUid] = useState('')
|
||||||
const [deviceInfo, setDeviceInfo] = useState<any>({})
|
const [deviceInfo, setDeviceInfo] = useState<any>({})
|
||||||
const [userName, setUserName] = useState<any>({})
|
const [userName, setUserName] = useState<any>({})
|
||||||
|
const handleWindowsChange = async (): Promise<void> => {
|
||||||
|
setEquipmentManagementModal(false)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal
|
<Modal
|
||||||
|
|
@ -30,7 +39,7 @@ const EquipmentManagement = forwardRef((_props: any, ref: any) => {
|
||||||
centered
|
centered
|
||||||
width={'500px'}
|
width={'500px'}
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
setEquipmentManagementModal(false)
|
handleWindowsChange()
|
||||||
}}>
|
}}>
|
||||||
<div className={styles.equipmentManagement}>
|
<div className={styles.equipmentManagement}>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -83,16 +92,24 @@ const EquipmentManagement = forwardRef((_props: any, ref: any) => {
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button type="primary" className='m-ant-btn' onClick={async () => {
|
<Button type="primary" className='m-ant-btn' onClick={async () => {
|
||||||
await onInvoke('setDrivers', {
|
let isOpen = await getKeyOpenChildWindow('shareScreenWindow')
|
||||||
uid: callerUid,
|
if (isOpen) {
|
||||||
driversJsonString: JSON.stringify(deviceInfo)
|
props.setDriver?.({
|
||||||
})
|
uid: callerUid,
|
||||||
setEquipmentManagementModal(false)
|
driversJsonString: JSON.stringify(deviceInfo)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await onInvoke('setDrivers', {
|
||||||
|
uid: callerUid,
|
||||||
|
driversJsonString: JSON.stringify(deviceInfo)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
handleWindowsChange()
|
||||||
message.success('设置成功')
|
message.success('设置成功')
|
||||||
}}>确定</Button>
|
}}>确定</Button>
|
||||||
<Button type="primary"
|
<Button type="primary"
|
||||||
style={{ backgroundColor: '#31353A', marginLeft: '10px' }}
|
style={{ backgroundColor: '#31353A', marginLeft: '10px' }}
|
||||||
onClick={() => setEquipmentManagementModal(false)}>取消</Button>
|
onClick={() => handleWindowsChange()}>取消</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal >
|
</Modal >
|
||||||
|
|
|
||||||
|
|
@ -12,20 +12,26 @@ import { role } from '@/config/role';
|
||||||
let time = null as any;
|
let time = null as any;
|
||||||
const JoinSetting = forwardRef((_props: any, ref: any) => {
|
const JoinSetting = forwardRef((_props: any, ref: any) => {
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
changeModal: (roomNum: string = '') => {
|
changeModal: async (roomNum: string = '') => {
|
||||||
let userInfo = JSON.parse(storage.getItem('user') as string)
|
let userInfo = JSON.parse(storage.getItem('user') as string)
|
||||||
setUser(userInfo)
|
setUser(userInfo)
|
||||||
setJoinRoomSettingModal(true)
|
setJoinRoomSettingModal(true)
|
||||||
|
if (location.hash.indexOf('/meeting') === -1) {
|
||||||
|
await agora.init()
|
||||||
|
}
|
||||||
setJoinRoomSettingForm((res: any) => {
|
setJoinRoomSettingForm((res: any) => {
|
||||||
res.forEach((item: any) => {
|
res.forEach(async (item: any, index: number) => {
|
||||||
item.active = false
|
if (index === 0 && role.ID.includes(userInfo.roleId)) {
|
||||||
|
await agora.getAudioMediaList().then(res => {
|
||||||
|
item.active = res.ecordingList.length ? true : false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
item.active = false
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
setRoomNumber(roomNum)
|
setRoomNumber(roomNum)
|
||||||
if (location.hash.indexOf('/meeting') === -1) {
|
|
||||||
agora.init()
|
|
||||||
}
|
|
||||||
getDeviceList()
|
getDeviceList()
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import styles from '@/components/Operation/index.module.scss'
|
import styles from '@/components/Operation/index.module.scss'
|
||||||
import ImageUrl from '@/utils/package/imageUrl';
|
import ImageUrl from '@/utils/package/imageUrl';
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
type OperationKeyType = 'minimize' | 'quit' | 'maximize' | 'unmaximize' | 'hide';
|
type OperationKeyType = 'minimize' | 'quit' | 'maximize' | 'unmaximize' | 'hide' | 'show';
|
||||||
type OperationType = {
|
type OperationType = {
|
||||||
icon: string;
|
icon: string;
|
||||||
key: OperationKeyType;
|
key: OperationKeyType;
|
||||||
|
|
@ -46,7 +46,11 @@ const Operation: React.FC = () => {
|
||||||
key: 'quit',
|
key: 'quit',
|
||||||
title: '关闭',
|
title: '关闭',
|
||||||
onClick: (key: OperationKeyType) => {
|
onClick: (key: OperationKeyType) => {
|
||||||
window.electron.setViewStatus(key)
|
if (location.hash.indexOf('/meeting') === -1) {
|
||||||
|
window.electron.setViewStatus(key)
|
||||||
|
} else {
|
||||||
|
window.electron.quit(false)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
show: true,
|
show: true,
|
||||||
},])
|
},])
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { storage } from '@/utils';
|
||||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||||
import { Button, Checkbox, Modal, Radio } from 'antd';
|
import { Button, Checkbox, Modal, Radio } from 'antd';
|
||||||
import { useState, useImperativeHandle, forwardRef } from "react";
|
import { useState, useImperativeHandle, forwardRef } from "react";
|
||||||
type OperationKeyType = 'minimize' | 'quit' | 'maximize' | 'unmaximize' | 'hide';
|
type OperationKeyType = 'minimize' | 'quit' | 'maximize' | 'unmaximize' | 'hide' | 'show';
|
||||||
const QuitTips = forwardRef((props: any, ref: any) => {
|
const QuitTips = forwardRef((props: any, ref: any) => {
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
changeModal: () => {
|
changeModal: () => {
|
||||||
|
|
@ -52,7 +52,7 @@ const QuitTips = forwardRef((props: any, ref: any) => {
|
||||||
<Button type="primary" className='m-ant-btn' onClick={() => {
|
<Button type="primary" className='m-ant-btn' onClick={() => {
|
||||||
setIsCloseModal(false)
|
setIsCloseModal(false)
|
||||||
if (optionsValue === 'quit') {
|
if (optionsValue === 'quit') {
|
||||||
window.electron.quit()
|
window.electron.quit(location.hash.indexOf('/meeting') === -1)
|
||||||
} else {
|
} else {
|
||||||
window.electron.setViewStatus(optionsValue)
|
window.electron.setViewStatus(optionsValue)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -176,19 +176,23 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.recordingComponents {
|
.recordingComponents {
|
||||||
>span {
|
|
||||||
color: #bfbfbf;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
>div {
|
>div {
|
||||||
display: flex;
|
margin-bottom: 20px;
|
||||||
align-items: center;
|
|
||||||
margin-top: 10px;
|
|
||||||
|
|
||||||
>span {
|
>span {
|
||||||
color: #878787;
|
color: #bfbfbf;
|
||||||
white-space: nowrap;
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
>div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
|
||||||
|
>span {
|
||||||
|
color: #878787;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ const StupWizard = forwardRef((props: any, ref: any) => {
|
||||||
top: '16px',
|
top: '16px',
|
||||||
cursor: 'pointer'
|
cursor: 'pointer'
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
if (location.hash.indexOf('/meeting') === -1) {
|
if (location.hash.indexOf('/meeting') === -1) {
|
||||||
agora.release()
|
agora.release()
|
||||||
}
|
}
|
||||||
|
|
@ -459,6 +459,7 @@ const AudioComponents = () => {
|
||||||
}
|
}
|
||||||
const RecordingComponents = () => {
|
const RecordingComponents = () => {
|
||||||
const [filePath, setFilePath] = useState('')
|
const [filePath, setFilePath] = useState('')
|
||||||
|
const [isRecordingTips, setIsRecordingTips] = useState(false)
|
||||||
const setting = JSON.parse(storage.getItem('setting') as string)
|
const setting = JSON.parse(storage.getItem('setting') as string)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!setting.recordingFilesPath) {
|
if (!setting.recordingFilesPath) {
|
||||||
|
|
@ -467,10 +468,14 @@ const RecordingComponents = () => {
|
||||||
const parentDirectory = path.resolve(currentDirectory, '../../Downloads') + '\\';
|
const parentDirectory = path.resolve(currentDirectory, '../../Downloads') + '\\';
|
||||||
setting.recordingFilesPath = parentDirectory;
|
setting.recordingFilesPath = parentDirectory;
|
||||||
setFilePath(setting.recordingFilesPath)
|
setFilePath(setting.recordingFilesPath)
|
||||||
storage.setItem('setting', JSON.stringify(setting))
|
|
||||||
} else {
|
} else {
|
||||||
setFilePath(setting.recordingFilesPath);
|
setFilePath(setting.recordingFilesPath);
|
||||||
}
|
}
|
||||||
|
if (setting.isRecordingTips === undefined) {
|
||||||
|
setting.isRecordingTips = true;
|
||||||
|
}
|
||||||
|
storage.setItem('setting', JSON.stringify(setting))
|
||||||
|
setIsRecordingTips(setting.isRecordingTips)
|
||||||
window.addEventListener('customStorageChange', handleCustomStorageChange);
|
window.addEventListener('customStorageChange', handleCustomStorageChange);
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('customStorageChange', handleCustomStorageChange);
|
window.removeEventListener('customStorageChange', handleCustomStorageChange);
|
||||||
|
|
@ -487,41 +492,53 @@ const RecordingComponents = () => {
|
||||||
<div>
|
<div>
|
||||||
<span>录制</span>
|
<span>录制</span>
|
||||||
<div className={styles.recordingComponents}>
|
<div className={styles.recordingComponents}>
|
||||||
<span>本地录制</span>
|
|
||||||
<div>
|
<div>
|
||||||
<span>本地录制文件路径</span>
|
<span>本地录制</span>
|
||||||
<Input
|
<div>
|
||||||
disabled={true}
|
<span>本地录制文件路径</span>
|
||||||
placeholder="请填入文件路径"
|
<Input
|
||||||
style={{ margin: '0 14px', flexGrow: 1 }}
|
disabled={true}
|
||||||
value={filePath}
|
placeholder="请填入文件路径"
|
||||||
onChange={async (e) => {
|
style={{ margin: '0 14px', flexGrow: 1 }}
|
||||||
setting.recordingFilesPath = e.target.value;
|
value={filePath}
|
||||||
|
onChange={async (e) => {
|
||||||
|
setting.recordingFilesPath = e.target.value;
|
||||||
|
storage.setItem('setting', JSON.stringify(setting))
|
||||||
|
setFilePath(e.target.value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button type="primary" onClick={() => {
|
||||||
|
window.electron.selectFilePath({
|
||||||
|
key: 'recordingFilesPath',
|
||||||
|
})
|
||||||
|
}} style={{ backgroundColor: '#31353A', marginRight: '10px' }}>选择保存目录</Button>
|
||||||
|
<Button type="primary" onClick={async () => {
|
||||||
|
try {
|
||||||
|
await fs.access(filePath, fs.constants.F_OK);
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
exec(`explorer "${filePath}"`);
|
||||||
|
} else if (process.platform === 'darwin') {
|
||||||
|
exec(`open "${filePath}"`);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.code === 'ENOENT') {
|
||||||
|
message.error('文件夹不存在!')
|
||||||
|
} else {
|
||||||
|
message.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}} style={{ backgroundColor: '#31353A' }}>打开</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>录制设置</span>
|
||||||
|
<div>
|
||||||
|
<Checkbox onChange={async (e) => {
|
||||||
|
setting.isRecordingTips = e.target.checked;
|
||||||
storage.setItem('setting', JSON.stringify(setting))
|
storage.setItem('setting', JSON.stringify(setting))
|
||||||
setFilePath(e.target.value)
|
setIsRecordingTips(e.target.checked)
|
||||||
}}
|
}} checked={isRecordingTips}>开启入会录制提示</Checkbox>
|
||||||
/>
|
</div>
|
||||||
<Button type="primary" onClick={() => {
|
|
||||||
window.electron.selectFilePath({
|
|
||||||
key: 'recordingFilesPath',
|
|
||||||
})
|
|
||||||
}} style={{ backgroundColor: '#31353A', marginRight: '10px' }}>选择保存目录</Button>
|
|
||||||
<Button type="primary" onClick={async () => {
|
|
||||||
try {
|
|
||||||
await fs.access(filePath, fs.constants.F_OK);
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
exec(`explorer "${filePath}"`);
|
|
||||||
} else if (process.platform === 'darwin') {
|
|
||||||
exec(`open "${filePath}"`);
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
if (error.code === 'ENOENT') {
|
|
||||||
message.error('文件夹不存在!')
|
|
||||||
} else {
|
|
||||||
message.error(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}} style={{ backgroundColor: '#31353A' }}>打开</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ const UserVideo: React.FC = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
userList.forEach(async (item: any) => {
|
userList.forEach(async (item: any) => {
|
||||||
await agora.destroyRendererByConfig(Number('1' + item.screenShareId))
|
await agora.destroyRendererByConfig(Number('1' + item.screenShareId), state.channelId + 'a')
|
||||||
await agora.setupRemoteVideoEx({
|
await agora.setupRemoteVideoEx({
|
||||||
uid: Number('1' + item.screenShareId),
|
uid: Number('1' + item.screenShareId),
|
||||||
view: document.getElementById(`video-${item.screenShareId}`),
|
view: document.getElementById(`video-${item.screenShareId}`),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
.chatBigWindow {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px 0;
|
||||||
|
|
||||||
|
.chatBigWindowTitle {
|
||||||
|
background-color: #16191E;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px 10px;
|
||||||
|
|
||||||
|
>span {
|
||||||
|
color: #EEEEEE;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
>img {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatBigWindowContent {
|
||||||
|
flex-grow: 1;
|
||||||
|
height: 0px;
|
||||||
|
overflow-y: auto;
|
||||||
|
background-color: rgb(31, 33, 37);
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.chatBigWindowContentLeft {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
>div:nth-child(1) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
>span {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #F3F3F5;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
>div {}
|
||||||
|
}
|
||||||
|
|
||||||
|
>div:nth-child(2) {
|
||||||
|
background-color: #5575F2;
|
||||||
|
color: #F3F3F5;
|
||||||
|
max-width: 266px;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 0 25px 25px 25px;
|
||||||
|
margin: 10px 0 10px 40px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatBigWindowContentRight {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
>div:nth-child(1) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
|
||||||
|
>span {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #F3F3F5;
|
||||||
|
}
|
||||||
|
|
||||||
|
>div {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
>div:nth-child(2) {
|
||||||
|
background-color: #464E6B;
|
||||||
|
color: #F3F3F5;
|
||||||
|
max-width: 266px;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 25px 0 25px 25px;
|
||||||
|
margin: 10px 40px 10px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatBigWindowButton {
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: rgb(31, 33, 37);
|
||||||
|
|
||||||
|
>button {
|
||||||
|
margin: 4px 4px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatBigWindowInput {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 10px 10px;
|
||||||
|
background-color: #16191E;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatBigWindowInputPopover {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
>button {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,284 @@
|
||||||
|
import styles from '@/page/Meeting/ChatBigWindow/index.module.scss'
|
||||||
|
import ImageUrl from '@/utils/package/imageUrl';
|
||||||
|
import { useEffect, useState, useRef } from "react";
|
||||||
|
import { storage } from '@/utils';
|
||||||
|
import { Button, Input, Modal, Popover } from 'antd';
|
||||||
|
import { role } from '@/config/role';
|
||||||
|
import { GetRoomUserItem } from '@/api/Meeting';
|
||||||
|
import Avatar from '@/components/Avatar';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { ExclamationCircleFilled } from '@ant-design/icons';
|
||||||
|
import EquipmentManagement from '@/components/EquipmentManagement';
|
||||||
|
const { confirm } = Modal;
|
||||||
|
const ChatBigWindow: React.FC = () => {
|
||||||
|
const [inputValue, setInputValue] = useState<string>('')
|
||||||
|
const [chatLists, setChatLists] = useState<any>([])
|
||||||
|
const [user, setUser] = useState<any>({});
|
||||||
|
const [roomUserItem, setRoomUserItem] = useState<any>(null)
|
||||||
|
const [commonlyChatList] = useState<any>([
|
||||||
|
'能听到我说话吗?',
|
||||||
|
'听得到',
|
||||||
|
'听不到',
|
||||||
|
'我要发言',
|
||||||
|
])
|
||||||
|
const equipmentManagementRef = useRef<any>();
|
||||||
|
const userInfo = JSON.parse(storage.getItem('user') as string)
|
||||||
|
const stateInfo = JSON.parse(storage.getItem('stateInfo') as string)
|
||||||
|
const channel = new BroadcastChannel('meeting_channel');
|
||||||
|
useEffect(() => {
|
||||||
|
setUser(userInfo)
|
||||||
|
channel.onmessage = function (event) {
|
||||||
|
const { type, showDriverList } = event.data;
|
||||||
|
switch (type) {
|
||||||
|
case 'showDriverList':
|
||||||
|
equipmentManagementRef.current.setData(showDriverList)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.electron.windowHandleMessageCallBack((_e: any, data: any) => {
|
||||||
|
setChatLists(data.parmes.chatList)
|
||||||
|
})
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'chatBigWindowSendChannelMsg',
|
||||||
|
chatBigWindowSendChannelMsg: {
|
||||||
|
msg: '',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
channel.close();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
const chatBigWindowView = document.getElementById('chatBigWindowView') as HTMLElement;
|
||||||
|
if (chatBigWindowView) {
|
||||||
|
chatBigWindowView.scrollTop = chatBigWindowView.scrollHeight;
|
||||||
|
}
|
||||||
|
}, [chatLists]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={`${styles.chatBigWindow}`}>
|
||||||
|
<div className={styles.chatBigWindowTitle}>
|
||||||
|
<span>聊天</span>
|
||||||
|
<img src={ImageUrl.icon18} className='drag' alt="" onClick={() => {
|
||||||
|
window.electron.setChildWindowShow({
|
||||||
|
key: 'chatBigWindow',
|
||||||
|
})
|
||||||
|
}} />
|
||||||
|
</div>
|
||||||
|
<div className={`${styles.chatBigWindowContent} drag`} id='chatBigWindowView'>
|
||||||
|
{chatLists.map((item: any, index: number) =>
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`${item.uid !== user.uid ? styles.chatBigWindowContentLeft : styles.chatBigWindowContentRight}`}>
|
||||||
|
{role.ID.includes(user.roleId) ? <Popover
|
||||||
|
placement="bottom"
|
||||||
|
title={''}
|
||||||
|
onOpenChange={(e: boolean) => {
|
||||||
|
if (e) {
|
||||||
|
GetRoomUserItem(stateInfo.channelId, item.uid).then((res: any) => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
setRoomUserItem(res.data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setRoomUserItem(null)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
content={
|
||||||
|
roomUserItem ? <div className={styles.chatBigWindowInputPopover}>
|
||||||
|
{roomUserItem.isRoomManager || role.ID.includes(roomUserItem.roleId) ? <Button
|
||||||
|
type="primary"
|
||||||
|
className='m-ant-btn'
|
||||||
|
size={'small'}
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'chatBigWindowSetAllUserLook',
|
||||||
|
chatBigWindowSetAllUserLook: {
|
||||||
|
roomUserItem,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>全员看Ta</Button> : null}
|
||||||
|
{roomUserItem.uid !== user.uid && !role.ID.includes(roomUserItem.roleId) ? <Button
|
||||||
|
type="primary"
|
||||||
|
className='m-ant-btn'
|
||||||
|
size={'small'}
|
||||||
|
onClick={async (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
if (roomUserItem.isRoomManager) {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'chatBigWindowDeleteRoomManager',
|
||||||
|
chatBigWindowDeleteRoomManager: {
|
||||||
|
uid: roomUserItem.uid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'chatBigWindowPostRoomManager',
|
||||||
|
chatBigWindowPostRoomManager: {
|
||||||
|
uid: roomUserItem.uid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await GetRoomUserItem(stateInfo.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();
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'chatBigWindowPostOpenMicr',
|
||||||
|
chatBigWindowPostOpenMicr: {
|
||||||
|
uid: roomUserItem.uid,
|
||||||
|
enableMicr: !roomUserItem.enableMicr
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await GetRoomUserItem(stateInfo.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();
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'chatBigWindowPostOpenCamera',
|
||||||
|
chatBigWindowPostOpenCamera: {
|
||||||
|
uid: roomUserItem.uid,
|
||||||
|
enableMicr: !roomUserItem.enableCamera
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await GetRoomUserItem(stateInfo.channelId, item.uid).then((res: any) => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
setRoomUserItem(res.data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>{roomUserItem.enableCamera ? '关闭视频' : '打开视频'}</Button> : null}
|
||||||
|
{roomUserItem.uid !== user.uid ? <Button
|
||||||
|
type="primary"
|
||||||
|
className='m-ant-btn'
|
||||||
|
size={'small'}
|
||||||
|
onClick={() => {
|
||||||
|
equipmentManagementRef.current.changeModal(item.uid, item.userName)
|
||||||
|
}}
|
||||||
|
>设备管理</Button> : null}
|
||||||
|
{roomUserItem.uid !== user.uid ? <Button
|
||||||
|
type="primary"
|
||||||
|
style={{ backgroundColor: '#EC3C3C' }}
|
||||||
|
size={'small'}
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
confirm({
|
||||||
|
title: '移出会议',
|
||||||
|
icon: <ExclamationCircleFilled />,
|
||||||
|
content: `确定将用户${item.userName}移出会议?`,
|
||||||
|
centered: true,
|
||||||
|
okText: '确定',
|
||||||
|
cancelText: '取消',
|
||||||
|
async onOk() {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'chatBigWindowGetRoomKickout',
|
||||||
|
chatBigWindowGetRoomKickout: {
|
||||||
|
uid: item.uid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>移出会议</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>
|
||||||
|
}
|
||||||
|
</div>}
|
||||||
|
<div>{item.message}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={`${styles.chatBigWindowButton} drag`}>
|
||||||
|
{
|
||||||
|
commonlyChatList.map((item: string, index: number) => {
|
||||||
|
return <Button
|
||||||
|
key={index}
|
||||||
|
type="primary"
|
||||||
|
className='m-ant-btn'
|
||||||
|
onClick={() => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'chatBigWindowSendChannelMsg',
|
||||||
|
chatBigWindowSendChannelMsg: {
|
||||||
|
msg: item,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>{item}</Button>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className={`${styles.chatBigWindowInput} drag`}>
|
||||||
|
<Input.TextArea
|
||||||
|
placeholder="请输入内容"
|
||||||
|
style={{ flexGrow: 1 }}
|
||||||
|
value={inputValue}
|
||||||
|
onChange={(e) => {
|
||||||
|
setInputValue(e.target.value)
|
||||||
|
}}
|
||||||
|
autoSize={{ minRows: 3, maxRows: 3 }} />
|
||||||
|
<Button type="primary" className='m-ant-btn' style={{ flexShrink: 0, marginTop: '4px' }} onClick={() => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'chatBigWindowSendChannelMsg',
|
||||||
|
chatBigWindowSendChannelMsg: {
|
||||||
|
msg: inputValue,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setInputValue('')
|
||||||
|
}}>发送</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<EquipmentManagement ref={equipmentManagementRef} getDriver={(uid: string) => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'userListWindowEquipmentManagement',
|
||||||
|
userListWindowEquipmentManagement: {
|
||||||
|
uid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}} setDriver={(data: any) => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'userListWindowSetEquipmentManagement',
|
||||||
|
userListWindowSetEquipmentManagement: data
|
||||||
|
});
|
||||||
|
}} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChatBigWindow
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
.chatSmallWindow {
|
||||||
|
color: white;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
>div:nth-child(1) {
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow-y: hidden;
|
||||||
|
max-height: 80%;
|
||||||
|
padding: 0 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
background-color: rgba(40, 40, 44, .4);
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
|
||||||
|
.chatSmallWindowContentLeft {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
background-color: #1e232baf;
|
||||||
|
padding: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 0 15px 15px 15px;
|
||||||
|
margin: 0 0 4px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
>span:nth-child(1) {
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #ff970f;
|
||||||
|
}
|
||||||
|
|
||||||
|
>span:nth-child(2) {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatSmallWindowContentRight {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
background-color: #464e6b55;
|
||||||
|
color: black;
|
||||||
|
padding: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 15px 0 15px 15px;
|
||||||
|
margin: 0 0 4px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
|
||||||
|
>span:nth-child(1) {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
>div:nth-child(2) {
|
||||||
|
flex-shrink: 0;
|
||||||
|
opacity: 0.4;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
>div:nth-child(3) {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 0px;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: rgba(40, 40, 44, .2);
|
||||||
|
padding: 0 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(40, 40, 44, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
>span {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
import styles from '@/page/Meeting/ChatSmallWindow/index.module.scss'
|
||||||
|
import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons';
|
||||||
|
import { Input } from 'antd';
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
const ChatSmallWindow: React.FC = () => {
|
||||||
|
const [inputValue, setInputValue] = useState<string>('')
|
||||||
|
const [chatLists, setChatLists] = useState<any>([])
|
||||||
|
const [isExpand, setIsExpand] = useState(false)
|
||||||
|
const channel = new BroadcastChannel('meeting_channel');
|
||||||
|
useEffect(() => {
|
||||||
|
window.electron.windowHandleMessageCallBack((_e: any, data: any) => {
|
||||||
|
setChatLists((newChatList: any) => {
|
||||||
|
data.parmes.chatListIten.timer = setTimeout(() => {
|
||||||
|
removeItemByIndex();
|
||||||
|
}, 10000);
|
||||||
|
return [data.parmes.chatListIten, ...newChatList]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
channel.close();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
const chatSmallWindowView = document.getElementById('chatSmallWindowView') as HTMLElement;
|
||||||
|
if (chatSmallWindowView) {
|
||||||
|
chatSmallWindowView.scrollTop = chatSmallWindowView.scrollHeight;
|
||||||
|
}
|
||||||
|
}, [chatLists]);
|
||||||
|
const removeItemByIndex = () => {
|
||||||
|
setChatLists((res: any) => {
|
||||||
|
return res.slice(0, -1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.chatSmallWindow}>
|
||||||
|
<div id='chatSmallWindowView'>
|
||||||
|
{chatLists.map((item: any, index: number) =>
|
||||||
|
<div className={`${styles.chatSmallWindowContentLeft}`} key={index}>
|
||||||
|
<div>
|
||||||
|
<span>{item.userName}:</span>
|
||||||
|
<span>{item.message}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='drag'>
|
||||||
|
<Input
|
||||||
|
placeholder="请输入内容"
|
||||||
|
style={{ flexGrow: 1 }}
|
||||||
|
value={inputValue}
|
||||||
|
onChange={(e) => {
|
||||||
|
setInputValue(e.target.value)
|
||||||
|
}}
|
||||||
|
onPressEnter={() => {
|
||||||
|
if (inputValue) {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'chatSmallWindowSendChannelMsg',
|
||||||
|
chatSmallWindowSendChannelMsg: {
|
||||||
|
msg: inputValue,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setInputValue('')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
suffix={
|
||||||
|
<span
|
||||||
|
style={{ color: '#47D3D0', cursor: 'pointer' }}
|
||||||
|
onClick={() => {
|
||||||
|
if (inputValue) {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'chatSmallWindowSendChannelMsg',
|
||||||
|
chatSmallWindowSendChannelMsg: {
|
||||||
|
msg: inputValue,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setInputValue('')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>发送
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={`drag`} onClick={() => {
|
||||||
|
setIsExpand(!isExpand)
|
||||||
|
window.electron.setChildWindow({
|
||||||
|
height: isExpand ? 150 : 150 / 2,
|
||||||
|
key: 'chatSmallWindow',
|
||||||
|
})
|
||||||
|
}}>
|
||||||
|
<span>{isExpand ? '展开' : '收起'}</span>
|
||||||
|
{isExpand ? <CaretDownOutlined /> : <CaretUpOutlined />}
|
||||||
|
</div>
|
||||||
|
</div >
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChatSmallWindow
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
.currentSpeakUserWindow {
|
||||||
|
color: white;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #16191E;
|
||||||
|
padding: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
max-width: 100%;
|
||||||
|
width: fit-content;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import styles from '@/page/Meeting/CurrentSpeakUserWindow/index.module.scss'
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
const CurrentSpeakUserWindow: React.FC = () => {
|
||||||
|
const [inputValue, setInputValue] = useState('')
|
||||||
|
const channel = new BroadcastChannel('meeting_channel');
|
||||||
|
useEffect(() => {
|
||||||
|
let time: NodeJS.Timeout;
|
||||||
|
time = setInterval(() => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'currentSpeakUserWindowGetUserName'
|
||||||
|
})
|
||||||
|
}, 1000)
|
||||||
|
window.electron.windowHandleMessageCallBack((_e: any, data: any) => {
|
||||||
|
if (data.parmes.currentSpeakUser.length) {
|
||||||
|
setInputValue(data.parmes.currentSpeakUser.join(';'))
|
||||||
|
} else {
|
||||||
|
setInputValue('')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
clearInterval(time)
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.currentSpeakUserWindow}>
|
||||||
|
<div title={`正在说话: ${inputValue}`}>
|
||||||
|
{`正在说话: ${inputValue}`}
|
||||||
|
</div>
|
||||||
|
</div >
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CurrentSpeakUserWindow
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
.noticeWindow {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
import styles from '@/page/Meeting/NoticeWindow/index.module.scss'
|
||||||
|
import { Button, notification } from 'antd';
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
const NoticeWindow: React.FC = () => {
|
||||||
|
const [api, contextHolder] = notification.useNotification({
|
||||||
|
stack: {
|
||||||
|
threshold: 3
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const channel = new BroadcastChannel('meeting_channel');
|
||||||
|
useEffect(() => {
|
||||||
|
window.electron.setChildWindowShow({
|
||||||
|
key: 'noticeWindow',
|
||||||
|
bool: false
|
||||||
|
})
|
||||||
|
channel.onmessage = function (event) {
|
||||||
|
const { type, noticeItem } = event.data;
|
||||||
|
switch (type) {
|
||||||
|
case 'noticeItem':
|
||||||
|
api.open({
|
||||||
|
message: '',
|
||||||
|
description: <div>
|
||||||
|
<span style={{ fontSize: '16px' }}>{noticeItem.uname}申请发言</span>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
className='m-ant-btn'
|
||||||
|
onClick={async (e: any) => {
|
||||||
|
let i = e.nativeEvent.path;
|
||||||
|
if (i) {
|
||||||
|
i.forEach((i: any) => {
|
||||||
|
if (i.className === 'ant-notification-notice ant-notification-notice-closable') {
|
||||||
|
i.childNodes.forEach((row: any) => {
|
||||||
|
if (row.className === 'ant-notification-notice-close') {
|
||||||
|
row.click()
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'noticeWindowPostRoomManager',
|
||||||
|
noticeWindowPostRoomManager: {
|
||||||
|
uid: noticeItem.uid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>接受</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={(e: any) => {
|
||||||
|
let item = e.nativeEvent.path;
|
||||||
|
if (item) {
|
||||||
|
item.forEach((item: any) => {
|
||||||
|
if (item.className === 'ant-notification-notice ant-notification-notice-closable') {
|
||||||
|
item.childNodes.forEach((row: any) => {
|
||||||
|
if (row.className === 'ant-notification-notice-close') {
|
||||||
|
row.click()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{ backgroundColor: '#EC3C3C', marginLeft: '14px' }}
|
||||||
|
>拒绝</Button>
|
||||||
|
</div>
|
||||||
|
</div>,
|
||||||
|
onClose: () => {
|
||||||
|
const dom = document.getElementsByClassName('ant-notification')
|
||||||
|
if (dom.length === 0) {
|
||||||
|
window.electron.setChildWindowShow({
|
||||||
|
key: 'noticeWindow',
|
||||||
|
bool: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
duration: 10,
|
||||||
|
placement: 'bottomRight',
|
||||||
|
showProgress: true,
|
||||||
|
pauseOnHover: false,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
channel.close();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={`${styles.noticeWindow} drag`}>
|
||||||
|
{contextHolder}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NoticeWindow
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
.shareScreenWindow {
|
||||||
|
color: white;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.shareScreenWindowTitle {
|
||||||
|
font-size: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: lighten(#07090B, 4%);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
>span:nth-child(2) {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #FF5219;
|
||||||
|
padding: 1px 10px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shareScreenWindowContent {
|
||||||
|
flex-grow: 1;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background-color: #07090B;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.shareScreenWindowContentList {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
width: calc(100% / 6);
|
||||||
|
|
||||||
|
>div {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
>img {
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
>div {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: bottom center;
|
||||||
|
background-size: cover;
|
||||||
|
width: 100%;
|
||||||
|
height: 0%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
>span {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shareScreenWindowExpand {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: lighten(#07090B, 4%);
|
||||||
|
padding: 0 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
>span {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
import { GetRoomUser } from '@/api/Meeting';
|
||||||
|
import { role } from '@/config/role';
|
||||||
|
import styles from '@/page/Meeting/ShareScreenWindow/index.module.scss'
|
||||||
|
import { storage } from '@/utils';
|
||||||
|
import ImageUrl from '@/utils/package/imageUrl';
|
||||||
|
import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons';
|
||||||
|
import { Button } from 'antd';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
const ShareScreenWindow: React.FC = () => {
|
||||||
|
const [footerLists, setFooterLists] = useState<any>([
|
||||||
|
{
|
||||||
|
title: '静音',
|
||||||
|
icon: ImageUrl.icon22,
|
||||||
|
iconActive: ImageUrl.icon22Active,
|
||||||
|
active: false,
|
||||||
|
select: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '关闭视频',
|
||||||
|
icon: ImageUrl.icon23,
|
||||||
|
iconActive: ImageUrl.icon23Active,
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '录制',
|
||||||
|
icon: ImageUrl.icon27,
|
||||||
|
iconSelect: ImageUrl.icon27Select,
|
||||||
|
iconActive: ImageUrl.icon27Active,
|
||||||
|
active: false,
|
||||||
|
select: false,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const [timeStr, setTimeStr] = useState(0)
|
||||||
|
const [isExpand, setIsExpand] = useState(false)
|
||||||
|
const [roomUserLists, setRoomUserLists] = useState<any>([])
|
||||||
|
const channel = new BroadcastChannel('meeting_channel');
|
||||||
|
const userInfo = JSON.parse(storage.getItem('user') as string)
|
||||||
|
let timeout: NodeJS.Timeout;
|
||||||
|
useEffect(() => {
|
||||||
|
getRoomUser()
|
||||||
|
channel.onmessage = function (event) {
|
||||||
|
let { type, time } = event.data;
|
||||||
|
switch (type) {
|
||||||
|
case 'time':
|
||||||
|
setTimeStr(time)
|
||||||
|
timeout = setInterval(() => {
|
||||||
|
setTimeStr(time++)
|
||||||
|
}, 1000)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'shareScreenWindowGetTime'
|
||||||
|
});
|
||||||
|
window.electron.windowHandleMessageCallBack((_e: any, data: any) => {
|
||||||
|
switch (data.parmes.type) {
|
||||||
|
case 'currentSpeakUserMe':
|
||||||
|
let domMe = document.getElementById(`micr-item-${userInfo.uid}`) as HTMLDivElement;
|
||||||
|
if (domMe) {
|
||||||
|
domMe.style.height = `${data.parmes.currentSpeakUserMe}%`
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'footerList':
|
||||||
|
const footerListTemplate = [...footerLists];
|
||||||
|
footerListTemplate[0].title = data.parmes.footerList[0][0].active ? '解除静音' : '静音';
|
||||||
|
footerListTemplate[0].active = data.parmes.footerList[0][0].active;
|
||||||
|
footerListTemplate[1].title = data.parmes.footerList[0][1].active ? '开启视频' : '关闭视频';
|
||||||
|
footerListTemplate[1].active = data.parmes.footerList[0][1].active;
|
||||||
|
footerListTemplate[4].title = data.parmes.footerList[1][3].active ? '录制中' : '录制';
|
||||||
|
footerListTemplate[4].active = data.parmes.footerList[1][3].active;
|
||||||
|
setFooterLists(footerListTemplate)
|
||||||
|
break;
|
||||||
|
case 'roomUserList':
|
||||||
|
setRoomUserLists(data.parmes.roomUserList)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
clearInterval(timeout)
|
||||||
|
channel.close();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
const changeCurrentSeconds = (time: number): string => {
|
||||||
|
const duration = dayjs.duration(time, 'seconds');
|
||||||
|
const hours = duration.hours(); // 整数小时
|
||||||
|
const minutes = duration.minutes(); // 整数分钟
|
||||||
|
const secondsRemaining = duration.seconds(); // 剩余的秒数
|
||||||
|
return `${hours > 9 ? hours : '0' + hours}:${minutes > 9 ? minutes : '0' + minutes}:${secondsRemaining > 9 ? secondsRemaining : '0' + secondsRemaining}`
|
||||||
|
}
|
||||||
|
// 获取房间用户
|
||||||
|
const getRoomUser = async (): Promise<void> => {
|
||||||
|
const data = JSON.parse(storage.getItem('stateInfo') as string)
|
||||||
|
await GetRoomUser(data.channelId).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
res.data.forEach((item: any) => {
|
||||||
|
item.isShow = true;
|
||||||
|
item.isRoom = true;
|
||||||
|
item.isAdmin = role.ID.includes(item.roleId) || item.isRoomManager
|
||||||
|
})
|
||||||
|
setRoomUserLists(res.data)
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'shareScreenWindowGetFooterLists',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 底部按钮点击效果
|
||||||
|
const changeFooterListSelect = (item: any, index: number, bool: boolean): void => {
|
||||||
|
let arr = ['静音', '解除静音', '关闭视频', '开启视频']
|
||||||
|
if (arr.indexOf(item.title) === -1) {
|
||||||
|
const footerListTemplate = [...footerLists]
|
||||||
|
footerListTemplate[index].select = bool;
|
||||||
|
setFooterLists(footerListTemplate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.shareScreenWindow} style={{ width: isExpand ? '100%' : '100%' }}>
|
||||||
|
<div className={styles.shareScreenWindowTitle}>
|
||||||
|
<span>{changeCurrentSeconds(timeStr)} 共享中</span>
|
||||||
|
{isExpand ? <span className='drag' onClick={() => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'shareScreenWindowClose',
|
||||||
|
shareScreenWindowClose: timeStr
|
||||||
|
});
|
||||||
|
}}>结束共享</span> : <span style={{ visibility: 'hidden' }}>结束共享</span>}
|
||||||
|
</div>
|
||||||
|
{isExpand ? null : <div className={`${styles.shareScreenWindowContent} drag`}>
|
||||||
|
<div className={styles.shareScreenWindowContentList}>
|
||||||
|
{footerLists.map((item: any, index: number) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onMouseDown={() => changeFooterListSelect(item, index, true)}
|
||||||
|
onMouseUp={() => changeFooterListSelect(item, index, false)}
|
||||||
|
onMouseLeave={() => changeFooterListSelect(item, index, false)}
|
||||||
|
onClick={async () => {
|
||||||
|
switch (item.title) {
|
||||||
|
case '静音':
|
||||||
|
case '解除静音':
|
||||||
|
case '关闭视频':
|
||||||
|
case '开启视频':
|
||||||
|
case '录制':
|
||||||
|
case '录制中':
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'shareScreenWindowfooterListsTitle',
|
||||||
|
shareScreenWindowfooterListsTitle: item.title
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case '聊天':
|
||||||
|
window.electron.setChildWindowShow({
|
||||||
|
key: 'chatBigWindow',
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case '成员':
|
||||||
|
window.electron.setChildWindowShow({
|
||||||
|
key: 'userListWindow',
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
key={index}>
|
||||||
|
<div>
|
||||||
|
{!item.active ? <div style={{ backgroundImage: `url(${ImageUrl.icon49})` }} id={`micr-item-${userInfo.uid}`}>
|
||||||
|
</div> : ''}
|
||||||
|
{item.select ? <img src={item.iconSelect} alt="" /> : <img src={item.active ? item.iconActive : item.icon} alt="" />}
|
||||||
|
</div>
|
||||||
|
<span>{item.title}{item.title === '成员' ? `(${roomUserLists.filter((item: any) => item.isRoom).length})` : ''}</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<Button type="primary" style={{ backgroundColor: '#FF5219', marginRight: '14px' }} size={'small'} onClick={() => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'shareScreenWindowClose',
|
||||||
|
shareScreenWindowClose: timeStr
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
结束共享
|
||||||
|
</Button>
|
||||||
|
</div>}
|
||||||
|
<div className={`${styles.shareScreenWindowExpand} drag`} onClick={() => {
|
||||||
|
setIsExpand(!isExpand)
|
||||||
|
window.electron.setChildWindow({
|
||||||
|
width: isExpand ? 440 : 440 / 2,
|
||||||
|
key: 'shareScreenWindow',
|
||||||
|
})
|
||||||
|
}}>
|
||||||
|
<span>{isExpand ? '展开' : '收起'}</span>
|
||||||
|
{isExpand ? <CaretDownOutlined /> : <CaretUpOutlined />}
|
||||||
|
</div>
|
||||||
|
</div >
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ShareScreenWindow
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
.userListWindow {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #16191E;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px 0;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.userListWindowTitle {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
|
>span {
|
||||||
|
color: #EEEEEE;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
>img {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.userListWindowContent {
|
||||||
|
flex-grow: 1;
|
||||||
|
height: 0px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 4px 10px;
|
||||||
|
|
||||||
|
>div:nth-child(1) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
>span {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #F3F3F5;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
>div {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
>div:nth-child(2) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
>img {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgb(52, 52, 52);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.userListWindowFooter {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #31353A;
|
||||||
|
color: #EEEEEE;
|
||||||
|
width: 104px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten(#31353A, 4%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: darken(#31353A, 4%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
import { role } from '@/config/role';
|
||||||
|
import styles from '@/page/Meeting/UserListWindow/index.module.scss'
|
||||||
|
import ImageUrl from '@/utils/package/imageUrl';
|
||||||
|
import { EllipsisOutlined, ExclamationCircleFilled, SearchOutlined } from '@ant-design/icons';
|
||||||
|
import { Button, Input, Modal, Popover } from 'antd';
|
||||||
|
import Avatar from '@/components/Avatar';
|
||||||
|
import { useEffect, useState, useRef } from "react";
|
||||||
|
import { storage } from '@/utils';
|
||||||
|
import EquipmentManagement from '@/components/EquipmentManagement';
|
||||||
|
const { confirm } = Modal;
|
||||||
|
|
||||||
|
const UserListWindow: React.FC = () => {
|
||||||
|
const [userSearchValue, setUserSearchValue] = useState('')
|
||||||
|
const [user, setUser] = useState<any>({});
|
||||||
|
const [roomUserList, setRoomUserList] = useState<any>([])
|
||||||
|
const equipmentManagementRef = useRef<any>();
|
||||||
|
const channel = new BroadcastChannel('meeting_channel');
|
||||||
|
const userInfo = JSON.parse(storage.getItem('user') as string)
|
||||||
|
useEffect(() => {
|
||||||
|
setUser(userInfo)
|
||||||
|
channel.onmessage = function (event) {
|
||||||
|
const { type, showDriverList } = event.data;
|
||||||
|
switch (type) {
|
||||||
|
case 'showDriverList':
|
||||||
|
equipmentManagementRef.current.setData(showDriverList)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'userListWindowGetRoomUserList'
|
||||||
|
});
|
||||||
|
window.electron.windowHandleMessageCallBack((_e: any, data: any) => {
|
||||||
|
switch (data.parmes.type) {
|
||||||
|
case 'roomUserList':
|
||||||
|
setRoomUserList(data.parmes.roomUserList)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
channel.close();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={`${styles.userListWindow}`}>
|
||||||
|
<div className={styles.userListWindowTitle}>
|
||||||
|
<span>成员列表</span>
|
||||||
|
<img src={ImageUrl.icon18} className='drag' alt="" onClick={() => {
|
||||||
|
window.electron.setChildWindowShow({
|
||||||
|
key: 'userListWindow',
|
||||||
|
})
|
||||||
|
}} />
|
||||||
|
</div>
|
||||||
|
<div className='drag' style={{ padding: '0 10px' }}>
|
||||||
|
<Input
|
||||||
|
placeholder="请输入用户名"
|
||||||
|
prefix={<SearchOutlined style={{ color: 'white' }} />}
|
||||||
|
value={userSearchValue}
|
||||||
|
onChange={(e) => {
|
||||||
|
setUserSearchValue(e.target.value)
|
||||||
|
const newRoomUserList = [...roomUserList]
|
||||||
|
newRoomUserList.forEach(row => {
|
||||||
|
if (e.target.value) {
|
||||||
|
if (row.userName.indexOf(e.target.value) !== -1) {
|
||||||
|
row.isShow = true;
|
||||||
|
} else {
|
||||||
|
row.isShow = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
row.isShow = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setRoomUserList(newRoomUserList)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={`${styles.userListWindowContent} drag`}>
|
||||||
|
{roomUserList.map((item: any, index: number) => {
|
||||||
|
return (
|
||||||
|
item.isShow && item.isRoom ? <div key={index + item.uid}>
|
||||||
|
<div>
|
||||||
|
<div><Avatar name={item.userName} /></div>
|
||||||
|
<span>
|
||||||
|
{item.userName}{item.uid === user.uid ? '(我)' : ''}
|
||||||
|
{role.ID.includes(item.roleId) || item.isRoomManager ?
|
||||||
|
<span style={{ color: '#02B188', marginLeft: '4px' }}>
|
||||||
|
{role.ID.includes(item.roleId) ? '管理员' : '发言人'}
|
||||||
|
</span>
|
||||||
|
: null}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{role.ID.includes(item.roleId) || item.isRoomManager ? <div>
|
||||||
|
<img src={item.enableMicr ? ImageUrl.icon22 : ImageUrl.icon22Active} alt="" onClick={() => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'userListWindowPostOpenMicr',
|
||||||
|
userListWindowPostOpenMicr: {
|
||||||
|
enableMicr: !item.enableMicr,
|
||||||
|
uid: item.uid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}} title={item.enableMicr ? '静音' : '解除静音'} />
|
||||||
|
</div> : null}
|
||||||
|
{role.ID.includes(item.roleId) || item.isRoomManager ? <div>
|
||||||
|
<img src={item.enableCamera ? ImageUrl.icon23 : ImageUrl.icon23Active} alt="" onClick={() => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'userListWindowPostOpenCamera',
|
||||||
|
userListWindowPostOpenCamera: {
|
||||||
|
enableCamera: !item.enableCamera,
|
||||||
|
uid: item.uid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}} title={item.enableCamera ? '关闭视频' : '开启视频'} />
|
||||||
|
</div> : null}
|
||||||
|
{item.uid !== user.uid && role.ID.includes(user.roleId) ? <div>
|
||||||
|
<Popover placement="left" title={''} content={
|
||||||
|
<div style={{ width: '100px' }}>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
className='m-ant-btn'
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
size={'small'}
|
||||||
|
onClick={() => {
|
||||||
|
equipmentManagementRef.current.changeModal(item.uid, item.userName)
|
||||||
|
}}
|
||||||
|
>设备管理</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
style={{ backgroundColor: '#EC3C3C', width: '100%', marginTop: '10px' }}
|
||||||
|
size={'small'}
|
||||||
|
onClick={() => {
|
||||||
|
confirm({
|
||||||
|
title: '移出会议',
|
||||||
|
icon: <ExclamationCircleFilled />,
|
||||||
|
content: `确定将用户${item.userName}移出会议?`,
|
||||||
|
centered: true,
|
||||||
|
okText: '确定',
|
||||||
|
cancelText: '取消',
|
||||||
|
async onOk() {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'userListWindowGetRoomKickout',
|
||||||
|
userListWindowGetRoomKickout: {
|
||||||
|
uid: item.uid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>移出会议</Button>
|
||||||
|
</div>
|
||||||
|
}>
|
||||||
|
<EllipsisOutlined style={{
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: '20px'
|
||||||
|
}} />
|
||||||
|
</Popover>
|
||||||
|
</div> : null}
|
||||||
|
{item.uid !== user.uid && !role.ID.includes(item.roleId) && role.ID.includes(user.roleId) ? <div onClick={() => {
|
||||||
|
if (item.isRoomManager) {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'userListWindowDeleteRoomManager',
|
||||||
|
userListWindowDeleteRoomManager: {
|
||||||
|
uid: item.uid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'userListWindowPostRoomManager',
|
||||||
|
userListWindowPostRoomManager: {
|
||||||
|
uid: item.uid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{!item.isRoomManager ?
|
||||||
|
<img src={ImageUrl.icon50} alt="" title='允许发言' /> :
|
||||||
|
<img src={ImageUrl.icon51} alt="" title='取消发言' />}
|
||||||
|
</div> : null}
|
||||||
|
</div>
|
||||||
|
</div> : null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={`${styles.userListWindowFooter}`}>
|
||||||
|
<div className='drag' onClick={() => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'userListWindowAllPostOpenMicr'
|
||||||
|
});
|
||||||
|
}}>全员静音</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<EquipmentManagement ref={equipmentManagementRef} getDriver={(uid: string) => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'userListWindowEquipmentManagement',
|
||||||
|
userListWindowEquipmentManagement: {
|
||||||
|
uid
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}} setDriver={(data: any) => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'userListWindowSetEquipmentManagement',
|
||||||
|
userListWindowSetEquipmentManagement: data
|
||||||
|
});
|
||||||
|
}} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserListWindow
|
||||||
|
|
@ -937,6 +937,7 @@
|
||||||
width: 144px;
|
width: 144px;
|
||||||
height: 94px;
|
height: 94px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
border: 5px solid transparent;
|
||||||
|
|
||||||
>img {
|
>img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -953,14 +954,16 @@
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
>div {
|
>div {
|
||||||
border: 1px solid #EBEBEB;
|
border: 5px solid yellow;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.active {
|
.active {
|
||||||
>div {
|
>div {
|
||||||
border: 1px solid #EBEBEB;
|
border: 5px solid yellow;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import { agora } from '@/utils/package/agora'
|
||||||
import { onInvoke, onSignalr, offSignalr } from '@/utils/package/signalr';
|
import { onInvoke, onSignalr, offSignalr } from '@/utils/package/signalr';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import durationPlugin from 'dayjs/plugin/duration';
|
import durationPlugin from 'dayjs/plugin/duration';
|
||||||
import { AudioVolumeInfo, ConnectionChangedReasonType, ConnectionStateType, QualityType, RtcConnection, RtcStats, UserOfflineReasonType, VideoSourceType, VideoStreamType } from 'agora-electron-sdk';
|
import { AudioVolumeInfo, ConnectionChangedReasonType, ConnectionStateType, LocalVideoStreamReason, LocalVideoStreamState, QualityType, RtcConnection, RtcStats, UserOfflineReasonType, VideoSourceType, VideoStreamType } 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';
|
||||||
|
|
@ -22,6 +22,7 @@ import EquipmentManagement from '@/components/EquipmentManagement';
|
||||||
import UserVideo from '@/components/UserVideo';
|
import UserVideo from '@/components/UserVideo';
|
||||||
import { role } from '@/config/role';
|
import { role } from '@/config/role';
|
||||||
import { fixWebmDuration } from "webm-duration-fix-buffer";
|
import { fixWebmDuration } from "webm-duration-fix-buffer";
|
||||||
|
import { getKeyOpenChildWindow, setKeyOpenChildWindow } from '@/utils/package/public';
|
||||||
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;
|
||||||
|
|
@ -41,6 +42,7 @@ const Meeting: React.FC = () => {
|
||||||
userVideo: false,
|
userVideo: false,
|
||||||
})
|
})
|
||||||
const [isSharedScreenModal, setIsSharedScreenModal] = useState(false);
|
const [isSharedScreenModal, setIsSharedScreenModal] = useState(false);
|
||||||
|
const [quitMeetingModal, setQuitMeetingModal] = useState(false);
|
||||||
const [user, setUser] = useState<any>({});
|
const [user, setUser] = useState<any>({});
|
||||||
const [sharedScreenList, setSharedScreenList] = useState<any>([]);
|
const [sharedScreenList, setSharedScreenList] = useState<any>([]);
|
||||||
const [sharedScreenItem, setSharedScreenItem] = useState<any>('');
|
const [sharedScreenItem, setSharedScreenItem] = useState<any>('');
|
||||||
|
|
@ -48,17 +50,17 @@ const Meeting: React.FC = () => {
|
||||||
const [footerList, setFooterList] = useState<any>([
|
const [footerList, setFooterList] = useState<any>([
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
title: '静音',
|
title: '解除静音',
|
||||||
icon: ImageUrl.icon22,
|
icon: ImageUrl.icon22,
|
||||||
iconActive: ImageUrl.icon22Active,
|
iconActive: ImageUrl.icon22Active,
|
||||||
active: false,
|
active: true,
|
||||||
select: false,
|
select: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '关闭视频',
|
title: '开启视频',
|
||||||
icon: ImageUrl.icon23,
|
icon: ImageUrl.icon23,
|
||||||
iconActive: ImageUrl.icon23Active,
|
iconActive: ImageUrl.icon23Active,
|
||||||
active: false,
|
active: true,
|
||||||
select: false,
|
select: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -142,6 +144,7 @@ const Meeting: React.FC = () => {
|
||||||
rowIndex: 0,
|
rowIndex: 0,
|
||||||
});
|
});
|
||||||
const [roomUserList, setRoomUserList] = useState<any>([])
|
const [roomUserList, setRoomUserList] = useState<any>([])
|
||||||
|
const [_speackUid, setSpeackUid] = useState<any>([])
|
||||||
const [chatList, setChatList] = useState<any>([])
|
const [chatList, setChatList] = useState<any>([])
|
||||||
const [currentVideoId, setCurrentVideoId] = useState('')
|
const [currentVideoId, setCurrentVideoId] = useState('')
|
||||||
let [currentSeconds, setCurrentSeconds] = useState(0)
|
let [currentSeconds, setCurrentSeconds] = useState(0)
|
||||||
|
|
@ -151,7 +154,8 @@ const Meeting: React.FC = () => {
|
||||||
text: '网络质量极好。'
|
text: '网络质量极好。'
|
||||||
})
|
})
|
||||||
const [networkOther, setNetworkOther] = useState<RtcStats>({})
|
const [networkOther, setNetworkOther] = useState<RtcStats>({})
|
||||||
const [isComputerAudio, setIsComputerAudio] = useState(true)
|
const [isComputerAudio, setIsComputerAudio] = useState(false)
|
||||||
|
const [_isScreenCapture, setIsScreenCapture] = useState(false)
|
||||||
const [isFluencyPriority, setIsFluencyPriority] = useState(false)
|
const [isFluencyPriority, setIsFluencyPriority] = useState(false)
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const [modeOpen, setModeOpen] = useState(false)
|
const [modeOpen, setModeOpen] = useState(false)
|
||||||
|
|
@ -184,46 +188,265 @@ const Meeting: React.FC = () => {
|
||||||
const [observer, setObserver] = useState<IntersectionObserver>()
|
const [observer, setObserver] = useState<IntersectionObserver>()
|
||||||
let userInfo = JSON.parse(storage.getItem('user') as string)
|
let userInfo = JSON.parse(storage.getItem('user') as string)
|
||||||
const msgTips = '您不是管理员或发言人,无法开启此功能!'
|
const msgTips = '您不是管理员或发言人,无法开启此功能!'
|
||||||
|
const channel = new BroadcastChannel('meeting_channel');
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let time: NodeJS.Timeout;
|
let time: NodeJS.Timeout;
|
||||||
// let getDesktopCapturerVideoTime: NodeJS.Timeout;
|
|
||||||
setUser(userInfo)
|
setUser(userInfo)
|
||||||
window.electron.getIsMaximized().then((res: boolean) => {
|
window.electron.getIsMaximized().then((res: boolean) => {
|
||||||
if (!res) {
|
if (!res) {
|
||||||
window.electron.setViewStatus('maximize')
|
window.electron.setViewStatus('maximize')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
setKeyOpenChildWindow('shareScreenWindow', false)
|
||||||
setMeetingMode('StandardMode');
|
setMeetingMode('StandardMode');
|
||||||
agoraInit()
|
agoraInit()
|
||||||
storage.setItem('noViewChatList', 0)
|
storage.setItem('noViewChatList', 0)
|
||||||
window.addEventListener('customStorageChange', handleCustomStorageChange);
|
window.addEventListener('customStorageChange', handleCustomStorageChange);
|
||||||
const container = document.getElementById('videoView') as HTMLElement;
|
const container = document.getElementById('videoView') as HTMLElement;
|
||||||
container.addEventListener('wheel', handleWheelChange);
|
container.addEventListener('wheel', handleWheelChange);
|
||||||
|
channel.onmessage = async function (event) {
|
||||||
|
const {
|
||||||
|
type,
|
||||||
|
shareScreenWindowfooterListsTitle,
|
||||||
|
shareScreenWindowClose,
|
||||||
|
userListWindowPostOpenMicr,
|
||||||
|
userListWindowPostOpenCamera,
|
||||||
|
userListWindowDeleteRoomManager,
|
||||||
|
userListWindowPostRoomManager,
|
||||||
|
userListWindowGetRoomKickout,
|
||||||
|
userListWindowEquipmentManagement,
|
||||||
|
userListWindowSetEquipmentManagement,
|
||||||
|
chatSmallWindowSendChannelMsg,
|
||||||
|
chatBigWindowSetAllUserLook,
|
||||||
|
chatBigWindowDeleteRoomManager,
|
||||||
|
chatBigWindowPostRoomManager,
|
||||||
|
chatBigWindowPostOpenMicr,
|
||||||
|
chatBigWindowPostOpenCamera,
|
||||||
|
chatBigWindowGetRoomKickout,
|
||||||
|
chatBigWindowSendChannelMsg,
|
||||||
|
noticeWindowPostRoomManager
|
||||||
|
} = event.data;
|
||||||
|
switch (type) {
|
||||||
|
case 'shareScreenWindowGetTime':
|
||||||
|
setCurrentSeconds((res => {
|
||||||
|
channel.postMessage({
|
||||||
|
type: 'time',
|
||||||
|
time: res,
|
||||||
|
});
|
||||||
|
return res
|
||||||
|
}))
|
||||||
|
break;
|
||||||
|
case 'shareScreenWindowClose':
|
||||||
|
setCurrentSeconds(shareScreenWindowClose)
|
||||||
|
await stopScreenCapture()
|
||||||
|
await allUserLook(userInfo.uid, userInfo.userName)
|
||||||
|
break;
|
||||||
|
case 'shareScreenWindowfooterListsTitle':
|
||||||
|
switch (shareScreenWindowfooterListsTitle) {
|
||||||
|
case '静音':
|
||||||
|
case '解除静音':
|
||||||
|
changeStatusList({
|
||||||
|
title: shareScreenWindowfooterListsTitle
|
||||||
|
}, 0, 1)
|
||||||
|
break;
|
||||||
|
case '关闭视频':
|
||||||
|
case '开启视频':
|
||||||
|
changeStatusList({
|
||||||
|
title: shareScreenWindowfooterListsTitle
|
||||||
|
}, 0, 2)
|
||||||
|
break;
|
||||||
|
case '录制':
|
||||||
|
case '录制中':
|
||||||
|
changeStatusList({
|
||||||
|
title: shareScreenWindowfooterListsTitle
|
||||||
|
}, 1, 3)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'shareScreenWindowGetFooterLists':
|
||||||
|
setFooterList((res: any) => {
|
||||||
|
window.electron.windowHandleMessage({
|
||||||
|
key: 'shareScreenWindow',
|
||||||
|
parmes: {
|
||||||
|
footerList: res,
|
||||||
|
type: 'footerList'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'userListWindowEquipmentManagement':
|
||||||
|
await onInvoke('getDrivers', {
|
||||||
|
uid: userListWindowEquipmentManagement.uid,
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'userListWindowSetEquipmentManagement':
|
||||||
|
await onInvoke('setDrivers', {
|
||||||
|
uid: userListWindowSetEquipmentManagement.uid,
|
||||||
|
driversJsonString: userListWindowSetEquipmentManagement.driversJsonString
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'userListWindowPostOpenMicr':
|
||||||
|
postOpenMicr(userListWindowPostOpenMicr.enableMicr, userListWindowPostOpenMicr.uid)
|
||||||
|
break;
|
||||||
|
case 'userListWindowPostOpenCamera':
|
||||||
|
postOpenCamera(userListWindowPostOpenCamera.enableCamera, userListWindowPostOpenCamera.uid)
|
||||||
|
break;
|
||||||
|
case 'userListWindowDeleteRoomManager':
|
||||||
|
DeleteRoomManager({
|
||||||
|
roomId: state.roomId,
|
||||||
|
roomNum: state.channelId,
|
||||||
|
userId: userListWindowDeleteRoomManager.uid
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'userListWindowPostRoomManager':
|
||||||
|
postRoomManager({
|
||||||
|
roomId: state.roomId,
|
||||||
|
roomNum: state.channelId,
|
||||||
|
userId: userListWindowPostRoomManager.uid
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'userListWindowGetRoomUserList':
|
||||||
|
setRoomUserList(((res: any) => {
|
||||||
|
window.electron.windowHandleMessage({
|
||||||
|
key: 'userListWindow',
|
||||||
|
parmes: {
|
||||||
|
roomUserList: res,
|
||||||
|
type: 'roomUserList'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}))
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
case 'userListWindowGetRoomKickout':
|
||||||
|
GetRoomKickout(state.channelId, userListWindowGetRoomKickout.uid)
|
||||||
|
break;
|
||||||
|
case 'userListWindowAllPostOpenMicr':
|
||||||
|
postOpenMicr(false, userInfo.id, true)
|
||||||
|
break;
|
||||||
|
case 'chatSmallWindowSendChannelMsg':
|
||||||
|
sendMsg(chatSmallWindowSendChannelMsg.msg)
|
||||||
|
break;
|
||||||
|
case 'chatBigWindowSetAllUserLook':
|
||||||
|
setAllUserLook(chatBigWindowSetAllUserLook.roomUserItem)
|
||||||
|
break;
|
||||||
|
case 'chatBigWindowDeleteRoomManager':
|
||||||
|
DeleteRoomManager({
|
||||||
|
roomId: state.roomId,
|
||||||
|
roomNum: state.channelId,
|
||||||
|
userId: chatBigWindowDeleteRoomManager.uid
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'chatBigWindowPostRoomManager':
|
||||||
|
postRoomManager({
|
||||||
|
roomId: state.roomId,
|
||||||
|
roomNum: state.channelId,
|
||||||
|
userId: chatBigWindowPostRoomManager.uid
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'chatBigWindowPostOpenMicr':
|
||||||
|
postOpenMicr(chatBigWindowPostOpenMicr.enableMicr, chatBigWindowPostOpenMicr.uid)
|
||||||
|
break;
|
||||||
|
case 'chatBigWindowPostOpenCamera':
|
||||||
|
postOpenCamera(chatBigWindowPostOpenCamera.enableCamera, chatBigWindowPostOpenCamera.uid)
|
||||||
|
break;
|
||||||
|
case 'chatBigWindowGetRoomKickout':
|
||||||
|
GetRoomKickout(state.channelId, chatBigWindowGetRoomKickout.uid)
|
||||||
|
break;
|
||||||
|
case 'chatBigWindowSendChannelMsg':
|
||||||
|
if (chatBigWindowSendChannelMsg.msg) {
|
||||||
|
sendMsg(chatBigWindowSendChannelMsg.msg)
|
||||||
|
} else[
|
||||||
|
setChatList((res: any) => {
|
||||||
|
window.electron.windowHandleMessage({
|
||||||
|
key: 'chatBigWindow',
|
||||||
|
parmes: {
|
||||||
|
chatList: res,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
case 'noticeWindowPostRoomManager':
|
||||||
|
postRoomManager({
|
||||||
|
roomId: state.roomId,
|
||||||
|
roomNum: state.channelId,
|
||||||
|
userId: noticeWindowPostRoomManager.uid
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'currentSpeakUserWindowGetUserName':
|
||||||
|
setSpeackUid((uids: any) => {
|
||||||
|
const usernames: string[] = [];
|
||||||
|
setRoomUserList((res: any) => {
|
||||||
|
uids.forEach((uid: any) => {
|
||||||
|
const user = res.find((item: any) => item.uid == uid);
|
||||||
|
if (user) {
|
||||||
|
usernames.push(user.userName);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
window.electron.windowHandleMessage({
|
||||||
|
key: 'currentSpeakUserWindow',
|
||||||
|
parmes: {
|
||||||
|
currentSpeakUser: usernames,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
});
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
time = setInterval(() => {
|
time = setInterval(() => {
|
||||||
setCurrentSeconds(currentSeconds++)
|
setCurrentSeconds(currentSeconds => {
|
||||||
|
return currentSeconds += 1
|
||||||
|
})
|
||||||
}, 1000)
|
}, 1000)
|
||||||
// getDesktopCapturerVideoTime = setInterval(() => {
|
// 首次加载图标更新
|
||||||
// setSharedScreenItem((i: any) => {
|
const firstFooterList = [...footerList]
|
||||||
// if (i && i.type === 0) {
|
firstFooterList[0][0].title = state.enableMicr ? '静音' : '解除静音'
|
||||||
// agora.getDesktopCapturerVideo({ width: 0, height: 0 }, { width: 0, height: 0 }, false).then(res => {
|
firstFooterList[0][0].active = !state.enableMicr
|
||||||
// if (res.length) {
|
firstFooterList[0][1].title = state.enableCamera ? '关闭视频' : '开启视频'
|
||||||
// let row = res.find((item: any) => item.sourceId === i.sourceId)
|
firstFooterList[0][1].active = !state.enableCamera
|
||||||
// if (!row) {
|
agora.muteLocalVideoStream(userInfo, state.enableMicr, state.enableCamera)
|
||||||
// stopScreenCapture()
|
setFooterList(firstFooterList)
|
||||||
// setSharedScreenItem('')
|
setTimeout(async () => {
|
||||||
// allUserLook(userInfo.uid, userInfo.userName)
|
const setting = await JSON.parse(storage.getItem('setting') as string);
|
||||||
// }
|
const stateInfo = await JSON.parse(storage.getItem('stateInfo') as string);
|
||||||
// }
|
if (stateInfo && setting.isRecordingTips && !recorder) {
|
||||||
// })
|
setRecorder((data: any) => {
|
||||||
// }
|
if (!data) {
|
||||||
// return i
|
confirm({
|
||||||
// })
|
title: '提示',
|
||||||
// }, 3000)
|
icon: <ExclamationCircleFilled />,
|
||||||
|
content: `是否录制本次会议?`,
|
||||||
|
centered: true,
|
||||||
|
okText: '确定',
|
||||||
|
cancelText: '取消',
|
||||||
|
async onOk() {
|
||||||
|
if (stateInfo) {
|
||||||
|
changeStatusList({
|
||||||
|
title: '录制'
|
||||||
|
}, 1, 3)
|
||||||
|
} else {
|
||||||
|
message.error('当前不在会议室!')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('customStorageChange', handleCustomStorageChange);
|
window.removeEventListener('customStorageChange', handleCustomStorageChange);
|
||||||
window.removeEventListener('wheel', handleWheelChange);
|
window.removeEventListener('wheel', handleWheelChange);
|
||||||
clearInterval(time)
|
clearInterval(time)
|
||||||
// clearInterval(getDesktopCapturerVideoTime)
|
channel.close();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
@ -262,6 +485,17 @@ const Meeting: React.FC = () => {
|
||||||
}
|
}
|
||||||
}, [currentEffective]);
|
}, [currentEffective]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (chatList.length) {
|
||||||
|
window.electron.windowHandleMessage({
|
||||||
|
key: 'chatBigWindow',
|
||||||
|
parmes: {
|
||||||
|
chatList,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [chatList]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let currentVideoUserItem = roomUserList.find((item: any) => item.uid === currentVideoId || item.screenShareId === currentVideoId)
|
let currentVideoUserItem = roomUserList.find((item: any) => item.uid === currentVideoId || item.screenShareId === currentVideoId)
|
||||||
if (currentVideoUserItem) {
|
if (currentVideoUserItem) {
|
||||||
|
|
@ -312,6 +546,12 @@ const Meeting: React.FC = () => {
|
||||||
setNoViewChatList(storageNoViewChatList)
|
setNoViewChatList(storageNoViewChatList)
|
||||||
}
|
}
|
||||||
setChatList((newChatList: any) => [...newChatList, item])
|
setChatList((newChatList: any) => [...newChatList, item])
|
||||||
|
window.electron.windowHandleMessage({
|
||||||
|
key: 'chatSmallWindow',
|
||||||
|
parmes: {
|
||||||
|
chatListIten: item,
|
||||||
|
}
|
||||||
|
})
|
||||||
setStatusList((res: any) => {
|
setStatusList((res: any) => {
|
||||||
if (!res.userChatList) {
|
if (!res.userChatList) {
|
||||||
api.open({
|
api.open({
|
||||||
|
|
@ -407,14 +647,14 @@ const Meeting: React.FC = () => {
|
||||||
message.success(`操作成功`)
|
message.success(`操作成功`)
|
||||||
await agora.updateChannelMediaOptions(item.user.isRoomManager)
|
await agora.updateChannelMediaOptions(item.user.isRoomManager)
|
||||||
await postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
|
await postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
|
||||||
await postOpenCameraApi(item.user.isRoomManager, userInfo.uid)
|
await postOpenCameraApi(false, userInfo.uid) // 不管身份如何改变都关闭摄像头
|
||||||
await stopScreenCapture()
|
await stopScreenCapture()
|
||||||
} else {
|
} else {
|
||||||
message.success(`${item.user.userName}已结束发言`)
|
message.success(`${item.user.userName}已结束发言`)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (item.user.uid === userInfo.uid) {
|
if (item.user.uid === userInfo.uid) {
|
||||||
if (!item.user.isRoomManager) {
|
if (item.user.isRoomManager) {
|
||||||
await agora.allLeaveChannelEx()
|
await agora.allLeaveChannelEx()
|
||||||
}
|
}
|
||||||
message.success(`管理员${item.user.isRoomManager ? '设置' : '取消'}您为发言人`)
|
message.success(`管理员${item.user.isRoomManager ? '设置' : '取消'}您为发言人`)
|
||||||
|
|
@ -426,7 +666,7 @@ const Meeting: React.FC = () => {
|
||||||
postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
|
postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
|
||||||
} else {
|
} else {
|
||||||
postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
|
postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
|
||||||
postOpenCameraApi(item.user.isRoomManager, userInfo.uid)
|
postOpenCameraApi(false, userInfo.uid)
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
})
|
})
|
||||||
|
|
@ -440,59 +680,73 @@ const Meeting: React.FC = () => {
|
||||||
break;
|
break;
|
||||||
// 申请发言
|
// 申请发言
|
||||||
case 'ApplyToSpeak':
|
case 'ApplyToSpeak':
|
||||||
api.open({
|
setIsScreenCapture(bool => {
|
||||||
message: '',
|
if (bool) {
|
||||||
description: <div>
|
window.electron.setChildWindowShow({
|
||||||
<span style={{ fontSize: '16px' }}>{item.uname}申请发言</span>
|
key: 'noticeWindow',
|
||||||
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
bool: true
|
||||||
<Button
|
})
|
||||||
type="primary"
|
channel.postMessage({
|
||||||
className='m-ant-btn'
|
type: 'noticeItem',
|
||||||
onClick={async (e: any) => {
|
noticeItem: item
|
||||||
let i = e.nativeEvent.path;
|
});
|
||||||
if (i) {
|
} else {
|
||||||
i.forEach((i: any) => {
|
api.open({
|
||||||
if (i.className === 'ant-notification-notice ant-notification-notice-closable') {
|
message: '',
|
||||||
i.childNodes.forEach((row: any) => {
|
description: <div>
|
||||||
if (row.className === 'ant-notification-notice-close') {
|
<span style={{ fontSize: '16px' }}>{item.uname}申请发言</span>
|
||||||
row.click()
|
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||||
postRoomManager({
|
<Button
|
||||||
roomId: state.roomId,
|
type="primary"
|
||||||
roomNum: state.channelId,
|
className='m-ant-btn'
|
||||||
userId: item.uid
|
onClick={async (e: any) => {
|
||||||
|
let i = e.nativeEvent.path;
|
||||||
|
if (i) {
|
||||||
|
i.forEach((i: any) => {
|
||||||
|
if (i.className === 'ant-notification-notice ant-notification-notice-closable') {
|
||||||
|
i.childNodes.forEach((row: any) => {
|
||||||
|
if (row.className === 'ant-notification-notice-close') {
|
||||||
|
row.click()
|
||||||
|
postRoomManager({
|
||||||
|
roomId: state.roomId,
|
||||||
|
roomNum: state.channelId,
|
||||||
|
userId: item.uid
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
}}
|
||||||
}
|
>接受</Button>
|
||||||
}}
|
<Button
|
||||||
>接受</Button>
|
type="primary"
|
||||||
<Button
|
onClick={(e: any) => {
|
||||||
type="primary"
|
let item = e.nativeEvent.path;
|
||||||
onClick={(e: any) => {
|
if (item) {
|
||||||
let item = e.nativeEvent.path;
|
item.forEach((item: any) => {
|
||||||
if (item) {
|
if (item.className === 'ant-notification-notice ant-notification-notice-closable') {
|
||||||
item.forEach((item: any) => {
|
item.childNodes.forEach((row: any) => {
|
||||||
if (item.className === 'ant-notification-notice ant-notification-notice-closable') {
|
if (row.className === 'ant-notification-notice-close') {
|
||||||
item.childNodes.forEach((row: any) => {
|
row.click()
|
||||||
if (row.className === 'ant-notification-notice-close') {
|
}
|
||||||
row.click()
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
}}
|
||||||
}
|
style={{ backgroundColor: '#EC3C3C', marginLeft: '14px' }}
|
||||||
}}
|
>拒绝</Button>
|
||||||
style={{ backgroundColor: '#EC3C3C', marginLeft: '14px' }}
|
</div>
|
||||||
>拒绝</Button>
|
</div>,
|
||||||
</div>
|
duration: 10,
|
||||||
</div>,
|
placement: 'bottomRight',
|
||||||
duration: 10,
|
showProgress: true,
|
||||||
placement: 'bottomRight',
|
pauseOnHover: false,
|
||||||
showProgress: true,
|
});
|
||||||
pauseOnHover: false,
|
}
|
||||||
});
|
return bool
|
||||||
|
})
|
||||||
break;
|
break;
|
||||||
// 管理员查看随机用户
|
// 管理员查看随机用户
|
||||||
case 'Watch':
|
case 'Watch':
|
||||||
|
|
@ -560,7 +814,12 @@ const Meeting: React.FC = () => {
|
||||||
case 'ShowDriverList':
|
case 'ShowDriverList':
|
||||||
if (item.driversJsonString) {
|
if (item.driversJsonString) {
|
||||||
const data = JSON.parse(item.driversJsonString);
|
const data = JSON.parse(item.driversJsonString);
|
||||||
equipmentManagementRef.current.setData(data)
|
const isOpen = await getKeyOpenChildWindow('shareScreenWindow')
|
||||||
|
if (isOpen) {
|
||||||
|
channel.postMessage({ type: 'showDriverList', showDriverList: data })
|
||||||
|
} else {
|
||||||
|
equipmentManagementRef.current.setData(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -639,6 +898,27 @@ const Meeting: React.FC = () => {
|
||||||
observerObject.observe(element);
|
observerObject.observe(element);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
window.electron.windowHandleMessage({
|
||||||
|
key: 'shareScreenWindow',
|
||||||
|
parmes: {
|
||||||
|
footerList,
|
||||||
|
type: 'footerList'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
window.electron.windowHandleMessage({
|
||||||
|
key: 'shareScreenWindow',
|
||||||
|
parmes: {
|
||||||
|
roomUserList,
|
||||||
|
type: 'roomUserList'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
window.electron.windowHandleMessage({
|
||||||
|
key: 'userListWindow',
|
||||||
|
parmes: {
|
||||||
|
roomUserList,
|
||||||
|
type: 'roomUserList'
|
||||||
|
}
|
||||||
|
})
|
||||||
return () => {
|
return () => {
|
||||||
elements.forEach(element => {
|
elements.forEach(element => {
|
||||||
observer?.unobserve(element);
|
observer?.unobserve(element);
|
||||||
|
|
@ -701,18 +981,30 @@ const Meeting: React.FC = () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onAudioVolumeIndication: async (speakers: AudioVolumeInfo[]) => {
|
onAudioVolumeIndication: async (speakers: AudioVolumeInfo[]) => {
|
||||||
speakers.forEach((item: any) => {
|
if (speakers.length) {
|
||||||
let domMe = document.getElementById(`micr-item-${userInfo.uid}`);
|
setSpeackUid((res: any) => {
|
||||||
let dom = document.getElementById(`micr-${item.uid ? item.uid : userInfo.uid}`);
|
return [...new Set([...res, ...(speakers.filter((item: any) => item.volume)).map(item => item.uid || userInfo.uid)])]
|
||||||
if (dom) {
|
})
|
||||||
const percentage = (item.volume / 255) * 100
|
speakers.forEach((item: any) => {
|
||||||
dom.style.height = `${percentage}%`
|
let domMe = document.getElementById(`micr-item-${userInfo.uid}`);
|
||||||
}
|
let dom = document.getElementById(`micr-${item.uid ? item.uid : userInfo.uid}`);
|
||||||
if (domMe && !item.uid) {
|
if (dom) {
|
||||||
const percentage = (item.volume / 255) * 100
|
const percentage = (item.volume / 255) * 100
|
||||||
domMe.style.height = `${percentage}%`
|
dom.style.height = `${percentage}%`
|
||||||
}
|
}
|
||||||
});
|
if (domMe && !item.uid) {
|
||||||
|
const percentage = (item.volume / 255) * 100
|
||||||
|
domMe.style.height = `${percentage}%`
|
||||||
|
window.electron.windowHandleMessage({
|
||||||
|
key: 'shareScreenWindow',
|
||||||
|
parmes: {
|
||||||
|
currentSpeakUserMe: percentage,
|
||||||
|
type: 'currentSpeakUserMe'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onNetworkQuality: async (_connection: RtcConnection, remoteUid: number, _txQuality: QualityType, rxQuality: QualityType) => {
|
onNetworkQuality: async (_connection: RtcConnection, remoteUid: number, _txQuality: QualityType, rxQuality: QualityType) => {
|
||||||
if (remoteUid === 0) {
|
if (remoteUid === 0) {
|
||||||
|
|
@ -748,6 +1040,18 @@ const Meeting: React.FC = () => {
|
||||||
message.error('网络断开,请检查网络')
|
message.error('网络断开,请检查网络')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onLocalVideoStateChanged: async (_source: VideoSourceType, _state: LocalVideoStreamState, reason: LocalVideoStreamReason) => {
|
||||||
|
if (reason === 12) {
|
||||||
|
setIsScreenCapture(bool => {
|
||||||
|
if (bool) {
|
||||||
|
stopScreenCapture()
|
||||||
|
setSharedScreenItem('')
|
||||||
|
allUserLook(userInfo.uid, userInfo.userName)
|
||||||
|
}
|
||||||
|
return bool
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
if (state.enableCamera) {
|
if (state.enableCamera) {
|
||||||
await agora.startCameraCapture()
|
await agora.startCameraCapture()
|
||||||
|
|
@ -847,8 +1151,19 @@ const Meeting: React.FC = () => {
|
||||||
setRoomUserList((res: any) => {
|
setRoomUserList((res: any) => {
|
||||||
let userItem = res.find((row: any) => row.uid === item.user.uid)
|
let userItem = res.find((row: any) => row.uid === item.user.uid)
|
||||||
if (userItem) {
|
if (userItem) {
|
||||||
for (const key in item.user) {
|
for (const keys in item.user) {
|
||||||
userItem[key] = item.user[key];
|
if (keys !== 'enableCamera' && keys !== 'enableMicr') {
|
||||||
|
userItem[keys] = item.user[keys];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key === 'OperCamera') {
|
||||||
|
userItem.enableCamera = item.user.enableCamera;
|
||||||
|
if (userItem.uid === userInfo.uid) {
|
||||||
|
userItem.enableCamera ? agora.startCameraCapture() : agora.stopCameraCapture()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key === 'OperMicr') {
|
||||||
|
userItem.enableMicr = item.user.enableMicr;
|
||||||
}
|
}
|
||||||
userItem.isAdmin = role.ID.includes(item.user.roleId) || item.user.isRoomManager;
|
userItem.isAdmin = role.ID.includes(item.user.roleId) || item.user.isRoomManager;
|
||||||
refreshVideoView(userItem)
|
refreshVideoView(userItem)
|
||||||
|
|
@ -1075,12 +1390,12 @@ const Meeting: React.FC = () => {
|
||||||
await allUserLook(userInfo.uid, userInfo.userName)
|
await allUserLook(userInfo.uid, userInfo.userName)
|
||||||
break;
|
break;
|
||||||
case '静音':
|
case '静音':
|
||||||
await postOpenMicr(false, user.uid)
|
await postOpenMicr(false, userInfo.uid)
|
||||||
break;
|
break;
|
||||||
case '解除静音':
|
case '解除静音':
|
||||||
await getUserRoomInfo().then(async (res) => {
|
await getUserRoomInfo().then(async (res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
await postOpenMicr(true, user.uid)
|
await postOpenMicr(true, userInfo.uid)
|
||||||
} else {
|
} else {
|
||||||
if (!isClicked) {
|
if (!isClicked) {
|
||||||
setCurrentRequestSpeakType('audio')
|
setCurrentRequestSpeakType('audio')
|
||||||
|
|
@ -1092,12 +1407,12 @@ const Meeting: React.FC = () => {
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
case '关闭视频':
|
case '关闭视频':
|
||||||
await postOpenCamera(false, user.uid)
|
await postOpenCamera(false, userInfo.uid)
|
||||||
break;
|
break;
|
||||||
case '开启视频':
|
case '开启视频':
|
||||||
await getUserRoomInfo().then(async (res) => {
|
await getUserRoomInfo().then(async (res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
await postOpenCamera(true, user.uid)
|
await postOpenCamera(true, userInfo.uid)
|
||||||
} else {
|
} else {
|
||||||
if (!isClicked) {
|
if (!isClicked) {
|
||||||
setCurrentRequestSpeakType('video')
|
setCurrentRequestSpeakType('video')
|
||||||
|
|
@ -1259,6 +1574,52 @@ const Meeting: React.FC = () => {
|
||||||
setIsSharedScreenModal(false)
|
setIsSharedScreenModal(false)
|
||||||
await agora.setDesktopCapturerVideo(sharedScreenItem, isComputerAudio, isFluencyPriority)
|
await agora.setDesktopCapturerVideo(sharedScreenItem, isComputerAudio, isFluencyPriority)
|
||||||
await allUserLook(user.screenShareId, user.userName)
|
await allUserLook(user.screenShareId, user.userName)
|
||||||
|
const isOpen = await getKeyOpenChildWindow('shareScreenWindow')
|
||||||
|
setIsScreenCapture(true)
|
||||||
|
window.electron.setViewStatus('hide')
|
||||||
|
if (!isOpen) {
|
||||||
|
window.electron.createChildWindow({
|
||||||
|
url: location.origin + `/#/noticeWindow`,
|
||||||
|
width: 388,
|
||||||
|
height: 150,
|
||||||
|
key: 'noticeWindow',
|
||||||
|
show: true,
|
||||||
|
})
|
||||||
|
window.electron.createChildWindow({
|
||||||
|
url: location.origin + `/#/shareScreenWindow`,
|
||||||
|
width: 400,
|
||||||
|
height: 80,
|
||||||
|
key: 'shareScreenWindow',
|
||||||
|
show: true,
|
||||||
|
})
|
||||||
|
window.electron.createChildWindow({
|
||||||
|
url: location.origin + `/#/chatSmallWindow`,
|
||||||
|
width: 200,
|
||||||
|
height: 150,
|
||||||
|
key: 'chatSmallWindow',
|
||||||
|
show: true,
|
||||||
|
})
|
||||||
|
window.electron.createChildWindow({
|
||||||
|
url: location.origin + `/#/currentSpeakUserWindow`,
|
||||||
|
width: 200,
|
||||||
|
height: 30,
|
||||||
|
key: 'currentSpeakUserWindow',
|
||||||
|
show: true,
|
||||||
|
})
|
||||||
|
window.electron.createChildWindow({
|
||||||
|
url: location.origin + `/#/chatBigWindow`,
|
||||||
|
width: 540,
|
||||||
|
height: 640,
|
||||||
|
key: 'chatBigWindow',
|
||||||
|
})
|
||||||
|
window.electron.createChildWindow({
|
||||||
|
url: location.origin + `/#/userListWindow`,
|
||||||
|
width: 440,
|
||||||
|
height: 540,
|
||||||
|
key: 'userListWindow',
|
||||||
|
})
|
||||||
|
setKeyOpenChildWindow('shareScreenWindow', true)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
message.error('请选择应用!')
|
message.error('请选择应用!')
|
||||||
}
|
}
|
||||||
|
|
@ -1267,7 +1628,9 @@ const Meeting: React.FC = () => {
|
||||||
const getDesktopCapturerVideo = (): void => {
|
const getDesktopCapturerVideo = (): void => {
|
||||||
agora.getDesktopCapturerVideo({ width: 300, height: 300 }, { width: 300, height: 300 }, true).then((res: any) => {
|
agora.getDesktopCapturerVideo({ width: 300, height: 300 }, { width: 300, height: 300 }, true).then((res: any) => {
|
||||||
res.forEach((item: any, index: number) => {
|
res.forEach((item: any, index: number) => {
|
||||||
item.sourceTitle = '桌面' + (index + 1)
|
if (item.type === 1) {
|
||||||
|
item.sourceTitle = '桌面' + (index + 1)
|
||||||
|
}
|
||||||
if (item.thumbImage.buffer) {
|
if (item.thumbImage.buffer) {
|
||||||
item.thumbnailUrl = thumbImageBufferToBase64(item.thumbImage)
|
item.thumbnailUrl = thumbImageBufferToBase64(item.thumbImage)
|
||||||
}
|
}
|
||||||
|
|
@ -1301,6 +1664,25 @@ const Meeting: React.FC = () => {
|
||||||
agora.stopScreenCapture()
|
agora.stopScreenCapture()
|
||||||
footerListTemplate[1][0].title = '共享屏幕'
|
footerListTemplate[1][0].title = '共享屏幕'
|
||||||
setFooterList(footerListTemplate)
|
setFooterList(footerListTemplate)
|
||||||
|
window.electron.closeChildWindow('shareScreenWindow')
|
||||||
|
setKeyOpenChildWindow('shareScreenWindow', false)
|
||||||
|
setIsScreenCapture(bool => {
|
||||||
|
if (bool) {
|
||||||
|
window.electron.setViewStatus('show')
|
||||||
|
window.electron.getWindowSize().then((res: any) => {
|
||||||
|
window.electron.setMainWindowSize({
|
||||||
|
width: Math.ceil(res.width / 1.5),
|
||||||
|
height: Math.ceil(res.height / 1.3),
|
||||||
|
})
|
||||||
|
window.electron.getIsMaximized().then((b: boolean) => {
|
||||||
|
if (!b) {
|
||||||
|
window.electron.setViewStatus('maximize')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
// 获取房间用户
|
// 获取房间用户
|
||||||
const getRoomUser = async (): Promise<void> => {
|
const getRoomUser = async (): Promise<void> => {
|
||||||
|
|
@ -1325,6 +1707,11 @@ const Meeting: React.FC = () => {
|
||||||
case 'meetingMode':
|
case 'meetingMode':
|
||||||
setMeetingMode(e.value)
|
setMeetingMode(e.value)
|
||||||
break;
|
break;
|
||||||
|
case 'quitMeeting':
|
||||||
|
if (e.value) {
|
||||||
|
setQuitMeetingModal(true)
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'reconnect':
|
case 'reconnect':
|
||||||
if (e.value == true) {
|
if (e.value == true) {
|
||||||
await onInvoke('joinChannel', {
|
await onInvoke('joinChannel', {
|
||||||
|
|
@ -1342,6 +1729,12 @@ const Meeting: React.FC = () => {
|
||||||
userId: userInfo.uid
|
userId: userInfo.uid
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
setIsScreenCapture(bool => {
|
||||||
|
if (bool) {
|
||||||
|
allUserLook(userItem.screenShareId, userItem.userName)
|
||||||
|
}
|
||||||
|
return bool
|
||||||
|
})
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -1357,12 +1750,19 @@ const Meeting: React.FC = () => {
|
||||||
roomNum: state.channelId,
|
roomNum: state.channelId,
|
||||||
msg: msg,
|
msg: msg,
|
||||||
})
|
})
|
||||||
setChatList((newChatList: any) => [...newChatList, {
|
let item = {
|
||||||
uid: user.uid,
|
uid: userInfo.uid,
|
||||||
userName: user.userName,
|
userName: userInfo.userName,
|
||||||
message: msg,
|
message: msg,
|
||||||
timestamp: +new Date()
|
timestamp: +new Date()
|
||||||
}])
|
}
|
||||||
|
setChatList((newChatList: any) => [...newChatList, item])
|
||||||
|
window.electron.windowHandleMessage({
|
||||||
|
key: 'chatSmallWindow',
|
||||||
|
parmes: {
|
||||||
|
chatListIten: item,
|
||||||
|
}
|
||||||
|
})
|
||||||
setTextMsg('');
|
setTextMsg('');
|
||||||
chatScrollBotton()
|
chatScrollBotton()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1783,7 +2183,7 @@ const Meeting: React.FC = () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>{item.isRoomManager ? '取消发言人' : '设为发言人'}</Button> : null}
|
>{item.isRoomManager ? '取消发言' : '允许发言'}</Button> : null}
|
||||||
{item.isRoomManager ? <Button
|
{item.isRoomManager ? <Button
|
||||||
type="primary"
|
type="primary"
|
||||||
className='m-ant-btn'
|
className='m-ant-btn'
|
||||||
|
|
@ -1950,7 +2350,7 @@ const Meeting: React.FC = () => {
|
||||||
{role.ID.includes(item.roleId) || item.isRoomManager ? <div>
|
{role.ID.includes(item.roleId) || item.isRoomManager ? <div>
|
||||||
<img src={item.enableMicr ? ImageUrl.icon22 : ImageUrl.icon22Active} alt="" onClick={() => {
|
<img src={item.enableMicr ? ImageUrl.icon22 : ImageUrl.icon22Active} alt="" onClick={() => {
|
||||||
postOpenMicr(!item.enableMicr, item.uid)
|
postOpenMicr(!item.enableMicr, item.uid)
|
||||||
}} title={item.enableMicr ? '静音' : '解除声音'} />
|
}} title={item.enableMicr ? '静音' : '解除静音'} />
|
||||||
</div> : null}
|
</div> : null}
|
||||||
{role.ID.includes(item.roleId) || item.isRoomManager ? <div>
|
{role.ID.includes(item.roleId) || item.isRoomManager ? <div>
|
||||||
<img src={item.enableCamera ? ImageUrl.icon23 : ImageUrl.icon23Active} alt="" onClick={() => {
|
<img src={item.enableCamera ? ImageUrl.icon23 : ImageUrl.icon23Active} alt="" onClick={() => {
|
||||||
|
|
@ -1959,28 +2359,7 @@ const Meeting: React.FC = () => {
|
||||||
</div> : null}
|
</div> : null}
|
||||||
{item.uid !== user.uid && role.ID.includes(user.roleId) ? <div>
|
{item.uid !== user.uid && role.ID.includes(user.roleId) ? <div>
|
||||||
<Popover placement="left" title={''} content={
|
<Popover placement="left" title={''} content={
|
||||||
<div>
|
<div style={{ width: '100px' }}>
|
||||||
{!role.ID.includes(item.roleId) ? <Button
|
|
||||||
type="primary"
|
|
||||||
className='m-ant-btn'
|
|
||||||
style={{ marginBottom: '10px', width: '100%' }}
|
|
||||||
size={'small'}
|
|
||||||
onClick={() => {
|
|
||||||
if (item.isRoomManager) {
|
|
||||||
DeleteRoomManager({
|
|
||||||
roomId: state.roomId,
|
|
||||||
roomNum: state.channelId,
|
|
||||||
userId: item.uid
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
postRoomManager({
|
|
||||||
roomId: state.roomId,
|
|
||||||
roomNum: state.channelId,
|
|
||||||
userId: item.uid
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>{item.isRoomManager ? '取消发言人' : '设为发言人'}</Button> : null}
|
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
className='m-ant-btn'
|
className='m-ant-btn'
|
||||||
|
|
@ -2000,12 +2379,29 @@ const Meeting: React.FC = () => {
|
||||||
>移出会议</Button>
|
>移出会议</Button>
|
||||||
</div>
|
</div>
|
||||||
}>
|
}>
|
||||||
<EllipsisOutlined style={{
|
<EllipsisOutlined style={{ color: '#fff', fontSize: '20px' }} />
|
||||||
color: '#fff',
|
|
||||||
fontSize: '20px'
|
|
||||||
}} />
|
|
||||||
</Popover>
|
</Popover>
|
||||||
</div> : null}
|
</div> : null}
|
||||||
|
{item.uid !== user.uid && !role.ID.includes(item.roleId) && role.ID.includes(user.roleId) ? <div onClick={() => {
|
||||||
|
if (item.isRoomManager) {
|
||||||
|
DeleteRoomManager({
|
||||||
|
roomId: state.roomId,
|
||||||
|
roomNum: state.channelId,
|
||||||
|
userId: item.uid
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
postRoomManager({
|
||||||
|
roomId: state.roomId,
|
||||||
|
roomNum: state.channelId,
|
||||||
|
userId: item.uid
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{!item.isRoomManager ?
|
||||||
|
<img src={ImageUrl.icon50} alt="" title='允许发言' /> :
|
||||||
|
<img src={ImageUrl.icon51} alt="" title='取消发言' />
|
||||||
|
}
|
||||||
|
</div> : null}
|
||||||
</div>
|
</div>
|
||||||
</div> : null
|
</div> : null
|
||||||
)
|
)
|
||||||
|
|
@ -2092,7 +2488,7 @@ const Meeting: React.FC = () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>{roomUserItem.isRoomManager ? '取消发言人' : '设为发言人'}</Button> : null}
|
>{roomUserItem.isRoomManager ? '取消发言' : '允许发言'}</Button> : null}
|
||||||
{roomUserItem.isRoomManager ? <Button
|
{roomUserItem.isRoomManager ? <Button
|
||||||
type="primary"
|
type="primary"
|
||||||
className='m-ant-btn'
|
className='m-ant-btn'
|
||||||
|
|
@ -2419,6 +2815,41 @@ const Meeting: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
title=""
|
||||||
|
open={quitMeetingModal}
|
||||||
|
footer={null}
|
||||||
|
closable={false}
|
||||||
|
centered
|
||||||
|
width={'190px'}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div className='meetingContentFooterPopover'>
|
||||||
|
{role.ID.includes(user.roleId) ?
|
||||||
|
<Popconfirm
|
||||||
|
title="提示"
|
||||||
|
description={`结束会议后,所有人将退出,是否结束?`}
|
||||||
|
onConfirm={async () => {
|
||||||
|
await GetLeaveAll({
|
||||||
|
roomNum: state.channelId,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
onCancel={() => {
|
||||||
|
|
||||||
|
}}
|
||||||
|
okText="结束"
|
||||||
|
cancelText="取消"
|
||||||
|
>
|
||||||
|
<div className='meetingContentFooterPopoverDel'>全员结束会议</div>
|
||||||
|
</Popconfirm>
|
||||||
|
: null}
|
||||||
|
<div className='meetingContentFooterPopoverDefault' onClick={async () => {
|
||||||
|
await leaveChannel()
|
||||||
|
}}>仅自己离开</div>
|
||||||
|
<div className='meetingContentFooterPopoverCancel' onClick={() => { setQuitMeetingModal(false) }}>取消</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
<SharedFilesModel ref={sharedFilesModelRef} />
|
<SharedFilesModel ref={sharedFilesModelRef} />
|
||||||
<SpeakerModeModal ref={speakerModeModalRef} />
|
<SpeakerModeModal ref={speakerModeModalRef} />
|
||||||
<InvitingPersonnelModal ref={invitingPersonnelRef} />
|
<InvitingPersonnelModal ref={invitingPersonnelRef} />
|
||||||
|
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
.shareScreenWindow {
|
|
||||||
background-color: #07090B;
|
|
||||||
color: white;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.shareScreenWindowTitle {
|
|
||||||
font-size: 12px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
padding: 4px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-color: lighten(#07090B, 4%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.shareScreenWindowContent {
|
|
||||||
flex-grow: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.shareScreenWindowContentList {
|
|
||||||
display: flex;
|
|
||||||
flex-grow: 1;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 0 20px;
|
|
||||||
|
|
||||||
>div {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
>img {
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
>span {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
import styles from '@/page/ShareScreenWindow/index.module.scss'
|
|
||||||
import ImageUrl from '@/utils/package/imageUrl';
|
|
||||||
import { Button } from 'antd';
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
// window.electron.createChildWindow({
|
|
||||||
// url: location.origin + `/#/shareScreenWindow`,
|
|
||||||
// width: 500,
|
|
||||||
// height: 70,
|
|
||||||
// key: 'shareScreenWindow',
|
|
||||||
// })
|
|
||||||
const ShareScreenWindow: React.FC = () => {
|
|
||||||
const [footerList, setFooterList] = useState<any>([
|
|
||||||
{
|
|
||||||
title: '静音',
|
|
||||||
icon: ImageUrl.icon22,
|
|
||||||
iconActive: ImageUrl.icon22Active,
|
|
||||||
active: false,
|
|
||||||
select: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '关闭视频',
|
|
||||||
icon: ImageUrl.icon23,
|
|
||||||
iconActive: ImageUrl.icon23Active,
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '设置',
|
|
||||||
icon: ImageUrl.icon28,
|
|
||||||
iconSelect: ImageUrl.icon28Select,
|
|
||||||
active: false,
|
|
||||||
select: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '录制',
|
|
||||||
icon: ImageUrl.icon27,
|
|
||||||
iconSelect: ImageUrl.icon27Select,
|
|
||||||
iconActive: ImageUrl.icon27Active,
|
|
||||||
active: false,
|
|
||||||
select: false,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={`${styles.shareScreenWindow} drag`}>
|
|
||||||
<div className={styles.shareScreenWindowTitle}>02:38 共享中</div>
|
|
||||||
<div className={styles.shareScreenWindowContent}>
|
|
||||||
<div className={styles.shareScreenWindowContentList}>
|
|
||||||
{footerList.map((item: any, index: number) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
console.log(item, index)
|
|
||||||
}}
|
|
||||||
key={index}>
|
|
||||||
{item.select ? <img src={item.iconSelect} alt="" /> : <img src={item.active ? item.iconActive : item.icon} alt="" />}
|
|
||||||
<span>{item.title}</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<Button type="primary" style={{ backgroundColor: '#FF5219', marginRight: '14px' }} onClick={() => {
|
|
||||||
|
|
||||||
}}>
|
|
||||||
结束会议
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ShareScreenWindow
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
export interface IElectronAPI {
|
export interface IElectronAPI {
|
||||||
setMainWindowSize: (config: any) => void;
|
setMainWindowSize: (config: any) => void;
|
||||||
getWindowSize: () => any;
|
getWindowSize: () => any;
|
||||||
setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize' | 'hide') => void;
|
setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize' | 'hide' | 'show') => void;
|
||||||
getIsMaximized: () => Promise<boolean>;
|
getIsMaximized: () => Promise<boolean>;
|
||||||
setWriteText: (text: string) => void;
|
setWriteText: (text: string) => void;
|
||||||
onQuit: (callBack: Function) => void;
|
onQuit: (callBack: Function) => void;
|
||||||
|
|
@ -12,13 +12,22 @@ export interface IElectronAPI {
|
||||||
selectFilePath: (data?: any) => void
|
selectFilePath: (data?: any) => void
|
||||||
onFilePath: (callBack: Function) => void;
|
onFilePath: (callBack: Function) => void;
|
||||||
getSources: () => any;
|
getSources: () => any;
|
||||||
quit: () => any;
|
quit: (bool) => any;
|
||||||
downFile: (callBack: Function) => void;
|
downFile: (callBack: Function) => void;
|
||||||
quitAndInstall: (callBack: Function) => void;
|
quitAndInstall: (callBack: Function) => void;
|
||||||
|
isOpenWindows: (callBack: Function) => void;
|
||||||
getVersion: () => Promise<string>;
|
getVersion: () => Promise<string>;
|
||||||
|
isVisible: () => Promise<string>;
|
||||||
setRegistry: (uuid: string) => any;
|
setRegistry: (uuid: string) => any;
|
||||||
getRegistry: () => any;
|
getRegistry: () => any;
|
||||||
createChildWindow: (config: any) => void;
|
createChildWindow: (config: any) => void;
|
||||||
|
setChildWindow: (config: any) => void;
|
||||||
|
setChildWindowShow: (config: any) => void;
|
||||||
|
closeChildWindow: (key: string) => void;
|
||||||
|
mainWindowCenter: () => any;
|
||||||
|
mainWindowHide: () => any;
|
||||||
|
windowHandleMessage: (data: any) => {}
|
||||||
|
windowHandleMessageCallBack: (callBack: Function) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ import {
|
||||||
AudioVolumeInfo,
|
AudioVolumeInfo,
|
||||||
UserOfflineReasonType,
|
UserOfflineReasonType,
|
||||||
ConnectionStateType,
|
ConnectionStateType,
|
||||||
ConnectionChangedReasonType
|
ConnectionChangedReasonType,
|
||||||
|
LocalVideoStreamReason,
|
||||||
|
LocalVideoStreamState
|
||||||
} from "agora-electron-sdk";
|
} from "agora-electron-sdk";
|
||||||
import { GetRoomRtcToken, GetAgoraConf } from "@/api/Home/Index";
|
import { GetRoomRtcToken, GetAgoraConf } from "@/api/Home/Index";
|
||||||
import { storage } from '@/utils';
|
import { storage } from '@/utils';
|
||||||
|
|
@ -38,7 +40,9 @@ export const agora = {
|
||||||
await rtcEngine.initialize({
|
await rtcEngine.initialize({
|
||||||
appId: data,
|
appId: data,
|
||||||
});
|
});
|
||||||
await agora.setDeviceManager(bool)
|
if (bool) {
|
||||||
|
await agora.setDeviceManager()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 获取rtcEngine
|
// 获取rtcEngine
|
||||||
|
|
@ -46,7 +50,7 @@ export const agora = {
|
||||||
return rtcEngine
|
return rtcEngine
|
||||||
},
|
},
|
||||||
// 获取当前设备是否存在不存在就获取默认设备
|
// 获取当前设备是否存在不存在就获取默认设备
|
||||||
setDeviceManager: async (bool: boolean = false) => {
|
setDeviceManager: async () => {
|
||||||
const setting = await JSON.parse(storage.getItem('setting') as string)
|
const setting = await JSON.parse(storage.getItem('setting') as string)
|
||||||
// 摄像头
|
// 摄像头
|
||||||
if (setting.videoDeviceId) {
|
if (setting.videoDeviceId) {
|
||||||
|
|
@ -99,19 +103,17 @@ export const agora = {
|
||||||
}
|
}
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
storage.setItem('setting', JSON.stringify(setting))
|
storage.setItem('setting', JSON.stringify(setting))
|
||||||
if (bool) {
|
const settingData = await JSON.parse(storage.getItem('setting') as string)
|
||||||
const setting = await JSON.parse(storage.getItem('setting') as string)
|
if (settingData.videoDeviceId) agora.setVideoDeviceManager(settingData.videoDeviceId) //指定摄像头头采集设备
|
||||||
if (setting.videoDeviceId) agora.setVideoDeviceManager(setting.videoDeviceId) //指定摄像头头采集设备
|
if (settingData.playBackDeviceId) agora.setPlaybackDevice(settingData.playBackDeviceId) //指定播放设备
|
||||||
if (setting.playBackDeviceId) agora.setPlaybackDevice(setting.playBackDeviceId) //指定播放设备
|
if (settingData.playBackVolume) agora.setPlaybackDeviceVolume(settingData.playBackVolume) // 设置播放设备音量
|
||||||
if (setting.playBackVolume) agora.setPlaybackDeviceVolume(setting.playBackVolume) // 设置播放设备音量
|
if (settingData.ecordingDeviceId) agora.setRecordingDevice(settingData.ecordingDeviceId) // 设置音频采集设备
|
||||||
if (setting.ecordingDeviceId) agora.setRecordingDevice(setting.ecordingDeviceId) // 设置音频采集设备
|
if (settingData.ecordingVolume) agora.setRecordingDeviceVolume(settingData.ecordingVolume) // 设置音频设备音量
|
||||||
if (setting.ecordingVolume) agora.setRecordingDeviceVolume(setting.ecordingVolume) // 设置音频设备音量
|
if (settingData.isAINoiseReduction) agora.setAINSMode(settingData.isAINoiseReduction, settingData.aINoiseReduction) // 设置ai降噪
|
||||||
if (setting.isAINoiseReduction) agora.setAINSMode(setting.isAINoiseReduction, setting.aINoiseReduction) // 设置ai降噪
|
|
||||||
}
|
|
||||||
}, 1000);
|
}, 1000);
|
||||||
},
|
},
|
||||||
// 事件回调
|
// 事件回调
|
||||||
registerEventHandler: ({ onJoinChannelSuccess, onUserJoined, onUserOffline, onAudioVolumeIndication, onNetworkQuality, onRtcStats, onConnectionStateChanged }: any) => {
|
registerEventHandler: ({ onJoinChannelSuccess, onUserJoined, onUserOffline, onAudioVolumeIndication, onNetworkQuality, onRtcStats, onConnectionStateChanged, onLocalVideoStateChanged }: any) => {
|
||||||
rtcEngine.registerEventHandler({
|
rtcEngine.registerEventHandler({
|
||||||
// 监听本地用户加入频道事件
|
// 监听本地用户加入频道事件
|
||||||
onJoinChannelSuccess: async (connection: RtcConnection, elapsed: number) => {
|
onJoinChannelSuccess: async (connection: RtcConnection, elapsed: number) => {
|
||||||
|
|
@ -153,6 +155,10 @@ export const agora = {
|
||||||
onConnectionStateChanged: async (connection: RtcConnection, state: ConnectionStateType, reason: ConnectionChangedReasonType) => {
|
onConnectionStateChanged: async (connection: RtcConnection, state: ConnectionStateType, reason: ConnectionChangedReasonType) => {
|
||||||
await onConnectionStateChanged?.(connection, state, reason)
|
await onConnectionStateChanged?.(connection, state, reason)
|
||||||
},
|
},
|
||||||
|
// 本地视频状态发生改变回调。
|
||||||
|
onLocalVideoStateChanged: async (source: VideoSourceType, state: LocalVideoStreamState, reason: LocalVideoStreamReason) => {
|
||||||
|
await onLocalVideoStateChanged?.(source, state, reason)
|
||||||
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 获取视图模式
|
// 获取视图模式
|
||||||
|
|
@ -165,7 +171,7 @@ export const agora = {
|
||||||
},
|
},
|
||||||
// 本地加入
|
// 本地加入
|
||||||
setupLocalVideo: async (item: any) => {
|
setupLocalVideo: async (item: any) => {
|
||||||
if (item.view?.childNodes.length === 1) {
|
if (item.view?.childNodes.length === 1 || item.type) {
|
||||||
await rtcEngine.setupLocalVideo({
|
await rtcEngine.setupLocalVideo({
|
||||||
renderMode: agora.getRrenderMode(item.uid),
|
renderMode: agora.getRrenderMode(item.uid),
|
||||||
sourceType: item.sourceType,
|
sourceType: item.sourceType,
|
||||||
|
|
@ -232,7 +238,7 @@ export const agora = {
|
||||||
},
|
},
|
||||||
// 加入频道
|
// 加入频道
|
||||||
joinChannel: async () => {
|
joinChannel: async () => {
|
||||||
await rtcEngine.enableAudioVolumeIndication(100, 1, true)
|
await rtcEngine.enableAudioVolumeIndication(100, 3, true)
|
||||||
await rtcEngine.joinChannel(option.token, option.channelId, option.uid);
|
await rtcEngine.joinChannel(option.token, option.channelId, option.uid);
|
||||||
await rtcEngine.setDualStreamModeEx(
|
await rtcEngine.setDualStreamModeEx(
|
||||||
SimulcastStreamMode.EnableSimulcastStream,
|
SimulcastStreamMode.EnableSimulcastStream,
|
||||||
|
|
@ -323,8 +329,8 @@ export const agora = {
|
||||||
rtcEngine.muteRemoteVideoStream(uid, mute)
|
rtcEngine.muteRemoteVideoStream(uid, mute)
|
||||||
},
|
},
|
||||||
// 销毁视频渲染dom
|
// 销毁视频渲染dom
|
||||||
destroyRendererByConfig: async (uid: number) => {
|
destroyRendererByConfig: async (uid: number, channelId: string) => {
|
||||||
await rtcEngine.destroyRendererByConfig(VideoSourceType.VideoSourceRemote, option.channelId + 'a', uid);
|
await rtcEngine.destroyRendererByConfig(VideoSourceType.VideoSourceRemote, channelId, uid);
|
||||||
},
|
},
|
||||||
// ai降噪
|
// ai降噪
|
||||||
setAINSMode: async (enabled: boolean, mode: AudioAinsMode) => {
|
setAINSMode: async (enabled: boolean, mode: AudioAinsMode) => {
|
||||||
|
|
@ -388,7 +394,7 @@ export const agora = {
|
||||||
},
|
},
|
||||||
// 桌面捕获音频和视频的媒体源的信息
|
// 桌面捕获音频和视频的媒体源的信息
|
||||||
getDesktopCapturerVideo: async (thumbSize: any, iconSize: any, includeScreen: boolean) => {
|
getDesktopCapturerVideo: async (thumbSize: any, iconSize: any, includeScreen: boolean) => {
|
||||||
return await rtcEngine.getScreenCaptureSources(thumbSize, iconSize, includeScreen).filter((item: any) => item.type === 1)
|
return await rtcEngine.getScreenCaptureSources(thumbSize, iconSize, includeScreen)
|
||||||
},
|
},
|
||||||
// 共享屏幕采集
|
// 共享屏幕采集
|
||||||
setDesktopCapturerVideo: async (targetSource: any, isComputerAudio: boolean, isFluencyPriority: boolean) => {
|
setDesktopCapturerVideo: async (targetSource: any, isComputerAudio: boolean, isFluencyPriority: boolean) => {
|
||||||
|
|
@ -414,8 +420,6 @@ export const agora = {
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
windowFocus: true,
|
windowFocus: true,
|
||||||
enableHighLight: true,
|
|
||||||
highLightColor: 0xFF99CC00,
|
|
||||||
...data
|
...data
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -425,8 +429,6 @@ export const agora = {
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
windowFocus: true,
|
windowFocus: true,
|
||||||
enableHighLight: true,
|
|
||||||
highLightColor: 0xFF99CC00,
|
|
||||||
...data
|
...data
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,8 @@ import icon47Active from '@/assets/icon47-active.png'
|
||||||
import icon48 from '@/assets/icon48.png'
|
import icon48 from '@/assets/icon48.png'
|
||||||
import icon48Select from '@/assets/icon48-select.png'
|
import icon48Select from '@/assets/icon48-select.png'
|
||||||
import icon49 from '@/assets/icon49.png'
|
import icon49 from '@/assets/icon49.png'
|
||||||
|
import icon50 from '@/assets/icon50.png'
|
||||||
|
import icon51 from '@/assets/icon51.png'
|
||||||
export default {
|
export default {
|
||||||
loading,
|
loading,
|
||||||
icon,
|
icon,
|
||||||
|
|
@ -145,4 +147,6 @@ export default {
|
||||||
icon48,
|
icon48,
|
||||||
icon48Select,
|
icon48Select,
|
||||||
icon49,
|
icon49,
|
||||||
|
icon50,
|
||||||
|
icon51,
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
import storage from "./storage";
|
||||||
|
export const setKeyOpenChildWindow = async (key: string, bool: boolean) => {
|
||||||
|
const openChildWindow = await JSON.parse(storage.getItem('openChildWindow') as string)
|
||||||
|
openChildWindow[key] = bool;
|
||||||
|
if (key === 'shareScreenWindow' && !bool) {
|
||||||
|
for (const k in openChildWindow) {
|
||||||
|
openChildWindow[k] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storage.setItem('openChildWindow', JSON.stringify(openChildWindow))
|
||||||
|
};
|
||||||
|
export const getKeyOpenChildWindow = async (key: string): Promise<boolean> => {
|
||||||
|
const openChildWindow = await JSON.parse(storage.getItem('openChildWindow') as string)
|
||||||
|
return openChildWindow[key]
|
||||||
|
};
|
||||||
|
|
@ -376,6 +376,7 @@ $pagination-hover-background-color: #5575F2;
|
||||||
.ant-message {
|
.ant-message {
|
||||||
-webkit-app-region: no-drag;
|
-webkit-app-region: no-drag;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ant-spin-fullscreen
|
// ant-spin-fullscreen
|
||||||
.ant-spin-fullscreen {
|
.ant-spin-fullscreen {
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
|
|
@ -383,4 +384,8 @@ $pagination-hover-background-color: #5575F2;
|
||||||
|
|
||||||
.ant-picker-dropdown {
|
.ant-picker-dropdown {
|
||||||
-webkit-app-region: no-drag;
|
-webkit-app-region: no-drag;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-tabs {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
}
|
}
|
||||||
|
|
@ -70,7 +70,9 @@ export default defineConfig({
|
||||||
AudioVolumeInfo,
|
AudioVolumeInfo,
|
||||||
UserOfflineReasonType,
|
UserOfflineReasonType,
|
||||||
ConnectionStateType,
|
ConnectionStateType,
|
||||||
ConnectionChangedReasonType
|
ConnectionChangedReasonType,
|
||||||
|
LocalVideoStreamState,
|
||||||
|
LocalVideoStreamReason
|
||||||
} = require("agora-electron-sdk")
|
} = require("agora-electron-sdk")
|
||||||
export {
|
export {
|
||||||
createAgoraRtcEngine,
|
createAgoraRtcEngine,
|
||||||
|
|
@ -89,7 +91,9 @@ export default defineConfig({
|
||||||
AudioVolumeInfo,
|
AudioVolumeInfo,
|
||||||
UserOfflineReasonType,
|
UserOfflineReasonType,
|
||||||
ConnectionStateType,
|
ConnectionStateType,
|
||||||
ConnectionChangedReasonType
|
ConnectionChangedReasonType,
|
||||||
|
LocalVideoStreamState,
|
||||||
|
LocalVideoStreamReason
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue