Merge pull request 'yangjie' (#49) from yangjie into master
Reviewed-on: #49
|
|
@ -1,6 +0,0 @@
|
||||||
#基础API 绝对的
|
|
||||||
VITE_BASE_URL_API = 'http://192.168.2.9:5192'
|
|
||||||
#当前IP 相对的
|
|
||||||
VITE_BASE_CURRENT_API = '.'
|
|
||||||
#开发环境
|
|
||||||
VITE_ENV = 'development'
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
#基础API 绝对的
|
|
||||||
VITE_BASE_URL_API = 'https://meeting-api.23544.com/pc'
|
|
||||||
#当前IP 相对的
|
|
||||||
VITE_BASE_CURRENT_API = '.'
|
|
||||||
#生产环境
|
|
||||||
VITE_ENV = 'production'
|
|
||||||
6
.env.xy
|
|
@ -1,6 +0,0 @@
|
||||||
#基础API 绝对的
|
|
||||||
VITE_BASE_URL_API = 'https://meeting-api.23544.com/pc'
|
|
||||||
#当前IP 相对的
|
|
||||||
VITE_BASE_CURRENT_API = '.'
|
|
||||||
#测试环境
|
|
||||||
VITE_ENV = 'xy'
|
|
||||||
|
Before Width: | Height: | Size: 162 KiB |
|
|
@ -0,0 +1,16 @@
|
||||||
|
!macro customFinishPage
|
||||||
|
AutoCloseWindow true
|
||||||
|
Function StartApp
|
||||||
|
${if} ${isUpdated}
|
||||||
|
StrCpy $1 "--updated"
|
||||||
|
${else}
|
||||||
|
StrCpy $1 ""
|
||||||
|
${endif}
|
||||||
|
${StdUtils.ExecShellAsUser} $0 "$launchLink" "open" "$1"
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
Function .onInstSuccess
|
||||||
|
Call StartApp
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
!macroend
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"appId": "agora.io.ElectronApiExample",
|
||||||
|
"asar": true,
|
||||||
|
"asarUnpack": [
|
||||||
|
"node_modules/agora-electron-sdk"
|
||||||
|
],
|
||||||
|
"buildDependenciesFromSource": true,
|
||||||
|
"compression": "normal",
|
||||||
|
"productName": "智汇享",
|
||||||
|
"publish": [
|
||||||
|
{
|
||||||
|
"provider": "generic",
|
||||||
|
"url": "http://192.168.2.9:8827"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"!*.log"
|
||||||
|
],
|
||||||
|
"win": {
|
||||||
|
"icon": "build/start.ico",
|
||||||
|
"requestedExecutionLevel": "highestAvailable",
|
||||||
|
"target": [
|
||||||
|
{
|
||||||
|
"target": "nsis",
|
||||||
|
"arch": [
|
||||||
|
"ia32"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"output": "electron"
|
||||||
|
},
|
||||||
|
"extraResources": [
|
||||||
|
{
|
||||||
|
"from": "src/assets/virtualBackground",
|
||||||
|
"to": "images",
|
||||||
|
"filter": [
|
||||||
|
"**/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nsis": {
|
||||||
|
"oneClick": false,
|
||||||
|
"installerIcon": "build/start.ico",
|
||||||
|
"uninstallerIcon": "build/start.ico",
|
||||||
|
"installerHeaderIcon": "build/start.ico",
|
||||||
|
"allowToChangeInstallationDirectory": true,
|
||||||
|
"createDesktopShortcut": true,
|
||||||
|
"createStartMenuShortcut": true,
|
||||||
|
"deleteAppDataOnUninstall": true,
|
||||||
|
"shortcutName": "智汇享",
|
||||||
|
"allowElevation": true,
|
||||||
|
"perMachine": true,
|
||||||
|
"include": "build/install.nsh"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -42,15 +42,16 @@
|
||||||
],
|
],
|
||||||
"nsis": {
|
"nsis": {
|
||||||
"oneClick": false,
|
"oneClick": false,
|
||||||
"installerIcon": "build/install.ico",
|
"installerIcon": "build/start.ico",
|
||||||
"uninstallerIcon": "build/install.ico",
|
"uninstallerIcon": "build/start.ico",
|
||||||
"installerHeaderIcon": "build/install.ico",
|
"installerHeaderIcon": "build/start.ico",
|
||||||
"allowToChangeInstallationDirectory": true,
|
"allowToChangeInstallationDirectory": true,
|
||||||
"createDesktopShortcut": true,
|
"createDesktopShortcut": true,
|
||||||
"createStartMenuShortcut": true,
|
"createStartMenuShortcut": true,
|
||||||
"deleteAppDataOnUninstall": true,
|
"deleteAppDataOnUninstall": true,
|
||||||
"shortcutName": "智汇享",
|
"shortcutName": "智汇享",
|
||||||
"allowElevation": true,
|
"allowElevation": true,
|
||||||
"perMachine": true
|
"perMachine": true,
|
||||||
|
"include": "build/install.nsh"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -51,6 +51,7 @@
|
||||||
"deleteAppDataOnUninstall": true,
|
"deleteAppDataOnUninstall": true,
|
||||||
"shortcutName": "湖北襄阳四中教研平台",
|
"shortcutName": "湖北襄阳四中教研平台",
|
||||||
"allowElevation": true,
|
"allowElevation": true,
|
||||||
"perMachine": true
|
"perMachine": true,
|
||||||
|
"include": "build/install.nsh"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
111
main.js
|
|
@ -11,6 +11,7 @@ const {
|
||||||
crashReporter,
|
crashReporter,
|
||||||
desktopCapturer,
|
desktopCapturer,
|
||||||
powerSaveBlocker,
|
powerSaveBlocker,
|
||||||
|
net
|
||||||
} = require('electron');
|
} = require('electron');
|
||||||
const path = require('node:path')
|
const path = require('node:path')
|
||||||
const updateJs = require('./src/utils/package/update')
|
const updateJs = require('./src/utils/package/update')
|
||||||
|
|
@ -18,16 +19,15 @@ const fs = require('fs');
|
||||||
const Registry = require('winreg');
|
const Registry = require('winreg');
|
||||||
const { autoUpdater, CancellationToken } = require('electron-updater');
|
const { autoUpdater, CancellationToken } = require('electron-updater');
|
||||||
const signalR = require('@microsoft/signalr');
|
const signalR = require('@microsoft/signalr');
|
||||||
const { setTimeout, setInterval, clearTimeout, clearInterval } = require('timers');
|
const { setTimeout, setInterval } = require('timers');
|
||||||
const cancellationToken = new CancellationToken()
|
const cancellationToken = new CancellationToken()
|
||||||
app.allowRendererProcessReuse = false;
|
app.allowRendererProcessReuse = false;
|
||||||
let mainWindow = null;
|
let mainWindow = null;
|
||||||
let childWindow = {}
|
let childWindow = {}
|
||||||
let isMaximized = false;
|
let isMaximized = false;
|
||||||
let env;
|
let env = 'development'; //development production xy
|
||||||
let regKey;
|
let regKey;
|
||||||
let connection = null;
|
let connection = null;
|
||||||
let envStr;
|
|
||||||
let startNumber = 0;
|
let startNumber = 0;
|
||||||
let buildStatus = false; //true 打包开发版本 false 本地开发
|
let buildStatus = false; //true 打包开发版本 false 本地开发
|
||||||
powerSaveBlocker.start('prevent-display-sleep')
|
powerSaveBlocker.start('prevent-display-sleep')
|
||||||
|
|
@ -53,16 +53,15 @@ class AppWindow extends BrowserWindow {
|
||||||
const finalConfig = { ...basicConfig, ...config };
|
const finalConfig = { ...basicConfig, ...config };
|
||||||
super(finalConfig);
|
super(finalConfig);
|
||||||
if (env === 'development') {
|
if (env === 'development') {
|
||||||
// 开发
|
|
||||||
if (buildStatus) {
|
if (buildStatus) {
|
||||||
this.loadFile(path.resolve(__dirname, './dist/index.html'));
|
this.loadURL('http://192.168.2.9:8827/');
|
||||||
} else {
|
} else {
|
||||||
this.loadURL('http://localhost:3000');
|
this.loadURL('http://localhost:3000');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 测试 | 生产
|
this.loadURL('https://meeting-api.23544.com/')
|
||||||
this.loadFile(path.resolve(__dirname, './dist/index.html'));
|
|
||||||
}
|
}
|
||||||
|
// this.loadFile(path.resolve(__dirname, './dist/index.html'))
|
||||||
this.once('ready-to-show', () => {
|
this.once('ready-to-show', () => {
|
||||||
this.show();
|
this.show();
|
||||||
});
|
});
|
||||||
|
|
@ -72,11 +71,20 @@ function quit() {
|
||||||
app.quit()
|
app.quit()
|
||||||
}
|
}
|
||||||
let tray;
|
let tray;
|
||||||
|
// 检查网络状态
|
||||||
|
function checkNetworkStatus() {
|
||||||
|
if (!net.isOnline()) {
|
||||||
|
dialog.showErrorBox(`${env === 'xy' ? '湖北襄阳四中教研平台' : '智汇享'}-网络连接错误', '当前无网络连接,请检查您的网络设置。`);
|
||||||
|
app.quit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
function createTray() {
|
function createTray() {
|
||||||
const iconPath = `${__dirname}/src/assets/${updateJs.getIcon(envStr)}.png`;
|
const iconPath = `${__dirname}/src/assets/${updateJs.getIcon(env)}.png`;
|
||||||
const trayIcon = nativeImage.createFromPath(iconPath);
|
const trayIcon = nativeImage.createFromPath(iconPath);
|
||||||
tray = new Tray(trayIcon);
|
tray = new Tray(trayIcon);
|
||||||
tray.setToolTip(updateJs.getTitle(envStr));
|
tray.setToolTip(updateJs.getTitle(env));
|
||||||
tray.on('click', () => {
|
tray.on('click', () => {
|
||||||
mainWindow.webContents.send('isOpenWindows');
|
mainWindow.webContents.send('isOpenWindows');
|
||||||
});
|
});
|
||||||
|
|
@ -95,6 +103,10 @@ function createWindow() {
|
||||||
}
|
}
|
||||||
const additionalData = { myKey: 'myValue' }
|
const additionalData = { myKey: 'myValue' }
|
||||||
app.on('ready', () => {
|
app.on('ready', () => {
|
||||||
|
// 检查网络状态
|
||||||
|
if (!checkNetworkStatus()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// const gotTheLock = true
|
// const gotTheLock = true
|
||||||
const gotTheLock = app.requestSingleInstanceLock(additionalData)
|
const gotTheLock = app.requestSingleInstanceLock(additionalData)
|
||||||
if (gotTheLock) {
|
if (gotTheLock) {
|
||||||
|
|
@ -103,15 +115,14 @@ app.on('ready', () => {
|
||||||
uploadToServer: false,
|
uploadToServer: false,
|
||||||
ignoreSystemCrashHandler: false
|
ignoreSystemCrashHandler: false
|
||||||
})
|
})
|
||||||
env = process.argv.find((arg) => arg.startsWith('--env='))?.split('=')[1];
|
// if (!buildStatus) {
|
||||||
if (env === 'development') {
|
// Object.defineProperty(app, 'isPackaged', {
|
||||||
Object.defineProperty(app, 'isPackaged', {
|
// get() {
|
||||||
get() {
|
// return true
|
||||||
return true
|
// }
|
||||||
}
|
// })
|
||||||
})
|
// autoUpdater.updateConfigPath = path.join('latest.yml')
|
||||||
autoUpdater.updateConfigPath = path.join('latest.yml')
|
// }
|
||||||
}
|
|
||||||
createWindow()
|
createWindow()
|
||||||
regKey = new Registry({
|
regKey = new Registry({
|
||||||
hive: Registry.HKCU,
|
hive: Registry.HKCU,
|
||||||
|
|
@ -149,12 +160,11 @@ app.on('ready', () => {
|
||||||
isMaximized = true;
|
isMaximized = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ipcMain.handle('setEnv', (event, str) => {
|
ipcMain.handle('startLoad', (event) => {
|
||||||
envStr = str;
|
|
||||||
if (startNumber === 0) {
|
if (startNumber === 0) {
|
||||||
updateHandle() // 检查更新
|
updateHandle() // 检查更新
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
updateHandle() // 每一小时检查更新
|
autoUpdater.checkForUpdates()
|
||||||
}, 1000 * 60 * 60)
|
}, 1000 * 60 * 60)
|
||||||
createTray()
|
createTray()
|
||||||
startNumber++
|
startNumber++
|
||||||
|
|
@ -162,7 +172,7 @@ app.on('ready', () => {
|
||||||
});
|
});
|
||||||
// 更新
|
// 更新
|
||||||
ipcMain.handle('updateHandle', () => {
|
ipcMain.handle('updateHandle', () => {
|
||||||
updateHandle()
|
autoUpdater.checkForUpdates()
|
||||||
});
|
});
|
||||||
// socket
|
// socket
|
||||||
ipcMain.handle('startSignalr', (event, user) => {
|
ipcMain.handle('startSignalr', (event, user) => {
|
||||||
|
|
@ -191,6 +201,8 @@ app.on('ready', () => {
|
||||||
connection.off('JoinChannelCallback');
|
connection.off('JoinChannelCallback');
|
||||||
connection.off('ExitSharedScreen');
|
connection.off('ExitSharedScreen');
|
||||||
connection.off('SetSpeaker');
|
connection.off('SetSpeaker');
|
||||||
|
connection.off('ReceivedOperation');
|
||||||
|
connection.off('StopedSharedScreen');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ipcMain.handle('onStop', (event) => {
|
ipcMain.handle('onStop', (event) => {
|
||||||
|
|
@ -210,7 +222,7 @@ app.on('ready', () => {
|
||||||
await connection.invoke(str, data.roomNum, data.msg)
|
await connection.invoke(str, data.roomNum, data.msg)
|
||||||
break;
|
break;
|
||||||
case 'sendOper':
|
case 'sendOper':
|
||||||
await connection.invoke(str, data.roomNum, data.type)
|
await connection.invoke(str, data.roomNum, data.contentString)
|
||||||
break;
|
break;
|
||||||
case 'getDrivers':
|
case 'getDrivers':
|
||||||
// 获取某个人的设备列表
|
// 获取某个人的设备列表
|
||||||
|
|
@ -236,6 +248,10 @@ app.on('ready', () => {
|
||||||
// 发言人设置成功
|
// 发言人设置成功
|
||||||
await connection.invoke(str, data)
|
await connection.invoke(str, data)
|
||||||
break;
|
break;
|
||||||
|
case 'sendOper2User':
|
||||||
|
// 扩展参数
|
||||||
|
await connection.invoke(str, data.uid, data.contentString)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ipcMain.handle('onOtherSignalr', (event) => {
|
ipcMain.handle('onOtherSignalr', (event) => {
|
||||||
|
|
@ -266,10 +282,10 @@ app.on('ready', () => {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
// 扩展操作
|
// 扩展操作
|
||||||
connection.on("Operation", (type) => {
|
connection.on("Operation", (contentString) => {
|
||||||
mainWindow.webContents.send('onSignalr', {
|
mainWindow.webContents.send('onSignalr', {
|
||||||
key: 'Operation',
|
key: 'Operation',
|
||||||
type
|
contentString
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
// 移出会议
|
// 移出会议
|
||||||
|
|
@ -411,6 +427,20 @@ app.on('ready', () => {
|
||||||
RoomManagerInputDTO
|
RoomManagerInputDTO
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
// 扩展参数
|
||||||
|
connection.on("ReceivedOperation", (contentString) => {
|
||||||
|
mainWindow.webContents.send('onSignalr', {
|
||||||
|
key: 'ReceivedOperation',
|
||||||
|
contentString
|
||||||
|
})
|
||||||
|
});
|
||||||
|
// 共享人取消共享屏幕
|
||||||
|
connection.on("StopedSharedScreen", (ScreenShareId) => {
|
||||||
|
mainWindow.webContents.send('onSignalr', {
|
||||||
|
key: 'StopedSharedScreen',
|
||||||
|
ScreenShareId
|
||||||
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 放大缩小退出窗口
|
// 放大缩小退出窗口
|
||||||
|
|
@ -452,6 +482,10 @@ app.on('ready', () => {
|
||||||
ipcMain.handle('getVersion', () => {
|
ipcMain.handle('getVersion', () => {
|
||||||
return app.getVersion();
|
return app.getVersion();
|
||||||
});
|
});
|
||||||
|
// 获取环境
|
||||||
|
ipcMain.handle('getEnv', () => {
|
||||||
|
return env;
|
||||||
|
});
|
||||||
// 获取窗口是否显示
|
// 获取窗口是否显示
|
||||||
ipcMain.handle('isVisible', () => {
|
ipcMain.handle('isVisible', () => {
|
||||||
return mainWindow.isVisible();
|
return mainWindow.isVisible();
|
||||||
|
|
@ -487,6 +521,11 @@ app.on('ready', () => {
|
||||||
downloadUpdate()
|
downloadUpdate()
|
||||||
} else if (data === '2') { // 下载完成 点击安装
|
} else if (data === '2') { // 下载完成 点击安装
|
||||||
quitAndInstall()
|
quitAndInstall()
|
||||||
|
} else if (data === '3') { // 打开弹窗
|
||||||
|
let message = JSON.stringify({
|
||||||
|
type: '3',
|
||||||
|
})
|
||||||
|
sendUpdateMessage(message)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 选择文件夹
|
// 选择文件夹
|
||||||
|
|
@ -604,16 +643,18 @@ app.on('ready', () => {
|
||||||
width: config.width,
|
width: config.width,
|
||||||
height: config.height,
|
height: config.height,
|
||||||
})
|
})
|
||||||
if (envStr === 'development') {
|
if (env === 'development') {
|
||||||
// 开发
|
// 开发
|
||||||
if (buildStatus) {
|
if (buildStatus) {
|
||||||
child.loadURL(`file://${path.join(__dirname, './dist/index.html')}#/${config.key}`);
|
child.loadURL(`http://192.168.2.9:8827/#/${config.key}`);
|
||||||
|
// child.loadURL(`file://${path.join(__dirname, './dist/index.html')}#/${config.key}`);
|
||||||
} else {
|
} else {
|
||||||
child.loadURL(config.url)
|
child.loadURL(config.url)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 测试 | 生产
|
// 测试 | 生产
|
||||||
child.loadURL(`file://${path.join(__dirname, './dist/index.html')}#/${config.key}`);
|
child.loadURL(`https://meeting-api.23544.com/#/${config.key}`);
|
||||||
|
// child.loadURL(`file://${path.join(__dirname, './dist/index.html')}#/${config.key}`);
|
||||||
}
|
}
|
||||||
child.hookWindowMessage(278, function (e) {
|
child.hookWindowMessage(278, function (e) {
|
||||||
child.setEnabled(false);//窗口禁用
|
child.setEnabled(false);//窗口禁用
|
||||||
|
|
@ -715,7 +756,6 @@ app.on('ready', () => {
|
||||||
});
|
});
|
||||||
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
|
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
|
||||||
function updateHandle() {
|
function updateHandle() {
|
||||||
autoUpdater.checkForUpdates()
|
|
||||||
// autoUpdater.checkForUpdatesAndNotify().catch();
|
// autoUpdater.checkForUpdatesAndNotify().catch();
|
||||||
const message = {
|
const message = {
|
||||||
error: '检查更新出错',
|
error: '检查更新出错',
|
||||||
|
|
@ -723,11 +763,11 @@ function updateHandle() {
|
||||||
updateAva: '检测到新版本,正在下载……',
|
updateAva: '检测到新版本,正在下载……',
|
||||||
updateNotAva: '已经是最新版本,不用更新'
|
updateNotAva: '已经是最新版本,不用更新'
|
||||||
}
|
}
|
||||||
autoUpdater.setFeedURL(updateJs.getUpdateUrl(envStr))
|
autoUpdater.setFeedURL(updateJs.getUpdateUrl(env))
|
||||||
autoUpdater.autoDownload = false // 不自动下载安装包
|
autoUpdater.autoDownload = false // 不自动下载安装包
|
||||||
autoUpdater.autoInstallOnAppQuit = false // 不自动安装
|
autoUpdater.autoInstallOnAppQuit = false // 不自动安装
|
||||||
autoUpdater.on('error', function (error) {
|
autoUpdater.on('error', function (error) {
|
||||||
sendUpdateMessage(message.error)
|
sendUpdateMessage(error)
|
||||||
})
|
})
|
||||||
autoUpdater.on('checking-for-update', function () {
|
autoUpdater.on('checking-for-update', function () {
|
||||||
sendUpdateMessage(message.checking)
|
sendUpdateMessage(message.checking)
|
||||||
|
|
@ -735,9 +775,14 @@ function updateHandle() {
|
||||||
autoUpdater.on('update-available', function (info) {
|
autoUpdater.on('update-available', function (info) {
|
||||||
let messageStr = JSON.stringify({ type: '0' })
|
let messageStr = JSON.stringify({ type: '0' })
|
||||||
sendUpdateMessage(messageStr)
|
sendUpdateMessage(messageStr)
|
||||||
|
mainWindow.webContents.send('changeLocalStorage', {
|
||||||
|
isUpdate: true,
|
||||||
|
});
|
||||||
})
|
})
|
||||||
autoUpdater.on('update-not-available', function (info) {
|
autoUpdater.on('update-not-available', function (info) {
|
||||||
|
mainWindow.webContents.send('changeLocalStorage', {
|
||||||
|
isUpdate: false,
|
||||||
|
});
|
||||||
})
|
})
|
||||||
// 更新下载进度事件
|
// 更新下载进度事件
|
||||||
autoUpdater.on('download-progress', function (progressObj) {
|
autoUpdater.on('download-progress', function (progressObj) {
|
||||||
|
|
@ -810,7 +855,7 @@ function mainWindowCenter() {
|
||||||
|
|
||||||
const startSignalr = async (user) => {
|
const startSignalr = async (user) => {
|
||||||
connection = new signalR.HubConnectionBuilder()
|
connection = new signalR.HubConnectionBuilder()
|
||||||
.withUrl(`${envStr === 'development' ? 'http://192.168.2.9:5192' : 'https://meeting-api.23544.com/pc'}/session-manage`, {
|
.withUrl(`${env === 'development' ? 'http://192.168.2.9:5192' : 'https://meeting-api.23544.com/pc'}/session-manage`, {
|
||||||
skipNegotiation: true,
|
skipNegotiation: true,
|
||||||
transport: signalR.HttpTransportType.WebSockets,
|
transport: signalR.HttpTransportType.WebSockets,
|
||||||
accessTokenFactory: () => user.token
|
accessTokenFactory: () => user.token
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
{
|
{
|
||||||
"name": "WGShare.Metting",
|
"name": "WGShare.Metting",
|
||||||
"version": "0.4.8",
|
"version": "0.7.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "WGShare.Metting",
|
"name": "WGShare.Metting",
|
||||||
"version": "0.4.8",
|
"version": "0.7.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^5.3.7",
|
"@ant-design/icons": "^5.3.7",
|
||||||
"@microsoft/signalr": "^8.0.0",
|
"@microsoft/signalr": "^8.0.0",
|
||||||
"@types/node": "^20.14.9",
|
"@types/node": "^20.14.9",
|
||||||
"agora-electron-sdk": "^4.4.0",
|
"agora-electron-sdk": "4.4.0",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"antd": "^5.18.2",
|
"antd": "^5.18.2",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
"electron-squirrel-startup": "^1.0.1",
|
"electron-squirrel-startup": "^1.0.1",
|
||||||
"electron-updater": "^6.2.1",
|
"electron-updater": "^6.2.1",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
"os": "^0.1.2",
|
"os": "^0.1.2",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
||||||
|
|
|
||||||
17
package.json
|
|
@ -1,21 +1,17 @@
|
||||||
{
|
{
|
||||||
"name": "WGShare.Metting",
|
"name": "WGShare.Metting",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.7.1",
|
"version": "0.8.0",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"authors": "yj",
|
"authors": "yj",
|
||||||
"description": "智汇享",
|
"description": "智汇享",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "concurrently \"electron . --env=development\" \"cross-env BROWSER=none vite\"",
|
"dev": "concurrently \"electron .\" \"cross-env BROWSER=none vite\"",
|
||||||
"prod": "concurrently \"electron . --env=production\" \"cross-env BROWSER=none vite\"",
|
"build": "vite build",
|
||||||
"xy": "concurrently \"electron . --env=xy\" \"cross-env BROWSER=none vite\"",
|
|
||||||
"build": "vite build --mode development",
|
|
||||||
"build:prod": "vite build --mode production",
|
|
||||||
"build:xy": "vite build --mode xy",
|
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"build:dev-win": "vite build --mode development & electron-builder -w --config=./config/build.json",
|
"build:dev": "vite build & electron-builder -w --config=./config/development.json",
|
||||||
"build:prod-win": "vite build --mode production & electron-builder -w --config=./config/build.json",
|
"build:prod": "vite build & electron-builder -w --config=./config/production.json",
|
||||||
"build:prod-win-xy": "vite build --mode xy & electron-builder -w --config=./config/xy.json"
|
"build:xy": "vite build & electron-builder -w --config=./config/xy.json"
|
||||||
},
|
},
|
||||||
"agora_electron": {
|
"agora_electron": {
|
||||||
"platform": "win32",
|
"platform": "win32",
|
||||||
|
|
@ -34,6 +30,7 @@
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
"electron-squirrel-startup": "^1.0.1",
|
"electron-squirrel-startup": "^1.0.1",
|
||||||
"electron-updater": "^6.2.1",
|
"electron-updater": "^6.2.1",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
"os": "^0.1.2",
|
"os": "^0.1.2",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
||||||
|
|
|
||||||
12
preload.js
|
|
@ -51,6 +51,10 @@ window.electron = {
|
||||||
getVersion: () => {
|
getVersion: () => {
|
||||||
return ipcRenderer.invoke('getVersion')
|
return ipcRenderer.invoke('getVersion')
|
||||||
},
|
},
|
||||||
|
// 获取环境
|
||||||
|
getEnv: () => {
|
||||||
|
return ipcRenderer.invoke('getEnv')
|
||||||
|
},
|
||||||
// 获取窗口是否显示
|
// 获取窗口是否显示
|
||||||
isVisible: () => {
|
isVisible: () => {
|
||||||
return ipcRenderer.invoke('isVisible')
|
return ipcRenderer.invoke('isVisible')
|
||||||
|
|
@ -87,9 +91,9 @@ window.electron = {
|
||||||
isOpenWindows: (callback) => {
|
isOpenWindows: (callback) => {
|
||||||
ipcRenderer.on('isOpenWindows', callback)
|
ipcRenderer.on('isOpenWindows', callback)
|
||||||
},
|
},
|
||||||
// 设置环境变量
|
// 首次加载
|
||||||
setEnv: (str) => {
|
startLoad: () => {
|
||||||
ipcRenderer.invoke('setEnv', str)
|
ipcRenderer.invoke('startLoad')
|
||||||
},
|
},
|
||||||
// 更新
|
// 更新
|
||||||
updateHandle: () => {
|
updateHandle: () => {
|
||||||
|
|
@ -134,7 +138,7 @@ window.electron = {
|
||||||
ipcRenderer.invoke('createChildWindow', {
|
ipcRenderer.invoke('createChildWindow', {
|
||||||
url: location.origin + `/#/noticeWindow`,
|
url: location.origin + `/#/noticeWindow`,
|
||||||
width: 388,
|
width: 388,
|
||||||
height: 150,
|
height: 180,
|
||||||
key: 'noticeWindow',
|
key: 'noticeWindow',
|
||||||
})
|
})
|
||||||
ipcRenderer.invoke('createChildWindow', {
|
ipcRenderer.invoke('createChildWindow', {
|
||||||
|
|
|
||||||
73
src/App.tsx
|
|
@ -8,20 +8,21 @@ import Login from '@/page/Login/index'
|
||||||
import Meeting from '@/page/Meeting/index'
|
import Meeting from '@/page/Meeting/index'
|
||||||
import NotFound from '@/page/NotFound/index'
|
import NotFound from '@/page/NotFound/index'
|
||||||
import { storage } from '@/utils'
|
import { storage } from '@/utils'
|
||||||
import { message, Spin } from "antd";
|
import { message, Modal, Spin } from "antd";
|
||||||
import JoinMeetingModal from "@/components/JoinMeetingModal";
|
import JoinMeetingModal from "@/components/JoinMeetingModal";
|
||||||
import UpdateModal from "@/components/UpdateModal";
|
import UpdateModal from "@/components/UpdateModal";
|
||||||
import * as CryptoJS from 'crypto-js';
|
import * as CryptoJS from 'crypto-js';
|
||||||
import { PostLogin } from "@/api/Login";
|
import { GetCheckOnline, 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 ShareScreenWindow from "@/page/Meeting/ShareScreenWindow";
|
import ShareScreenWindow from "@/page/Meeting/ShareScreenWindow";
|
||||||
import UserListWindow from "@/page/Meeting/UserListWindow";
|
import UserListWindow from "@/page/Meeting/UserListWindow";
|
||||||
import ChatSmallWindow from "@/page/Meeting/ChatSmallWindow";
|
import ChatSmallWindow from "@/page/Meeting/ChatSmallWindow";
|
||||||
import ChatBigWindow from "@/page/Meeting/ChatBigWindow";
|
import ChatBigWindow from "@/page/Meeting/ChatBigWindow";
|
||||||
import NoticeWindow from "@/page/Meeting/NoticeWindow";
|
import NoticeWindow from "@/page/Meeting/NoticeWindow";
|
||||||
import { getKeyOpenChildWindow, getTitle, setKeyOpenChildWindow, storageSeeting } from "./utils/package/public";
|
import { getKeyOpenChildWindow, getTitle, setKeyOpenChildWindow, storageSeeting } from "./utils/package/public";
|
||||||
|
import { ExclamationCircleFilled } from "@ant-design/icons";
|
||||||
|
const { confirm } = Modal;
|
||||||
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 = () => {
|
||||||
|
|
@ -41,9 +42,7 @@ const App: React.FC = () => {
|
||||||
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)
|
||||||
window.electron.setEnv(import.meta.env.VITE_ENV);
|
const login = () => {
|
||||||
if (userInfo && !userInfo.isAnonymous) {
|
|
||||||
if (loginInfo && loginInfo.isAutoLogin) {
|
|
||||||
PostLogin({
|
PostLogin({
|
||||||
account: loginInfo.account,
|
account: loginInfo.account,
|
||||||
pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex)
|
pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex)
|
||||||
|
|
@ -57,6 +56,31 @@ const App: React.FC = () => {
|
||||||
toSrc('/login')
|
toSrc('/login')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
if (userInfo && !userInfo.isAnonymous) {
|
||||||
|
if (loginInfo && loginInfo.isAutoLogin) {
|
||||||
|
GetCheckOnline(loginInfo.account).then(req => {
|
||||||
|
if (req.code === 200) {
|
||||||
|
if (req.data) {
|
||||||
|
confirm({
|
||||||
|
title: '提示',
|
||||||
|
icon: <ExclamationCircleFilled />,
|
||||||
|
content: `账号已在其他地方登录,是否强制登陆?`,
|
||||||
|
centered: true,
|
||||||
|
okText: '确定',
|
||||||
|
cancelText: '取消',
|
||||||
|
async onOk() {
|
||||||
|
login()
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
toSrc('/login')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
login()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
toSrc('/login')
|
toSrc('/login')
|
||||||
}
|
}
|
||||||
|
|
@ -79,6 +103,7 @@ const App: React.FC = () => {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
window.electron.startLoad();
|
||||||
window.electron.downFile(async (_e: any, data: any) => {
|
window.electron.downFile(async (_e: any, data: any) => {
|
||||||
const response = await fetch(data.filePath);
|
const response = await fetch(data.filePath);
|
||||||
const arrayBuffer = await response.arrayBuffer();
|
const arrayBuffer = await response.arrayBuffer();
|
||||||
|
|
@ -127,9 +152,7 @@ const App: React.FC = () => {
|
||||||
}, [])
|
}, [])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.electron.onUpdate((_e: any, data: any) => {
|
window.electron.onUpdate((_e: any, data: any) => {
|
||||||
if (location.hash.indexOf('/meeting') === -1) {
|
|
||||||
updateModalRef.current.changeModal(data)
|
updateModalRef.current.changeModal(data)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
if (!storage.getItem('setting')) {
|
if (!storage.getItem('setting')) {
|
||||||
storage.setItem('setting', JSON.stringify(storageSeeting))
|
storage.setItem('setting', JSON.stringify(storageSeeting))
|
||||||
|
|
@ -164,16 +187,24 @@ const App: React.FC = () => {
|
||||||
if (location.href.indexOf('/login') !== -1) {
|
if (location.href.indexOf('/login') !== -1) {
|
||||||
window.electron.onStop()
|
window.electron.onStop()
|
||||||
}
|
}
|
||||||
|
if (location.hash && location.hash.indexOf('/meeting') === -1) {
|
||||||
|
window.electron.updateHandle()
|
||||||
|
}
|
||||||
message.destroy('cameraTemporarily')
|
message.destroy('cameraTemporarily')
|
||||||
}, [navigate])
|
}, [navigate])
|
||||||
}
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.addEventListener('keydown', (event) => {
|
document.addEventListener('keydown', async (event) => {
|
||||||
if (event.key === 'F11') {
|
if (event.keyCode == 122) {
|
||||||
|
event.preventDefault();
|
||||||
|
} else if (((event.ctrlKey && event.keyCode == 82) || event.keyCode == 116)) {
|
||||||
|
let env = await window.electron.getEnv()
|
||||||
|
if (env !== 'development') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
document.getElementsByTagName('title')[0].innerText = getTitle(import.meta.env.VITE_ENV)
|
getTitle()
|
||||||
}, [])
|
}, [])
|
||||||
const handleResize = (): void => {
|
const handleResize = (): void => {
|
||||||
setWindowSize({
|
setWindowSize({
|
||||||
|
|
@ -200,8 +231,10 @@ const App: React.FC = () => {
|
||||||
if (item.msg) {
|
if (item.msg) {
|
||||||
message.error(item.msg)
|
message.error(item.msg)
|
||||||
}
|
}
|
||||||
await leaveChannel(true)
|
await leaveChannel()
|
||||||
|
setTimeout(() => {
|
||||||
toSrc('/login')
|
toSrc('/login')
|
||||||
|
}, 5000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -223,7 +256,7 @@ const App: React.FC = () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
const leaveChannel = async (bool?: boolean): Promise<void> => {
|
const leaveChannel = async (): Promise<void> => {
|
||||||
if (location.hash.indexOf('/meeting') === 1) {
|
if (location.hash.indexOf('/meeting') === 1) {
|
||||||
window.electron.closeChildWindow('shareScreenWindow')
|
window.electron.closeChildWindow('shareScreenWindow')
|
||||||
setKeyOpenChildWindow('shareScreenWindow', false)
|
setKeyOpenChildWindow('shareScreenWindow', false)
|
||||||
|
|
@ -240,11 +273,9 @@ const App: React.FC = () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const data = JSON.parse(localStorage.stateInfo);
|
const data = JSON.parse(localStorage.stateInfo);
|
||||||
if (!bool) {
|
await window.electron.onInvoke('levelChannel', {
|
||||||
await GetLeave({
|
roomNum: data.channelId
|
||||||
roomNum: data.channelId,
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
await agora.leaveChannel()
|
await agora.leaveChannel()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -260,12 +291,8 @@ const App: React.FC = () => {
|
||||||
storage.removeItem('user')
|
storage.removeItem('user')
|
||||||
navigate('/login')
|
navigate('/login')
|
||||||
}
|
}
|
||||||
} else if (e.key === 'reconnect') {
|
} else if (e.key === 'env') {
|
||||||
if (e.value == true) {
|
|
||||||
if (location.hash.indexOf('/meeting') === -1) {
|
|
||||||
window.electron.updateHandle()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,9 @@ export const PostAnonLogin = (data: any) =>
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const GetCheckOnline = (account: string) =>
|
||||||
|
request({
|
||||||
|
url: `/auth/check-online?account=${account}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
|
@ -171,3 +171,14 @@ export const PostSharedScreen = (roomNum: string) =>
|
||||||
url: `/room/shared-screen?roomNum=${roomNum}`,
|
url: `/room/shared-screen?roomNum=${roomNum}`,
|
||||||
method: 'post'
|
method: 'post'
|
||||||
})
|
})
|
||||||
|
export const PostStopSharedScreen = (roomNum: string) =>
|
||||||
|
request({
|
||||||
|
url: `/room/stop-shared-screen?roomNum=${roomNum}`,
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
export const PostHomeVerLog = (data: any) =>
|
||||||
|
request({
|
||||||
|
url: `/home/ver-log`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 712 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 838 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 600 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 921 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 58 KiB |
|
|
@ -0,0 +1,48 @@
|
||||||
|
import ImageUrl from '@/utils/package/imageUrl';
|
||||||
|
import { Empty, Popover } from 'antd';
|
||||||
|
import { GetQrcode } from '@/api/Home/Index';
|
||||||
|
import { memo, useImperativeHandle, forwardRef, useState } from "react";
|
||||||
|
const Code = forwardRef((props: any, ref: any) => {
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
getData: () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
const [baseImage, setBaseImage] = useState('');
|
||||||
|
const [roomNum, setRoomNum] = useState(props.roomNum);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Popover
|
||||||
|
placement="bottom"
|
||||||
|
onOpenChange={async (e: boolean) => {
|
||||||
|
setBaseImage('')
|
||||||
|
if (e) {
|
||||||
|
let env = await window.electron.getEnv()
|
||||||
|
GetQrcode(roomNum, env === 'development' ? 'trial' : 'release').then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
setBaseImage(res.data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
content={
|
||||||
|
baseImage ? <div>
|
||||||
|
<img style={{ width: '200px', margin: '0 auto' }} src={`data:image/png;base64,${baseImage}`} alt="" />
|
||||||
|
<div style={{ color: 'white', textAlign: 'center', fontSize: '16px', marginTop: '10px' }}>
|
||||||
|
<span>微信中长按图片识别小程序码</span><br />
|
||||||
|
<span>加入会议</span>
|
||||||
|
</div>
|
||||||
|
</div> : <div>
|
||||||
|
<Empty description={'二维码加载中,请稍后'} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div title='小程序'>
|
||||||
|
<img src={ImageUrl.icon55} alt="" style={{ width: '16px' }} />
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default memo(Code)
|
||||||
|
|
@ -9,6 +9,7 @@ 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';
|
import { role } from '@/config/role';
|
||||||
|
import { PostHomeVerLog } from '@/api/Meeting';
|
||||||
const { setInterval, clearInterval } = require('timers');
|
const { setInterval, clearInterval } = require('timers');
|
||||||
let time = null as any;
|
let time = null as any;
|
||||||
const JoinSetting = forwardRef((_props: any, ref: any) => {
|
const JoinSetting = forwardRef((_props: any, ref: any) => {
|
||||||
|
|
@ -201,6 +202,13 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
||||||
GetRoomInfo(roomNumber).then(async (res) => {
|
GetRoomInfo(roomNumber).then(async (res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
await agora.release()
|
await agora.release()
|
||||||
|
await window.electron.getVersion().then(async req => {
|
||||||
|
await PostHomeVerLog({
|
||||||
|
version: req,
|
||||||
|
platformType: 1,
|
||||||
|
roomNum: roomNumber,
|
||||||
|
})
|
||||||
|
})
|
||||||
navigate(`/meeting`, {
|
navigate(`/meeting`, {
|
||||||
state: {
|
state: {
|
||||||
channelId: roomNumber,
|
channelId: roomNumber,
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,9 @@ const StupWizard = forwardRef((_props: any, ref: any) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
storage.setItem('setting', JSON.stringify(setting))
|
storage.setItem('setting', JSON.stringify(setting))
|
||||||
|
},
|
||||||
|
getStupWizardModal: () => {
|
||||||
|
return isStupWizard
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
const [list, setList] = useState([
|
const [list, setList] = useState([
|
||||||
|
|
@ -130,9 +133,11 @@ const StupWizard = forwardRef((_props: any, ref: any) => {
|
||||||
})
|
})
|
||||||
const CurrencyComponents = () => {
|
const CurrencyComponents = () => {
|
||||||
const [optionsValue, setOperationValue] = useState<'hide' | 'quit'>('hide');
|
const [optionsValue, setOperationValue] = useState<'hide' | 'quit'>('hide');
|
||||||
|
const [voiceStimulation, setVoiceStimulation] = useState(true);
|
||||||
const setting = JSON.parse(storage.getItem('setting') as string)
|
const setting = JSON.parse(storage.getItem('setting') as string)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setOperationValue(setting.closeSetting)
|
setOperationValue(setting.closeSetting)
|
||||||
|
setVoiceStimulation(setting.voiceStimulation)
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -151,6 +156,33 @@ const CurrencyComponents = () => {
|
||||||
<Radio value={'hide'}>不退出程序,最小化到托盘</Radio>
|
<Radio value={'hide'}>不退出程序,最小化到托盘</Radio>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>语音激励 <Popover
|
||||||
|
content={
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
color: 'white'
|
||||||
|
}}>
|
||||||
|
开启语音激励后,会优先显示正在说话的与会成员。
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
title=""
|
||||||
|
>
|
||||||
|
<QuestionCircleOutlined style={{
|
||||||
|
color: 'white',
|
||||||
|
cursor: 'pointer',
|
||||||
|
marginRight: '10px'
|
||||||
|
}} />
|
||||||
|
</Popover></span>
|
||||||
|
<Radio.Group onChange={(e: any) => {
|
||||||
|
setting.voiceStimulation = e.target.value;
|
||||||
|
storage.setItem('setting', JSON.stringify(setting))
|
||||||
|
setVoiceStimulation(e.target.value)
|
||||||
|
}} style={{ flexShrink: 0, margin: '10px 0' }} value={voiceStimulation}>
|
||||||
|
<Radio value={true}>开启</Radio>
|
||||||
|
<Radio value={false}>关闭</Radio>
|
||||||
|
</Radio.Group>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -213,7 +245,8 @@ const VideoComponents = () => {
|
||||||
}, [darkLightEnhancement]);
|
}, [darkLightEnhancement]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof virtualBackground.sourceIndex === 'number') {
|
if (typeof virtualBackground.sourceIndex === 'number') {
|
||||||
if (import.meta.env.VITE_ENV === 'development') {
|
window.electron.getEnv().then(res=>{
|
||||||
|
if (res === 'development') {
|
||||||
window.electron.getAppPath().then((res: string) => {
|
window.electron.getAppPath().then((res: string) => {
|
||||||
const imagePath = path.join(res, 'src', 'assets', 'virtualBackground', `${virtualBackground.sourceIndex + 1}.png`);
|
const imagePath = path.join(res, 'src', 'assets', 'virtualBackground', `${virtualBackground.sourceIndex + 1}.png`);
|
||||||
agora.enableVirtualBackground(virtualBackground.isVirtualBackground, {
|
agora.enableVirtualBackground(virtualBackground.isVirtualBackground, {
|
||||||
|
|
@ -230,6 +263,7 @@ const VideoComponents = () => {
|
||||||
color: Number(virtualBackground.color),
|
color: Number(virtualBackground.color),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
agora.enableVirtualBackground(virtualBackground.isVirtualBackground, {
|
agora.enableVirtualBackground(virtualBackground.isVirtualBackground, {
|
||||||
background_source_type: 1,
|
background_source_type: 1,
|
||||||
|
|
@ -696,7 +730,18 @@ const AudioComponents = () => {
|
||||||
ecordingVolume: e,
|
ecordingVolume: e,
|
||||||
})
|
})
|
||||||
}} disabled={!audioDeviceManager.ecordingItem} />
|
}} disabled={!audioDeviceManager.ecordingItem} />
|
||||||
|
{/* || audioDeviceManager.autoEcordingVolume */}
|
||||||
</div>
|
</div>
|
||||||
|
{/* <div style={{ marginBottom: '10px' }}>
|
||||||
|
<Checkbox onChange={async (e) => {
|
||||||
|
setting.autoEcordingVolume = e.target.checked;
|
||||||
|
storage.setItem('setting', JSON.stringify(setting))
|
||||||
|
setAudioDeviceManager({
|
||||||
|
...audioDeviceManager,
|
||||||
|
autoEcordingVolume: e.target.checked
|
||||||
|
})
|
||||||
|
}} checked={audioDeviceManager.autoEcordingVolume}>自动调整麦克风音量</Checkbox>
|
||||||
|
</div> */}
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<Checkbox checked={audioDeviceManager.isAINoiseReduction} onChange={(e) => {
|
<Checkbox checked={audioDeviceManager.isAINoiseReduction} onChange={(e) => {
|
||||||
|
|
@ -729,16 +774,6 @@ const AudioComponents = () => {
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <div>
|
|
||||||
<Checkbox onChange={async (e) => {
|
|
||||||
setting.autoEcordingVolume = e.target.checked;
|
|
||||||
storage.setItem('setting', JSON.stringify(setting))
|
|
||||||
setAudioDeviceManager({
|
|
||||||
...audioDeviceManager,
|
|
||||||
autoEcordingVolume: e.target.checked
|
|
||||||
})
|
|
||||||
}} checked={audioDeviceManager.autoEcordingVolume}>自动调整麦克风音量</Checkbox>
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className={styles.audioComponentsSelect}>
|
<div className={styles.audioComponentsSelect}>
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,106 @@
|
||||||
import styles from '@/components/UpdateModal/index.module.scss'
|
import styles from '@/components/UpdateModal/index.module.scss'
|
||||||
import ImageUrl from '@/utils/package/imageUrl';
|
import ImageUrl from '@/utils/package/imageUrl';
|
||||||
import { getUpdateUrl } from '@/utils/package/public';
|
import { getUpdateUrl, isVersion } from '@/utils/package/public';
|
||||||
|
import { ExclamationCircleFilled } from '@ant-design/icons';
|
||||||
import { Button, Flex, Modal, Progress } from 'antd';
|
import { Button, Flex, Modal, Progress } from 'antd';
|
||||||
import { forwardRef, useImperativeHandle, useState, memo } from "react";
|
import { forwardRef, useImperativeHandle, useState, memo, useEffect } from "react";
|
||||||
|
const { confirm } = Modal;
|
||||||
|
|
||||||
const UpdateModal = forwardRef((props: any, ref: any) => {
|
const UpdateModal = forwardRef((_props: any, ref: any) => {
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
changeModal: (data: any) => {
|
changeModal: (data: any) => {
|
||||||
|
if (JSON.stringify(data).includes('Error') || JSON.stringify(data).includes('{}')) {
|
||||||
|
setIsError(res => {
|
||||||
|
if (res) {
|
||||||
|
setIsError(false)
|
||||||
|
confirm({
|
||||||
|
keyboard: false,
|
||||||
|
title: '提示',
|
||||||
|
icon: <ExclamationCircleFilled />,
|
||||||
|
content: `更新失败,请尝试手动更新!`,
|
||||||
|
centered: true,
|
||||||
|
okText: '立即更新',
|
||||||
|
wrapClassName: 'hideCancelText',
|
||||||
|
cancelText: '',
|
||||||
|
async onOk() {
|
||||||
|
isVersion((bool: boolean, req: any) => {
|
||||||
|
if (bool && req) {
|
||||||
|
window.electron.getEnv().then(res => {
|
||||||
|
location.href = `${getUpdateUrl(res)}/${req.path}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
let dataJson = JSON.parse(data)
|
let dataJson = JSON.parse(data)
|
||||||
getContent()
|
|
||||||
if (dataJson.type === '0') { // 打开弹窗
|
if (dataJson.type === '0') { // 打开弹窗
|
||||||
setIsUpdateModal(true)
|
setProgress(res => {
|
||||||
|
if (res) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
window.electron.onDownload('1')
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
} else if (dataJson.type === '1') { // 下载中 返回进度值
|
} else if (dataJson.type === '1') { // 下载中 返回进度值
|
||||||
|
if (dataJson.value === 100 && location.hash.indexOf('/meeting') === -1) {
|
||||||
|
setIsUpdateModal(true)
|
||||||
|
getContent()
|
||||||
|
}
|
||||||
setProgress(dataJson.value.toFixed(2))
|
setProgress(dataJson.value.toFixed(2))
|
||||||
} else if (dataJson.type === '2') { // 下载完成
|
} else if (dataJson.type === '2') { // 下载完成
|
||||||
setProgress(100)
|
setProgress(100)
|
||||||
|
if (location.hash.indexOf('/meeting') === -1) {
|
||||||
|
setIsUpdateModal(true)
|
||||||
|
getContent()
|
||||||
|
}
|
||||||
|
} else if (dataJson.type === '3') {
|
||||||
|
if (location.hash.indexOf('/meeting') === -1) {
|
||||||
|
setIsUpdateModal(true)
|
||||||
|
getContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
const [isUpdateModal, setIsUpdateModal] = useState(false);
|
const [isUpdateModal, setIsUpdateModal] = useState(false);
|
||||||
const [progress, setProgress] = useState(0); // 下载进度值
|
const [progress, setProgress] = useState(0); // 下载进度值
|
||||||
const [updateContent, setUpdateContent] = useState('') // 版本更新内容
|
const [updateContent, setUpdateContent] = useState('') // 版本更新内容
|
||||||
|
const [env, setEnv] = useState('')
|
||||||
|
const [_isError, setIsError] = useState(true)
|
||||||
|
useEffect(() => {
|
||||||
|
window.electron.getEnv().then(res => {
|
||||||
|
setEnv(res)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
function getContent() {
|
function getContent() {
|
||||||
fetch(`${getUpdateUrl(import.meta.env.VITE_ENV)}/update.txt?t=${+new Date()}`) // 配置服务器地址
|
window.electron.getEnv().then(res => {
|
||||||
|
fetch(`${getUpdateUrl(res)}/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())
|
||||||
}
|
}
|
||||||
throw new Error('Network response was not ok.');
|
throw new Error('Network response was not ok.');
|
||||||
})
|
})
|
||||||
.then(textContent => {
|
.then(_textContent => {
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(_error => {
|
||||||
});
|
});
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeModal() {
|
function closeModal() {
|
||||||
if (progress != 100) {
|
// if (progress != 100) {
|
||||||
window.electron.onDownload('0') // 取消下载
|
// window.electron.onDownload('0') // 取消下载
|
||||||
}
|
// }
|
||||||
setIsUpdateModal(false)
|
setIsUpdateModal(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,12 +110,12 @@ const UpdateModal = forwardRef((props: any, ref: any) => {
|
||||||
title=""
|
title=""
|
||||||
open={isUpdateModal}
|
open={isUpdateModal}
|
||||||
footer={null}
|
footer={null}
|
||||||
// onCancel={() => closeModal()}
|
onCancel={() => closeModal()}
|
||||||
centered
|
centered
|
||||||
width={'400px'}
|
width={'400px'}
|
||||||
className='modal-padding'
|
className='modal-padding'
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
closeIcon={false}
|
closeIcon={progress === 100 ? false : true}
|
||||||
>
|
>
|
||||||
<div className={styles.isUpdateModal} style={{ backgroundImage: `url(${ImageUrl.icon7})` }}>
|
<div className={styles.isUpdateModal} style={{ backgroundImage: `url(${ImageUrl.icon7})` }}>
|
||||||
<div className={styles.remarks} dangerouslySetInnerHTML={{ __html: updateContent }}>
|
<div className={styles.remarks} dangerouslySetInnerHTML={{ __html: updateContent }}>
|
||||||
|
|
@ -67,7 +128,7 @@ const UpdateModal = forwardRef((props: any, ref: any) => {
|
||||||
style={{ width: '100%', height: '40px', marginBottom: '10px' }}
|
style={{ width: '100%', height: '40px', marginBottom: '10px' }}
|
||||||
className={`m-ant-btn`}
|
className={`m-ant-btn`}
|
||||||
>立即更新</Button>
|
>立即更新</Button>
|
||||||
{import.meta.env.VITE_ENV === "development" ? <div className={styles.button2} onClick={() => setIsUpdateModal(false)}>暂不更新</div> : null}
|
{env === "development" ? <div className={styles.button2} onClick={() => setIsUpdateModal(false)}>暂不更新</div> : null}
|
||||||
</div> : progress < 100 ?
|
</div> : progress < 100 ?
|
||||||
<div style={{ margin: '20px 0' }}>
|
<div style={{ margin: '20px 0' }}>
|
||||||
下载进度:{progress}%
|
下载进度:{progress}%
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,10 @@ const UserName = forwardRef((props: any, ref: any) => {
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const stateInfo = await JSON.parse(storage.getItem('stateInfo') as string);
|
const stateInfo = await JSON.parse(storage.getItem('stateInfo') as string);
|
||||||
if (info.userName) {
|
if (info.userName) {
|
||||||
|
if (info.userName.length > 10) {
|
||||||
|
message.error('用户名称最多10个字!')
|
||||||
|
return
|
||||||
|
}
|
||||||
PutAlterUname({
|
PutAlterUname({
|
||||||
nickName: info.userName,
|
nickName: info.userName,
|
||||||
roomNum: stateInfo.channelId,
|
roomNum: stateInfo.channelId,
|
||||||
|
|
|
||||||
|
|
@ -121,14 +121,6 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
>div:nth-child(2) {
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
>img {
|
|
||||||
width: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
>div:nth-child(2) {
|
>div:nth-child(2) {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ 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, Select, Radio } from "antd";
|
import { Button, Input, Modal, Pagination, Empty, message, Popover, Popconfirm, DatePicker, Select, Radio } from "antd";
|
||||||
import { GetRoom, PostRoom, GetCheckoutRoomNum, GetRoomRtcToken, DeleteRoom, GetRecord, PostRoomInfo, GetQrcode } from '@/api/Home/Index';
|
import { GetRoom, PostRoom, GetCheckoutRoomNum, GetRoomRtcToken, DeleteRoom, GetRecord, PostRoomInfo } from '@/api/Home/Index';
|
||||||
import ImageUrl from '@/utils/package/imageUrl'
|
import ImageUrl from '@/utils/package/imageUrl'
|
||||||
import { ExclamationCircleFilled, ReloadOutlined } from '@ant-design/icons';
|
import { ExclamationCircleFilled, ReloadOutlined } from '@ant-design/icons';
|
||||||
import JoinSetting from '@/components/JoinSetting';
|
import JoinSetting from '@/components/JoinSetting';
|
||||||
|
|
@ -14,6 +14,10 @@ import dayjs from 'dayjs';
|
||||||
import StupWizard from '@/components/StupWizard';
|
import StupWizard from '@/components/StupWizard';
|
||||||
import { GetSubDpList } from '@/api/Home/User';
|
import { GetSubDpList } from '@/api/Home/User';
|
||||||
import FeedBackModel from '@/components/FeedBackModel';
|
import FeedBackModel from '@/components/FeedBackModel';
|
||||||
|
import { PostHomeVerLog } from '@/api/Meeting';
|
||||||
|
import Code from '@/components/Code';
|
||||||
|
import { isVersion } from "@/utils/package/public";
|
||||||
|
|
||||||
const { setInterval, clearInterval } = require('timers');
|
const { setInterval, clearInterval } = require('timers');
|
||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
const { exec } = require('child_process');
|
const { exec } = require('child_process');
|
||||||
|
|
@ -46,7 +50,6 @@ const Index: React.FC = () => {
|
||||||
const [timeData, setTimeData] = useState<any>([]);
|
const [timeData, setTimeData] = useState<any>([]);
|
||||||
const [isCreateRoom, setIsCreateRoom] = useState<boolean>(false);
|
const [isCreateRoom, setIsCreateRoom] = useState<boolean>(false);
|
||||||
const [allowAnonymous, setAllowAnonymous] = useState(true);
|
const [allowAnonymous, setAllowAnonymous] = useState(true);
|
||||||
const [baseImage, setBaseImage] = useState('');
|
|
||||||
const userInfo = JSON.parse(storage.getItem('user') as string)
|
const userInfo = JSON.parse(storage.getItem('user') as string)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setUser(userInfo)
|
setUser(userInfo)
|
||||||
|
|
@ -245,35 +248,7 @@ const Index: React.FC = () => {
|
||||||
<span>{item.roomNum}</span>
|
<span>{item.roomNum}</span>
|
||||||
<img src={ImageUrl.icon10} alt="" />
|
<img src={ImageUrl.icon10} alt="" />
|
||||||
</div>
|
</div>
|
||||||
<Popover
|
<Code roomNum={item.roomNum}></Code>
|
||||||
placement="bottom"
|
|
||||||
onOpenChange={(e: boolean) => {
|
|
||||||
setBaseImage('')
|
|
||||||
if (e) {
|
|
||||||
GetQrcode(item.roomNum, import.meta.env.VITE_ENV === 'development' ? 'trial' : 'release').then(res => {
|
|
||||||
if (res.code === 200) {
|
|
||||||
setBaseImage(res.data)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
content={
|
|
||||||
baseImage ? <div>
|
|
||||||
<img style={{ width: '200px', margin: '0 auto' }} src={`data:image/png;base64,${baseImage}`} alt="" />
|
|
||||||
<div style={{ color: 'white', textAlign: 'center', fontSize: '16px', marginTop: '10px' }}>
|
|
||||||
<span>微信中长按图片识别小程序码</span><br />
|
|
||||||
<span>加入会议</span>
|
|
||||||
</div>
|
|
||||||
</div> : <div>
|
|
||||||
<Empty description={'二维码加载中,请稍后'} />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div title='小程序'>
|
|
||||||
<img src={ImageUrl.icon55} alt="" />
|
|
||||||
</div>
|
|
||||||
</Popover>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{role.ID.includes(userInfo.roleId) ? <Popover
|
{role.ID.includes(userInfo.roleId) ? <Popover
|
||||||
|
|
@ -335,13 +310,26 @@ const Index: React.FC = () => {
|
||||||
<Button type="primary"
|
<Button type="primary"
|
||||||
iconPosition={'end'}
|
iconPosition={'end'}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
storage.setItem('loading', true)
|
||||||
|
isVersion((bool: boolean) => {
|
||||||
|
storage.setItem('loading', false)
|
||||||
|
if (bool) {
|
||||||
|
window.electron.onDownload('3')
|
||||||
|
} else {
|
||||||
if (role.ID.includes(userInfo.roleId)) {
|
if (role.ID.includes(userInfo.roleId)) {
|
||||||
joinSettingRef.current.changeModal(item.roomNum)
|
joinSettingRef.current.changeModal(item.roomNum)
|
||||||
} else {
|
} else {
|
||||||
storage.setItem('loading', true)
|
storage.setItem('loading', true)
|
||||||
postRefresh(() => {
|
postRefresh(() => {
|
||||||
getRoomRtcToken(item.roomNum, (options: any) => {
|
getRoomRtcToken(item.roomNum, async (options: any) => {
|
||||||
if (options) {
|
if (options) {
|
||||||
|
await window.electron.getVersion().then(async req => {
|
||||||
|
await PostHomeVerLog({
|
||||||
|
version: req,
|
||||||
|
platformType: 1,
|
||||||
|
roomNum: item.roomNum,
|
||||||
|
})
|
||||||
|
})
|
||||||
navigate(`/meeting`, {
|
navigate(`/meeting`, {
|
||||||
state: {
|
state: {
|
||||||
channelId: item.roomNum,
|
channelId: item.roomNum,
|
||||||
|
|
@ -357,6 +345,8 @@ const Index: React.FC = () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
icon={<img src={ImageUrl.icon9} alt="" />}
|
icon={<img src={ImageUrl.icon9} alt="" />}
|
||||||
className='m-ant-btn'>
|
className='m-ant-btn'>
|
||||||
|
|
|
||||||
|
|
@ -458,6 +458,9 @@ const User: React.FC = () => {
|
||||||
if (!addUserFrom.UserName && isCreateUser !== 'batch') {
|
if (!addUserFrom.UserName && isCreateUser !== 'batch') {
|
||||||
return message.error('请输入用户名称!')
|
return message.error('请输入用户名称!')
|
||||||
}
|
}
|
||||||
|
if (addUserFrom.UserName.length > 10) {
|
||||||
|
return message.error('用户名称最多10个字!')
|
||||||
|
}
|
||||||
if (addUserFrom.year === '') {
|
if (addUserFrom.year === '') {
|
||||||
return message.error('请输入届!')
|
return message.error('请输入届!')
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,8 +120,26 @@
|
||||||
|
|
||||||
@else if $i ==4 {
|
@else if $i ==4 {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
>div:nth-child(1) {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
>span:nth-child(2) {
|
||||||
|
background-color: red;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0px 4px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
>div:nth-child(2) {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@else if $i ==5 {
|
@else if $i ==5 {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import styles from '@/page/Home/index.module.scss'
|
import styles from '@/page/Home/index.module.scss'
|
||||||
import { useEffect, useState, useRef } from "react";
|
import { useEffect, useState, useRef } from "react";
|
||||||
import { Outlet, useNavigate } from 'react-router-dom';
|
import { Outlet, useNavigate } from 'react-router-dom';
|
||||||
import { Popconfirm, Popover } from 'antd';
|
import { Button, Popconfirm, Popover } from 'antd';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import 'dayjs/locale/zh-cn'
|
import 'dayjs/locale/zh-cn'
|
||||||
import { storage } from '@/utils';
|
import { storage } from '@/utils';
|
||||||
|
|
@ -45,6 +45,7 @@ const Home: React.FC = () => {
|
||||||
]);
|
]);
|
||||||
const [userInfo, setUserInfo] = useState<any>({})
|
const [userInfo, setUserInfo] = useState<any>({})
|
||||||
const [version, setVersion] = useState<string>('')
|
const [version, setVersion] = useState<string>('')
|
||||||
|
const [update, setUpdate] = useState(false)
|
||||||
const [dateInfo, setDateInfo] = useState<{
|
const [dateInfo, setDateInfo] = useState<{
|
||||||
work: string;
|
work: string;
|
||||||
time: string;
|
time: string;
|
||||||
|
|
@ -67,11 +68,18 @@ const Home: React.FC = () => {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
const timer = setInterval(updateTime, 1000);
|
const timer = setInterval(updateTime, 1000);
|
||||||
|
window.addEventListener('customStorageChange', handleCustomStorageChange);
|
||||||
return () => {
|
return () => {
|
||||||
|
window.removeEventListener('customStorageChange', handleCustomStorageChange);
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleCustomStorageChange = (e: any): void => {
|
||||||
|
if (e.key === 'isUpdate') {
|
||||||
|
setUpdate(e.value)
|
||||||
|
}
|
||||||
|
};
|
||||||
const changtNavList = (index: number, bool?: boolean): void => {
|
const changtNavList = (index: number, bool?: boolean): void => {
|
||||||
const newNavList = [...navList];
|
const newNavList = [...navList];
|
||||||
if (typeof bool === 'boolean') {
|
if (typeof bool === 'boolean') {
|
||||||
|
|
@ -126,14 +134,22 @@ const Home: React.FC = () => {
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
<div className='drag'>
|
||||||
<div>
|
<div>
|
||||||
版本号:{version}
|
<span>版本号:{version}</span>
|
||||||
|
{update ? <span>new</span> : null}
|
||||||
|
</div>
|
||||||
|
{update ? <div>
|
||||||
|
<Button type="primary" className='m-ant-btn' style={{ width: '100%' }} onClick={() => {
|
||||||
|
window.electron.onDownload('3')
|
||||||
|
}}>立即更新</Button>
|
||||||
|
</div> : null}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Popover
|
<Popover
|
||||||
placement="right"
|
placement="right"
|
||||||
content={
|
content={
|
||||||
<img style={{ width: '400px' }} src={'https://meeting-api.23544.com/meeting/update/ddq.png'} alt="" />
|
<img style={{ width: '400px' }} src={`https://meeting-api.23544.com/meeting/update/ddq.png?t=${+new Date()}`} alt="" />
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className='drag' title='反馈建议'>
|
<div className='drag' title='反馈建议'>
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,14 @@ import { useEffect, useState } from "react";
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { Input, Button, Checkbox, message, Modal } from "antd"
|
import { Input, Button, Checkbox, message, Modal } from "antd"
|
||||||
import { storage } from '@/utils'
|
import { storage } from '@/utils'
|
||||||
import { GetCheckUser, PostAnonLogin, PostLogin } from '@/api/Login'
|
import { GetCheckOnline, GetCheckUser, PostAnonLogin, PostLogin } from '@/api/Login'
|
||||||
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 { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { GetCheckoutRoomNum, GetRoomInfo, GetRoomRtcToken } from '@/api/Home/Index';
|
import { GetCheckoutRoomNum, GetRoomInfo, GetRoomRtcToken } from '@/api/Home/Index';
|
||||||
|
import { ExclamationCircleFilled } from '@ant-design/icons';
|
||||||
|
import { isVersion } from '@/utils/package/public';
|
||||||
|
const { confirm } = Modal;
|
||||||
const Login: React.FC = () => {
|
const Login: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [accountPasswordStatus, setAccountPasswordStatus] = useState<boolean>(false);
|
const [accountPasswordStatus, setAccountPasswordStatus] = useState<boolean>(false);
|
||||||
|
|
@ -37,13 +40,16 @@ const Login: React.FC = () => {
|
||||||
roomNum: '',
|
roomNum: '',
|
||||||
})
|
})
|
||||||
const [nameModal, setNameModal] = useState(false)
|
const [nameModal, setNameModal] = useState(false)
|
||||||
|
const [env, setEnv] = useState('')
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.electron.setMainWindowSize({
|
window.electron.setMainWindowSize({
|
||||||
width: 752,
|
width: 752,
|
||||||
height: 520,
|
height: 520,
|
||||||
key: 'login'
|
key: 'login'
|
||||||
})
|
})
|
||||||
|
window.electron.getEnv().then(res => {
|
||||||
|
setEnv(res)
|
||||||
|
})
|
||||||
if (storage.getItem('login')) {
|
if (storage.getItem('login')) {
|
||||||
const login = JSON.parse(storage.getItem('login') as string);
|
const login = JSON.parse(storage.getItem('login') as string);
|
||||||
const data = {
|
const data = {
|
||||||
|
|
@ -100,7 +106,32 @@ const Login: React.FC = () => {
|
||||||
}
|
}
|
||||||
GetCheckUser(operation.account).then(res => {
|
GetCheckUser(operation.account).then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
res.data ? setAccountPasswordStatus(true) : message.error('账号不存在!')
|
if (res.data) {
|
||||||
|
GetCheckOnline(operation.account).then(req => {
|
||||||
|
if (req.code === 200) {
|
||||||
|
if (req.data) {
|
||||||
|
confirm({
|
||||||
|
title: '提示',
|
||||||
|
icon: <ExclamationCircleFilled />,
|
||||||
|
content: `账号已在其他地方登录,是否强制登陆?`,
|
||||||
|
centered: true,
|
||||||
|
okText: '确定',
|
||||||
|
cancelText: '取消',
|
||||||
|
async onOk() {
|
||||||
|
setAccountPasswordStatus(true)
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setAccountPasswordStatus(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
message.error('账号不存在!')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +204,7 @@ const Login: React.FC = () => {
|
||||||
<>
|
<>
|
||||||
<div className={styles.login}>
|
<div className={styles.login}>
|
||||||
<div className={styles.loginBg}>
|
<div className={styles.loginBg}>
|
||||||
<img src={import.meta.env.VITE_ENV === 'xy' ? ImageUrl.icon53 : ImageUrl.icon1} alt="" />
|
{env ? <img src={env === 'xy' ? ImageUrl.icon53 : ImageUrl.icon1} alt="" /> : null}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.loginContent}>
|
<div className={styles.loginContent}>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -315,6 +346,15 @@ const Login: React.FC = () => {
|
||||||
if (!anonInfo.nickName) {
|
if (!anonInfo.nickName) {
|
||||||
return message.error('请输入参会昵称!')
|
return message.error('请输入参会昵称!')
|
||||||
}
|
}
|
||||||
|
if (anonInfo.nickName.length > 10) {
|
||||||
|
return message.error('参会昵称最多10个字!')
|
||||||
|
}
|
||||||
|
storage.setItem('loading', true)
|
||||||
|
isVersion((bool: boolean) => {
|
||||||
|
storage.setItem('loading', false)
|
||||||
|
if (bool) {
|
||||||
|
window.electron.onDownload('3')
|
||||||
|
} else {
|
||||||
storage.setItem('loading', true)
|
storage.setItem('loading', true)
|
||||||
PostAnonLogin(anonInfo).then(async (res) => {
|
PostAnonLogin(anonInfo).then(async (res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
|
|
@ -357,6 +397,8 @@ const Login: React.FC = () => {
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
storage.setItem('loading', false)
|
storage.setItem('loading', false)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}}>进入</Button>
|
}}>进入</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #F3F3F5;
|
color: #F3F3F5;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
>div {}
|
>div {}
|
||||||
|
|
@ -77,6 +79,8 @@
|
||||||
>span {
|
>span {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #F3F3F5;
|
color: #F3F3F5;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
>div {
|
>div {
|
||||||
|
|
|
||||||
|
|
@ -206,19 +206,30 @@ const ChatBigWindow: React.FC = () => {
|
||||||
>移出会议</Button> : null}
|
>移出会议</Button> : null}
|
||||||
</div> : <div style={{ color: 'white' }}>用户不在房间内</div>
|
</div> : <div style={{ color: 'white' }}>用户不在房间内</div>
|
||||||
}>
|
}>
|
||||||
<div>
|
<div title={item.userName}>
|
||||||
<div><Avatar name={item.userName} /></div>
|
<div><Avatar name={item.userName} /></div>
|
||||||
{item.uid !== user.uid ?
|
{item.uid !== user.uid ?
|
||||||
<span>{item.userName} <span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
|
<span>
|
||||||
<span> <span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
|
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '150px' }}>{item.userName}</span>
|
||||||
|
<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>
|
||||||
|
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '150px' }}>{item.userName}</span>
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</Popover> : <div>
|
</Popover> : <div title={item.userName}>
|
||||||
<div><Avatar name={item.userName} /></div>
|
<div><Avatar name={item.userName} /></div>
|
||||||
{item.uid !== user.uid ?
|
{item.uid !== user.uid ?
|
||||||
<span>{item.userName}<span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
|
<span>
|
||||||
<span><span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
|
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '150px' }}>{item.userName}</span>
|
||||||
|
<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>
|
||||||
|
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '150px' }}>{item.userName}</span>
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
</div>}
|
</div>}
|
||||||
<div>{item.message}</div>
|
<div>{item.message}</div>
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
>span:nth-child(1) {
|
>span:nth-child(1) {
|
||||||
white-space: nowrap;
|
word-break: break-all;
|
||||||
color: #ff970f;
|
color: #ff970f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,10 @@ const NoticeWindow: React.FC = () => {
|
||||||
api.open({
|
api.open({
|
||||||
message: '',
|
message: '',
|
||||||
description: <div>
|
description: <div>
|
||||||
<span style={{ fontSize: '16px' }}>{noticeItem.uname}申请发言</span>
|
<div style={{ fontSize: '16px' }}>
|
||||||
|
<div style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={noticeItem.uname}>{noticeItem.uname}</div>
|
||||||
|
<div>申请发言</div>
|
||||||
|
</div>
|
||||||
<div style={{ display: 'flex', justifyContent: 'flex-end' }} className='drag'>
|
<div style={{ display: 'flex', justifyContent: 'flex-end' }} className='drag'>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ const ShareScreenWindow: React.FC = () => {
|
||||||
}}
|
}}
|
||||||
key={index}>
|
key={index}>
|
||||||
<div>
|
<div>
|
||||||
{!item.active ? <div style={{ backgroundImage: `url(${ImageUrl.icon49})` }} id={`micr-item-${userInfo.uid}`}>
|
{!item.active ? <div style={{ backgroundImage: `url(${ImageUrl.icon49})`, transition: '0.18s' }} id={`micr-item-${userInfo.uid}`}>
|
||||||
</div> : ''}
|
</div> : ''}
|
||||||
{item.select ? <img src={item.iconSelect} alt="" /> : <img src={item.active ? item.iconActive : item.icon} alt="" />}
|
{item.select ? <img src={item.iconSelect} alt="" /> : <img src={item.active ? item.iconActive : item.icon} alt="" />}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@
|
||||||
|
|
||||||
// 演讲者模式
|
// 演讲者模式
|
||||||
.meetingContentBodyLeftSpeakerMode {
|
.meetingContentBodyLeftSpeakerMode {
|
||||||
width: 18%;
|
width: 270px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
|
@ -312,7 +312,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.meetingContentSwiperCard {
|
.meetingContentSwiperCard {
|
||||||
height: calc(100% / 6);
|
height: 160px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -379,7 +379,7 @@
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
height: 100% !important;
|
height: 100% !important;
|
||||||
width: calc(100% - 18%) !important;
|
width: calc(100% - 270px) !important;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -390,7 +390,7 @@
|
||||||
|
|
||||||
.meetingContentSwiperCard {
|
.meetingContentSwiperCard {
|
||||||
height: 160px;
|
height: 160px;
|
||||||
width: calc(100% / 6);
|
width: 270px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -444,8 +444,8 @@
|
||||||
color: white;
|
color: white;
|
||||||
border: 1px white solid;
|
border: 1px white solid;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
width: 30px;
|
width: 25px;
|
||||||
height: 30px;
|
height: 25px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -549,6 +549,8 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #F3F3F5;
|
color: #F3F3F5;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
>div {
|
>div {
|
||||||
|
|
@ -660,6 +662,8 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #F3F3F5;
|
color: #F3F3F5;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -689,6 +693,8 @@
|
||||||
>span {
|
>span {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #F3F3F5;
|
color: #F3F3F5;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
>div {
|
>div {
|
||||||
|
|
@ -798,7 +804,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
>img {
|
>img {
|
||||||
height: 50px;
|
height: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
>span {
|
>span {
|
||||||
|
|
@ -820,8 +826,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
>label {
|
>label {
|
||||||
height: 50px;
|
height: 35px;
|
||||||
height: 50px;
|
height: 35px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,12 @@ import { SearchOutlined, EllipsisOutlined, ExclamationCircleFilled, FullscreenEx
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import { thumbImageBufferToBase64 } from '@/utils/package/base64'
|
import { thumbImageBufferToBase64 } from '@/utils/package/base64'
|
||||||
import { storage } from '@/utils';
|
import { storage } from '@/utils';
|
||||||
import { GetRoomUser, PostOpenMicr, GetSharedScreen, PostOpenCamera, GetLeaveAll, PostRoomManager, DeleteRoomManager, GetRoomKickout, GetShowUser, PostShowUser, PostMuteAll, GetRoomUserItem, GetApplySpeak, PostSharedScreen } from '@/api/Meeting';
|
import { GetRoomUser, PostOpenMicr, GetSharedScreen, PostOpenCamera, GetLeaveAll, PostRoomManager, DeleteRoomManager, GetRoomKickout, GetShowUser, PostShowUser, PostMuteAll, GetRoomUserItem, GetApplySpeak, PostSharedScreen, PostStopSharedScreen } from '@/api/Meeting';
|
||||||
import ImageUrl from '@/utils/package/imageUrl'
|
import ImageUrl from '@/utils/package/imageUrl'
|
||||||
import { agora } from '@/utils/package/agora'
|
import { agora } from '@/utils/package/agora'
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import durationPlugin from 'dayjs/plugin/duration';
|
import durationPlugin from 'dayjs/plugin/duration';
|
||||||
import { AudioVolumeInfo, ConnectionChangedReasonType, ConnectionStateType, LocalVideoStreamReason, LocalVideoStreamState, RenderModeType, RtcConnection, RtcStats, UserOfflineReasonType, VideoSourceType, VideoStreamType } from 'agora-electron-sdk';
|
import { AudioVolumeInfo, ConnectionChangedReasonType, ConnectionStateType, LocalVideoStreamReason, LocalVideoStreamState, RenderModeType, RtcConnection, RtcStats, StreamPublishState, 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';
|
||||||
|
|
@ -26,6 +26,7 @@ import MeetingDisconnected from '@/components/MeetingDisconnected';
|
||||||
import SingIn from '@/components/SingIn';
|
import SingIn from '@/components/SingIn';
|
||||||
import UserName from '@/components/UserName';
|
import UserName from '@/components/UserName';
|
||||||
import { GetRoomRtcToken } from '@/api/Home/Index';
|
import { GetRoomRtcToken } from '@/api/Home/Index';
|
||||||
|
import Code from '@/components/Code';
|
||||||
const { setTimeout, setInterval, clearTimeout, clearInterval } = require('timers');
|
const { setTimeout, setInterval, clearTimeout, clearInterval } = require('timers');
|
||||||
const { confirm } = Modal;
|
const { confirm } = Modal;
|
||||||
const { exec } = require('child_process');
|
const { exec } = require('child_process');
|
||||||
|
|
@ -158,6 +159,8 @@ const Meeting: React.FC = () => {
|
||||||
itemIndex: 0,
|
itemIndex: 0,
|
||||||
rowIndex: 0,
|
rowIndex: 0,
|
||||||
});
|
});
|
||||||
|
const [_audioStatus, setAudioStatus] = useState<StreamPublishState>(1);
|
||||||
|
const [_videoStatus, setVideoStatus] = useState<StreamPublishState>(1);
|
||||||
const [roomUserList, setRoomUserList] = useState<any>([])
|
const [roomUserList, setRoomUserList] = useState<any>([])
|
||||||
const [_speackUid, setSpeackUid] = useState<any>([])
|
const [_speackUid, setSpeackUid] = useState<any>([])
|
||||||
const [currentSpeakUser, setCurrentSpeakUser] = useState<any>([])
|
const [currentSpeakUser, setCurrentSpeakUser] = useState<any>([])
|
||||||
|
|
@ -215,6 +218,7 @@ const Meeting: React.FC = () => {
|
||||||
});
|
});
|
||||||
const [isVideoFullScreen, setIsVideoFullScreen] = useState<boolean>(false)
|
const [isVideoFullScreen, setIsVideoFullScreen] = useState<boolean>(false)
|
||||||
const [observer, setObserver] = useState<IntersectionObserver>()
|
const [observer, setObserver] = useState<IntersectionObserver>()
|
||||||
|
const [_activeSpeaker, setActiveSpeaker] = useState('')
|
||||||
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');
|
const channel = new BroadcastChannel('meeting_channel');
|
||||||
|
|
@ -272,7 +276,7 @@ const Meeting: React.FC = () => {
|
||||||
case 'shareScreenWindowClose':
|
case 'shareScreenWindowClose':
|
||||||
setCurrentSeconds(shareScreenWindowClose)
|
setCurrentSeconds(shareScreenWindowClose)
|
||||||
await stopScreenCapture()
|
await stopScreenCapture()
|
||||||
await allUserLook(userInfo.uid, userInfo.userName)
|
await allUserLook(userInfo.uid, userInfo.userName, true)
|
||||||
break;
|
break;
|
||||||
case 'shareScreenWindowfooterListsTitle':
|
case 'shareScreenWindowfooterListsTitle':
|
||||||
switch (shareScreenWindowfooterListsTitle) {
|
switch (shareScreenWindowfooterListsTitle) {
|
||||||
|
|
@ -719,7 +723,7 @@ const Meeting: React.FC = () => {
|
||||||
break;
|
break;
|
||||||
// 扩展操作
|
// 扩展操作
|
||||||
case 'Operation':
|
case 'Operation':
|
||||||
switch (item.type) {
|
switch (item.contentString) {
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -782,6 +786,14 @@ const Meeting: React.FC = () => {
|
||||||
break;
|
break;
|
||||||
// 发言人用户信息刷新
|
// 发言人用户信息刷新
|
||||||
case 'ManagerRefresh':
|
case 'ManagerRefresh':
|
||||||
|
if (!item.user.isRoomManager) {
|
||||||
|
setCurrentVideoId((res: any) => {
|
||||||
|
if (res === String(item.user.uid)) {
|
||||||
|
getShowUser()
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
}
|
||||||
setAllUserListData('ManagerRefresh', item, async () => {
|
setAllUserListData('ManagerRefresh', item, async () => {
|
||||||
if (item.user.uid === item.uid) {
|
if (item.user.uid === item.uid) {
|
||||||
if (item.user.uid === userInfo.uid) {
|
if (item.user.uid === userInfo.uid) {
|
||||||
|
|
@ -821,8 +833,6 @@ const Meeting: React.FC = () => {
|
||||||
break;
|
break;
|
||||||
// 申请发言
|
// 申请发言
|
||||||
case 'ApplyToSpeak':
|
case 'ApplyToSpeak':
|
||||||
setIsScreenCapture(bool => {
|
|
||||||
if (bool) {
|
|
||||||
window.electron.setChildWindowShow({
|
window.electron.setChildWindowShow({
|
||||||
key: 'noticeWindow',
|
key: 'noticeWindow',
|
||||||
bool: true
|
bool: true
|
||||||
|
|
@ -831,63 +841,6 @@ const Meeting: React.FC = () => {
|
||||||
type: 'noticeItem',
|
type: 'noticeItem',
|
||||||
noticeItem: item
|
noticeItem: item
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
api.open({
|
|
||||||
message: '',
|
|
||||||
description: <div>
|
|
||||||
<span style={{ fontSize: '16px' }}>{item.uname}申请发言</span>
|
|
||||||
<div style={{ display: 'flex', justifyContent: 'flex-end' }} className='drag'>
|
|
||||||
<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()
|
|
||||||
postRoomManager({
|
|
||||||
roomId: state.roomId,
|
|
||||||
roomNum: state.channelId,
|
|
||||||
userId: item.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>,
|
|
||||||
duration: 10,
|
|
||||||
placement: 'bottomRight',
|
|
||||||
showProgress: true,
|
|
||||||
pauseOnHover: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return bool
|
|
||||||
})
|
|
||||||
break;
|
break;
|
||||||
// 管理员查看随机用户
|
// 管理员查看随机用户
|
||||||
case 'Watch':
|
case 'Watch':
|
||||||
|
|
@ -932,7 +885,7 @@ const Meeting: React.FC = () => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
playBackDeviceId: res[1].playBackList.find((row: any) => row.deviceId === setting.playBackDeviceId) ? setting.playBackDeviceId : res[1].playBackList.length ? res[1].playBackList[0].deviceId : null,
|
playBackDeviceId: res[1].playBackList.find((row: any) => row.deviceId === setting.playBackDeviceId) ? setting.playBackDeviceId : res[1].playBackList.length ? res[1].playBackList[0].deviceId : null,
|
||||||
ecordingVolume: res[1].ecordingVolume
|
ecordingVolume: setting.ecordingVolume
|
||||||
}
|
}
|
||||||
window.electron.onInvoke('sendDrivers', {
|
window.electron.onInvoke('sendDrivers', {
|
||||||
uid: item.callerUid,
|
uid: item.callerUid,
|
||||||
|
|
@ -1023,10 +976,35 @@ const Meeting: React.FC = () => {
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
// 共享
|
// 设置发言人
|
||||||
case 'SetSpeaker':
|
case 'SetSpeaker':
|
||||||
window.electron.onInvoke('SetSpeakerCallback', item.RoomManagerInputDTO)
|
window.electron.onInvoke('SetSpeakerCallback', item.RoomManagerInputDTO)
|
||||||
break;
|
break;
|
||||||
|
// 扩展参数
|
||||||
|
case 'ReceivedOperation':
|
||||||
|
try {
|
||||||
|
const temp = JSON.parse(item.contentString)
|
||||||
|
if (temp.type === 'audio') {
|
||||||
|
await PostOpenMicr({
|
||||||
|
roomNum: temp.roomNum,
|
||||||
|
uid: temp.uid,
|
||||||
|
enableMicr: temp.enableMicr
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await PostOpenCamera({
|
||||||
|
roomNum: temp.roomNum,
|
||||||
|
uid: temp.uid,
|
||||||
|
enableCamera: temp.enableCamera
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// 共享人取消共享屏幕
|
||||||
|
case 'StopedSharedScreen':
|
||||||
|
setVideoUser()
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return () => {
|
return () => {
|
||||||
|
|
@ -1182,6 +1160,61 @@ const Meeting: React.FC = () => {
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}, [isClickedMediaSteam]);
|
}, [isClickedMediaSteam]);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// let timer: NodeJS.Timeout | string = '';
|
||||||
|
// if (audioStatus === 1 && videoStatus === 1) {
|
||||||
|
// if (timer) {
|
||||||
|
// clearTimeout(timer)
|
||||||
|
// timer = ''
|
||||||
|
// }
|
||||||
|
// timer = setTimeout(() => {
|
||||||
|
// setIsShare((req: any) => {
|
||||||
|
// if (!req) {
|
||||||
|
// setRoomUserList((res: any) => {
|
||||||
|
// let userItem = res.find((item: any) => item.uid === userInfo.uid)
|
||||||
|
// if (!role.ID.includes(userInfo.roleId) && userItem && userItem.isRoomManager) {
|
||||||
|
// DeleteRoomManager({
|
||||||
|
// roomId: state.roomId,
|
||||||
|
// roomNum: state.channelId,
|
||||||
|
// userId: userInfo.uid
|
||||||
|
// })
|
||||||
|
// confirm({
|
||||||
|
// title: '提示',
|
||||||
|
// icon: <ExclamationCircleFilled />,
|
||||||
|
// content: `由于您长时间未发言,已自动取消发言权限,是否重新申请发言?`,
|
||||||
|
// centered: true,
|
||||||
|
// okText: '确定',
|
||||||
|
// cancelText: '取消',
|
||||||
|
// async onOk() {
|
||||||
|
// GetApplySpeak(state.channelId).then(res => {
|
||||||
|
// if (res.code === 200) {
|
||||||
|
// setIsClicked(true);
|
||||||
|
// message.success('申请发言成功')
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// },
|
||||||
|
// onCancel() {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// clearTimeout(timer)
|
||||||
|
// timer = ''
|
||||||
|
// return res
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// return req
|
||||||
|
// })
|
||||||
|
// }, 1000 * 60 * 5);
|
||||||
|
// } else {
|
||||||
|
// if (timer) {
|
||||||
|
// clearTimeout(timer)
|
||||||
|
// timer = ''
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return () => timer ? clearTimeout(timer) : '';
|
||||||
|
// }, [audioStatus, videoStatus]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let timer: NodeJS.Timeout | undefined;
|
let timer: NodeJS.Timeout | undefined;
|
||||||
if (timer) {
|
if (timer) {
|
||||||
|
|
@ -1313,6 +1346,32 @@ const Meeting: React.FC = () => {
|
||||||
channelId: connection.channelId,
|
channelId: connection.channelId,
|
||||||
renderMode: RenderModeType.RenderModeFit
|
renderMode: RenderModeType.RenderModeFit
|
||||||
})
|
})
|
||||||
|
setCurrentVideoId((res: any) => {
|
||||||
|
if (res === String(remoteUid)) {
|
||||||
|
let dom: any;
|
||||||
|
setCurrentLookUserStatus(req => {
|
||||||
|
switch (req) {
|
||||||
|
case 1:
|
||||||
|
dom = document.getElementById(`video-source-camera-primary`) as HTMLElement
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
dom = document.getElementById(`video-source-screen`) as HTMLElement;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
dom = document.getElementById(`video-source-remote-screen`) as HTMLElement
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
dom = document.getElementById(`video-source-remote-camera`) as HTMLElement
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dom && dom.childNodes.length === 1) {
|
||||||
|
renderVideo(String(remoteUid))
|
||||||
|
}
|
||||||
|
return req
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1369,6 +1428,20 @@ const Meeting: React.FC = () => {
|
||||||
} else if (state === 3) {
|
} else if (state === 3) {
|
||||||
meetingDisconnectedRef.current.changeModal(false)
|
meetingDisconnectedRef.current.changeModal(false)
|
||||||
setIsAgoraDisconnected(false)
|
setIsAgoraDisconnected(false)
|
||||||
|
} else if (state === 5) {
|
||||||
|
confirm({
|
||||||
|
keyboard: false,
|
||||||
|
title: '提示',
|
||||||
|
icon: <ExclamationCircleFilled />,
|
||||||
|
content: `重连失败,请退出房间重试!`,
|
||||||
|
centered: true,
|
||||||
|
okText: '退出',
|
||||||
|
wrapClassName: 'hideCancelText',
|
||||||
|
cancelText: '',
|
||||||
|
async onOk() {
|
||||||
|
leaveChannel()
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onConnectionLost: () => {
|
onConnectionLost: () => {
|
||||||
|
|
@ -1388,18 +1461,33 @@ const Meeting: React.FC = () => {
|
||||||
if (bool) {
|
if (bool) {
|
||||||
stopScreenCapture()
|
stopScreenCapture()
|
||||||
setSharedScreenItem('')
|
setSharedScreenItem('')
|
||||||
allUserLook(userInfo.uid, userInfo.userName)
|
allUserLook(userInfo.uid, userInfo.userName, true)
|
||||||
}
|
}
|
||||||
return bool
|
return bool
|
||||||
})
|
})
|
||||||
} else if (reason === 3 || reason === 4) {
|
} else if (reason === 3 || reason === 4) {
|
||||||
message.error({
|
message.error({
|
||||||
content: <div>请检查摄像头是否正常工作,检查摄像头是否被其他应用占用,或者尝试重新加入频道,<span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
|
content: <div>检查摄像头是否正常、未被占用,或尝试重新加入频道。<span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
|
||||||
stupWizardRef.current.changeModal(1);
|
stupWizardRef.current.changeModal(1);
|
||||||
}}>前往修改摄像头</span></div>,
|
}}>前往修改摄像头</span></div>,
|
||||||
duration: 60,
|
duration: 15,
|
||||||
key: 'cameraTemporarily'
|
key: 'cameraTemporarily'
|
||||||
});
|
});
|
||||||
|
} else if (_state === 3) {
|
||||||
|
if (!stupWizardRef.current.getStupWizardModal()) {
|
||||||
|
await PostOpenCamera({
|
||||||
|
roomNum: state.channelId,
|
||||||
|
uid: userInfo.uid,
|
||||||
|
enableCamera: false
|
||||||
|
})
|
||||||
|
message.error({
|
||||||
|
content: <div>检查摄像头是否正常、未被占用,或尝试重新加入频道。<span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
|
||||||
|
stupWizardRef.current.changeModal(1);
|
||||||
|
}}>前往修改摄像头</span></div>,
|
||||||
|
duration: 15,
|
||||||
|
key: 'cameraTemporarily'
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onTokenPrivilegeWillExpire: async (connection: RtcConnection, _token: string) => {
|
onTokenPrivilegeWillExpire: async (connection: RtcConnection, _token: string) => {
|
||||||
|
|
@ -1411,6 +1499,23 @@ const Meeting: React.FC = () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
onVideoPublishStateChanged: (_source: VideoSourceType, _channel: string, _oldState: StreamPublishState, newState: StreamPublishState, _elapseSinceLastState: number) => {
|
||||||
|
setVideoStatus(newState)
|
||||||
|
},
|
||||||
|
onAudioPublishStateChanged: (_channel: string, _oldState: StreamPublishState, newState: StreamPublishState, _elapseSinceLastState: number) => {
|
||||||
|
setAudioStatus(newState)
|
||||||
|
},
|
||||||
|
onActiveSpeaker: (_connection: RtcConnection, uid: number) => {
|
||||||
|
if (String(uid).length !== 9) {
|
||||||
|
setActiveSpeaker(String(uid))
|
||||||
|
}
|
||||||
|
setIsShare((res: any) => {
|
||||||
|
if (!res && String(uid).length !== 9) {
|
||||||
|
renderVideo(String(uid))
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (state.enableCamera) {
|
if (state.enableCamera) {
|
||||||
|
|
@ -1664,6 +1769,20 @@ const Meeting: React.FC = () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const setVideoUser = () => {
|
||||||
|
setRoomUserList((newChatList: any) => {
|
||||||
|
setActiveSpeaker(res => {
|
||||||
|
let item = newChatList.find((item: any) => item.uid === res)
|
||||||
|
if (item && item.isRoom && item.isAdmin) {
|
||||||
|
renderVideo(res)
|
||||||
|
} else {
|
||||||
|
getShowUser()
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
return newChatList
|
||||||
|
})
|
||||||
|
}
|
||||||
// 加入房间时间
|
// 加入房间时间
|
||||||
const changeCurrentSeconds = (): string => {
|
const changeCurrentSeconds = (): string => {
|
||||||
const duration = dayjs.duration(currentSeconds, 'seconds');
|
const duration = dayjs.duration(currentSeconds, 'seconds');
|
||||||
|
|
@ -1731,8 +1850,8 @@ const Meeting: React.FC = () => {
|
||||||
if (res) {
|
if (res) {
|
||||||
GetSharedScreen(state.channelId).then(req => {
|
GetSharedScreen(state.channelId).then(req => {
|
||||||
if (req.code === 200) {
|
if (req.code === 200) {
|
||||||
if (res.data) {
|
if (req.data) {
|
||||||
setIsShare(res.data)
|
setIsShare(req.data)
|
||||||
}
|
}
|
||||||
getDesktopCapturerVideo()
|
getDesktopCapturerVideo()
|
||||||
setIsSharedScreenModal(true)
|
setIsSharedScreenModal(true)
|
||||||
|
|
@ -1753,7 +1872,7 @@ const Meeting: React.FC = () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (row.title === '停止共享') {
|
if (row.title === '停止共享') {
|
||||||
await allUserLook(userInfo.uid, userInfo.userName)
|
await allUserLook(userInfo.uid, userInfo.userName, true)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '静音':
|
case '静音':
|
||||||
|
|
@ -2020,9 +2139,13 @@ const Meeting: React.FC = () => {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
// 设置全员看谁
|
// 设置全员看谁
|
||||||
const allUserLook = async (uid: string, name: string): Promise<void> => {
|
const allUserLook = async (uid: string, name: string, bool?: boolean): Promise<void> => {
|
||||||
|
if (bool) {
|
||||||
|
await PostStopSharedScreen(state.channelId)
|
||||||
|
} else {
|
||||||
await PostShowUser(state.channelId, uid, name)
|
await PostShowUser(state.channelId, uid, name)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 设置发言人
|
// 设置发言人
|
||||||
const postRoomManager = async (data: any): Promise<void> => {
|
const postRoomManager = async (data: any): Promise<void> => {
|
||||||
if (isAdmin >= 20) {
|
if (isAdmin >= 20) {
|
||||||
|
|
@ -2083,7 +2206,25 @@ const Meeting: React.FC = () => {
|
||||||
item.isRoom = true;
|
item.isRoom = true;
|
||||||
item.isAdmin = role.ID.includes(item.roleId) || item.isRoomManager
|
item.isAdmin = role.ID.includes(item.roleId) || item.isRoomManager
|
||||||
})
|
})
|
||||||
setRoomUserList(res.data)
|
setRoomUserList((req: any) => {
|
||||||
|
if (req.length) {
|
||||||
|
let arr: any = []
|
||||||
|
res.data.forEach((item: any) => {
|
||||||
|
let userItem = req.find((row: any) => row.uid == item.uid);
|
||||||
|
if (userItem) {
|
||||||
|
userItem.enableCamera = item.enableCamera;
|
||||||
|
userItem.enableMicr = item.enableMicr;
|
||||||
|
userItem.isRoomManager = item.isRoomManager;
|
||||||
|
userItem.isAdmin = role.ID.includes(item.roleId) || item.isRoomManager;
|
||||||
|
} else {
|
||||||
|
arr.push(item)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return [...req, ...arr]
|
||||||
|
} else {
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
})
|
||||||
getUserRoomInfo().then(async (res) => {
|
getUserRoomInfo().then(async (res) => {
|
||||||
await agora.updateChannelMediaOptions(res ? true : false)
|
await agora.updateChannelMediaOptions(res ? true : false)
|
||||||
changeAgoraDevice()
|
changeAgoraDevice()
|
||||||
|
|
@ -2115,7 +2256,7 @@ const Meeting: React.FC = () => {
|
||||||
enableCamera: !storeDevice[0][1].active,
|
enableCamera: !storeDevice[0][1].active,
|
||||||
isRoomManager: userItem ? userItem.isRoomManager : false,
|
isRoomManager: userItem ? userItem.isRoomManager : false,
|
||||||
})
|
})
|
||||||
await getShowUser()
|
setVideoUser()
|
||||||
if (userItem.isRoomManager) {
|
if (userItem.isRoomManager) {
|
||||||
await postOpenMicr(!storeDevice[0][0].active, userInfo.uid)
|
await postOpenMicr(!storeDevice[0][0].active, userInfo.uid)
|
||||||
await postOpenCamera(!storeDevice[0][1].active, userInfo.uid)
|
await postOpenCamera(!storeDevice[0][1].active, userInfo.uid)
|
||||||
|
|
@ -2147,13 +2288,15 @@ const Meeting: React.FC = () => {
|
||||||
const sendMsg = (text?: string): void => {
|
const sendMsg = (text?: string): void => {
|
||||||
let msg = text ? text : textMsg;
|
let msg = text ? text : textMsg;
|
||||||
if (msg) {
|
if (msg) {
|
||||||
|
setRoomUserList((res: any) => {
|
||||||
|
let row = res.find((item: any) => item.uid === userInfo.uid)
|
||||||
window.electron.onInvoke('sendChannelMsg', {
|
window.electron.onInvoke('sendChannelMsg', {
|
||||||
roomNum: state.channelId,
|
roomNum: state.channelId,
|
||||||
msg: msg,
|
msg: msg,
|
||||||
})
|
})
|
||||||
let item = {
|
let item = {
|
||||||
uid: userInfo.uid,
|
uid: userInfo.uid,
|
||||||
userName: userInfo.userName,
|
userName: row.userName,
|
||||||
message: msg,
|
message: msg,
|
||||||
timestamp: +new Date()
|
timestamp: +new Date()
|
||||||
}
|
}
|
||||||
|
|
@ -2164,8 +2307,9 @@ const Meeting: React.FC = () => {
|
||||||
chatListIten: item,
|
chatListIten: item,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
setTextMsg('');
|
|
||||||
chatScrollBotton()
|
chatScrollBotton()
|
||||||
|
return res
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
message.error('请输入内容!')
|
message.error('请输入内容!')
|
||||||
}
|
}
|
||||||
|
|
@ -2213,8 +2357,6 @@ const Meeting: React.FC = () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 开关麦克风
|
// 开关麦克风
|
||||||
const postOpenMicrApi = async (enableMicr: boolean, uid: string, isAll: boolean, isMessage: boolean = false): Promise<void> => {
|
const postOpenMicrApi = async (enableMicr: boolean, uid: string, isAll: boolean, isMessage: boolean = false): Promise<void> => {
|
||||||
if (isAll) {
|
if (isAll) {
|
||||||
|
|
@ -2223,11 +2365,20 @@ const Meeting: React.FC = () => {
|
||||||
enableMicr
|
enableMicr
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
await PostOpenMicr({
|
await window.electron.onInvoke('sendOper2User', {
|
||||||
|
uid,
|
||||||
|
contentString: JSON.stringify({
|
||||||
roomNum: state.channelId,
|
roomNum: state.channelId,
|
||||||
uid,
|
uid,
|
||||||
enableMicr
|
enableMicr,
|
||||||
|
type: 'audio'
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
// await PostOpenMicr({
|
||||||
|
// roomNum: state.channelId,
|
||||||
|
// uid,
|
||||||
|
// enableMicr
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
if (isMessage) {
|
if (isMessage) {
|
||||||
// message.success('操作成功')
|
// message.success('操作成功')
|
||||||
|
|
@ -2268,11 +2419,20 @@ const Meeting: React.FC = () => {
|
||||||
} else {
|
} else {
|
||||||
await agora.stopCameraCapture();
|
await agora.stopCameraCapture();
|
||||||
}
|
}
|
||||||
await PostOpenCamera({
|
await window.electron.onInvoke('sendOper2User', {
|
||||||
|
uid,
|
||||||
|
contentString: JSON.stringify({
|
||||||
roomNum: state.channelId,
|
roomNum: state.channelId,
|
||||||
uid,
|
uid,
|
||||||
enableCamera
|
enableCamera,
|
||||||
|
type: 'video'
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
// await PostOpenCamera({
|
||||||
|
// roomNum: state.channelId,
|
||||||
|
// uid,
|
||||||
|
// enableCamera
|
||||||
|
// })
|
||||||
if (isMessage) {
|
if (isMessage) {
|
||||||
// message.success('操作成功')
|
// message.success('操作成功')
|
||||||
}
|
}
|
||||||
|
|
@ -2376,7 +2536,7 @@ const Meeting: React.FC = () => {
|
||||||
</svg>
|
</svg>
|
||||||
</div> //右
|
</div> //右
|
||||||
} else {
|
} else {
|
||||||
return <div className={`${styles.speakerModeIcon} drag`} style={{ left: 'calc(18% - 4px)' }} title='收起' onClick={() => setIsVideoFullScreen(true)}>
|
return <div className={`${styles.speakerModeIcon} drag`} style={{ left: 'calc(270px - 4px)' }} title='收起' onClick={() => setIsVideoFullScreen(true)}>
|
||||||
<svg width="12" height="22" viewBox="0 0 12 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="12" height="22" viewBox="0 0 12 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M11.9355 1.45949L10.7759 0.299805L0.0636029 11.0143L10.7759 21.7275L11.9355 20.5679L2.38107 11.0136L11.9355 1.45949Z" />
|
<path d="M11.9355 1.45949L10.7759 0.299805L0.0636029 11.0143L10.7759 21.7275L11.9355 20.5679L2.38107 11.0136L11.9355 1.45949Z" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
@ -2415,6 +2575,14 @@ const Meeting: React.FC = () => {
|
||||||
}
|
}
|
||||||
message.success('操作成功')
|
message.success('操作成功')
|
||||||
}
|
}
|
||||||
|
// 判断是否出现滚动条
|
||||||
|
const hasScrollbar = () => {
|
||||||
|
let element = document.getElementById('videoView') as HTMLDivElement
|
||||||
|
if (element) {
|
||||||
|
return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
// 移出房间
|
// 移出房间
|
||||||
const getRoomKickout = async (channelId: string, uid: string, userName: string): Promise<void> => {
|
const getRoomKickout = async (channelId: string, uid: string, userName: string): Promise<void> => {
|
||||||
confirm({
|
confirm({
|
||||||
|
|
@ -2601,7 +2769,9 @@ const Meeting: React.FC = () => {
|
||||||
</Popover>}
|
</Popover>}
|
||||||
<div>{changeCurrentSeconds()}</div>
|
<div>{changeCurrentSeconds()}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>会议号:{state.channelId} 会议名称:{state.roomName}</div>
|
<div style={{ display: 'flex', alignItems: 'center' }}>会议号:{state.channelId} 会议名称:{state.roomName}
|
||||||
|
<span className='drag' style={{ marginTop: '2px', marginLeft: '4px' }}><Code roomNum={state.channelId}></Code></span>
|
||||||
|
</div>
|
||||||
<div className='drag'>
|
<div className='drag'>
|
||||||
<Popover
|
<Popover
|
||||||
content={
|
content={
|
||||||
|
|
@ -2769,13 +2939,13 @@ const Meeting: React.FC = () => {
|
||||||
</div> : null)
|
</div> : null)
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
{isAdmin > 6 ? <div>
|
{hasScrollbar() ? <div>
|
||||||
{meetingMode === "StandardMode" ? <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: '20px', top: '66px' }} onClick={() => {
|
{meetingMode === "StandardMode" ? <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: '20px', top: '66px' }} onClick={() => {
|
||||||
const container = document.getElementById('videoView') as HTMLElement;
|
const container = document.getElementById('videoView') as HTMLElement;
|
||||||
container.scrollLeft -= 100
|
container.scrollLeft -= 100
|
||||||
}}>
|
}}>
|
||||||
<CaretLeftOutlined />
|
<CaretLeftOutlined />
|
||||||
</div> : <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: '8.2%', top: '20px' }} onClick={() => {
|
</div> : <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: '115px', top: '20px' }} onClick={() => {
|
||||||
const container = document.getElementById('videoView') as HTMLElement;
|
const container = document.getElementById('videoView') as HTMLElement;
|
||||||
container.scrollTop -= 100
|
container.scrollTop -= 100
|
||||||
}}>
|
}}>
|
||||||
|
|
@ -2786,7 +2956,7 @@ const Meeting: React.FC = () => {
|
||||||
container.scrollLeft += 100
|
container.scrollLeft += 100
|
||||||
}}>
|
}}>
|
||||||
<CaretRightOutlined />
|
<CaretRightOutlined />
|
||||||
</div> : <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: '8.2%', bottom: '20px' }} onClick={() => {
|
</div> : <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: '115px', bottom: '20px' }} onClick={() => {
|
||||||
const container = document.getElementById('videoView') as HTMLElement;
|
const container = document.getElementById('videoView') as HTMLElement;
|
||||||
container.scrollTop += 100
|
container.scrollTop += 100
|
||||||
}}>
|
}}>
|
||||||
|
|
@ -2900,7 +3070,7 @@ const Meeting: React.FC = () => {
|
||||||
<div>
|
<div>
|
||||||
<div><Avatar name={item.userName} /></div>
|
<div><Avatar name={item.userName} /></div>
|
||||||
<span>
|
<span>
|
||||||
{item.userName}{item.uid === user.uid ? '(我)' : ''}
|
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: role.ID.includes(item.roleId) || item.isRoomManager ? '50px' : '80px' }} title={item.userName}>{item.userName}</span>{item.uid === user.uid ? '(我)' : ''}
|
||||||
{role.ID.includes(item.roleId) || item.isRoomManager ?
|
{role.ID.includes(item.roleId) || item.isRoomManager ?
|
||||||
<span style={{ color: '#02B188', marginLeft: '4px' }}>
|
<span style={{ color: '#02B188', marginLeft: '4px' }}>
|
||||||
{role.ID.includes(item.roleId) ? '管理员' : '发言人'}
|
{role.ID.includes(item.roleId) ? '管理员' : '发言人'}
|
||||||
|
|
@ -3120,19 +3290,30 @@ const Meeting: React.FC = () => {
|
||||||
>移出会议</Button> : null}
|
>移出会议</Button> : null}
|
||||||
</div> : <div style={{ color: 'white' }}>用户不在房间内</div>
|
</div> : <div style={{ color: 'white' }}>用户不在房间内</div>
|
||||||
}>
|
}>
|
||||||
<div>
|
<div title={item.userName}>
|
||||||
<div><Avatar name={item.userName} /></div>
|
<div><Avatar name={item.userName} /></div>
|
||||||
{item.uid !== user.uid ?
|
{item.uid !== user.uid ?
|
||||||
<span>{item.userName} <span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
|
<span>
|
||||||
<span> <span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
|
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '150px' }}>{item.userName}</span>
|
||||||
|
<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>
|
||||||
|
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '150px' }}>{item.userName}</span>
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</Popover> : <div>
|
</Popover> : <div title={item.userName}>
|
||||||
<div><Avatar name={item.userName} /></div>
|
<div><Avatar name={item.userName} /></div>
|
||||||
{item.uid !== user.uid ?
|
{item.uid !== user.uid ?
|
||||||
<span>{item.userName}<span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
|
<span>
|
||||||
<span><span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
|
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '150px' }}>{item.userName}</span>
|
||||||
|
<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>
|
||||||
|
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '150px' }}>{item.userName}</span>
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
</div>}
|
</div>}
|
||||||
<div>{item.message}</div>
|
<div>{item.message}</div>
|
||||||
|
|
@ -3157,7 +3338,10 @@ const Meeting: React.FC = () => {
|
||||||
<Input.TextArea placeholder="请输入消息" value={textMsg} style={{ flexGrow: 1 }} onChange={(e) => {
|
<Input.TextArea placeholder="请输入消息" value={textMsg} style={{ flexGrow: 1 }} onChange={(e) => {
|
||||||
setTextMsg(e.target.value)
|
setTextMsg(e.target.value)
|
||||||
}}></Input.TextArea>
|
}}></Input.TextArea>
|
||||||
<Button type="primary" className='m-ant-btn' style={{ flexShrink: 0, marginTop: '4px' }} onClick={() => sendMsg()}>发送</Button>
|
<Button type="primary" className='m-ant-btn' style={{ flexShrink: 0, marginTop: '4px' }} onClick={() => {
|
||||||
|
sendMsg()
|
||||||
|
setTextMsg('');
|
||||||
|
}}>发送</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
|
|
@ -3327,7 +3511,7 @@ const Meeting: React.FC = () => {
|
||||||
key={rowIndex}>
|
key={rowIndex}>
|
||||||
<label>
|
<label>
|
||||||
<img src={row.active ? row.iconActive : row.icon} alt="" />
|
<img src={row.active ? row.iconActive : row.icon} alt="" />
|
||||||
{!row.active ? <div style={{ backgroundImage: `url(${ImageUrl.icon49})` }} id={`micr-item-${userInfo.uid}`}>
|
{!row.active ? <div style={{ backgroundImage: `url(${ImageUrl.icon49})`, transition: '0.18s' }} id={`micr-item-${userInfo.uid}`}>
|
||||||
</div> : ''}
|
</div> : ''}
|
||||||
</label>
|
</label>
|
||||||
<span>{row.title}</span>
|
<span>{row.title}</span>
|
||||||
|
|
@ -3494,7 +3678,7 @@ const meetingContentUser = (item: any, bool?: boolean) => {
|
||||||
<>
|
<>
|
||||||
<div className={styles.meetingContentUser}>
|
<div className={styles.meetingContentUser}>
|
||||||
<div className={styles.meetingContentUserName}>
|
<div className={styles.meetingContentUserName}>
|
||||||
{role.ID.includes(item.roleId) || item.isRoomManager ?
|
{role.ID.includes(item.roleId) ?
|
||||||
<div style={{ background: role.ID.includes(item.roleId) ? '#FDC229' : '#3F51B5' }}>
|
<div style={{ background: role.ID.includes(item.roleId) ? '#FDC229' : '#3F51B5' }}>
|
||||||
<img src={ImageUrl.icon32} alt="" />
|
<img src={ImageUrl.icon32} alt="" />
|
||||||
</div> : null}
|
</div> : null}
|
||||||
|
|
@ -3502,7 +3686,7 @@ const meetingContentUser = (item: any, bool?: boolean) => {
|
||||||
bool ? !item.enableMicr ? <img src={item.enableMicr ? ImageUrl.icon22 : ImageUrl.icon22Active} alt="" /> : '' :
|
bool ? !item.enableMicr ? <img src={item.enableMicr ? ImageUrl.icon22 : ImageUrl.icon22Active} alt="" /> : '' :
|
||||||
<label>
|
<label>
|
||||||
<img src={item.enableMicr ? ImageUrl.icon22 : ImageUrl.icon22Active} alt="" />
|
<img src={item.enableMicr ? ImageUrl.icon22 : ImageUrl.icon22Active} alt="" />
|
||||||
{item.enableMicr ? <div style={{ backgroundImage: `url(${ImageUrl.icon49})` }} id={`micr-${item.uid}`}>
|
{item.enableMicr ? <div style={{ backgroundImage: `url(${ImageUrl.icon49})`, transition: '0.18s' }} id={`micr-${item.uid}`}>
|
||||||
</div> : ''}
|
</div> : ''}
|
||||||
</label>
|
</label>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,10 @@ export interface IElectronAPI {
|
||||||
downFile: (callBack: Function) => void;
|
downFile: (callBack: Function) => void;
|
||||||
quitAndInstall: (callBack: Function) => void;
|
quitAndInstall: (callBack: Function) => void;
|
||||||
isOpenWindows: (callBack: Function) => void;
|
isOpenWindows: (callBack: Function) => void;
|
||||||
setEnv: (str: string) => any;
|
startLoad: () => any;
|
||||||
updateHandle: () => any;
|
updateHandle: () => any;
|
||||||
getVersion: () => Promise<string>;
|
getVersion: () => Promise<string>;
|
||||||
|
getEnv: () => Promise<string>;
|
||||||
isVisible: () => Promise<string>;
|
isVisible: () => Promise<string>;
|
||||||
setRegistry: (uuid: string) => any;
|
setRegistry: (uuid: string) => any;
|
||||||
getRegistry: () => any;
|
getRegistry: () => any;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
declare module 'react-dom/client';
|
declare module 'react-dom/client';
|
||||||
declare module 'crypto-js';
|
declare module 'crypto-js';
|
||||||
|
declare module 'js-yaml';
|
||||||
declare module 'uuid';
|
declare module 'uuid';
|
||||||
|
|
@ -21,7 +21,8 @@ import {
|
||||||
ColorEnhanceOptions,
|
ColorEnhanceOptions,
|
||||||
LowlightEnhanceOptions,
|
LowlightEnhanceOptions,
|
||||||
VirtualBackgroundSource,
|
VirtualBackgroundSource,
|
||||||
AudienceLatencyLevelType
|
AudienceLatencyLevelType,
|
||||||
|
StreamPublishState
|
||||||
} 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';
|
||||||
|
|
@ -124,7 +125,8 @@ export const agora = {
|
||||||
if (settingData.darkLightEnhancement) agora.setLowlightEnhanceOptions(settingData.darkLightEnhancement.isDarkLightEnhancement, settingData.darkLightEnhancement)
|
if (settingData.darkLightEnhancement) agora.setLowlightEnhanceOptions(settingData.darkLightEnhancement.isDarkLightEnhancement, settingData.darkLightEnhancement)
|
||||||
if (settingData.virtualBackground) {
|
if (settingData.virtualBackground) {
|
||||||
if (typeof settingData.virtualBackground.sourceIndex === 'number') {
|
if (typeof settingData.virtualBackground.sourceIndex === 'number') {
|
||||||
if (import.meta.env.VITE_ENV === 'development') {
|
window.electron.getEnv().then(res => {
|
||||||
|
if (res === 'development') {
|
||||||
window.electron.getAppPath().then((res: string) => {
|
window.electron.getAppPath().then((res: string) => {
|
||||||
const imagePath = path.join(res, 'src', 'assets', 'virtualBackground', `${settingData.virtualBackground.sourceIndex + 1}.png`);
|
const imagePath = path.join(res, 'src', 'assets', 'virtualBackground', `${settingData.virtualBackground.sourceIndex + 1}.png`);
|
||||||
agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, {
|
agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, {
|
||||||
|
|
@ -141,6 +143,7 @@ export const agora = {
|
||||||
color: Number(settingData.virtualBackground.color),
|
color: Number(settingData.virtualBackground.color),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, {
|
agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, {
|
||||||
background_source_type: 1,
|
background_source_type: 1,
|
||||||
|
|
@ -151,7 +154,7 @@ export const agora = {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
},
|
},
|
||||||
// 事件回调
|
// 事件回调
|
||||||
registerEventHandler: ({ onJoinChannelSuccess, onUserJoined, onUserOffline, onAudioVolumeIndication, onRtcStats, onConnectionStateChanged, onLocalVideoStateChanged, onConnectionLost, onTokenPrivilegeWillExpire }: any) => {
|
registerEventHandler: ({ onJoinChannelSuccess, onUserJoined, onUserOffline, onAudioVolumeIndication, onRtcStats, onConnectionStateChanged, onLocalVideoStateChanged, onConnectionLost, onTokenPrivilegeWillExpire, onActiveSpeaker, onVideoPublishStateChanged, onAudioPublishStateChanged }: any) => {
|
||||||
rtcEngine.registerEventHandler({
|
rtcEngine.registerEventHandler({
|
||||||
// 监听本地用户加入频道事件
|
// 监听本地用户加入频道事件
|
||||||
onJoinChannelSuccess: async (connection: RtcConnection, elapsed: number) => {
|
onJoinChannelSuccess: async (connection: RtcConnection, elapsed: number) => {
|
||||||
|
|
@ -166,17 +169,13 @@ export const agora = {
|
||||||
await onUserOffline?.(connection, remoteUid, reason)
|
await onUserOffline?.(connection, remoteUid, reason)
|
||||||
},
|
},
|
||||||
// // 视频发布状态改变回调
|
// // 视频发布状态改变回调
|
||||||
// onVideoPublishStateChanged: (source: any, channel: any, oldState: any, newState: any, elapseSinceLastState: any) => {
|
onVideoPublishStateChanged: (source: VideoSourceType, channel: string, oldState: StreamPublishState, newState: StreamPublishState, elapseSinceLastState: number) => {
|
||||||
// if (newState === 1) {
|
onVideoPublishStateChanged?.(source, channel, oldState, newState, elapseSinceLastState)
|
||||||
|
},
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// // 音频发布状态改变回调
|
// // 音频发布状态改变回调
|
||||||
// onAudioPublishStateChanged: (channel: any, oldState: any, newState: any, elapseSinceLastState: any) => {
|
onAudioPublishStateChanged: (channel: string, oldState: StreamPublishState, newState: StreamPublishState, elapseSinceLastState: number) => {
|
||||||
// if (newState === 1) {
|
onAudioPublishStateChanged?.(channel, oldState, newState, elapseSinceLastState)
|
||||||
|
},
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// // 用户音量提示回调。
|
// // 用户音量提示回调。
|
||||||
onAudioVolumeIndication: async (_connection: RtcConnection, speakers: AudioVolumeInfo[], _speakerNumber: number, _totalVolume: number) => {
|
onAudioVolumeIndication: async (_connection: RtcConnection, speakers: AudioVolumeInfo[], _speakerNumber: number, _totalVolume: number) => {
|
||||||
await onAudioVolumeIndication?.(speakers)
|
await onAudioVolumeIndication?.(speakers)
|
||||||
|
|
@ -200,6 +199,13 @@ export const agora = {
|
||||||
// Token 即将在 30s 内过期回调。
|
// Token 即将在 30s 内过期回调。
|
||||||
onTokenPrivilegeWillExpire: (connection: RtcConnection, token: string) => {
|
onTokenPrivilegeWillExpire: (connection: RtcConnection, token: string) => {
|
||||||
onTokenPrivilegeWillExpire?.(connection, token)
|
onTokenPrivilegeWillExpire?.(connection, token)
|
||||||
|
},
|
||||||
|
// 监测到远端最活跃用户回调。
|
||||||
|
onActiveSpeaker: (connection: RtcConnection, uid: number) => {
|
||||||
|
const setting = JSON.parse(storage.getItem('setting') as string);
|
||||||
|
if (setting.voiceStimulation) {
|
||||||
|
onActiveSpeaker?.(connection, uid)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -289,7 +295,7 @@ export const agora = {
|
||||||
},
|
},
|
||||||
// 加入频道
|
// 加入频道
|
||||||
joinChannel: async () => {
|
joinChannel: async () => {
|
||||||
await rtcEngine.enableAudioVolumeIndication(100, 3, true)
|
await rtcEngine.enableAudioVolumeIndication(200, 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,
|
||||||
|
|
@ -302,6 +308,7 @@ export const agora = {
|
||||||
},
|
},
|
||||||
{ channelId: option.channelId, localUid: Number(option.uid) }
|
{ channelId: option.channelId, localUid: Number(option.uid) }
|
||||||
);
|
);
|
||||||
|
await rtcEngine.setAudioScenario(8)
|
||||||
},
|
},
|
||||||
// 更新频道配置
|
// 更新频道配置
|
||||||
updateChannelMediaOptions: async (bool: boolean) => {
|
updateChannelMediaOptions: async (bool: boolean) => {
|
||||||
|
|
@ -441,8 +448,8 @@ export const agora = {
|
||||||
startCameraCapture: async (bool: boolean = false) => {
|
startCameraCapture: async (bool: boolean = false) => {
|
||||||
await rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {
|
await rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {
|
||||||
format: {
|
format: {
|
||||||
width: bool ? 160 : 1280,
|
width: bool ? 160 : 1920,
|
||||||
height: bool ? 160 : 720,
|
height: bool ? 160 : 1080,
|
||||||
fps: 15,
|
fps: 15,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -472,7 +479,7 @@ export const agora = {
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
frameRate: isFluencyPriority ? 30 : 15,
|
frameRate: isFluencyPriority ? 15 : 7,
|
||||||
dimensions: {
|
dimensions: {
|
||||||
width: 1920,
|
width: 1920,
|
||||||
height: 1080,
|
height: 1080,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import storage from "./storage";
|
import storage from "./storage";
|
||||||
|
import axios from "axios";
|
||||||
|
import yaml from 'js-yaml'
|
||||||
export const setKeyOpenChildWindow = async (key: string, bool: boolean) => {
|
export const setKeyOpenChildWindow = async (key: string, bool: boolean) => {
|
||||||
const openChildWindow = await JSON.parse(storage.getItem('openChildWindow') as string)
|
const openChildWindow = await JSON.parse(storage.getItem('openChildWindow') as string)
|
||||||
openChildWindow[key] = bool;
|
openChildWindow[key] = bool;
|
||||||
|
|
@ -27,6 +29,7 @@ export const storageSeeting: any = {
|
||||||
shareFilesPath: path.resolve(__dirname, '../../Downloads/') + '\\', //共享文件保存路径
|
shareFilesPath: path.resolve(__dirname, '../../Downloads/') + '\\', //共享文件保存路径
|
||||||
isShareSavePath: true, //是否下载钱询问每个文件保存的位置
|
isShareSavePath: true, //是否下载钱询问每个文件保存的位置
|
||||||
closeSetting: 'hide', //关闭按钮设置
|
closeSetting: 'hide', //关闭按钮设置
|
||||||
|
voiceStimulation: true, //语音激励
|
||||||
isAINoiseReduction: true, //是否开启ai降噪
|
isAINoiseReduction: true, //是否开启ai降噪
|
||||||
aINoiseReduction: 1, // 降噪模式
|
aINoiseReduction: 1, // 降噪模式
|
||||||
isRecordingTips: true, //是否开启录制提示
|
isRecordingTips: true, //是否开启录制提示
|
||||||
|
|
@ -59,15 +62,61 @@ export const getUpdateUrl = (env: string) => {
|
||||||
switch (env) {
|
switch (env) {
|
||||||
case 'xy':
|
case 'xy':
|
||||||
return 'https://meeting-api.23544.com/meeting/xysz'
|
return 'https://meeting-api.23544.com/meeting/xysz'
|
||||||
|
case 'development':
|
||||||
|
return 'http://192.168.2.9:8827'
|
||||||
default:
|
default:
|
||||||
return 'https://meeting-api.23544.com/meeting/update'
|
return 'https://meeting-api.23544.com/meeting/update'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const getTitle = (env: string) => {
|
export const getTitle = async () => {
|
||||||
|
let env = await window.electron.getEnv()
|
||||||
|
let str;
|
||||||
switch (env) {
|
switch (env) {
|
||||||
case 'xy':
|
case 'xy':
|
||||||
return '湖北襄阳四中教研平台'
|
str = '湖北襄阳四中教研平台'
|
||||||
|
break;
|
||||||
|
case 'development':
|
||||||
|
str = '智汇享'
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return '智汇享'
|
str = '智汇享'
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
document.getElementsByTagName('title')[0].innerText = str
|
||||||
|
}
|
||||||
|
export const compareVersions = (version1: string, version2: string): number => {
|
||||||
|
const v1Parts = version1.split('.').map(Number);
|
||||||
|
const v2Parts = version2.split('.').map(Number);
|
||||||
|
const maxLength = Math.max(v1Parts.length, v2Parts.length);
|
||||||
|
for (let i = 0; i < maxLength; i++) {
|
||||||
|
const v1 = v1Parts[i] || 0;
|
||||||
|
const v2 = v2Parts[i] || 0;
|
||||||
|
if (v1 > v2) {
|
||||||
|
return 1;
|
||||||
|
} else if (v1 < v2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isVersion = (callBack: Function) => {
|
||||||
|
window.electron.getEnv().then(res => {
|
||||||
|
axios.get(`${getUpdateUrl(res)}/latest.yml`).then(res => {
|
||||||
|
if (res.status === 200 && res.data) {
|
||||||
|
const data = yaml.load(res.data); // 解析 YAML 内容
|
||||||
|
window.electron.getVersion().then(req => {
|
||||||
|
if (compareVersions(data.version, req) == 1) {
|
||||||
|
callBack(true, data)
|
||||||
|
} else {
|
||||||
|
callBack(false, data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
callBack(false)
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
callBack(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,8 @@ module.exports = {
|
||||||
switch (env) {
|
switch (env) {
|
||||||
case 'xy':
|
case 'xy':
|
||||||
return 'https://meeting-api.23544.com/meeting/xysz'
|
return 'https://meeting-api.23544.com/meeting/xysz'
|
||||||
|
case 'development':
|
||||||
|
return 'http://192.168.2.9:8827'
|
||||||
default:
|
default:
|
||||||
return 'https://meeting-api.23544.com/meeting/update'
|
return 'https://meeting-api.23544.com/meeting/update'
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +13,8 @@ module.exports = {
|
||||||
switch (env) {
|
switch (env) {
|
||||||
case 'xy':
|
case 'xy':
|
||||||
return '湖北襄阳四中教研平台'
|
return '湖北襄阳四中教研平台'
|
||||||
|
case 'development':
|
||||||
|
return '智汇享'
|
||||||
default:
|
default:
|
||||||
return '智汇享'
|
return '智汇享'
|
||||||
}
|
}
|
||||||
|
|
@ -19,6 +23,8 @@ module.exports = {
|
||||||
switch (env) {
|
switch (env) {
|
||||||
case 'xy':
|
case 'xy':
|
||||||
return 'icon54'
|
return 'icon54'
|
||||||
|
case 'development':
|
||||||
|
return 'icon'
|
||||||
default:
|
default:
|
||||||
return 'icon'
|
return 'icon'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { AxiosRequestConfig, AxiosResponse } from 'axios'
|
import { AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||||
import Request from './request'
|
import Request from './request'
|
||||||
import { constant } from '@/config'
|
import { constant } from '@/config'
|
||||||
|
let baseURL = !location.hostname.includes('meeting-api.23544.com') ? 'http://192.168.2.9:5192' : 'https://meeting-api.23544.com/pc'
|
||||||
// 实例化
|
// 实例化
|
||||||
const req = new Request({
|
const req = new Request({
|
||||||
baseURL: import.meta.env.VITE_BASE_URL_API,
|
baseURL,
|
||||||
timeout: constant.CONFIG_REQUEST_TIMEOUT_TIME as number,
|
timeout: constant.CONFIG_REQUEST_TIMEOUT_TIME as number,
|
||||||
interceptors: {
|
interceptors: {
|
||||||
// 请求拦截器
|
// 请求拦截器
|
||||||
|
|
@ -22,5 +22,4 @@ const request = (config: any) => {
|
||||||
}
|
}
|
||||||
return req.request<any>(config)
|
return req.request<any>(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default request
|
export default request
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,9 @@ class Request {
|
||||||
case 403:
|
case 403:
|
||||||
updatePostRefresh()
|
updatePostRefresh()
|
||||||
break
|
break
|
||||||
|
case 502:
|
||||||
|
message.error('网络已断开,请检查网络状态')
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
message.error(err.message)
|
message.error(err.message)
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,9 @@ export default defineConfig({
|
||||||
ColorEnhanceOptions,
|
ColorEnhanceOptions,
|
||||||
LowlightEnhanceOptions,
|
LowlightEnhanceOptions,
|
||||||
VirtualBackgroundSource,
|
VirtualBackgroundSource,
|
||||||
AudienceLatencyLevelType
|
AudienceLatencyLevelType,
|
||||||
|
StreamPublishState,
|
||||||
|
IMediaEngine
|
||||||
} = require("agora-electron-sdk")
|
} = require("agora-electron-sdk")
|
||||||
export {
|
export {
|
||||||
createAgoraRtcEngine,
|
createAgoraRtcEngine,
|
||||||
|
|
@ -101,7 +103,9 @@ export default defineConfig({
|
||||||
ColorEnhanceOptions,
|
ColorEnhanceOptions,
|
||||||
LowlightEnhanceOptions,
|
LowlightEnhanceOptions,
|
||||||
VirtualBackgroundSource,
|
VirtualBackgroundSource,
|
||||||
AudienceLatencyLevelType
|
AudienceLatencyLevelType,
|
||||||
|
StreamPublishState,
|
||||||
|
IMediaEngine
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
|
|
|
||||||