WGShare.Client.Electron/src/App.tsx

327 lines
14 KiB
TypeScript

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, Modal, Spin } from "antd";
import JoinMeetingModal from "@/components/JoinMeetingModal";
import UpdateModal from "@/components/UpdateModal";
import * as CryptoJS from 'crypto-js';
import { GetCheckOnline, PostLogin } from "@/api/Login";
import { agora } from "@/utils/package/agora";
import QuitTips from "@/components/QuitTips";
import { GetLeave } from "@/api/Meeting";
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 NoticeWindow from "@/page/Meeting/NoticeWindow";
import { getKeyOpenChildWindow, getTitle, setKeyOpenChildWindow, storageSeeting } from "./utils/package/public";
import { ExclamationCircleFilled } from "@ant-design/icons";
const { confirm } = Modal;
const fs = require('fs').promises;
const { exec } = require('child_process');
const App: React.FC = () => {
const navigate = useNavigate();
const { state } = useLocation();
const joinMeetingModalRef = useRef<any>();
const updateModalRef = useRef<any>();
const quitTipsRef = useRef<any>();
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', '#/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)
const login = () => {
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 window.electron.startSignalr(res.data)
} else {
toSrc('/login')
}
})
}
if (userInfo && !userInfo.isAnonymous) {
if (loginInfo && loginInfo.isAutoLogin) {
GetCheckOnline(loginInfo.account).then(req => {
if (req.code === 200) {
if (req.data) {
confirm({
title: '提示',
icon: <ExclamationCircleFilled />,
content: `账号已在其他地方登录,是否强制登陆?`,
centered: true,
okText: '确定',
cancelText: '取消',
async onOk() {
login()
},
onCancel() {
toSrc('/login')
}
})
} else {
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.startLoad();
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) => {
let bool = await window.electron.isVisible()
if (bool) {
storage.setItem('quitMeeting', true)
window.electron.setViewStatus('show')
}
})
window.electron.isOpenWindows(async (_e: any) => {
let bool = await window.electron.isVisible()
if (location.hash.indexOf('/meeting') === -1) {
window.electron.setViewStatus(bool ? 'hide' : 'show')
} else {
let shareScreenWindow = await getKeyOpenChildWindow('shareScreenWindow')
if (!shareScreenWindow) {
window.electron.setViewStatus(bool ? 'hide' : 'show')
}
}
})
window.electron.changeLocalStorage(async (_e: any, data: any) => {
for (const key in data) {
storage.setItem(key, data[key])
}
})
}, [])
useEffect(() => {
window.electron.onUpdate((_e: any, data: any) => {
updateModalRef.current.changeModal(data)
})
if (!storage.getItem('setting')) {
storage.setItem('setting', JSON.stringify(storageSeeting))
}
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(location.hash.indexOf('/meeting') === -1)
} 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(location.hash.indexOf('/meeting') === -1)
}
} else {
quitTipsRef.current.changeModal()
}
}
})
}
storage.setItem('stateInfo', JSON.stringify(state))
}, [state])
useEffect(() => {
if (location.href.indexOf('/login') !== -1) {
window.electron.onStop()
}
if (location.hash.indexOf('/meeting') === -1) {
window.electron.updateHandle()
}
message.destroy('cameraTemporarily')
}, [navigate])
}
useEffect(() => {
document.addEventListener('keydown', (event) => {
if (event.key === 'F11') {
event.preventDefault();
}
});
document.getElementsByTagName('title')[0].innerText = getTitle(import.meta.env.VITE_ENV)
}, [])
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 => {
window.electron.onOtherSignalr(async (_e: any, 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<void> => {
if (location.hash.indexOf('/meeting') === 1) {
window.electron.closeChildWindow('shareScreenWindow')
setKeyOpenChildWindow('shareScreenWindow', false)
window.electron.setViewStatus('show')
window.electron.getWindowSize().then((res: any) => {
window.electron.setMainWindowSize({
width: Math.ceil(res.width / 1.5),
height: Math.ceil(res.height / 1.3),
})
window.electron.getIsMaximized().then((b: boolean) => {
if (!b) {
window.electron.setViewStatus('maximize')
}
})
})
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')
}
} else if (e.key === 'reconnect') {
if (e.value == true) {
if (location.hash.indexOf('/meeting') === -1) {
window.electron.updateHandle()
}
} else {
updateModalRef.current.setProgress()
}
}
};
return (
<>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/home' element={<Home />}>
<Route path='/home' element={<Navigate to='/home/index' />} />
<Route path='/home/index' element={<Index />} />
<Route path='/home/user' element={<User />} />
</Route>
<Route path='/login' element={<Login />} />
<Route path='/meeting' element={<Meeting />} />
<Route path='/shareScreenWindow' element={<ShareScreenWindow />} />
<Route path='/userListWindow' element={<UserListWindow />} />
<Route path='/chatSmallWindow' element={<ChatSmallWindow />} />
<Route path='/chatBigWindow' element={<ChatBigWindow />} />
<Route path='/noticeWindow' element={<NoticeWindow />} />
<Route path='*' element={<NotFound />} />
</Routes>
<Spin spinning={spinning} fullscreen />
<JoinMeetingModal ref={joinMeetingModalRef} />
<UpdateModal ref={updateModalRef} />
<QuitTips ref={quitTipsRef} />
</>
)
}
export default App