Compare commits
72 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
016dcf6e09 | |
|
|
bde5002e1e | |
|
|
bcfc790dd3 | |
|
|
55deae9654 | |
|
|
a08e0a6ece | |
|
|
00c16d44ff | |
|
|
e90186e4b9 | |
|
|
c9a6984a02 | |
|
|
440f19b436 | |
|
|
f0c79d64cd | |
|
|
f6aca11a83 | |
|
|
c69d965183 | |
|
|
489d5c8511 | |
|
|
76e968322d | |
|
|
ef55fab17d | |
|
|
1f897ad6b3 | |
|
|
56e3a19356 | |
|
|
a02232a770 | |
|
|
715ee0be43 | |
|
|
d6e9de24bf | |
|
|
860f141782 | |
|
|
882bacb2d5 | |
|
|
700566fd7e | |
|
|
f438a90c76 | |
|
|
b185bb7d67 | |
|
|
06a2e6e4ac | |
|
|
4b59b1a18d | |
|
|
ed2c39e7fc | |
|
|
1e3107d0e2 | |
|
|
37c06ca19f | |
|
|
7093367904 | |
|
|
4121283ef1 | |
|
|
705e5f1b01 | |
|
|
864f305acf | |
|
|
2b4a3cdbca | |
|
|
e01c308800 | |
|
|
62846483fd | |
|
|
8094a2669a | |
|
|
034d46b39e | |
|
|
f9dc5830aa | |
|
|
13de6c510d | |
|
|
b4d03efec7 | |
|
|
550073a73a | |
|
|
40342246cc | |
|
|
d11f437e2d | |
|
|
ac00b4b2a9 | |
|
|
6d6a9756e8 | |
|
|
b689fa0f76 | |
|
|
caba67da14 | |
|
|
fce3209e59 | |
|
|
67682defa8 | |
|
|
32d238fb7f | |
|
|
4520bba95d | |
|
|
32acac493d | |
|
|
1a98b6e7d4 | |
|
|
aa76736cf4 | |
|
|
79d393ab14 | |
|
|
c79c06aaa3 | |
|
|
0fbcb32565 | |
|
|
dc9ee39a1e | |
|
|
f709f3db42 | |
|
|
2b97e5d93b | |
|
|
4776b15026 | |
|
|
1ec1c1f12f | |
|
|
a80ee1efab | |
|
|
3c2356087d | |
|
|
7363635217 | |
|
|
4cf65d50a3 | |
|
|
0fb2b4bf75 | |
|
|
7f6c0bffb4 | |
|
|
1b62f6a9ff | |
|
|
0d50925d0b |
|
|
@ -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": {
|
||||
"oneClick": false,
|
||||
"installerIcon": "build/install.ico",
|
||||
"uninstallerIcon": "build/install.ico",
|
||||
"installerHeaderIcon": "build/install.ico",
|
||||
"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
|
||||
"perMachine": true,
|
||||
"include": "build/install.nsh"
|
||||
}
|
||||
}
|
||||
|
|
@ -51,6 +51,7 @@
|
|||
"deleteAppDataOnUninstall": true,
|
||||
"shortcutName": "湖北襄阳四中教研平台",
|
||||
"allowElevation": true,
|
||||
"perMachine": true
|
||||
"perMachine": true,
|
||||
"include": "build/install.nsh"
|
||||
}
|
||||
}
|
||||
111
main.js
|
|
@ -11,6 +11,7 @@ const {
|
|||
crashReporter,
|
||||
desktopCapturer,
|
||||
powerSaveBlocker,
|
||||
net
|
||||
} = require('electron');
|
||||
const path = require('node:path')
|
||||
const updateJs = require('./src/utils/package/update')
|
||||
|
|
@ -18,16 +19,15 @@ const fs = require('fs');
|
|||
const Registry = require('winreg');
|
||||
const { autoUpdater, CancellationToken } = require('electron-updater');
|
||||
const signalR = require('@microsoft/signalr');
|
||||
const { setTimeout, setInterval, clearTimeout, clearInterval } = require('timers');
|
||||
const { setTimeout, setInterval } = require('timers');
|
||||
const cancellationToken = new CancellationToken()
|
||||
app.allowRendererProcessReuse = false;
|
||||
let mainWindow = null;
|
||||
let childWindow = {}
|
||||
let isMaximized = false;
|
||||
let env;
|
||||
let env = 'development'; //development production xy
|
||||
let regKey;
|
||||
let connection = null;
|
||||
let envStr;
|
||||
let startNumber = 0;
|
||||
let buildStatus = false; //true 打包开发版本 false 本地开发
|
||||
powerSaveBlocker.start('prevent-display-sleep')
|
||||
|
|
@ -53,16 +53,15 @@ class AppWindow extends BrowserWindow {
|
|||
const finalConfig = { ...basicConfig, ...config };
|
||||
super(finalConfig);
|
||||
if (env === 'development') {
|
||||
// 开发
|
||||
if (buildStatus) {
|
||||
this.loadFile(path.resolve(__dirname, './dist/index.html'));
|
||||
this.loadURL('http://192.168.2.9:8827/');
|
||||
} else {
|
||||
this.loadURL('http://localhost:3000');
|
||||
}
|
||||
} else {
|
||||
// 测试 | 生产
|
||||
this.loadFile(path.resolve(__dirname, './dist/index.html'));
|
||||
this.loadURL('https://meeting-api.23544.com/')
|
||||
}
|
||||
// this.loadFile(path.resolve(__dirname, './dist/index.html'))
|
||||
this.once('ready-to-show', () => {
|
||||
this.show();
|
||||
});
|
||||
|
|
@ -72,11 +71,20 @@ function quit() {
|
|||
app.quit()
|
||||
}
|
||||
let tray;
|
||||
// 检查网络状态
|
||||
function checkNetworkStatus() {
|
||||
if (!net.isOnline()) {
|
||||
dialog.showErrorBox(`${env === 'xy' ? '湖北襄阳四中教研平台' : '智汇享'}-网络连接错误', '当前无网络连接,请检查您的网络设置。`);
|
||||
app.quit();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
tray = new Tray(trayIcon);
|
||||
tray.setToolTip(updateJs.getTitle(envStr));
|
||||
tray.setToolTip(updateJs.getTitle(env));
|
||||
tray.on('click', () => {
|
||||
mainWindow.webContents.send('isOpenWindows');
|
||||
});
|
||||
|
|
@ -95,6 +103,10 @@ function createWindow() {
|
|||
}
|
||||
const additionalData = { myKey: 'myValue' }
|
||||
app.on('ready', () => {
|
||||
// 检查网络状态
|
||||
if (!checkNetworkStatus()) {
|
||||
return;
|
||||
}
|
||||
// const gotTheLock = true
|
||||
const gotTheLock = app.requestSingleInstanceLock(additionalData)
|
||||
if (gotTheLock) {
|
||||
|
|
@ -103,15 +115,14 @@ app.on('ready', () => {
|
|||
uploadToServer: false,
|
||||
ignoreSystemCrashHandler: false
|
||||
})
|
||||
env = process.argv.find((arg) => arg.startsWith('--env='))?.split('=')[1];
|
||||
if (env === 'development') {
|
||||
Object.defineProperty(app, 'isPackaged', {
|
||||
get() {
|
||||
return true
|
||||
}
|
||||
})
|
||||
autoUpdater.updateConfigPath = path.join('latest.yml')
|
||||
}
|
||||
// if (!buildStatus) {
|
||||
// Object.defineProperty(app, 'isPackaged', {
|
||||
// get() {
|
||||
// return true
|
||||
// }
|
||||
// })
|
||||
// autoUpdater.updateConfigPath = path.join('latest.yml')
|
||||
// }
|
||||
createWindow()
|
||||
regKey = new Registry({
|
||||
hive: Registry.HKCU,
|
||||
|
|
@ -149,12 +160,11 @@ app.on('ready', () => {
|
|||
isMaximized = true;
|
||||
}
|
||||
});
|
||||
ipcMain.handle('setEnv', (event, str) => {
|
||||
envStr = str;
|
||||
ipcMain.handle('startLoad', (event) => {
|
||||
if (startNumber === 0) {
|
||||
updateHandle() // 检查更新
|
||||
setInterval(() => {
|
||||
updateHandle() // 每一小时检查更新
|
||||
autoUpdater.checkForUpdates()
|
||||
}, 1000 * 60 * 60)
|
||||
createTray()
|
||||
startNumber++
|
||||
|
|
@ -162,7 +172,7 @@ app.on('ready', () => {
|
|||
});
|
||||
// 更新
|
||||
ipcMain.handle('updateHandle', () => {
|
||||
updateHandle()
|
||||
autoUpdater.checkForUpdates()
|
||||
});
|
||||
// socket
|
||||
ipcMain.handle('startSignalr', (event, user) => {
|
||||
|
|
@ -191,6 +201,8 @@ app.on('ready', () => {
|
|||
connection.off('JoinChannelCallback');
|
||||
connection.off('ExitSharedScreen');
|
||||
connection.off('SetSpeaker');
|
||||
connection.off('ReceivedOperation');
|
||||
connection.off('StopedSharedScreen');
|
||||
}
|
||||
});
|
||||
ipcMain.handle('onStop', (event) => {
|
||||
|
|
@ -210,7 +222,7 @@ app.on('ready', () => {
|
|||
await connection.invoke(str, data.roomNum, data.msg)
|
||||
break;
|
||||
case 'sendOper':
|
||||
await connection.invoke(str, data.roomNum, data.type)
|
||||
await connection.invoke(str, data.roomNum, data.contentString)
|
||||
break;
|
||||
case 'getDrivers':
|
||||
// 获取某个人的设备列表
|
||||
|
|
@ -236,6 +248,10 @@ app.on('ready', () => {
|
|||
// 发言人设置成功
|
||||
await connection.invoke(str, data)
|
||||
break;
|
||||
case 'sendOper2User':
|
||||
// 扩展参数
|
||||
await connection.invoke(str, data.uid, data.contentString)
|
||||
break;
|
||||
}
|
||||
});
|
||||
ipcMain.handle('onOtherSignalr', (event) => {
|
||||
|
|
@ -266,10 +282,10 @@ app.on('ready', () => {
|
|||
})
|
||||
});
|
||||
// 扩展操作
|
||||
connection.on("Operation", (type) => {
|
||||
connection.on("Operation", (contentString) => {
|
||||
mainWindow.webContents.send('onSignalr', {
|
||||
key: 'Operation',
|
||||
type
|
||||
contentString
|
||||
})
|
||||
});
|
||||
// 移出会议
|
||||
|
|
@ -411,6 +427,20 @@ app.on('ready', () => {
|
|||
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', () => {
|
||||
return app.getVersion();
|
||||
});
|
||||
// 获取环境
|
||||
ipcMain.handle('getEnv', () => {
|
||||
return env;
|
||||
});
|
||||
// 获取窗口是否显示
|
||||
ipcMain.handle('isVisible', () => {
|
||||
return mainWindow.isVisible();
|
||||
|
|
@ -487,6 +521,11 @@ app.on('ready', () => {
|
|||
downloadUpdate()
|
||||
} else if (data === '2') { // 下载完成 点击安装
|
||||
quitAndInstall()
|
||||
} else if (data === '3') { // 打开弹窗
|
||||
let message = JSON.stringify({
|
||||
type: '3',
|
||||
})
|
||||
sendUpdateMessage(message)
|
||||
}
|
||||
});
|
||||
// 选择文件夹
|
||||
|
|
@ -604,16 +643,18 @@ app.on('ready', () => {
|
|||
width: config.width,
|
||||
height: config.height,
|
||||
})
|
||||
if (envStr === 'development') {
|
||||
if (env === 'development') {
|
||||
// 开发
|
||||
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 {
|
||||
child.loadURL(config.url)
|
||||
}
|
||||
} 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.setEnabled(false);//窗口禁用
|
||||
|
|
@ -715,7 +756,6 @@ app.on('ready', () => {
|
|||
});
|
||||
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
|
||||
function updateHandle() {
|
||||
autoUpdater.checkForUpdates()
|
||||
// autoUpdater.checkForUpdatesAndNotify().catch();
|
||||
const message = {
|
||||
error: '检查更新出错',
|
||||
|
|
@ -723,11 +763,11 @@ function updateHandle() {
|
|||
updateAva: '检测到新版本,正在下载……',
|
||||
updateNotAva: '已经是最新版本,不用更新'
|
||||
}
|
||||
autoUpdater.setFeedURL(updateJs.getUpdateUrl(envStr))
|
||||
autoUpdater.setFeedURL(updateJs.getUpdateUrl(env))
|
||||
autoUpdater.autoDownload = false // 不自动下载安装包
|
||||
autoUpdater.autoInstallOnAppQuit = false // 不自动安装
|
||||
autoUpdater.on('error', function (error) {
|
||||
sendUpdateMessage(message.error)
|
||||
sendUpdateMessage(error)
|
||||
})
|
||||
autoUpdater.on('checking-for-update', function () {
|
||||
sendUpdateMessage(message.checking)
|
||||
|
|
@ -735,9 +775,14 @@ function updateHandle() {
|
|||
autoUpdater.on('update-available', function (info) {
|
||||
let messageStr = JSON.stringify({ type: '0' })
|
||||
sendUpdateMessage(messageStr)
|
||||
mainWindow.webContents.send('changeLocalStorage', {
|
||||
isUpdate: true,
|
||||
});
|
||||
})
|
||||
autoUpdater.on('update-not-available', function (info) {
|
||||
|
||||
mainWindow.webContents.send('changeLocalStorage', {
|
||||
isUpdate: false,
|
||||
});
|
||||
})
|
||||
// 更新下载进度事件
|
||||
autoUpdater.on('download-progress', function (progressObj) {
|
||||
|
|
@ -810,7 +855,7 @@ function mainWindowCenter() {
|
|||
|
||||
const startSignalr = async (user) => {
|
||||
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,
|
||||
transport: signalR.HttpTransportType.WebSockets,
|
||||
accessTokenFactory: () => user.token
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
{
|
||||
"name": "WGShare.Metting",
|
||||
"version": "0.4.8",
|
||||
"version": "0.7.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "WGShare.Metting",
|
||||
"version": "0.4.8",
|
||||
"version": "0.7.1",
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.3.7",
|
||||
"@microsoft/signalr": "^8.0.0",
|
||||
"@types/node": "^20.14.9",
|
||||
"agora-electron-sdk": "^4.4.0",
|
||||
"agora-electron-sdk": "4.4.0",
|
||||
"animate.css": "^4.1.1",
|
||||
"antd": "^5.18.2",
|
||||
"axios": "^1.7.2",
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
"dayjs": "^1.11.11",
|
||||
"electron-squirrel-startup": "^1.0.1",
|
||||
"electron-updater": "^6.2.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"os": "^0.1.2",
|
||||
"path": "^0.12.7",
|
||||
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
||||
|
|
|
|||
17
package.json
|
|
@ -1,21 +1,17 @@
|
|||
{
|
||||
"name": "WGShare.Metting",
|
||||
"private": true,
|
||||
"version": "0.7.1",
|
||||
"version": "0.8.0",
|
||||
"main": "main.js",
|
||||
"authors": "yj",
|
||||
"description": "智汇享",
|
||||
"scripts": {
|
||||
"dev": "concurrently \"electron . --env=development\" \"cross-env BROWSER=none vite\"",
|
||||
"prod": "concurrently \"electron . --env=production\" \"cross-env BROWSER=none vite\"",
|
||||
"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",
|
||||
"dev": "concurrently \"electron .\" \"cross-env BROWSER=none vite\"",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"build:dev-win": "vite build --mode development & electron-builder -w --config=./config/build.json",
|
||||
"build:prod-win": "vite build --mode production & electron-builder -w --config=./config/build.json",
|
||||
"build:prod-win-xy": "vite build --mode xy & electron-builder -w --config=./config/xy.json"
|
||||
"build:dev": "vite build & electron-builder -w --config=./config/development.json",
|
||||
"build:prod": "vite build & electron-builder -w --config=./config/production.json",
|
||||
"build:xy": "vite build & electron-builder -w --config=./config/xy.json"
|
||||
},
|
||||
"agora_electron": {
|
||||
"platform": "win32",
|
||||
|
|
@ -34,6 +30,7 @@
|
|||
"dayjs": "^1.11.11",
|
||||
"electron-squirrel-startup": "^1.0.1",
|
||||
"electron-updater": "^6.2.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"os": "^0.1.2",
|
||||
"path": "^0.12.7",
|
||||
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
||||
|
|
|
|||
12
preload.js
|
|
@ -51,6 +51,10 @@ window.electron = {
|
|||
getVersion: () => {
|
||||
return ipcRenderer.invoke('getVersion')
|
||||
},
|
||||
// 获取环境
|
||||
getEnv: () => {
|
||||
return ipcRenderer.invoke('getEnv')
|
||||
},
|
||||
// 获取窗口是否显示
|
||||
isVisible: () => {
|
||||
return ipcRenderer.invoke('isVisible')
|
||||
|
|
@ -87,9 +91,9 @@ window.electron = {
|
|||
isOpenWindows: (callback) => {
|
||||
ipcRenderer.on('isOpenWindows', callback)
|
||||
},
|
||||
// 设置环境变量
|
||||
setEnv: (str) => {
|
||||
ipcRenderer.invoke('setEnv', str)
|
||||
// 首次加载
|
||||
startLoad: () => {
|
||||
ipcRenderer.invoke('startLoad')
|
||||
},
|
||||
// 更新
|
||||
updateHandle: () => {
|
||||
|
|
@ -134,7 +138,7 @@ window.electron = {
|
|||
ipcRenderer.invoke('createChildWindow', {
|
||||
url: location.origin + `/#/noticeWindow`,
|
||||
width: 388,
|
||||
height: 150,
|
||||
height: 180,
|
||||
key: 'noticeWindow',
|
||||
})
|
||||
ipcRenderer.invoke('createChildWindow', {
|
||||
|
|
|
|||
97
src/App.tsx
|
|
@ -8,20 +8,21 @@ import Login from '@/page/Login/index'
|
|||
import Meeting from '@/page/Meeting/index'
|
||||
import NotFound from '@/page/NotFound/index'
|
||||
import { storage } from '@/utils'
|
||||
import { message, Spin } from "antd";
|
||||
import { message, Modal, Spin } from "antd";
|
||||
import JoinMeetingModal from "@/components/JoinMeetingModal";
|
||||
import UpdateModal from "@/components/UpdateModal";
|
||||
import * as CryptoJS from 'crypto-js';
|
||||
import { PostLogin } from "@/api/Login";
|
||||
import { GetCheckOnline, PostLogin } from "@/api/Login";
|
||||
import { agora } from "@/utils/package/agora";
|
||||
import QuitTips from "@/components/QuitTips";
|
||||
import { GetLeave } from "@/api/Meeting";
|
||||
import ShareScreenWindow from "@/page/Meeting/ShareScreenWindow";
|
||||
import UserListWindow from "@/page/Meeting/UserListWindow";
|
||||
import ChatSmallWindow from "@/page/Meeting/ChatSmallWindow";
|
||||
import ChatBigWindow from "@/page/Meeting/ChatBigWindow";
|
||||
import NoticeWindow from "@/page/Meeting/NoticeWindow";
|
||||
import { getKeyOpenChildWindow, getTitle, setKeyOpenChildWindow, storageSeeting } from "./utils/package/public";
|
||||
import { ExclamationCircleFilled } from "@ant-design/icons";
|
||||
const { confirm } = Modal;
|
||||
const fs = require('fs').promises;
|
||||
const { exec } = require('child_process');
|
||||
const App: React.FC = () => {
|
||||
|
|
@ -41,20 +42,43 @@ const App: React.FC = () => {
|
|||
useEffect(() => {
|
||||
let userInfo = JSON.parse(storage.getItem('user') as string)
|
||||
let loginInfo = JSON.parse(storage.getItem('login') as string)
|
||||
window.electron.setEnv(import.meta.env.VITE_ENV);
|
||||
const login = () => {
|
||||
PostLogin({
|
||||
account: loginInfo.account,
|
||||
pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex)
|
||||
}).then(async (res) => {
|
||||
if (res.code === 200) {
|
||||
storage.setItem('user', JSON.stringify(res.data))
|
||||
storage.setItem('userLogin', true)
|
||||
toSrc('/home')
|
||||
await window.electron.startSignalr(res.data)
|
||||
} else {
|
||||
toSrc('/login')
|
||||
}
|
||||
})
|
||||
}
|
||||
if (userInfo && !userInfo.isAnonymous) {
|
||||
if (loginInfo && loginInfo.isAutoLogin) {
|
||||
PostLogin({
|
||||
account: loginInfo.account,
|
||||
pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex)
|
||||
}).then(async (res) => {
|
||||
if (res.code === 200) {
|
||||
storage.setItem('user', JSON.stringify(res.data))
|
||||
storage.setItem('userLogin', true)
|
||||
toSrc('/home')
|
||||
await window.electron.startSignalr(res.data)
|
||||
} else {
|
||||
toSrc('/login')
|
||||
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 {
|
||||
|
|
@ -79,6 +103,7 @@ const App: React.FC = () => {
|
|||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
window.electron.startLoad();
|
||||
window.electron.downFile(async (_e: any, data: any) => {
|
||||
const response = await fetch(data.filePath);
|
||||
const arrayBuffer = await response.arrayBuffer();
|
||||
|
|
@ -127,9 +152,7 @@ const App: React.FC = () => {
|
|||
}, [])
|
||||
useEffect(() => {
|
||||
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')) {
|
||||
storage.setItem('setting', JSON.stringify(storageSeeting))
|
||||
|
|
@ -164,16 +187,24 @@ const App: React.FC = () => {
|
|||
if (location.href.indexOf('/login') !== -1) {
|
||||
window.electron.onStop()
|
||||
}
|
||||
if (location.hash && location.hash.indexOf('/meeting') === -1) {
|
||||
window.electron.updateHandle()
|
||||
}
|
||||
message.destroy('cameraTemporarily')
|
||||
}, [navigate])
|
||||
}
|
||||
useEffect(() => {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'F11') {
|
||||
document.addEventListener('keydown', async (event) => {
|
||||
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();
|
||||
}
|
||||
}
|
||||
});
|
||||
document.getElementsByTagName('title')[0].innerText = getTitle(import.meta.env.VITE_ENV)
|
||||
getTitle()
|
||||
}, [])
|
||||
const handleResize = (): void => {
|
||||
setWindowSize({
|
||||
|
|
@ -200,8 +231,10 @@ const App: React.FC = () => {
|
|||
if (item.msg) {
|
||||
message.error(item.msg)
|
||||
}
|
||||
await leaveChannel(true)
|
||||
toSrc('/login')
|
||||
await leaveChannel()
|
||||
setTimeout(() => {
|
||||
toSrc('/login')
|
||||
}, 5000);
|
||||
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) {
|
||||
window.electron.closeChildWindow('shareScreenWindow')
|
||||
setKeyOpenChildWindow('shareScreenWindow', false)
|
||||
|
|
@ -240,11 +273,9 @@ const App: React.FC = () => {
|
|||
})
|
||||
})
|
||||
const data = JSON.parse(localStorage.stateInfo);
|
||||
if (!bool) {
|
||||
await GetLeave({
|
||||
roomNum: data.channelId,
|
||||
})
|
||||
}
|
||||
await window.electron.onInvoke('levelChannel', {
|
||||
roomNum: data.channelId
|
||||
})
|
||||
await agora.leaveChannel()
|
||||
}
|
||||
};
|
||||
|
|
@ -260,12 +291,8 @@ const App: React.FC = () => {
|
|||
storage.removeItem('user')
|
||||
navigate('/login')
|
||||
}
|
||||
} else if (e.key === 'reconnect') {
|
||||
if (e.value == true) {
|
||||
if (location.hash.indexOf('/meeting') === -1) {
|
||||
window.electron.updateHandle()
|
||||
}
|
||||
}
|
||||
} else if (e.key === 'env') {
|
||||
|
||||
}
|
||||
};
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -22,4 +22,10 @@ export const PostAnonLogin = (data: any) =>
|
|||
url: `/auth/anon-login`,
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
|
||||
export const GetCheckOnline = (account: string) =>
|
||||
request({
|
||||
url: `/auth/check-online?account=${account}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
|
@ -170,4 +170,15 @@ export const PostSharedScreen = (roomNum: string) =>
|
|||
request({
|
||||
url: `/room/shared-screen?roomNum=${roomNum}`,
|
||||
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 { agora } from '@/utils/package/agora';
|
||||
import { role } from '@/config/role';
|
||||
import { PostHomeVerLog } from '@/api/Meeting';
|
||||
const { setInterval, clearInterval } = require('timers');
|
||||
let time = null as any;
|
||||
const JoinSetting = forwardRef((_props: any, ref: any) => {
|
||||
|
|
@ -201,6 +202,13 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
|||
GetRoomInfo(roomNumber).then(async (res) => {
|
||||
if (res.code === 200) {
|
||||
await agora.release()
|
||||
await window.electron.getVersion().then(async req => {
|
||||
await PostHomeVerLog({
|
||||
version: req,
|
||||
platformType: 1,
|
||||
roomNum: roomNumber,
|
||||
})
|
||||
})
|
||||
navigate(`/meeting`, {
|
||||
state: {
|
||||
channelId: roomNumber,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ const StupWizard = forwardRef((_props: any, ref: any) => {
|
|||
}
|
||||
}
|
||||
storage.setItem('setting', JSON.stringify(setting))
|
||||
},
|
||||
getStupWizardModal: () => {
|
||||
return isStupWizard
|
||||
}
|
||||
}))
|
||||
const [list, setList] = useState([
|
||||
|
|
@ -130,9 +133,11 @@ const StupWizard = forwardRef((_props: any, ref: any) => {
|
|||
})
|
||||
const CurrencyComponents = () => {
|
||||
const [optionsValue, setOperationValue] = useState<'hide' | 'quit'>('hide');
|
||||
const [voiceStimulation, setVoiceStimulation] = useState(true);
|
||||
const setting = JSON.parse(storage.getItem('setting') as string)
|
||||
useEffect(() => {
|
||||
setOperationValue(setting.closeSetting)
|
||||
setVoiceStimulation(setting.voiceStimulation)
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
|
|
@ -151,6 +156,33 @@ const CurrencyComponents = () => {
|
|||
<Radio value={'hide'}>不退出程序,最小化到托盘</Radio>
|
||||
</Radio.Group>
|
||||
</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>
|
||||
|
|
@ -213,23 +245,25 @@ const VideoComponents = () => {
|
|||
}, [darkLightEnhancement]);
|
||||
useEffect(() => {
|
||||
if (typeof virtualBackground.sourceIndex === 'number') {
|
||||
if (import.meta.env.VITE_ENV === 'development') {
|
||||
window.electron.getAppPath().then((res: string) => {
|
||||
const imagePath = path.join(res, 'src', 'assets', 'virtualBackground', `${virtualBackground.sourceIndex + 1}.png`);
|
||||
window.electron.getEnv().then(res=>{
|
||||
if (res === 'development') {
|
||||
window.electron.getAppPath().then((res: string) => {
|
||||
const imagePath = path.join(res, 'src', 'assets', 'virtualBackground', `${virtualBackground.sourceIndex + 1}.png`);
|
||||
agora.enableVirtualBackground(virtualBackground.isVirtualBackground, {
|
||||
source: imagePath,
|
||||
background_source_type: 2,
|
||||
color: Number(virtualBackground.color),
|
||||
})
|
||||
})
|
||||
} else {
|
||||
const imagePath = path.join((process as any).resourcesPath, 'images', `${virtualBackground.sourceIndex + 1}.png`);
|
||||
agora.enableVirtualBackground(virtualBackground.isVirtualBackground, {
|
||||
source: imagePath,
|
||||
background_source_type: 2,
|
||||
color: Number(virtualBackground.color),
|
||||
})
|
||||
})
|
||||
} else {
|
||||
const imagePath = path.join((process as any).resourcesPath, 'images', `${virtualBackground.sourceIndex + 1}.png`);
|
||||
agora.enableVirtualBackground(virtualBackground.isVirtualBackground, {
|
||||
source: imagePath,
|
||||
background_source_type: 2,
|
||||
color: Number(virtualBackground.color),
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
agora.enableVirtualBackground(virtualBackground.isVirtualBackground, {
|
||||
background_source_type: 1,
|
||||
|
|
@ -696,7 +730,18 @@ const AudioComponents = () => {
|
|||
ecordingVolume: e,
|
||||
})
|
||||
}} disabled={!audioDeviceManager.ecordingItem} />
|
||||
{/* || audioDeviceManager.autoEcordingVolume */}
|
||||
</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>
|
||||
<Checkbox checked={audioDeviceManager.isAINoiseReduction} onChange={(e) => {
|
||||
|
|
@ -729,16 +774,6 @@ const AudioComponents = () => {
|
|||
</Radio.Group>
|
||||
</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 className={styles.audioComponentsSelect}>
|
||||
|
|
|
|||
|
|
@ -1,45 +1,106 @@
|
|||
import styles from '@/components/UpdateModal/index.module.scss'
|
||||
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 { 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, () => ({
|
||||
changeModal: (data: any) => {
|
||||
let dataJson = JSON.parse(data)
|
||||
getContent()
|
||||
if (dataJson.type === '0') { // 打开弹窗
|
||||
setIsUpdateModal(true)
|
||||
} else if (dataJson.type === '1') { // 下载中 返回进度值
|
||||
setProgress(dataJson.value.toFixed(2))
|
||||
} else if (dataJson.type === '2') { // 下载完成
|
||||
setProgress(100)
|
||||
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)
|
||||
if (dataJson.type === '0') { // 打开弹窗
|
||||
setProgress(res => {
|
||||
if (res) {
|
||||
|
||||
} else {
|
||||
window.electron.onDownload('1')
|
||||
}
|
||||
return res
|
||||
})
|
||||
} else if (dataJson.type === '1') { // 下载中 返回进度值
|
||||
if (dataJson.value === 100 && location.hash.indexOf('/meeting') === -1) {
|
||||
setIsUpdateModal(true)
|
||||
getContent()
|
||||
}
|
||||
setProgress(dataJson.value.toFixed(2))
|
||||
} else if (dataJson.type === '2') { // 下载完成
|
||||
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 [progress, setProgress] = useState(0); // 下载进度值
|
||||
const [updateContent, setUpdateContent] = useState('') // 版本更新内容
|
||||
|
||||
const [env, setEnv] = useState('')
|
||||
const [_isError, setIsError] = useState(true)
|
||||
useEffect(() => {
|
||||
window.electron.getEnv().then(res => {
|
||||
setEnv(res)
|
||||
})
|
||||
}, [])
|
||||
function getContent() {
|
||||
fetch(`${getUpdateUrl(import.meta.env.VITE_ENV)}/update.txt?t=${+new Date()}`) // 配置服务器地址
|
||||
.then(async response => {
|
||||
if (response.status === 200) {
|
||||
return setUpdateContent(await response.text())
|
||||
}
|
||||
throw new Error('Network response was not ok.');
|
||||
})
|
||||
.then(textContent => {
|
||||
})
|
||||
.catch(error => {
|
||||
});
|
||||
window.electron.getEnv().then(res => {
|
||||
fetch(`${getUpdateUrl(res)}/update.txt?t=${+new Date()}`) // 配置服务器地址
|
||||
.then(async response => {
|
||||
if (response.status === 200) {
|
||||
return setUpdateContent(await response.text())
|
||||
}
|
||||
throw new Error('Network response was not ok.');
|
||||
})
|
||||
.then(_textContent => {
|
||||
})
|
||||
.catch(_error => {
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
if (progress != 100) {
|
||||
window.electron.onDownload('0') // 取消下载
|
||||
}
|
||||
// if (progress != 100) {
|
||||
// window.electron.onDownload('0') // 取消下载
|
||||
// }
|
||||
setIsUpdateModal(false)
|
||||
}
|
||||
|
||||
|
|
@ -49,12 +110,12 @@ const UpdateModal = forwardRef((props: any, ref: any) => {
|
|||
title=""
|
||||
open={isUpdateModal}
|
||||
footer={null}
|
||||
// onCancel={() => closeModal()}
|
||||
onCancel={() => closeModal()}
|
||||
centered
|
||||
width={'400px'}
|
||||
className='modal-padding'
|
||||
maskClosable={false}
|
||||
closeIcon={false}
|
||||
closeIcon={progress === 100 ? false : true}
|
||||
>
|
||||
<div className={styles.isUpdateModal} style={{ backgroundImage: `url(${ImageUrl.icon7})` }}>
|
||||
<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' }}
|
||||
className={`m-ant-btn`}
|
||||
>立即更新</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 style={{ margin: '20px 0' }}>
|
||||
下载进度:{progress}%
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ const UserName = forwardRef((props: any, ref: any) => {
|
|||
onClick={async () => {
|
||||
const stateInfo = await JSON.parse(storage.getItem('stateInfo') as string);
|
||||
if (info.userName) {
|
||||
if (info.userName.length > 10) {
|
||||
message.error('用户名称最多10个字!')
|
||||
return
|
||||
}
|
||||
PutAlterUname({
|
||||
nickName: info.userName,
|
||||
roomNum: stateInfo.channelId,
|
||||
|
|
|
|||
|
|
@ -121,14 +121,6 @@
|
|||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
>div:nth-child(2) {
|
||||
cursor: pointer;
|
||||
|
||||
>img {
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>div:nth-child(2) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import styles from '@/page/Home/Index/index.module.scss'
|
|||
import { useEffect, useState, useRef } from "react";
|
||||
import Operation from '@/components/Operation';
|
||||
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 { ExclamationCircleFilled, ReloadOutlined } from '@ant-design/icons';
|
||||
import JoinSetting from '@/components/JoinSetting';
|
||||
|
|
@ -14,6 +14,10 @@ import dayjs from 'dayjs';
|
|||
import StupWizard from '@/components/StupWizard';
|
||||
import { GetSubDpList } from '@/api/Home/User';
|
||||
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 fs = require('fs').promises;
|
||||
const { exec } = require('child_process');
|
||||
|
|
@ -46,7 +50,6 @@ const Index: React.FC = () => {
|
|||
const [timeData, setTimeData] = useState<any>([]);
|
||||
const [isCreateRoom, setIsCreateRoom] = useState<boolean>(false);
|
||||
const [allowAnonymous, setAllowAnonymous] = useState(true);
|
||||
const [baseImage, setBaseImage] = useState('');
|
||||
const userInfo = JSON.parse(storage.getItem('user') as string)
|
||||
useEffect(() => {
|
||||
setUser(userInfo)
|
||||
|
|
@ -245,35 +248,7 @@ const Index: React.FC = () => {
|
|||
<span>{item.roomNum}</span>
|
||||
<img src={ImageUrl.icon10} alt="" />
|
||||
</div>
|
||||
<Popover
|
||||
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>
|
||||
|
||||
<Code roomNum={item.roomNum}></Code>
|
||||
</div>
|
||||
<div>
|
||||
{role.ID.includes(userInfo.roleId) ? <Popover
|
||||
|
|
@ -335,28 +310,43 @@ const Index: React.FC = () => {
|
|||
<Button type="primary"
|
||||
iconPosition={'end'}
|
||||
onClick={async () => {
|
||||
if (role.ID.includes(userInfo.roleId)) {
|
||||
joinSettingRef.current.changeModal(item.roomNum)
|
||||
} else {
|
||||
storage.setItem('loading', true)
|
||||
postRefresh(() => {
|
||||
getRoomRtcToken(item.roomNum, (options: any) => {
|
||||
if (options) {
|
||||
navigate(`/meeting`, {
|
||||
state: {
|
||||
channelId: item.roomNum,
|
||||
token: options.token,
|
||||
tokenA: options.tokenA,
|
||||
roomId: item.id,
|
||||
roomName: item.roomName,
|
||||
enableMicr: false,
|
||||
enableCamera: false,
|
||||
storage.setItem('loading', true)
|
||||
isVersion((bool: boolean) => {
|
||||
storage.setItem('loading', false)
|
||||
if (bool) {
|
||||
window.electron.onDownload('3')
|
||||
} else {
|
||||
if (role.ID.includes(userInfo.roleId)) {
|
||||
joinSettingRef.current.changeModal(item.roomNum)
|
||||
} else {
|
||||
storage.setItem('loading', true)
|
||||
postRefresh(() => {
|
||||
getRoomRtcToken(item.roomNum, async (options: any) => {
|
||||
if (options) {
|
||||
await window.electron.getVersion().then(async req => {
|
||||
await PostHomeVerLog({
|
||||
version: req,
|
||||
platformType: 1,
|
||||
roomNum: item.roomNum,
|
||||
})
|
||||
})
|
||||
navigate(`/meeting`, {
|
||||
state: {
|
||||
channelId: item.roomNum,
|
||||
token: options.token,
|
||||
tokenA: options.tokenA,
|
||||
roomId: item.id,
|
||||
roomName: item.roomName,
|
||||
enableMicr: false,
|
||||
enableCamera: false,
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}}
|
||||
icon={<img src={ImageUrl.icon9} alt="" />}
|
||||
className='m-ant-btn'>
|
||||
|
|
|
|||
|
|
@ -458,6 +458,9 @@ const User: React.FC = () => {
|
|||
if (!addUserFrom.UserName && isCreateUser !== 'batch') {
|
||||
return message.error('请输入用户名称!')
|
||||
}
|
||||
if (addUserFrom.UserName.length > 10) {
|
||||
return message.error('用户名称最多10个字!')
|
||||
}
|
||||
if (addUserFrom.year === '') {
|
||||
return message.error('请输入届!')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,8 +120,26 @@
|
|||
|
||||
@else if $i ==4 {
|
||||
flex-shrink: 0;
|
||||
color: #ccc;
|
||||
font-size: 16px;
|
||||
|
||||
>div:nth-child(1) {
|
||||
color: #ccc;
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import styles from '@/page/Home/index.module.scss'
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import { Outlet, useNavigate } from 'react-router-dom';
|
||||
import { Popconfirm, Popover } from 'antd';
|
||||
import { Button, Popconfirm, Popover } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn'
|
||||
import { storage } from '@/utils';
|
||||
|
|
@ -45,6 +45,7 @@ const Home: React.FC = () => {
|
|||
]);
|
||||
const [userInfo, setUserInfo] = useState<any>({})
|
||||
const [version, setVersion] = useState<string>('')
|
||||
const [update, setUpdate] = useState(false)
|
||||
const [dateInfo, setDateInfo] = useState<{
|
||||
work: string;
|
||||
time: string;
|
||||
|
|
@ -67,11 +68,18 @@ const Home: React.FC = () => {
|
|||
})
|
||||
};
|
||||
const timer = setInterval(updateTime, 1000);
|
||||
window.addEventListener('customStorageChange', handleCustomStorageChange);
|
||||
return () => {
|
||||
window.removeEventListener('customStorageChange', handleCustomStorageChange);
|
||||
clearInterval(timer);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleCustomStorageChange = (e: any): void => {
|
||||
if (e.key === 'isUpdate') {
|
||||
setUpdate(e.value)
|
||||
}
|
||||
};
|
||||
const changtNavList = (index: number, bool?: boolean): void => {
|
||||
const newNavList = [...navList];
|
||||
if (typeof bool === 'boolean') {
|
||||
|
|
@ -126,14 +134,22 @@ const Home: React.FC = () => {
|
|||
)
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
版本号:{version}
|
||||
<div className='drag'>
|
||||
<div>
|
||||
<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>
|
||||
<Popover
|
||||
placement="right"
|
||||
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='反馈建议'>
|
||||
|
|
|
|||
|
|
@ -4,11 +4,14 @@ import { useEffect, useState } from "react";
|
|||
import { useNavigate } from 'react-router-dom';
|
||||
import { Input, Button, Checkbox, message, Modal } from "antd"
|
||||
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 ImageUrl from '@/utils/package/imageUrl'
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
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 navigate = useNavigate();
|
||||
const [accountPasswordStatus, setAccountPasswordStatus] = useState<boolean>(false);
|
||||
|
|
@ -37,13 +40,16 @@ const Login: React.FC = () => {
|
|||
roomNum: '',
|
||||
})
|
||||
const [nameModal, setNameModal] = useState(false)
|
||||
|
||||
const [env, setEnv] = useState('')
|
||||
useEffect(() => {
|
||||
window.electron.setMainWindowSize({
|
||||
width: 752,
|
||||
height: 520,
|
||||
key: 'login'
|
||||
})
|
||||
window.electron.getEnv().then(res => {
|
||||
setEnv(res)
|
||||
})
|
||||
if (storage.getItem('login')) {
|
||||
const login = JSON.parse(storage.getItem('login') as string);
|
||||
const data = {
|
||||
|
|
@ -100,7 +106,32 @@ const Login: React.FC = () => {
|
|||
}
|
||||
GetCheckUser(operation.account).then(res => {
|
||||
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.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 className={styles.loginContent}>
|
||||
<div>
|
||||
|
|
@ -315,47 +346,58 @@ const Login: React.FC = () => {
|
|||
if (!anonInfo.nickName) {
|
||||
return message.error('请输入参会昵称!')
|
||||
}
|
||||
if (anonInfo.nickName.length > 10) {
|
||||
return message.error('参会昵称最多10个字!')
|
||||
}
|
||||
storage.setItem('loading', true)
|
||||
PostAnonLogin(anonInfo).then(async (res) => {
|
||||
if (res.code == 200) {
|
||||
storage.setItem('user', JSON.stringify(res.data))
|
||||
storage.setItem('userLogin', true)
|
||||
await window.electron.startSignalr(res.data)
|
||||
getRoomRtcToken(anonInfo.roomNum, (options: any) => {
|
||||
if (options) {
|
||||
GetRoomInfo(anonInfo.roomNum).then(async (res) => {
|
||||
if (res.code === 200) {
|
||||
setTimeout(() => {
|
||||
isVersion((bool: boolean) => {
|
||||
storage.setItem('loading', false)
|
||||
if (bool) {
|
||||
window.electron.onDownload('3')
|
||||
} else {
|
||||
storage.setItem('loading', true)
|
||||
PostAnonLogin(anonInfo).then(async (res) => {
|
||||
if (res.code == 200) {
|
||||
storage.setItem('user', JSON.stringify(res.data))
|
||||
storage.setItem('userLogin', true)
|
||||
await window.electron.startSignalr(res.data)
|
||||
getRoomRtcToken(anonInfo.roomNum, (options: any) => {
|
||||
if (options) {
|
||||
GetRoomInfo(anonInfo.roomNum).then(async (res) => {
|
||||
if (res.code === 200) {
|
||||
setTimeout(() => {
|
||||
storage.setItem('loading', false)
|
||||
window.electron.getWindowSize().then((res: any) => {
|
||||
window.electron.setMainWindowSize({
|
||||
width: Math.ceil(res.width / 1.5),
|
||||
height: Math.ceil(res.height / 1.3),
|
||||
})
|
||||
})
|
||||
navigate(`/meeting`, {
|
||||
state: {
|
||||
channelId: anonInfo.roomNum,
|
||||
token: options.token,
|
||||
tokenA: options.tokenA,
|
||||
roomId: res.data.id,
|
||||
roomName: res.data.roomName,
|
||||
enableMicr: false,
|
||||
enableCamera: false,
|
||||
}
|
||||
})
|
||||
}, 2000)
|
||||
} else {
|
||||
storage.setItem('loading', false)
|
||||
}
|
||||
}).catch(() => {
|
||||
storage.setItem('loading', false)
|
||||
window.electron.getWindowSize().then((res: any) => {
|
||||
window.electron.setMainWindowSize({
|
||||
width: Math.ceil(res.width / 1.5),
|
||||
height: Math.ceil(res.height / 1.3),
|
||||
})
|
||||
})
|
||||
navigate(`/meeting`, {
|
||||
state: {
|
||||
channelId: anonInfo.roomNum,
|
||||
token: options.token,
|
||||
tokenA: options.tokenA,
|
||||
roomId: res.data.id,
|
||||
roomName: res.data.roomName,
|
||||
enableMicr: false,
|
||||
enableCamera: false,
|
||||
}
|
||||
})
|
||||
}, 2000)
|
||||
} else {
|
||||
storage.setItem('loading', false)
|
||||
})
|
||||
}
|
||||
}).catch(() => {
|
||||
storage.setItem('loading', false)
|
||||
})
|
||||
}
|
||||
}).catch(() => {
|
||||
storage.setItem('loading', false)
|
||||
})
|
||||
}
|
||||
}).catch(() => {
|
||||
storage.setItem('loading', false)
|
||||
})
|
||||
}}>进入</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@
|
|||
font-size: 14px;
|
||||
color: #F3F3F5;
|
||||
margin-left: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
>div {}
|
||||
|
|
@ -77,6 +79,8 @@
|
|||
>span {
|
||||
font-size: 14px;
|
||||
color: #F3F3F5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
>div {
|
||||
|
|
|
|||
|
|
@ -206,19 +206,30 @@ const ChatBigWindow: React.FC = () => {
|
|||
>移出会议</Button> : null}
|
||||
</div> : <div style={{ color: 'white' }}>用户不在房间内</div>
|
||||
}>
|
||||
<div>
|
||||
<div title={item.userName}>
|
||||
<div><Avatar name={item.userName} /></div>
|
||||
{item.uid !== user.uid ?
|
||||
<span>{item.userName} <span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
|
||||
<span> <span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
|
||||
<span>
|
||||
<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>
|
||||
</Popover> : <div>
|
||||
</Popover> : <div title={item.userName}>
|
||||
<div><Avatar name={item.userName} /></div>
|
||||
{item.uid !== user.uid ?
|
||||
<span>{item.userName}<span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
|
||||
<span><span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
|
||||
<span>
|
||||
<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>{item.message}</div>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
display: flex;
|
||||
|
||||
>span:nth-child(1) {
|
||||
white-space: nowrap;
|
||||
word-break: break-all;
|
||||
color: #ff970f;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,10 @@ const NoticeWindow: React.FC = () => {
|
|||
api.open({
|
||||
message: '',
|
||||
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'>
|
||||
<Button
|
||||
type="primary"
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ const ShareScreenWindow: React.FC = () => {
|
|||
}}
|
||||
key={index}>
|
||||
<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> : ''}
|
||||
{item.select ? <img src={item.iconSelect} alt="" /> : <img src={item.active ? item.iconActive : item.icon} alt="" />}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@
|
|||
|
||||
// 演讲者模式
|
||||
.meetingContentBodyLeftSpeakerMode {
|
||||
width: 18%;
|
||||
width: 270px;
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
|
||||
|
|
@ -312,7 +312,7 @@
|
|||
}
|
||||
|
||||
.meetingContentSwiperCard {
|
||||
height: calc(100% / 6);
|
||||
height: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -379,7 +379,7 @@
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
height: 100% !important;
|
||||
width: calc(100% - 18%) !important;
|
||||
width: calc(100% - 270px) !important;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
|
@ -390,7 +390,7 @@
|
|||
|
||||
.meetingContentSwiperCard {
|
||||
height: 160px;
|
||||
width: calc(100% / 6);
|
||||
width: 270px;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
|
@ -444,8 +444,8 @@
|
|||
color: white;
|
||||
border: 1px white solid;
|
||||
font-size: 20px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
|
@ -549,6 +549,8 @@
|
|||
font-size: 14px;
|
||||
color: #F3F3F5;
|
||||
margin-left: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
>div {
|
||||
|
|
@ -660,6 +662,8 @@
|
|||
font-size: 14px;
|
||||
color: #F3F3F5;
|
||||
margin-left: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -689,6 +693,8 @@
|
|||
>span {
|
||||
font-size: 14px;
|
||||
color: #F3F3F5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
>div {
|
||||
|
|
@ -798,7 +804,7 @@
|
|||
}
|
||||
|
||||
>img {
|
||||
height: 50px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
>span {
|
||||
|
|
@ -820,8 +826,8 @@
|
|||
}
|
||||
|
||||
>label {
|
||||
height: 50px;
|
||||
height: 50px;
|
||||
height: 35px;
|
||||
height: 35px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ import { SearchOutlined, EllipsisOutlined, ExclamationCircleFilled, FullscreenEx
|
|||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { thumbImageBufferToBase64 } from '@/utils/package/base64'
|
||||
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 { agora } from '@/utils/package/agora'
|
||||
import dayjs from 'dayjs';
|
||||
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 SharedFilesModel from '@/components/SharedFilesModel';
|
||||
import StupWizard from '@/components/StupWizard';
|
||||
|
|
@ -26,6 +26,7 @@ import MeetingDisconnected from '@/components/MeetingDisconnected';
|
|||
import SingIn from '@/components/SingIn';
|
||||
import UserName from '@/components/UserName';
|
||||
import { GetRoomRtcToken } from '@/api/Home/Index';
|
||||
import Code from '@/components/Code';
|
||||
const { setTimeout, setInterval, clearTimeout, clearInterval } = require('timers');
|
||||
const { confirm } = Modal;
|
||||
const { exec } = require('child_process');
|
||||
|
|
@ -158,6 +159,8 @@ const Meeting: React.FC = () => {
|
|||
itemIndex: 0,
|
||||
rowIndex: 0,
|
||||
});
|
||||
const [_audioStatus, setAudioStatus] = useState<StreamPublishState>(1);
|
||||
const [_videoStatus, setVideoStatus] = useState<StreamPublishState>(1);
|
||||
const [roomUserList, setRoomUserList] = useState<any>([])
|
||||
const [_speackUid, setSpeackUid] = useState<any>([])
|
||||
const [currentSpeakUser, setCurrentSpeakUser] = useState<any>([])
|
||||
|
|
@ -215,6 +218,7 @@ const Meeting: React.FC = () => {
|
|||
});
|
||||
const [isVideoFullScreen, setIsVideoFullScreen] = useState<boolean>(false)
|
||||
const [observer, setObserver] = useState<IntersectionObserver>()
|
||||
const [_activeSpeaker, setActiveSpeaker] = useState('')
|
||||
let userInfo = JSON.parse(storage.getItem('user') as string)
|
||||
const msgTips = '您不是管理员或发言人,无法开启此功能!'
|
||||
const channel = new BroadcastChannel('meeting_channel');
|
||||
|
|
@ -272,7 +276,7 @@ const Meeting: React.FC = () => {
|
|||
case 'shareScreenWindowClose':
|
||||
setCurrentSeconds(shareScreenWindowClose)
|
||||
await stopScreenCapture()
|
||||
await allUserLook(userInfo.uid, userInfo.userName)
|
||||
await allUserLook(userInfo.uid, userInfo.userName, true)
|
||||
break;
|
||||
case 'shareScreenWindowfooterListsTitle':
|
||||
switch (shareScreenWindowfooterListsTitle) {
|
||||
|
|
@ -719,7 +723,7 @@ const Meeting: React.FC = () => {
|
|||
break;
|
||||
// 扩展操作
|
||||
case 'Operation':
|
||||
switch (item.type) {
|
||||
switch (item.contentString) {
|
||||
|
||||
}
|
||||
break;
|
||||
|
|
@ -782,6 +786,14 @@ const Meeting: React.FC = () => {
|
|||
break;
|
||||
// 发言人用户信息刷新
|
||||
case 'ManagerRefresh':
|
||||
if (!item.user.isRoomManager) {
|
||||
setCurrentVideoId((res: any) => {
|
||||
if (res === String(item.user.uid)) {
|
||||
getShowUser()
|
||||
}
|
||||
return res
|
||||
})
|
||||
}
|
||||
setAllUserListData('ManagerRefresh', item, async () => {
|
||||
if (item.user.uid === item.uid) {
|
||||
if (item.user.uid === userInfo.uid) {
|
||||
|
|
@ -821,73 +833,14 @@ const Meeting: React.FC = () => {
|
|||
break;
|
||||
// 申请发言
|
||||
case 'ApplyToSpeak':
|
||||
setIsScreenCapture(bool => {
|
||||
if (bool) {
|
||||
window.electron.setChildWindowShow({
|
||||
key: 'noticeWindow',
|
||||
bool: true
|
||||
})
|
||||
channel.postMessage({
|
||||
type: 'noticeItem',
|
||||
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
|
||||
window.electron.setChildWindowShow({
|
||||
key: 'noticeWindow',
|
||||
bool: true
|
||||
})
|
||||
channel.postMessage({
|
||||
type: 'noticeItem',
|
||||
noticeItem: item
|
||||
});
|
||||
break;
|
||||
// 管理员查看随机用户
|
||||
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,
|
||||
ecordingVolume: res[1].ecordingVolume
|
||||
ecordingVolume: setting.ecordingVolume
|
||||
}
|
||||
window.electron.onInvoke('sendDrivers', {
|
||||
uid: item.callerUid,
|
||||
|
|
@ -1023,10 +976,35 @@ const Meeting: React.FC = () => {
|
|||
return res
|
||||
})
|
||||
break;
|
||||
// 共享
|
||||
// 设置发言人
|
||||
case 'SetSpeaker':
|
||||
window.electron.onInvoke('SetSpeakerCallback', item.RoomManagerInputDTO)
|
||||
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 () => {
|
||||
|
|
@ -1182,6 +1160,61 @@ const Meeting: React.FC = () => {
|
|||
return () => clearTimeout(timer);
|
||||
}, [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(() => {
|
||||
let timer: NodeJS.Timeout | undefined;
|
||||
if (timer) {
|
||||
|
|
@ -1313,6 +1346,32 @@ const Meeting: React.FC = () => {
|
|||
channelId: connection.channelId,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1369,6 +1428,20 @@ const Meeting: React.FC = () => {
|
|||
} else if (state === 3) {
|
||||
meetingDisconnectedRef.current.changeModal(false)
|
||||
setIsAgoraDisconnected(false)
|
||||
} else if (state === 5) {
|
||||
confirm({
|
||||
keyboard: false,
|
||||
title: '提示',
|
||||
icon: <ExclamationCircleFilled />,
|
||||
content: `重连失败,请退出房间重试!`,
|
||||
centered: true,
|
||||
okText: '退出',
|
||||
wrapClassName: 'hideCancelText',
|
||||
cancelText: '',
|
||||
async onOk() {
|
||||
leaveChannel()
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
onConnectionLost: () => {
|
||||
|
|
@ -1388,18 +1461,33 @@ const Meeting: React.FC = () => {
|
|||
if (bool) {
|
||||
stopScreenCapture()
|
||||
setSharedScreenItem('')
|
||||
allUserLook(userInfo.uid, userInfo.userName)
|
||||
allUserLook(userInfo.uid, userInfo.userName, true)
|
||||
}
|
||||
return bool
|
||||
})
|
||||
} else if (reason === 3 || reason === 4) {
|
||||
message.error({
|
||||
content: <div>请检查摄像头是否正常工作,检查摄像头是否被其他应用占用,或者尝试重新加入频道,<span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
|
||||
content: <div>检查摄像头是否正常、未被占用,或尝试重新加入频道。<span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
|
||||
stupWizardRef.current.changeModal(1);
|
||||
}}>前往修改摄像头</span></div>,
|
||||
duration: 60,
|
||||
duration: 15,
|
||||
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) => {
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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 duration = dayjs.duration(currentSeconds, 'seconds');
|
||||
|
|
@ -1731,8 +1850,8 @@ const Meeting: React.FC = () => {
|
|||
if (res) {
|
||||
GetSharedScreen(state.channelId).then(req => {
|
||||
if (req.code === 200) {
|
||||
if (res.data) {
|
||||
setIsShare(res.data)
|
||||
if (req.data) {
|
||||
setIsShare(req.data)
|
||||
}
|
||||
getDesktopCapturerVideo()
|
||||
setIsSharedScreenModal(true)
|
||||
|
|
@ -1753,7 +1872,7 @@ const Meeting: React.FC = () => {
|
|||
}
|
||||
})
|
||||
if (row.title === '停止共享') {
|
||||
await allUserLook(userInfo.uid, userInfo.userName)
|
||||
await allUserLook(userInfo.uid, userInfo.userName, true)
|
||||
}
|
||||
break;
|
||||
case '静音':
|
||||
|
|
@ -2020,8 +2139,12 @@ const Meeting: React.FC = () => {
|
|||
})
|
||||
};
|
||||
// 设置全员看谁
|
||||
const allUserLook = async (uid: string, name: string): Promise<void> => {
|
||||
await PostShowUser(state.channelId, uid, name)
|
||||
const allUserLook = async (uid: string, name: string, bool?: boolean): Promise<void> => {
|
||||
if (bool) {
|
||||
await PostStopSharedScreen(state.channelId)
|
||||
} else {
|
||||
await PostShowUser(state.channelId, uid, name)
|
||||
}
|
||||
}
|
||||
// 设置发言人
|
||||
const postRoomManager = async (data: any): Promise<void> => {
|
||||
|
|
@ -2083,7 +2206,25 @@ const Meeting: React.FC = () => {
|
|||
item.isRoom = true;
|
||||
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) => {
|
||||
await agora.updateChannelMediaOptions(res ? true : false)
|
||||
changeAgoraDevice()
|
||||
|
|
@ -2115,7 +2256,7 @@ const Meeting: React.FC = () => {
|
|||
enableCamera: !storeDevice[0][1].active,
|
||||
isRoomManager: userItem ? userItem.isRoomManager : false,
|
||||
})
|
||||
await getShowUser()
|
||||
setVideoUser()
|
||||
if (userItem.isRoomManager) {
|
||||
await postOpenMicr(!storeDevice[0][0].active, userInfo.uid)
|
||||
await postOpenCamera(!storeDevice[0][1].active, userInfo.uid)
|
||||
|
|
@ -2147,25 +2288,28 @@ const Meeting: React.FC = () => {
|
|||
const sendMsg = (text?: string): void => {
|
||||
let msg = text ? text : textMsg;
|
||||
if (msg) {
|
||||
window.electron.onInvoke('sendChannelMsg', {
|
||||
roomNum: state.channelId,
|
||||
msg: msg,
|
||||
})
|
||||
let item = {
|
||||
uid: userInfo.uid,
|
||||
userName: userInfo.userName,
|
||||
message: msg,
|
||||
timestamp: +new Date()
|
||||
}
|
||||
setChatList((newChatList: any) => [...newChatList, item])
|
||||
window.electron.windowHandleMessage({
|
||||
key: 'chatSmallWindow',
|
||||
parmes: {
|
||||
chatListIten: item,
|
||||
setRoomUserList((res: any) => {
|
||||
let row = res.find((item: any) => item.uid === userInfo.uid)
|
||||
window.electron.onInvoke('sendChannelMsg', {
|
||||
roomNum: state.channelId,
|
||||
msg: msg,
|
||||
})
|
||||
let item = {
|
||||
uid: userInfo.uid,
|
||||
userName: row.userName,
|
||||
message: msg,
|
||||
timestamp: +new Date()
|
||||
}
|
||||
setChatList((newChatList: any) => [...newChatList, item])
|
||||
window.electron.windowHandleMessage({
|
||||
key: 'chatSmallWindow',
|
||||
parmes: {
|
||||
chatListIten: item,
|
||||
}
|
||||
})
|
||||
chatScrollBotton()
|
||||
return res
|
||||
})
|
||||
setTextMsg('');
|
||||
chatScrollBotton()
|
||||
} else {
|
||||
message.error('请输入内容!')
|
||||
}
|
||||
|
|
@ -2213,8 +2357,6 @@ const Meeting: React.FC = () => {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 开关麦克风
|
||||
const postOpenMicrApi = async (enableMicr: boolean, uid: string, isAll: boolean, isMessage: boolean = false): Promise<void> => {
|
||||
if (isAll) {
|
||||
|
|
@ -2223,11 +2365,20 @@ const Meeting: React.FC = () => {
|
|||
enableMicr
|
||||
})
|
||||
} else {
|
||||
await PostOpenMicr({
|
||||
roomNum: state.channelId,
|
||||
await window.electron.onInvoke('sendOper2User', {
|
||||
uid,
|
||||
enableMicr
|
||||
contentString: JSON.stringify({
|
||||
roomNum: state.channelId,
|
||||
uid,
|
||||
enableMicr,
|
||||
type: 'audio'
|
||||
})
|
||||
})
|
||||
// await PostOpenMicr({
|
||||
// roomNum: state.channelId,
|
||||
// uid,
|
||||
// enableMicr
|
||||
// })
|
||||
}
|
||||
if (isMessage) {
|
||||
// message.success('操作成功')
|
||||
|
|
@ -2268,11 +2419,20 @@ const Meeting: React.FC = () => {
|
|||
} else {
|
||||
await agora.stopCameraCapture();
|
||||
}
|
||||
await PostOpenCamera({
|
||||
roomNum: state.channelId,
|
||||
await window.electron.onInvoke('sendOper2User', {
|
||||
uid,
|
||||
enableCamera
|
||||
contentString: JSON.stringify({
|
||||
roomNum: state.channelId,
|
||||
uid,
|
||||
enableCamera,
|
||||
type: 'video'
|
||||
})
|
||||
})
|
||||
// await PostOpenCamera({
|
||||
// roomNum: state.channelId,
|
||||
// uid,
|
||||
// enableCamera
|
||||
// })
|
||||
if (isMessage) {
|
||||
// message.success('操作成功')
|
||||
}
|
||||
|
|
@ -2376,7 +2536,7 @@ const Meeting: React.FC = () => {
|
|||
</svg>
|
||||
</div> //右
|
||||
} 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">
|
||||
<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>
|
||||
|
|
@ -2415,6 +2575,14 @@ const Meeting: React.FC = () => {
|
|||
}
|
||||
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> => {
|
||||
confirm({
|
||||
|
|
@ -2601,7 +2769,9 @@ const Meeting: React.FC = () => {
|
|||
</Popover>}
|
||||
<div>{changeCurrentSeconds()}</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'>
|
||||
<Popover
|
||||
content={
|
||||
|
|
@ -2769,13 +2939,13 @@ const Meeting: React.FC = () => {
|
|||
</div> : null)
|
||||
}
|
||||
)}
|
||||
{isAdmin > 6 ? <div>
|
||||
{hasScrollbar() ? <div>
|
||||
{meetingMode === "StandardMode" ? <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: '20px', top: '66px' }} onClick={() => {
|
||||
const container = document.getElementById('videoView') as HTMLElement;
|
||||
container.scrollLeft -= 100
|
||||
}}>
|
||||
<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;
|
||||
container.scrollTop -= 100
|
||||
}}>
|
||||
|
|
@ -2786,7 +2956,7 @@ const Meeting: React.FC = () => {
|
|||
container.scrollLeft += 100
|
||||
}}>
|
||||
<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;
|
||||
container.scrollTop += 100
|
||||
}}>
|
||||
|
|
@ -2900,7 +3070,7 @@ const Meeting: React.FC = () => {
|
|||
<div>
|
||||
<div><Avatar name={item.userName} /></div>
|
||||
<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 ?
|
||||
<span style={{ color: '#02B188', marginLeft: '4px' }}>
|
||||
{role.ID.includes(item.roleId) ? '管理员' : '发言人'}
|
||||
|
|
@ -3120,19 +3290,30 @@ const Meeting: React.FC = () => {
|
|||
>移出会议</Button> : null}
|
||||
</div> : <div style={{ color: 'white' }}>用户不在房间内</div>
|
||||
}>
|
||||
<div>
|
||||
<div title={item.userName}>
|
||||
<div><Avatar name={item.userName} /></div>
|
||||
{item.uid !== user.uid ?
|
||||
<span>{item.userName} <span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
|
||||
<span> <span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
|
||||
<span>
|
||||
<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>
|
||||
</Popover> : <div>
|
||||
</Popover> : <div title={item.userName}>
|
||||
<div><Avatar name={item.userName} /></div>
|
||||
{item.uid !== user.uid ?
|
||||
<span>{item.userName}<span style={{ fontSize: '12px', color: '#ccc', marginLeft: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')}</span></span> :
|
||||
<span><span style={{ fontSize: '12px', color: '#ccc', marginRight: '4px' }}>{dayjs(item.timestamp).format('HH:mm:ss')} </span>{item.userName}</span>
|
||||
<span>
|
||||
<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>{item.message}</div>
|
||||
|
|
@ -3157,7 +3338,10 @@ const Meeting: React.FC = () => {
|
|||
<Input.TextArea placeholder="请输入消息" value={textMsg} style={{ flexGrow: 1 }} onChange={(e) => {
|
||||
setTextMsg(e.target.value)
|
||||
}}></Input.TextArea>
|
||||
<Button type="primary" className='m-ant-btn' style={{ flexShrink: 0, marginTop: '4px' }} onClick={() => sendMsg()}>发送</Button>
|
||||
<Button type="primary" className='m-ant-btn' style={{ flexShrink: 0, marginTop: '4px' }} onClick={() => {
|
||||
sendMsg()
|
||||
setTextMsg('');
|
||||
}}>发送</Button>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
|
|
@ -3327,7 +3511,7 @@ const Meeting: React.FC = () => {
|
|||
key={rowIndex}>
|
||||
<label>
|
||||
<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> : ''}
|
||||
</label>
|
||||
<span>{row.title}</span>
|
||||
|
|
@ -3494,7 +3678,7 @@ const meetingContentUser = (item: any, bool?: boolean) => {
|
|||
<>
|
||||
<div className={styles.meetingContentUser}>
|
||||
<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' }}>
|
||||
<img src={ImageUrl.icon32} alt="" />
|
||||
</div> : null}
|
||||
|
|
@ -3502,7 +3686,7 @@ const meetingContentUser = (item: any, bool?: boolean) => {
|
|||
bool ? !item.enableMicr ? <img src={item.enableMicr ? ImageUrl.icon22 : ImageUrl.icon22Active} alt="" /> : '' :
|
||||
<label>
|
||||
<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> : ''}
|
||||
</label>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,10 @@ export interface IElectronAPI {
|
|||
downFile: (callBack: Function) => void;
|
||||
quitAndInstall: (callBack: Function) => void;
|
||||
isOpenWindows: (callBack: Function) => void;
|
||||
setEnv: (str: string) => any;
|
||||
startLoad: () => any;
|
||||
updateHandle: () => any;
|
||||
getVersion: () => Promise<string>;
|
||||
getEnv: () => Promise<string>;
|
||||
isVisible: () => Promise<string>;
|
||||
setRegistry: (uuid: string) => any;
|
||||
getRegistry: () => any;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
declare module 'react-dom/client';
|
||||
declare module 'crypto-js';
|
||||
declare module 'js-yaml';
|
||||
declare module 'uuid';
|
||||
|
|
@ -21,7 +21,8 @@ import {
|
|||
ColorEnhanceOptions,
|
||||
LowlightEnhanceOptions,
|
||||
VirtualBackgroundSource,
|
||||
AudienceLatencyLevelType
|
||||
AudienceLatencyLevelType,
|
||||
StreamPublishState
|
||||
} from "agora-electron-sdk";
|
||||
import { GetRoomRtcToken, GetAgoraConf } from "@/api/Home/Index";
|
||||
import { storage } from '@/utils';
|
||||
|
|
@ -124,23 +125,25 @@ export const agora = {
|
|||
if (settingData.darkLightEnhancement) agora.setLowlightEnhanceOptions(settingData.darkLightEnhancement.isDarkLightEnhancement, settingData.darkLightEnhancement)
|
||||
if (settingData.virtualBackground) {
|
||||
if (typeof settingData.virtualBackground.sourceIndex === 'number') {
|
||||
if (import.meta.env.VITE_ENV === 'development') {
|
||||
window.electron.getAppPath().then((res: string) => {
|
||||
const imagePath = path.join(res, 'src', 'assets', 'virtualBackground', `${settingData.virtualBackground.sourceIndex + 1}.png`);
|
||||
window.electron.getEnv().then(res => {
|
||||
if (res === 'development') {
|
||||
window.electron.getAppPath().then((res: string) => {
|
||||
const imagePath = path.join(res, 'src', 'assets', 'virtualBackground', `${settingData.virtualBackground.sourceIndex + 1}.png`);
|
||||
agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, {
|
||||
source: imagePath,
|
||||
background_source_type: 2,
|
||||
color: Number(settingData.virtualBackground.color),
|
||||
})
|
||||
})
|
||||
} else {
|
||||
const imagePath = path.join((process as any).resourcesPath, 'images', `${settingData.virtualBackground.sourceIndex + 1}.png`);
|
||||
agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, {
|
||||
source: imagePath,
|
||||
background_source_type: 2,
|
||||
color: Number(settingData.virtualBackground.color),
|
||||
})
|
||||
})
|
||||
} else {
|
||||
const imagePath = path.join((process as any).resourcesPath, 'images', `${settingData.virtualBackground.sourceIndex + 1}.png`);
|
||||
agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, {
|
||||
source: imagePath,
|
||||
background_source_type: 2,
|
||||
color: Number(settingData.virtualBackground.color),
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, {
|
||||
background_source_type: 1,
|
||||
|
|
@ -151,7 +154,7 @@ export const agora = {
|
|||
}, 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({
|
||||
// 监听本地用户加入频道事件
|
||||
onJoinChannelSuccess: async (connection: RtcConnection, elapsed: number) => {
|
||||
|
|
@ -166,17 +169,13 @@ export const agora = {
|
|||
await onUserOffline?.(connection, remoteUid, reason)
|
||||
},
|
||||
// // 视频发布状态改变回调
|
||||
// onVideoPublishStateChanged: (source: any, channel: any, oldState: any, newState: any, elapseSinceLastState: any) => {
|
||||
// if (newState === 1) {
|
||||
|
||||
// }
|
||||
// },
|
||||
onVideoPublishStateChanged: (source: VideoSourceType, channel: string, oldState: StreamPublishState, newState: StreamPublishState, elapseSinceLastState: number) => {
|
||||
onVideoPublishStateChanged?.(source, channel, oldState, newState, elapseSinceLastState)
|
||||
},
|
||||
// // 音频发布状态改变回调
|
||||
// onAudioPublishStateChanged: (channel: any, oldState: any, newState: any, elapseSinceLastState: any) => {
|
||||
// if (newState === 1) {
|
||||
|
||||
// }
|
||||
// },
|
||||
onAudioPublishStateChanged: (channel: string, oldState: StreamPublishState, newState: StreamPublishState, elapseSinceLastState: number) => {
|
||||
onAudioPublishStateChanged?.(channel, oldState, newState, elapseSinceLastState)
|
||||
},
|
||||
// // 用户音量提示回调。
|
||||
onAudioVolumeIndication: async (_connection: RtcConnection, speakers: AudioVolumeInfo[], _speakerNumber: number, _totalVolume: number) => {
|
||||
await onAudioVolumeIndication?.(speakers)
|
||||
|
|
@ -200,6 +199,13 @@ export const agora = {
|
|||
// Token 即将在 30s 内过期回调。
|
||||
onTokenPrivilegeWillExpire: (connection: RtcConnection, token: string) => {
|
||||
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 () => {
|
||||
await rtcEngine.enableAudioVolumeIndication(100, 3, true)
|
||||
await rtcEngine.enableAudioVolumeIndication(200, 3, true)
|
||||
await rtcEngine.joinChannel(option.token, option.channelId, option.uid);
|
||||
await rtcEngine.setDualStreamModeEx(
|
||||
SimulcastStreamMode.EnableSimulcastStream,
|
||||
|
|
@ -302,6 +308,7 @@ export const agora = {
|
|||
},
|
||||
{ channelId: option.channelId, localUid: Number(option.uid) }
|
||||
);
|
||||
await rtcEngine.setAudioScenario(8)
|
||||
},
|
||||
// 更新频道配置
|
||||
updateChannelMediaOptions: async (bool: boolean) => {
|
||||
|
|
@ -441,8 +448,8 @@ export const agora = {
|
|||
startCameraCapture: async (bool: boolean = false) => {
|
||||
await rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {
|
||||
format: {
|
||||
width: bool ? 160 : 1280,
|
||||
height: bool ? 160 : 720,
|
||||
width: bool ? 160 : 1920,
|
||||
height: bool ? 160 : 1080,
|
||||
fps: 15,
|
||||
}
|
||||
})
|
||||
|
|
@ -472,7 +479,7 @@ export const agora = {
|
|||
}
|
||||
|
||||
let data = {
|
||||
frameRate: isFluencyPriority ? 30 : 15,
|
||||
frameRate: isFluencyPriority ? 15 : 7,
|
||||
dimensions: {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import path from "path";
|
||||
import storage from "./storage";
|
||||
import axios from "axios";
|
||||
import yaml from 'js-yaml'
|
||||
export const setKeyOpenChildWindow = async (key: string, bool: boolean) => {
|
||||
const openChildWindow = await JSON.parse(storage.getItem('openChildWindow') as string)
|
||||
openChildWindow[key] = bool;
|
||||
|
|
@ -27,6 +29,7 @@ export const storageSeeting: any = {
|
|||
shareFilesPath: path.resolve(__dirname, '../../Downloads/') + '\\', //共享文件保存路径
|
||||
isShareSavePath: true, //是否下载钱询问每个文件保存的位置
|
||||
closeSetting: 'hide', //关闭按钮设置
|
||||
voiceStimulation: true, //语音激励
|
||||
isAINoiseReduction: true, //是否开启ai降噪
|
||||
aINoiseReduction: 1, // 降噪模式
|
||||
isRecordingTips: true, //是否开启录制提示
|
||||
|
|
@ -59,15 +62,61 @@ export const getUpdateUrl = (env: string) => {
|
|||
switch (env) {
|
||||
case 'xy':
|
||||
return 'https://meeting-api.23544.com/meeting/xysz'
|
||||
case 'development':
|
||||
return 'http://192.168.2.9:8827'
|
||||
default:
|
||||
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) {
|
||||
case 'xy':
|
||||
return '湖北襄阳四中教研平台'
|
||||
str = '湖北襄阳四中教研平台'
|
||||
break;
|
||||
case 'development':
|
||||
str = '智汇享'
|
||||
break;
|
||||
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) {
|
||||
case 'xy':
|
||||
return 'https://meeting-api.23544.com/meeting/xysz'
|
||||
case 'development':
|
||||
return 'http://192.168.2.9:8827'
|
||||
default:
|
||||
return 'https://meeting-api.23544.com/meeting/update'
|
||||
}
|
||||
|
|
@ -11,6 +13,8 @@ module.exports = {
|
|||
switch (env) {
|
||||
case 'xy':
|
||||
return '湖北襄阳四中教研平台'
|
||||
case 'development':
|
||||
return '智汇享'
|
||||
default:
|
||||
return '智汇享'
|
||||
}
|
||||
|
|
@ -19,6 +23,8 @@ module.exports = {
|
|||
switch (env) {
|
||||
case 'xy':
|
||||
return 'icon54'
|
||||
case 'development':
|
||||
return 'icon'
|
||||
default:
|
||||
return 'icon'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||
import Request from './request'
|
||||
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({
|
||||
baseURL: import.meta.env.VITE_BASE_URL_API,
|
||||
baseURL,
|
||||
timeout: constant.CONFIG_REQUEST_TIMEOUT_TIME as number,
|
||||
interceptors: {
|
||||
// 请求拦截器
|
||||
|
|
@ -22,5 +22,4 @@ const request = (config: any) => {
|
|||
}
|
||||
return req.request<any>(config)
|
||||
}
|
||||
|
||||
export default request
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ class Request {
|
|||
case 403:
|
||||
updatePostRefresh()
|
||||
break
|
||||
case 502:
|
||||
message.error('网络已断开,请检查网络状态')
|
||||
break
|
||||
default:
|
||||
message.error(err.message)
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -76,7 +76,9 @@ export default defineConfig({
|
|||
ColorEnhanceOptions,
|
||||
LowlightEnhanceOptions,
|
||||
VirtualBackgroundSource,
|
||||
AudienceLatencyLevelType
|
||||
AudienceLatencyLevelType,
|
||||
StreamPublishState,
|
||||
IMediaEngine
|
||||
} = require("agora-electron-sdk")
|
||||
export {
|
||||
createAgoraRtcEngine,
|
||||
|
|
@ -101,7 +103,9 @@ export default defineConfig({
|
|||
ColorEnhanceOptions,
|
||||
LowlightEnhanceOptions,
|
||||
VirtualBackgroundSource,
|
||||
AudienceLatencyLevelType
|
||||
AudienceLatencyLevelType,
|
||||
StreamPublishState,
|
||||
IMediaEngine
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
|
|
|||