Compare commits

..

No commits in common. "3b03d6a8c36352e79d2a940e4c63472fb579be03" and "734dc7a41a911fc89aaa6ce0c59fd159a7bed9f3" have entirely different histories.

57 changed files with 670 additions and 1504 deletions

View File

@ -1,5 +1,5 @@
#基础API 绝对的 #基础API 绝对的
VITE_BASE_URL_API = 'https://meeting-api.23544.com/pc' VITE_BASE_URL_API = 'http://192.168.2.9:5192'
VITE_BASE_URL_DRAW_API = 'http://192.168.2.9:6555' VITE_BASE_URL_DRAW_API = 'http://192.168.2.9:6555'
#当前IP 相对的 #当前IP 相对的
VITE_BASE_CURRENT_API = '.' VITE_BASE_CURRENT_API = '.'

58
main.js
View File

@ -16,6 +16,7 @@ const { autoUpdater, CancellationToken } = require('electron-updater');
const cancellationToken = new CancellationToken() const cancellationToken = new CancellationToken()
app.allowRendererProcessReuse = false; app.allowRendererProcessReuse = false;
let mainWindow = null; let mainWindow = null;
let newWindow = null;
let isMaximized = false; let isMaximized = false;
let env; let env;
@ -129,9 +130,6 @@ app.on('ready', () => {
} }
createWindow() createWindow()
updateHandle() // 检查更新 updateHandle() // 检查更新
setInterval(() => {
updateHandle() // 每一小时检查更新
}, 1000 * 60 * 60)
createTray() createTray()
// 获取当前脚本所在目录的绝对路径 // 获取当前脚本所在目录的绝对路径
const currentDirectory = __dirname; const currentDirectory = __dirname;
@ -144,11 +142,11 @@ app.on('ready', () => {
} }
// 监听f12打开控制台 // 监听f12打开控制台
mainWindow.webContents.on('before-input-event', (event, input) => { mainWindow.webContents.on('before-input-event', (event, input) => {
// if (env === 'development') { if (env === 'development') {
if (input.key === 'F12') { if (input.key === 'F12') {
mainWindow.webContents.openDevTools() mainWindow.webContents.openDevTools()
} }
// } }
}); });
// 监听移动 // 监听移动
mainWindow.on('move', () => { mainWindow.on('move', () => {
@ -245,12 +243,6 @@ app.on('ready', () => {
} }
} }
}); });
// 获取桌面大小
ipcMain.handle('getWindowSize', (event, config) => {
const primaryDisplay = screen.getPrimaryDisplay()
const { width, height } = primaryDisplay.workAreaSize
return { width, height }
});
// 设置桌面应用基础属性 // 设置桌面应用基础属性
ipcMain.handle('setMainWindowSize', (event, config) => { ipcMain.handle('setMainWindowSize', (event, config) => {
// 设置最小窗口尺寸 // 设置最小窗口尺寸
@ -271,6 +263,46 @@ app.on('ready', () => {
const y = Math.round((display.workArea.height - mainWindow.getSize()[1]) / 2); const y = Math.round((display.workArea.height - mainWindow.getSize()[1]) / 2);
mainWindow.setPosition(x, y); mainWindow.setPosition(x, y);
}); });
// 打开新窗口
ipcMain.handle('oepnWindow', (event, data) => {
if (newWindow) {
newWindow.focus();
} else {
newWindow = new BrowserWindow({
width: 1200,
height: 800,
minWidth: 1200,
minHeight: 800,
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
enableRemoteModule: true,
nodeIntegrationInWorker: true,
allowMediaDevices: true,
preload: path.join(__dirname, 'preload.js')
},
frame: false,
backgroundColor: '#00000000',
transparent: true,
});
newWindow.loadURL(data.url);
newWindow.focus();
newWindow.webContents.on('before-input-event', (event, input) => {
if (env === 'development') {
if (input.key === 'F12') {
newWindow.webContents.openDevTools()
}
}
});
}
});
// 关闭会议监控窗口
ipcMain.handle('closeMonitorWindow', () => {
if (newWindow) {
newWindow.close();
newWindow = null
}
});
} }
}); });
// 检测更新在你想要检查更新的时候执行renderer事件触发后的操作自行编写 // 检测更新在你想要检查更新的时候执行renderer事件触发后的操作自行编写
@ -281,9 +313,9 @@ function updateHandle() {
error: '检查更新出错', error: '检查更新出错',
checking: '正在检查更新……', checking: '正在检查更新……',
updateAva: '检测到新版本,正在下载……', updateAva: '检测到新版本,正在下载……',
updateNotAva: '已经是最新版本,不用更新' updateNotAva: '现在使用的就是最新版本,不用更新'
} }
autoUpdater.setFeedURL('https://meeting-api.23544.com/meeting/update') autoUpdater.setFeedURL('https://update.23544.com/metting')
autoUpdater.autoDownload = false // 不自动下载安装包 autoUpdater.autoDownload = false // 不自动下载安装包
autoUpdater.autoInstallOnAppQuit = false // 不自动安装 autoUpdater.autoInstallOnAppQuit = false // 不自动安装
autoUpdater.on('error', function (error) { autoUpdater.on('error', function (error) {

View File

@ -1,10 +1,10 @@
{ {
"name": "WGShare.Metting", "name": "WGShare.Metting",
"private": true, "private": true,
"version": "0.1.14", "version": "0.0.1",
"main": "main.js", "main": "main.js",
"authors": "yj", "authors": "yj",
"description": "智汇享", "description": "test",
"scripts": { "scripts": {
"dev": "concurrently \"electron . --env=development\" \"cross-env BROWSER=none vite\"", "dev": "concurrently \"electron . --env=development\" \"cross-env BROWSER=none vite\"",
"test": "concurrently \"electron . --env=test\" \"cross-env BROWSER=none vite\"", "test": "concurrently \"electron . --env=test\" \"cross-env BROWSER=none vite\"",
@ -69,7 +69,7 @@
"publish": [ "publish": [
{ {
"provider": "generic", "provider": "generic",
"url": "https://meeting-api.23544.com/meeting/update" "url": "https://update.23544.com/metting"
} }
], ],
"files": [ "files": [
@ -77,7 +77,6 @@
], ],
"win": { "win": {
"icon": "build/start.ico", "icon": "build/start.ico",
"requestedExecutionLevel": "highestAvailable",
"target": [ "target": [
{ {
"target": "nsis", "target": "nsis",
@ -100,9 +99,7 @@
"createDesktopShortcut": true, "createDesktopShortcut": true,
"createStartMenuShortcut": true, "createStartMenuShortcut": true,
"deleteAppDataOnUninstall": true, "deleteAppDataOnUninstall": true,
"shortcutName": "智汇享", "shortcutName": "智汇享"
"allowElevation": true,
"perMachine":true
} }
} }
} }

View File

@ -5,10 +5,6 @@ window.electron = {
setMainWindowSize: (config) => { setMainWindowSize: (config) => {
ipcRenderer.invoke('setMainWindowSize', { ...config }) ipcRenderer.invoke('setMainWindowSize', { ...config })
}, },
// 获取窗口大小
getWindowSize: (config) => {
return ipcRenderer.invoke('getWindowSize')
},
// 设置窗口状态 // 设置窗口状态
setViewStatus: (status) => { setViewStatus: (status) => {
ipcRenderer.invoke('setViewStatus', status) ipcRenderer.invoke('setViewStatus', status)
@ -64,5 +60,13 @@ window.electron = {
// 下载文件 // 下载文件
downFile: (callback) => { downFile: (callback) => {
ipcRenderer.on('downFile', callback) ipcRenderer.on('downFile', callback)
},
// 打开新窗口
oepnWindow: (data) => {
ipcRenderer.invoke('oepnWindow', data)
},
// 关闭会议监控窗口
closeMonitorWindow: () => {
ipcRenderer.invoke('closeMonitorWindow')
} }
} }

View File

@ -17,6 +17,7 @@ import { PostLogin } from "@/api/Login";
import { agora } from "@/utils/package/agora"; import { agora } from "@/utils/package/agora";
import QuitTips from "@/components/QuitTips"; import QuitTips from "@/components/QuitTips";
import { GetLeave } from "@/api/Meeting"; import { GetLeave } from "@/api/Meeting";
import UserVideo from "./page/UserVideo";
import path from "path"; import path from "path";
const fs = require('fs').promises; const fs = require('fs').promises;
const { exec } = require('child_process'); const { exec } = require('child_process');
@ -32,6 +33,7 @@ const App: React.FC = () => {
}); });
const [spinning, setSpinning] = useState(false); const [spinning, setSpinning] = useState(false);
const [isState, setIsState] = useState(true); const [isState, setIsState] = useState(true);
if (location.href.indexOf('/userVideo') === -1) {
useEffect(() => { useEffect(() => {
let userInfo = JSON.parse(storage.getItem('user') as string) let userInfo = JSON.parse(storage.getItem('user') as string)
let loginInfo = JSON.parse(storage.getItem('login') as string) let loginInfo = JSON.parse(storage.getItem('login') as string)
@ -43,7 +45,6 @@ const App: React.FC = () => {
}).then(async (res) => { }).then(async (res) => {
if (res.code === 200) { if (res.code === 200) {
storage.setItem('user', JSON.stringify(res.data)) storage.setItem('user', JSON.stringify(res.data))
storage.setItem('userLogin', true)
toSrc('/home') toSrc('/home')
await startSignalr() await startSignalr()
} else { } else {
@ -120,8 +121,6 @@ const App: React.FC = () => {
shareFilesPath: path.resolve(__dirname, '../../Downloads/') + '\\', //共享文件保存路径 shareFilesPath: path.resolve(__dirname, '../../Downloads/') + '\\', //共享文件保存路径
isShareSavePath: true, //是否下载钱询问每个文件保存的位置 isShareSavePath: true, //是否下载钱询问每个文件保存的位置
closeSetting: 'hide', //关闭按钮设置 closeSetting: 'hide', //关闭按钮设置
isAINoiseReduction: true, //是否开启ai降噪
aINoiseReduction: 1, // 降噪模式
})) }))
} }
}, []) }, [])
@ -151,7 +150,11 @@ const App: React.FC = () => {
if (location.href.indexOf('/login') !== -1) { if (location.href.indexOf('/login') !== -1) {
onStop() onStop()
} }
if (location.href.indexOf('/meeting') === -1) {
window.electron.closeMonitorWindow()
}
}, [navigate]) }, [navigate])
}
useEffect(() => { useEffect(() => {
document.addEventListener('keydown', (event) => { document.addEventListener('keydown', (event) => {
if (event.key === 'F11') { if (event.key === 'F11') {
@ -197,22 +200,20 @@ const App: React.FC = () => {
}) })
} }
const toSrc = (path: string): void => { const toSrc = (path: string): void => {
window.electron.getWindowSize().then((res: any) => {
switch (path) { switch (path) {
case '/login': case '/login':
storage.removeItem('user') storage.removeItem('user')
storage.setItem('userLogin', false)
navigate('/login') navigate('/login')
break; break;
case '/home': case '/home':
window.electron.setMainWindowSize({ window.electron.setMainWindowSize({
width: Math.ceil(res.width / 1.5), width: 1200,
height: Math.ceil(res.height / 1.3), height: 800,
}) })
navigate('/home') navigate('/home')
break; break;
} }
})
}; };
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) {
@ -232,10 +233,6 @@ const App: React.FC = () => {
if (Boolean(e.value)) { if (Boolean(e.value)) {
onEventSignalr() onEventSignalr()
} }
} else if (e.key === 'userLogin') {
if (!Boolean(e.value)) {
navigate('/login')
}
} }
}; };
@ -262,6 +259,7 @@ const App: React.FC = () => {
</Route> </Route>
<Route path='/login' element={<Login />} /> <Route path='/login' element={<Login />} />
<Route path='/meeting' element={<Meeting />} /> <Route path='/meeting' element={<Meeting />} />
<Route path='/userVideo' element={<UserVideo />} />
<Route path='*' element={<NotFound />} /> <Route path='*' element={<NotFound />} />
</Routes> </Routes>
<Spin spinning={spinning} fullscreen /> <Spin spinning={spinning} fullscreen />

View File

@ -5,17 +5,12 @@ export const GetRoom = (data: { pageIndex: number, pageSize: number }) =>
method: 'get' method: 'get'
}) })
export const PostRoom = (data: any) => export const PostRomm = (data: any) =>
request({ request({
url: `/home/room`, url: `/home/room`,
method: 'post', method: 'post',
data, data,
}) })
export const DeleteRoom = (roomId: string) =>
request({
url: `/home/room?roomId=${roomId}`,
method: 'delete',
})
export const GetCheckoutRoomNum = (roomNum: string) => export const GetCheckoutRoomNum = (roomNum: string) =>
request({ request({
@ -35,15 +30,3 @@ export const GetRoomInfo = (roomNum: string) =>
method: 'get', method: 'get',
}) })
export const GetAgoraConf = () =>
request({
url: `/home/agora-conf`,
method: 'get',
})
export const GetRecord = (beginTimestamp: number, endTimestamp: number, roomNum: string) =>
request({
url: `/home/record?beginTimestamp=${beginTimestamp}&endTimestamp=${endTimestamp}&roomNum=${roomNum}`,
method: 'get',
})

View File

@ -38,10 +38,3 @@ export const GetRoleDpList = () =>
url: `/pub/role-dp-list`, url: `/pub/role-dp-list`,
method: 'get', method: 'get',
}) })
export const PostUserImport = (data: any) =>
request({
url: `/user/import`,
method: 'post',
data
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 977 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 892 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 769 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 963 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -1,23 +0,0 @@
.equipmentManagement {
padding: 10px;
box-sizing: border-box;
>div:nth-child(1) {
>div {
display: flex;
align-items: center;
margin-bottom: 10px;
>span {
color: #EEEEEE;
font-size: 16px;
margin-right: 10px;
}
}
}
>div:nth-child(2) {
display: flex;
justify-content: center;
margin-top: 20px;
}
}

View File

@ -1,103 +0,0 @@
import styles from '@/components/EquipmentManagement/index.module.scss'
import { onInvoke } from '@/utils/package/signalr';
import { Button, Modal, Select, Slider, message } from 'antd';
import { useState, useImperativeHandle, forwardRef } from "react";
const EquipmentManagement = forwardRef((_props: any, ref: any) => {
useImperativeHandle(ref, () => ({
changeModal: async (uid: string, userName: string) => {
setCallerUid(uid)
setDeviceInfo({})
await onInvoke('getDrivers', {
uid
})
setUserName(userName)
setEquipmentManagementModal(true)
},
setData: (data: any) => {
setDeviceInfo(data)
}
}))
const [equipmentManagementModal, setEquipmentManagementModal] = useState(false)
const [callerUid, setCallerUid] = useState('')
const [deviceInfo, setDeviceInfo] = useState<any>({})
const [userName, setUserName] = useState<any>({})
return (
<>
<Modal
title={`设备管理(${userName})`}
open={equipmentManagementModal}
footer={null}
centered
width={'500px'}
onCancel={() => {
setEquipmentManagementModal(false)
}}>
<div className={styles.equipmentManagement}>
<div>
<div>
<span></span>
<Select
placeholder={deviceInfo?.videoList?.length ? '请选择设备' : '未检测到摄像头'}
options={deviceInfo?.videoList} style={{ flexGrow: 1 }}
value={deviceInfo?.videoDeviceId} onChange={async (e) => {
setDeviceInfo({
...deviceInfo,
videoDeviceId: e
})
}} />
</div>
<div>
<span></span>
<Select
placeholder={deviceInfo?.ecordingList?.length ? '请选择设备' : '未检测到麦克风'}
options={deviceInfo?.ecordingList} style={{ flexGrow: 1 }}
value={deviceInfo?.ecordingDeviceId} onChange={async (e) => {
setDeviceInfo({
...deviceInfo,
ecordingDeviceId: e
})
}} />;
</div>
<div>
<span></span>
<Slider value={deviceInfo.ecordingVolume} style={{ flexGrow: 1 }} max={255}
onChange={async (e) => {
setDeviceInfo({
...deviceInfo,
ecordingVolume: e
})
}} disabled={!deviceInfo.ecordingDeviceId} />
</div>
<div>
<span></span>
<Select
placeholder={deviceInfo?.playBackList?.length ? '请选择设备' : '未检测到麦克风'}
options={deviceInfo?.playBackList} style={{ flexGrow: 1 }}
value={deviceInfo?.playBackDeviceId} onChange={async (e) => {
setDeviceInfo({
...deviceInfo,
playBackDeviceId: e
})
}} />;
</div>
</div>
<div>
<Button type="primary" className='m-ant-btn' onClick={async () => {
await onInvoke('setDrivers', {
uid: callerUid,
driversJsonString: JSON.stringify(deviceInfo)
})
setEquipmentManagementModal(false)
message.success('设置成功')
}}></Button>
<Button type="primary"
style={{ backgroundColor: '#31353A', marginLeft: '10px' }}
onClick={() => setEquipmentManagementModal(false)}></Button>
</div>
</div>
</Modal >
</>
)
})
export default EquipmentManagement

View File

@ -8,7 +8,6 @@ import { PostRefresh } from '@/api/Login';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { agora } from '@/utils/package/agora'; import { agora } from '@/utils/package/agora';
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, () => ({
@ -72,7 +71,7 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
}) })
} }
const getRoomRtcToken = async (roomNum: string, callBack: Function): Promise<void> => { const getRoomRtcToken = async (roomNum: string, callBack: Function): Promise<void> => {
Promise.all([GetRoomRtcToken(roomNum), GetRoomRtcToken(roomNum + 'a')]).then(res => { Promise.all([GetRoomRtcToken(roomNum), GetRoomRtcToken(roomNum + '1')]).then(res => {
if (res[0].code === 200 && res[1].code === 200) { if (res[0].code === 200 && res[1].code === 200) {
callBack({ callBack({
token: res[0].data, token: res[0].data,
@ -85,7 +84,6 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
await PostRefresh(user.refresh_token).then(res => { await PostRefresh(user.refresh_token).then(res => {
if (res.code === 200) { if (res.code === 200) {
storage.setItem('user', JSON.stringify(res.data)) storage.setItem('user', JSON.stringify(res.data))
storage.setItem('userLogin', true)
callBack(res.data) callBack(res.data)
} }
}) })
@ -128,7 +126,7 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
{ {
joinRoomSettingForm.map((item, index) => { joinRoomSettingForm.map((item, index) => {
return <div key={index} onClick={async () => { return <div key={index} onClick={async () => {
if (role.ID.includes(user.roleId)) { if (user.roleId === '1') {
let msg = ''; let msg = '';
if (index === 0) { if (index === 0) {
await agora.getAudioMediaList().then(res => { await agora.getAudioMediaList().then(res => {

View File

@ -7,15 +7,14 @@ import {
VerticalAlignBottomOutlined VerticalAlignBottomOutlined
} from '@ant-design/icons'; } from '@ant-design/icons';
import { Button, Input, message, Modal, Pagination, Progress, Table } from 'antd'; import { Button, Input, message, Modal, Pagination, Progress, Table } from 'antd';
import { forwardRef, useEffect, useImperativeHandle, useState, useRef } from "react"; import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import { DeleteRoomFile, GetRoomFile, GetRoomFileDwUrl, GetRoomUpFileurl, GetRoomUserItem, PostRoomFile } from '@/api/Meeting'; import { DeleteRoomFile, GetRoomFile, GetRoomFileDwUrl, GetRoomUpFileurl, GetRoomUserItem, PostRoomFile } from '@/api/Meeting';
import axios from 'axios'; import axios from 'axios';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { storage } from '@/utils'; import { storage } from '@/utils';
import StupWizard from '../StupWizard';
import { role } from '@/config/role';
const fs = require('fs').promises; const fs = require('fs').promises;
const { exec } = require('child_process'); const { exec } = require('child_process');
const { Column } = Table const { Column } = Table
const SharedFilesModel = forwardRef((props: any, ref: any) => { const SharedFilesModel = forwardRef((props: any, ref: any) => {
@ -27,10 +26,8 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
setRoomUserItem(res.data) setRoomUserItem(res.data)
} }
}) })
getRoomFile()
} }
})) }))
const stupWizardRef = useRef<any>();
const { state } = useLocation(); const { state } = useLocation();
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [roomUserItem, setRoomUserItem] = useState<any>({}) const [roomUserItem, setRoomUserItem] = useState<any>({})
@ -129,7 +126,7 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
}) })
} }
}} /> }} />
{roomUserItem && role.ID.includes(roomUserItem.roleId) || roomUserItem.isRoomManager ? <ProfileOutlined title={showRowSelection ? '取消框选' : '显示框选'} onClick={() => { {roomUserItem && roomUserItem.roleId === '1' || roomUserItem.isRoomManager ? <ProfileOutlined title={showRowSelection ? '取消框选' : '显示框选'} onClick={() => {
setShowRowSelection(!showRowSelection) setShowRowSelection(!showRowSelection)
}} style={{ color: showRowSelection ? '#5575F2' : 'white' }} /> : null} }} style={{ color: showRowSelection ? '#5575F2' : 'white' }} /> : null}
{showRowSelection ? <DeleteOutlined title='删除' onClick={() => { {showRowSelection ? <DeleteOutlined title='删除' onClick={() => {
@ -313,11 +310,7 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
} }
} catch (error: any) { } catch (error: any) {
if (error.code === 'ENOENT') { if (error.code === 'ENOENT') {
message.error({ message.error('文件夹不存在!')
content: <div> <span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
stupWizardRef.current.changeModal(4)
}}></span></div>,
})
return return
} else { } else {
message.error(error) message.error(error)
@ -330,6 +323,7 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
}) })
} }
}) })
}} /> }} />
{/* <FolderOutlined title='文件' style={{ color: '#FFA000', cursor: 'pointer', marginLeft: '10px' }} /> */} {/* <FolderOutlined title='文件' style={{ color: '#FFA000', cursor: 'pointer', marginLeft: '10px' }} /> */}
</> </>
@ -350,7 +344,6 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
</div> </div>
</div> </div>
</Modal> </Modal>
<StupWizard ref={stupWizardRef} />
</> </>
) )
}) })

View File

@ -1,6 +1,6 @@
import styles from '@/components/StupWizard/index.module.scss' import styles from '@/components/StupWizard/index.module.scss'
import ImageUrl from '@/utils/package/imageUrl'; import ImageUrl from '@/utils/package/imageUrl';
import { Button, Checkbox, Empty, Input, message, Modal, Popover, Radio, Select, Slider, Space } from 'antd'; import { Button, Checkbox, Empty, Input, message, Modal, Popover, Radio, Select, Slider } from 'antd';
import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import { agora } from '@/utils/package/agora' import { agora } from '@/utils/package/agora'
import { CloseOutlined, LoadingOutlined, QuestionCircleOutlined } from '@ant-design/icons'; import { CloseOutlined, LoadingOutlined, QuestionCircleOutlined } from '@ant-design/icons';
@ -11,7 +11,7 @@ const fs = require('fs').promises;
const { exec } = require('child_process'); const { exec } = require('child_process');
const StupWizard = forwardRef((props: any, ref: any) => { const StupWizard = forwardRef((props: any, ref: any) => {
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
changeModal: (index: number = 0) => { changeModal: () => {
if (location.hash.indexOf('/meeting') === -1) { if (location.hash.indexOf('/meeting') === -1) {
agora.init() agora.init()
} }
@ -19,7 +19,7 @@ const StupWizard = forwardRef((props: any, ref: any) => {
res.forEach((item: any) => { res.forEach((item: any) => {
item.active = false item.active = false
}); });
res[index].active = true; res[0].active = true;
return res return res
}) })
setIsStupWizard(true) setIsStupWizard(true)
@ -243,8 +243,6 @@ const AudioComponents = () => {
ecordingActive: false, ecordingActive: false,
ecordingVolume: 0, ecordingVolume: 0,
autoEcordingVolume: true, autoEcordingVolume: true,
isAINoiseReduction: true,
aINoiseReduction: 1
}); });
const setting = JSON.parse(storage.getItem('setting') as string) const setting = JSON.parse(storage.getItem('setting') as string)
useEffect(() => { useEffect(() => {
@ -290,9 +288,7 @@ const AudioComponents = () => {
ecordingItem: setting.ecordingDeviceId, ecordingItem: setting.ecordingDeviceId,
ecordingVolume: setting.ecordingVolume, ecordingVolume: setting.ecordingVolume,
playBackVolume: setting.playBackVolume, playBackVolume: setting.playBackVolume,
autoEcordingVolume: setting.autoEcordingVolume, autoEcordingVolume: setting.autoEcordingVolume
isAINoiseReduction: setting.isAINoiseReduction,
aINoiseReduction: setting.aINoiseReduction,
}) })
} }
return ( return (
@ -354,38 +350,6 @@ const AudioComponents = () => {
}) })
}} disabled={!audioDeviceManager.ecordingItem} /> }} disabled={!audioDeviceManager.ecordingItem} />
</div> </div>
<div>
<div>
<Checkbox checked={audioDeviceManager.isAINoiseReduction} onChange={(e) => {
setting.isAINoiseReduction = e.target.checked;
storage.setItem('setting', JSON.stringify(setting))
setAudioDeviceManager({
...audioDeviceManager,
isAINoiseReduction: e.target.checked
})
agora.setAINSMode(e.target.checked, audioDeviceManager.aINoiseReduction)
}}>
AI降噪
</Checkbox>
</div>
<div style={{ margin: '10px 0 0 20px' }}>
<Radio.Group onChange={(e) => {
setting.aINoiseReduction = e.target.value;
storage.setItem('setting', JSON.stringify(setting))
setAudioDeviceManager({
...audioDeviceManager,
aINoiseReduction: e.target.value
})
agora.setAINSMode(audioDeviceManager.isAINoiseReduction, e.target.value)
}} disabled={!audioDeviceManager.isAINoiseReduction} value={audioDeviceManager.aINoiseReduction}>
<Space direction="vertical">
<Radio value={0}></Radio>
<Radio value={1}></Radio>
<Radio value={2}></Radio>
</Space>
</Radio.Group>
</div>
</div>
{/* <div> {/* <div>
<Checkbox onChange={async (e) => { <Checkbox onChange={async (e) => {
setting.autoEcordingVolume = e.target.checked; setting.autoEcordingVolume = e.target.checked;

View File

@ -22,7 +22,7 @@ const UpdateModal = forwardRef((props: any, ref: any) => {
const [updateContent, setUpdateContent] = useState('') // 版本更新内容 const [updateContent, setUpdateContent] = useState('') // 版本更新内容
function getContent() { function getContent() {
fetch(`https://meeting-api.23544.com/meeting/update/update.txt?t=${+new Date()}`) // 配置服务器地址 fetch(`https://update.23544.com/metting/update.txt?t=${+new Date()}`) // 配置服务器地址
.then(async response => { .then(async response => {
if (response.status === 200) { if (response.status === 200) {
return setUpdateContent(await response.text()) return setUpdateContent(await response.text())
@ -67,7 +67,7 @@ const UpdateModal = forwardRef((props: any, ref: any) => {
></Button> ></Button>
<div className={styles.button2} onClick={() => setIsUpdateModal(false)}></div> <div className={styles.button2} onClick={() => setIsUpdateModal(false)}></div>
</div> : progress < 100 ? </div> : progress < 100 ?
<div style={{ margin: '20px 0' }}> <div style={{ marginTop: '20px' }}>
{progress}% {progress}%
<Flex gap="small" vertical> <Flex gap="small" vertical>
<Progress percent={progress} showInfo={false} /> <Progress percent={progress} showInfo={false} />
@ -75,7 +75,7 @@ const UpdateModal = forwardRef((props: any, ref: any) => {
</div> : </div> :
<Button type="primary" <Button type="primary"
onClick={() => window.electron.onDownload('2')} onClick={() => window.electron.onDownload('2')}
style={{ width: '100%', height: '40px', margin: '20px 0' }} style={{ width: '100%', height: '40px', marginTop: '20px' }}
className={`m-ant-btn`} className={`m-ant-btn`}
></Button> ></Button>
} }

View File

@ -1,3 +0,0 @@
export const role = {
ID: ['1', '3']
}

View File

@ -1,21 +1,14 @@
import styles from '@/page/Home/Index/index.module.scss' import styles from '@/page/Home/Index/index.module.scss'
import { useEffect, useState, useRef } from "react"; import { useEffect, useState, useRef } from "react";
import Operation from '@/components/Operation'; import Operation from '@/components/Operation';
import { Button, Input, Modal, Pagination, Empty, message, Popover, Popconfirm, DatePicker } from "antd"; import { Button, Input, Modal, Pagination, Empty, message } from "antd";
import { GetRoom, PostRoom, GetCheckoutRoomNum, GetRoomRtcToken, DeleteRoom, GetRecord } from '@/api/Home/Index'; import { GetRoom, PostRomm, GetCheckoutRoomNum, GetRoomRtcToken } from '@/api/Home/Index';
import ImageUrl from '@/utils/package/imageUrl' import ImageUrl from '@/utils/package/imageUrl'
import { ExclamationCircleFilled, ReloadOutlined } from '@ant-design/icons'; import { ReloadOutlined } from '@ant-design/icons';
import JoinSetting from '@/components/JoinSetting'; import JoinSetting from '@/components/JoinSetting';
import { storage } from '@/utils'; import { storage } from '@/utils';
import { PostRefresh } from '@/api/Login'; import { PostRefresh } from '@/api/Login';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { role } from '@/config/role';
import dayjs from 'dayjs';
import StupWizard from '@/components/StupWizard';
const fs = require('fs').promises;
const { exec } = require('child_process');
const { RangePicker } = DatePicker;
const { confirm } = Modal;
const Index: React.FC = () => { const Index: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const [list, setList] = useState({ const [list, setList] = useState({
@ -25,15 +18,12 @@ const Index: React.FC = () => {
pageSize: 12, pageSize: 12,
}) })
const [createRoomModal, setCreateRoomModal] = useState(false) const [createRoomModal, setCreateRoomModal] = useState(false)
const [timeSelectModal, setTimeSelectModal] = useState(false)
const [createRoomFrom, setCreateRoomFrom] = useState<{ roomName: string, roomNum: string }>({ const [createRoomFrom, setCreateRoomFrom] = useState<{ roomName: string, roomNum: string }>({
roomName: "", roomName: "",
roomNum: "" roomNum: ""
}) })
const joinSettingRef = useRef<any>(); const joinSettingRef = useRef<any>();
const stupWizardRef = useRef<any>();
const [user, setUser] = useState<any>({}); const [user, setUser] = useState<any>({});
const [currentRoomInfo, setCurrentRoomInfo] = useState<any>({});
const userInfo = JSON.parse(storage.getItem('user') as string) const userInfo = JSON.parse(storage.getItem('user') as string)
useEffect(() => { useEffect(() => {
setUser(userInfo) setUser(userInfo)
@ -80,7 +70,7 @@ const Index: React.FC = () => {
}) })
} }
const getRoomRtcToken = async (roomNum: string, callBack: Function): Promise<void> => { const getRoomRtcToken = async (roomNum: string, callBack: Function): Promise<void> => {
Promise.all([GetRoomRtcToken(roomNum), GetRoomRtcToken(roomNum + 'a')]).then(res => { Promise.all([GetRoomRtcToken(roomNum), GetRoomRtcToken(roomNum + '1')]).then(res => {
if (res[0].code === 200 && res[1].code === 200) { if (res[0].code === 200 && res[1].code === 200) {
callBack({ callBack({
token: res[0].data, token: res[0].data,
@ -93,59 +83,10 @@ const Index: React.FC = () => {
await PostRefresh(user.refresh_token).then(res => { await PostRefresh(user.refresh_token).then(res => {
if (res.code === 200) { if (res.code === 200) {
storage.setItem('user', JSON.stringify(res.data)) storage.setItem('user', JSON.stringify(res.data))
storage.setItem('userLogin', true)
callBack(res.data) callBack(res.data)
} }
}) })
} }
const changeOpen = (index: number, bool: boolean): void => {
const newList = [...list.data] as any;
newList[index].open = bool
setList({
...list,
data: newList
})
}
const fileUpLoad = async (data: { url: string, content: string, fileName: string }): Promise<void> => {
const setting = await JSON.parse(storage.getItem('setting') as string)
try {
const response = await fetch(data.url);
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
await fs.writeFile(`${setting.shareFilesPath}\\${data.fileName}`, buffer, {});
confirm({
title: '提示',
icon: <ExclamationCircleFilled />,
content: data.content,
centered: true,
okText: '打开文件夹',
cancelText: '关闭',
async onOk() {
await fs.access(setting.shareFilesPath, fs.constants.F_OK);
if (process.platform === 'win32') {
exec(`explorer "${setting.shareFilesPath}"`);
} else if (process.platform === 'darwin') {
exec(`open "${setting.shareFilesPath}"`);
}
},
onCancel() {
}
})
} catch (error: any) {
if (error.code === 'ENOENT') {
message.error({
content: <div> <span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
stupWizardRef.current.changeModal(4)
}}></span></div>
})
return
} else {
message.error(error)
}
}
}
return ( return (
<> <>
<div className={styles.index}> <div className={styles.index}>
@ -206,52 +147,12 @@ const Index: React.FC = () => {
<img src={ImageUrl.icon10} alt="" /> <img src={ImageUrl.icon10} alt="" />
</div> </div>
<div> <div>
<Popover
content={ {/* <Button type="primary" danger>设置</Button> */}
<div className='meetingContentFooterPopover'>
<Popconfirm
title="提示"
description={`确定删除该会议吗`}
onConfirm={async () => {
DeleteRoom(item.id).then((res) => {
if (res.code === 200) {
message.success('删除成功')
changeOpen(index, false)
getRoomList()
}
})
}}
onCancel={() => {
changeOpen(index, false)
}}
okText="确定"
cancelText="取消"
>
<div></div>
</Popconfirm>
<div onClick={() => {
changeOpen(index, false)
setTimeSelectModal(true)
}}></div>
<div onClick={() => {
changeOpen(index, false)
}}></div>
</div>
}
title=""
trigger="click"
open={item.open}
onOpenChange={() => {
setCurrentRoomInfo(list.data[index])
changeOpen(index, true)
}}
>
<Button type="primary" danger></Button>
</Popover>
<Button type="primary" <Button type="primary"
iconPosition={'end'} iconPosition={'end'}
onClick={async () => { onClick={async () => {
if (role.ID.includes(userInfo.roleId)) { if (userInfo.roleId === '1') {
joinSettingRef.current.changeModal(item.roomNum) joinSettingRef.current.changeModal(item.roomNum)
} else { } else {
postRefresh(() => { postRefresh(() => {
@ -366,7 +267,7 @@ const Index: React.FC = () => {
if (bool) { if (bool) {
message.error('房间号已存在!') message.error('房间号已存在!')
} else { } else {
PostRoom(createRoomFrom).then(res => { PostRomm(createRoomFrom).then(res => {
if (res.code === 200) { if (res.code === 200) {
message.success('创建成功!') message.success('创建成功!')
setCreateRoomModal(false) setCreateRoomModal(false)
@ -379,32 +280,7 @@ const Index: React.FC = () => {
</div> </div>
</div> </div>
</Modal> </Modal>
<Modal title="选择时间段" destroyOnClose={true} open={timeSelectModal} footer={null} onCancel={() => setTimeSelectModal(false)} centered width={'400px'}>
<div>
<RangePicker
showTime={{ format: 'YYYY-MM-DD HH:mm:ss' }}
format="YYYY-MM-DD HH:mm:ss"
onChange={(_value, dateString) => {
const setting = JSON.parse(storage.getItem('setting') as string)
if (dateString.length === 2) {
GetRecord(dayjs(dateString[0]).unix(), dayjs(dateString[1]).unix(), currentRoomInfo.roomNum).then(res => {
if (res.code === 200) {
const fileName = res.data.split('/').pop().split('?')[0];
fileUpLoad({
url: res.data,
content: `下载参会记录成功!文件已保存至:${setting.shareFilesPath}`,
fileName
})
}
setTimeSelectModal(false)
})
}
}}
/>
</div>
</Modal>
<JoinSetting ref={joinSettingRef} /> <JoinSetting ref={joinSettingRef} />
<StupWizard ref={stupWizardRef} />
</> </>
) )
} }

View File

@ -21,14 +21,11 @@
display: flex; display: flex;
align-items: center; align-items: center;
>button {
margin-right: 22px;
}
.userBtnsDel { .userBtnsDel {
background-color: #3A1457; background-color: #3A1457;
box-shadow: none; box-shadow: none;
color: white; color: white;
margin-left: 22px;
&:hover { &:hover {
background-color: lighten(#3A1457, 5%) !important; background-color: lighten(#3A1457, 5%) !important;

View File

@ -1,19 +1,13 @@
import styles from '@/page/Home/User/index.module.scss' import styles from '@/page/Home/User/index.module.scss'
import { useEffect, useState, useRef } from "react"; import { useEffect, useState } from "react";
import Operation from '@/components/Operation'; import Operation from '@/components/Operation';
import { Button, Input, Table, Pagination, Modal, message, Select } from "antd"; import { Button, Input, Table, Pagination, Modal, message, Select } from "antd";
import { ExclamationCircleFilled, SearchOutlined } from '@ant-design/icons'; import { SearchOutlined } from '@ant-design/icons';
import { GetUserList, PostUser, PutUser, DeleteUser, PutUserPwd, GetRoleDpList, PostUserImport } from '@/api/Home/User'; import { GetUserList, PostUser, PutUser, DeleteUser, PutUserPwd, GetRoleDpList } from '@/api/Home/User';
import * as CryptoJS from 'crypto-js'; import * as CryptoJS from 'crypto-js';
import ImageUrl from '@/utils/package/imageUrl'; import ImageUrl from '@/utils/package/imageUrl';
import { storage } from '@/utils';
import StupWizard from '@/components/StupWizard';
const { Column } = Table const { Column } = Table
const { confirm } = Modal;
const { exec } = require('child_process');
const fs = require('fs').promises;
const User: React.FC = () => { const User: React.FC = () => {
const stupWizardRef = useRef<any>();
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [isCreateUser, setIsCreateUser] = useState(false); const [isCreateUser, setIsCreateUser] = useState(false);
const [list, setList] = useState({ const [list, setList] = useState({
@ -33,7 +27,6 @@ const User: React.FC = () => {
UserName: "" UserName: ""
}) })
const [changeUserPawModal, setChangeUserPawModal] = useState(false) const [changeUserPawModal, setChangeUserPawModal] = useState(false)
const [changeImportModal, setChangeImportModal] = useState(false)
const [changeUserPawFrom, setChangeUserPawFrom] = useState({ const [changeUserPawFrom, setChangeUserPawFrom] = useState({
Pwd: "", Pwd: "",
newPwd: '', newPwd: '',
@ -79,46 +72,6 @@ const User: React.FC = () => {
} }
}) })
} }
const fileUpLoad = async (data: { url: string, content: string, fileName: string }): Promise<void> => {
const setting = await JSON.parse(storage.getItem('setting') as string)
try {
const response = await fetch(data.url);
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
await fs.writeFile(`${setting.shareFilesPath}\\${data.fileName}`, buffer, {});
setChangeImportModal(false)
confirm({
title: '提示',
icon: <ExclamationCircleFilled />,
content: data.content,
centered: true,
okText: '打开文件夹',
cancelText: '关闭',
async onOk() {
await fs.access(setting.shareFilesPath, fs.constants.F_OK);
if (process.platform === 'win32') {
exec(`explorer "${setting.shareFilesPath}"`);
} else if (process.platform === 'darwin') {
exec(`open "${setting.shareFilesPath}"`);
}
},
onCancel() {
}
})
} catch (error: any) {
if (error.code === 'ENOENT') {
message.error({
content: <div> <span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
stupWizardRef.current.changeModal(4)
}}></span></div>
})
return
} else {
message.error(error)
}
}
}
return ( return (
<> <>
<div className={styles.user}> <div className={styles.user}>
@ -147,13 +100,6 @@ const User: React.FC = () => {
className='m-ant-btn'> className='m-ant-btn'>
</Button> </Button>
<Button type="primary"
onClick={() => {
setChangeImportModal(true)
}}
className='m-ant-btn'>
</Button>
<Button type="primary" <Button type="primary"
icon={<img src={ImageUrl.icon21} alt="" />} icon={<img src={ImageUrl.icon21} alt="" />}
className={styles.userBtnsDel} className={styles.userBtnsDel}
@ -275,14 +221,17 @@ const User: React.FC = () => {
<Input <Input
style={{ flexGrow: 1 }} style={{ flexGrow: 1 }}
placeholder="请输入账号" placeholder="请输入账号"
maxLength={30} maxLength={11}
showCount={true} showCount={true}
value={addUserFrom.Account} value={addUserFrom.Account}
onChange={(e) => { onChange={(e) => {
const regex = /^[0-9]*$/;
if (regex.test(e.target.value)) {
setAddUserFrom({ setAddUserFrom({
...addUserFrom, ...addUserFrom,
Account: e.target.value, Account: e.target.value,
}); });
}
}} }}
/> />
</div> </div>
@ -451,69 +400,6 @@ const User: React.FC = () => {
</div> </div>
</div> </div>
</Modal> </Modal>
<Modal title='批量导入用户' open={changeImportModal} onCancel={() => setChangeImportModal(false)} footer={null} centered width={'300px'}>
<div>
<div>
<Button type="primary" className='m-ant-btn' style={{ width: '100%', marginBottom: '10px' }}
onClick={async () => {
const setting = await JSON.parse(storage.getItem('setting') as string)
await fileUpLoad({
url: 'https://wgshare.oss-cn-chengdu.aliyuncs.com/%E7%94%A8%E6%88%B7%E6%89%B9%E9%87%8F%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF%E8%A1%A8.xlsx',
content: `下载导入模板成功!文件已保存至:${setting.shareFilesPath}`,
fileName: `用户批量导入模板表_${+new Date()}.xlsx`
})
}}
>
</Button>
</div>
<div>
<Button type="primary" className='m-ant-btn' style={{ width: '100%' }}
onClick={() => {
const file = document.createElement("input") as any;
file.type = "file";
file.accept = ".xls,.xlsx";
file.onchange = async () => {
const setting = await JSON.parse(storage.getItem('setting') as string)
const fileInfo = file.files[0];
const formData = new FormData();
formData.append("file", fileInfo);
await PostUserImport(formData).then(res => {
if (res.code === 200) {
if (res.data.item1) {
if (list.pageIndex === 1) {
getUserList()
} else {
setList({
...list,
pageIndex: 1
})
}
message.success(res.data.item3)
} else {
if (res.data.item2) {
const fileName = res.data.item2.split('/').pop().split('?')[0];
fileUpLoad({
url: res.data.item2,
content: `导入模板失败!失败文件已保存至:${setting.shareFilesPath}`,
fileName
})
}
message.error(res.data.item3)
}
}
})
setChangeImportModal(false)
};
file.click();
}}
>
</Button>
</div>
</div>
</Modal>
<StupWizard ref={stupWizardRef} />
</> </>
) )
} }

View File

@ -139,8 +139,8 @@ const Home: React.FC = () => {
title="提示" title="提示"
description="确认退出吗?" description="确认退出吗?"
onConfirm={() => { onConfirm={() => {
navigate('/login')
storage.removeItem('user') storage.removeItem('user')
storage.setItem('userLogin', false)
}} }}
onCancel={() => { onCancel={() => {

View File

@ -140,13 +140,10 @@ const Login: React.FC = () => {
optionsValue: operation.optionsValue, optionsValue: operation.optionsValue,
})) }))
storage.setItem('user', JSON.stringify(res.data)) storage.setItem('user', JSON.stringify(res.data))
storage.setItem('userLogin', true)
try { try {
window.electron.getWindowSize().then((res: any) => {
window.electron.setMainWindowSize({ window.electron.setMainWindowSize({
width: Math.ceil(res.width / 1.5), width: 1200,
height: Math.ceil(res.height / 1.3), height: 800,
})
}) })
} catch { } catch {

View File

@ -31,32 +31,9 @@
>img { >img {
width: 18px; width: 18px;
}
>label {
height: 18px;
width: 18px;
position: relative;
>img {
width: 100%;
height: 100%;
margin-right: 4px; margin-right: 4px;
} }
>div {
position: absolute;
left: 0;
bottom: 0;
height: 0%;
width: 100%;
overflow: hidden;
background-repeat: no-repeat;
background-position: bottom center;
background-size: cover;
}
}
>span { >span {
font-size: 13px; font-size: 13px;
color: #EEEEEE; color: #EEEEEE;
@ -183,7 +160,6 @@
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
position: relative; position: relative;
overflow: hidden;
.standardModeIcon { .standardModeIcon {
position: absolute; position: absolute;
@ -233,7 +209,6 @@
} }
} }
// 自由者模式 // 自由者模式
.meetingContentBodyLeftFreedomMode { .meetingContentBodyLeftFreedomMode {
width: 100%; width: 100%;
@ -307,7 +282,7 @@
position: absolute !important; position: absolute !important;
bottom: 0; bottom: 0;
left: 0; left: 0;
height: calc(100% - 170px) !important; height: calc(100% - 160px) !important;
width: 100% !important; width: 100% !important;
z-index: 2; z-index: 2;
} }
@ -368,7 +343,6 @@
} }
} }
.meetingContentSwiperCardFullScreenIcon { .meetingContentSwiperCardFullScreenIcon {
position: absolute; position: absolute;
z-index: 3; z-index: 3;
@ -420,14 +394,33 @@
padding: 10px 20px; padding: 10px 20px;
white-space: nowrap; white-space: nowrap;
} }
.meetingContentSwiperCardBorder {
position: absolute;
height: 3px;
width: calc(100% - 20px);
background-color: #2C2C2C;
overflow: hidden;
left: 10px;
z-index: 1;
bottom: 9px;
>div {
background-color: #5575F2;
position: absolute;
height: 3px;
left: 0;
top: 0;
}
}
} }
.meetingContentBodyRight { .meetingContentBodyRight {
width: 300px;
flex-shrink: 0; flex-shrink: 0;
height: 100%; height: 100%;
.meetingUserList { .meetingUserList {
width: 300px;
height: 100%; height: 100%;
padding: 10px 0 20px; padding: 10px 0 20px;
box-sizing: border-box; box-sizing: border-box;
@ -542,7 +535,6 @@
} }
.meetingUserChat { .meetingUserChat {
width: 300px;
height: 100%; height: 100%;
background-color: #16191E; background-color: #16191E;
display: flex; display: flex;
@ -661,39 +653,6 @@
border-top: 1px solid #23272E; border-top: 1px solid #23272E;
} }
} }
.meetingUserVideoList {
padding: 10px 10px 10px;
box-sizing: border-box;
height: 100%;
background-color: #16191E;
display: flex;
flex-direction: column;
.meetingUserVideoListTitle {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
>span {
color: #EEEEEE;
font-size: 18px;
}
>img {
cursor: pointer;
}
}
.meetingUserVideoListContent {
flex-grow: 1;
height: 0px;
overflow-y: auto;
box-sizing: border-box;
}
}
} }
} }
@ -725,7 +684,7 @@
} }
>img { >img {
height: 50px; height: 30px;
} }
>span { >span {
@ -746,31 +705,6 @@
right: -10px; right: -10px;
} }
>label {
height: 50px;
height: 50px;
cursor: pointer;
position: relative;
>img {
width: 100%;
height: 100%;
margin-right: 4px;
}
>div {
position: absolute;
left: 0;
bottom: 0;
height: 0%;
width: 100%;
overflow: hidden;
background-repeat: no-repeat;
background-position: bottom center;
background-size: cover;
}
}
&:hover { &:hover {
background-color: #161A29; background-color: #161A29;
} }

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,13 +1,14 @@
import styles from '@/components/UserVideo/index.module.scss'
import { GetPolling } from '@/api/Meeting'; import { GetPolling } from '@/api/Meeting';
import styles from '@/page/UserVideo/index.module.scss'
import { storage } from '@/utils';
import { agora } from '@/utils/package/agora'; import { agora } from '@/utils/package/agora';
import { CloseOutlined } from '@ant-design/icons';
import { Button, Empty, Select, message } from 'antd'; import { Button, Empty, Select, message } from 'antd';
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useLocation } from 'react-router';
import { VideoStreamType } from 'agora-electron-sdk';
const UserVideo: React.FC = () => { const UserVideo: React.FC = () => {
const { state } = useLocation(); let userInfo = JSON.parse(storage.getItem('user') as string)
const [user, setUser] = useState<any>({});
const [from, setFrom] = useState<any>({ const [from, setFrom] = useState<any>({
cycleIntervalList: [ cycleIntervalList: [
{ value: 30, label: '30秒' }, { value: 30, label: '30秒' },
@ -17,16 +18,19 @@ const UserVideo: React.FC = () => {
], ],
cycleIntervalValue: 30, cycleIntervalValue: 30,
viewPeople: [ viewPeople: [
{ value: 6, label: '6人' }, { value: 4, label: '4人' },
{ value: 8, label: '8人' },
{ value: 12, label: '12人' }, { value: 12, label: '12人' },
// { value: 20, label: '20人' }, { value: 16, label: '16人' },
{ value: 20, label: '20人' },
], ],
viewPeopleValue: 6, viewPeopleValue: 4,
}) })
const [timeNumber, setTimeNumber] = useState(30); const [timeNumber, setTimeNumber] = useState(30);
const [timeStatus, setTimeStatus] = useState(false); const [timeStatus, setTimeStatus] = useState(false);
const [userList, setUserList] = useState([]); const [userList, setUserList] = useState([]);
useEffect(() => { useEffect(() => {
setUser(userInfo)
window.addEventListener('customStorageChange', handleCustomStorageChange); window.addEventListener('customStorageChange', handleCustomStorageChange);
return () => { return () => {
window.removeEventListener('customStorageChange', handleCustomStorageChange); window.removeEventListener('customStorageChange', handleCustomStorageChange);
@ -59,14 +63,12 @@ const UserVideo: React.FC = () => {
}, [from.viewPeopleValue]) }, [from.viewPeopleValue])
useEffect(() => { useEffect(() => {
userList.forEach(async (item: any) => { userList.forEach((item: any) => {
await agora.destroyRendererByConfig(Number('1' + item.screenShareId)) // agora.meetingMonitoringSetupRemoteVideoJoin({
await agora.setupRemoteVideoEx({ // uid: Number('1' + item.screenShareId),
uid: Number('1' + item.screenShareId), // view: document.getElementById(`video-${item.uid}`),
view: document.getElementById(`video-${item.screenShareId}`), // channelId: getQueryParameterRegex('channelId'),
channelId: state.channelId + 'a', // })
})
await agora.setRemoteVideoStreamType(Number('1' + item.screenShareId), VideoStreamType.VideoStreamLow, false)
}) })
}, [userList]) }, [userList])
// 监听缓存变化 // 监听缓存变化
@ -75,22 +77,30 @@ const UserVideo: React.FC = () => {
} }
}; };
// 获取地址栏参数
const getQueryParameterRegex = (name: string): string | null => {
const reg = new RegExp(`[?&]${name}=([^&#]*)`);
const results = window.location.href.match(reg);
return results === null ? null : results[1];
}
// 获取轮训用户 // 获取轮训用户
const getPolling = async (): Promise<void> => { const getPolling = async (): Promise<void> => {
setUserList([]) GetPolling(getQueryParameterRegex('channelId')?.split('1')[0] as string, from.viewPeopleValue).then((res: any) => {
setFrom((res: any) => {
GetPolling(state.channelId?.split('a')[0] as string, res.viewPeopleValue).then((res: any) => {
if (res.code === 200) { if (res.code === 200) {
setUserList(res.data) setUserList(res.data)
} }
}) })
return res
})
}; };
return ( return (
<> <>
<div className={styles.userVideo}> <div className={styles.userVideo}>
<div className={`${styles.userVideoContent}`}> <div className={styles.userVideoTitle}>
<CloseOutlined className='drag' onClick={() => {
window.electron.closeMonitorWindow()
}} />
</div>
<div className={`${styles.userVideoContent} drag`}>
<div className={styles.userVideoContentHeader}> <div className={styles.userVideoContentHeader}>
<div> <div>
<div> <div>
@ -98,7 +108,6 @@ const UserVideo: React.FC = () => {
<Select <Select
placeholder='请选择循环间隔' placeholder='请选择循环间隔'
options={from.cycleIntervalList} options={from.cycleIntervalList}
size={'small'}
value={from.cycleIntervalValue} onChange={(e) => { value={from.cycleIntervalValue} onChange={(e) => {
setFrom({ ...from, cycleIntervalValue: e }) setFrom({ ...from, cycleIntervalValue: e })
setTimeNumber(e) setTimeNumber(e)
@ -109,7 +118,6 @@ const UserVideo: React.FC = () => {
<Select <Select
placeholder='请选择查看人数' placeholder='请选择查看人数'
options={from.viewPeople} options={from.viewPeople}
size={'small'}
value={from.viewPeopleValue} onChange={(e) => { value={from.viewPeopleValue} onChange={(e) => {
setFrom({ ...from, viewPeopleValue: e }) setFrom({ ...from, viewPeopleValue: e })
}} /> }} />
@ -119,7 +127,6 @@ const UserVideo: React.FC = () => {
<span>{timeNumber}</span> <span>{timeNumber}</span>
{timeStatus ? <Button {timeStatus ? <Button
type="primary" type="primary"
size={'small'}
onClick={() => { onClick={() => {
setTimeStatus(!timeStatus) setTimeStatus(!timeStatus)
}} }}
@ -128,7 +135,6 @@ const UserVideo: React.FC = () => {
<Button <Button
type="primary" type="primary"
className='m-ant-btn' className='m-ant-btn'
size={'small'}
onClick={() => { onClick={() => {
setTimeStatus(!timeStatus) setTimeStatus(!timeStatus)
}} }}
@ -139,8 +145,8 @@ const UserVideo: React.FC = () => {
{ {
userList.map((item: any, index: number) => { userList.map((item: any, index: number) => {
return <div className={styles.userVideoContentListItem} key={index}> return <div className={styles.userVideoContentListItem} key={index}>
<div className={styles.userVideoContentListItemVideo} id={`video-${item.screenShareId}`}> <div className={styles.userVideoContentListItemVideo} id={`video-${item.uid}`}>
<div>{item.userName}{item.isRoomManager ? '(发言中)' : ''}</div>
</div> </div>
</div> </div>
}) })

4
src/render.d.ts vendored
View File

@ -1,7 +1,6 @@
// electron-env.d.ts // electron-env.d.ts
export interface IElectronAPI { export interface IElectronAPI {
setMainWindowSize: (config: any) => void; setMainWindowSize: (config: any) => void;
getWindowSize: () => any;
setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize' | 'hide') => void; setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize' | 'hide') => void;
getIsMaximized: () => Promise<boolean>; getIsMaximized: () => Promise<boolean>;
setWriteText: (text: string) => void; setWriteText: (text: string) => void;
@ -16,6 +15,9 @@ export interface IElectronAPI {
downFile: (callBack: Function) => void; downFile: (callBack: Function) => void;
quitAndInstall: (callBack: Function) => void; quitAndInstall: (callBack: Function) => void;
getVersion: () => Promise<string>; getVersion: () => Promise<string>;
oepnWindow: (data: any) => any;
closeMonitorWindow: () => void
} }
declare global { declare global {

View File

@ -5,16 +5,12 @@ import {
VideoViewSetupMode, VideoViewSetupMode,
ScreenCaptureSourceType, ScreenCaptureSourceType,
RenderModeType, RenderModeType,
ChannelProfileType, ChannelProfileType
AudioAinsMode,
SimulcastStreamMode,
VideoStreamType
} from "agora-electron-sdk"; } from "agora-electron-sdk";
import { GetRoomRtcToken, GetAgoraConf } from "@/api/Home/Index"; import { GetRoomRtcToken } from "@/api/Home/Index";
import { storage } from '@/utils'; import { storage } from '@/utils';
import { role } from "@/config/role";
const option: any = { const option: any = {
appId: '', appId: 'dcfc466a6ecb4a1f972630065dfb1e75',
token: '', token: '',
tokenA: '', tokenA: '',
channelId: '', channelId: '',
@ -25,14 +21,11 @@ let rtcEngine: any = '';
export const agora = { export const agora = {
// 初始化 // 初始化
init: async (bool: boolean = false) => { init: async (bool: boolean = false) => {
const { data } = await GetAgoraConf();
if (data) {
rtcEngine = createAgoraRtcEngine(); rtcEngine = createAgoraRtcEngine();
await rtcEngine.initialize({ await rtcEngine.initialize({
appId: data, appId: option.appId,
}); });
await agora.setDeviceManager(bool) await agora.setDeviceManager(bool)
}
}, },
// 获取rtcEngine // 获取rtcEngine
getRtcEngine: () => { getRtcEngine: () => {
@ -99,7 +92,6 @@ export const agora = {
if (setting.playBackVolume) agora.setPlaybackDeviceVolume(setting.playBackVolume) // 设置播放设备音量 if (setting.playBackVolume) agora.setPlaybackDeviceVolume(setting.playBackVolume) // 设置播放设备音量
if (setting.ecordingDeviceId) agora.setRecordingDevice(setting.ecordingDeviceId) // 设置音频采集设备 if (setting.ecordingDeviceId) agora.setRecordingDevice(setting.ecordingDeviceId) // 设置音频采集设备
if (setting.ecordingVolume) agora.setRecordingDeviceVolume(setting.ecordingVolume) // 设置音频设备音量 if (setting.ecordingVolume) agora.setRecordingDeviceVolume(setting.ecordingVolume) // 设置音频设备音量
if (setting.isAINoiseReduction) agora.setAINSMode(setting.isAINoiseReduction, setting.aINoiseReduction) // 设置ai降噪
} }
}, 1000); }, 1000);
}, },
@ -171,20 +163,6 @@ export const agora = {
); );
} }
}, },
setupRemoteVideoEx: async (item: any) => {
if (item.view?.childNodes.length === 1) {
await rtcEngine.setupRemoteVideoEx(
{
renderMode: agora.getRrenderMode(item.uid),
sourceType: VideoSourceType.VideoSourceRemote,
uid: item.uid,
view: item.view,
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
},
{ channelId: item.channelId },
);
}
},
// 退出 // 退出
setupRemoteVideo: async (item: any) => { setupRemoteVideo: async (item: any) => {
await rtcEngine.setupRemoteVideo( await rtcEngine.setupRemoteVideo(
@ -215,17 +193,6 @@ export const agora = {
joinChannel: async () => { joinChannel: async () => {
await rtcEngine.enableAudioVolumeIndication(100, 1, true) await rtcEngine.enableAudioVolumeIndication(100, 1, true)
await rtcEngine.joinChannel(option.token, option.channelId, option.uid); await rtcEngine.joinChannel(option.token, option.channelId, option.uid);
await rtcEngine.setDualStreamModeEx(
SimulcastStreamMode.EnableSimulcastStream,
{
dimensions: {
width: 320,
height: 180
},
framerate: 5,
},
{ channelId: option.channelId, localUid: Number(option.uid) }
);
}, },
// 更新频道配置 // 更新频道配置
updateChannelMediaOptions: async (bool: boolean) => { updateChannelMediaOptions: async (bool: boolean) => {
@ -238,14 +205,6 @@ export const agora = {
publishScreenTrack: false,//设置是否发布屏幕采集的视频 publishScreenTrack: false,//设置是否发布屏幕采集的视频
}) })
}, },
// 设置接收大小流
setRemoteVideoStreamType: async (uid: number, type: VideoStreamType, bool: boolean) => {
await rtcEngine.setRemoteVideoStreamTypeEx(
Number(uid),
type,
bool ? { channelId: option.channelId, localUid: Number(option.uid) } : { channelId: option.channelId + 'a', localUid: Number('1' + option.screenShareId) }
)
},
// 共享屏幕单独用户 // 共享屏幕单独用户
joinChannelEx: async (uid: any) => { joinChannelEx: async (uid: any) => {
await agora.leaveChannelEx(uid) await agora.leaveChannelEx(uid)
@ -263,53 +222,26 @@ export const agora = {
); );
}, },
// 所有用户加入的第二个房间 // 所有用户加入的第二个房间
allJoinChannelEx: async (bool: boolean = false) => { allJoinChannelEx: async () => {
const user = await JSON.parse(storage.getItem('user') as string)
await agora.startCameraCapture(true)
await rtcEngine.joinChannelEx( await rtcEngine.joinChannelEx(
option.tokenA, option.tokenA,
{ channelId: option.channelId + 'a', localUid: Number('1' + option.screenShareId) }, { channelId: option.channelId + '1', localUid: Number('1' + option.screenShareId) },
{ {}
clientRoleType: bool ? ClientRoleType.ClientRoleAudience : ClientRoleType.ClientRoleBroadcaster, //用户角色 ClientRoleBroadcaster 主播 ClientRoleAudience 观众 );
await agora.updateChannelMediaOptionsEx(false)
},
updateChannelMediaOptionsEx: async (bool: boolean) => {
rtcEngine.updateChannelMediaOptionsEx({
clientRoleType: bool ? ClientRoleType.ClientRoleBroadcaster : ClientRoleType.ClientRoleAudience, //用户角色 ClientRoleBroadcaster 主播 ClientRoleAudience 观众
autoSubscribeAudio: false,//设置是否自动订阅所有音频流 autoSubscribeAudio: false,//设置是否自动订阅所有音频流
autoSubscribeVideo: role.ID.includes(user.roleId) ? true : false,//设置是否自动订阅所有视频流 autoSubscribeVideo: true,//设置是否自动订阅所有视频流
publishMicrophoneTrack: false,//设置是否发布麦克风采集到的音频 publishMicrophoneTrack: true,//设置是否发布麦克风采集到的音频
publishCameraTrack: true,//设置是否发布摄像头采集的视频 publishCameraTrack: true,//设置是否发布摄像头采集的视频
publishScreenTrack: false,//设置是否发布屏幕采集的视频 publishScreenTrack: false,//设置是否发布屏幕采集的视频
} }, {
); channelId: option.channelId + '1',
await rtcEngine.setDualStreamModeEx( localUid: Number('1' + option.screenShareId)
SimulcastStreamMode.EnableSimulcastStream, })
{
dimensions: {
width: 320,
height: 180
},
framerate: 5,
},
{ channelId: option.channelId + 'a', localUid: Number('1' + option.screenShareId) }
);
},
// 退出第二个房间
allLeaveChannelEx: async () => {
await agora.stopCameraCapture();
await rtcEngine.leaveChannelEx({ channelId: option.channelId + 'a', localUid: Number('1' + option.screenShareId) })
},
// 停止/恢复接收指定的视频流。
muteRemoteVideoStreamEx: async (uid: number, mute: boolean) => {
await rtcEngine.muteRemoteVideoStreamEx(uid, mute, { channelId: option.channelId, localUid: Number(option.uid) })
},
// 取消或恢复订阅指定远端用户的音频流
muteRemoteVideoStream: async (uid: number, mute: boolean) => {
rtcEngine.muteRemoteVideoStream(uid, mute)
},
// 销毁视频渲染dom
destroyRendererByConfig: async (uid: number) => {
await rtcEngine.destroyRendererByConfig(VideoSourceType.VideoSourceRemote, option.channelId + 'a', uid);
},
// ai降噪
setAINSMode: async (enabled: boolean, mode: AudioAinsMode) => {
rtcEngine.setAINSMode(enabled, mode)
}, },
// 离开共享屏幕频道 // 离开共享屏幕频道
leaveChannelEx: async (uid: any) => { leaveChannelEx: async (uid: any) => {
@ -321,27 +253,19 @@ export const agora = {
rtcEngine.enableLoopbackRecording(false) rtcEngine.enableLoopbackRecording(false)
}, },
// 取消或恢复发布本地音频流 // 取消或恢复发布本地音频流
muteLocalAudioStream: async (data: any, mute: any) => { muteLocalAudioStream: async (mute: any) => {
// await rtcEngine.muteLocalAudioStream(mute) await rtcEngine.muteLocalAudioStream(mute)
await rtcEngine.updateChannelMediaOptions({
clientRoleType: data ? ClientRoleType.ClientRoleBroadcaster : ClientRoleType.ClientRoleAudience, //用户角色 ClientRoleBroadcaster 主播 ClientRoleAudience 观众
autoSubscribeAudio: true,//设置是否自动订阅所有音频流
autoSubscribeVideo: true,//设置是否自动订阅所有视频流
publishMicrophoneTrack: mute,//设置是否发布麦克风采集到的音频
publishCameraTrack: true,//设置是否发布摄像头采集的视频
publishScreenTrack: false,//设置是否发布屏幕采集的视频
})
}, },
// 取消或恢复发布本地视频流 // 取消或恢复发布本地视频流
muteLocalVideoStream: async (mute: any) => { muteLocalVideoStream: async (mute: any) => {
await rtcEngine.muteLocalVideoStream(mute) await rtcEngine.muteLocalVideoStream(mute)
}, },
// 摄像头采集 // 摄像头采集
startCameraCapture: async (bool: boolean = false) => { startCameraCapture: async () => {
await rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, { await rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {
format: { format: {
width: bool ? 160 : 1280, width: 640,
height: bool ? 160 : 720, height: 360,
fps: 15, fps: 15,
} }
}) })
@ -358,10 +282,13 @@ export const agora = {
option.uid = Number(data.uid); option.uid = Number(data.uid);
option.screenShareId = data.screenShareId; option.screenShareId = data.screenShareId;
await agora.joinChannel() await agora.joinChannel()
if (data.tokenA) {
await agora.allJoinChannelEx()
}
}, },
// 桌面捕获音频和视频的媒体源的信息 // 桌面捕获音频和视频的媒体源的信息
getDesktopCapturerVideo: async (thumbSize: any, iconSize: any, includeScreen: boolean) => { getDesktopCapturerVideo: async () => {
return await rtcEngine.getScreenCaptureSources(thumbSize, iconSize, includeScreen).filter((item: any) => item.type === 1) return rtcEngine.getScreenCaptureSources({ width: 300, height: 300 }, { width: 300, height: 300 }, true);
}, },
// 共享屏幕采集 // 共享屏幕采集
setDesktopCapturerVideo: async (targetSource: any, isComputerAudio: boolean, isFluencyPriority: boolean) => { setDesktopCapturerVideo: async (targetSource: any, isComputerAudio: boolean, isFluencyPriority: boolean) => {

View File

@ -70,7 +70,6 @@ import icon47 from '@/assets/icon47.png'
import icon47Active from '@/assets/icon47-active.png' 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'
export default { export default {
loading, loading,
icon, icon,
@ -143,6 +142,5 @@ export default {
icon47, icon47,
icon47Active, icon47Active,
icon48, icon48,
icon48Select, icon48Select
icon49,
} }

View File

@ -160,27 +160,6 @@ export const onSignalr = (callBack: Function) => {
watchUids watchUids
}) })
}); });
// 设备列表
connection.on("DriverList", (callerUid: string) => {
callBack({
key: 'DriverList',
callerUid
})
});
// 设置设备
connection.on("SaveDriver", (driver: string) => {
callBack({
key: 'SaveDriver',
driver
})
});
// 显示设备列表
connection.on("ShowDriverList", (driversJsonString: string) => {
callBack({
key: 'ShowDriverList',
driversJsonString
})
});
} }
} }
export const offSignalr = () => { export const offSignalr = () => {
@ -199,9 +178,6 @@ export const offSignalr = () => {
connection.off('ManagerRefresh'); connection.off('ManagerRefresh');
connection.off('ApplyToSpeak'); connection.off('ApplyToSpeak');
connection.off('Watch'); connection.off('Watch');
connection.off('DriverList');
connection.off('SetDriver');
connection.off('ShowDriverList');
} }
} }
export const onInvoke = async (str: string, data: any) => { export const onInvoke = async (str: string, data: any) => {
@ -213,18 +189,6 @@ export const onInvoke = async (str: string, data: any) => {
// 4:屏幕共享 // 4:屏幕共享
await connection.invoke(str, data.roomNum, data.type) await connection.invoke(str, data.roomNum, data.type)
break; break;
case 'getDrivers':
// 获取某个人的设备列表
await connection.invoke(str, data.uid)
break;
case 'sendDrivers':
// 发送设备列表给某个人
await connection.invoke(str, data.uid, data.driversJsonString)
break;
case 'setDrivers':
// 设置某个人的设备列表
await connection.invoke(str, data.uid, data.driversJsonString)
break;
} }
} }
export const onStop = async () => { export const onStop = async () => {

View File

@ -60,7 +60,7 @@ class Request {
message.error(resData.message) message.error(resData.message)
} }
} }
if (resData.code === 1403) { if (resData.code === 1403 || resData.code === 1000) {
toLogin() toLogin()
} }
return resData return resData
@ -113,7 +113,7 @@ class Request {
} }
function toLogin() { function toLogin() {
storage.removeItem('user') storage.removeItem('user')
storage.setItem('userLogin', false) location.href = location.origin + '/#/login'
} }
function updatePostRefresh() { function updatePostRefresh() {
let user = JSON.parse(storage.getItem('user') as string); let user = JSON.parse(storage.getItem('user') as string);
@ -121,7 +121,6 @@ function updatePostRefresh() {
PostRefresh(user.refresh_token).then((res) => { PostRefresh(user.refresh_token).then((res) => {
if (res.code == 200) { if (res.code == 200) {
storage.setItem('user', JSON.stringify(res.data)) storage.setItem('user', JSON.stringify(res.data))
storage.setItem('userLogin', true)
} else { } else {
toLogin() toLogin()
} }

View File

@ -343,16 +343,11 @@ $pagination-hover-background-color: #5575F2;
} }
.ant-radio-checked .ant-radio-inner { .ant-radio-checked .ant-radio-inner {
background-color: $btn-background-color;
border-color: $btn-background-color; border-color: $btn-background-color;
background-color: $btn-background-color;
} }
} }
:where(.css-dev-only-do-not-override-98ntnt).ant-radio-wrapper .ant-radio-disabled .ant-radio-inner {
background-color: #28282C;
border-color: #28282C;
}
// ant-notification // ant-notification
.ant-notification { .ant-notification {
.ant-notification-notice-wrapper { .ant-notification-notice-wrapper {
@ -376,8 +371,3 @@ $pagination-hover-background-color: #5575F2;
} }
} }
} }
// ant-message
.ant-message {
-webkit-app-region: no-drag;
}

View File

@ -60,10 +60,7 @@ export default defineConfig({
RenderModeType, RenderModeType,
ScreenCaptureSourceType, ScreenCaptureSourceType,
VideoSourceType, VideoSourceType,
VideoViewSetupMode, VideoViewSetupMode
AudioAinsMode,
SimulcastStreamMode,
VideoStreamType
} = require("agora-electron-sdk") } = require("agora-electron-sdk")
export { export {
createAgoraRtcEngine, createAgoraRtcEngine,
@ -72,10 +69,7 @@ export default defineConfig({
RenderModeType, RenderModeType,
ScreenCaptureSourceType, ScreenCaptureSourceType,
VideoSourceType, VideoSourceType,
VideoViewSetupMode, VideoViewSetupMode
AudioAinsMode,
SimulcastStreamMode,
VideoStreamType
} }
`, `,
}) })