下载文件准备
This commit is contained in:
parent
250cb75558
commit
76db877293
|
|
@ -14,6 +14,7 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
<script type="module" src="/src/utils/package/agora.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
2
main.js
2
main.js
|
|
@ -8,7 +8,7 @@ class AppWindow extends BrowserWindow {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
const basicConfig = {
|
const basicConfig = {
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
contextIsolation: true,
|
contextIsolation: false,
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
enableRemoteModule: true,
|
enableRemoteModule: true,
|
||||||
nodeIntegrationInWorker: true,
|
nodeIntegrationInWorker: true,
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@
|
||||||
"agora-electron-sdk": "^4.3.2",
|
"agora-electron-sdk": "^4.3.2",
|
||||||
"antd": "^5.18.2",
|
"antd": "^5.18.2",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
"electron-squirrel-startup": "^1.0.1",
|
"electron-squirrel-startup": "^1.0.1",
|
||||||
"js-md5": "^0.8.3",
|
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.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",
|
||||||
|
|
@ -1408,9 +1408,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.15",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
|
|
@ -1446,9 +1446,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@microsoft/signalr": {
|
"node_modules/@microsoft/signalr": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.7",
|
||||||
"resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.7.tgz",
|
||||||
"integrity": "sha512-K/wS/VmzRWePCGqGh8MU8OWbS1Zvu7DG7LSJS62fBB8rJUXwwj4axQtqrAAwKGUZHQF6CuteuQR9xMsVpM2JNA==",
|
"integrity": "sha512-PHcdMv8v5hJlBkRHAuKG5trGViQEkPYee36LnJQx4xHOQ5LL4X0nEWIxOp5cCtZ7tu+30quz5V3k0b1YNuc6lw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"abort-controller": "^3.0.0",
|
"abort-controller": "^3.0.0",
|
||||||
"eventsource": "^2.0.2",
|
"eventsource": "^2.0.2",
|
||||||
|
|
@ -4132,9 +4132,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.23.1",
|
"version": "4.23.2",
|
||||||
"resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.23.1.tgz",
|
"resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.23.2.tgz",
|
||||||
"integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==",
|
"integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -4151,10 +4151,10 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"caniuse-lite": "^1.0.30001629",
|
"caniuse-lite": "^1.0.30001640",
|
||||||
"electron-to-chromium": "^1.4.796",
|
"electron-to-chromium": "^1.4.820",
|
||||||
"node-releases": "^2.0.14",
|
"node-releases": "^2.0.14",
|
||||||
"update-browserslist-db": "^1.0.16"
|
"update-browserslist-db": "^1.1.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"browserslist": "cli.js"
|
"browserslist": "cli.js"
|
||||||
|
|
@ -4393,9 +4393,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001640",
|
"version": "1.0.30001641",
|
||||||
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz",
|
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001641.tgz",
|
||||||
"integrity": "sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==",
|
"integrity": "sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -5024,6 +5024,11 @@
|
||||||
"node": ">=12.10"
|
"node": ">=12.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/crypto-js": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
||||||
|
},
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz",
|
||||||
|
|
@ -6126,9 +6131,9 @@
|
||||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.819",
|
"version": "1.4.823",
|
||||||
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.819.tgz",
|
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.823.tgz",
|
||||||
"integrity": "sha512-8RwI6gKUokbHWcN3iRij/qpvf/wCbIVY5slODi85werwqUQwpFXM+dvUBND93Qh7SB0pW3Hlq3/wZsqQ3M9Jaw==",
|
"integrity": "sha512-4h+oPeAiGQOHFyUJOqpoEcPj/xxlicxBzOErVeYVMMmAiXUXsGpsFd0QXBMaUUbnD8hhSfLf9uw+MlsoIA7j5w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/electron-winstaller": {
|
"node_modules/electron-winstaller": {
|
||||||
|
|
@ -8847,11 +8852,6 @@
|
||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/js-md5": {
|
|
||||||
"version": "0.8.3",
|
|
||||||
"resolved": "https://registry.npmmirror.com/js-md5/-/js-md5-0.8.3.tgz",
|
|
||||||
"integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ=="
|
|
||||||
},
|
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
|
@ -11200,9 +11200,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rc-picker": {
|
"node_modules/rc-picker": {
|
||||||
"version": "4.6.7",
|
"version": "4.6.8",
|
||||||
"resolved": "https://registry.npmmirror.com/rc-picker/-/rc-picker-4.6.7.tgz",
|
"resolved": "https://registry.npmmirror.com/rc-picker/-/rc-picker-4.6.8.tgz",
|
||||||
"integrity": "sha512-ZntxLH863jdNPZq2i6e2+1iXpRfYKHjNfUGgoObA1YExuWAnTCHpZzOkBuS43GnVcnp2MPDp78pH9OZJFd2hLw==",
|
"integrity": "sha512-Lq2m68YGcmWXhzAmxTcL3vOjik7NQjcZ6fmZqBlgdrMCg3VnuKHmtk5CHGWd3wCiy2qNxSYIqWAidB1EQViPpQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.24.7",
|
"@babel/runtime": "^7.24.7",
|
||||||
"@rc-component/trigger": "^2.0.0",
|
"@rc-component/trigger": "^2.0.0",
|
||||||
|
|
@ -12311,9 +12311,9 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/sass": {
|
"node_modules/sass": {
|
||||||
"version": "1.77.6",
|
"version": "1.77.7",
|
||||||
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.77.6.tgz",
|
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.77.7.tgz",
|
||||||
"integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==",
|
"integrity": "sha512-9ywH75cO+rLjbrZ6en3Gp8qAMwPGBapFtlsMJoDTkcMU/bSe5a6cjKVUn5Jr4Gzg5GbP3HE8cm+02pLCgcoMow==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": ">=3.0.0 <4.0.0",
|
"chokidar": ">=3.0.0 <4.0.0",
|
||||||
"immutable": "^4.0.0",
|
"immutable": "^4.0.0",
|
||||||
|
|
@ -15660,9 +15660,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@jridgewell/sourcemap-codec": {
|
"@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.15",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@jridgewell/trace-mapping": {
|
"@jridgewell/trace-mapping": {
|
||||||
|
|
@ -15685,9 +15685,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@microsoft/signalr": {
|
"@microsoft/signalr": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.7",
|
||||||
"resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.7.tgz",
|
||||||
"integrity": "sha512-K/wS/VmzRWePCGqGh8MU8OWbS1Zvu7DG7LSJS62fBB8rJUXwwj4axQtqrAAwKGUZHQF6CuteuQR9xMsVpM2JNA==",
|
"integrity": "sha512-PHcdMv8v5hJlBkRHAuKG5trGViQEkPYee36LnJQx4xHOQ5LL4X0nEWIxOp5cCtZ7tu+30quz5V3k0b1YNuc6lw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"abort-controller": "^3.0.0",
|
"abort-controller": "^3.0.0",
|
||||||
"eventsource": "^2.0.2",
|
"eventsource": "^2.0.2",
|
||||||
|
|
@ -17419,15 +17419,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"version": "4.23.1",
|
"version": "4.23.2",
|
||||||
"resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.23.1.tgz",
|
"resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.23.2.tgz",
|
||||||
"integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==",
|
"integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"caniuse-lite": "^1.0.30001629",
|
"caniuse-lite": "^1.0.30001640",
|
||||||
"electron-to-chromium": "^1.4.796",
|
"electron-to-chromium": "^1.4.820",
|
||||||
"node-releases": "^2.0.14",
|
"node-releases": "^2.0.14",
|
||||||
"update-browserslist-db": "^1.0.16"
|
"update-browserslist-db": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"buffer": {
|
"buffer": {
|
||||||
|
|
@ -17604,9 +17604,9 @@
|
||||||
"integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg=="
|
"integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg=="
|
||||||
},
|
},
|
||||||
"caniuse-lite": {
|
"caniuse-lite": {
|
||||||
"version": "1.0.30001640",
|
"version": "1.0.30001641",
|
||||||
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz",
|
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001641.tgz",
|
||||||
"integrity": "sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==",
|
"integrity": "sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"canvas-size": {
|
"canvas-size": {
|
||||||
|
|
@ -18073,6 +18073,11 @@
|
||||||
"integrity": "sha512-n63i0lZ0rvQ6FXiGQ+/JFCKAUyPFhLQYJIqKaa+tSJtfKeULF/IDNDAbdnSIxgS4NTuw2b0+lj8LzfITuq+ZxQ==",
|
"integrity": "sha512-n63i0lZ0rvQ6FXiGQ+/JFCKAUyPFhLQYJIqKaa+tSJtfKeULF/IDNDAbdnSIxgS4NTuw2b0+lj8LzfITuq+ZxQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"crypto-js": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
||||||
|
},
|
||||||
"csstype": {
|
"csstype": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz",
|
||||||
|
|
@ -18973,9 +18978,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.4.819",
|
"version": "1.4.823",
|
||||||
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.819.tgz",
|
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.823.tgz",
|
||||||
"integrity": "sha512-8RwI6gKUokbHWcN3iRij/qpvf/wCbIVY5slODi85werwqUQwpFXM+dvUBND93Qh7SB0pW3Hlq3/wZsqQ3M9Jaw==",
|
"integrity": "sha512-4h+oPeAiGQOHFyUJOqpoEcPj/xxlicxBzOErVeYVMMmAiXUXsGpsFd0QXBMaUUbnD8hhSfLf9uw+MlsoIA7j5w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"electron-winstaller": {
|
"electron-winstaller": {
|
||||||
|
|
@ -20916,11 +20921,6 @@
|
||||||
"is-object": "^1.0.1"
|
"is-object": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"js-md5": {
|
|
||||||
"version": "0.8.3",
|
|
||||||
"resolved": "https://registry.npmmirror.com/js-md5/-/js-md5-0.8.3.tgz",
|
|
||||||
"integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ=="
|
|
||||||
},
|
|
||||||
"js-tokens": {
|
"js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
|
@ -22669,9 +22669,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rc-picker": {
|
"rc-picker": {
|
||||||
"version": "4.6.7",
|
"version": "4.6.8",
|
||||||
"resolved": "https://registry.npmmirror.com/rc-picker/-/rc-picker-4.6.7.tgz",
|
"resolved": "https://registry.npmmirror.com/rc-picker/-/rc-picker-4.6.8.tgz",
|
||||||
"integrity": "sha512-ZntxLH863jdNPZq2i6e2+1iXpRfYKHjNfUGgoObA1YExuWAnTCHpZzOkBuS43GnVcnp2MPDp78pH9OZJFd2hLw==",
|
"integrity": "sha512-Lq2m68YGcmWXhzAmxTcL3vOjik7NQjcZ6fmZqBlgdrMCg3VnuKHmtk5CHGWd3wCiy2qNxSYIqWAidB1EQViPpQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.24.7",
|
"@babel/runtime": "^7.24.7",
|
||||||
"@rc-component/trigger": "^2.0.0",
|
"@rc-component/trigger": "^2.0.0",
|
||||||
|
|
@ -23430,9 +23430,9 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"sass": {
|
"sass": {
|
||||||
"version": "1.77.6",
|
"version": "1.77.7",
|
||||||
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.77.6.tgz",
|
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.77.7.tgz",
|
||||||
"integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==",
|
"integrity": "sha512-9ywH75cO+rLjbrZ6en3Gp8qAMwPGBapFtlsMJoDTkcMU/bSe5a6cjKVUn5Jr4Gzg5GbP3HE8cm+02pLCgcoMow==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"chokidar": ">=3.0.0 <4.0.0",
|
"chokidar": ">=3.0.0 <4.0.0",
|
||||||
"immutable": "^4.0.0",
|
"immutable": "^4.0.0",
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,9 @@
|
||||||
"agora-electron-sdk": "^4.3.2",
|
"agora-electron-sdk": "^4.3.2",
|
||||||
"antd": "^5.18.2",
|
"antd": "^5.18.2",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
"electron-squirrel-startup": "^1.0.1",
|
"electron-squirrel-startup": "^1.0.1",
|
||||||
"js-md5": "^0.8.3",
|
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.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",
|
||||||
|
|
|
||||||
343
preload.js
343
preload.js
|
|
@ -1,321 +1,24 @@
|
||||||
// 在 preload 脚本中。
|
// // 在 preload 脚本中。
|
||||||
const { ipcRenderer, contextBridge } = require('electron')
|
const { ipcRenderer } = require('electron')
|
||||||
const {
|
window.electron = {
|
||||||
createAgoraRtcEngine,
|
// 设置窗口大小
|
||||||
ClientRoleType,
|
setMainWindowSize: (config) => {
|
||||||
VideoSourceType,
|
ipcRenderer.invoke('setMainWindowSize', { ...config })
|
||||||
VideoViewSetupMode,
|
},
|
||||||
ScreenCaptureSourceType,
|
// 设置窗口状态
|
||||||
RenderModeType,
|
setViewStatus: (status) => {
|
||||||
ChannelProfileType,
|
ipcRenderer.invoke('setViewStatus', status)
|
||||||
MediaRecorderContainerFormat,
|
},
|
||||||
MediaRecorderStreamType
|
// 获取当前是否全屏
|
||||||
} = require("agora-electron-sdk");
|
getIsMaximized: () => {
|
||||||
const { message } = require('antd');
|
return ipcRenderer.invoke('getIsMaximized')
|
||||||
const rtcEngine = createAgoraRtcEngine();
|
},
|
||||||
const option = {
|
// 复制文字
|
||||||
appId: 'dcfc466a6ecb4a1f972630065dfb1e75',
|
setWriteText: (text) => {
|
||||||
token: '',
|
return ipcRenderer.invoke('setWriteText', text)
|
||||||
channelId: '',
|
},
|
||||||
userid: '',
|
// 下载文件并放置选择的文件夹
|
||||||
}
|
dwFile: (url) => {
|
||||||
rtcEngine.initialize({
|
ipcRenderer.invoke('dwFile', url)
|
||||||
appId: option.appId,
|
|
||||||
});
|
|
||||||
|
|
||||||
let videoID = '';
|
|
||||||
let iMediaRecorder = '';
|
|
||||||
|
|
||||||
const getDom = () => {
|
|
||||||
return document.getElementById('video-1');
|
|
||||||
}
|
|
||||||
// 离开频道
|
|
||||||
const leaveChannel = () => {
|
|
||||||
rtcEngine.leaveChannel({
|
|
||||||
stopAudioMixing: true,
|
|
||||||
stopAllEffect: true,
|
|
||||||
stopMicrophoneRecording: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 离开频道
|
|
||||||
const joinChannel = (bool) => {
|
|
||||||
if (bool) {
|
|
||||||
rtcEngine.joinChannel(option.token, option.channelId, option.userid, {
|
|
||||||
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景
|
|
||||||
clientRoleType: ClientRoleType.ClientRoleBroadcaster, //用户角色 1主播 2观众
|
|
||||||
publishMicrophoneTrack: true, //设置是否发布麦克风采集到的音频
|
|
||||||
publishCameraTrack: false, //设置是否发布摄像头采集的视频
|
|
||||||
publishScreenTrack: true, //设置是否发布屏幕采集的视频
|
|
||||||
autoSubscribeAudio: true, //设置是否自动订阅所有音频流
|
|
||||||
autoSubscribeVideo: true, //设置是否自动订阅所有视频流
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
rtcEngine.joinChannel(option.token, option.channelId, option.userid, {
|
|
||||||
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景
|
|
||||||
clientRoleType: ClientRoleType.ClientRoleBroadcaster, //设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可
|
|
||||||
publishMicrophoneTrack: true, //发布麦克风采集的音频
|
|
||||||
publishCameraTrack: true, //发布摄像头采集的视频
|
|
||||||
publishScreenTrack: false, //设置是否发布屏幕采集的视频
|
|
||||||
autoSubscribeAudio: true, //自动订阅所有音频流
|
|
||||||
autoSubscribeVideo: true, //自动订阅所有视频流
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 停止共享屏幕
|
|
||||||
const stopScreenCapture = () => {
|
|
||||||
rtcEngine.stopScreenCapture();
|
|
||||||
}
|
|
||||||
|
|
||||||
rtcEngine.registerEventHandler({
|
|
||||||
// 监听本地用户加入频道事件
|
|
||||||
onJoinChannelSuccess: ({ channelId, localUid }, elapsed) => {
|
|
||||||
console.log({ channelId, localUid }, elapsed, '加入房间');
|
|
||||||
// 本地用户加入频道后,设置本地视频窗口
|
|
||||||
rtcEngine.setupLocalVideo({
|
|
||||||
renderMode: RenderModeType.RenderModeFit,
|
|
||||||
// sourceType: VideoSourceType.VideoSourceScreen,
|
|
||||||
sourceType: VideoSourceType.VideoSourceCameraPrimary,
|
|
||||||
uid: localUid,
|
|
||||||
view: getDom(),
|
|
||||||
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 监听远端用户加入频道事件
|
|
||||||
onUserJoined: ({ channelId, localUid }, remoteUid, elapsed) => {
|
|
||||||
// 远端用户加入频道后,设置远端视频窗口
|
|
||||||
rtcEngine.setupRemoteVideo(
|
|
||||||
{
|
|
||||||
renderMode: RenderModeType.RenderModeFit,
|
|
||||||
sourceType: VideoSourceType.VideoSourceRemote,
|
|
||||||
uid: remoteUid,
|
|
||||||
view: getDom(),
|
|
||||||
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
|
|
||||||
},
|
|
||||||
{ channelId },
|
|
||||||
);
|
|
||||||
|
|
||||||
},
|
|
||||||
// 视频发布状态改变回调
|
|
||||||
onVideoPublishStateChanged: (source, channel, oldState, newState, elapseSinceLastState) => {
|
|
||||||
if (newState === 1) {
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 音频发布状态改变回调
|
|
||||||
onAudioPublishStateChanged: (channel, oldState, newState, elapseSinceLastState) => {
|
|
||||||
if (newState === 1) {
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 监听用户离开频道事件
|
|
||||||
onUserOffline: ({ channelId, localUid }, remoteUid, reason) => {
|
|
||||||
// 远端用户离开频道后,关闭远端视频窗口
|
|
||||||
rtcEngine.setupRemoteVideo(
|
|
||||||
{
|
|
||||||
renderMode: RenderModeType.RenderModeFit,
|
|
||||||
sourceType: VideoSourceType.VideoSourceRemote,
|
|
||||||
uid: remoteUid,
|
|
||||||
view: getDom(),
|
|
||||||
setupMode: VideoViewSetupMode.VideoViewSetupRemove,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// 用户音量提示回调。
|
|
||||||
onAudioVolumeIndication: (connection, speakers, speakerNumber, totalVolume) => {
|
|
||||||
const percentage = (totalVolume / 255) * 100
|
|
||||||
if (document.getElementById('recordingDeviceTest')) {
|
|
||||||
document.getElementById('recordingDeviceTest').style.width = `${percentage}%`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'electron',
|
|
||||||
{
|
|
||||||
// 桌面捕获音频和视频的媒体源的信息
|
|
||||||
getDesktopCapturerVideo: async () => {
|
|
||||||
return rtcEngine.getScreenCaptureSources({ width: 300, height: 300 }, { width: 300, height: 300 }, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 共享屏幕采集
|
|
||||||
setDesktopCapturerVideo: (targetSource) => {
|
|
||||||
stopScreenCapture()
|
|
||||||
if (
|
|
||||||
targetSource.type ===
|
|
||||||
ScreenCaptureSourceType.ScreencapturesourcetypeScreen
|
|
||||||
) {
|
|
||||||
rtcEngine.startScreenCaptureByDisplayId(
|
|
||||||
targetSource.sourceId,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
windowFocus: true,
|
|
||||||
enableHighLight: true,
|
|
||||||
highLightColor: 0xFF99CC00,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
rtcEngine.startScreenCaptureByWindowId(
|
|
||||||
targetSource.sourceId,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
windowFocus: true,
|
|
||||||
enableHighLight: true,
|
|
||||||
highLightColor: 0xFF99CC00,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
joinChannel(true)
|
|
||||||
},
|
|
||||||
// 摄像头采集
|
|
||||||
setCameraCapture: () => {
|
|
||||||
rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {})
|
|
||||||
joinChannel(false)
|
|
||||||
},
|
|
||||||
// 加入频道
|
|
||||||
setJoinChannel: (data) => {
|
|
||||||
option.token = data.token;
|
|
||||||
option.channelId = data.channelId;
|
|
||||||
option.userid = Number(data.userid);
|
|
||||||
rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {})
|
|
||||||
joinChannel(false)
|
|
||||||
},
|
|
||||||
// 离开频道
|
|
||||||
leaveChannel: () => {
|
|
||||||
leaveChannel()
|
|
||||||
},
|
|
||||||
// 停止共享屏幕
|
|
||||||
stopScreenCapture: () => {
|
|
||||||
stopScreenCapture()
|
|
||||||
},
|
|
||||||
// 取消或恢复发布本地音频流
|
|
||||||
muteLocalAudioStream: (mute) => {
|
|
||||||
rtcEngine.muteLocalAudioStream(mute)
|
|
||||||
},
|
|
||||||
// 取消或恢复发布本地视频流
|
|
||||||
muteLocalVideoStream: (mute) => {
|
|
||||||
rtcEngine.muteLocalVideoStream(mute)
|
|
||||||
},
|
|
||||||
// 获取当前生成的视频id
|
|
||||||
getVideoId: () => {
|
|
||||||
return videoID;
|
|
||||||
},
|
|
||||||
// 获取音频设备列表
|
|
||||||
getAudioMediaList: () => {
|
|
||||||
return {
|
|
||||||
currentDevice: rtcEngine.getAudioDeviceManager().getRecordingDefaultDevice(),
|
|
||||||
currentDevices: rtcEngine.getAudioDeviceManager().enumerateRecordingDevices(),
|
|
||||||
currentVolume: rtcEngine.getAudioDeviceManager().getRecordingDeviceVolume()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 设置音频设备音量
|
|
||||||
setRecordingDeviceVolume: (volume) => {
|
|
||||||
rtcEngine.getAudioDeviceManager().setRecordingDeviceVolume(volume)
|
|
||||||
},
|
|
||||||
// 设置音频采集设备
|
|
||||||
setRecordingDevice: (deviceId) => {
|
|
||||||
rtcEngine.getAudioDeviceManager().setRecordingDevice(deviceId)
|
|
||||||
},
|
|
||||||
// 启动音频采集设备测试
|
|
||||||
startRecordingDeviceTest: (indicationInterval) => {
|
|
||||||
rtcEngine.getAudioDeviceManager().startRecordingDeviceTest(indicationInterval)
|
|
||||||
navigator.mediaDevices.getUserMedia({ audio: true })
|
|
||||||
.then((stream) => {
|
|
||||||
let dom = document.getElementById('startAudio');
|
|
||||||
dom.srcObject = stream;
|
|
||||||
dom.play()
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
message.error('无法获取麦克风!');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 停止音频设备回路测试
|
|
||||||
stopAudioDeviceLoopbackTest: () => {
|
|
||||||
rtcEngine.getAudioDeviceManager().stopAudioDeviceLoopbackTest()
|
|
||||||
rtcEngine.getAudioDeviceManager().stopRecordingDeviceTest()
|
|
||||||
let video = document.getElementById('startPreview');
|
|
||||||
if (video.srcObject) {
|
|
||||||
const tracks = video.srcObject.getTracks();
|
|
||||||
tracks.forEach((track) => {
|
|
||||||
track.stop();
|
|
||||||
});
|
|
||||||
video.srcObject = null;
|
|
||||||
}
|
|
||||||
let audio = document.getElementById('startAudio');
|
|
||||||
if (audio.srcObject) {
|
|
||||||
const tracks = audio.srcObject.getTracks();
|
|
||||||
tracks.forEach((track) => {
|
|
||||||
track.stop();
|
|
||||||
});
|
|
||||||
audio.srcObject = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 开启本地视频预览
|
|
||||||
startPreview: async () => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
navigator.mediaDevices.getUserMedia({
|
|
||||||
video: true,
|
|
||||||
audio: true,
|
|
||||||
}).then((stream) => {
|
|
||||||
let dom = document.getElementById('startPreview');
|
|
||||||
dom.srcObject = stream;
|
|
||||||
dom.play()
|
|
||||||
resolve(true)
|
|
||||||
}).catch((error) => {
|
|
||||||
message.error('无法获取摄像头!');
|
|
||||||
resolve(true)
|
|
||||||
});
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 开始录制音视频
|
|
||||||
startRecording: () => {
|
|
||||||
iMediaRecorder = rtcEngine.createMediaRecorder({
|
|
||||||
channelId: option.channelId,
|
|
||||||
uid: 123,
|
|
||||||
})
|
|
||||||
iMediaRecorder.setMediaRecorderObserver({
|
|
||||||
// 录制状态发生改变回调。
|
|
||||||
onRecorderStateChanged: (channelId, uid, state, reason) => {
|
|
||||||
console.log(channelId, uid, state, reason, '录制状态发生改变回调。');
|
|
||||||
},
|
|
||||||
// 录制信息更新回调。
|
|
||||||
onRecorderInfoUpdated: (channelId, uid, info) => {
|
|
||||||
console.log(channelId, uid, info, '录制信息更新回调。');
|
|
||||||
},
|
|
||||||
})
|
|
||||||
iMediaRecorder.startRecording({
|
|
||||||
storagePath: `D:/word/${+new Date()}.mp4`, //录音文件在本地保存的绝对路径,需精确到文件名及格式
|
|
||||||
containerFormat: MediaRecorderContainerFormat.FormatMp4, //录制文件的格式
|
|
||||||
streamType: MediaRecorderStreamType.StreamTypeBoth, //录制内容
|
|
||||||
maxDurationMs: 7200000, //maxDurationMs
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 停止录制音视频
|
|
||||||
stopRecording: () => {
|
|
||||||
iMediaRecorder.stopRecording()
|
|
||||||
rtcEngine.destroyMediaRecorder(iMediaRecorder)
|
|
||||||
iMediaRecorder = ""
|
|
||||||
},
|
|
||||||
// 设置窗口大小
|
|
||||||
setMainWindowSize: (config) => {
|
|
||||||
ipcRenderer.invoke('setMainWindowSize', { ...config })
|
|
||||||
},
|
|
||||||
// 设置窗口状态
|
|
||||||
setViewStatus: (status) => {
|
|
||||||
ipcRenderer.invoke('setViewStatus', status)
|
|
||||||
},
|
|
||||||
// 获取当前是否全屏
|
|
||||||
getIsMaximized: () => {
|
|
||||||
return ipcRenderer.invoke('getIsMaximized')
|
|
||||||
},
|
|
||||||
// 复制文字
|
|
||||||
setWriteText: (text) => {
|
|
||||||
return ipcRenderer.invoke('setWriteText', text)
|
|
||||||
},
|
|
||||||
// 下载文件并放置选择的文件夹
|
|
||||||
dwFile: (url) => {
|
|
||||||
ipcRenderer.invoke('dwFile', url)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
@ -24,3 +24,9 @@ export const GetRoomRtcToken = (roomNum: string) =>
|
||||||
method: 'get',
|
method: 'get',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const GetRoomInfo = (roomNum: string) =>
|
||||||
|
request({
|
||||||
|
url: `/room/${roomNum}`,
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ export const GetRoomUpFileurl = (roomNum: string, fileSuffix: string) =>
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
|
|
||||||
export const GetRoomFileDwUrl = (fileUrl: string) =>
|
export const GetRoomFileDwUrl = (fileUrl: string, fileId: string) =>
|
||||||
request({
|
request({
|
||||||
url: `/room/file-dw-url?fileUrl=${fileUrl}`,
|
url: `/room/file-dw-url?fileUrl=${fileUrl}&fileId=${fileId}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { useEffect, useState } from "react";
|
||||||
import Operation from '@/components/Operation';
|
import Operation from '@/components/Operation';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { Button, Input, Modal, Pagination, Empty, message } from "antd";
|
import { Button, Input, Modal, Pagination, Empty, message } from "antd";
|
||||||
import { GetRoom, PostRomm, GetCheckoutRoomNum, GetRoomRtcToken } from '@/api/Home/Index';
|
import { GetRoom, PostRomm, GetCheckoutRoomNum, GetRoomRtcToken, GetRoomInfo } from '@/api/Home/Index';
|
||||||
const Index: React.FC = () => {
|
const Index: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [list, setList] = useState({
|
const [list, setList] = useState({
|
||||||
|
|
@ -119,7 +119,8 @@ const Index: React.FC = () => {
|
||||||
navigate(`/meeting`, {
|
navigate(`/meeting`, {
|
||||||
state: {
|
state: {
|
||||||
channelId: item.roomNum,
|
channelId: item.roomNum,
|
||||||
token: res
|
token: res,
|
||||||
|
roomId: item.id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -249,12 +250,18 @@ const Index: React.FC = () => {
|
||||||
}
|
}
|
||||||
isGetCheckoutRoomNum(joinRoomFrom, (bool: boolean) => {
|
isGetCheckoutRoomNum(joinRoomFrom, (bool: boolean) => {
|
||||||
if (bool) {
|
if (bool) {
|
||||||
getRoomRtcToken(joinRoomFrom, (res: any) => {
|
getRoomRtcToken(joinRoomFrom, (token: string) => {
|
||||||
if (res) {
|
if (token) {
|
||||||
navigate(`/meeting`, {
|
setJoinRoomModal(false)
|
||||||
state: {
|
GetRoomInfo(joinRoomFrom).then(res => {
|
||||||
channelId: joinRoomFrom,
|
if (res.code === 200) {
|
||||||
token: res
|
navigate(`/meeting`, {
|
||||||
|
state: {
|
||||||
|
channelId: joinRoomFrom,
|
||||||
|
token,
|
||||||
|
roomId: res.data.id
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import Operation from '@/components/Operation';
|
||||||
import { Button, Input, Table, Pagination, Modal, message, Select } from "antd";
|
import { Button, Input, Table, Pagination, Modal, message, Select } from "antd";
|
||||||
import { SearchOutlined } from '@ant-design/icons';
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
import { GetUserList, PostUser, PutUser, DeleteUser, PutUserPwd, GetRoleDpList } from '@/api/Home/User';
|
import { GetUserList, PostUser, PutUser, DeleteUser, PutUserPwd, GetRoleDpList } from '@/api/Home/User';
|
||||||
import { md5 } from 'js-md5';
|
import * as CryptoJS from 'crypto-js';
|
||||||
const { Column } = Table
|
const { Column } = Table
|
||||||
const User: React.FC = () => {
|
const User: React.FC = () => {
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||||
|
|
@ -288,7 +288,7 @@ const User: React.FC = () => {
|
||||||
if (isCreateUser) {
|
if (isCreateUser) {
|
||||||
await PostUser({
|
await PostUser({
|
||||||
...addUserFrom,
|
...addUserFrom,
|
||||||
Pwd: md5(addUserFrom.Pwd)
|
Pwd: CryptoJS.MD5(addUserFrom.Pwd).toString(CryptoJS.enc.Hex)
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
setAddUserModal(false)
|
setAddUserModal(false)
|
||||||
|
|
@ -356,7 +356,8 @@ const User: React.FC = () => {
|
||||||
if (changeUserPawFrom.Pwd !== changeUserPawFrom.newPwd) {
|
if (changeUserPawFrom.Pwd !== changeUserPawFrom.newPwd) {
|
||||||
return message.error('新密码与确认密码不一致!')
|
return message.error('新密码与确认密码不一致!')
|
||||||
}
|
}
|
||||||
await PutUserPwd({ id: addUserFrom.Id, pwd: md5(changeUserPawFrom.Pwd) }).then(res => {
|
|
||||||
|
await PutUserPwd({ id: addUserFrom.Id, pwd: CryptoJS.MD5(changeUserPawFrom.Pwd).toString(CryptoJS.enc.Hex) }).then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
setChangeUserPawModal(false)
|
setChangeUserPawModal(false)
|
||||||
message.success('修改成功')
|
message.success('修改成功')
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { useNavigate } from 'react-router-dom';
|
||||||
import { Input, Button, Checkbox, message } from "antd"
|
import { Input, Button, Checkbox, message } from "antd"
|
||||||
import { storage } from '@/utils'
|
import { storage } from '@/utils'
|
||||||
import { GetCheckUser, PostLogin } from '@/api/Login'
|
import { GetCheckUser, PostLogin } from '@/api/Login'
|
||||||
import { md5 } from 'js-md5';
|
import * as CryptoJS from 'crypto-js';
|
||||||
import { startSignalr } from '@/utils/package/signalr'
|
import { startSignalr } from '@/utils/package/signalr'
|
||||||
const Login: React.FC = () => {
|
const Login: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
@ -102,7 +102,7 @@ const Login: React.FC = () => {
|
||||||
const loginClick = (): void => {
|
const loginClick = (): void => {
|
||||||
PostLogin({
|
PostLogin({
|
||||||
account: operation.account,
|
account: operation.account,
|
||||||
pwd: md5(operation.password)
|
pwd: CryptoJS.MD5(operation.password).toString(CryptoJS.enc.Hex)
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
message.success('登录成功!')
|
message.success('登录成功!')
|
||||||
|
|
@ -118,8 +118,8 @@ const Login: React.FC = () => {
|
||||||
width: 1200,
|
width: 1200,
|
||||||
height: 800,
|
height: 800,
|
||||||
})
|
})
|
||||||
startSignalr()
|
|
||||||
navigate('/home')
|
navigate('/home')
|
||||||
|
startSignalr()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ const Meeting: React.FC = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isInit) {
|
if (isInit) {
|
||||||
setUser(JSON.parse(storage.getItem('user') as string))
|
setUser(JSON.parse(storage.getItem('user') as string))
|
||||||
// window.electron.setJoinChannel({
|
// window.agora.setJoinChannel({
|
||||||
// channelId: state.channelId,
|
// channelId: state.channelId,
|
||||||
// userid: user.userName,
|
// userid: user.userName,
|
||||||
// token: state.token,
|
// token: state.token,
|
||||||
|
|
@ -149,49 +149,49 @@ const Meeting: React.FC = () => {
|
||||||
setIsSharedScreenModal(true)
|
setIsSharedScreenModal(true)
|
||||||
break;
|
break;
|
||||||
case '停止共享':
|
case '停止共享':
|
||||||
window.electron.stopScreenCapture()
|
window.agora.stopScreenCapture()
|
||||||
footerListTemplate[itemIndex][rowIndex].title = '共享屏幕'
|
footerListTemplate[itemIndex][rowIndex].title = '共享屏幕'
|
||||||
break;
|
break;
|
||||||
case '关闭声音':
|
case '关闭声音':
|
||||||
footerListTemplate[itemIndex][rowIndex].title = '开启声音'
|
footerListTemplate[itemIndex][rowIndex].title = '开启声音'
|
||||||
footerListTemplate[itemIndex][rowIndex].active = true
|
footerListTemplate[itemIndex][rowIndex].active = true
|
||||||
setFooterList(footerListTemplate)
|
setFooterList(footerListTemplate)
|
||||||
window.electron.muteLocalAudioStream(true)
|
window.agora.muteLocalAudioStream(true)
|
||||||
break;
|
break;
|
||||||
case '开启声音':
|
case '开启声音':
|
||||||
footerListTemplate[itemIndex][rowIndex].title = '关闭声音'
|
footerListTemplate[itemIndex][rowIndex].title = '关闭声音'
|
||||||
footerListTemplate[itemIndex][rowIndex].active = false
|
footerListTemplate[itemIndex][rowIndex].active = false
|
||||||
setFooterList(footerListTemplate)
|
setFooterList(footerListTemplate)
|
||||||
window.electron.muteLocalAudioStream(false)
|
window.agora.muteLocalAudioStream(false)
|
||||||
break;
|
break;
|
||||||
case '关闭视频':
|
case '关闭视频':
|
||||||
footerListTemplate[itemIndex][rowIndex].title = '开启视频'
|
footerListTemplate[itemIndex][rowIndex].title = '开启视频'
|
||||||
footerListTemplate[itemIndex][rowIndex].active = true
|
footerListTemplate[itemIndex][rowIndex].active = true
|
||||||
setFooterList(footerListTemplate)
|
setFooterList(footerListTemplate)
|
||||||
window.electron.muteLocalVideoStream(true)
|
window.agora.muteLocalVideoStream(true)
|
||||||
break;
|
break;
|
||||||
case '开启视频':
|
case '开启视频':
|
||||||
footerListTemplate[itemIndex][rowIndex].title = '关闭视频'
|
footerListTemplate[itemIndex][rowIndex].title = '关闭视频'
|
||||||
footerListTemplate[itemIndex][rowIndex].active = false
|
footerListTemplate[itemIndex][rowIndex].active = false
|
||||||
setFooterList(footerListTemplate)
|
setFooterList(footerListTemplate)
|
||||||
window.electron.muteLocalVideoStream(false)
|
window.agora.muteLocalVideoStream(false)
|
||||||
break;
|
break;
|
||||||
case '设置向导':
|
case '设置向导':
|
||||||
getAudioMediaList()
|
getAudioMediaList()
|
||||||
window.electron.startRecordingDeviceTest(200)
|
window.agora.startRecordingDeviceTest(200)
|
||||||
setIsStupWizard(true)
|
setIsStupWizard(true)
|
||||||
break;
|
break;
|
||||||
case '录制':
|
case '录制':
|
||||||
footerListTemplate[itemIndex][rowIndex].title = '录制中'
|
footerListTemplate[itemIndex][rowIndex].title = '录制中'
|
||||||
footerListTemplate[itemIndex][rowIndex].active = true
|
footerListTemplate[itemIndex][rowIndex].active = true
|
||||||
setFooterList(footerListTemplate)
|
setFooterList(footerListTemplate)
|
||||||
window.electron.startRecording()
|
window.agora.startRecording()
|
||||||
break;
|
break;
|
||||||
case '录制中':
|
case '录制中':
|
||||||
footerListTemplate[itemIndex][rowIndex].title = '录制'
|
footerListTemplate[itemIndex][rowIndex].title = '录制'
|
||||||
footerListTemplate[itemIndex][rowIndex].active = false
|
footerListTemplate[itemIndex][rowIndex].active = false
|
||||||
setFooterList(footerListTemplate)
|
setFooterList(footerListTemplate)
|
||||||
window.electron.stopRecording()
|
window.agora.stopRecording()
|
||||||
break;
|
break;
|
||||||
case '共享文件':
|
case '共享文件':
|
||||||
await getRoomFile()
|
await getRoomFile()
|
||||||
|
|
@ -209,8 +209,8 @@ const Meeting: React.FC = () => {
|
||||||
const footerListTemplate = [...footerList]
|
const footerListTemplate = [...footerList]
|
||||||
footerListTemplate[footerListIndex.itemIndex][footerListIndex.rowIndex].title = '停止共享'
|
footerListTemplate[footerListIndex.itemIndex][footerListIndex.rowIndex].title = '停止共享'
|
||||||
setIsSharedScreenModal(false)
|
setIsSharedScreenModal(false)
|
||||||
window.electron.setDesktopCapturerVideo(sharedScreenItem)
|
window.agora.setDesktopCapturerVideo(sharedScreenItem)
|
||||||
setVideoID(window.electron.getVideoId())
|
setVideoID(window.agora.getVideoId())
|
||||||
} else {
|
} else {
|
||||||
message.error('请选择应用!')
|
message.error('请选择应用!')
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +218,7 @@ const Meeting: React.FC = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDesktopCapturerVideo = (): void => {
|
const getDesktopCapturerVideo = (): void => {
|
||||||
window.electron.getDesktopCapturerVideo().then((res: any) => {
|
window.agora.getDesktopCapturerVideo().then((res: any) => {
|
||||||
if (sharedScreenList.length !== res.length) {
|
if (sharedScreenList.length !== res.length) {
|
||||||
res.forEach((item: any) => {
|
res.forEach((item: any) => {
|
||||||
if (item.thumbImage.buffer) {
|
if (item.thumbImage.buffer) {
|
||||||
|
|
@ -234,7 +234,7 @@ const Meeting: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAudioMediaList = (): void => {
|
const getAudioMediaList = (): void => {
|
||||||
const { currentDevices, currentDevice, currentVolume } = window.electron.getAudioMediaList();
|
const { currentDevices, currentDevice, currentVolume } = window.agora.getAudioMediaList();
|
||||||
setAudioDeviceManager({
|
setAudioDeviceManager({
|
||||||
currentDevices: currentDevices.map((row: any) => {
|
currentDevices: currentDevices.map((row: any) => {
|
||||||
return {
|
return {
|
||||||
|
|
@ -252,7 +252,7 @@ const Meeting: React.FC = () => {
|
||||||
pageIndex: fileList.pageIndex,
|
pageIndex: fileList.pageIndex,
|
||||||
pageSize: fileList.pageSize,
|
pageSize: fileList.pageSize,
|
||||||
keyword: fileList.keyword,
|
keyword: fileList.keyword,
|
||||||
roomId: state.channelId
|
roomId: state.roomId
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
setFileList({
|
setFileList({
|
||||||
|
|
@ -400,13 +400,13 @@ const Meeting: React.FC = () => {
|
||||||
content={
|
content={
|
||||||
<div className='meetingContentFooterPopover'>
|
<div className='meetingContentFooterPopover'>
|
||||||
<div onClick={() => {
|
<div onClick={() => {
|
||||||
window.electron.leaveChannel()
|
window.agora.leaveChannel()
|
||||||
window.electron.stopScreenCapture()
|
window.agora.stopScreenCapture()
|
||||||
navigate(-1)
|
navigate(-1)
|
||||||
}}>全员结束会议</div>
|
}}>全员结束会议</div>
|
||||||
<div onClick={() => {
|
<div onClick={() => {
|
||||||
window.electron.leaveChannel()
|
window.agora.leaveChannel()
|
||||||
window.electron.stopScreenCapture()
|
window.agora.stopScreenCapture()
|
||||||
navigate(-1)
|
navigate(-1)
|
||||||
}}>仅自己离开</div>
|
}}>仅自己离开</div>
|
||||||
<div onClick={() => { setOpen(false) }}>取消</div>
|
<div onClick={() => { setOpen(false) }}>取消</div>
|
||||||
|
|
@ -477,7 +477,7 @@ const Meeting: React.FC = () => {
|
||||||
...audioDeviceManager,
|
...audioDeviceManager,
|
||||||
currentDevice: e
|
currentDevice: e
|
||||||
})
|
})
|
||||||
window.electron.setRecordingDevice(e);
|
window.agora.setRecordingDevice(e);
|
||||||
getAudioMediaList()
|
getAudioMediaList()
|
||||||
}} />;
|
}} />;
|
||||||
<audio src="" id='startAudio'></audio>
|
<audio src="" id='startAudio'></audio>
|
||||||
|
|
@ -489,7 +489,7 @@ const Meeting: React.FC = () => {
|
||||||
...audioDeviceManager,
|
...audioDeviceManager,
|
||||||
currentVolume: e
|
currentVolume: e
|
||||||
})
|
})
|
||||||
window.electron.setRecordingDeviceVolume(e)
|
window.agora.setRecordingDeviceVolume(e)
|
||||||
}} style={{ flexGrow: 1 }} />
|
}} style={{ flexGrow: 1 }} />
|
||||||
</div> :
|
</div> :
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -526,7 +526,7 @@ const Meeting: React.FC = () => {
|
||||||
audio.srcObject = null;
|
audio.srcObject = null;
|
||||||
}
|
}
|
||||||
setStepsStatus(false)
|
setStepsStatus(false)
|
||||||
window.electron.startPreview().then((res: boolean) => {
|
window.agora.startPreview().then((res: boolean) => {
|
||||||
setIsVideoLoad(res)
|
setIsVideoLoad(res)
|
||||||
})
|
})
|
||||||
}}>下一步</Button>
|
}}>下一步</Button>
|
||||||
|
|
@ -538,9 +538,9 @@ const Meeting: React.FC = () => {
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isVideoLoad) {
|
if (isVideoLoad) {
|
||||||
setIsVideoLoad(false)
|
setIsVideoLoad(false)
|
||||||
window.electron.stopAudioDeviceLoopbackTest()
|
window.agora.stopAudioDeviceLoopbackTest()
|
||||||
setStepsStatus(true)
|
setStepsStatus(true)
|
||||||
window.electron.startRecordingDeviceTest(200)
|
window.agora.startRecordingDeviceTest(200)
|
||||||
} else {
|
} else {
|
||||||
message.error('视频加载中!')
|
message.error('视频加载中!')
|
||||||
}
|
}
|
||||||
|
|
@ -551,8 +551,8 @@ const Meeting: React.FC = () => {
|
||||||
className='m-ant-btn'
|
className='m-ant-btn'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isVideoLoad) {
|
if (isVideoLoad) {
|
||||||
window.electron.stopAudioDeviceLoopbackTest()
|
window.agora.stopAudioDeviceLoopbackTest()
|
||||||
window.electron.setRecordingDeviceVolume(audioDeviceManager.currentVolume)
|
window.agora.setRecordingDeviceVolume(audioDeviceManager.currentVolume)
|
||||||
setIsStupWizard(false)
|
setIsStupWizard(false)
|
||||||
setStepsStatus(true)
|
setStepsStatus(true)
|
||||||
setIsVideoLoad(false)
|
setIsVideoLoad(false)
|
||||||
|
|
@ -654,7 +654,7 @@ const Meeting: React.FC = () => {
|
||||||
fileUrl: res.data.key,
|
fileUrl: res.data.key,
|
||||||
size: fileInfo.size,
|
size: fileInfo.size,
|
||||||
fileName: fileInfo.name,
|
fileName: fileInfo.name,
|
||||||
roomId: state.channelId
|
roomId: state.roomId
|
||||||
})
|
})
|
||||||
getRoomFile()
|
getRoomFile()
|
||||||
})
|
})
|
||||||
|
|
@ -696,7 +696,7 @@ const Meeting: React.FC = () => {
|
||||||
<Column title="操作" render={(item) => (
|
<Column title="操作" render={(item) => (
|
||||||
<>
|
<>
|
||||||
<VerticalAlignBottomOutlined title='下载' style={{ color: '#5575F2', cursor: 'pointer' }} onClick={() => {
|
<VerticalAlignBottomOutlined title='下载' style={{ color: '#5575F2', cursor: 'pointer' }} onClick={() => {
|
||||||
GetRoomFileDwUrl(item.fileUrl).then(res => {
|
GetRoomFileDwUrl(item.fileUrl, item.id).then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
window.electron.dwFile(res.data)
|
window.electron.dwFile(res.data)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,18 @@
|
||||||
// electron-env.d.ts
|
// electron-env.d.ts
|
||||||
export interface IElectronAPI {
|
export interface IElectronAPI {
|
||||||
|
setMainWindowSize: (config: any) => void;
|
||||||
|
setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize') => void;
|
||||||
|
getIsMaximized: () => Promise<boolean>;
|
||||||
|
setWriteText: (text: string) => void;
|
||||||
|
dwFile: (url: string) => void;
|
||||||
|
}
|
||||||
|
export interface Agora {
|
||||||
getDesktopCapturerVideo: () => Promise<void>;
|
getDesktopCapturerVideo: () => Promise<void>;
|
||||||
setDesktopCapturerVideo: (data: any) => void;
|
setDesktopCapturerVideo: (data: any) => void;
|
||||||
setCameraCapture: (data: any) => void;
|
setCameraCapture: (data: any) => void;
|
||||||
getAudioMediaList: () => { currentDevice: any, currentDevices: any, currentVolume: number };
|
getAudioMediaList: () => { currentDevice: any, currentDevices: any, currentVolume: number };
|
||||||
setRecordingDeviceVolume: (volume: number) => void;
|
setRecordingDeviceVolume: (volume: number) => void;
|
||||||
setRecordingDevice: (deviceId: string) => void;
|
setRecordingDevice: (deviceId: string) => void;
|
||||||
setMainWindowSize: (config: any) => void;
|
|
||||||
getIsMaximized: () => Promise<boolean>;
|
|
||||||
setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize') => void;
|
|
||||||
setJoinChannel: (data: { channelId: string, userid: string, token: string }) => Promise<void>;
|
setJoinChannel: (data: { channelId: string, userid: string, token: string }) => Promise<void>;
|
||||||
getVideoId: () => string;
|
getVideoId: () => string;
|
||||||
startRecordingDeviceTest: (indicationInterval: number) => void;
|
startRecordingDeviceTest: (indicationInterval: number) => void;
|
||||||
|
|
@ -20,12 +24,10 @@ export interface IElectronAPI {
|
||||||
stopScreenCapture: () => void;
|
stopScreenCapture: () => void;
|
||||||
muteLocalAudioStream: (mute: boolean) => void;
|
muteLocalAudioStream: (mute: boolean) => void;
|
||||||
muteLocalVideoStream: (mute: boolean) => void;
|
muteLocalVideoStream: (mute: boolean) => void;
|
||||||
setWriteText: (text: string) => void;
|
|
||||||
dwFile: (url: string) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
electron: IElectronAPI;
|
electron: IElectronAPI;
|
||||||
|
agora: Agora
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
declare module 'react-dom/client';
|
declare module 'react-dom/client';
|
||||||
|
declare module 'crypto-js';
|
||||||
|
|
@ -0,0 +1,295 @@
|
||||||
|
const {
|
||||||
|
createAgoraRtcEngine,
|
||||||
|
ClientRoleType,
|
||||||
|
VideoSourceType,
|
||||||
|
VideoViewSetupMode,
|
||||||
|
ScreenCaptureSourceType,
|
||||||
|
RenderModeType,
|
||||||
|
ChannelProfileType,
|
||||||
|
MediaRecorderContainerFormat,
|
||||||
|
MediaRecorderStreamType
|
||||||
|
} = require("agora-electron-sdk");
|
||||||
|
const { message } = require('antd');
|
||||||
|
const rtcEngine = createAgoraRtcEngine();
|
||||||
|
const option = {
|
||||||
|
appId: 'dcfc466a6ecb4a1f972630065dfb1e75',
|
||||||
|
token: '',
|
||||||
|
channelId: '',
|
||||||
|
userid: '',
|
||||||
|
}
|
||||||
|
rtcEngine.initialize({
|
||||||
|
appId: option.appId,
|
||||||
|
});
|
||||||
|
|
||||||
|
rtcEngine.registerEventHandler({
|
||||||
|
// 监听本地用户加入频道事件
|
||||||
|
onJoinChannelSuccess: ({ channelId, localUid }, elapsed) => {
|
||||||
|
console.log({ channelId, localUid }, elapsed, '加入房间');
|
||||||
|
// 本地用户加入频道后,设置本地视频窗口
|
||||||
|
rtcEngine.setupLocalVideo({
|
||||||
|
renderMode: RenderModeType.RenderModeFit,
|
||||||
|
// sourceType: VideoSourceType.VideoSourceScreen,
|
||||||
|
sourceType: VideoSourceType.VideoSourceCameraPrimary,
|
||||||
|
uid: localUid,
|
||||||
|
view: getDom(),
|
||||||
|
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 监听远端用户加入频道事件
|
||||||
|
onUserJoined: ({ channelId, localUid }, remoteUid, elapsed) => {
|
||||||
|
// 远端用户加入频道后,设置远端视频窗口
|
||||||
|
rtcEngine.setupRemoteVideo(
|
||||||
|
{
|
||||||
|
renderMode: RenderModeType.RenderModeFit,
|
||||||
|
sourceType: VideoSourceType.VideoSourceRemote,
|
||||||
|
uid: remoteUid,
|
||||||
|
view: getDom(),
|
||||||
|
setupMode: VideoViewSetupMode.VideoViewSetupAdd,
|
||||||
|
},
|
||||||
|
{ channelId },
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
// 视频发布状态改变回调
|
||||||
|
onVideoPublishStateChanged: (source, channel, oldState, newState, elapseSinceLastState) => {
|
||||||
|
if (newState === 1) {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 音频发布状态改变回调
|
||||||
|
onAudioPublishStateChanged: (channel, oldState, newState, elapseSinceLastState) => {
|
||||||
|
if (newState === 1) {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 监听用户离开频道事件
|
||||||
|
onUserOffline: ({ channelId, localUid }, remoteUid, reason) => {
|
||||||
|
// 远端用户离开频道后,关闭远端视频窗口
|
||||||
|
rtcEngine.setupRemoteVideo(
|
||||||
|
{
|
||||||
|
renderMode: RenderModeType.RenderModeFit,
|
||||||
|
sourceType: VideoSourceType.VideoSourceRemote,
|
||||||
|
uid: remoteUid,
|
||||||
|
view: getDom(),
|
||||||
|
setupMode: VideoViewSetupMode.VideoViewSetupRemove,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
// 用户音量提示回调。
|
||||||
|
onAudioVolumeIndication: (connection, speakers, speakerNumber, totalVolume) => {
|
||||||
|
const percentage = (totalVolume / 255) * 100
|
||||||
|
if (document.getElementById('recordingDeviceTest')) {
|
||||||
|
document.getElementById('recordingDeviceTest').style.width = `${percentage}%`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let videoID = '';
|
||||||
|
let iMediaRecorder = '';
|
||||||
|
|
||||||
|
const agora = {
|
||||||
|
getDom: () => {
|
||||||
|
return document.getElementById('video-1');
|
||||||
|
},
|
||||||
|
// 离开频道
|
||||||
|
leaveChannel: () => {
|
||||||
|
rtcEngine.leaveChannel({
|
||||||
|
stopAudioMixing: true,
|
||||||
|
stopAllEffect: true,
|
||||||
|
stopMicrophoneRecording: true,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 加入频道
|
||||||
|
joinChannel: (bool) => {
|
||||||
|
if (bool) {
|
||||||
|
rtcEngine.joinChannel(option.token, option.channelId, option.userid, {
|
||||||
|
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景
|
||||||
|
clientRoleType: ClientRoleType.ClientRoleBroadcaster, //用户角色 1主播 2观众
|
||||||
|
publishMicrophoneTrack: true, //设置是否发布麦克风采集到的音频
|
||||||
|
publishCameraTrack: false, //设置是否发布摄像头采集的视频
|
||||||
|
publishScreenTrack: true, //设置是否发布屏幕采集的视频
|
||||||
|
autoSubscribeAudio: true, //设置是否自动订阅所有音频流
|
||||||
|
autoSubscribeVideo: true, //设置是否自动订阅所有视频流
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
rtcEngine.joinChannel(option.token, option.channelId, option.userid, {
|
||||||
|
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景
|
||||||
|
clientRoleType: ClientRoleType.ClientRoleBroadcaster, //设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可
|
||||||
|
publishMicrophoneTrack: true, //发布麦克风采集的音频
|
||||||
|
publishCameraTrack: true, //发布摄像头采集的视频
|
||||||
|
publishScreenTrack: false, //设置是否发布屏幕采集的视频
|
||||||
|
autoSubscribeAudio: true, //自动订阅所有音频流
|
||||||
|
autoSubscribeVideo: true, //自动订阅所有视频流
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 停止录制音视频
|
||||||
|
stopRecording: () => {
|
||||||
|
iMediaRecorder.stopRecording()
|
||||||
|
rtcEngine.destroyMediaRecorder(iMediaRecorder)
|
||||||
|
iMediaRecorder = ""
|
||||||
|
},
|
||||||
|
// 开始录制音视频
|
||||||
|
startRecording: () => {
|
||||||
|
iMediaRecorder = rtcEngine.createMediaRecorder({
|
||||||
|
channelId: option.channelId,
|
||||||
|
uid: 123,
|
||||||
|
})
|
||||||
|
iMediaRecorder.setMediaRecorderObserver({
|
||||||
|
// 录制状态发生改变回调。
|
||||||
|
onRecorderStateChanged: (channelId, uid, state, reason) => {
|
||||||
|
console.log(channelId, uid, state, reason, '录制状态发生改变回调。');
|
||||||
|
},
|
||||||
|
// 录制信息更新回调。
|
||||||
|
onRecorderInfoUpdated: (channelId, uid, info) => {
|
||||||
|
console.log(channelId, uid, info, '录制信息更新回调。');
|
||||||
|
},
|
||||||
|
})
|
||||||
|
iMediaRecorder.startRecording({
|
||||||
|
storagePath: `D:/word/${+new Date()}.mp4`, //录音文件在本地保存的绝对路径,需精确到文件名及格式
|
||||||
|
containerFormat: MediaRecorderContainerFormat.FormatMp4, //录制文件的格式
|
||||||
|
streamType: MediaRecorderStreamType.StreamTypeBoth, //录制内容
|
||||||
|
maxDurationMs: 7200000, //maxDurationMs
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 停止共享屏幕
|
||||||
|
stopScreenCapture: () => {
|
||||||
|
rtcEngine.stopScreenCapture();
|
||||||
|
},
|
||||||
|
// 开启本地视频预览
|
||||||
|
startPreview: async () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
navigator.mediaDevices.getUserMedia({
|
||||||
|
video: true,
|
||||||
|
audio: true,
|
||||||
|
}).then((stream) => {
|
||||||
|
let dom = document.getElementById('startPreview');
|
||||||
|
dom.srcObject = stream;
|
||||||
|
dom.play()
|
||||||
|
resolve(true)
|
||||||
|
}).catch((error) => {
|
||||||
|
message.error('无法获取摄像头!');
|
||||||
|
resolve(true)
|
||||||
|
});
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 停止音频设备回路测试
|
||||||
|
stopAudioDeviceLoopbackTest: () => {
|
||||||
|
rtcEngine.getAudioDeviceManager().stopAudioDeviceLoopbackTest()
|
||||||
|
rtcEngine.getAudioDeviceManager().stopRecordingDeviceTest()
|
||||||
|
let video = document.getElementById('startPreview');
|
||||||
|
if (video.srcObject) {
|
||||||
|
const tracks = video.srcObject.getTracks();
|
||||||
|
tracks.forEach((track) => {
|
||||||
|
track.stop();
|
||||||
|
});
|
||||||
|
video.srcObject = null;
|
||||||
|
}
|
||||||
|
let audio = document.getElementById('startAudio');
|
||||||
|
if (audio.srcObject) {
|
||||||
|
const tracks = audio.srcObject.getTracks();
|
||||||
|
tracks.forEach((track) => {
|
||||||
|
track.stop();
|
||||||
|
});
|
||||||
|
audio.srcObject = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 启动音频采集设备测试
|
||||||
|
startRecordingDeviceTest: (indicationInterval) => {
|
||||||
|
rtcEngine.getAudioDeviceManager().startRecordingDeviceTest(indicationInterval)
|
||||||
|
navigator.mediaDevices.getUserMedia({ audio: true })
|
||||||
|
.then((stream) => {
|
||||||
|
let dom = document.getElementById('startAudio');
|
||||||
|
dom.srcObject = stream;
|
||||||
|
dom.play()
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
message.error('无法获取麦克风!');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 获取音频设备列表
|
||||||
|
getAudioMediaList: () => {
|
||||||
|
return {
|
||||||
|
currentDevice: rtcEngine.getAudioDeviceManager().getRecordingDefaultDevice(),
|
||||||
|
currentDevices: rtcEngine.getAudioDeviceManager().enumerateRecordingDevices(),
|
||||||
|
currentVolume: rtcEngine.getAudioDeviceManager().getRecordingDeviceVolume()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 设置音频设备音量
|
||||||
|
setRecordingDeviceVolume: (volume) => {
|
||||||
|
rtcEngine.getAudioDeviceManager().setRecordingDeviceVolume(volume)
|
||||||
|
},
|
||||||
|
// 设置音频采集设备
|
||||||
|
setRecordingDevice: (deviceId) => {
|
||||||
|
rtcEngine.getAudioDeviceManager().setRecordingDevice(deviceId)
|
||||||
|
},
|
||||||
|
// 摄像头采集
|
||||||
|
setCameraCapture: () => {
|
||||||
|
rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {})
|
||||||
|
// joinChannel(false)
|
||||||
|
},
|
||||||
|
// 加入频道
|
||||||
|
setJoinChannel: (data) => {
|
||||||
|
option.token = data.token;
|
||||||
|
option.channelId = data.channelId;
|
||||||
|
option.userid = Number(data.userid);
|
||||||
|
rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {})
|
||||||
|
// joinChannel(false)
|
||||||
|
},
|
||||||
|
// 离开频道
|
||||||
|
leaveChannel: () => {
|
||||||
|
// leaveChannel()
|
||||||
|
},
|
||||||
|
// 停止共享屏幕
|
||||||
|
stopScreenCapture: () => {
|
||||||
|
// stopScreenCapture()
|
||||||
|
},
|
||||||
|
// 取消或恢复发布本地音频流
|
||||||
|
muteLocalAudioStream: (mute) => {
|
||||||
|
rtcEngine.muteLocalAudioStream(mute)
|
||||||
|
},
|
||||||
|
// 取消或恢复发布本地视频流
|
||||||
|
muteLocalVideoStream: (mute) => {
|
||||||
|
rtcEngine.muteLocalVideoStream(mute)
|
||||||
|
},
|
||||||
|
// 获取当前生成的视频id
|
||||||
|
getVideoId: () => {
|
||||||
|
return videoID;
|
||||||
|
},
|
||||||
|
// 桌面捕获音频和视频的媒体源的信息
|
||||||
|
getDesktopCapturerVideo: async () => {
|
||||||
|
return rtcEngine.getScreenCaptureSources({ width: 300, height: 300 }, { width: 300, height: 300 }, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 共享屏幕采集
|
||||||
|
setDesktopCapturerVideo: (targetSource) => {
|
||||||
|
// stopScreenCapture()
|
||||||
|
if (
|
||||||
|
targetSource.type ===
|
||||||
|
ScreenCaptureSourceType.ScreencapturesourcetypeScreen
|
||||||
|
) {
|
||||||
|
rtcEngine.startScreenCaptureByDisplayId(
|
||||||
|
targetSource.sourceId,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
windowFocus: true,
|
||||||
|
enableHighLight: true,
|
||||||
|
highLightColor: 0xFF99CC00,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
rtcEngine.startScreenCaptureByWindowId(
|
||||||
|
targetSource.sourceId,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
windowFocus: true,
|
||||||
|
enableHighLight: true,
|
||||||
|
highLightColor: 0xFF99CC00,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// joinChannel(true)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
window.agora = agora;
|
||||||
Loading…
Reference in New Issue