diff --git a/main.js b/main.js
index c942700..a611d85 100644
--- a/main.js
+++ b/main.js
@@ -10,6 +10,7 @@ const {
dialog,
crashReporter,
desktopCapturer,
+ powerSaveBlocker,
} = require('electron');
const path = require('node:path')
const updateJs = require('./src/utils/package/update')
@@ -28,6 +29,10 @@ 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) {
@@ -49,7 +54,11 @@ class AppWindow extends BrowserWindow {
super(finalConfig);
if (env === 'development') {
// 开发
- this.loadURL('http://localhost:3000');
+ if (buildStatus) {
+ this.loadFile(path.resolve(__dirname, './dist/index.html'));
+ } else {
+ this.loadURL('http://localhost:3000');
+ }
} else {
// 测试 | 生产
this.loadFile(path.resolve(__dirname, './dist/index.html'));
@@ -62,33 +71,12 @@ class AppWindow extends BrowserWindow {
function quit() {
app.quit()
}
-
+let tray;
function createTray() {
const iconPath = `${__dirname}/src/assets/${updateJs.getIcon(envStr)}.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 = new Tray(trayIcon);
tray.setToolTip(updateJs.getTitle(envStr));
- tray.setContextMenu(contextMenu);
tray.on('click', () => {
mainWindow.webContents.send('isOpenWindows');
});
@@ -97,6 +85,13 @@ 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', () => {
@@ -136,6 +131,12 @@ app.on('ready', () => {
mainWindow.webContents.openDevTools()
}
});
+ mainWindow.on('focus', () => {
+ mainWindow.show()
+ });
+ mainWindow.on('maximize', () => {
+ mainWindow.show()
+ });
// 监听移动
mainWindow.on('move', () => {
// 如果是全屏自动恢复到上次窗口大小
@@ -182,6 +183,8 @@ app.on('ready', () => {
connection.off('SetDriver');
connection.off('ShowDriverList');
connection.off('ModifyNickName');
+ connection.off('JoinChannelCallback');
+ connection.off('ExitSharedScreen');
}
});
ipcMain.handle('onStop', (event) => {
@@ -201,7 +204,6 @@ app.on('ready', () => {
await connection.invoke(str, data.roomNum, data.msg)
break;
case 'sendOper':
- // 4:屏幕共享
await connection.invoke(str, data.roomNum, data.type)
break;
case 'getDrivers':
@@ -217,11 +219,11 @@ 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;
}
@@ -379,6 +381,19 @@ app.on('ready', () => {
nickName
})
});
+ // 加入房间回调
+ connection.on("JoinChannelCallback", (isSuccess) => {
+ mainWindow.webContents.send('onSignalr', {
+ key: 'JoinChannelCallback',
+ isSuccess,
+ })
+ });
+ // 退出共享
+ connection.on("ExitSharedScreen", () => {
+ mainWindow.webContents.send('onSignalr', {
+ key: 'ExitSharedScreen'
+ })
+ });
}
});
// 放大缩小退出窗口
@@ -489,9 +504,32 @@ 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);
@@ -551,11 +589,22 @@ app.on('ready', () => {
})
if (envStr === 'development') {
// 开发
- child.loadURL(config.url)
+ if (buildStatus) {
+ 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.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) {
diff --git a/package.json b/package.json
index ce35f53..98dada8 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "WGShare.Metting",
"private": true,
- "version": "0.6.3",
+ "version": "0.6.5",
"main": "main.js",
"authors": "yj",
"description": "智汇享",
diff --git a/src/api/Home/Index/index.ts b/src/api/Home/Index/index.ts
index d18265e..8756a7d 100644
--- a/src/api/Home/Index/index.ts
+++ b/src/api/Home/Index/index.ts
@@ -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`,
diff --git a/src/api/Meeting/index.ts b/src/api/Meeting/index.ts
index 22db4c8..6bf6328 100644
--- a/src/api/Meeting/index.ts
+++ b/src/api/Meeting/index.ts
@@ -154,4 +154,14 @@ export const PutAlterUname = (data: any) =>
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'
})
\ No newline at end of file
diff --git a/src/assets/icon56-active.png b/src/assets/icon56-active.png
new file mode 100644
index 0000000..8e637e8
Binary files /dev/null and b/src/assets/icon56-active.png differ
diff --git a/src/assets/icon56.png b/src/assets/icon56.png
new file mode 100644
index 0000000..3bd9904
Binary files /dev/null and b/src/assets/icon56.png differ
diff --git a/src/components/FeedBackModel/index.module.scss b/src/components/FeedBackModel/index.module.scss
new file mode 100644
index 0000000..689f213
--- /dev/null
+++ b/src/components/FeedBackModel/index.module.scss
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/components/FeedBackModel/index.tsx b/src/components/FeedBackModel/index.tsx
new file mode 100644
index 0000000..f46997a
--- /dev/null
+++ b/src/components/FeedBackModel/index.tsx
@@ -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 } 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 (
+ <>
+ setIsFeedBackModel(false)}
+ centered
+ width={'500px'}
+ >
+
+
+
+
评分:
+
+ {
+ setFeedBackForm({
+ ...feedBackForm,
+ rateValue: e
+ })
+ }} />
+
+
+
+
建议:
+
+ {
+ feedBackList.map((item, index) => {
+ return (
+
{
+ const feedBackListTemp = [...feedBackList]
+ feedBackListTemp[index].active = !feedBackListTemp[index].active
+ setFeedBackList(feedBackListTemp)
+ }}>
+ {item.text}
+
+ )
+ })
+ }
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+})
+
+export default FeedBackModel
\ No newline at end of file
diff --git a/src/components/JoinSetting/index.tsx b/src/components/JoinSetting/index.tsx
index e8be5b5..a3a6f93 100644
--- a/src/components/JoinSetting/index.tsx
+++ b/src/components/JoinSetting/index.tsx
@@ -170,7 +170,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 {
diff --git a/src/components/StupWizard/index.tsx b/src/components/StupWizard/index.tsx
index 55dde8c..06e17de 100644
--- a/src/components/StupWizard/index.tsx
+++ b/src/components/StupWizard/index.tsx
@@ -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) => {
@@ -84,6 +85,8 @@ const StupWizard = forwardRef((_props: any, ref: any) => {
{list.map((row: any, index: number) => {
return (
{
+ 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 +109,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)
}}
/>
@@ -247,7 +252,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 +310,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))
diff --git a/src/page/Home/Index/index.tsx b/src/page/Home/Index/index.tsx
index 270763b..a745085 100644
--- a/src/page/Home/Index/index.tsx
+++ b/src/page/Home/Index/index.tsx
@@ -8,11 +8,12 @@ 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';
const { setInterval, clearInterval } = require('timers');
const fs = require('fs').promises;
const { exec } = require('child_process');
@@ -20,6 +21,7 @@ const { RangePicker } = DatePicker;
const { confirm } = Modal;
const Index: React.FC = () => {
const navigate = useNavigate();
+ const { state } = useLocation();
const [list, setList] = useState({
data: [],
total: 0,
@@ -37,6 +39,7 @@ const Index: React.FC = () => {
})
const joinSettingRef = useRef
();
const stupWizardRef = useRef();
+ const feedBackModelRef = useRef();
const [user, setUser] = useState({});
const [currentRoomInfo, setCurrentRoomInfo] = useState({});
const [subjectList, setSubjectList] = useState([]);
@@ -47,6 +50,9 @@ const Index: React.FC = () => {
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
@@ -551,6 +557,7 @@ const Index: React.FC = () => {
+
>
)
}
diff --git a/src/page/Home/index.module.scss b/src/page/Home/index.module.scss
index 86d1f6e..db9972a 100644
--- a/src/page/Home/index.module.scss
+++ b/src/page/Home/index.module.scss
@@ -130,7 +130,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 +144,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 +165,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;
}
}
diff --git a/src/page/Home/index.tsx b/src/page/Home/index.tsx
index 04f99fb..b31ed27 100644
--- a/src/page/Home/index.tsx
+++ b/src/page/Home/index.tsx
@@ -1,7 +1,7 @@
import styles from '@/page/Home/index.module.scss'
import { useEffect, useState, useRef } from "react";
import { Outlet, useNavigate } from 'react-router-dom';
-import { Popconfirm } from 'antd';
+import { Popconfirm, Popover } from 'antd';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn'
import { storage } from '@/utils';
@@ -130,6 +130,17 @@ const Home: React.FC = () => {
版本号:{version}
+
+ }
+ >
+
+
{
stupWizardRef.current.changeModal()
}}>
diff --git a/src/page/Meeting/NoticeWindow/index.tsx b/src/page/Meeting/NoticeWindow/index.tsx
index d1be2a7..6a00b7b 100644
--- a/src/page/Meeting/NoticeWindow/index.tsx
+++ b/src/page/Meeting/NoticeWindow/index.tsx
@@ -68,13 +68,15 @@ const NoticeWindow: React.FC = () => {
,
onClose: () => {
- const dom = document.getElementsByClassName('ant-notification')
- if (dom.length === 0) {
- window.electron.setChildWindowShow({
- key: 'noticeWindow',
- bool: false
- })
- }
+ setTimeout(() => {
+ const dom = document.getElementsByClassName('ant-notification')
+ if (dom.length === 0) {
+ window.electron.setChildWindowShow({
+ key: 'noticeWindow',
+ bool: false
+ })
+ }
+ }, 500);
},
duration: 10,
placement: 'bottomRight',
diff --git a/src/page/Meeting/ShareScreenWindow/index.tsx b/src/page/Meeting/ShareScreenWindow/index.tsx
index 772f6b2..25984a4 100644
--- a/src/page/Meeting/ShareScreenWindow/index.tsx
+++ b/src/page/Meeting/ShareScreenWindow/index.tsx
@@ -4,6 +4,7 @@ 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";
@@ -50,6 +51,12 @@ const ShareScreenWindow: React.FC = () => {
const [timeStr, setTimeStr] = useState(0)
const [isExpand, setIsExpand] = useState(false)
const [roomUserLists, setRoomUserLists] = useState([])
+ const [currentEffective, setCurrentEffective] = useState(3)
+ const [networkOther, setNetworkOther] = useState({})
+ 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;
@@ -97,6 +104,11 @@ const ShareScreenWindow: React.FC = () => {
case 'roomUserList':
setRoomUserLists(data.parmes.roomUserList)
break;
+ case 'nnetworkStatus':
+ setCurrentEffective(data.parmes.currentEffective)
+ setNetworkQuality(data.parmes.networkQuality)
+ setNetworkOther(data.parmes.networkOther)
+ break;
}
})
return () => {
@@ -141,13 +153,19 @@ const ShareScreenWindow: React.FC = () => {
<>
- {changeCurrentSeconds(timeStr)} 共享中
- {isExpand ? {
+ {changeCurrentSeconds(timeStr)} 共享中
+ {networkIcon(currentEffective)}
+
+ 网络质量:{networkQuality.level}
+ 延迟:{networkOther.lastmileDelay}ms
+
+
+ {isExpand ? {
channel.postMessage({
type: 'shareScreenWindowClose',
shareScreenWindowClose: timeStr
});
- }}>结束共享 : 结束共享}
+ }}>结束共享 : 结束共享}
{isExpand ? null :
@@ -217,4 +235,60 @@ const ShareScreenWindow: React.FC = () => {
)
}
+const networkIcon = (network: number) => {
+ switch (network) {
+ case 0:
+ return
+ case 1:
+ return
+ case 2:
+ return
+ case 3:
+ return
+ }
+}
+
export default ShareScreenWindow
diff --git a/src/page/Meeting/index.module.scss b/src/page/Meeting/index.module.scss
index 7a75217..f3a07c0 100644
--- a/src/page/Meeting/index.module.scss
+++ b/src/page/Meeting/index.module.scss
@@ -232,6 +232,11 @@
position: relative;
overflow: hidden;
+ #videoView {
+ position: relative;
+ border: 1px red solid;
+ }
+
.standardModeIcon {
position: absolute;
left: 50%;
@@ -305,6 +310,10 @@
.meetingContentSwiperCard {
width: 100%;
}
+
+ .meetingContentSwiperCard {
+ height: calc(100% / 6);
+ }
}
// 单画面模式
@@ -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: 30px;
+ height: 30px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+
.meetingContentBodyLeftBlock {
position: absolute;
background-color: #1F2022;
diff --git a/src/page/Meeting/index.tsx b/src/page/Meeting/index.tsx
index 7f2103e..278e590 100644
--- a/src/page/Meeting/index.tsx
+++ b/src/page/Meeting/index.tsx
@@ -4,16 +4,16 @@ import Operation from '@/components/Operation';
import SpeakerModeModal from '@/components/SpeakerModeModal';
import InvitingPersonnelModal from '@/components/InvitingPersonnelModal';
import { Button, Input, Popover, Modal, Checkbox, message, Popconfirm, notification } from "antd";
-import { SearchOutlined, EllipsisOutlined, ExclamationCircleFilled, FullscreenExitOutlined, FullscreenOutlined, QuestionCircleOutlined } from '@ant-design/icons';
+import { SearchOutlined, EllipsisOutlined, ExclamationCircleFilled, FullscreenExitOutlined, FullscreenOutlined, QuestionCircleOutlined, CaretLeftOutlined, CaretRightOutlined, CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons';
import { useLocation, useNavigate } from 'react-router-dom';
import { thumbImageBufferToBase64 } from '@/utils/package/base64'
import { storage } from '@/utils';
-import { GetRoomUser, PostOpenMicr, PostOpenCamera, GetLeaveAll, PostRoomManager, DeleteRoomManager, GetRoomKickout, GetShowUser, PostShowUser, PostMuteAll, GetRoomUserItem, GetApplySpeak } from '@/api/Meeting';
+import { GetRoomUser, PostOpenMicr, PostOpenCamera, GetLeaveAll, PostRoomManager, DeleteRoomManager, GetRoomKickout, GetShowUser, PostShowUser, PostMuteAll, GetRoomUserItem, GetApplySpeak, PostSharedScreen } from '@/api/Meeting';
import ImageUrl from '@/utils/package/imageUrl'
import { agora } from '@/utils/package/agora'
import dayjs from 'dayjs';
import durationPlugin from 'dayjs/plugin/duration';
-import { AudioVolumeInfo, ConnectionChangedReasonType, ConnectionStateType, LocalVideoStreamReason, LocalVideoStreamState, QualityType, RtcConnection, RtcStats, UserOfflineReasonType, VideoSourceType, VideoStreamType } from 'agora-electron-sdk';
+import { AudioVolumeInfo, ConnectionChangedReasonType, ConnectionStateType, LocalVideoStreamReason, LocalVideoStreamState, RenderModeType, RtcConnection, RtcStats, UserOfflineReasonType, VideoSourceType, VideoStreamType } from 'agora-electron-sdk';
import Avatar from '@/components/Avatar';
import SharedFilesModel from '@/components/SharedFilesModel';
import StupWizard from '@/components/StupWizard';
@@ -25,6 +25,7 @@ import { getKeyOpenChildWindow, setKeyOpenChildWindow } from '@/utils/package/pu
import MeetingDisconnected from '@/components/MeetingDisconnected';
import SingIn from '@/components/SingIn';
import UserName from '@/components/UserName';
+import { GetRoomRtcToken } from '@/api/Home/Index';
const { setTimeout, setInterval, clearTimeout, clearInterval } = require('timers');
const { confirm } = Modal;
const { exec } = require('child_process');
@@ -163,17 +164,20 @@ const Meeting: React.FC = () => {
const [chatList, setChatList] = useState
([])
const [isExpand, setIsExpand] = useState(false)
const [currentVideoId, setCurrentVideoId] = useState('')
+ const [currentVideoUid, setCurrentVideoUid] = useState('')
let [currentSeconds, setCurrentSeconds] = useState(0)
- const [currentEffective, setCurrentEffective] = useState(4)
+ const [isNetworkQuality, setIsNetworkQuality] = useState(false)
+ const [currentEffective, setCurrentEffective] = useState(3)
const [networkQuality, setNetworkQuality] = useState({
level: '佳',
- text: '网络质量极好。'
+ text: '网络质量极好'
})
const [networkOther, setNetworkOther] = useState({})
const [isComputerAudio, setIsComputerAudio] = useState(false)
const [_isLeave, setIsLeave] = useState(false)
const [isScreenCapture, setIsScreenCapture] = useState(false)
const [isFluencyPriority, setIsFluencyPriority] = useState(false)
+ const [isClickLock, setIsClickLock] = useState(false)
const [open, setOpen] = useState(false)
const [modeOpen, setModeOpen] = useState(false)
const [meetingMode, setMeetingMode] = useState('')
@@ -181,14 +185,19 @@ const Meeting: React.FC = () => {
const [noViewChatList, setNoViewChatList] = useState(0)
const [currentLookUserAccount, setCurrentLookUserAccount] = useState('')
const [recorder, setRecorder] = useState('')
+ const [contextMenu, setContextMenu] = useState('')
+ const [contextMenuStyle, setContextMenuStyle] = useState({
+ top: 0,
+ left: 0,
+ })
const [_currentRequestSpeakType, setCurrentRequestSpeakType] = useState<'video' | 'audio' | ''>('')
const [_mediaStream, setMediaStream] = useState([])
const [isShare, setIsShare] = useState(null)
const [isSharePopConfirm, setIsSharePopConfirm] = useState(false)
const [_isNetworkDisconnected, setIsNetworkDisconnected] = useState(false)
+ const [isAgoraDisconnected, setIsAgoraDisconnected] = useState(false)
const [isShareUser, setIsShareUser] = useState(null)
const [currentLookUserStatus, setCurrentLookUserStatus] = useState<0 | 1 | 2 | 3 | 4>(1)
- const [clickCurrentLookUserStatus, setClickCurrentLookUserStatus] = useState(true)
const [commonlyChatList] = useState([
'能听到我说话吗?',
'听得到',
@@ -197,6 +206,7 @@ const Meeting: React.FC = () => {
])
const [roomUserItem, setRoomUserItem] = useState(null)
const [isAdmin, setIsAdmin] = useState(0)
+ const [_socketRemberNumber, setSocketRemberNumber] = useState(0)
const [api, contextHolder] = notification.useNotification({
stack: {
threshold: 3
@@ -208,9 +218,11 @@ const Meeting: React.FC = () => {
const msgTips = '您不是管理员或发言人,无法开启此功能!'
const channel = new BroadcastChannel('meeting_channel');
let storeDevice: any;
+ let agoraTime: NodeJS.Timeout;
useEffect(() => {
window.electron.createChildWindow('hide')
let time: NodeJS.Timeout;
+ let refreshTime: NodeJS.Timeout;
setUser(userInfo)
window.electron.getIsMaximized().then((res: boolean) => {
if (!res) {
@@ -338,7 +350,6 @@ const Meeting: React.FC = () => {
return res
}))
break;
- break;
case 'userListWindowGetRoomKickout':
GetRoomKickout(state.channelId, userListWindowGetRoomKickout.uid)
break;
@@ -417,6 +428,24 @@ const Meeting: React.FC = () => {
return []
})
}, 1000)
+ refreshTime = setInterval(() => {
+ GetRoomUser(state.channelId).then(res => {
+ if (res.code === 200) {
+ res.data.forEach((item: any) => {
+ setRoomUserList((data: any) => {
+ let row = data.find((row: any) => row.uid == item.uid);
+ if (row) {
+ row.enableCamera = item.enableCamera;
+ row.enableMicr = item.enableMicr;
+ row.isRoomManager = item.isRoomManager;
+ row.isAdmin = role.ID.includes(item.roleId) || item.isRoomManager;
+ }
+ return data
+ })
+ });
+ }
+ })
+ }, 1000 * 30)
// 首次加载图标更新
const firstFooterList = [...footerList]
firstFooterList[0][0].title = state.enableMicr ? '静音' : '解除静音'
@@ -485,45 +514,103 @@ const Meeting: React.FC = () => {
window.removeEventListener('customStorageChange', handleCustomStorageChange);
window.removeEventListener('wheel', handleWheelChange);
clearInterval(time)
+ clearInterval(refreshTime)
channel.close();
window.electron.closeChildWindow('shareScreenWindow')
};
}, []);
useEffect(() => {
- switch (currentEffective) {
- case 0:
+ if (networkOther) {
+ let data = networkOther as any;
+ if (storage.getItem('reconnect') === 'true') {
+ if (data.lastmileDelay < 100) {
+ setNetworkQuality({
+ level: '佳',
+ text: '网络质量极好'
+ })
+ setCurrentEffective(3)
+ window.electron.windowHandleMessage({
+ key: 'shareScreenWindow',
+ parmes: {
+ currentEffective: 3,
+ networkQuality: {
+ level: '佳',
+ text: '网络质量极好'
+ },
+ networkOther: {
+ lastmileDelay: data.lastmileDelay
+ },
+ type: 'nnetworkStatus'
+ }
+ })
+ } else if (data.lastmileDelay > 500) {
+ setNetworkQuality({
+ level: '非常差',
+ text: '完全无法沟通'
+ })
+ setIsNetworkQuality(true)
+ setCurrentEffective(1)
+ window.electron.windowHandleMessage({
+ key: 'shareScreenWindow',
+ parmes: {
+ currentEffective: 1,
+ networkQuality: {
+ level: '非常差',
+ text: '完全无法沟通'
+ },
+ networkOther: {
+ lastmileDelay: data.lastmileDelay
+ },
+ type: 'nnetworkStatus'
+ }
+ })
+ } else if (data.lastmileDelay < 500 && data.lastmileDelay > 100) {
+ setNetworkQuality({
+ level: '差',
+ text: '勉强能沟通但不顺畅'
+ })
+ setIsNetworkQuality(true)
+ setCurrentEffective(2)
+ window.electron.windowHandleMessage({
+ key: 'shareScreenWindow',
+ parmes: {
+ currentEffective: 2,
+ networkQuality: {
+ level: '差',
+ text: '勉强能沟通但不顺畅'
+ },
+ networkOther: {
+ lastmileDelay: data.lastmileDelay
+ },
+ type: 'nnetworkStatus'
+ }
+ })
+ }
+ } else {
setNetworkQuality({
level: '断开连接',
text: '网络连接断开'
})
- break;
- case 1:
- setNetworkQuality({
- level: '非常差',
- text: '完全无法沟通'
+ setCurrentEffective(0)
+ window.electron.windowHandleMessage({
+ key: 'shareScreenWindow',
+ parmes: {
+ currentEffective: 0,
+ networkQuality: {
+ level: '断开连接',
+ text: '网络连接断开'
+ },
+ networkOther: {
+ lastmileDelay: data.lastmileDelay
+ },
+ type: 'nnetworkStatus'
+ }
})
- break;
- case 2:
- setNetworkQuality({
- level: '差',
- text: '勉强能沟通但不顺畅'
- })
- break;
- case 3:
- setNetworkQuality({
- level: '良好',
- text: ' 有瑕疵但不影响沟通'
- })
- break;
- case 4:
- setNetworkQuality({
- level: '佳',
- text: '网络质量极好'
- })
- break;
+
+ }
}
- }, [currentEffective]);
+ }, [networkOther]);
useEffect(() => {
if (chatList.length) {
@@ -573,6 +660,30 @@ const Meeting: React.FC = () => {
}
}, [currentVideoId, isShare]);
+ useEffect(() => {
+ if (isAgoraDisconnected) {
+ agoraTime = setTimeout(() => {
+ confirm({
+ keyboard: false,
+ title: '提示',
+ icon: ,
+ content: `重连失败,请退出房间重试!`,
+ centered: true,
+ okText: '退出',
+ wrapClassName: 'hideCancelText',
+ cancelText: '',
+ async onOk() {
+ leaveChannel()
+ },
+ })
+ clearTimeout(agoraTime)
+ }, 1000 * 60);
+ } else {
+ clearTimeout(agoraTime)
+ }
+ return () => clearTimeout(agoraTime);
+ }, [isAgoraDisconnected]);
+
useEffect(() => {
window.electron.onSignalr(async (_e: any, item: any) => {
const setting = JSON.parse(storage.getItem('setting') as string)
@@ -607,18 +718,8 @@ const Meeting: React.FC = () => {
break;
// 扩展操作
case 'Operation':
- // 4:屏幕共享
switch (item.type) {
- case 4:
- setIsShare((res: any) => {
- if (userInfo.screenShareId === String(res)) {
- changeStatusList({
- title: '共享冲突停止共享',
- }, 1, 0)
- }
- return res
- })
- break;
+
}
break;
// 全员离开房间
@@ -792,7 +893,11 @@ const Meeting: React.FC = () => {
if (!role.ID.includes(userInfo.roleId)) {
let userId = item.watchUids.find((uid: any) => uid === userInfo.uid)
if (userId) {
- await agora.allJoinChannelEx()
+ GetRoomRtcToken(state.channelId + 'a').then(async res => {
+ if (res.code === 200) {
+ await agora.allJoinChannelEx(false, res.data)
+ }
+ })
} else {
await agora.allLeaveChannelEx()
}
@@ -865,6 +970,58 @@ const Meeting: React.FC = () => {
case 'ModifyNickName':
setAllUserListData('ModifyNickName', item)
break;
+ // 加入房间回调
+ case 'JoinChannelCallback':
+ if (item.isSuccess) {
+ await getRoomUser()
+ } else {
+ setSocketRemberNumber(res => {
+ if (res >= 3) {
+ confirm({
+ keyboard: false,
+ title: '提示',
+ icon: ,
+ content: `加入房间失败!`,
+ centered: true,
+ okText: '退出',
+ wrapClassName: 'hideCancelText',
+ cancelText: '',
+ async onOk() {
+ leaveChannel()
+ },
+ })
+ } else {
+ setTimeout(() => {
+ async function setUserStatus(res: any) {
+ let userItem = res.find((item: any) => item.uid === userInfo.uid)
+ await window.electron.onInvoke('joinChannel', {
+ roomNum: state.channelId,
+ enableMicr: !storeDevice[0][0].active,
+ enableCamera: !storeDevice[0][1].active,
+ isRoomManager: userItem ? userItem.isRoomManager : false,
+ })
+ }
+ setRoomUserList((res: any) => {
+ setUserStatus(res)
+ return res
+ })
+ }, 3000);
+ }
+ return res >= 3 ? 3 : res++
+ })
+ }
+ break;
+ // 共享
+ case 'ExitSharedScreen':
+ setIsScreenCapture((res) => {
+ if (res) {
+ changeStatusList({
+ title: '共享冲突停止共享',
+ }, 1, 0)
+ }
+ return res
+ })
+ break;
}
})
return () => {
@@ -948,14 +1105,75 @@ const Meeting: React.FC = () => {
}, [isClicked]);
useEffect(() => {
- let timer: NodeJS.Timeout;
+ async function setView() {
+ let uid = currentVideoUid
+ switch (currentLookUserStatus) {
+ case 1:
+ await agora.setupLocalVideo({
+ uid: Number(uid),
+ view: document.getElementById(`video-source-camera-primary`) as HTMLElement,
+ channelId: state.channelId,
+ sourceType: VideoSourceType.VideoSourceCameraPrimary,
+ renderMode: RenderModeType.RenderModeFit
+ })
+ setIsClickLock(false)
+ break;
+ case 2:
+ await agora.setupLocalVideo({
+ uid: Number(uid),
+ view: document.getElementById(`video-source-screen`) as HTMLElement,
+ channelId: state.channelId,
+ sourceType: VideoSourceType.VideoSourceScreen,
+ renderMode: RenderModeType.RenderModeFit
+ })
+ setIsClickLock(false)
+ break;
+ case 3:
+ await agora.setupRemoteVideoJoin({
+ uid: Number(uid),
+ view: document.getElementById(`video-source-remote-screen`) as HTMLElement,
+ channelId: state.channelId,
+ renderMode: RenderModeType.RenderModeFit
+ })
+ setIsClickLock(false)
+ break;
+ case 4:
+ await agora.setupRemoteVideoJoin({
+ uid: Number(uid),
+ view: document.getElementById(`video-source-remote-camera`) as HTMLElement,
+ channelId: state.channelId,
+ renderMode: RenderModeType.RenderModeFit
+ })
+ setIsClickLock(false)
+ break;
+ }
+ }
+ if (currentVideoUid) {
+ setTimeout(() => {
+ setView()
+ }, currentVideoId ? 0 : 1500);
+ }
+ }, [currentVideoUid]);
+ useEffect(() => {
+ if (isScreenCapture) {
+ agora.setupLocalVideo({
+ uid: Number(user.uid),
+ view: document.getElementById(`meetingAbsoluteVideo`) as HTMLElement,
+ channelId: state.channelId,
+ sourceType: VideoSourceType.VideoSourceCameraPrimary,
+ type: true
+ })
+ }
+ }, [isScreenCapture]);
+
+ useEffect(() => {
+ let timer: NodeJS.Timeout;
if (isClickedMediaSteam) {
timer = setTimeout(() => {
setIsClickedMediaSteam(false)
}, 3000);
}
-
return () => clearTimeout(timer);
}, [isClickedMediaSteam]);
@@ -1028,6 +1246,7 @@ const Meeting: React.FC = () => {
view: document.getElementById(`video-${connection.localUid}`),
channelId: connection.channelId,
sourceType: VideoSourceType.VideoSourceCameraPrimary,
+ renderMode: RenderModeType.RenderModeFit
})
}, 1000);
getShowUser();
@@ -1044,6 +1263,7 @@ const Meeting: React.FC = () => {
uid: Number(remoteUid),
view: document.getElementById(`video-${remoteUid}`),
channelId: connection.channelId,
+ renderMode: RenderModeType.RenderModeFit
})
}, 1000);
}
@@ -1059,6 +1279,7 @@ const Meeting: React.FC = () => {
uid: Number(remoteUid),
view: null,
channelId: connection.channelId,
+ renderMode: RenderModeType.RenderModeFit
});
}
},
@@ -1090,31 +1311,6 @@ const Meeting: React.FC = () => {
});
}
},
- onNetworkQuality: async (_connection: RtcConnection, remoteUid: number, _txQuality: QualityType, rxQuality: QualityType) => {
- if (remoteUid === 0) {
- switch (rxQuality) {
- case 1:
- setCurrentEffective(4)
- break;
- case 2:
- case 3:
- setCurrentEffective(3)
- break;
- case 4:
- setCurrentEffective(2)
- break;
- case 5:
- setCurrentEffective(1)
- break;
- case 6:
- setCurrentEffective(0)
- break;
- default:
- setCurrentEffective(storage.getItem('reconnect') === 'true' ? 4 : 0)
- break;
- }
- }
- },
onRtcStats: async (stats: RtcStats) => {
setNetworkOther(stats)
},
@@ -1124,10 +1320,12 @@ const Meeting: React.FC = () => {
} else if (state === 3) {
meetingDisconnectedRef.current.changeModal(false)
+ setIsAgoraDisconnected(false)
}
},
onConnectionLost: () => {
meetingDisconnectedRef.current.changeModal(true)
+ setIsAgoraDisconnected(true)
setIsScreenCapture(bool => {
if (bool) {
setIsNetworkDisconnected(true)
@@ -1155,6 +1353,16 @@ const Meeting: React.FC = () => {
key: 'cameraTemporarily'
});
}
+ },
+ onTokenPrivilegeWillExpire: async (connection: RtcConnection, _token: string) => {
+ await GetRoomRtcToken(connection.channelId || '').then(res => {
+ if (res.code === 200) {
+ agora.refreshToken({
+ token: res.data,
+ connection,
+ })
+ }
+ })
}
})
if (state.enableCamera) {
@@ -1165,7 +1373,6 @@ const Meeting: React.FC = () => {
uid: userInfo.uid,
screenShareId: userInfo.screenShareId,
token: state.token,
- tokenA: state.tokenA,
})
}
// 状态更新
@@ -1233,12 +1440,14 @@ const Meeting: React.FC = () => {
view: document.getElementById(`video-${userItem.uid}`),
channelId: state.channelId,
sourceType: VideoSourceType.VideoSourceCameraPrimary,
+ renderMode: RenderModeType.RenderModeFit
})
} else {
await agora.setupRemoteVideoJoin({
uid: Number(userItem.uid),
view: document.getElementById(`video-${userItem.uid}`),
channelId: state.channelId,
+ renderMode: RenderModeType.RenderModeFit
})
}
}
@@ -1266,6 +1475,9 @@ const Meeting: React.FC = () => {
userItem.enableMicr = item.user.enableMicr;
}
userItem.isAdmin = role.ID.includes(item.user.roleId) || item.user.isRoomManager;
+ if (!userItem.isAdmin) {
+ agora.destroyRendererByConfig(Number(userItem.uid), state.channelId)
+ }
refreshVideoView(userItem)
}
if (key === 'ManagerRefresh') {
@@ -1283,7 +1495,9 @@ const Meeting: React.FC = () => {
}
userItem.isRoom = true;
userItem.isAdmin = role.ID.includes(item.user.roleId) || item.user.isRoomManager;
- refreshVideoView(userItem)
+ setTimeout(() => {
+ refreshVideoView(userItem)
+ }, 0);
return [...res]
} else {
item.user.isRoom = true;
@@ -1333,23 +1547,34 @@ const Meeting: React.FC = () => {
}
// 滚动
const handleWheelChange = (e: any): void => {
- const container = document.getElementById('videoView') as HTMLElement;
- if (e.wheelDeltaY > 0) {
- container.scrollLeft -= 100
- } else {
- container.scrollLeft += 100
- }
+ setMeetingMode(res => {
+ if (res === 'StandardMode') {
+ const container = document.getElementById('videoView') as HTMLElement;
+ if (e.wheelDeltaY > 0) {
+ container.scrollLeft -= 100
+ } else {
+ container.scrollLeft += 100
+ }
+ }
+ return res
+ })
}
// 渲染视频
const renderVideo = async (uid: string = ''): Promise => {
+ if (isClickLock) {
+ return
+ }
if (uid) {
- if (currentVideoId === uid || clickCurrentLookUserStatus === false) {
+ if (currentVideoId === uid || currentVideoUid === uid) {
return
}
} else {
uid = userInfo.uid
}
- setClickCurrentLookUserStatus(false)
+ await agora.destroyRendererByView(`video-source-camera-primary`)
+ await agora.destroyRendererByView(`video-source-screen`)
+ await agora.destroyRendererByView(`video-source-remote-screen`)
+ await agora.destroyRendererByView(`video-source-remote-camera`)
setCurrentLookUserStatus(0)
setRoomUserList((res: any) => {
let item = res.find((item: any) => item.uid === uid || item.screenShareId === uid)
@@ -1358,59 +1583,28 @@ const Meeting: React.FC = () => {
}
return res
})
- setTimeout(() => {
- if (uid === userInfo.uid || uid === userInfo.screenShareId) {
- if (String(uid).length === 9) {
- // 共享屏幕
- setCurrentLookUserStatus(2)
- setTimeout(async () => {
- await agora.setupLocalVideo({
- uid: Number(uid),
- view: document.getElementById(`video-source-screen`) as HTMLElement,
- channelId: state.channelId,
- sourceType: VideoSourceType.VideoSourceScreen,
- })
- setClickCurrentLookUserStatus(true)
- }, 1500);
- } else {
- // 摄像头
- setCurrentLookUserStatus(1)
- setTimeout(async () => {
- await agora.setupLocalVideo({
- uid: Number(uid),
- view: document.getElementById(`video-source-camera-primary`) as HTMLElement,
- channelId: state.channelId,
- sourceType: VideoSourceType.VideoSourceCameraPrimary,
- })
- setClickCurrentLookUserStatus(true)
- }, 1500);
- }
+ setIsClickLock(true)
+ setCurrentVideoUid('')
+ if (uid === userInfo.uid || uid === userInfo.screenShareId) {
+ if (String(uid).length === 9) {
+ // 共享屏幕
+ setCurrentLookUserStatus(2)
} else {
- if (String(uid).length === 9) {
- // 共享屏幕
- setCurrentLookUserStatus(3)
- setTimeout(async () => {
- await agora.setupRemoteVideoJoin({
- uid: Number(uid),
- view: document.getElementById(`video-source-remote-screen`) as HTMLElement,
- channelId: state.channelId,
- })
- setClickCurrentLookUserStatus(true)
- }, 1500);
- } else {
- // 摄像头
- setCurrentLookUserStatus(4)
- setTimeout(async () => {
- await agora.setupRemoteVideoJoin({
- uid: Number(uid),
- view: document.getElementById(`video-source-remote-camera`) as HTMLElement,
- channelId: state.channelId,
- })
- setClickCurrentLookUserStatus(true)
- }, 1500);
- }
+ // 摄像头
+ setCurrentLookUserStatus(1)
}
- }, 1000)
+ } else {
+ if (String(uid).length === 9) {
+ // 共享屏幕
+ setCurrentLookUserStatus(3)
+ } else {
+ // 摄像头
+ setCurrentLookUserStatus(4)
+ }
+ }
+ setTimeout(() => {
+ setCurrentVideoUid(uid)
+ }, 500);
}
// 全员观看
const getShowUser = async (): Promise => {
@@ -1645,7 +1839,11 @@ const Meeting: React.FC = () => {
break;
case '会议监控':
if (!statusList.userVideo) {
- await agora.allJoinChannelEx(true)
+ GetRoomRtcToken(state.channelId + 'a').then(async res => {
+ if (res.code === 200) {
+ await agora.allJoinChannelEx(true, res.data)
+ }
+ })
} else {
await agora.allLeaveChannelEx()
}
@@ -1703,7 +1901,11 @@ const Meeting: React.FC = () => {
if (userInfo.isAnonymous) {
storage.setItem('userLogin', false)
} else {
- navigate('/home/index')
+ navigate(`/home/index`, {
+ state: {
+ currentSeconds
+ }
+ })
}
}
return res
@@ -1711,7 +1913,6 @@ const Meeting: React.FC = () => {
}
// 分享屏幕
const clickSharedScreen = async (): Promise => {
- let data = sharedScreenList.find((item: any) => item.sourceId === sharedScreenItem.sourceId)
const elements = document.querySelectorAll('.intersectionObserver-view');
if (elements.length) {
elements.forEach(item => {
@@ -1721,35 +1922,30 @@ const Meeting: React.FC = () => {
});
agora.setSubscribeVideoBlocklist([Number(user.screenShareId)], 1)
}
- if (data) {
- const footerListTemplate = [...footerList]
- footerListTemplate[footerListIndex.itemIndex][footerListIndex.rowIndex].title = '停止共享'
- setIsSharedScreenModal(false)
- await agora.setDesktopCapturerVideo(sharedScreenItem, isComputerAudio, isFluencyPriority)
- await allUserLook(user.screenShareId, user.userName)
- const isOpen = await getKeyOpenChildWindow('shareScreenWindow')
- setIsScreenCapture(true)
- if (!isOpen) {
- window.electron.createChildWindow('show')
- setKeyOpenChildWindow('shareScreenWindow', true)
- window.electron.setMainWindowSize({
- width: 250,
- height: 160,
- })
- window.electron.setPosition('right')
- setTimeout(() => {
- agora.setupLocalVideo({
- uid: Number(user.uid),
- view: document.getElementById(`meetingAbsoluteVideo`) as HTMLElement,
- channelId: state.channelId,
- sourceType: VideoSourceType.VideoSourceCameraPrimary,
- type: true
+ GetRoomRtcToken(state.channelId).then(async res => {
+ if (res.code === 200) {
+ await agora.destroyRendererByView(`video-source-camera-primary`)
+ await agora.destroyRendererByView(`video-source-screen`)
+ await agora.destroyRendererByView(`video-source-remote-screen`)
+ await agora.destroyRendererByView(`video-source-remote-camera`)
+ const footerListTemplate = [...footerList]
+ footerListTemplate[footerListIndex.itemIndex][footerListIndex.rowIndex].title = '停止共享'
+ setIsSharedScreenModal(false)
+ await agora.setDesktopCapturerVideo(sharedScreenItem, isComputerAudio, isFluencyPriority, res.data)
+ await allUserLook(user.screenShareId, user.userName)
+ const isOpen = await getKeyOpenChildWindow('shareScreenWindow')
+ setIsScreenCapture(true)
+ if (!isOpen) {
+ window.electron.createChildWindow('show')
+ setKeyOpenChildWindow('shareScreenWindow', true)
+ window.electron.setMainWindowSize({
+ width: 250,
+ height: 160,
})
- }, 1500);
+ window.electron.setPosition('right')
+ }
}
- } else {
- message.error('请选择应用!')
- }
+ })
}
// 获取桌面可共享屏幕的引用
const getDesktopCapturerVideo = (): void => {
@@ -1786,14 +1982,18 @@ const Meeting: React.FC = () => {
}
// 停止共享
const stopScreenCapture = async (): Promise => {
+ await agora.destroyRendererByView(`meetingAbsoluteVideo`)
const footerListTemplate = [...footerList]
await agora.leaveChannelEx(userInfo.screenShareId)
agora.stopScreenCapture()
- await agora.destroyRendererByView()
footerListTemplate[1][0].title = '共享屏幕'
setFooterList(footerListTemplate)
window.electron.createChildWindow('stop')
setKeyOpenChildWindow('shareScreenWindow', false)
+ window.electron.setChildWindowShow({
+ key: 'noticeWindow',
+ bool: false
+ })
setIsScreenCapture(bool => {
if (bool) {
window.electron.setViewStatus('show')
@@ -1844,15 +2044,15 @@ const Meeting: React.FC = () => {
if (e.value == true) {
message.success('网络已连接。')
meetingDisconnectedRef.current.changeModal(false)
+ setIsAgoraDisconnected(false)
async function setUserStatus(res: any) {
let userItem = res.find((item: any) => item.uid === userInfo.uid)
await window.electron.onInvoke('joinChannel', {
roomNum: state.channelId,
enableMicr: !storeDevice[0][0].active,
enableCamera: !storeDevice[0][1].active,
- isRoomManager: userItem.isRoomManager
+ isRoomManager: userItem ? userItem.isRoomManager : false,
})
- await getRoomUser()
await getShowUser()
if (userItem.isRoomManager) {
await postOpenMicr(!storeDevice[0][0].active, userInfo.uid)
@@ -1968,7 +2168,7 @@ const Meeting: React.FC = () => {
})
}
if (isMessage) {
- message.success('操作成功')
+ // message.success('操作成功')
}
}
// 开关视频
@@ -2012,7 +2212,7 @@ const Meeting: React.FC = () => {
enableCamera
})
if (isMessage) {
- message.success('操作成功')
+ // message.success('操作成功')
}
}
// 演讲者模式
@@ -2134,7 +2334,6 @@ const Meeting: React.FC = () => {
enableMicr,
enableCamera
})
- await getRoomUser()
}
// 离开房间
const getLeave = async (): Promise => {
@@ -2173,7 +2372,10 @@ const Meeting: React.FC = () => {
}
return (
<>
-
+
{
+ setContextMenu('')
+ setIsNetworkQuality(false)
+ }}>
{isScreenCapture ?
{currentSpeakUser.length ? '正在说话:' + currentSpeakUser.join(';') : '正在说话:'}
{footerList[0][1].active ?
@@ -2187,12 +2389,109 @@ const Meeting: React.FC = () => {
})
}}>{isExpand ? '展开' : '收起'}
: null}
+ {contextMenu ?
+ {contextMenu.isRoomManager || role.ID.includes(contextMenu.roleId) ? : null}
+ {contextMenu.uid !== user.uid && !role.ID.includes(contextMenu.roleId) ? : null}
+ {contextMenu.isRoomManager ? : null}
+ {contextMenu.isRoomManager ? : null}
+ {contextMenu.uid !== user.uid ? : null}
+ {contextMenu.uid !== user.uid ? : null}
+ {contextMenu.uid !== user.uid ? : null}
+
: null}
{contextHolder}
{isScreenCapture ? null :
+ setIsNetworkQuality(false)}>
网络质量:
{networkQuality.level}
@@ -2230,7 +2529,10 @@ const Meeting: React.FC = () => {
title=""
trigger="hover"
>
-
+
setIsNetworkQuality(true)}
+
+ >
{networkIcon(currentEffective)}
详情
@@ -2293,6 +2595,15 @@ const Meeting: React.FC = () => {
renderVideo(item.uid)
}
}}
+ onContextMenu={(e: any) => {
+ if (role.ID.includes(userInfo.roleId)) {
+ setContextMenuStyle({
+ top: e.clientY,
+ left: e.clientX,
+ })
+ setContextMenu(item)
+ }
+ }}
>
@@ -2358,10 +2669,23 @@ const Meeting: React.FC = () => {
type="primary"
className='m-ant-btn'
size={'small'}
- onClick={() => {
+ onClick={(event) => {
+ event.stopPropagation();
equipmentManagement(item.uid, item.userName)
}}
>设备管理 : null}
+ {item.uid !== user.uid ? : null}
{item.uid !== user.uid ? : null}
- {item.uid !== user.uid ? : null}
}>
@@ -2394,7 +2707,31 @@ const Meeting: React.FC = () => {
: null)
}
)}
- {currentLookUserStatus === 0 && currentLookUserAccount ?
+ {roomUserList.length > 6 ?
+ {meetingMode === "StandardMode" ?
{
+ const container = document.getElementById('videoView') as HTMLElement;
+ container.scrollLeft -= 100
+ }}>
+
+
:
{
+ const container = document.getElementById('videoView') as HTMLElement;
+ container.scrollTop -= 100
+ }}>
+
+
}
+ {meetingMode === "StandardMode" ?
{
+ const container = document.getElementById('videoView') as HTMLElement;
+ container.scrollLeft += 100
+ }}>
+
+
:
{
+ const container = document.getElementById('videoView') as HTMLElement;
+ container.scrollTop += 100
+ }}>
+
+
}
+
: null}
+ {currentLookUserStatus === 0 ?
{
@@ -2405,7 +2742,7 @@ const Meeting: React.FC = () => {
setIsVideoFullScreen(true)} />}
{meetingContentUser(currentLookUserAccount, true)}
: null}
- {currentLookUserStatus === 1 && currentLookUserAccount ?
+ {currentLookUserStatus === 1 ?
{
@@ -2417,7 +2754,7 @@ const Meeting: React.FC = () => {
{meetingContentUser(currentLookUserAccount, true)}
{currentLookUserAccount.enableCamera ? null : meetingContentError(currentLookUserAccount)}
: null}
- {currentLookUserStatus === 2 && currentLookUserAccount ?
+ {currentLookUserStatus === 2 ?
@@ -2428,7 +2765,7 @@ const Meeting: React.FC = () => {
setIsVideoFullScreen(true)} />}
{meetingContentUser(currentLookUserAccount, true)}
: null}
- {currentLookUserStatus === 3 && currentLookUserAccount ?
+ {currentLookUserStatus === 3 ?
@@ -2439,7 +2776,7 @@ const Meeting: React.FC = () => {
setIsVideoFullScreen(true)} />}
{meetingContentUser(currentLookUserAccount, true)}
: null}
- {currentLookUserStatus === 4 && currentLookUserAccount ?
+ {currentLookUserStatus === 4 ?
@@ -2524,22 +2861,23 @@ const Meeting: React.FC = () => {
+
-
+
}>
@@ -2696,7 +3042,8 @@ const Meeting: React.FC = () => {
type="primary"
className='m-ant-btn'
size={'small'}
- onClick={() => {
+ onClick={(event) => {
+ event.stopPropagation();
equipmentManagement(roomUserItem.uid, roomUserItem.userName)
}}
>设备管理 : null}
@@ -2955,8 +3302,8 @@ const Meeting: React.FC = () => {
)
})}
}
-
-
+
+
@@ -2994,12 +3341,17 @@ const Meeting: React.FC = () => {
description={`这将停止[${isShareUser?.userName}]的共享,是否继续?`}
open={isSharePopConfirm}
onConfirm={async () => {
- setIsSharePopConfirm(false)
- await window.electron.onInvoke('sendOper', {
- roomNum: state.channelId,
- type: 4,
- })
- clickSharedScreen()
+ let data = sharedScreenList.find((item: any) => item.sourceId === sharedScreenItem.sourceId)
+ if (data) {
+ PostSharedScreen(state.channelId).then(res => {
+ if (res.code === 200) {
+ setIsSharePopConfirm(false)
+ clickSharedScreen()
+ }
+ })
+ } else {
+ message.error('请选择应用!')
+ }
}}
onCancel={() => {
setIsSharePopConfirm(false)
@@ -3012,7 +3364,16 @@ const Meeting: React.FC = () => {
}}>共享
:
}
@@ -3107,44 +3468,55 @@ const meetingContentError = (item: any) => {
const networkIcon = (network: number) => {
switch (network) {
case 0:
- return