Compare commits
203 Commits
master-襄阳四
...
master
| 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 | |
|
|
2598ecbcea | |
|
|
fe1ed45d94 | |
|
|
52d8ff14b1 | |
|
|
7f9e62027a | |
|
|
e0ac4b2223 | |
|
|
05c4cfdd95 | |
|
|
369aaa420c | |
|
|
cc69c3d864 | |
|
|
f70074aa6d | |
|
|
0c052a6cd0 | |
|
|
d45cc15b1f | |
|
|
f24150af42 | |
|
|
fb05838a68 | |
|
|
c0b6b7afd1 | |
|
|
7fd79873f3 | |
|
|
c71ea10a4b | |
|
|
3c9b3ac48a | |
|
|
7b4cfbeb1d | |
|
|
25e9f16af0 | |
|
|
fd809034c1 | |
|
|
26ce3707d7 | |
|
|
74760e6382 | |
|
|
2e2074fda3 | |
|
|
0e37a751ea | |
|
|
70c54d71fd | |
|
|
a4ae5577d4 | |
|
|
2164fcfde4 | |
|
|
c8dc0e3276 | |
|
|
24a174c7b5 | |
|
|
e5c4b85dc4 | |
|
|
8bd09d6f01 | |
|
|
54a5b442cd | |
|
|
1d2f1072ef | |
|
|
c2b36c0b3f | |
|
|
dae9b35802 | |
|
|
9b58afece8 | |
|
|
75396341eb | |
|
|
678962d1e9 | |
|
|
dc619db987 | |
|
|
982867dfe1 | |
|
|
96959a3e6f | |
|
|
2afcef025b | |
|
|
1887bb39bc | |
|
|
bfb85e53a9 | |
|
|
88cad54e52 | |
|
|
ad16a0867b | |
|
|
6d98f0fc0f | |
|
|
c6887b2747 | |
|
|
36e1bda441 | |
|
|
f993e740d7 | |
|
|
a5e2e8b036 | |
|
|
9080065f60 | |
|
|
9f045f7531 | |
|
|
d10fdd1d5c | |
|
|
3b79abb8ee | |
|
|
c299f6f5af | |
|
|
496a4dd28f | |
|
|
956f045fad | |
|
|
2abf010867 | |
|
|
20604bb28a | |
|
|
9a6a5904a4 | |
|
|
e820c3e53c | |
|
|
92cfef8f91 | |
|
|
1c6f551a3b | |
|
|
d0ca3c9321 | |
|
|
5c5780d150 | |
|
|
d51d1f9844 | |
|
|
488724aa62 | |
|
|
d2d20d3efd | |
|
|
3723873d71 | |
|
|
c07de8d2a1 | |
|
|
3bc5994506 | |
|
|
1ad41eaf26 | |
|
|
2284b01d89 | |
|
|
c9ca37d323 | |
|
|
e26d8f0c3f | |
|
|
5d6c43e27a | |
|
|
f47681d2f1 | |
|
|
d867305ca4 | |
|
|
3df6dc6add | |
|
|
12eaca27f9 | |
|
|
db568f46eb | |
|
|
bc78d3a692 | |
|
|
e5ca4e6f3a | |
|
|
63914c1fb7 | |
|
|
d0387662a6 | |
|
|
2501267340 | |
|
|
3632bd4d07 | |
|
|
6fce7478c6 | |
|
|
9f154c558e | |
|
|
20e25fa96d | |
|
|
631dbf26b1 | |
|
|
c557fed280 | |
|
|
7b7049681a | |
|
|
bfd629f264 | |
|
|
8176c9b5d7 | |
|
|
ec5edabaf0 | |
|
|
782350dc77 | |
|
|
41e9742610 | |
|
|
c8d8db27d7 | |
|
|
97abad8231 | |
|
|
aa8809e03c | |
|
|
39010986d2 | |
|
|
d30b6ed762 | |
|
|
ae8ba8cbe2 | |
|
|
7aa8bb4a8f | |
|
|
bafa7e3a70 | |
|
|
4f462e818b | |
|
|
c99ec3668c | |
|
|
9a5ef75322 | |
|
|
0781ebc3af | |
|
|
cb1593a76f | |
|
|
79b1d8c5c2 | |
|
|
0b57e83e29 | |
|
|
cc2759b242 | |
|
|
b314a2c25f | |
|
|
5fb95d6a15 | |
|
|
4fbcf0e319 | |
|
|
a20c833de0 | |
|
|
234665d08d | |
|
|
4528696ec7 | |
|
|
9619230cf8 | |
|
|
844547d853 | |
|
|
b267f8bf4c | |
|
|
a29784bb26 | |
|
|
3498dc9a61 | |
|
|
e81f89fd88 | |
|
|
954b6d38e5 | |
|
|
a390572d99 | |
|
|
605b10e5a5 | |
|
|
3c0faea343 |
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
263
main.js
|
|
@ -8,7 +8,10 @@ const {
|
|||
ipcMain,
|
||||
clipboard,
|
||||
dialog,
|
||||
crashReporter,
|
||||
desktopCapturer,
|
||||
powerSaveBlocker,
|
||||
net
|
||||
} = require('electron');
|
||||
const path = require('node:path')
|
||||
const updateJs = require('./src/utils/package/update')
|
||||
|
|
@ -16,15 +19,20 @@ const fs = require('fs');
|
|||
const Registry = require('winreg');
|
||||
const { autoUpdater, CancellationToken } = require('electron-updater');
|
||||
const signalR = require('@microsoft/signalr');
|
||||
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')
|
||||
const id = powerSaveBlocker.start('prevent-display-sleep')
|
||||
powerSaveBlocker.stop(id)
|
||||
|
||||
class AppWindow extends BrowserWindow {
|
||||
constructor(config) {
|
||||
|
|
@ -44,13 +52,16 @@ class AppWindow extends BrowserWindow {
|
|||
};
|
||||
const finalConfig = { ...basicConfig, ...config };
|
||||
super(finalConfig);
|
||||
if (envStr === 'development') {
|
||||
// 开发
|
||||
this.loadURL('http://localhost:3000');
|
||||
if (env === 'development') {
|
||||
if (buildStatus) {
|
||||
this.loadURL('http://192.168.2.9:8827/');
|
||||
} else {
|
||||
// 测试 | 生产
|
||||
this.loadFile(path.resolve(__dirname, './dist/index.html'));
|
||||
this.loadURL('http://localhost:3000');
|
||||
}
|
||||
} else {
|
||||
this.loadURL('https://meeting-api.23544.com/')
|
||||
}
|
||||
// this.loadFile(path.resolve(__dirname, './dist/index.html'))
|
||||
this.once('ready-to-show', () => {
|
||||
this.show();
|
||||
});
|
||||
|
|
@ -59,33 +70,21 @@ class AppWindow extends BrowserWindow {
|
|||
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);
|
||||
const tray = new Tray(trayIcon);
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: '打开', click: () => {
|
||||
mainWindow.webContents.send('isOpenWindows');
|
||||
},
|
||||
// icon: iconPath,
|
||||
},
|
||||
{
|
||||
label: '最小化到系统托盘', click: () => {
|
||||
mainWindow.hide();
|
||||
},
|
||||
// icon: iconPath,
|
||||
},
|
||||
{
|
||||
label: '退出', click: async () => {
|
||||
quit()
|
||||
},
|
||||
// icon: iconPath,
|
||||
},
|
||||
]);
|
||||
tray.setToolTip(updateJs.getTitle(envStr));
|
||||
tray.setContextMenu(contextMenu);
|
||||
tray = new Tray(trayIcon);
|
||||
tray.setToolTip(updateJs.getTitle(env));
|
||||
tray.on('click', () => {
|
||||
mainWindow.webContents.send('isOpenWindows');
|
||||
});
|
||||
|
|
@ -94,20 +93,36 @@ function createTray() {
|
|||
function createWindow() {
|
||||
mainWindow = new AppWindow();
|
||||
mainWindow.focus();
|
||||
mainWindow.hookWindowMessage(278, function (e) {
|
||||
mainWindow.setEnabled(false);//窗口禁用
|
||||
setTimeout(() => {
|
||||
mainWindow.setEnabled(true);//窗口启用
|
||||
}, 100);
|
||||
return true;
|
||||
})
|
||||
}
|
||||
const additionalData = { myKey: 'myValue' }
|
||||
app.on('ready', () => {
|
||||
// 检查网络状态
|
||||
if (!checkNetworkStatus()) {
|
||||
return;
|
||||
}
|
||||
// const gotTheLock = true
|
||||
const gotTheLock = app.requestSingleInstanceLock(additionalData)
|
||||
if (gotTheLock) {
|
||||
env = process.argv.find((arg) => arg.startsWith('--env='))?.split('=')[1];
|
||||
if (env === 'development') {
|
||||
Object.defineProperty(app, 'isPackaged', {
|
||||
get() {
|
||||
return true
|
||||
}
|
||||
app.getPath('crashDumps')
|
||||
crashReporter.start({
|
||||
uploadToServer: false,
|
||||
ignoreSystemCrashHandler: false
|
||||
})
|
||||
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,
|
||||
|
|
@ -128,6 +143,12 @@ app.on('ready', () => {
|
|||
mainWindow.webContents.openDevTools()
|
||||
}
|
||||
});
|
||||
mainWindow.on('focus', () => {
|
||||
mainWindow.show()
|
||||
});
|
||||
mainWindow.on('maximize', () => {
|
||||
mainWindow.show()
|
||||
});
|
||||
// 监听移动
|
||||
mainWindow.on('move', () => {
|
||||
// 如果是全屏自动恢复到上次窗口大小
|
||||
|
|
@ -139,13 +160,19 @@ 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++
|
||||
}
|
||||
});
|
||||
// 更新
|
||||
ipcMain.handle('updateHandle', () => {
|
||||
autoUpdater.checkForUpdates()
|
||||
});
|
||||
// socket
|
||||
ipcMain.handle('startSignalr', (event, user) => {
|
||||
|
|
@ -170,6 +197,12 @@ app.on('ready', () => {
|
|||
connection.off('DriverList');
|
||||
connection.off('SetDriver');
|
||||
connection.off('ShowDriverList');
|
||||
connection.off('ModifyNickName');
|
||||
connection.off('JoinChannelCallback');
|
||||
connection.off('ExitSharedScreen');
|
||||
connection.off('SetSpeaker');
|
||||
connection.off('ReceivedOperation');
|
||||
connection.off('StopedSharedScreen');
|
||||
}
|
||||
});
|
||||
ipcMain.handle('onStop', (event) => {
|
||||
|
|
@ -189,8 +222,7 @@ app.on('ready', () => {
|
|||
await connection.invoke(str, data.roomNum, data.msg)
|
||||
break;
|
||||
case 'sendOper':
|
||||
// 4:屏幕共享
|
||||
await connection.invoke(str, data.roomNum, data.type)
|
||||
await connection.invoke(str, data.roomNum, data.contentString)
|
||||
break;
|
||||
case 'getDrivers':
|
||||
// 获取某个人的设备列表
|
||||
|
|
@ -205,13 +237,21 @@ app.on('ready', () => {
|
|||
await connection.invoke(str, data.uid, data.driversJsonString)
|
||||
break;
|
||||
case 'joinChannel':
|
||||
// 设置某个人的设备列表
|
||||
// 加入房间
|
||||
await connection.invoke(str, data.roomNum, data.enableMicr, data.enableCamera, data.isRoomManager || false)
|
||||
break;
|
||||
case 'levelChannel':
|
||||
// 设置某个人的设备列表
|
||||
// 退出房间
|
||||
await connection.invoke(str, data.roomNum)
|
||||
break;
|
||||
case 'SetSpeakerCallback':
|
||||
// 发言人设置成功
|
||||
await connection.invoke(str, data)
|
||||
break;
|
||||
case 'sendOper2User':
|
||||
// 扩展参数
|
||||
await connection.invoke(str, data.uid, data.contentString)
|
||||
break;
|
||||
}
|
||||
});
|
||||
ipcMain.handle('onOtherSignalr', (event) => {
|
||||
|
|
@ -242,10 +282,10 @@ app.on('ready', () => {
|
|||
})
|
||||
});
|
||||
// 扩展操作
|
||||
connection.on("Operation", (type) => {
|
||||
connection.on("Operation", (contentString) => {
|
||||
mainWindow.webContents.send('onSignalr', {
|
||||
key: 'Operation',
|
||||
type
|
||||
contentString
|
||||
})
|
||||
});
|
||||
// 移出会议
|
||||
|
|
@ -359,6 +399,48 @@ app.on('ready', () => {
|
|||
driversJsonString
|
||||
})
|
||||
});
|
||||
// 修改用户名称
|
||||
connection.on("ModifyNickName", (uid, nickName) => {
|
||||
mainWindow.webContents.send('onSignalr', {
|
||||
key: 'ModifyNickName',
|
||||
uid,
|
||||
nickName
|
||||
})
|
||||
});
|
||||
// 加入房间回调
|
||||
connection.on("JoinChannelCallback", (isSuccess) => {
|
||||
mainWindow.webContents.send('onSignalr', {
|
||||
key: 'JoinChannelCallback',
|
||||
isSuccess,
|
||||
})
|
||||
});
|
||||
// 退出共享
|
||||
connection.on("ExitSharedScreen", () => {
|
||||
mainWindow.webContents.send('onSignalr', {
|
||||
key: 'ExitSharedScreen'
|
||||
})
|
||||
});
|
||||
// 设置发言人
|
||||
connection.on("SetSpeaker", (RoomManagerInputDTO) => {
|
||||
mainWindow.webContents.send('onSignalr', {
|
||||
key: 'SetSpeaker',
|
||||
RoomManagerInputDTO
|
||||
})
|
||||
});
|
||||
// 扩展参数
|
||||
connection.on("ReceivedOperation", (contentString) => {
|
||||
mainWindow.webContents.send('onSignalr', {
|
||||
key: 'ReceivedOperation',
|
||||
contentString
|
||||
})
|
||||
});
|
||||
// 共享人取消共享屏幕
|
||||
connection.on("StopedSharedScreen", (ScreenShareId) => {
|
||||
mainWindow.webContents.send('onSignalr', {
|
||||
key: 'StopedSharedScreen',
|
||||
ScreenShareId
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
// 放大缩小退出窗口
|
||||
|
|
@ -382,6 +464,9 @@ app.on('ready', () => {
|
|||
case 'show':
|
||||
mainWindow.show()
|
||||
mainWindow.focus();
|
||||
mainWindow.setSkipTaskbar(false)
|
||||
mainWindow.setResizable(true)
|
||||
mainWindow.setAlwaysOnTop(false)
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
|
@ -397,6 +482,10 @@ app.on('ready', () => {
|
|||
ipcMain.handle('getVersion', () => {
|
||||
return app.getVersion();
|
||||
});
|
||||
// 获取环境
|
||||
ipcMain.handle('getEnv', () => {
|
||||
return env;
|
||||
});
|
||||
// 获取窗口是否显示
|
||||
ipcMain.handle('isVisible', () => {
|
||||
return mainWindow.isVisible();
|
||||
|
|
@ -432,6 +521,11 @@ app.on('ready', () => {
|
|||
downloadUpdate()
|
||||
} else if (data === '2') { // 下载完成 点击安装
|
||||
quitAndInstall()
|
||||
} else if (data === '3') { // 打开弹窗
|
||||
let message = JSON.stringify({
|
||||
type: '3',
|
||||
})
|
||||
sendUpdateMessage(message)
|
||||
}
|
||||
});
|
||||
// 选择文件夹
|
||||
|
|
@ -465,6 +559,34 @@ app.on('ready', () => {
|
|||
});
|
||||
// 设置桌面应用基础属性
|
||||
ipcMain.handle('setMainWindowSize', (event, config) => {
|
||||
if (config.width === 250) {
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: '退出',
|
||||
click: () => quit(),
|
||||
},
|
||||
]);
|
||||
tray.setContextMenu(contextMenu);
|
||||
mainWindow.setSkipTaskbar(true)
|
||||
mainWindow.setResizable(false)
|
||||
mainWindow.setAlwaysOnTop(true, 'screen-saver')
|
||||
} else {
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: '打开',
|
||||
click: () => mainWindow.webContents.send('isOpenWindows'),
|
||||
},
|
||||
{
|
||||
label: '最小化到系统托盘',
|
||||
click: () => mainWindow.hide(),
|
||||
},
|
||||
{
|
||||
label: '退出',
|
||||
click: () => quit(),
|
||||
},
|
||||
]);
|
||||
tray.setContextMenu(contextMenu);
|
||||
}
|
||||
// 设置最小窗口尺寸
|
||||
mainWindow.setMinimumSize(config.width, config.height);
|
||||
// 设置最大尺寸
|
||||
|
|
@ -521,13 +643,26 @@ app.on('ready', () => {
|
|||
width: config.width,
|
||||
height: config.height,
|
||||
})
|
||||
if (envStr === 'development') {
|
||||
if (env === 'development') {
|
||||
// 开发
|
||||
if (buildStatus) {
|
||||
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);//窗口禁用
|
||||
setTimeout(() => {
|
||||
child.setEnabled(true);//窗口启用
|
||||
}, 100);
|
||||
return true;
|
||||
})
|
||||
childWindow[config.key] = child
|
||||
child.once('ready-to-show', () => {
|
||||
if (config.show) {
|
||||
|
|
@ -552,9 +687,6 @@ app.on('ready', () => {
|
|||
childWindow[k] = ""
|
||||
}
|
||||
}
|
||||
mainWindow.setSkipTaskbar(false)
|
||||
mainWindow.setResizable(true)
|
||||
mainWindow.setAlwaysOnTop(false)
|
||||
} else {
|
||||
childWindow[key].close()
|
||||
childWindow[key] = ""
|
||||
|
|
@ -589,6 +721,9 @@ app.on('ready', () => {
|
|||
childWindow[config.key].hide()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (config.bool) {
|
||||
childWindow[config.key].hide()
|
||||
} else {
|
||||
if (childWindow[config.key].isVisible()) {
|
||||
childWindow[config.key].hide()
|
||||
|
|
@ -596,6 +731,7 @@ app.on('ready', () => {
|
|||
childWindow[config.key].show()
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// 定位主窗口
|
||||
ipcMain.handle('setPosition', (event, data) => {
|
||||
|
|
@ -620,7 +756,6 @@ app.on('ready', () => {
|
|||
});
|
||||
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
|
||||
function updateHandle() {
|
||||
autoUpdater.checkForUpdates()
|
||||
// autoUpdater.checkForUpdatesAndNotify().catch();
|
||||
const message = {
|
||||
error: '检查更新出错',
|
||||
|
|
@ -628,23 +763,26 @@ 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)
|
||||
})
|
||||
autoUpdater.on('update-available', function (info) {
|
||||
let messageStr = JSON.stringify({ type: '0' })
|
||||
setTimeout(() => {
|
||||
sendUpdateMessage(messageStr)
|
||||
}, 5000)
|
||||
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) {
|
||||
|
|
@ -695,9 +833,6 @@ function windowOperation(config) {
|
|||
case 'shareScreenWindow':
|
||||
x = Math.round((display.workArea.width - child.getSize()[0]) / 2);
|
||||
child.setPosition(x, 0);
|
||||
mainWindow.setSkipTaskbar(true)
|
||||
mainWindow.setResizable(false)
|
||||
mainWindow.setAlwaysOnTop(true, 'screen-saver')
|
||||
break;
|
||||
case 'chatSmallWindow':
|
||||
y = height - child.getSize()[1];
|
||||
|
|
@ -720,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.6.0",
|
||||
"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",
|
||||
|
|
|
|||
69
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,13 @@ window.electron = {
|
|||
isOpenWindows: (callback) => {
|
||||
ipcRenderer.on('isOpenWindows', callback)
|
||||
},
|
||||
// 设置环境变量
|
||||
setEnv: (str) => {
|
||||
ipcRenderer.invoke('setEnv', str)
|
||||
// 首次加载
|
||||
startLoad: () => {
|
||||
ipcRenderer.invoke('startLoad')
|
||||
},
|
||||
// 更新
|
||||
updateHandle: () => {
|
||||
ipcRenderer.invoke('updateHandle')
|
||||
},
|
||||
// 通知下载最新的包
|
||||
onDownload: (type) => {
|
||||
|
|
@ -116,8 +124,59 @@ window.electron = {
|
|||
ipcRenderer.invoke('setRegistry', uuid)
|
||||
},
|
||||
// 创建子窗口
|
||||
createChildWindow: (config) => {
|
||||
ipcRenderer.invoke('createChildWindow', config)
|
||||
createChildWindow: (str) => {
|
||||
switch (str) {
|
||||
case 'show':
|
||||
ipcRenderer.invoke('setChildWindowShow', {
|
||||
key: 'shareScreenWindow',
|
||||
})
|
||||
ipcRenderer.invoke('setChildWindowShow', {
|
||||
key: 'chatSmallWindow',
|
||||
})
|
||||
break;
|
||||
case 'hide':
|
||||
ipcRenderer.invoke('createChildWindow', {
|
||||
url: location.origin + `/#/noticeWindow`,
|
||||
width: 388,
|
||||
height: 180,
|
||||
key: 'noticeWindow',
|
||||
})
|
||||
ipcRenderer.invoke('createChildWindow', {
|
||||
url: location.origin + `/#/shareScreenWindow`,
|
||||
width: 400,
|
||||
height: 80,
|
||||
key: 'shareScreenWindow',
|
||||
})
|
||||
ipcRenderer.invoke('createChildWindow', {
|
||||
url: location.origin + `/#/chatSmallWindow`,
|
||||
width: 200,
|
||||
height: 150,
|
||||
key: 'chatSmallWindow',
|
||||
})
|
||||
ipcRenderer.invoke('createChildWindow', {
|
||||
url: location.origin + `/#/chatBigWindow`,
|
||||
width: 540,
|
||||
height: 640,
|
||||
key: 'chatBigWindow',
|
||||
})
|
||||
ipcRenderer.invoke('createChildWindow', {
|
||||
url: location.origin + `/#/userListWindow`,
|
||||
width: 440,
|
||||
height: 540,
|
||||
key: 'userListWindow',
|
||||
})
|
||||
break;
|
||||
case 'stop':
|
||||
ipcRenderer.invoke('setChildWindowShow', {
|
||||
key: 'shareScreenWindow',
|
||||
bool: true
|
||||
})
|
||||
ipcRenderer.invoke('setChildWindowShow', {
|
||||
key: 'chatSmallWindow',
|
||||
bool: true
|
||||
})
|
||||
break;
|
||||
}
|
||||
},
|
||||
// 关闭子窗口
|
||||
closeChildWindow: (key) => {
|
||||
|
|
|
|||
67
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,9 +42,7 @@ 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);
|
||||
if (userInfo && !userInfo.isAnonymous) {
|
||||
if (loginInfo && loginInfo.isAutoLogin) {
|
||||
const login = () => {
|
||||
PostLogin({
|
||||
account: loginInfo.account,
|
||||
pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex)
|
||||
|
|
@ -57,6 +56,31 @@ const App: React.FC = () => {
|
|||
toSrc('/login')
|
||||
}
|
||||
})
|
||||
}
|
||||
if (userInfo && !userInfo.isAnonymous) {
|
||||
if (loginInfo && loginInfo.isAutoLogin) {
|
||||
GetCheckOnline(loginInfo.account).then(req => {
|
||||
if (req.code === 200) {
|
||||
if (req.data) {
|
||||
confirm({
|
||||
title: '提示',
|
||||
icon: <ExclamationCircleFilled />,
|
||||
content: `账号已在其他地方登录,是否强制登陆?`,
|
||||
centered: true,
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
async onOk() {
|
||||
login()
|
||||
},
|
||||
onCancel() {
|
||||
toSrc('/login')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
login()
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
toSrc('/login')
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
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)
|
||||
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,6 +291,8 @@ const App: React.FC = () => {
|
|||
storage.removeItem('user')
|
||||
navigate('/login')
|
||||
}
|
||||
} else if (e.key === 'env') {
|
||||
|
||||
}
|
||||
};
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -5,6 +5,12 @@ export const GetRoom = (data: { pageIndex: number, pageSize: number }) =>
|
|||
method: 'get'
|
||||
})
|
||||
|
||||
export const PostFeedback = (data: any) =>
|
||||
request({
|
||||
url: `/home/feedback`,
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
export const PostRoom = (data: any) =>
|
||||
request({
|
||||
url: `/home/room`,
|
||||
|
|
@ -46,6 +52,11 @@ export const GetAgoraConf = () =>
|
|||
url: `/home/agora-conf`,
|
||||
method: 'get',
|
||||
})
|
||||
export const GetQrcode = (roomNum: string, env: string) =>
|
||||
request({
|
||||
url: `/home/r-qrcode?roomNum=${roomNum}&env=${env}`,
|
||||
method: 'get',
|
||||
})
|
||||
|
||||
export const GetRecord = (beginTimestamp: number, endTimestamp: number, roomNum: string) =>
|
||||
request({
|
||||
|
|
|
|||
|
|
@ -23,3 +23,9 @@ export const PostAnonLogin = (data: any) =>
|
|||
method: 'post',
|
||||
data,
|
||||
})
|
||||
|
||||
export const GetCheckOnline = (account: string) =>
|
||||
request({
|
||||
url: `/auth/check-online?account=${account}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
|
@ -71,14 +71,20 @@ export const PostRoomManager = (data: any) =>
|
|||
request({
|
||||
url: `/room/manager`,
|
||||
method: 'post',
|
||||
data
|
||||
data: {
|
||||
...data,
|
||||
SettingUserId: ''
|
||||
}
|
||||
})
|
||||
|
||||
export const DeleteRoomManager = (data: any) =>
|
||||
request({
|
||||
url: `/room/manager`,
|
||||
method: 'delete',
|
||||
data
|
||||
data: {
|
||||
...data,
|
||||
SettingUserId: ''
|
||||
}
|
||||
})
|
||||
|
||||
export const GetRoomKickout = (roomNum: string, kickUid: string) =>
|
||||
|
|
@ -148,3 +154,31 @@ export const PostRoomSingnIn = (data: any) =>
|
|||
method: 'post',
|
||||
data
|
||||
})
|
||||
|
||||
export const PutAlterUname = (data: any) =>
|
||||
request({
|
||||
url: `/room/alter-uname`,
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
export const GetSharedScreen = (roomNum: string) =>
|
||||
request({
|
||||
url: `/room/shared-screen?roomNum=${roomNum}`,
|
||||
method: 'get'
|
||||
})
|
||||
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 |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.6 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 |
|
|
@ -1,5 +1,5 @@
|
|||
import styles from '@/components/Avatar/index.module.scss'
|
||||
import { useState, useImperativeHandle, forwardRef } from "react";
|
||||
import { memo, useImperativeHandle, forwardRef } from "react";
|
||||
const Avatar = forwardRef((props: any, ref: any) => {
|
||||
useImperativeHandle(ref, () => ({
|
||||
getData: () => {
|
||||
|
|
@ -15,4 +15,4 @@ const Avatar = forwardRef((props: any, ref: any) => {
|
|||
)
|
||||
})
|
||||
|
||||
export default Avatar
|
||||
export default memo(Avatar)
|
||||
|
|
@ -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)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import styles from '@/components/EquipmentManagement/index.module.scss'
|
||||
import { getKeyOpenChildWindow } from '@/utils/package/public';
|
||||
import { Button, Modal, Select, Slider, message } from 'antd';
|
||||
import { useState, useImperativeHandle, forwardRef } from "react";
|
||||
import { useState, useImperativeHandle, forwardRef, memo } from "react";
|
||||
const EquipmentManagement = forwardRef((props: any, ref: any) => {
|
||||
useImperativeHandle(ref, () => ({
|
||||
changeModal: async (uid: string, userName: string) => {
|
||||
|
|
@ -116,4 +116,4 @@ const EquipmentManagement = forwardRef((props: any, ref: any) => {
|
|||
)
|
||||
})
|
||||
|
||||
export default EquipmentManagement
|
||||
export default memo(EquipmentManagement)
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
.feedBackModel {
|
||||
max-height: 80vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.feedBackModelContent {
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
margin: 10px 0;
|
||||
|
||||
.feedBackModelContentRate {
|
||||
margin-bottom: 20px;
|
||||
background-color: #101215;
|
||||
padding: 10px 20px 30px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.feedBackModelContentList {
|
||||
margin-bottom: 20px;
|
||||
|
||||
>div:nth-child(2) {
|
||||
>div {
|
||||
background-color: #101215;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
color: #7F859B;
|
||||
font-size: 14px;
|
||||
padding: 4px 8px;
|
||||
box-sizing: border-box;
|
||||
border: 1px transparent solid;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: white;
|
||||
border: 1px #495EAD solid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.feedBackModelFooter {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
import { PostFeedback } from '@/api/Home/Index';
|
||||
import styles from '@/components/FeedBackModel/index.module.scss'
|
||||
import { Button, message, Modal, Rate } from 'antd';
|
||||
import TextArea from 'antd/es/input/TextArea';
|
||||
import { useState, useImperativeHandle, forwardRef, memo } from "react";
|
||||
const FeedBackModel = forwardRef((_props: any, ref: any) => {
|
||||
useImperativeHandle(ref, () => ({
|
||||
changeModal: () => {
|
||||
setIsFeedBackModel(true)
|
||||
},
|
||||
}))
|
||||
const [isFeedBackModel, setIsFeedBackModel] = useState(false);
|
||||
const [feedBackForm, setFeedBackForm] = useState({
|
||||
rateValue: 0,
|
||||
otherContent: '',
|
||||
});
|
||||
const [feedBackList, setFeedBackList] = useState([
|
||||
{
|
||||
text: "软件卡顿",
|
||||
value: 2,
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
text: "设计不合理",
|
||||
value: 3,
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
text: "功能太少",
|
||||
value: 4,
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
text: "通话不流畅",
|
||||
value: 5,
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
text: "视频卡顿",
|
||||
value: 6,
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
text: "操作麻烦",
|
||||
value: 7,
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
text: "其他,需要手动填写",
|
||||
value: 1,
|
||||
active: false,
|
||||
},
|
||||
]);
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
title="反馈建议评分"
|
||||
open={isFeedBackModel}
|
||||
footer={null}
|
||||
destroyOnClose={true}
|
||||
onCancel={() => setIsFeedBackModel(false)}
|
||||
centered
|
||||
width={'500px'}
|
||||
>
|
||||
<div className={styles.feedBackModel}>
|
||||
<div className={styles.feedBackModelContent}>
|
||||
<div className={styles.feedBackModelContentRate}>
|
||||
<div style={{ color: 'white', fontSize: '14px', marginBottom: '4px' }}>评分:</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
||||
<Rate value={feedBackForm.rateValue} allowHalf style={{ transform: 'scale(2)' }} allowClear onChange={(e) => {
|
||||
setFeedBackForm({
|
||||
...feedBackForm,
|
||||
rateValue: e
|
||||
})
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.feedBackModelContentList}>
|
||||
<div style={{ color: 'white', fontSize: '14px', marginBottom: '4px' }}>建议:</div>
|
||||
<div>
|
||||
{
|
||||
feedBackList.map((item, index) => {
|
||||
return (
|
||||
<div key={index} className={item.active ? styles.active : ''} onClick={() => {
|
||||
const feedBackListTemp = [...feedBackList]
|
||||
feedBackListTemp[index].active = !feedBackListTemp[index].active
|
||||
setFeedBackList(feedBackListTemp)
|
||||
}}>
|
||||
<span>{item.text}</span>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.feedBackModelContentList} style={{ visibility: feedBackList[feedBackList.length - 1].active ? 'visible' : 'hidden' }}>
|
||||
<TextArea
|
||||
placeholder="填写意见"
|
||||
value={feedBackForm.otherContent}
|
||||
autoSize={{ minRows: 3, maxRows: 6 }}
|
||||
onChange={(e) => {
|
||||
setFeedBackForm({
|
||||
...feedBackForm,
|
||||
otherContent: e.target.value
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.feedBackModelFooter}>
|
||||
<Button type="primary" className='m-ant-btn'
|
||||
onClick={() => {
|
||||
let parmes = {
|
||||
score: feedBackForm.rateValue,
|
||||
otherContent: feedBackList[feedBackList.length - 1].active ? feedBackForm.otherContent : '',
|
||||
types: feedBackList.filter(row => row.active).map((item: any) => item.value),
|
||||
}
|
||||
if (feedBackForm.rateValue === 0) {
|
||||
message.error('请选择评分')
|
||||
return
|
||||
}
|
||||
PostFeedback(parmes).then(res => {
|
||||
if (res.code === 200) {
|
||||
message.success('提交成功!')
|
||||
setIsFeedBackModel(false)
|
||||
}
|
||||
})
|
||||
}}>提交</Button>
|
||||
<Button type="primary" style={{ backgroundColor: 'rgb(16,20,24)', marginLeft: '20px' }}
|
||||
onClick={() => setIsFeedBackModel(false)}>关闭</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
export default memo(FeedBackModel)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import styles from '@/components/InvitingPersonnelModal/index.module.scss'
|
||||
import { Button, Checkbox, Input, Modal, Pagination, Radio, message } from 'antd';
|
||||
import { useState, useImperativeHandle, forwardRef, useEffect } from "react";
|
||||
import { useState, useImperativeHandle, forwardRef, useEffect, memo } from "react";
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import { GetUserList } from '@/api/Home/User';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
|
@ -197,4 +197,4 @@ const InvitingPersonnelModal = forwardRef((props: any, ref: any) => {
|
|||
})
|
||||
|
||||
|
||||
export default InvitingPersonnelModal
|
||||
export default memo(InvitingPersonnelModal)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import styles from '@/components/JoinMeetingModal/index.module.scss'
|
||||
import ImageUrl from '@/utils/package/imageUrl';
|
||||
import { Modal, message } from 'antd';
|
||||
import { useState, useImperativeHandle, forwardRef, useRef } from "react";
|
||||
import { useState, useImperativeHandle, forwardRef, useRef, memo } from "react";
|
||||
import Avatar from '@/components/Avatar';
|
||||
import JoinSetting from '../JoinSetting';
|
||||
const JoinMeetingModal = forwardRef((props: any, ref: any) => {
|
||||
|
|
@ -55,4 +55,4 @@ const JoinMeetingModal = forwardRef((props: any, ref: any) => {
|
|||
)
|
||||
})
|
||||
|
||||
export default JoinMeetingModal
|
||||
export default memo(JoinMeetingModal)
|
||||
|
|
@ -3,12 +3,14 @@ import { storage } from '@/utils';
|
|||
import ImageUrl from '@/utils/package/imageUrl';
|
||||
import { GetCheckoutRoomNum, GetRoomRtcToken, GetRoomInfo } from '@/api/Home/Index';
|
||||
import { Button, Modal, message } from 'antd';
|
||||
import { useState, useImperativeHandle, forwardRef } from "react";
|
||||
import { useState, useImperativeHandle, forwardRef, memo } from "react";
|
||||
import { PostRefresh } from '@/api/Login';
|
||||
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) => {
|
||||
useImperativeHandle(ref, () => ({
|
||||
|
|
@ -19,8 +21,8 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
|||
if (location.hash.indexOf('/meeting') === -1) {
|
||||
await agora.init()
|
||||
}
|
||||
setJoinRoomSettingForm((res: any) => {
|
||||
res.forEach(async (item: any, index: number) => {
|
||||
const list = [...joinRoomSettingForm]
|
||||
list.forEach(async (item: any, index: number) => {
|
||||
if (index === 0 && role.ID.includes(userInfo.roleId)) {
|
||||
await agora.getAudioMediaList().then(res => {
|
||||
item.active = res.ecordingList.length ? true : false
|
||||
|
|
@ -29,8 +31,7 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
|||
item.active = false
|
||||
}
|
||||
});
|
||||
return res
|
||||
})
|
||||
setJoinRoomSettingForm(list)
|
||||
setRoomNumber(roomNum)
|
||||
getDeviceList()
|
||||
}
|
||||
|
|
@ -170,7 +171,7 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
|||
setJoinRoomSettingForm(list)
|
||||
if (index === 1) {
|
||||
if (list[index].active) {
|
||||
agora.startPreview('videoPreview', Number(user.screenShareId))
|
||||
agora.startPreview('videoPreview', Number(user.screenShareId), +new Date())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -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,
|
||||
|
|
@ -221,6 +229,7 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
|||
})
|
||||
} else {
|
||||
message.error('房间号不存在!')
|
||||
storage.setItem('loading', false)
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
|
@ -235,4 +244,4 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
|||
)
|
||||
})
|
||||
|
||||
export default JoinSetting
|
||||
export default memo(JoinSetting)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import styles from '@/components/MeetingDisconnected/index.module.scss'
|
||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||
import { useState, useImperativeHandle, forwardRef } from "react";
|
||||
import { useState, useImperativeHandle, forwardRef, memo } from "react";
|
||||
const MeetingDisconnected = forwardRef((props: any, ref: any) => {
|
||||
useImperativeHandle(ref, () => ({
|
||||
changeModal: (bool: boolean) => {
|
||||
|
|
@ -17,4 +17,4 @@ const MeetingDisconnected = forwardRef((props: any, ref: any) => {
|
|||
)
|
||||
})
|
||||
|
||||
export default MeetingDisconnected
|
||||
export default memo(MeetingDisconnected)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import styles from '@/components/Operation/index.module.scss'
|
||||
import ImageUrl from '@/utils/package/imageUrl';
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState, memo } from "react";
|
||||
type OperationKeyType = 'minimize' | 'quit' | 'maximize' | 'unmaximize' | 'hide' | 'show';
|
||||
type OperationType = {
|
||||
icon: string;
|
||||
|
|
@ -100,4 +100,4 @@ const Operation: React.FC = () => {
|
|||
</>
|
||||
)
|
||||
}
|
||||
export default Operation
|
||||
export default memo(Operation)
|
||||
|
|
@ -2,7 +2,7 @@ import styles from '@/components/QuitTips/index.module.scss'
|
|||
import { storage } from '@/utils';
|
||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||
import { Button, Checkbox, Modal, Radio } from 'antd';
|
||||
import { useState, useImperativeHandle, forwardRef } from "react";
|
||||
import { useState, useImperativeHandle, forwardRef, memo } from "react";
|
||||
type OperationKeyType = 'minimize' | 'quit' | 'maximize' | 'unmaximize' | 'hide' | 'show';
|
||||
const QuitTips = forwardRef((props: any, ref: any) => {
|
||||
useImperativeHandle(ref, () => ({
|
||||
|
|
@ -66,4 +66,4 @@ const QuitTips = forwardRef((props: any, ref: any) => {
|
|||
)
|
||||
})
|
||||
|
||||
export default QuitTips
|
||||
export default memo(QuitTips)
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
import styles from '@/components/SharedFilesModel/index.module.scss'
|
||||
import {
|
||||
DeleteOutlined,
|
||||
LoadingOutlined,
|
||||
ProfileOutlined,
|
||||
ReloadOutlined,
|
||||
SearchOutlined,
|
||||
VerticalAlignBottomOutlined
|
||||
} from '@ant-design/icons';
|
||||
import { Button, Input, message, Modal, Pagination, Progress, Table } from 'antd';
|
||||
import { forwardRef, useEffect, useImperativeHandle, useState, useRef } from "react";
|
||||
import { Button, Input, message, Modal, Pagination, Popconfirm, Progress, Table } from 'antd';
|
||||
import { forwardRef, useEffect, useImperativeHandle, useState, useRef, memo } from "react";
|
||||
import { DeleteRoomFile, GetRoomFile, GetRoomFileDwUrl, GetRoomUpFileurl, GetRoomUserItem, PostRoomFile } from '@/api/Meeting';
|
||||
import axios from 'axios';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
|
@ -100,10 +101,10 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
|
|||
</div>
|
||||
<div style={{ color: 'white' }}>
|
||||
<Input
|
||||
placeholder="搜索"
|
||||
placeholder="请输入文件名"
|
||||
style={{ width: '200px' }}
|
||||
prefix={<SearchOutlined style={{ color: 'white' }} />}
|
||||
onChange={(e) => {
|
||||
onPressEnter={(e: any) => {
|
||||
if (fileList.pageIndex === 1) {
|
||||
setFileList({
|
||||
...fileList,
|
||||
|
|
@ -116,8 +117,30 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
|
|||
pageIndex: 1
|
||||
})
|
||||
}
|
||||
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
if (fileList.pageIndex === 1) {
|
||||
setFileList({
|
||||
...fileList,
|
||||
keyword: e.target.value,
|
||||
})
|
||||
} else {
|
||||
setFileList({
|
||||
...fileList,
|
||||
keyword: e.target.value,
|
||||
pageIndex: 1
|
||||
})
|
||||
}
|
||||
}}
|
||||
suffix={
|
||||
<span
|
||||
style={{ color: '#47D3D0', cursor: 'pointer' }}
|
||||
onClick={() => {
|
||||
getRoomFile()
|
||||
}}
|
||||
>搜索
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
<ReloadOutlined title='刷新' onClick={() => {
|
||||
if (fileList.pageIndex === 1) {
|
||||
|
|
@ -129,10 +152,14 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
|
|||
})
|
||||
}
|
||||
}} />
|
||||
{roomUserItem && role.ID.includes(roomUserItem.roleId) || roomUserItem.isRoomManager ? <ProfileOutlined title={showRowSelection ? '取消框选' : '显示框选'} onClick={() => {
|
||||
{roomUserItem && (role.ID.includes(roomUserItem.roleId) || roomUserItem.isRoomManager) && fileList.data.length ? <ProfileOutlined title={showRowSelection ? '取消框选' : '显示框选'} onClick={() => {
|
||||
setShowRowSelection(!showRowSelection)
|
||||
}} style={{ color: showRowSelection ? '#5575F2' : 'white' }} /> : null}
|
||||
{showRowSelection ? <DeleteOutlined title='删除' onClick={() => {
|
||||
{showRowSelection && fileList.data.length && selectedRowKeys.length ?
|
||||
<Popconfirm
|
||||
title="提示"
|
||||
description="确认删除吗?"
|
||||
onConfirm={() => {
|
||||
if (selectedRowKeys.length) {
|
||||
DeleteRoomFile(selectedRowKeys).then(res => {
|
||||
if (res.code === 200) {
|
||||
|
|
@ -150,8 +177,16 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
|
|||
} else {
|
||||
message.error('请选择文件!')
|
||||
}
|
||||
}} /> : null}
|
||||
<Button type="primary" style={{ backgroundColor: '#31353A' }}
|
||||
}}
|
||||
onCancel={() => {
|
||||
|
||||
}}
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
>
|
||||
<DeleteOutlined title='删除' />
|
||||
</Popconfirm> : null}
|
||||
{roomUserItem && role.ID.includes(roomUserItem.roleId) || roomUserItem.isRoomManager ? <Button type="primary" style={{ backgroundColor: '#31353A' }}
|
||||
onClick={() => {
|
||||
if (isUpFile) {
|
||||
message.error('文件上传中,请稍后上传。')
|
||||
|
|
@ -211,7 +246,7 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
|
|||
};
|
||||
file.click();
|
||||
}}
|
||||
>上传</Button>
|
||||
>上传</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -258,9 +293,10 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
|
|||
/>
|
||||
<Column title="操作" render={(item) => (
|
||||
<>
|
||||
<VerticalAlignBottomOutlined title='下载'
|
||||
{!item.showPercentComplete ? <VerticalAlignBottomOutlined title='下载'
|
||||
style={{ color: '#5575F2', cursor: 'pointer' }}
|
||||
onClick={async () => {
|
||||
storage.setItem('loading', true)
|
||||
GetRoomFileDwUrl(item.fileUrl, item.id).then(res => {
|
||||
if (res.code === 200) {
|
||||
axios({
|
||||
|
|
@ -329,8 +365,10 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
|
|||
}, 2000)
|
||||
})
|
||||
}
|
||||
}).finally(() => {
|
||||
storage.setItem('loading', false)
|
||||
})
|
||||
}} />
|
||||
}} /> : <LoadingOutlined />}
|
||||
{/* <FolderOutlined title='文件' style={{ color: '#FFA000', cursor: 'pointer', marginLeft: '10px' }} /> */}
|
||||
</>
|
||||
)} />
|
||||
|
|
@ -341,7 +379,7 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
|
|||
...fileList,
|
||||
pageIndex: e
|
||||
})
|
||||
}} pageSize={fileList.pageSize} current={fileList.pageIndex} hideOnSinglePage={true} showSizeChanger={false}/>
|
||||
}} pageSize={fileList.pageSize} current={fileList.pageIndex} hideOnSinglePage={true} showSizeChanger={false} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -355,4 +393,4 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
|
|||
)
|
||||
})
|
||||
|
||||
export default SharedFilesModel
|
||||
export default memo(SharedFilesModel)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ import { GetRoomSingnIn, PostRoomSingnIn } from '@/api/Meeting';
|
|||
import styles from '@/components/SingIn/index.module.scss'
|
||||
import { storage } from '@/utils';
|
||||
import { Button, message, Modal } from 'antd';
|
||||
import { useState, useImperativeHandle, forwardRef } from "react";
|
||||
import { useState, useImperativeHandle, forwardRef, memo } from "react";
|
||||
const SingIn = forwardRef((props: any, ref: any) => {
|
||||
useImperativeHandle(ref, () => ({
|
||||
changeModal: () => {
|
||||
getRoomSingnIn()
|
||||
},
|
||||
getModal: () => {
|
||||
setIsMessage(true)
|
||||
return new Promise((resolve, reject) => {
|
||||
setSingInModal(bool => {
|
||||
resolve(bool)
|
||||
|
|
@ -18,12 +19,20 @@ const SingIn = forwardRef((props: any, ref: any) => {
|
|||
},
|
||||
}))
|
||||
const [singInModal, setSingInModal] = useState(false);
|
||||
const [isMessage, setIsMessage] = useState(false);
|
||||
const [singInList, setSingInList] = useState([]);
|
||||
const getRoomSingnIn = async (): Promise<void> => {
|
||||
await GetRoomSingnIn().then(res => {
|
||||
if (res.code === 200) {
|
||||
if (res.data.length) {
|
||||
setSingInModal(true)
|
||||
} else {
|
||||
setIsMessage(bool => {
|
||||
if (!bool) {
|
||||
message.error('暂未绑定签到人,请联系管理员添加后签到!')
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
setSingInList(res.data.map((item: any) => {
|
||||
return {
|
||||
|
|
@ -76,4 +85,4 @@ const SingIn = forwardRef((props: any, ref: any) => {
|
|||
)
|
||||
})
|
||||
|
||||
export default SingIn
|
||||
export default memo(SingIn)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import styles from '@/components/SpeakerModeModal/index.module.scss'
|
||||
import { Checkbox, Modal } from 'antd';
|
||||
import { useState, useImperativeHandle, forwardRef } from "react";
|
||||
import { useState, useImperativeHandle, forwardRef, memo } from "react";
|
||||
import { storage } from '@/utils';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { GetSyncView } from '@/api/Meeting';
|
||||
|
|
@ -147,4 +147,4 @@ const FourScreenMode: React.FC<Props> = ({ onClick, meetingMode }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export default SpeakerModeModal
|
||||
export default memo(SpeakerModeModal)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import styles from '@/components/StupWizard/index.module.scss'
|
||||
import ImageUrl from '@/utils/package/imageUrl';
|
||||
import { Button, Checkbox, Empty, Input, message, Modal, Popover, Radio, Select, Slider, Space } from 'antd';
|
||||
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
||||
import { forwardRef, useEffect, useImperativeHandle, useState, memo } from "react";
|
||||
import { agora } from '@/utils/package/agora'
|
||||
import { CloseOutlined, LoadingOutlined, QuestionCircleOutlined } from '@ant-design/icons';
|
||||
import { storage } from '@/utils';
|
||||
|
|
@ -11,6 +11,7 @@ import { storageSeeting } from '@/utils/package/public';
|
|||
let meetingUserInfo = '' as any;
|
||||
const fs = require('fs').promises;
|
||||
const { exec } = require('child_process');
|
||||
let c = +new Date();
|
||||
const StupWizard = forwardRef((_props: any, ref: any) => {
|
||||
useImperativeHandle(ref, () => ({
|
||||
changeModal: (index: number = 0, data: any) => {
|
||||
|
|
@ -33,6 +34,9 @@ const StupWizard = forwardRef((_props: any, ref: any) => {
|
|||
}
|
||||
}
|
||||
storage.setItem('setting', JSON.stringify(setting))
|
||||
},
|
||||
getStupWizardModal: () => {
|
||||
return isStupWizard
|
||||
}
|
||||
}))
|
||||
const [list, setList] = useState([
|
||||
|
|
@ -84,6 +88,8 @@ const StupWizard = forwardRef((_props: any, ref: any) => {
|
|||
{list.map((row: any, index: number) => {
|
||||
return (
|
||||
<div key={index} className={`${row.active ? styles.active : ''}`} onClick={async () => {
|
||||
const userInfo = JSON.parse(storage.getItem('user') as string)
|
||||
await agora.destroyRendererByConfigPreview(Number(userInfo.screenShareId), c)
|
||||
const newList = [...list];
|
||||
newList.forEach(item => item.active = false);
|
||||
newList[index].active = true;
|
||||
|
|
@ -106,9 +112,11 @@ const StupWizard = forwardRef((_props: any, ref: any) => {
|
|||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={async () => {
|
||||
const userInfo = JSON.parse(storage.getItem('user') as string)
|
||||
if (location.hash.indexOf('/meeting') === -1) {
|
||||
agora.release()
|
||||
}
|
||||
await agora.destroyRendererByConfigPreview(Number(userInfo.screenShareId), c)
|
||||
setIsStupWizard(false)
|
||||
}}
|
||||
/>
|
||||
|
|
@ -125,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 (
|
||||
<>
|
||||
|
|
@ -146,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>
|
||||
|
|
@ -208,7 +245,8 @@ const VideoComponents = () => {
|
|||
}, [darkLightEnhancement]);
|
||||
useEffect(() => {
|
||||
if (typeof virtualBackground.sourceIndex === 'number') {
|
||||
if (import.meta.env.VITE_ENV === 'development') {
|
||||
window.electron.getEnv().then(res=>{
|
||||
if (res === 'development') {
|
||||
window.electron.getAppPath().then((res: string) => {
|
||||
const imagePath = path.join(res, 'src', 'assets', 'virtualBackground', `${virtualBackground.sourceIndex + 1}.png`);
|
||||
agora.enableVirtualBackground(virtualBackground.isVirtualBackground, {
|
||||
|
|
@ -225,6 +263,7 @@ const VideoComponents = () => {
|
|||
color: Number(virtualBackground.color),
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
agora.enableVirtualBackground(virtualBackground.isVirtualBackground, {
|
||||
background_source_type: 1,
|
||||
|
|
@ -247,7 +286,7 @@ const VideoComponents = () => {
|
|||
})
|
||||
if (setting.videoDeviceId && list.length) {
|
||||
await agora.setVideoDeviceManager(setting.videoDeviceId)
|
||||
await agora.startPreview('videoPreview', Number(userInfo.screenShareId))
|
||||
await agora.startPreview('videoPreview', Number(userInfo.screenShareId), c)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -305,7 +344,7 @@ const VideoComponents = () => {
|
|||
agora.setVideoDeviceManager(e)
|
||||
if (!setting.videoDeviceId) {
|
||||
const userInfo = JSON.parse(storage.getItem('user') as string)
|
||||
await agora.startPreview('videoPreview', Number(userInfo.screenShareId))
|
||||
await agora.startPreview('videoPreview', Number(userInfo.screenShareId), c)
|
||||
}
|
||||
setting.videoDeviceId = e;
|
||||
storage.setItem('setting', JSON.stringify(setting))
|
||||
|
|
@ -691,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) => {
|
||||
|
|
@ -724,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}>
|
||||
|
|
@ -964,4 +1004,4 @@ const FileComponents = () => {
|
|||
)
|
||||
}
|
||||
|
||||
export default StupWizard
|
||||
export default memo(StupWizard)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect } from "react";
|
||||
import { useEffect, memo } from "react";
|
||||
import '@/components/TldrawView/index.scss'
|
||||
import {
|
||||
Tldraw,
|
||||
|
|
@ -44,4 +44,4 @@ const TldrawView: React.FC = () => {
|
|||
</>
|
||||
)
|
||||
}
|
||||
export default TldrawView
|
||||
export default memo(TldrawView)
|
||||
|
|
@ -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 } 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) => {
|
||||
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)
|
||||
getContent()
|
||||
if (dataJson.type === '0') { // 打开弹窗
|
||||
setIsUpdateModal(true)
|
||||
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()}`) // 配置服务器地址
|
||||
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 => {
|
||||
.then(_textContent => {
|
||||
})
|
||||
.catch(error => {
|
||||
.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}%
|
||||
|
|
@ -87,4 +148,4 @@ const UpdateModal = forwardRef((props: any, ref: any) => {
|
|||
)
|
||||
})
|
||||
|
||||
export default UpdateModal
|
||||
export default memo(UpdateModal)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
.userNameModal {
|
||||
|
||||
.userNameModalFooter {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
import { PutAlterUname } from '@/api/Meeting';
|
||||
import styles from '@/components/UserName/index.module.scss'
|
||||
import { storage } from '@/utils';
|
||||
import { Button, Input, message, Modal } from 'antd';
|
||||
import { useState, useImperativeHandle, forwardRef, memo } from "react";
|
||||
const UserName = forwardRef((props: any, ref: any) => {
|
||||
useImperativeHandle(ref, () => ({
|
||||
changeModal: (data: any) => {
|
||||
setInfo(data)
|
||||
setUserNameModal(true)
|
||||
}
|
||||
}))
|
||||
const [userNameModal, setUserNameModal] = useState(false);
|
||||
const [info, setInfo] = useState({
|
||||
userName: '',
|
||||
uid: ''
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
title="修改用户名"
|
||||
open={userNameModal}
|
||||
footer={null}
|
||||
destroyOnClose={true}
|
||||
onCancel={() => setUserNameModal(false)}
|
||||
centered
|
||||
width={'300px'}
|
||||
>
|
||||
<div className={styles.userNameModal}>
|
||||
<div className={styles.userNameModalContent}>
|
||||
<Input
|
||||
placeholder="请输入用户名称"
|
||||
style={{ width: '100%' }}
|
||||
value={info.userName}
|
||||
onChange={(e) => {
|
||||
setInfo({
|
||||
...info,
|
||||
userName: e.target.value
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.userNameModalFooter}>
|
||||
<Button type="primary" style={{ backgroundColor: 'rgb(16,20,24)', marginRight: '14px' }}
|
||||
onClick={() => setUserNameModal(false)}>关闭</Button>
|
||||
<Button type="primary"
|
||||
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,
|
||||
uid: info.uid,
|
||||
}).then((res) => {
|
||||
if (res.code === 200) {
|
||||
message.success('修改成功')
|
||||
setUserNameModal(false)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
message.error('请输入用户名')
|
||||
}
|
||||
}}
|
||||
className='m-ant-btn'>
|
||||
修改
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
export default memo(UserName)
|
||||
|
|
@ -65,8 +65,8 @@
|
|||
height: 0;
|
||||
|
||||
.userVideoContentListItem {
|
||||
height: 32%;
|
||||
width: calc(100% / 4 - 8px);
|
||||
height: calc(100% / 6 - 8px);
|
||||
width: calc(100% / 2 - 8px);
|
||||
padding: 4px;
|
||||
|
||||
.userVideoContentListItemVideo {
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ import styles from '@/components/UserVideo/index.module.scss'
|
|||
import { GetPolling } from '@/api/Meeting';
|
||||
import { agora } from '@/utils/package/agora';
|
||||
import { Button, Empty, Select, message } from 'antd';
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState, memo } from "react";
|
||||
import { useLocation } from 'react-router';
|
||||
import { VideoStreamType } from 'agora-electron-sdk';
|
||||
const { setInterval, clearInterval } = require('timers');
|
||||
const UserVideo: React.FC = () => {
|
||||
const { state } = useLocation();
|
||||
const [from, setFrom] = useState<any>({
|
||||
|
|
@ -153,4 +154,4 @@ const UserVideo: React.FC = () => {
|
|||
)
|
||||
}
|
||||
|
||||
export default UserVideo
|
||||
export default memo(UserVideo)
|
||||
|
|
|
|||
|
|
@ -108,14 +108,20 @@
|
|||
>div:nth-child(1) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
>div:nth-child(1) {
|
||||
margin-right: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
>span {
|
||||
color: #767676;
|
||||
margin-right: 4px;
|
||||
margin-right: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>div:nth-child(2) {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -1,24 +1,31 @@
|
|||
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 } from "antd";
|
||||
import { Button, Input, Modal, Pagination, Empty, message, Popover, Popconfirm, DatePicker, Select, Radio } from "antd";
|
||||
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';
|
||||
import { storage } from '@/utils';
|
||||
import { PostRefresh } from '@/api/Login';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { role } from '@/config/role';
|
||||
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');
|
||||
const { RangePicker } = DatePicker;
|
||||
const { confirm } = Modal;
|
||||
const Index: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { state } = useLocation();
|
||||
const [list, setList] = useState({
|
||||
data: [],
|
||||
total: 0,
|
||||
|
|
@ -36,14 +43,19 @@ const Index: React.FC = () => {
|
|||
})
|
||||
const joinSettingRef = useRef<any>();
|
||||
const stupWizardRef = useRef<any>();
|
||||
const feedBackModelRef = useRef<any>();
|
||||
const [user, setUser] = useState<any>({});
|
||||
const [currentRoomInfo, setCurrentRoomInfo] = useState<any>({});
|
||||
const [subjectList, setSubjectList] = useState<any>([]);
|
||||
const [timeData, setTimeData] = useState<any>([]);
|
||||
const [isCreateRoom, setIsCreateRoom] = useState<boolean>(false);
|
||||
const [allowAnonymous, setAllowAnonymous] = useState(true);
|
||||
const userInfo = JSON.parse(storage.getItem('user') as string)
|
||||
useEffect(() => {
|
||||
setUser(userInfo)
|
||||
if (state?.currentSeconds >= 600) {
|
||||
feedBackModelRef.current.changeModal()
|
||||
}
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
let time = null as any
|
||||
|
|
@ -230,11 +242,14 @@ const Index: React.FC = () => {
|
|||
<span>{item.onlineUserCount}人</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div onClick={() => copyRoomNum(item.roomNum)} title='复制房间号'>
|
||||
<span>{item.roomNum}</span>
|
||||
<img src={ImageUrl.icon10} alt="" />
|
||||
</div>
|
||||
<Code roomNum={item.roomNum}></Code>
|
||||
</div>
|
||||
<div>
|
||||
{role.ID.includes(userInfo.roleId) ? <Popover
|
||||
content={
|
||||
|
|
@ -272,6 +287,7 @@ const Index: React.FC = () => {
|
|||
year: item.year,
|
||||
id: item.id,
|
||||
})
|
||||
setAllowAnonymous(item.allowAnonymous)
|
||||
getSubDpList()
|
||||
setIsCreateRoom(false)
|
||||
setCreateRoomModal(true)
|
||||
|
|
@ -294,13 +310,26 @@ const Index: React.FC = () => {
|
|||
<Button type="primary"
|
||||
iconPosition={'end'}
|
||||
onClick={async () => {
|
||||
storage.setItem('loading', true)
|
||||
isVersion((bool: boolean) => {
|
||||
storage.setItem('loading', false)
|
||||
if (bool) {
|
||||
window.electron.onDownload('3')
|
||||
} else {
|
||||
if (role.ID.includes(userInfo.roleId)) {
|
||||
joinSettingRef.current.changeModal(item.roomNum)
|
||||
} else {
|
||||
storage.setItem('loading', true)
|
||||
postRefresh(() => {
|
||||
getRoomRtcToken(item.roomNum, (options: any) => {
|
||||
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,
|
||||
|
|
@ -316,6 +345,8 @@ const Index: React.FC = () => {
|
|||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}}
|
||||
icon={<img src={ImageUrl.icon9} alt="" />}
|
||||
className='m-ant-btn'>
|
||||
|
|
@ -352,7 +383,6 @@ const Index: React.FC = () => {
|
|||
placeholder="请输入房间号"
|
||||
style={{ flexGrow: 1 }}
|
||||
className={styles.letterSpacing}
|
||||
showCount
|
||||
maxLength={8}
|
||||
value={createRoomFrom.roomNum}
|
||||
onChange={(e) => {
|
||||
|
|
@ -389,7 +419,6 @@ const Index: React.FC = () => {
|
|||
<Input.TextArea
|
||||
placeholder="请输入房间名字"
|
||||
style={{ flexGrow: 1 }}
|
||||
showCount
|
||||
maxLength={30}
|
||||
value={createRoomFrom.roomName}
|
||||
onChange={(e) => {
|
||||
|
|
@ -404,6 +433,7 @@ const Index: React.FC = () => {
|
|||
<span>届:</span>
|
||||
<Input
|
||||
placeholder="请输入届"
|
||||
maxLength={4}
|
||||
style={{ flexGrow: 1 }}
|
||||
value={createRoomFrom.year}
|
||||
onChange={(e) => {
|
||||
|
|
@ -430,6 +460,15 @@ const Index: React.FC = () => {
|
|||
})
|
||||
}} />
|
||||
</div>
|
||||
<div>
|
||||
<span>游客入会:</span>
|
||||
<Radio.Group onChange={(e) => {
|
||||
setAllowAnonymous(e.target.value);
|
||||
}} value={allowAnonymous}>
|
||||
<Radio value={true}>开启</Radio>
|
||||
<Radio value={false}>关闭</Radio>
|
||||
</Radio.Group>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{
|
||||
display: 'flex', justifyContent: 'center'
|
||||
|
|
@ -442,7 +481,7 @@ const Index: React.FC = () => {
|
|||
if (!createRoomFrom.roomNum) {
|
||||
return message.error('请输入房间号!')
|
||||
}
|
||||
if (!createRoomFrom.year) {
|
||||
if (createRoomFrom.year === "") {
|
||||
return message.error('请输入届!')
|
||||
}
|
||||
if (isCreateRoom) {
|
||||
|
|
@ -450,20 +489,22 @@ const Index: React.FC = () => {
|
|||
if (bool) {
|
||||
message.error('房间号已存在!')
|
||||
} else {
|
||||
PostRoom(createRoomFrom).then(res => {
|
||||
PostRoom({ ...createRoomFrom, allowAnonymous }).then(res => {
|
||||
if (res.code === 200) {
|
||||
message.success('创建成功!')
|
||||
setCreateRoomModal(false)
|
||||
setAllowAnonymous(true)
|
||||
getRoomList()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
PostRoomInfo(createRoomFrom).then(res => {
|
||||
PostRoomInfo({ ...createRoomFrom, allowAnonymous }).then(res => {
|
||||
if (res.code === 200) {
|
||||
message.success('更新成功!')
|
||||
setCreateRoomModal(false)
|
||||
setAllowAnonymous(true)
|
||||
getRoomList()
|
||||
}
|
||||
})
|
||||
|
|
@ -506,6 +547,7 @@ const Index: React.FC = () => {
|
|||
</Modal>
|
||||
<JoinSetting ref={joinSettingRef} />
|
||||
<StupWizard ref={stupWizardRef} />
|
||||
<FeedBackModel ref={feedBackModelRef} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -415,6 +415,7 @@ const User: React.FC = () => {
|
|||
<Input
|
||||
placeholder="请输入届"
|
||||
value={addUserFrom.year}
|
||||
maxLength={4}
|
||||
onChange={(e) => {
|
||||
const regex = /^[0-9]*$/;
|
||||
if (regex.test(e.target.value)) {
|
||||
|
|
@ -457,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('请输入届!')
|
||||
}
|
||||
|
|
@ -602,7 +606,7 @@ const User: React.FC = () => {
|
|||
onClick={() => {
|
||||
const file = document.createElement("input") as any;
|
||||
file.type = "file";
|
||||
// file.accept = ".xls,.xlsx";
|
||||
file.accept = ".xls,.xlsx";
|
||||
file.onchange = async () => {
|
||||
const setting = await JSON.parse(storage.getItem('setting') as string)
|
||||
const fileInfo = file.files[0];
|
||||
|
|
@ -669,7 +673,7 @@ const User: React.FC = () => {
|
|||
onClick={() => {
|
||||
const file = document.createElement("input") as any;
|
||||
file.type = "file";
|
||||
// file.accept = ".xls,.xlsx";
|
||||
file.accept = ".xls,.xlsx";
|
||||
file.onchange = async () => {
|
||||
const setting = await JSON.parse(storage.getItem('setting') as string)
|
||||
const fileInfo = file.files[0];
|
||||
|
|
@ -762,12 +766,17 @@ const User: React.FC = () => {
|
|||
<Button type="primary" style={{ backgroundColor: '#31353A', marginRight: '14px' }}
|
||||
onClick={() => setSignInUserModal(false)}>取消</Button>
|
||||
<Button type="primary" className='m-ant-btn' onClick={() => {
|
||||
let signInNameNull = signInUserForm.currentUserList.find((item: any) => !item.signInName)
|
||||
if (signInNameNull) {
|
||||
message.error('请输入用户名称');
|
||||
} else {
|
||||
PutSigns(signInUserForm.uid, signInUserForm.currentUserList).then(res => {
|
||||
if (res.code === 200) {
|
||||
message.success('签到绑定成功')
|
||||
setSignInUserModal(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
}}>确定</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -120,8 +120,26 @@
|
|||
|
||||
@else if $i ==4 {
|
||||
flex-shrink: 0;
|
||||
|
||||
>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 {
|
||||
|
|
@ -130,7 +148,7 @@
|
|||
padding-top: 10px;
|
||||
margin-top: 10px;
|
||||
|
||||
@for $i from 1 through 2 {
|
||||
@for $i from 1 through 3 {
|
||||
>div:nth-child(#{$i}) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -144,13 +162,16 @@
|
|||
height: 16px;
|
||||
|
||||
@if $i ==1 {
|
||||
background: url('/src/assets/icon16.png') no-repeat center/cover;
|
||||
background: url('/src/assets/icon56.png') no-repeat center/120%;
|
||||
}
|
||||
|
||||
@else if $i ==2 {
|
||||
background: url('/src/assets/icon15.png') no-repeat center/cover;
|
||||
background: url('/src/assets/icon16.png') no-repeat center/cover;
|
||||
}
|
||||
|
||||
@else if $i ==3 {
|
||||
background: url('/src/assets/icon15.png') no-repeat center/cover;
|
||||
}
|
||||
}
|
||||
|
||||
>span {
|
||||
|
|
@ -162,10 +183,14 @@
|
|||
&:hover {
|
||||
>div {
|
||||
@if $i ==1 {
|
||||
background: url('/src/assets/icon16-active.png') no-repeat center/cover;
|
||||
background: url('/src/assets/icon56-active.png') no-repeat center/120%;
|
||||
}
|
||||
|
||||
@else if $i ==2 {
|
||||
background: url('/src/assets/icon16-active.png') no-repeat center/cover;
|
||||
}
|
||||
|
||||
@else if $i ==3 {
|
||||
background: url('/src/assets/icon15-active.png') no-repeat center/cover;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import styles from '@/page/Home/index.module.scss'
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import { Outlet, useNavigate } from 'react-router-dom';
|
||||
import { Popconfirm } from 'antd';
|
||||
import { Button, Popconfirm, Popover } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn'
|
||||
import { storage } from '@/utils';
|
||||
import ImageUrl from '@/utils/package/imageUrl'
|
||||
import Avatar from '@/components/Avatar';
|
||||
import StupWizard from '@/components/StupWizard';
|
||||
const { setInterval, clearInterval } = require('timers');
|
||||
dayjs.locale('zh-cn');
|
||||
type navListType = {
|
||||
title: string;
|
||||
|
|
@ -44,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;
|
||||
|
|
@ -66,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') {
|
||||
|
|
@ -125,10 +134,29 @@ const Home: React.FC = () => {
|
|||
)
|
||||
})}
|
||||
</div>
|
||||
<div className='drag'>
|
||||
<div>
|
||||
版本号:{version}
|
||||
<span>版本号:{version}</span>
|
||||
{update ? <span>new</span> : null}
|
||||
</div>
|
||||
{update ? <div>
|
||||
<Button type="primary" className='m-ant-btn' style={{ width: '100%' }} onClick={() => {
|
||||
window.electron.onDownload('3')
|
||||
}}>立即更新</Button>
|
||||
</div> : null}
|
||||
</div>
|
||||
<div>
|
||||
<Popover
|
||||
placement="right"
|
||||
content={
|
||||
<img style={{ width: '400px' }} src={`https://meeting-api.23544.com/meeting/update/ddq.png?t=${+new Date()}`} alt="" />
|
||||
}
|
||||
>
|
||||
<div className='drag' title='反馈建议'>
|
||||
<div></div>
|
||||
<span>反馈建议</span>
|
||||
</div>
|
||||
</Popover>
|
||||
<div className='drag' title='设置' onClick={() => {
|
||||
stupWizardRef.current.changeModal()
|
||||
}}>
|
||||
|
|
|
|||
|
|
@ -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,6 +346,15 @@ const Login: React.FC = () => {
|
|||
if (!anonInfo.nickName) {
|
||||
return message.error('请输入参会昵称!')
|
||||
}
|
||||
if (anonInfo.nickName.length > 10) {
|
||||
return message.error('参会昵称最多10个字!')
|
||||
}
|
||||
storage.setItem('loading', true)
|
||||
isVersion((bool: boolean) => {
|
||||
storage.setItem('loading', false)
|
||||
if (bool) {
|
||||
window.electron.onDownload('3')
|
||||
} else {
|
||||
storage.setItem('loading', true)
|
||||
PostAnonLogin(anonInfo).then(async (res) => {
|
||||
if (res.code == 200) {
|
||||
|
|
@ -357,6 +397,8 @@ const Login: React.FC = () => {
|
|||
}).catch(() => {
|
||||
storage.setItem('loading', false)
|
||||
})
|
||||
}
|
||||
})
|
||||
}}>进入</Button>
|
||||
</div>
|
||||
</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"
|
||||
|
|
@ -68,6 +71,7 @@ const NoticeWindow: React.FC = () => {
|
|||
</div>
|
||||
</div>,
|
||||
onClose: () => {
|
||||
setTimeout(() => {
|
||||
const dom = document.getElementsByClassName('ant-notification')
|
||||
if (dom.length === 0) {
|
||||
window.electron.setChildWindowShow({
|
||||
|
|
@ -75,6 +79,7 @@ const NoticeWindow: React.FC = () => {
|
|||
bool: false
|
||||
})
|
||||
}
|
||||
}, 500);
|
||||
},
|
||||
duration: 10,
|
||||
placement: 'bottomRight',
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ import styles from '@/page/Meeting/ShareScreenWindow/index.module.scss'
|
|||
import { storage } from '@/utils';
|
||||
import ImageUrl from '@/utils/package/imageUrl';
|
||||
import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons';
|
||||
import { RtcStats } from 'agora-electron-sdk';
|
||||
import { Button } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import { useEffect, useState } from "react";
|
||||
const { setInterval, clearInterval } = require('timers');
|
||||
const ShareScreenWindow: React.FC = () => {
|
||||
const [footerLists, setFooterLists] = useState<any>([
|
||||
{
|
||||
|
|
@ -49,11 +51,22 @@ const ShareScreenWindow: React.FC = () => {
|
|||
const [timeStr, setTimeStr] = useState(0)
|
||||
const [isExpand, setIsExpand] = useState(false)
|
||||
const [roomUserLists, setRoomUserLists] = useState<any>([])
|
||||
const [currentEffective, setCurrentEffective] = useState(3)
|
||||
const [networkOther, setNetworkOther] = useState<RtcStats>({})
|
||||
const [networkQuality, setNetworkQuality] = useState({
|
||||
level: '佳',
|
||||
text: '网络质量极好'
|
||||
})
|
||||
const channel = new BroadcastChannel('meeting_channel');
|
||||
const userInfo = JSON.parse(storage.getItem('user') as string)
|
||||
let timeout: NodeJS.Timeout;
|
||||
useEffect(() => {
|
||||
getRoomUser()
|
||||
if (!role.ID.includes(userInfo.roleId)) {
|
||||
setFooterLists((res: any) => {
|
||||
return res.splice(4, 1)
|
||||
})
|
||||
}
|
||||
channel.onmessage = function (event) {
|
||||
let { type, time } = event.data;
|
||||
switch (type) {
|
||||
|
|
@ -82,13 +95,20 @@ const ShareScreenWindow: React.FC = () => {
|
|||
footerListTemplate[0].active = data.parmes.footerList[0][0].active;
|
||||
footerListTemplate[1].title = data.parmes.footerList[0][1].active ? '开启视频' : '关闭视频';
|
||||
footerListTemplate[1].active = data.parmes.footerList[0][1].active;
|
||||
if (role.ID.includes(userInfo.roleId)) {
|
||||
footerListTemplate[4].title = data.parmes.footerList[1][3].active ? '录制中' : '录制';
|
||||
footerListTemplate[4].active = data.parmes.footerList[1][3].active;
|
||||
}
|
||||
setFooterLists(footerListTemplate)
|
||||
break;
|
||||
case 'roomUserList':
|
||||
setRoomUserLists(data.parmes.roomUserList)
|
||||
break;
|
||||
case 'nnetworkStatus':
|
||||
setCurrentEffective(data.parmes.currentEffective)
|
||||
setNetworkQuality(data.parmes.networkQuality)
|
||||
setNetworkOther(data.parmes.networkOther)
|
||||
break;
|
||||
}
|
||||
})
|
||||
return () => {
|
||||
|
|
@ -133,13 +153,19 @@ const ShareScreenWindow: React.FC = () => {
|
|||
<>
|
||||
<div className={styles.shareScreenWindow} style={{ width: isExpand ? '100%' : '100%' }}>
|
||||
<div className={styles.shareScreenWindowTitle}>
|
||||
<span>{changeCurrentSeconds(timeStr)} 共享中</span>
|
||||
{isExpand ? <span className='drag' onClick={() => {
|
||||
<span>{changeCurrentSeconds(timeStr)} {!isExpand ? '共享中' : ''}
|
||||
{networkIcon(currentEffective)}
|
||||
<span style={{ color: 'white', marginLeft: '30px' }}>
|
||||
{!isExpand ? <span style={{ marginRight: '10px' }}>网络质量:{networkQuality.level}</span> : ''}
|
||||
<span>延迟:{networkOther.lastmileDelay}ms</span>
|
||||
</span>
|
||||
</span>
|
||||
{isExpand ? <span className='drag' style={{ flexShrink: 0 }} onClick={() => {
|
||||
channel.postMessage({
|
||||
type: 'shareScreenWindowClose',
|
||||
shareScreenWindowClose: timeStr
|
||||
});
|
||||
}}>结束共享</span> : <span style={{ visibility: 'hidden' }}>结束共享</span>}
|
||||
}}>结束共享</span> : <span style={{ visibility: 'hidden', flexShrink: 0 }}>结束共享</span>}
|
||||
</div>
|
||||
{isExpand ? null : <div className={`${styles.shareScreenWindowContent} drag`}>
|
||||
<div className={styles.shareScreenWindowContentList}>
|
||||
|
|
@ -176,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>
|
||||
|
|
@ -197,7 +223,7 @@ const ShareScreenWindow: React.FC = () => {
|
|||
<div className={`${styles.shareScreenWindowExpand} drag`} onClick={() => {
|
||||
setIsExpand(!isExpand)
|
||||
window.electron.setChildWindow({
|
||||
width: isExpand ? 440 : 440 / 2,
|
||||
width: isExpand ? 440 : 440 / 1.6,
|
||||
key: 'shareScreenWindow',
|
||||
})
|
||||
}}>
|
||||
|
|
@ -209,4 +235,60 @@ const ShareScreenWindow: React.FC = () => {
|
|||
)
|
||||
}
|
||||
|
||||
const networkIcon = (network: number) => {
|
||||
switch (network) {
|
||||
case 0:
|
||||
return <svg width="33" height="32" viewBox="0 0 33 32" fill="none" xmlns="http://www.w3.org/2000/svg" className='drag' style={{ transform: 'scale(0.5)', position: 'absolute', top: '-4px' }}>
|
||||
<g clip-path="url(#clip0_21262_3609)">
|
||||
<path d="M4.44094 32C3.03695 32 1.90039 31.15 1.90039 30.1V15.3C1.90039 14.25 3.03695 13.4 4.44094 13.4C5.84492 13.4 6.98149 14.25 6.98149 15.3V30.1C6.98149 31.15 5.84492 32 4.44094 32ZM17.01 32C15.606 32 14.4694 31.15 14.4694 30.1V8.9C14.4694 7.85 15.606 7 17.01 7C18.4139 7 19.5505 7.85 19.5505 8.9V30.1C19.5505 31.15 18.4139 32 17.01 32ZM29.579 32C28.175 32 27.0384 31.15 27.0384 30.1V1.9C27.0384 0.85 28.175 0 29.579 0C30.983 0 32.1195 0.85 32.1195 1.9V30.1C32.1195 31.15 30.983 32 29.579 32Z" fill="#7C8280" />
|
||||
<path d="M7.00124 2.11509L5.01758 4.09875L3.03391 2.11509C2.77629 1.85747 2.35122 1.85747 2.0936 2.11509C1.83599 2.37271 1.83599 2.79778 2.0936 3.0554L4.07727 5.03906L2.0936 7.02273C1.83599 7.28035 1.83599 7.70542 2.0936 7.96304C2.35122 8.22065 2.77629 8.22065 3.03391 7.96304L5.01758 5.97937L7.00124 7.96304C7.25886 8.22065 7.68393 8.22065 7.94155 7.96304C8.19917 7.70542 8.19917 7.28035 7.94155 7.02273L5.95789 5.03906L7.94155 3.0554C8.19917 2.79778 8.19917 2.37271 7.94155 2.11509C7.68393 1.85747 7.25886 1.85747 7.00124 2.11509Z" fill="#F90000" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_21262_3609">
|
||||
<rect width="32" height="32" fill="white" transform="translate(0.119141)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
case 1:
|
||||
return <svg width="33" height="32" viewBox="0 0 33 32" fill="none" xmlns="http://www.w3.org/2000/svg" className='drag' style={{ transform: 'scale(0.5)', position: 'absolute', top: '-4px' }}>
|
||||
<g clip-path="url(#clip0_21262_3615)">
|
||||
<path d="M26.9316 30.1C26.9316 31.15 28.0918 32 29.5249 32C30.9581 32 32.1182 31.15 32.1182 30.1V1.9C32.1182 0.85 30.9581 0 29.5249 0C28.0918 0 26.9316 0.85 26.9316 1.9V30.1Z" fill="#7C8280" />
|
||||
<path d="M14.1035 30.1C14.1035 31.15 15.2637 32 16.6968 32C18.1299 32 19.2901 31.15 19.2901 30.1V8.9C19.2901 7.85 18.1299 7 16.6968 7C15.2637 7 14.1035 7.85 14.1035 8.9V30.1Z" fill="#7C8280" />
|
||||
<path d="M1.27344 30.1004C1.27344 31.1504 2.4336 32.0004 3.86673 32.0004C5.29986 32.0004 6.46002 31.1504 6.46002 30.1004V15.3004C6.46002 14.2504 5.29986 13.4004 3.86673 13.4004C2.4336 13.4004 1.27344 14.2504 1.27344 15.3004V30.1004Z" fill="#FF800B" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_21262_3615">
|
||||
<rect width="32" height="32" fill="white" transform="translate(0.119141)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
case 2:
|
||||
return <svg width="33" height="32" viewBox="0 0 33 32" fill="none" xmlns="http://www.w3.org/2000/svg" className='drag' style={{ transform: 'scale(0.5)', position: 'absolute', top: '-4px' }}>
|
||||
<g clip-path="url(#clip0_21262_3621)">
|
||||
<path d="M26.9316 30.1C26.9316 31.15 28.0918 32 29.5249 32C30.9581 32 32.1182 31.15 32.1182 30.1V1.9C32.1182 0.85 30.9581 0 29.5249 0C28.0918 0 26.9316 0.85 26.9316 1.9V30.1Z" fill="#7C8280" />
|
||||
<path d="M14.1035 30.1C14.1035 31.15 15.2637 32 16.6968 32C18.1299 32 19.2901 31.15 19.2901 30.1V8.9C19.2901 7.85 18.1299 7 16.6968 7C15.2637 7 14.1035 7.85 14.1035 8.9V30.1Z" fill="#FF800B" />
|
||||
<path d="M1.27344 30.1004C1.27344 31.1504 2.4336 32.0004 3.86673 32.0004C5.29986 32.0004 6.46002 31.1504 6.46002 30.1004V15.3004C6.46002 14.2504 5.29986 13.4004 3.86673 13.4004C2.4336 13.4004 1.27344 14.2504 1.27344 15.3004V30.1004Z" fill="#FF800B" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_21262_3621">
|
||||
<rect width="32" height="32" fill="white" transform="translate(0.119141)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
case 3:
|
||||
return <svg width="33" height="32" viewBox="0 0 33 32" fill="none" xmlns="http://www.w3.org/2000/svg" className='drag' style={{ transform: 'scale(0.5)', position: 'absolute', top: '-4px' }}>
|
||||
<g clip-path="url(#clip0_21262_3625)">
|
||||
<path d="M26.9316 30.1C26.9316 31.15 28.0918 32 29.5249 32C30.9581 32 32.1182 31.15 32.1182 30.1V1.9C32.1182 0.85 30.9581 0 29.5249 0C28.0918 0 26.9316 0.85 26.9316 1.9V30.1Z" fill="#02B188" />
|
||||
<path d="M14.1035 30.1C14.1035 31.15 15.2637 32 16.6968 32C18.1299 32 19.2901 31.15 19.2901 30.1V8.9C19.2901 7.85 18.1299 7 16.6968 7C15.2637 7 14.1035 7.85 14.1035 8.9V30.1Z" fill="#02B188" />
|
||||
<path d="M1.27344 30.1004C1.27344 31.1504 2.4336 32.0004 3.86673 32.0004C5.29986 32.0004 6.46002 31.1504 6.46002 30.1004V15.3004C6.46002 14.2504 5.29986 13.4004 3.86673 13.4004C2.4336 13.4004 1.27344 14.2504 1.27344 15.3004V30.1004Z" fill="#02B188" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_21262_3625">
|
||||
<rect width="32" height="32" fill="white" transform="translate(0.119141)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
}
|
||||
}
|
||||
|
||||
export default ShareScreenWindow
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import Avatar from '@/components/Avatar';
|
|||
import { useEffect, useState, useRef } from "react";
|
||||
import { storage } from '@/utils';
|
||||
import EquipmentManagement from '@/components/EquipmentManagement';
|
||||
import UserName from '@/components/UserName';
|
||||
const { confirm } = Modal;
|
||||
|
||||
const UserListWindow: React.FC = () => {
|
||||
|
|
@ -14,6 +15,7 @@ const UserListWindow: React.FC = () => {
|
|||
const [user, setUser] = useState<any>({});
|
||||
const [roomUserList, setRoomUserList] = useState<any>([])
|
||||
const equipmentManagementRef = useRef<any>();
|
||||
const userNameRef = useRef<any>();
|
||||
const channel = new BroadcastChannel('meeting_channel');
|
||||
const userInfo = JSON.parse(storage.getItem('user') as string)
|
||||
useEffect(() => {
|
||||
|
|
@ -149,6 +151,18 @@ const UserListWindow: React.FC = () => {
|
|||
});
|
||||
}}
|
||||
>移出会议</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
className='m-ant-btn'
|
||||
style={{ width: '100%', marginTop: '10px' }}
|
||||
size={'small'}
|
||||
onClick={() => {
|
||||
userNameRef.current.changeModal({
|
||||
userName: item.userName,
|
||||
uid: item.uid
|
||||
})
|
||||
}}
|
||||
>修改用户名</Button>
|
||||
</div>
|
||||
}>
|
||||
<EllipsisOutlined style={{
|
||||
|
|
@ -192,6 +206,7 @@ const UserListWindow: React.FC = () => {
|
|||
}}>全员静音</div>
|
||||
</div>
|
||||
</div>
|
||||
<UserName ref={userNameRef} />
|
||||
<EquipmentManagement ref={equipmentManagementRef} getDriver={(uid: string) => {
|
||||
channel.postMessage({
|
||||
type: 'userListWindowEquipmentManagement',
|
||||
|
|
|
|||
|
|
@ -232,6 +232,11 @@
|
|||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
#videoView {
|
||||
position: relative;
|
||||
border: 1px red solid;
|
||||
}
|
||||
|
||||
.standardModeIcon {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
|
|
@ -298,13 +303,17 @@
|
|||
|
||||
// 演讲者模式
|
||||
.meetingContentBodyLeftSpeakerMode {
|
||||
width: 18%;
|
||||
width: 270px;
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
|
||||
.meetingContentSwiperCard {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.meetingContentSwiperCard {
|
||||
height: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
// 单画面模式
|
||||
|
|
@ -370,7 +379,7 @@
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
height: 100% !important;
|
||||
width: calc(100% - 18%) !important;
|
||||
width: calc(100% - 270px) !important;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
|
@ -381,7 +390,7 @@
|
|||
|
||||
.meetingContentSwiperCard {
|
||||
height: 160px;
|
||||
width: calc(100% / 6);
|
||||
width: 270px;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
|
@ -427,6 +436,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
.meetingContentSwiperCaret {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
cursor: pointer;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
color: white;
|
||||
border: 1px white solid;
|
||||
font-size: 20px;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
.meetingContentBodyLeftBlock {
|
||||
position: absolute;
|
||||
background-color: #1F2022;
|
||||
|
|
@ -524,6 +549,8 @@
|
|||
font-size: 14px;
|
||||
color: #F3F3F5;
|
||||
margin-left: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
>div {
|
||||
|
|
@ -635,6 +662,8 @@
|
|||
font-size: 14px;
|
||||
color: #F3F3F5;
|
||||
margin-left: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -664,6 +693,8 @@
|
|||
>span {
|
||||
font-size: 14px;
|
||||
color: #F3F3F5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
>div {
|
||||
|
|
@ -773,7 +804,7 @@
|
|||
}
|
||||
|
||||
>img {
|
||||
height: 50px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
>span {
|
||||
|
|
@ -795,8 +826,8 @@
|
|||
}
|
||||
|
||||
>label {
|
||||
height: 50px;
|
||||
height: 50px;
|
||||
height: 35px;
|
||||
height: 35px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,12 +24,14 @@ 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;
|
||||
createChildWindow: (config: any) => void;
|
||||
createChildWindow: (str: string) => void;
|
||||
setChildWindow: (config: any) => void;
|
||||
setChildWindowShow: (config: any) => void;
|
||||
closeChildWindow: (key: string) => void;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
declare module 'react-dom/client';
|
||||
declare module 'crypto-js';
|
||||
declare module 'js-yaml';
|
||||
declare module 'uuid';
|
||||
|
|
@ -9,7 +9,6 @@ import {
|
|||
AudioAinsMode,
|
||||
SimulcastStreamMode,
|
||||
VideoStreamType,
|
||||
QualityType,
|
||||
RtcConnection,
|
||||
RtcStats,
|
||||
AudioVolumeInfo,
|
||||
|
|
@ -21,16 +20,18 @@ import {
|
|||
BeautyOptions,
|
||||
ColorEnhanceOptions,
|
||||
LowlightEnhanceOptions,
|
||||
VirtualBackgroundSource
|
||||
VirtualBackgroundSource,
|
||||
AudienceLatencyLevelType,
|
||||
StreamPublishState
|
||||
} from "agora-electron-sdk";
|
||||
import { GetRoomRtcToken, GetAgoraConf } from "@/api/Home/Index";
|
||||
import { storage } from '@/utils';
|
||||
import { role } from "@/config/role";
|
||||
import path from "path";
|
||||
const os = require("os");
|
||||
const option: any = {
|
||||
appId: '',
|
||||
token: '',
|
||||
tokenA: '',
|
||||
channelId: '',
|
||||
uid: '',
|
||||
screenShareId: '',
|
||||
|
|
@ -44,6 +45,7 @@ export const agora = {
|
|||
rtcEngine = createAgoraRtcEngine();
|
||||
await rtcEngine.initialize({
|
||||
appId: data,
|
||||
logConfig: { filePath: path.resolve(os.homedir(), "./agorasdk.log") }
|
||||
});
|
||||
if (bool) {
|
||||
await agora.setDeviceManager()
|
||||
|
|
@ -123,7 +125,8 @@ 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.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, {
|
||||
|
|
@ -140,6 +143,7 @@ export const agora = {
|
|||
color: Number(settingData.virtualBackground.color),
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, {
|
||||
background_source_type: 1,
|
||||
|
|
@ -150,7 +154,7 @@ export const agora = {
|
|||
}, 1000);
|
||||
},
|
||||
// 事件回调
|
||||
registerEventHandler: ({ onJoinChannelSuccess, onUserJoined, onUserOffline, onAudioVolumeIndication, onNetworkQuality, onRtcStats, onConnectionStateChanged, onLocalVideoStateChanged, onConnectionLost }: any) => {
|
||||
registerEventHandler: ({ onJoinChannelSuccess, onUserJoined, onUserOffline, onAudioVolumeIndication, onRtcStats, onConnectionStateChanged, onLocalVideoStateChanged, onConnectionLost, onTokenPrivilegeWillExpire, onActiveSpeaker, onVideoPublishStateChanged, onAudioPublishStateChanged }: any) => {
|
||||
rtcEngine.registerEventHandler({
|
||||
// 监听本地用户加入频道事件
|
||||
onJoinChannelSuccess: async (connection: RtcConnection, elapsed: number) => {
|
||||
|
|
@ -165,25 +169,17 @@ 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)
|
||||
},
|
||||
//通话中每个用户的网络上下行 last mile 质量报告回调。
|
||||
onNetworkQuality: async (connection: RtcConnection, remoteUid: number, txQuality: QualityType, rxQuality: QualityType) => {
|
||||
await onNetworkQuality?.(connection, remoteUid, txQuality, rxQuality)
|
||||
},
|
||||
//当前通话相关的统计信息回调。
|
||||
onRtcStats: async (_connection: RtcConnection, stats: RtcStats) => {
|
||||
await onRtcStats?.(stats)
|
||||
|
|
@ -199,9 +195,26 @@ export const agora = {
|
|||
// 网络连接中断,且 SDK 无法在 10 秒内连接服务器回调。
|
||||
onConnectionLost: (_connection: RtcConnection) => {
|
||||
onConnectionLost?.()
|
||||
},
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 刷新token
|
||||
refreshToken: async (data: any) => {
|
||||
await rtcEngine.updateChannelMediaOptionsEx({
|
||||
token: data.token,
|
||||
}, data.connection);
|
||||
},
|
||||
// 获取视图模式
|
||||
getRrenderMode: (uid: number) => {
|
||||
if (String(uid).length === 9) {
|
||||
|
|
@ -213,8 +226,11 @@ export const agora = {
|
|||
// 本地加入
|
||||
setupLocalVideo: async (item: any) => {
|
||||
if (item.view?.childNodes.length === 1 || item.type) {
|
||||
if (String(item.uid).length === 9) {
|
||||
return
|
||||
}
|
||||
await rtcEngine.setupLocalVideo({
|
||||
renderMode: agora.getRrenderMode(item.uid),
|
||||
renderMode: item.renderMode || agora.getRrenderMode(item.uid),
|
||||
sourceType: item.sourceType,
|
||||
uid: item.uid,
|
||||
view: item.view,
|
||||
|
|
@ -227,7 +243,7 @@ export const agora = {
|
|||
if (item.view?.childNodes.length === 1) {
|
||||
await rtcEngine.setupRemoteVideo(
|
||||
{
|
||||
renderMode: agora.getRrenderMode(item.uid),
|
||||
renderMode: item.renderMode || agora.getRrenderMode(item.uid),
|
||||
sourceType: VideoSourceType.VideoSourceRemote,
|
||||
uid: item.uid,
|
||||
view: item.view,
|
||||
|
|
@ -241,7 +257,7 @@ export const agora = {
|
|||
if (item.view?.childNodes.length === 1) {
|
||||
await rtcEngine.setupRemoteVideoEx(
|
||||
{
|
||||
renderMode: agora.getRrenderMode(item.uid),
|
||||
renderMode: item.renderMode || agora.getRrenderMode(item.uid),
|
||||
sourceType: VideoSourceType.VideoSourceRemote,
|
||||
uid: item.uid,
|
||||
view: item.view,
|
||||
|
|
@ -255,7 +271,7 @@ export const agora = {
|
|||
setupRemoteVideo: async (item: any) => {
|
||||
await rtcEngine.setupRemoteVideo(
|
||||
{
|
||||
renderMode: agora.getRrenderMode(item.uid),
|
||||
renderMode: item.renderMode || agora.getRrenderMode(item.uid),
|
||||
sourceType: VideoSourceType.VideoSourceRemote,
|
||||
uid: item.uid,
|
||||
view: item.view,
|
||||
|
|
@ -279,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,
|
||||
|
|
@ -292,6 +308,7 @@ export const agora = {
|
|||
},
|
||||
{ channelId: option.channelId, localUid: Number(option.uid) }
|
||||
);
|
||||
await rtcEngine.setAudioScenario(8)
|
||||
},
|
||||
// 更新频道配置
|
||||
updateChannelMediaOptions: async (bool: boolean) => {
|
||||
|
|
@ -302,6 +319,7 @@ export const agora = {
|
|||
publishMicrophoneTrack: true,//设置是否发布麦克风采集到的音频
|
||||
publishCameraTrack: true,//设置是否发布摄像头采集的视频
|
||||
publishScreenTrack: false,//设置是否发布屏幕采集的视频
|
||||
audienceLatencyLevel: bool ? AudienceLatencyLevelType.AudienceLatencyLevelUltraLowLatency : AudienceLatencyLevelType.AudienceLatencyLevelLowLatency,
|
||||
})
|
||||
},
|
||||
// 设置接收大小流
|
||||
|
|
@ -313,10 +331,10 @@ export const agora = {
|
|||
)
|
||||
},
|
||||
// 共享屏幕单独用户
|
||||
joinChannelEx: async (uid: any) => {
|
||||
joinChannelEx: async (uid: any, token: string) => {
|
||||
await agora.leaveChannelEx(uid)
|
||||
await rtcEngine.joinChannelEx(
|
||||
option.token,
|
||||
token,
|
||||
{ channelId: option.channelId, localUid: Number(uid) },
|
||||
{
|
||||
autoSubscribeAudio: false,//设置是否自动订阅所有音频流
|
||||
|
|
@ -329,11 +347,11 @@ export const agora = {
|
|||
);
|
||||
},
|
||||
// 所有用户加入的第二个房间
|
||||
allJoinChannelEx: async (bool: boolean = false) => {
|
||||
allJoinChannelEx: async (bool: boolean = false, token: string) => {
|
||||
const user = await JSON.parse(storage.getItem('user') as string)
|
||||
await agora.startCameraCapture(true)
|
||||
await rtcEngine.joinChannelEx(
|
||||
option.tokenA,
|
||||
token,
|
||||
{ channelId: option.channelId + 'a', localUid: Number('1' + option.screenShareId) },
|
||||
{
|
||||
clientRoleType: bool ? ClientRoleType.ClientRoleAudience : ClientRoleType.ClientRoleBroadcaster, //用户角色 ClientRoleBroadcaster 主播 ClientRoleAudience 观众
|
||||
|
|
@ -342,6 +360,7 @@ export const agora = {
|
|||
publishMicrophoneTrack: false,//设置是否发布麦克风采集到的音频
|
||||
publishCameraTrack: true,//设置是否发布摄像头采集的视频
|
||||
publishScreenTrack: false,//设置是否发布屏幕采集的视频
|
||||
audienceLatencyLevel: bool ? AudienceLatencyLevelType.AudienceLatencyLevelLowLatency : AudienceLatencyLevelType.AudienceLatencyLevelUltraLowLatency,
|
||||
}
|
||||
);
|
||||
await rtcEngine.setDualStreamModeEx(
|
||||
|
|
@ -358,20 +377,33 @@ export const agora = {
|
|||
},
|
||||
// 退出第二个房间
|
||||
allLeaveChannelEx: async () => {
|
||||
await agora.stopCameraCapture();
|
||||
await rtcEngine.leaveChannelEx({ channelId: option.channelId + 'a', localUid: Number('1' + option.screenShareId) })
|
||||
},
|
||||
// 停止/恢复接收指定的视频流。
|
||||
muteRemoteVideoStreamEx: async (uid: number, mute: boolean) => {
|
||||
await rtcEngine.muteRemoteVideoStreamEx(uid, mute, { channelId: option.channelId, localUid: Number(option.uid) })
|
||||
},
|
||||
// 设置视频订阅黑名单。
|
||||
setSubscribeVideoBlocklist: async (uidList: number[], uidNumber: number) => {
|
||||
await rtcEngine.setSubscribeVideoBlocklist(uidList, uidNumber)
|
||||
},
|
||||
// 取消或恢复订阅指定远端用户的音频流
|
||||
muteRemoteVideoStream: async (uid: number, mute: boolean) => {
|
||||
rtcEngine.muteRemoteVideoStream(uid, mute)
|
||||
},
|
||||
// 销毁视频渲染dom
|
||||
destroyRendererByConfig: async (uid: number, channelId?: string) => {
|
||||
await rtcEngine.destroyRendererByConfig(VideoSourceType.VideoSourceRemote, channelId, uid);
|
||||
await rtcEngine.destroyRendererByConfig(option.uid === uid ? VideoSourceType.VideoSourceCameraPrimary : VideoSourceType.VideoSourceRemote, channelId, uid);
|
||||
},
|
||||
destroyRendererByConfigPreview: async (uid: number, channelId: number) => {
|
||||
await agora.destroyRendererByView('videoPreview')
|
||||
await rtcEngine.leaveChannelEx({ channelId: `${channelId + uid}`, localUid: Number(uid) })
|
||||
},
|
||||
destroyRendererByView: async (key: string) => {
|
||||
let dom = document.getElementById(key);
|
||||
if (dom) {
|
||||
await rtcEngine.destroyRendererByView(dom);
|
||||
}
|
||||
},
|
||||
// ai降噪
|
||||
setAINSMode: async (enabled: boolean, mode: AudioAinsMode) => {
|
||||
|
|
@ -396,6 +428,7 @@ export const agora = {
|
|||
publishMicrophoneTrack: publishMicrophoneTrack,//设置是否发布麦克风采集到的音频
|
||||
publishCameraTrack: publishCameraTrack,//设置是否发布摄像头采集的视频
|
||||
publishScreenTrack: false,//设置是否发布屏幕采集的视频
|
||||
audienceLatencyLevel: data ? AudienceLatencyLevelType.AudienceLatencyLevelUltraLowLatency : AudienceLatencyLevelType.AudienceLatencyLevelLowLatency,
|
||||
})
|
||||
},
|
||||
// 取消或恢复发布本地视频流
|
||||
|
|
@ -408,26 +441,26 @@ export const agora = {
|
|||
publishMicrophoneTrack: publishMicrophoneTrack,//设置是否发布麦克风采集到的音频
|
||||
publishCameraTrack: publishCameraTrack,//设置是否发布摄像头采集的视频
|
||||
publishScreenTrack: false,//设置是否发布屏幕采集的视频
|
||||
audienceLatencyLevel: data ? AudienceLatencyLevelType.AudienceLatencyLevelUltraLowLatency : AudienceLatencyLevelType.AudienceLatencyLevelLowLatency,
|
||||
})
|
||||
},
|
||||
// 摄像头采集
|
||||
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,
|
||||
}
|
||||
})
|
||||
},
|
||||
// 停止采集摄像头
|
||||
stopCameraCapture: async () => {
|
||||
await rtcEngine.stopCameraCapture()
|
||||
await rtcEngine.stopCameraCapture(VideoSourceType.VideoSourceCamera)
|
||||
},
|
||||
// 加入频道
|
||||
setJoinChannel: async (data: any) => {
|
||||
option.token = data.token;
|
||||
option.tokenA = data.tokenA;
|
||||
option.channelId = data.channelId;
|
||||
option.uid = Number(data.uid);
|
||||
option.screenShareId = data.screenShareId;
|
||||
|
|
@ -438,7 +471,7 @@ export const agora = {
|
|||
return await rtcEngine.getScreenCaptureSources(thumbSize, iconSize, includeScreen)
|
||||
},
|
||||
// 共享屏幕采集
|
||||
setDesktopCapturerVideo: async (targetSource: any, isComputerAudio: boolean, isFluencyPriority: boolean) => {
|
||||
setDesktopCapturerVideo: async (targetSource: any, isComputerAudio: boolean, isFluencyPriority: boolean, token: string) => {
|
||||
const user = JSON.parse(storage.getItem('user') as string)
|
||||
agora.stopScreenCapture();
|
||||
if (isComputerAudio) {
|
||||
|
|
@ -446,7 +479,7 @@ export const agora = {
|
|||
}
|
||||
|
||||
let data = {
|
||||
frameRate: isFluencyPriority ? 30 : 15,
|
||||
frameRate: isFluencyPriority ? 15 : 7,
|
||||
dimensions: {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
|
|
@ -474,7 +507,7 @@ export const agora = {
|
|||
}
|
||||
);
|
||||
}
|
||||
await agora.joinChannelEx(user.screenShareId)
|
||||
await agora.joinChannelEx(user.screenShareId, token)
|
||||
},
|
||||
// 获取系统中所有的视频设备列表。
|
||||
getVideoDeviceManager: async (): Promise<any> => {
|
||||
|
|
@ -488,12 +521,12 @@ export const agora = {
|
|||
await rtcEngine.getVideoDeviceManager().setDevice(deviceIdUTF8)
|
||||
},
|
||||
// 开启本地视频预览
|
||||
startPreview: async (id: string, uid: number): Promise<void> => {
|
||||
startPreview: async (id: string, uid: number, channelId: number): Promise<void> => {
|
||||
rtcEngine.enableVideo();
|
||||
rtcEngine.startPreview();
|
||||
await GetRoomRtcToken(`${+new Date()}`).then(async (res) => {
|
||||
await GetRoomRtcToken(`${channelId + uid}`).then(async (res) => {
|
||||
await rtcEngine.joinChannelEx(res.data, {
|
||||
channelId: `${+new Date() + uid}`,
|
||||
channelId: `${channelId + uid}`,
|
||||
localUid: uid,
|
||||
}, {
|
||||
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting,
|
||||
|
|
|
|||
|
|
@ -82,6 +82,10 @@ import virtualBackground6 from '@/assets/virtualBackground/6.png'
|
|||
import icon52 from '@/assets/icon52.png'
|
||||
import icon52Select from '@/assets/icon52-select.png'
|
||||
import icon53 from '@/assets/icon53.png'
|
||||
import icon54 from '@/assets/icon54.png'
|
||||
import icon55 from '@/assets/icon55.png'
|
||||
import icon56 from '@/assets/icon56.png'
|
||||
import icon56Active from '@/assets/icon56-active.png'
|
||||
export default {
|
||||
loading,
|
||||
icon,
|
||||
|
|
@ -166,5 +170,9 @@ export default {
|
|||
virtualBackground6,
|
||||
icon52,
|
||||
icon52Select,
|
||||
icon53
|
||||
icon53,
|
||||
icon54,
|
||||
icon55,
|
||||
icon56,
|
||||
icon56Active
|
||||
}
|
||||
|
|
@ -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,12 +77,25 @@ class Request {
|
|||
case 403:
|
||||
updatePostRefresh()
|
||||
break
|
||||
case 502:
|
||||
message.error('网络已断开,请检查网络状态')
|
||||
break
|
||||
default:
|
||||
message.error(err.message)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (err.code) {
|
||||
case "ECONNABORTED":
|
||||
message.error('网络连接超时,请检查网络状态')
|
||||
break;
|
||||
case "ERR_NETWORK":
|
||||
message.error('网络已断开,请检查网络状态')
|
||||
break;
|
||||
default:
|
||||
message.error(err.message)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -405,3 +405,16 @@ $pagination-hover-background-color: #5575F2;
|
|||
.ant-tabs {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.ant-rate .ant-rate-star-first,
|
||||
.ant-rate .ant-rate-star-second {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.hideCancelText {
|
||||
.ant-modal-confirm-btns {
|
||||
>button:nth-child(1){
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,7 +64,6 @@ export default defineConfig({
|
|||
AudioAinsMode,
|
||||
SimulcastStreamMode,
|
||||
VideoStreamType,
|
||||
QualityType,
|
||||
RtcConnection,
|
||||
RtcStats,
|
||||
AudioVolumeInfo,
|
||||
|
|
@ -76,7 +75,10 @@ export default defineConfig({
|
|||
BeautyOptions,
|
||||
ColorEnhanceOptions,
|
||||
LowlightEnhanceOptions,
|
||||
VirtualBackgroundSource
|
||||
VirtualBackgroundSource,
|
||||
AudienceLatencyLevelType,
|
||||
StreamPublishState,
|
||||
IMediaEngine
|
||||
} = require("agora-electron-sdk")
|
||||
export {
|
||||
createAgoraRtcEngine,
|
||||
|
|
@ -89,7 +91,6 @@ export default defineConfig({
|
|||
AudioAinsMode,
|
||||
SimulcastStreamMode,
|
||||
VideoStreamType,
|
||||
QualityType,
|
||||
RtcConnection,
|
||||
RtcStats,
|
||||
AudioVolumeInfo,
|
||||
|
|
@ -101,7 +102,10 @@ export default defineConfig({
|
|||
BeautyOptions,
|
||||
ColorEnhanceOptions,
|
||||
LowlightEnhanceOptions,
|
||||
VirtualBackgroundSource
|
||||
VirtualBackgroundSource,
|
||||
AudienceLatencyLevelType,
|
||||
StreamPublishState,
|
||||
IMediaEngine
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
|
|
|||