会议监控测试
This commit is contained in:
parent
94bb8d5ff0
commit
92d8e9e443
14
main.js
14
main.js
|
|
@ -16,6 +16,7 @@ const { autoUpdater, CancellationToken } = require('electron-updater');
|
|||
const cancellationToken = new CancellationToken()
|
||||
app.allowRendererProcessReuse = false;
|
||||
let mainWindow = null;
|
||||
let newWindow = null;
|
||||
let isMaximized = false;
|
||||
let env;
|
||||
|
||||
|
|
@ -264,7 +265,10 @@ app.on('ready', () => {
|
|||
});
|
||||
// 打开新窗口
|
||||
ipcMain.handle('oepnWindow', (event, data) => {
|
||||
const newWindow = new BrowserWindow({
|
||||
if (newWindow) {
|
||||
newWindow.focus();
|
||||
} else {
|
||||
newWindow = new BrowserWindow({
|
||||
width: 1200,
|
||||
height: 800,
|
||||
minWidth: 1200,
|
||||
|
|
@ -290,6 +294,14 @@ app.on('ready', () => {
|
|||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 关闭会议监控窗口
|
||||
ipcMain.handle('closeMonitorWindow', () => {
|
||||
if (newWindow) {
|
||||
newWindow.close();
|
||||
newWindow = null
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
{
|
||||
"name": "multi.person.meeting",
|
||||
"name": "WGShare.Metting",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "multi.person.meeting",
|
||||
"name": "WGShare.Metting",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.3.7",
|
||||
"@microsoft/signalr": "^8.0.0",
|
||||
"@reduxjs/toolkit": "^2.2.7",
|
||||
"@types/node": "^20.14.9",
|
||||
"agora-electron-sdk": "^4.3.2",
|
||||
"animate.css": "^4.1.1",
|
||||
|
|
@ -24,6 +25,7 @@
|
|||
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-redux": "^9.1.2",
|
||||
"react-router-dom": "^6.23.1",
|
||||
"sass": "^1.77.5",
|
||||
"tldraw": "^2.2.0"
|
||||
|
|
@ -2243,6 +2245,29 @@
|
|||
"react-dom": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@reduxjs/toolkit": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmmirror.com/@reduxjs/toolkit/-/toolkit-2.2.7.tgz",
|
||||
"integrity": "sha512-faI3cZbSdFb8yv9dhDTmGwclW0vk0z5o1cia+kf7gCbaCwHI5e+7tP57mJUv22pNcNbeA62GSrPpfrUfdXcQ6g==",
|
||||
"dependencies": {
|
||||
"immer": "^10.0.3",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"reselect": "^5.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.9.0 || ^17.0.0 || ^18",
|
||||
"react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmmirror.com/@remix-run/router/-/router-1.17.1.tgz",
|
||||
|
|
@ -2519,6 +2544,11 @@
|
|||
"resolved": "https://registry.npmmirror.com/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
||||
"integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
|
||||
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
|
||||
},
|
||||
"node_modules/@types/verror": {
|
||||
"version": "1.10.10",
|
||||
"resolved": "https://registry.npmmirror.com/@types/verror/-/verror-1.10.10.tgz",
|
||||
|
|
@ -7265,6 +7295,15 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"node_modules/immer": {
|
||||
"version": "10.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz",
|
||||
"integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/immer"
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-4.3.6.tgz",
|
||||
|
|
@ -9620,6 +9659,28 @@
|
|||
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz",
|
||||
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
|
||||
},
|
||||
"node_modules/react-redux": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-9.1.2.tgz",
|
||||
"integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==",
|
||||
"dependencies": {
|
||||
"@types/use-sync-external-store": "^0.0.3",
|
||||
"use-sync-external-store": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"react": "^18.0",
|
||||
"redux": "^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.13.0.tgz",
|
||||
|
|
@ -9863,6 +9924,19 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/redux/-/redux-5.0.1.tgz",
|
||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
|
||||
},
|
||||
"node_modules/redux-thunk": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/redux-thunk/-/redux-thunk-3.1.0.tgz",
|
||||
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
|
||||
"peerDependencies": {
|
||||
"redux": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
|
|
@ -9999,6 +10073,11 @@
|
|||
"resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz",
|
||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
|
||||
},
|
||||
"node_modules/reselect": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/reselect/-/reselect-5.1.1.tgz",
|
||||
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="
|
||||
},
|
||||
"node_modules/resize-observer-polyfill": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||
|
|
@ -11675,6 +11754,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
|
||||
"integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/utf8-byte-length": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
|
||||
|
|
@ -13473,6 +13560,17 @@
|
|||
"rc-util": "^5.38.0"
|
||||
}
|
||||
},
|
||||
"@reduxjs/toolkit": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmmirror.com/@reduxjs/toolkit/-/toolkit-2.2.7.tgz",
|
||||
"integrity": "sha512-faI3cZbSdFb8yv9dhDTmGwclW0vk0z5o1cia+kf7gCbaCwHI5e+7tP57mJUv22pNcNbeA62GSrPpfrUfdXcQ6g==",
|
||||
"requires": {
|
||||
"immer": "^10.0.3",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"reselect": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"@remix-run/router": {
|
||||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmmirror.com/@remix-run/router/-/router-1.17.1.tgz",
|
||||
|
|
@ -13721,6 +13819,11 @@
|
|||
"resolved": "https://registry.npmmirror.com/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
||||
"integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="
|
||||
},
|
||||
"@types/use-sync-external-store": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
|
||||
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
|
||||
},
|
||||
"@types/verror": {
|
||||
"version": "1.10.10",
|
||||
"resolved": "https://registry.npmmirror.com/@types/verror/-/verror-1.10.10.tgz",
|
||||
|
|
@ -17293,6 +17396,11 @@
|
|||
"resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
|
||||
},
|
||||
"immer": {
|
||||
"version": "10.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz",
|
||||
"integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw=="
|
||||
},
|
||||
"immutable": {
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-4.3.6.tgz",
|
||||
|
|
@ -19025,6 +19133,15 @@
|
|||
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz",
|
||||
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
|
||||
},
|
||||
"react-redux": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-9.1.2.tgz",
|
||||
"integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==",
|
||||
"requires": {
|
||||
"@types/use-sync-external-store": "^0.0.3",
|
||||
"use-sync-external-store": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"react-refresh": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.13.0.tgz",
|
||||
|
|
@ -19193,6 +19310,17 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"redux": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/redux/-/redux-5.0.1.tgz",
|
||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
|
||||
},
|
||||
"redux-thunk": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/redux-thunk/-/redux-thunk-3.1.0.tgz",
|
||||
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
|
||||
"requires": {}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
|
|
@ -19298,6 +19426,11 @@
|
|||
"resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz",
|
||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
|
||||
},
|
||||
"reselect": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/reselect/-/reselect-5.1.1.tgz",
|
||||
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="
|
||||
},
|
||||
"resize-observer-polyfill": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||
|
|
@ -20592,6 +20725,12 @@
|
|||
"tslib": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"use-sync-external-store": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
|
||||
"integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
|
||||
"requires": {}
|
||||
},
|
||||
"utf8-byte-length": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
"dependencies": {
|
||||
"@ant-design/icons": "^5.3.7",
|
||||
"@microsoft/signalr": "^8.0.0",
|
||||
"@reduxjs/toolkit": "^2.2.7",
|
||||
"@types/node": "^20.14.9",
|
||||
"agora-electron-sdk": "^4.3.2",
|
||||
"animate.css": "^4.1.1",
|
||||
|
|
@ -39,6 +40,7 @@
|
|||
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-redux": "^9.1.2",
|
||||
"react-router-dom": "^6.23.1",
|
||||
"sass": "^1.77.5",
|
||||
"tldraw": "^2.2.0"
|
||||
|
|
|
|||
|
|
@ -65,4 +65,8 @@ window.electron = {
|
|||
oepnWindow: (data) => {
|
||||
ipcRenderer.invoke('oepnWindow', data)
|
||||
},
|
||||
// 关闭会议监控窗口
|
||||
closeMonitorWindow: () => {
|
||||
ipcRenderer.invoke('closeMonitorWindow')
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ const App: React.FC = () => {
|
|||
});
|
||||
const [spinning, setSpinning] = useState(false);
|
||||
const [isState, setIsState] = useState(true);
|
||||
const urlWindow = ['#/userVideo']
|
||||
if (urlWindow.indexOf(location.hash) === -1) {
|
||||
if (location.href.indexOf('#/userVideo') === -1) {
|
||||
useEffect(() => {
|
||||
let userInfo = JSON.parse(storage.getItem('user') as string)
|
||||
let loginInfo = JSON.parse(storage.getItem('login') as string)
|
||||
|
|
@ -151,6 +150,9 @@ const App: React.FC = () => {
|
|||
if (location.href.indexOf('/login') !== -1) {
|
||||
onStop()
|
||||
}
|
||||
if (location.href.indexOf('#/meeting') === -1) {
|
||||
window.electron.closeMonitorWindow()
|
||||
}
|
||||
}, [navigate])
|
||||
}
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -130,3 +130,8 @@ export const GetApplySpeak = (roomNum: string) =>
|
|||
url: `/room/apply-speak?roomNum=${roomNum}`,
|
||||
method: 'get'
|
||||
})
|
||||
export const GetPolling = (roomNum: string, count: string) =>
|
||||
request({
|
||||
url: `/room/polling?roomNum=${roomNum}&count=${count}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
|
@ -71,9 +71,12 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
|||
})
|
||||
}
|
||||
const getRoomRtcToken = async (roomNum: string, callBack: Function): Promise<void> => {
|
||||
await GetRoomRtcToken(roomNum).then(res => {
|
||||
if (res.code === 200) {
|
||||
callBack(res.data)
|
||||
Promise.all([GetRoomRtcToken(roomNum), GetRoomRtcToken(roomNum + 'a')]).then(res => {
|
||||
if (res[0].code === 200 && res[1].code === 200) {
|
||||
callBack({
|
||||
token: res[0].data,
|
||||
tokenA: res[1].data,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -169,8 +172,8 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
|||
}
|
||||
isGetCheckoutRoomNum(roomNumber, (bool: boolean) => {
|
||||
if (bool) {
|
||||
getRoomRtcToken(roomNumber, (token: string) => {
|
||||
if (token) {
|
||||
getRoomRtcToken(roomNumber, (options: any) => {
|
||||
if (options) {
|
||||
postRefresh(() => {
|
||||
clearInterval(time)
|
||||
setJoinRoomSettingModal(false)
|
||||
|
|
@ -180,7 +183,8 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
|||
navigate(`/meeting`, {
|
||||
state: {
|
||||
channelId: roomNumber,
|
||||
token,
|
||||
token: options.token,
|
||||
tokenA: options.tokenA,
|
||||
roomId: res.data.id,
|
||||
roomName: res.data.roomName,
|
||||
enableMicr: joinRoomSettingForm[0].active,
|
||||
|
|
|
|||
|
|
@ -5,10 +5,14 @@ import { HashRouter } from 'react-router-dom';
|
|||
import { ConfigProvider } from 'antd';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import 'animate.css';
|
||||
import { Provider } from 'react-redux'
|
||||
import store from '@/utils/package/store';
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<HashRouter>
|
||||
<ConfigProvider locale={zhCN}>
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>
|
||||
</ConfigProvider>
|
||||
</HashRouter>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -85,13 +85,13 @@ const Meeting: React.FC = () => {
|
|||
active: false,
|
||||
select: false,
|
||||
},
|
||||
// {
|
||||
// title: '会议监控',
|
||||
// icon: ImageUrl.icon48,
|
||||
// iconSelect: ImageUrl.icon48Select,
|
||||
// active: false,
|
||||
// select: false,
|
||||
// },
|
||||
{
|
||||
title: '会议监控',
|
||||
icon: ImageUrl.icon48,
|
||||
iconSelect: ImageUrl.icon48Select,
|
||||
active: false,
|
||||
select: false,
|
||||
},
|
||||
{
|
||||
title: '录制',
|
||||
icon: ImageUrl.icon27,
|
||||
|
|
@ -188,6 +188,7 @@ const Meeting: React.FC = () => {
|
|||
agora.init(true)
|
||||
agora.registerEventHandler({
|
||||
onJoinChannelSuccess: async (info: any, _elapsed: any) => {
|
||||
if (info.channelId === state.channelId) {
|
||||
if (String(info.localUid).length !== 9) {
|
||||
await getJoin(state.enableMicr, state.enableCamera)
|
||||
setTimeout(async () => {
|
||||
|
|
@ -200,8 +201,10 @@ const Meeting: React.FC = () => {
|
|||
getShowUser();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
},
|
||||
onUserJoined: async (info: any, remoteUid: any, _elapsed: any) => {
|
||||
if (info.channelId === state.channelId) {
|
||||
if (String(remoteUid).length === 9) {
|
||||
setIsShare(remoteUid)
|
||||
} else {
|
||||
|
|
@ -213,8 +216,10 @@ const Meeting: React.FC = () => {
|
|||
})
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
},
|
||||
onUserOffline: async (info: any, remoteUid: any, _reason: any) => {
|
||||
if (info.channelId === state.channelId) {
|
||||
if (String(remoteUid).length === 9) {
|
||||
setIsShare(null)
|
||||
renderVideo()
|
||||
|
|
@ -230,6 +235,7 @@ const Meeting: React.FC = () => {
|
|||
}
|
||||
return res
|
||||
})
|
||||
}
|
||||
},
|
||||
onAudioVolumeIndication: async (speakers: any) => {
|
||||
speakers.forEach((item: any) => {
|
||||
|
|
@ -241,11 +247,14 @@ const Meeting: React.FC = () => {
|
|||
});
|
||||
}
|
||||
})
|
||||
if (state.enableCamera) {
|
||||
agora.startCameraCapture()
|
||||
}
|
||||
agora.setJoinChannel({
|
||||
channelId: state.channelId,
|
||||
uid: userInfo.uid,
|
||||
token: state.token,
|
||||
tokenA: userInfo.uid === '1' ? '' : state.tokenA,
|
||||
})
|
||||
storage.setItem('noViewChatList', 0)
|
||||
window.addEventListener('customStorageChange', handleCustomStorageChange);
|
||||
|
|
@ -465,6 +474,10 @@ const Meeting: React.FC = () => {
|
|||
pauseOnHover: false,
|
||||
});
|
||||
break;
|
||||
// 管理员查看随机用户
|
||||
case 'Watch':
|
||||
console.log(item);
|
||||
break;
|
||||
}
|
||||
})
|
||||
return () => {
|
||||
|
|
@ -915,7 +928,7 @@ const Meeting: React.FC = () => {
|
|||
break;
|
||||
case '会议监控':
|
||||
window.electron.oepnWindow({
|
||||
url: location.origin + '/#/userVideo'
|
||||
url: location.origin + `/#/userVideo?channelId=${state.channelId + 'a'}&token=${state.tokenA}`
|
||||
})
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
|
||||
import { GetPolling } from '@/api/Meeting';
|
||||
import styles from '@/page/UserVideo/index.module.scss'
|
||||
import { storage } from '@/utils';
|
||||
import monitorAgora from '@/utils/package/monitorAgora';
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import { Button, Select } from 'antd';
|
||||
import { VideoSourceType } from 'agora-electron-sdk';
|
||||
import { Button, Select, message } from 'antd';
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const UserVideo: React.FC = () => {
|
||||
let userInfo = JSON.parse(storage.getItem('user') as string)
|
||||
const [user, setUser] = useState<any>({});
|
||||
const [from, setFrom] = useState<any>({
|
||||
cycleIntervalList: [
|
||||
{ value: 30, label: '30秒' },
|
||||
|
|
@ -22,15 +27,86 @@ const UserVideo: React.FC = () => {
|
|||
],
|
||||
viewPeopleValue: 4,
|
||||
})
|
||||
const [timeNumber, setTimeNumber] = useState(30);
|
||||
const [timeStatus, setTimeStatus] = useState(false);
|
||||
useEffect(() => {
|
||||
setUser(userInfo)
|
||||
monitorAgora.init()
|
||||
monitorAgora.setJoinChannel({
|
||||
channelId: getQueryParameterRegex('channelId'),
|
||||
uid: userInfo.uid,
|
||||
token: getQueryParameterRegex('token'),
|
||||
})
|
||||
monitorAgora.registerEventHandler({
|
||||
onJoinChannelSuccess: async (info: any, _elapsed: any) => {
|
||||
// await monitorAgora.setupLocalVideo({
|
||||
// uid: info.localUid,
|
||||
// view: document.getElementById(`video-${info.localUid}`),
|
||||
// channelId: info.channelId,
|
||||
// sourceType: VideoSourceType.VideoSourceCameraPrimary,
|
||||
// })
|
||||
},
|
||||
onUserJoined: async (info: any, remoteUid: any, _elapsed: any) => {
|
||||
|
||||
},
|
||||
onUserOffline: async (info: any, remoteUid: any, _reason: any) => {
|
||||
|
||||
},
|
||||
})
|
||||
window.addEventListener('customStorageChange', handleCustomStorageChange);
|
||||
return () => {
|
||||
window.removeEventListener('customStorageChange', handleCustomStorageChange);
|
||||
}
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
let time = null as any;
|
||||
if (timeStatus) {
|
||||
time = setInterval(() => {
|
||||
setTimeNumber((timeNumber: number) => {
|
||||
if (timeNumber === 1) {
|
||||
getPolling()
|
||||
message.success('刷新成功!')
|
||||
return from.cycleIntervalValue
|
||||
} else {
|
||||
return timeNumber - 1
|
||||
}
|
||||
})
|
||||
}, 1000)
|
||||
} else {
|
||||
clearInterval(time)
|
||||
}
|
||||
return () => {
|
||||
clearInterval(time)
|
||||
}
|
||||
}, [timeStatus])
|
||||
|
||||
useEffect(() => {
|
||||
getPolling()
|
||||
}, [from.viewPeopleValue])
|
||||
// 监听缓存变化
|
||||
const handleCustomStorageChange = async (e: any): Promise<void> => {
|
||||
// console.log(e);
|
||||
};
|
||||
// 获取地址栏参数
|
||||
const getQueryParameterRegex = (name: string): string | null => {
|
||||
const reg = new RegExp(`[?&]${name}=([^&#]*)`);
|
||||
const results = window.location.href.match(reg);
|
||||
return results === null ? null : results[1];
|
||||
}
|
||||
// 获取轮训用户
|
||||
const getPolling = async (): Promise<void> => {
|
||||
GetPolling(getQueryParameterRegex('channelId') as string, from.viewPeopleValue).then((res: any) => {
|
||||
console.log(res);
|
||||
})
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className={styles.userVideo}>
|
||||
<div className={styles.userVideoTitle}>
|
||||
会议监控
|
||||
<CloseOutlined className='drag' />
|
||||
<CloseOutlined className='drag' onClick={() => {
|
||||
window.electron.closeMonitorWindow()
|
||||
}} />
|
||||
</div>
|
||||
<div className={`${styles.userVideoContent} drag`}>
|
||||
<div className={styles.userVideoContentHeader}>
|
||||
|
|
@ -42,6 +118,7 @@ const UserVideo: React.FC = () => {
|
|||
options={from.cycleIntervalList}
|
||||
value={from.cycleIntervalValue} onChange={(e) => {
|
||||
setFrom({ ...from, cycleIntervalValue: e })
|
||||
setTimeNumber(e)
|
||||
}} />
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -55,47 +132,26 @@ const UserVideo: React.FC = () => {
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>30秒后刷新</span>
|
||||
{/* <Button
|
||||
<span>{timeNumber}秒后刷新</span>
|
||||
{timeStatus ? <Button
|
||||
type="primary"
|
||||
onClick={() => { }}
|
||||
style={{ backgroundColor: '#EC3C3C', marginLeft: '14px' }}
|
||||
>暂停循环</Button> */}
|
||||
onClick={() => {
|
||||
setTimeStatus(!timeStatus)
|
||||
}}
|
||||
style={{ backgroundColor: '#EC3C3C' }}
|
||||
>暂停循环</Button> :
|
||||
<Button
|
||||
type="primary"
|
||||
className='m-ant-btn'
|
||||
onClick={() => { }}
|
||||
>开始循环</Button>
|
||||
onClick={() => {
|
||||
setTimeStatus(!timeStatus)
|
||||
}}
|
||||
>开始循环</Button>}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.userVideoContentList}>
|
||||
<div className={styles.userVideoContentListItem}>
|
||||
<div className={styles.userVideoContentListItemVideo}>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.userVideoContentListItem}>
|
||||
<div className={styles.userVideoContentListItemVideo}>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.userVideoContentListItem}>
|
||||
<div className={styles.userVideoContentListItemVideo}>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.userVideoContentListItem}>
|
||||
<div className={styles.userVideoContentListItemVideo}>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.userVideoContentListItem}>
|
||||
<div className={styles.userVideoContentListItemVideo}>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.userVideoContentListItem}>
|
||||
<div className={styles.userVideoContentListItemVideo}>
|
||||
<div className={styles.userVideoContentListItemVideo} id={`video-${user.uid}`}>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ export interface IElectronAPI {
|
|||
quitAndInstall: (callBack: Function) => void;
|
||||
getVersion: () => Promise<string>;
|
||||
oepnWindow: (data: any) => any;
|
||||
|
||||
closeMonitorWindow: () => void
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { storage } from '@/utils';
|
|||
const option: any = {
|
||||
appId: 'dcfc466a6ecb4a1f972630065dfb1e75',
|
||||
token: '',
|
||||
tokenA: '',
|
||||
channelId: '',
|
||||
uid: '',
|
||||
}
|
||||
|
|
@ -216,6 +217,21 @@ const agora = {
|
|||
}
|
||||
);
|
||||
},
|
||||
// 所有用户加入的第二个房间
|
||||
allJoinChannelEx: async () => {
|
||||
await rtcEngine.joinChannelEx(
|
||||
option.tokenA,
|
||||
{ channelId: option.channelId + 'a', localUid: Number(option.uid) },
|
||||
{
|
||||
autoSubscribeAudio: false,//设置是否自动订阅所有音频流
|
||||
autoSubscribeVideo: false,//设置是否自动订阅所有视频流
|
||||
publishMicrophoneTrack: false,//设置是否发布麦克风采集到的音频
|
||||
publishCameraTrack: true,//设置是否发布摄像头采集的视频
|
||||
clientRoleType: ClientRoleType.ClientRoleAudience,//用户角色 ClientRoleBroadcaster 主播 ClientRoleAudience 观众
|
||||
publishScreenTrack: false,//设置是否发布屏幕采集的视频
|
||||
}
|
||||
);
|
||||
},
|
||||
// 离开共享屏幕频道
|
||||
leaveChannelEx: async (uid: any) => {
|
||||
await rtcEngine.leaveChannelEx({ channelId: option.channelId, localUid: Number(uid) })
|
||||
|
|
@ -250,9 +266,13 @@ const agora = {
|
|||
// 加入频道
|
||||
setJoinChannel: async (data: any) => {
|
||||
option.token = data.token;
|
||||
option.tokenA = data.tokenA;
|
||||
option.channelId = data.channelId;
|
||||
option.uid = Number(data.uid);
|
||||
await agora.joinChannel()
|
||||
if (data.tokenA) {
|
||||
await agora.allJoinChannelEx()
|
||||
}
|
||||
},
|
||||
// 桌面捕获音频和视频的媒体源的信息
|
||||
getDesktopCapturerVideo: async () => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
// 暂时无用
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
export const agoraReducer = createSlice({
|
||||
name: 'agora',
|
||||
initialState: {
|
||||
value: 0,
|
||||
} as any,
|
||||
reducers: {
|
||||
initAgora: async (state) => {
|
||||
|
||||
},
|
||||
},
|
||||
});
|
||||
export const { initAgora } = agoraReducer.actions;
|
||||
export default agoraReducer.reducer;
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
import {
|
||||
createAgoraRtcEngine,
|
||||
ClientRoleType,
|
||||
VideoSourceType,
|
||||
VideoViewSetupMode,
|
||||
RenderModeType,
|
||||
} from "agora-electron-sdk";
|
||||
import { storage } from "..";
|
||||
const option: any = {
|
||||
appId: 'dcfc466a6ecb4a1f972630065dfb1e75',
|
||||
token: '',
|
||||
channelId: '',
|
||||
uid: '',
|
||||
}
|
||||
let rtcEngine: any = '';
|
||||
|
||||
const monitorAgora = {
|
||||
// 初始化
|
||||
init: async () => {
|
||||
rtcEngine = createAgoraRtcEngine();
|
||||
await rtcEngine.initialize({
|
||||
appId: option.appId,
|
||||
});
|
||||
await monitorAgora.setDeviceManager()
|
||||
},
|
||||
// 获取当前设备是否存在不存在就获取默认设备
|
||||
setDeviceManager: async (bool: boolean = false) => {
|
||||
const setting = await JSON.parse(storage.getItem('setting') as string)
|
||||
// 摄像头
|
||||
if (setting.videoDeviceId) {
|
||||
await monitorAgora.getVideoDeviceManager().then(async (res) => {
|
||||
let item = res.list.find((item: any) => item.deviceId === setting.videoDeviceId);
|
||||
if (item) {
|
||||
await monitorAgora.setVideoDeviceManager(setting.videoDeviceId)
|
||||
} else {
|
||||
await monitorAgora.setVideoDeviceManager(await rtcEngine.getVideoDeviceManager().getDevice())
|
||||
setting.videoDeviceId = await rtcEngine.getVideoDeviceManager().getDevice()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
await monitorAgora.setVideoDeviceManager(await rtcEngine.getVideoDeviceManager().getDevice())
|
||||
setting.videoDeviceId = await rtcEngine.getVideoDeviceManager().getDevice()
|
||||
}
|
||||
|
||||
// 播放设备
|
||||
if (setting.playBackDeviceId) {
|
||||
await monitorAgora.getAudioMediaList().then(async (res) => {
|
||||
let item = res.playBackList.find((item: any) => item.deviceId === setting.playBackDeviceId);
|
||||
if (item) {
|
||||
await monitorAgora.setPlaybackDevice(setting.playBackDeviceId)
|
||||
} else {
|
||||
await monitorAgora.setPlaybackDevice(res.playBackItem.deviceId)
|
||||
setting.playBackDeviceId = res.playBackItem.deviceId
|
||||
}
|
||||
})
|
||||
} else {
|
||||
let deviceId = await rtcEngine.getAudioDeviceManager().getPlaybackDefaultDevice().deviceId;
|
||||
await monitorAgora.setPlaybackDevice(deviceId)
|
||||
setting.playBackDeviceId = deviceId
|
||||
}
|
||||
|
||||
// 音频设备
|
||||
if (setting.ecordingDeviceId) {
|
||||
await monitorAgora.getAudioMediaList().then(async (res) => {
|
||||
let item = res.ecordingList.find((item: any) => item.deviceId === setting.ecordingDeviceId);
|
||||
if (item) {
|
||||
await monitorAgora.setRecordingDevice(setting.ecordingDeviceId)
|
||||
} else {
|
||||
await monitorAgora.setRecordingDevice(res.ecordingItem.deviceId)
|
||||
setting.ecordingDeviceId = res.ecordingItem.deviceId
|
||||
}
|
||||
})
|
||||
} else {
|
||||
let deviceId = await rtcEngine.getAudioDeviceManager().getRecordingDefaultDevice().deviceId;
|
||||
await monitorAgora.setRecordingDevice(deviceId)
|
||||
setting.ecordingDeviceId = deviceId
|
||||
}
|
||||
setTimeout(async () => {
|
||||
storage.setItem('setting', JSON.stringify(setting))
|
||||
if (bool) {
|
||||
const setting = await JSON.parse(storage.getItem('setting') as string)
|
||||
if (setting.videoDeviceId) monitorAgora.setVideoDeviceManager(setting.videoDeviceId) //指定摄像头头采集设备
|
||||
if (setting.playBackDeviceId) monitorAgora.setPlaybackDevice(setting.playBackDeviceId) //指定播放设备
|
||||
if (setting.playBackVolume) monitorAgora.setPlaybackDeviceVolume(setting.playBackVolume) // 设置播放设备音量
|
||||
if (setting.ecordingDeviceId) monitorAgora.setRecordingDevice(setting.ecordingDeviceId) // 设置音频采集设备
|
||||
if (setting.ecordingVolume) monitorAgora.setRecordingDeviceVolume(setting.ecordingVolume) // 设置音频设备音量
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
// 事件回调
|
||||
registerEventHandler: ({ onJoinChannelSuccess, onUserJoined, onUserOffline }: any) => {
|
||||
rtcEngine.registerEventHandler({
|
||||
// 监听本地用户加入频道事件
|
||||
onJoinChannelSuccess: async (info: any, elapsed: any) => {
|
||||
await onJoinChannelSuccess(info, elapsed)
|
||||
},
|
||||
// 监听远端用户加入频道事件
|
||||
onUserJoined: async (info: any, remoteUid: any, elapsed: any) => {
|
||||
await onUserJoined(info, remoteUid, elapsed)
|
||||
},
|
||||
// 监听用户离开频道事件
|
||||
onUserOffline: async (info: any, remoteUid: any, reason: any) => {
|
||||
await onUserOffline(info, remoteUid, reason)
|
||||
},
|
||||
});
|
||||
},
|
||||
// 加入频道
|
||||
setJoinChannel: async (data: any) => {
|
||||
option.token = data.token;
|
||||
option.channelId = data.channelId;
|
||||
option.uid = Number(data.uid);
|
||||
await monitorAgora.JoinChannelEx()
|
||||
},
|
||||
// 所有用户加入的第二个房间
|
||||
JoinChannelEx: async () => {
|
||||
await rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {
|
||||
format: {
|
||||
width: 640,
|
||||
height: 360,
|
||||
fps: 15,
|
||||
}
|
||||
})
|
||||
await rtcEngine.joinChannelEx(
|
||||
option.token,
|
||||
{ channelId: option.channelId, localUid: Number(option.uid) },
|
||||
{
|
||||
autoSubscribeAudio: false,//设置是否自动订阅所有音频流
|
||||
autoSubscribeVideo: false,//设置是否自动订阅所有视频流
|
||||
publishMicrophoneTrack: false,//设置是否发布麦克风采集到的音频
|
||||
publishCameraTrack: true,//设置是否发布摄像头采集的视频
|
||||
clientRoleType: ClientRoleType.ClientRoleBroadcaster,//用户角色 ClientRoleBroadcaster 主播 ClientRoleAudience 观众
|
||||
publishScreenTrack: false,//设置是否发布屏幕采集的视频
|
||||
}
|
||||
);
|
||||
},
|
||||
// 本地加入
|
||||
setupLocalVideo: async (item: any) => {
|
||||
if (item.view?.childNodes.length === 0) {
|
||||
await rtcEngine.setupLocalVideo({
|
||||
renderMode: RenderModeType.RenderModeHidden,
|
||||
sourceType: item.sourceType,
|
||||
uid: item.uid,
|
||||
view: item.view,
|
||||
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
|
||||
});
|
||||
}
|
||||
},
|
||||
// 远端加入
|
||||
setupRemoteVideoJoin: async (item: any) => {
|
||||
if (item.view?.childNodes.length === 0) {
|
||||
await rtcEngine.setupRemoteVideo(
|
||||
{
|
||||
renderMode: RenderModeType.RenderModeHidden,
|
||||
sourceType: VideoSourceType.VideoSourceRemote,
|
||||
uid: item.uid,
|
||||
view: item.view,
|
||||
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
|
||||
},
|
||||
{ channelId: item.channelId },
|
||||
);
|
||||
}
|
||||
},
|
||||
// 退出
|
||||
setupRemoteVideo: async (item: any) => {
|
||||
await rtcEngine.setupRemoteVideo(
|
||||
{
|
||||
renderMode: RenderModeType.RenderModeHidden,
|
||||
sourceType: VideoSourceType.VideoSourceRemote,
|
||||
uid: item.uid,
|
||||
view: item.view,
|
||||
setupMode: VideoViewSetupMode.VideoViewSetupRemove,
|
||||
},
|
||||
);
|
||||
},
|
||||
// 销毁
|
||||
release: async () => {
|
||||
await rtcEngine.release()
|
||||
},
|
||||
// 获取系统中所有的视频设备列表。
|
||||
getVideoDeviceManager: async (): Promise<any> => {
|
||||
return {
|
||||
list: rtcEngine.getVideoDeviceManager().enumerateVideoDevices(),
|
||||
item: rtcEngine.getVideoDeviceManager().getDevice()
|
||||
}
|
||||
},
|
||||
// 通过设备 ID 指定视频采集设备。
|
||||
setVideoDeviceManager: async (deviceIdUTF8: string) => {
|
||||
await rtcEngine.getVideoDeviceManager().setDevice(deviceIdUTF8)
|
||||
},
|
||||
// 获取输入输出设备列表
|
||||
getAudioMediaList: async () => {
|
||||
return {
|
||||
playBackList: rtcEngine.getAudioDeviceManager().enumeratePlaybackDevices(),
|
||||
ecordingList: rtcEngine.getAudioDeviceManager().enumerateRecordingDevices(),
|
||||
playBackItem: rtcEngine.getAudioDeviceManager().getPlaybackDefaultDevice(),
|
||||
ecordingItem: rtcEngine.getAudioDeviceManager().getRecordingDefaultDevice(),
|
||||
ecordingVolume: rtcEngine.getAudioDeviceManager().getRecordingDeviceVolume(),
|
||||
}
|
||||
},
|
||||
// 指定播放设备
|
||||
setPlaybackDevice: async (deviceId: string) => {
|
||||
await rtcEngine.getAudioDeviceManager().setPlaybackDevice(deviceId)
|
||||
},
|
||||
// 设置音频采集设备
|
||||
setRecordingDevice: async (deviceId: string) => {
|
||||
await rtcEngine.getAudioDeviceManager().setRecordingDevice(deviceId)
|
||||
},
|
||||
// 设置播放设备音量
|
||||
setPlaybackDeviceVolume: async (volume: number) => {
|
||||
await rtcEngine.getAudioDeviceManager().setPlaybackDeviceVolume(volume)
|
||||
},
|
||||
// 设置音频设备音量
|
||||
setRecordingDeviceVolume: async (volume: number) => {
|
||||
await rtcEngine.getAudioDeviceManager().setRecordingDeviceVolume(volume)
|
||||
},
|
||||
}
|
||||
|
||||
export default monitorAgora;
|
||||
|
|
@ -153,6 +153,13 @@ export const onSignalr = (callBack: Function) => {
|
|||
uname
|
||||
})
|
||||
});
|
||||
// 管理员查看随机用户
|
||||
connection.on("Watch", (watchUids: string[]) => {
|
||||
callBack({
|
||||
key: 'Watch',
|
||||
watchUids
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
export const offSignalr = () => {
|
||||
|
|
@ -170,6 +177,7 @@ export const offSignalr = () => {
|
|||
connection.off('OperCamera');
|
||||
connection.off('ManagerRefresh');
|
||||
connection.off('ApplyToSpeak');
|
||||
connection.off('Watch');
|
||||
}
|
||||
}
|
||||
export const onInvoke = async (str: string, data: any) => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import agoraReducer from '@/utils/package/features/agoraReducer'
|
||||
export default configureStore({
|
||||
reducer: {
|
||||
agora: agoraReducer,
|
||||
}
|
||||
});
|
||||
Loading…
Reference in New Issue