会议监控测试
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()
|
const cancellationToken = new CancellationToken()
|
||||||
app.allowRendererProcessReuse = false;
|
app.allowRendererProcessReuse = false;
|
||||||
let mainWindow = null;
|
let mainWindow = null;
|
||||||
|
let newWindow = null;
|
||||||
let isMaximized = false;
|
let isMaximized = false;
|
||||||
let env;
|
let env;
|
||||||
|
|
||||||
|
|
@ -264,7 +265,10 @@ app.on('ready', () => {
|
||||||
});
|
});
|
||||||
// 打开新窗口
|
// 打开新窗口
|
||||||
ipcMain.handle('oepnWindow', (event, data) => {
|
ipcMain.handle('oepnWindow', (event, data) => {
|
||||||
const newWindow = new BrowserWindow({
|
if (newWindow) {
|
||||||
|
newWindow.focus();
|
||||||
|
} else {
|
||||||
|
newWindow = new BrowserWindow({
|
||||||
width: 1200,
|
width: 1200,
|
||||||
height: 800,
|
height: 800,
|
||||||
minWidth: 1200,
|
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",
|
"version": "0.0.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "multi.person.meeting",
|
"name": "WGShare.Metting",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^5.3.7",
|
"@ant-design/icons": "^5.3.7",
|
||||||
"@microsoft/signalr": "^8.0.0",
|
"@microsoft/signalr": "^8.0.0",
|
||||||
|
"@reduxjs/toolkit": "^2.2.7",
|
||||||
"@types/node": "^20.14.9",
|
"@types/node": "^20.14.9",
|
||||||
"agora-electron-sdk": "^4.3.2",
|
"agora-electron-sdk": "^4.3.2",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
|
|
@ -24,6 +25,7 @@
|
||||||
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"react-redux": "^9.1.2",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"sass": "^1.77.5",
|
"sass": "^1.77.5",
|
||||||
"tldraw": "^2.2.0"
|
"tldraw": "^2.2.0"
|
||||||
|
|
@ -2243,6 +2245,29 @@
|
||||||
"react-dom": ">=16.9.0"
|
"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": {
|
"node_modules/@remix-run/router": {
|
||||||
"version": "1.17.1",
|
"version": "1.17.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@remix-run/router/-/router-1.17.1.tgz",
|
"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",
|
"resolved": "https://registry.npmmirror.com/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
||||||
"integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="
|
"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": {
|
"node_modules/@types/verror": {
|
||||||
"version": "1.10.10",
|
"version": "1.10.10",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/verror/-/verror-1.10.10.tgz",
|
"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": {
|
"node_modules/immutable": {
|
||||||
"version": "4.3.6",
|
"version": "4.3.6",
|
||||||
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-4.3.6.tgz",
|
"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",
|
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz",
|
||||||
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
|
"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": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.13.0",
|
"version": "0.13.0",
|
||||||
"resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.13.0.tgz",
|
"resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.13.0.tgz",
|
||||||
|
|
@ -9863,6 +9924,19 @@
|
||||||
"node": ">=0.10.0"
|
"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": {
|
"node_modules/regenerator-runtime": {
|
||||||
"version": "0.14.1",
|
"version": "0.14.1",
|
||||||
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
"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",
|
"resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz",
|
||||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
|
"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": {
|
"node_modules/resize-observer-polyfill": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
"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": {
|
"node_modules/utf8-byte-length": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmmirror.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
|
"resolved": "https://registry.npmmirror.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
|
||||||
|
|
@ -13473,6 +13560,17 @@
|
||||||
"rc-util": "^5.38.0"
|
"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": {
|
"@remix-run/router": {
|
||||||
"version": "1.17.1",
|
"version": "1.17.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@remix-run/router/-/router-1.17.1.tgz",
|
"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",
|
"resolved": "https://registry.npmmirror.com/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
||||||
"integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="
|
"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": {
|
"@types/verror": {
|
||||||
"version": "1.10.10",
|
"version": "1.10.10",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/verror/-/verror-1.10.10.tgz",
|
"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",
|
"resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
|
"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": {
|
"immutable": {
|
||||||
"version": "4.3.6",
|
"version": "4.3.6",
|
||||||
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-4.3.6.tgz",
|
"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",
|
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz",
|
||||||
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
|
"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": {
|
"react-refresh": {
|
||||||
"version": "0.13.0",
|
"version": "0.13.0",
|
||||||
"resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.13.0.tgz",
|
"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": {
|
"regenerator-runtime": {
|
||||||
"version": "0.14.1",
|
"version": "0.14.1",
|
||||||
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
"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",
|
"resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz",
|
||||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
|
"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": {
|
"resize-observer-polyfill": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
"resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||||
|
|
@ -20592,6 +20725,12 @@
|
||||||
"tslib": "^2.0.0"
|
"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": {
|
"utf8-byte-length": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmmirror.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
|
"resolved": "https://registry.npmmirror.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^5.3.7",
|
"@ant-design/icons": "^5.3.7",
|
||||||
"@microsoft/signalr": "^8.0.0",
|
"@microsoft/signalr": "^8.0.0",
|
||||||
|
"@reduxjs/toolkit": "^2.2.7",
|
||||||
"@types/node": "^20.14.9",
|
"@types/node": "^20.14.9",
|
||||||
"agora-electron-sdk": "^4.3.2",
|
"agora-electron-sdk": "^4.3.2",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
|
|
@ -39,6 +40,7 @@
|
||||||
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"react-redux": "^9.1.2",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"sass": "^1.77.5",
|
"sass": "^1.77.5",
|
||||||
"tldraw": "^2.2.0"
|
"tldraw": "^2.2.0"
|
||||||
|
|
|
||||||
|
|
@ -65,4 +65,8 @@ window.electron = {
|
||||||
oepnWindow: (data) => {
|
oepnWindow: (data) => {
|
||||||
ipcRenderer.invoke('oepnWindow', data)
|
ipcRenderer.invoke('oepnWindow', data)
|
||||||
},
|
},
|
||||||
|
// 关闭会议监控窗口
|
||||||
|
closeMonitorWindow: () => {
|
||||||
|
ipcRenderer.invoke('closeMonitorWindow')
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,7 @@ const App: React.FC = () => {
|
||||||
});
|
});
|
||||||
const [spinning, setSpinning] = useState(false);
|
const [spinning, setSpinning] = useState(false);
|
||||||
const [isState, setIsState] = useState(true);
|
const [isState, setIsState] = useState(true);
|
||||||
const urlWindow = ['#/userVideo']
|
if (location.href.indexOf('#/userVideo') === -1) {
|
||||||
if (urlWindow.indexOf(location.hash) === -1) {
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let userInfo = JSON.parse(storage.getItem('user') as string)
|
let userInfo = JSON.parse(storage.getItem('user') as string)
|
||||||
let loginInfo = JSON.parse(storage.getItem('login') as string)
|
let loginInfo = JSON.parse(storage.getItem('login') as string)
|
||||||
|
|
@ -151,6 +150,9 @@ const App: React.FC = () => {
|
||||||
if (location.href.indexOf('/login') !== -1) {
|
if (location.href.indexOf('/login') !== -1) {
|
||||||
onStop()
|
onStop()
|
||||||
}
|
}
|
||||||
|
if (location.href.indexOf('#/meeting') === -1) {
|
||||||
|
window.electron.closeMonitorWindow()
|
||||||
|
}
|
||||||
}, [navigate])
|
}, [navigate])
|
||||||
}
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -130,3 +130,8 @@ export const GetApplySpeak = (roomNum: string) =>
|
||||||
url: `/room/apply-speak?roomNum=${roomNum}`,
|
url: `/room/apply-speak?roomNum=${roomNum}`,
|
||||||
method: 'get'
|
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> => {
|
const getRoomRtcToken = async (roomNum: string, callBack: Function): Promise<void> => {
|
||||||
await GetRoomRtcToken(roomNum).then(res => {
|
Promise.all([GetRoomRtcToken(roomNum), GetRoomRtcToken(roomNum + 'a')]).then(res => {
|
||||||
if (res.code === 200) {
|
if (res[0].code === 200 && res[1].code === 200) {
|
||||||
callBack(res.data)
|
callBack({
|
||||||
|
token: res[0].data,
|
||||||
|
tokenA: res[1].data,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -123,7 +126,7 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
||||||
{
|
{
|
||||||
joinRoomSettingForm.map((item, index) => {
|
joinRoomSettingForm.map((item, index) => {
|
||||||
return <div key={index} onClick={async () => {
|
return <div key={index} onClick={async () => {
|
||||||
if (user.roleId === '1'){
|
if (user.roleId === '1') {
|
||||||
let msg = '';
|
let msg = '';
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
await agora.getAudioMediaList().then(res => {
|
await agora.getAudioMediaList().then(res => {
|
||||||
|
|
@ -150,7 +153,7 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
||||||
agora.startPreview('videoPreview', Number(user.account))
|
agora.startPreview('videoPreview', Number(user.account))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
message.error('您不是管理员,无法开启此功能!')
|
message.error('您不是管理员,无法开启此功能!')
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
|
|
@ -169,8 +172,8 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
||||||
}
|
}
|
||||||
isGetCheckoutRoomNum(roomNumber, (bool: boolean) => {
|
isGetCheckoutRoomNum(roomNumber, (bool: boolean) => {
|
||||||
if (bool) {
|
if (bool) {
|
||||||
getRoomRtcToken(roomNumber, (token: string) => {
|
getRoomRtcToken(roomNumber, (options: any) => {
|
||||||
if (token) {
|
if (options) {
|
||||||
postRefresh(() => {
|
postRefresh(() => {
|
||||||
clearInterval(time)
|
clearInterval(time)
|
||||||
setJoinRoomSettingModal(false)
|
setJoinRoomSettingModal(false)
|
||||||
|
|
@ -180,7 +183,8 @@ const JoinSetting = forwardRef((_props: any, ref: any) => {
|
||||||
navigate(`/meeting`, {
|
navigate(`/meeting`, {
|
||||||
state: {
|
state: {
|
||||||
channelId: roomNumber,
|
channelId: roomNumber,
|
||||||
token,
|
token: options.token,
|
||||||
|
tokenA: options.tokenA,
|
||||||
roomId: res.data.id,
|
roomId: res.data.id,
|
||||||
roomName: res.data.roomName,
|
roomName: res.data.roomName,
|
||||||
enableMicr: joinRoomSettingForm[0].active,
|
enableMicr: joinRoomSettingForm[0].active,
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,14 @@ import { HashRouter } from 'react-router-dom';
|
||||||
import { ConfigProvider } from 'antd';
|
import { ConfigProvider } from 'antd';
|
||||||
import zhCN from 'antd/locale/zh_CN';
|
import zhCN from 'antd/locale/zh_CN';
|
||||||
import 'animate.css';
|
import 'animate.css';
|
||||||
|
import { Provider } from 'react-redux'
|
||||||
|
import store from '@/utils/package/store';
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
<ConfigProvider locale={zhCN}>
|
<ConfigProvider locale={zhCN}>
|
||||||
|
<Provider store={store}>
|
||||||
<App />
|
<App />
|
||||||
|
</Provider>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
</HashRouter>
|
</HashRouter>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -85,13 +85,13 @@ const Meeting: React.FC = () => {
|
||||||
active: false,
|
active: false,
|
||||||
select: false,
|
select: false,
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// title: '会议监控',
|
title: '会议监控',
|
||||||
// icon: ImageUrl.icon48,
|
icon: ImageUrl.icon48,
|
||||||
// iconSelect: ImageUrl.icon48Select,
|
iconSelect: ImageUrl.icon48Select,
|
||||||
// active: false,
|
active: false,
|
||||||
// select: false,
|
select: false,
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
title: '录制',
|
title: '录制',
|
||||||
icon: ImageUrl.icon27,
|
icon: ImageUrl.icon27,
|
||||||
|
|
@ -188,6 +188,7 @@ const Meeting: React.FC = () => {
|
||||||
agora.init(true)
|
agora.init(true)
|
||||||
agora.registerEventHandler({
|
agora.registerEventHandler({
|
||||||
onJoinChannelSuccess: async (info: any, _elapsed: any) => {
|
onJoinChannelSuccess: async (info: any, _elapsed: any) => {
|
||||||
|
if (info.channelId === state.channelId) {
|
||||||
if (String(info.localUid).length !== 9) {
|
if (String(info.localUid).length !== 9) {
|
||||||
await getJoin(state.enableMicr, state.enableCamera)
|
await getJoin(state.enableMicr, state.enableCamera)
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
|
|
@ -200,8 +201,10 @@ const Meeting: React.FC = () => {
|
||||||
getShowUser();
|
getShowUser();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onUserJoined: async (info: any, remoteUid: any, _elapsed: any) => {
|
onUserJoined: async (info: any, remoteUid: any, _elapsed: any) => {
|
||||||
|
if (info.channelId === state.channelId) {
|
||||||
if (String(remoteUid).length === 9) {
|
if (String(remoteUid).length === 9) {
|
||||||
setIsShare(remoteUid)
|
setIsShare(remoteUid)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -213,8 +216,10 @@ const Meeting: React.FC = () => {
|
||||||
})
|
})
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onUserOffline: async (info: any, remoteUid: any, _reason: any) => {
|
onUserOffline: async (info: any, remoteUid: any, _reason: any) => {
|
||||||
|
if (info.channelId === state.channelId) {
|
||||||
if (String(remoteUid).length === 9) {
|
if (String(remoteUid).length === 9) {
|
||||||
setIsShare(null)
|
setIsShare(null)
|
||||||
renderVideo()
|
renderVideo()
|
||||||
|
|
@ -230,6 +235,7 @@ const Meeting: React.FC = () => {
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onAudioVolumeIndication: async (speakers: any) => {
|
onAudioVolumeIndication: async (speakers: any) => {
|
||||||
speakers.forEach((item: any) => {
|
speakers.forEach((item: any) => {
|
||||||
|
|
@ -241,11 +247,14 @@ const Meeting: React.FC = () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (state.enableCamera) {
|
||||||
agora.startCameraCapture()
|
agora.startCameraCapture()
|
||||||
|
}
|
||||||
agora.setJoinChannel({
|
agora.setJoinChannel({
|
||||||
channelId: state.channelId,
|
channelId: state.channelId,
|
||||||
uid: userInfo.uid,
|
uid: userInfo.uid,
|
||||||
token: state.token,
|
token: state.token,
|
||||||
|
tokenA: userInfo.uid === '1' ? '' : state.tokenA,
|
||||||
})
|
})
|
||||||
storage.setItem('noViewChatList', 0)
|
storage.setItem('noViewChatList', 0)
|
||||||
window.addEventListener('customStorageChange', handleCustomStorageChange);
|
window.addEventListener('customStorageChange', handleCustomStorageChange);
|
||||||
|
|
@ -465,6 +474,10 @@ const Meeting: React.FC = () => {
|
||||||
pauseOnHover: false,
|
pauseOnHover: false,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
// 管理员查看随机用户
|
||||||
|
case 'Watch':
|
||||||
|
console.log(item);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return () => {
|
return () => {
|
||||||
|
|
@ -915,7 +928,7 @@ const Meeting: React.FC = () => {
|
||||||
break;
|
break;
|
||||||
case '会议监控':
|
case '会议监控':
|
||||||
window.electron.oepnWindow({
|
window.electron.oepnWindow({
|
||||||
url: location.origin + '/#/userVideo'
|
url: location.origin + `/#/userVideo?channelId=${state.channelId + 'a'}&token=${state.tokenA}`
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
|
|
||||||
|
import { GetPolling } from '@/api/Meeting';
|
||||||
import styles from '@/page/UserVideo/index.module.scss'
|
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 { 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";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
const UserVideo: React.FC = () => {
|
const UserVideo: React.FC = () => {
|
||||||
|
let userInfo = JSON.parse(storage.getItem('user') as string)
|
||||||
|
const [user, setUser] = useState<any>({});
|
||||||
const [from, setFrom] = useState<any>({
|
const [from, setFrom] = useState<any>({
|
||||||
cycleIntervalList: [
|
cycleIntervalList: [
|
||||||
{ value: 30, label: '30秒' },
|
{ value: 30, label: '30秒' },
|
||||||
|
|
@ -22,15 +27,86 @@ const UserVideo: React.FC = () => {
|
||||||
],
|
],
|
||||||
viewPeopleValue: 4,
|
viewPeopleValue: 4,
|
||||||
})
|
})
|
||||||
|
const [timeNumber, setTimeNumber] = useState(30);
|
||||||
|
const [timeStatus, setTimeStatus] = useState(false);
|
||||||
useEffect(() => {
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={styles.userVideo}>
|
<div className={styles.userVideo}>
|
||||||
<div className={styles.userVideoTitle}>
|
<div className={styles.userVideoTitle}>
|
||||||
会议监控
|
会议监控
|
||||||
<CloseOutlined className='drag' />
|
<CloseOutlined className='drag' onClick={() => {
|
||||||
|
window.electron.closeMonitorWindow()
|
||||||
|
}} />
|
||||||
</div>
|
</div>
|
||||||
<div className={`${styles.userVideoContent} drag`}>
|
<div className={`${styles.userVideoContent} drag`}>
|
||||||
<div className={styles.userVideoContentHeader}>
|
<div className={styles.userVideoContentHeader}>
|
||||||
|
|
@ -42,6 +118,7 @@ const UserVideo: React.FC = () => {
|
||||||
options={from.cycleIntervalList}
|
options={from.cycleIntervalList}
|
||||||
value={from.cycleIntervalValue} onChange={(e) => {
|
value={from.cycleIntervalValue} onChange={(e) => {
|
||||||
setFrom({ ...from, cycleIntervalValue: e })
|
setFrom({ ...from, cycleIntervalValue: e })
|
||||||
|
setTimeNumber(e)
|
||||||
}} />
|
}} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -55,47 +132,26 @@ const UserVideo: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>30秒后刷新</span>
|
<span>{timeNumber}秒后刷新</span>
|
||||||
{/* <Button
|
{timeStatus ? <Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => { }}
|
onClick={() => {
|
||||||
style={{ backgroundColor: '#EC3C3C', marginLeft: '14px' }}
|
setTimeStatus(!timeStatus)
|
||||||
>暂停循环</Button> */}
|
}}
|
||||||
|
style={{ backgroundColor: '#EC3C3C' }}
|
||||||
|
>暂停循环</Button> :
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
className='m-ant-btn'
|
className='m-ant-btn'
|
||||||
onClick={() => { }}
|
onClick={() => {
|
||||||
>开始循环</Button>
|
setTimeStatus(!timeStatus)
|
||||||
|
}}
|
||||||
|
>开始循环</Button>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.userVideoContentList}>
|
<div className={styles.userVideoContentList}>
|
||||||
<div className={styles.userVideoContentListItem}>
|
<div className={styles.userVideoContentListItem}>
|
||||||
<div className={styles.userVideoContentListItemVideo}>
|
<div className={styles.userVideoContentListItemVideo} id={`video-${user.uid}`}>
|
||||||
|
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ export interface IElectronAPI {
|
||||||
quitAndInstall: (callBack: Function) => void;
|
quitAndInstall: (callBack: Function) => void;
|
||||||
getVersion: () => Promise<string>;
|
getVersion: () => Promise<string>;
|
||||||
oepnWindow: (data: any) => any;
|
oepnWindow: (data: any) => any;
|
||||||
|
|
||||||
|
closeMonitorWindow: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import { storage } from '@/utils';
|
||||||
const option: any = {
|
const option: any = {
|
||||||
appId: 'dcfc466a6ecb4a1f972630065dfb1e75',
|
appId: 'dcfc466a6ecb4a1f972630065dfb1e75',
|
||||||
token: '',
|
token: '',
|
||||||
|
tokenA: '',
|
||||||
channelId: '',
|
channelId: '',
|
||||||
uid: '',
|
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) => {
|
leaveChannelEx: async (uid: any) => {
|
||||||
await rtcEngine.leaveChannelEx({ channelId: option.channelId, localUid: Number(uid) })
|
await rtcEngine.leaveChannelEx({ channelId: option.channelId, localUid: Number(uid) })
|
||||||
|
|
@ -250,9 +266,13 @@ const agora = {
|
||||||
// 加入频道
|
// 加入频道
|
||||||
setJoinChannel: async (data: any) => {
|
setJoinChannel: async (data: any) => {
|
||||||
option.token = data.token;
|
option.token = data.token;
|
||||||
|
option.tokenA = data.tokenA;
|
||||||
option.channelId = data.channelId;
|
option.channelId = data.channelId;
|
||||||
option.uid = Number(data.uid);
|
option.uid = Number(data.uid);
|
||||||
await agora.joinChannel()
|
await agora.joinChannel()
|
||||||
|
if (data.tokenA) {
|
||||||
|
await agora.allJoinChannelEx()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// 桌面捕获音频和视频的媒体源的信息
|
// 桌面捕获音频和视频的媒体源的信息
|
||||||
getDesktopCapturerVideo: async () => {
|
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
|
uname
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
// 管理员查看随机用户
|
||||||
|
connection.on("Watch", (watchUids: string[]) => {
|
||||||
|
callBack({
|
||||||
|
key: 'Watch',
|
||||||
|
watchUids
|
||||||
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const offSignalr = () => {
|
export const offSignalr = () => {
|
||||||
|
|
@ -170,6 +177,7 @@ export const offSignalr = () => {
|
||||||
connection.off('OperCamera');
|
connection.off('OperCamera');
|
||||||
connection.off('ManagerRefresh');
|
connection.off('ManagerRefresh');
|
||||||
connection.off('ApplyToSpeak');
|
connection.off('ApplyToSpeak');
|
||||||
|
connection.off('Watch');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const onInvoke = async (str: string, data: any) => {
|
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