import { useEffect, useRef, useState } from "react"; import '@/utils/styles/App.scss' import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom'; import Home from '@/page/Home/index' import Index from '@/page/Home/Index/index' import User from '@/page/Home/User/index' import Login from '@/page/Login/index' import Meeting from '@/page/Meeting/index' import NotFound from '@/page/NotFound/index' import { storage } from '@/utils' import { message, Spin } from "antd"; import { onOtherSignalr, onStop, startSignalr } from "@/utils/package/signalr"; import JoinMeetingModal from "@/components/JoinMeetingModal"; import UpdateModal from "@/components/UpdateModal"; import * as CryptoJS from 'crypto-js'; import { PostLogin } from "@/api/Login"; import { agora } from "@/utils/package/agora"; import QuitTips from "@/components/QuitTips"; import { GetLeave } from "@/api/Meeting"; import path from "path"; import ShareScreenWindow from "@/page/Meeting/ShareScreenWindow"; import UserListWindow from "@/page/Meeting/UserListWindow"; import ChatSmallWindow from "@/page/Meeting/ChatSmallWindow"; import ChatBigWindow from "@/page/Meeting/ChatBigWindow"; import CurrentSpeakUserWindow from "@/page/Meeting/CurrentSpeakUserWindow"; import NoticeWindow from "@/page/Meeting/NoticeWindow"; const fs = require('fs').promises; const { exec } = require('child_process'); const App: React.FC = () => { const navigate = useNavigate(); const { state } = useLocation(); const joinMeetingModalRef = useRef(); const updateModalRef = useRef(); const quitTipsRef = useRef(); const [_windowSize, setWindowSize] = useState({ width: window.innerWidth, height: window.innerHeight, }); const [spinning, setSpinning] = useState(false); const [isState, setIsState] = useState(true); const urlHashArr = ['#/userListWindow', '#/shareScreenWindow', '#/chatSmallWindow', '#/chatBigWindow', '#/currentSpeakUserWindow', '#/noticeWindow'] if (urlHashArr.indexOf(location.hash) == -1) { useEffect(() => { let userInfo = JSON.parse(storage.getItem('user') as string) let loginInfo = JSON.parse(storage.getItem('login') as string) if (userInfo && !userInfo.isAnonymous) { if (loginInfo && loginInfo.isAutoLogin) { PostLogin({ account: loginInfo.account, pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex) }).then(async (res) => { if (res.code === 200) { storage.setItem('user', JSON.stringify(res.data)) storage.setItem('userLogin', true) toSrc('/home') await startSignalr() } else { toSrc('/login') } }) } else { toSrc('/login') } } else { toSrc('/login') } window.addEventListener('resize', handleResize); const originalSetItem = window.localStorage.setItem; window.localStorage.setItem = function (key, value) { originalSetItem.call(this, key, value); const event = new Event('customStorageChange') as any; event.key = key event.value = value window.dispatchEvent(event); }; window.addEventListener('customStorageChange', handleCustomStorageChange); return () => { window.removeEventListener('resize', handleResize); window.removeEventListener('customStorageChange', handleCustomStorageChange); }; }, []); useEffect(() => { window.electron.downFile(async (_e: any, data: any) => { const response = await fetch(data.filePath); const arrayBuffer = await response.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); fs.writeFile(`${data.downFilePaths}${data.fileName}`, buffer, {}); message.success(`下载成功!文件已保存至:${data.downFilePaths}`) await fs.access(data.downFilePaths, fs.constants.F_OK); if (process.platform === 'win32') { exec(`explorer "${data.downFilePaths}"`); } else if (process.platform === 'darwin') { exec(`open "${data.downFilePaths}"`); } }) window.electron.onFilePath(async (_e: any, filePath: string, key: string) => { const setting = await JSON.parse(storage.getItem('setting') as string) if (key === 'recordingFilesPath') { setting.recordingFilesPath = filePath } else { setting.shareFilesPath = filePath } storage.setItem('setting', JSON.stringify(setting)) }) window.electron.quitAndInstall(async (_e: any) => { leaveChannel() }) }, []) useEffect(() => { window.electron.onUpdate((_e: any, data: any) => { if (location.hash.indexOf('/meeting') === -1) { updateModalRef.current.changeModal(data) } }) if (!storage.getItem('setting')) { storage.setItem('setting', JSON.stringify({ videoDeviceId: '', //摄像头id ecordingDeviceId: "", //输入设备id playBackDeviceId: "", //输出设备id ecordingVolume: '', //输入音量 playBackVolume: '', //输出音量 autoEcordingVolume: true, //是否自动调整麦克风音量 recordingFilesPath: path.resolve(__dirname, '../../Downloads') + '\\', //本地录制保存路径 shareFilesPath: path.resolve(__dirname, '../../Downloads/') + '\\', //共享文件保存路径 isShareSavePath: true, //是否下载钱询问每个文件保存的位置 closeSetting: 'hide', //关闭按钮设置 isAINoiseReduction: true, //是否开启ai降噪 aINoiseReduction: 1, // 降噪模式 isRecordingTips: true, //是否开启录制提示 })) } if (!storage.getItem('openChildWindow')) { storage.setItem('openChildWindow', JSON.stringify({})) } }, []) useEffect(() => { if (isState) { setIsState(false) window.electron.onQuit(async () => { if (location.hash.indexOf('/login') === 1) { window.electron.quit() } else { if (storage.getItem('isTips') === 'true') { const setting = JSON.parse(storage.getItem('setting') as string) if (setting.closeSetting === 'hide') { window.electron.setViewStatus(setting.closeSetting) } else { window.electron.quit() } } else { quitTipsRef.current.changeModal() } } }) } storage.setItem('stateInfo', JSON.stringify(state)) }, [state]) useEffect(() => { if (location.href.indexOf('/login') !== -1) { onStop() } }, [navigate]) } useEffect(() => { document.addEventListener('keydown', (event) => { if (event.key === 'F11') { event.preventDefault(); } }); }, []) const handleResize = (): void => { setWindowSize({ width: window.innerWidth, height: window.innerHeight, }); window.electron.getIsMaximized().then((res: boolean) => { const dom = document.getElementById('root') as HTMLElement; dom.style.borderRadius = res ? '0px' : '10px' }) }; const onEventSignalr = (): void => { onOtherSignalr(async (item: any) => { switch (item.key) { case 'Invitation': window.electron.joinNotification({ body: item.roomName, name: item.InviterName, }) joinMeetingModalRef.current.changeModal(item) break; case 'ForceLogout': if (item.msg) { message.error(item.msg) } await leaveChannel(true) toSrc('/login') break; } }) } const toSrc = (path: string): void => { window.electron.getWindowSize().then((res: any) => { switch (path) { case '/login': storage.setItem('userLogin', false) navigate('/login') break; case '/home': window.electron.setMainWindowSize({ width: Math.ceil(res.width / 1.5), height: Math.ceil(res.height / 1.3), }) navigate('/home') break; } }) }; const leaveChannel = async (bool?: boolean): Promise => { if (location.hash.indexOf('/meeting') === 1) { const data = JSON.parse(localStorage.stateInfo); if (!bool) { await GetLeave({ roomNum: data.channelId, }) } await agora.leaveChannel() } }; const handleCustomStorageChange = (e: any): void => { if (e.key === 'loading') { setSpinning(Boolean(e.value)) } else if (e.key === 'isSignalr') { if (Boolean(e.value)) { onEventSignalr() } } else if (e.key === 'userLogin') { if (!Boolean(e.value)) { storage.removeItem('user') navigate('/login') } } }; return ( <> } /> }> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> ) } export default App