Compare commits

..

No commits in common. "8f2f93d0a4dd19383106452365961a690e355792" and "4cd47addfe050d9aebdc21e04d120c6ea4ad46f8" have entirely different histories.

18 changed files with 201 additions and 507 deletions

25
main.js
View File

@ -17,7 +17,6 @@ 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 childWindow = {}
let isMaximized = false; let isMaximized = false;
let env; let env;
let regKey; let regKey;
@ -300,30 +299,6 @@ app.on('ready', () => {
}) })
}); });
}); });
// 创建子窗口
ipcMain.handle('createChildWindow', (event, config) => {
const child = new BrowserWindow({
parent: mainWindow,
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
enableRemoteModule: true,
nodeIntegrationInWorker: true,
allowMediaDevices: true,
preload: path.join(__dirname, 'preload.js')
},
show: false,
frame: false,
backgroundColor: '#00000000',
transparent: true,
})
child.loadURL(config.url)
childWindow[config.key] = child
child.once('ready-to-show', () => {
child.show()
child.setSize(config.width, config.height)
})
});
} }
}); });
// 检测更新在你想要检查更新的时候执行renderer事件触发后的操作自行编写 // 检测更新在你想要检查更新的时候执行renderer事件触发后的操作自行编写

View File

@ -73,8 +73,4 @@ window.electron = {
setRegistry: (uuid) => { setRegistry: (uuid) => {
ipcRenderer.invoke('setRegistry', uuid) ipcRenderer.invoke('setRegistry', uuid)
}, },
// 创建子窗口
createChildWindow: (config) => {
ipcRenderer.invoke('createChildWindow', config)
},
} }

View File

@ -18,7 +18,6 @@ import { agora } from "@/utils/package/agora";
import QuitTips from "@/components/QuitTips"; import QuitTips from "@/components/QuitTips";
import { GetLeave } from "@/api/Meeting"; import { GetLeave } from "@/api/Meeting";
import path from "path"; import path from "path";
import ShareScreenWindow from "./page/ShareScreenWindow";
const fs = require('fs').promises; const fs = require('fs').promises;
const { exec } = require('child_process'); const { exec } = require('child_process');
const App: React.FC = () => { const App: React.FC = () => {
@ -33,124 +32,122 @@ const App: React.FC = () => {
}); });
const [spinning, setSpinning] = useState(false); const [spinning, setSpinning] = useState(false);
const [isState, setIsState] = useState(true); const [isState, setIsState] = useState(true);
if (location.hash.indexOf('shareScreenWindow') == -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) if (userInfo && Number(userInfo.perms)) {
if (userInfo && !userInfo.isAnonymous) { if (loginInfo && loginInfo.isAutoLogin) {
if (loginInfo && loginInfo.isAutoLogin) { PostLogin({
PostLogin({ account: loginInfo.account,
account: loginInfo.account, pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex)
pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex) }).then(async (res) => {
}).then(async (res) => { if (res.code === 200) {
if (res.code === 200) { storage.setItem('user', JSON.stringify(res.data))
storage.setItem('user', JSON.stringify(res.data)) storage.setItem('userLogin', true)
storage.setItem('userLogin', true) toSrc('/home')
toSrc('/home') await startSignalr()
await startSignalr() } else {
} else { toSrc('/login')
toSrc('/login') }
} })
})
} else {
toSrc('/login')
}
} else { } else {
toSrc('/login') toSrc('/login')
} }
window.addEventListener('resize', handleResize); } else {
const originalSetItem = window.localStorage.setItem; toSrc('/login')
window.localStorage.setItem = function (key, value) { }
originalSetItem.call(this, key, value); window.addEventListener('resize', handleResize);
const event = new Event('customStorageChange') as any; const originalSetItem = window.localStorage.setItem;
event.key = key window.localStorage.setItem = function (key, value) {
event.value = value originalSetItem.call(this, key, value);
window.dispatchEvent(event); const event = new Event('customStorageChange') as any;
}; event.key = key
window.addEventListener('customStorageChange', handleCustomStorageChange); event.value = value
return () => { window.dispatchEvent(event);
window.removeEventListener('resize', handleResize); };
window.removeEventListener('customStorageChange', handleCustomStorageChange); window.addEventListener('customStorageChange', handleCustomStorageChange);
}; return () => {
}, []); window.removeEventListener('resize', handleResize);
useEffect(() => { window.removeEventListener('customStorageChange', handleCustomStorageChange);
window.electron.downFile(async (_e: any, data: any) => { };
const response = await fetch(data.filePath); }, []);
const arrayBuffer = await response.arrayBuffer(); useEffect(() => {
const buffer = Buffer.from(arrayBuffer); window.electron.downFile(async (_e: any, data: any) => {
fs.writeFile(`${data.downFilePaths}${data.fileName}`, buffer, {}); const response = await fetch(data.filePath);
message.success(`下载成功!文件已保存至:${data.downFilePaths}`) const arrayBuffer = await response.arrayBuffer();
await fs.access(data.downFilePaths, fs.constants.F_OK); const buffer = Buffer.from(arrayBuffer);
if (process.platform === 'win32') { fs.writeFile(`${data.downFilePaths}${data.fileName}`, buffer, {});
exec(`explorer "${data.downFilePaths}"`); message.success(`下载成功!文件已保存至:${data.downFilePaths}`)
} else if (process.platform === 'darwin') { await fs.access(data.downFilePaths, fs.constants.F_OK);
exec(`open "${data.downFilePaths}"`); if (process.platform === 'win32') {
} exec(`explorer "${data.downFilePaths}"`);
}) } else if (process.platform === 'darwin') {
window.electron.onFilePath(async (_e: any, filePath: string, key: string) => { exec(`open "${data.downFilePaths}"`);
const setting = await JSON.parse(storage.getItem('setting') as string) }
if (key === 'recordingFilesPath') { })
setting.recordingFilesPath = filePath 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, // 降噪模式
}))
}
}, [])
useEffect(() => {
if (isState) {
setIsState(false)
window.electron.onQuit(async () => {
if (location.hash.indexOf('/login') === 1) {
window.electron.quit()
} else { } else {
setting.shareFilesPath = filePath if (storage.getItem('isTips') === 'true') {
} const setting = JSON.parse(storage.getItem('setting') as string)
storage.setItem('setting', JSON.stringify(setting)) if (setting.closeSetting === 'hide') {
}) window.electron.setViewStatus(setting.closeSetting)
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, // 降噪模式
}))
}
}, [])
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 { } else {
quitTipsRef.current.changeModal() window.electron.quit()
} }
} else {
quitTipsRef.current.changeModal()
} }
}) }
} })
storage.setItem('stateInfo', JSON.stringify(state)) }
}, [state]) storage.setItem('stateInfo', JSON.stringify(state))
useEffect(() => { }, [state])
if (location.href.indexOf('/login') !== -1) { useEffect(() => {
onStop() if (location.href.indexOf('/login') !== -1) {
} onStop()
}, [navigate]) }
} }, [navigate])
useEffect(() => { useEffect(() => {
document.addEventListener('keydown', (event) => { document.addEventListener('keydown', (event) => {
if (event.key === 'F11') { if (event.key === 'F11') {
@ -242,7 +239,6 @@ const App: React.FC = () => {
</Route> </Route>
<Route path='/login' element={<Login />} /> <Route path='/login' element={<Login />} />
<Route path='/meeting' element={<Meeting />} /> <Route path='/meeting' element={<Meeting />} />
<Route path='/shareScreenWindow' element={<ShareScreenWindow />} />
<Route path='*' element={<NotFound />} /> <Route path='*' element={<NotFound />} />
</Routes> </Routes>
<Spin spinning={spinning} fullscreen /> <Spin spinning={spinning} fullscreen />

View File

@ -11,12 +11,6 @@ export const PostRoom = (data: any) =>
method: 'post', method: 'post',
data, data,
}) })
export const PostRoomInfo = (data: any) =>
request({
url: `/home/room-info`,
method: 'put',
data,
})
export const DeleteRoom = (roomId: string) => export const DeleteRoom = (roomId: string) =>
request({ request({
url: `/home/room?roomId=${roomId}`, url: `/home/room?roomId=${roomId}`,

View File

@ -19,13 +19,6 @@ export const PutUser = (data: any) =>
method: 'put', method: 'put',
data data
}) })
export const PutUserBth = (data: any) =>
request({
url: `/user/bth`,
method: 'put',
data
})
export const DeleteUser = (data: any) => export const DeleteUser = (data: any) =>
request({ request({
url: `/user`, url: `/user`,
@ -40,12 +33,6 @@ export const PutUserPwd = (data: { id: string, pwd: string }) =>
data data
}) })
export const GetSubDpList = () =>
request({
url: `/pub/sub-dp-list`,
method: 'get',
})
export const GetRoleDpList = () => export const GetRoleDpList = () =>
request({ request({
url: `/pub/role-dp-list`, url: `/pub/role-dp-list`,

View File

@ -158,7 +158,7 @@ const InvitingPersonnelModal = forwardRef((props: any, ref: any) => {
</div> </div>
</div>) : <span style={{ display: 'block', textAlign: 'center', color: 'white', padding: '30px 0' }}></span>} </div>) : <span style={{ display: 'block', textAlign: 'center', color: 'white', padding: '30px 0' }}></span>}
</div> </div>
<Pagination size="small" total={list.total} showSizeChanger={false} style={{ flexShrink: 0, margin: '10px 0 0' }} onChange={(e) => { <Pagination size="small" total={list.total} style={{ flexShrink: 0, margin: '10px 0 0' }} onChange={(e) => {
setList({ setList({
...list, ...list,
pageIndex: e pageIndex: e

View File

@ -341,7 +341,7 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
...fileList, ...fileList,
pageIndex: e pageIndex: e
}) })
}} pageSize={fileList.pageSize} current={fileList.pageIndex} hideOnSinglePage={true} showSizeChanger={false}/> }} pageSize={fileList.pageSize} current={fileList.pageIndex} hideOnSinglePage={true} />
</div> </div>
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@ import App from './App.tsx'
import '@/utils/styles/main.css' import '@/utils/styles/main.css'
import { HashRouter } from 'react-router-dom'; import { HashRouter } from 'react-router-dom';
import { ConfigProvider } from 'antd'; import { ConfigProvider } from 'antd';
import zhCN from 'antd/es/locale/zh_CN'; import zhCN from 'antd/locale/zh_CN';
import 'animate.css'; import 'animate.css';
ReactDOM.createRoot(document.getElementById('root')!).render( ReactDOM.createRoot(document.getElementById('root')!).render(
<HashRouter> <HashRouter>

View File

@ -1,8 +1,8 @@
import styles from '@/page/Home/Index/index.module.scss' import styles from '@/page/Home/Index/index.module.scss'
import { useEffect, useState, useRef } from "react"; import { useEffect, useState, useRef } from "react";
import Operation from '@/components/Operation'; import Operation from '@/components/Operation';
import { Button, Input, Modal, Pagination, Empty, message, Popover, Popconfirm, DatePicker, Select } from "antd"; import { Button, Input, Modal, Pagination, Empty, message, Popover, Popconfirm, DatePicker } from "antd";
import { GetRoom, PostRoom, GetCheckoutRoomNum, GetRoomRtcToken, DeleteRoom, GetRecord, PostRoomInfo } from '@/api/Home/Index'; import { GetRoom, PostRoom, GetCheckoutRoomNum, GetRoomRtcToken, DeleteRoom, GetRecord } from '@/api/Home/Index';
import ImageUrl from '@/utils/package/imageUrl' import ImageUrl from '@/utils/package/imageUrl'
import { ExclamationCircleFilled, ReloadOutlined } from '@ant-design/icons'; import { ExclamationCircleFilled, ReloadOutlined } from '@ant-design/icons';
import JoinSetting from '@/components/JoinSetting'; import JoinSetting from '@/components/JoinSetting';
@ -12,7 +12,6 @@ import { useNavigate } from 'react-router-dom';
import { role } from '@/config/role'; import { role } from '@/config/role';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import StupWizard from '@/components/StupWizard'; import StupWizard from '@/components/StupWizard';
import { GetSubDpList } from '@/api/Home/User';
const fs = require('fs').promises; const fs = require('fs').promises;
const { exec } = require('child_process'); const { exec } = require('child_process');
const { RangePicker } = DatePicker; const { RangePicker } = DatePicker;
@ -27,20 +26,15 @@ const Index: React.FC = () => {
}) })
const [createRoomModal, setCreateRoomModal] = useState(false) const [createRoomModal, setCreateRoomModal] = useState(false)
const [timeSelectModal, setTimeSelectModal] = useState(false) const [timeSelectModal, setTimeSelectModal] = useState(false)
const [createRoomFrom, setCreateRoomFrom] = useState<{ id: string, roomName: string, roomNum: string, subject: string, year: string }>({ const [createRoomFrom, setCreateRoomFrom] = useState<{ roomName: string, roomNum: string }>({
id: "",
roomName: "", roomName: "",
roomNum: "", roomNum: ""
subject: "",
year: ""
}) })
const joinSettingRef = useRef<any>(); const joinSettingRef = useRef<any>();
const stupWizardRef = useRef<any>(); const stupWizardRef = useRef<any>();
const [user, setUser] = useState<any>({}); const [user, setUser] = useState<any>({});
const [currentRoomInfo, setCurrentRoomInfo] = useState<any>({}); const [currentRoomInfo, setCurrentRoomInfo] = useState<any>({});
const [subjectList, setSubjectList] = useState<any>([]);
const [timeData, setTimeData] = useState<any>([]); const [timeData, setTimeData] = useState<any>([]);
const [isCreateRoom, setIsCreateRoom] = useState<boolean>(false);
const userInfo = JSON.parse(storage.getItem('user') as string) const userInfo = JSON.parse(storage.getItem('user') as string)
useEffect(() => { useEffect(() => {
setUser(userInfo) setUser(userInfo)
@ -68,12 +62,7 @@ const Index: React.FC = () => {
setList({ setList({
...list, ...list,
total: res.data.total, total: res.data.total,
data: res.data.items.map((item: any) => { data: res.data.items,
return {
...item,
open: false
}
}),
}) })
} }
}) })
@ -91,13 +80,6 @@ const Index: React.FC = () => {
} }
}) })
} }
const getSubDpList = async (): Promise<void> => {
await GetSubDpList().then(res => {
if (res.code === 200) {
setSubjectList(res.data.map((item: any) => { return { value: item.value, label: item.name } }))
}
})
}
const getRoomRtcToken = async (roomNum: string, callBack: Function): Promise<void> => { const getRoomRtcToken = async (roomNum: string, callBack: Function): Promise<void> => {
Promise.all([GetRoomRtcToken(roomNum), GetRoomRtcToken(roomNum + 'a')]).then(res => { Promise.all([GetRoomRtcToken(roomNum), GetRoomRtcToken(roomNum + 'a')]).then(res => {
if (res[0].code === 200 && res[1].code === 200) { if (res[0].code === 200 && res[1].code === 200) {
@ -184,13 +166,8 @@ const Index: React.FC = () => {
onClick={() => { onClick={() => {
setCreateRoomFrom({ setCreateRoomFrom({
roomName: "", roomName: "",
roomNum: "", roomNum: ""
subject: "",
year: "",
id: "",
}) })
getSubDpList()
setIsCreateRoom(true)
setCreateRoomModal(true) setCreateRoomModal(true)
}} }}
style={{ marginRight: '22px' }} style={{ marginRight: '22px' }}
@ -257,26 +234,13 @@ const Index: React.FC = () => {
okText="确定" okText="确定"
cancelText="取消" cancelText="取消"
> >
<div className='meetingContentFooterPopoverDel'></div> <div></div>
</Popconfirm> : null} </Popconfirm> : null}
<div className='meetingContentFooterPopoverDefault' onClick={() => { <div onClick={() => {
changeOpen(index, false) changeOpen(index, false)
setTimeSelectModal(true) setTimeSelectModal(true)
}}></div> }}></div>
<div className='meetingContentFooterPopoverDefault' onClick={() => { <div onClick={() => {
changeOpen(index, false)
setCreateRoomFrom({
roomName: item.roomName,
roomNum: item.roomNum,
subject: item.subject,
year: item.year,
id: item.id,
})
getSubDpList()
setIsCreateRoom(false)
setCreateRoomModal(true)
}}></div>
<div className='meetingContentFooterPopoverCancel' onClick={() => {
changeOpen(index, false) changeOpen(index, false)
}}></div> }}></div>
</div> </div>
@ -334,19 +298,19 @@ const Index: React.FC = () => {
</div> </div>
} }
<div className={styles.indexContentPagination}> <div className={styles.indexContentPagination}>
<Pagination size="small" total={list.total} onChange={(e: number) => { <Pagination size="small" total={list.total} onChange={(e) => {
setList({ setList({
...list, ...list,
pageIndex: e pageIndex: e
}) })
}} pageSize={list.pageSize} showSizeChanger={false} /> }} pageSize={list.pageSize} />
</div> </div>
</div> </div>
</div> </div>
<Modal title={isCreateRoom ? '新建会议室' : '修改会议信息'} open={createRoomModal} footer={null} closable={false} centered width={'400px'}> <Modal title="新建会议室" open={createRoomModal} footer={null} closable={false} centered width={'400px'}>
<div> <div>
<div> <div>
{isCreateRoom ? <Input <Input
placeholder="请输入房间号" placeholder="请输入房间号"
style={{ marginBottom: '14px' }} style={{ marginBottom: '14px' }}
className={styles.letterSpacing} className={styles.letterSpacing}
@ -380,7 +344,7 @@ const Index: React.FC = () => {
> >
</span> </span>
} }
/> : null} />
<Input.TextArea <Input.TextArea
placeholder="请输入房间名字" placeholder="请输入房间名字"
style={{ marginBottom: '14px' }} style={{ marginBottom: '14px' }}
@ -394,30 +358,6 @@ const Index: React.FC = () => {
}) })
}} }}
autoSize /> autoSize />
<Input
placeholder="请输入届"
style={{ marginBottom: '14px' }}
value={createRoomFrom.year}
onChange={(e) => {
const regex = /^[0-9]*$/;
if (regex.test(e.target.value)) {
setCreateRoomFrom({
...createRoomFrom,
year: e.target.value
})
}
}}
/>
<Select
placeholder='请选择学科'
style={{ width: '100%', marginBottom: '14px' }}
options={subjectList}
value={createRoomFrom.subject === "" ? null : createRoomFrom.subject} onChange={(e) => {
setCreateRoomFrom({
...createRoomFrom,
subject: e
})
}} />
</div> </div>
<div style={{ <div style={{
display: 'flex', justifyContent: 'center' display: 'flex', justifyContent: 'center'
@ -430,36 +370,20 @@ const Index: React.FC = () => {
if (!createRoomFrom.roomNum) { if (!createRoomFrom.roomNum) {
return message.error('请输入房间号!') return message.error('请输入房间号!')
} }
if (!createRoomFrom.year) { isGetCheckoutRoomNum(createRoomFrom.roomNum, (bool: boolean) => {
return message.error('请输入届!') if (bool) {
} message.error('房间号已存在!')
if (createRoomFrom.subject === "") { } else {
return message.error('请选择学科!') PostRoom(createRoomFrom).then(res => {
} if (res.code === 200) {
if (isCreateRoom) { message.success('创建成功!')
isGetCheckoutRoomNum(createRoomFrom.roomNum, (bool: boolean) => { setCreateRoomModal(false)
if (bool) { getRoomList()
message.error('房间号已存在!') }
} else { })
PostRoom(createRoomFrom).then(res => { }
if (res.code === 200) { })
message.success('创建成功!') }}></Button>
setCreateRoomModal(false)
getRoomList()
}
})
}
})
} else {
PostRoomInfo(createRoomFrom).then(res => {
if (res.code === 200) {
message.success('更新成功!')
setCreateRoomModal(false)
getRoomList()
}
})
}
}}>{isCreateRoom ? '创建' : '更新'}</Button>
</div> </div>
</div> </div>
</Modal> </Modal>

View File

@ -3,7 +3,7 @@ import { useEffect, useState, useRef } from "react";
import Operation from '@/components/Operation'; 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 { ExclamationCircleFilled, SearchOutlined } from '@ant-design/icons'; import { ExclamationCircleFilled, SearchOutlined } from '@ant-design/icons';
import { GetUserList, PostUser, PutUser, DeleteUser, PutUserPwd, GetRoleDpList, PostUserImport, GetSubDpList, PutUserBth } from '@/api/Home/User'; import { GetUserList, PostUser, PutUser, DeleteUser, PutUserPwd, GetRoleDpList, PostUserImport } from '@/api/Home/User';
import * as CryptoJS from 'crypto-js'; import * as CryptoJS from 'crypto-js';
import ImageUrl from '@/utils/package/imageUrl'; import ImageUrl from '@/utils/package/imageUrl';
import { storage } from '@/utils'; import { storage } from '@/utils';
@ -15,7 +15,7 @@ const fs = require('fs').promises;
const User: React.FC = () => { const User: React.FC = () => {
const stupWizardRef = useRef<any>(); const stupWizardRef = useRef<any>();
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [isCreateUser, setIsCreateUser] = useState<'add' | 'batch' | 'edit'>(); const [isCreateUser, setIsCreateUser] = useState(false);
const [list, setList] = useState({ const [list, setList] = useState({
data: [], data: [],
searchKeywod: '', searchKeywod: '',
@ -30,9 +30,7 @@ const User: React.FC = () => {
Account: "", Account: "",
RoleId: null, RoleId: null,
Pwd: "", Pwd: "",
UserName: "", UserName: ""
subject: null,
year: "",
}) })
const [changeUserPawModal, setChangeUserPawModal] = useState(false) const [changeUserPawModal, setChangeUserPawModal] = useState(false)
const [changeImportModal, setChangeImportModal] = useState(false) const [changeImportModal, setChangeImportModal] = useState(false)
@ -41,14 +39,10 @@ const User: React.FC = () => {
newPwd: '', newPwd: '',
}) })
const [deleteUserPawModal, setDeleteUserPawModal] = useState(false) const [deleteUserPawModal, setDeleteUserPawModal] = useState(false)
const [subjectList, setSubjectList] = useState<any>([]);
useEffect(() => {
getSubDpList()
}, []);
useEffect(() => { useEffect(() => {
getUserList() getUserList()
}, [list.pageIndex, list.pageSize]); }, [list.pageIndex]);
const getUserList = async (): Promise<void> => { const getUserList = async (): Promise<void> => {
await GetUserList({ await GetUserList({
@ -67,7 +61,6 @@ const User: React.FC = () => {
} }
}), }),
}) })
setSelectedRowKeys([])
} }
}) })
} }
@ -125,13 +118,7 @@ const User: React.FC = () => {
} }
} }
} }
const getSubDpList = async (): Promise<void> => {
await GetSubDpList().then(res => {
if (res.code === 200) {
setSubjectList(res.data.map((item: any) => { return { value: item.value, label: item.name } }))
}
})
}
return ( return (
<> <>
<div className={styles.user}> <div className={styles.user}>
@ -144,15 +131,13 @@ const User: React.FC = () => {
onClick={() => { onClick={() => {
getRoleDpList((bool: boolean) => { getRoleDpList((bool: boolean) => {
if (bool) { if (bool) {
setIsCreateUser('add') setIsCreateUser(true)
setAddUserFrom({ setAddUserFrom({
Id: "", Id: "",
Account: "", Account: "",
RoleId: null, RoleId: null,
Pwd: "", Pwd: "",
UserName: "", UserName: "",
subject: null,
year: "",
}) })
setAddUserModal(true) setAddUserModal(true)
} }
@ -169,31 +154,6 @@ const User: React.FC = () => {
className='m-ant-btn'> className='m-ant-btn'>
</Button> </Button>
<Button type="primary"
onClick={() => {
if (selectedRowKeys.length) {
getRoleDpList((bool: boolean) => {
if (bool) {
setIsCreateUser('batch')
setAddUserFrom({
Id: "",
Account: "",
RoleId: null,
Pwd: "",
UserName: "",
subject: null,
year: "",
})
setAddUserModal(true)
}
})
} else {
message.error('请选择需要修改的用户!')
}
}}
className='m-ant-btn'>
</Button>
<Button type="primary" <Button type="primary"
icon={<img src={ImageUrl.icon21} alt="" />} icon={<img src={ImageUrl.icon21} alt="" />}
className={styles.userBtnsDel} className={styles.userBtnsDel}
@ -201,7 +161,7 @@ const User: React.FC = () => {
if (selectedRowKeys.length) { if (selectedRowKeys.length) {
setDeleteUserPawModal(true) setDeleteUserPawModal(true)
} else { } else {
message.error('请选择要删除的用户') message.error('请选择要删除的用户')
} }
}} }}
> >
@ -254,13 +214,7 @@ const User: React.FC = () => {
<div style={{ color: item.isOnline ? '#02B188' : 'rgb(221 11 11)' }}>{item.isOnline ? '在线' : '离线'}</div> <div style={{ color: item.isOnline ? '#02B188' : 'rgb(221 11 11)' }}>{item.isOnline ? '在线' : '离线'}</div>
</> </>
)} /> )} />
<Column title="届" dataIndex="year" key="year" /> <Column title="操作" render={(item) => (
<Column title="学科" render={(item) => (
<>
<div>{subjectList.find((subject: any) => subject.value === item.subject)?.label}</div>
</>
)} />
<Column title="操作" width={200} render={(item) => (
<> <>
<Button <Button
type="primary" type="primary"
@ -269,15 +223,13 @@ const User: React.FC = () => {
onClick={() => { onClick={() => {
getRoleDpList((bool: boolean) => { getRoleDpList((bool: boolean) => {
if (bool) { if (bool) {
setIsCreateUser('edit') setIsCreateUser(false)
setAddUserFrom({ setAddUserFrom({
...addUserFrom, ...addUserFrom,
Id: item.id, Id: item.id,
Account: item.account, Account: item.account,
RoleId: item.roleId, RoleId: item.roleId,
UserName: item.userName, UserName: item.userName,
subject: item.subject,
year: item.year,
}) })
setAddUserModal(true) setAddUserModal(true)
} }
@ -306,20 +258,19 @@ const User: React.FC = () => {
</Table> </Table>
<div className={styles.userContentPagination}> <div className={styles.userContentPagination}>
<span>{list.total}</span> <span>{list.total}</span>
<Pagination size="small" total={list.total} onChange={(page, pageSize) => { <Pagination size="small" total={list.total} onChange={(e) => {
setList({ setList({
...list, ...list,
pageIndex: page, pageIndex: e
pageSize: pageSize
}) })
}} showSizeChanger pageSizeOptions={[10, 14, 20, 30, 40, 50, 100]} pageSize={list.pageSize} current={list.pageIndex} /> }} pageSize={list.pageSize} current={list.pageIndex} hideOnSinglePage={true} />
</div> </div>
</div> </div>
</div> </div>
<Modal title={isCreateUser === 'add' ? '添加用户' : isCreateUser === 'edit' ? '编辑用户' : '批量修改用户信息'} open={addUserModal} footer={null} closable={false} centered width={'500px'}> <Modal title={isCreateUser ? '添加用户' : '编辑用户'} open={addUserModal} footer={null} closable={false} centered width={'500px'}>
<div> <div>
<div className={styles.addUserModal}> <div className={styles.addUserModal}>
{isCreateUser !== 'batch' ? <div> <div>
<span></span> <span></span>
<Input <Input
style={{ flexGrow: 1 }} style={{ flexGrow: 1 }}
@ -334,7 +285,7 @@ const User: React.FC = () => {
}); });
}} }}
/> />
</div> : null} </div>
<div> <div>
<span></span> <span></span>
<Select <Select
@ -348,7 +299,7 @@ const User: React.FC = () => {
}); });
}} />; }} />;
</div> </div>
{isCreateUser === 'add' ? <div> {isCreateUser ? <div>
<span></span> <span></span>
<Input.Password <Input.Password
placeholder="请输入密码" placeholder="请输入密码"
@ -362,7 +313,7 @@ const User: React.FC = () => {
}} }}
/> />
</div> : null} </div> : null}
{isCreateUser !== 'batch' ? <div> <div>
<span></span> <span></span>
<Input <Input
placeholder="请输入用户名称" placeholder="请输入用户名称"
@ -375,35 +326,6 @@ const User: React.FC = () => {
}); });
}} }}
/> />
</div> : null}
<div>
<span></span>
<Input
placeholder="请输入届"
value={addUserFrom.year}
onChange={(e) => {
const regex = /^[0-9]*$/;
if (regex.test(e.target.value)) {
setAddUserFrom({
...addUserFrom,
year: e.target.value
});
}
}}
/>
</div>
<div>
<span></span>
<Select
placeholder='请选择学科'
style={{ flexGrow: 1 }}
options={subjectList}
value={addUserFrom.subject} onChange={(e) => {
setAddUserFrom({
...addUserFrom,
subject: e
});
}} />
</div> </div>
</div> </div>
<div style={{ <div style={{
@ -411,66 +333,43 @@ const User: React.FC = () => {
}}> }}>
<Button type="primary" style={{ backgroundColor: '#31353A', marginRight: '14px' }} onClick={() => setAddUserModal(false)}></Button> <Button type="primary" style={{ backgroundColor: '#31353A', marginRight: '14px' }} onClick={() => setAddUserModal(false)}></Button>
<Button type="primary" className='m-ant-btn' onClick={async () => { <Button type="primary" className='m-ant-btn' onClick={async () => {
if (!addUserFrom.Account && isCreateUser !== 'batch') { if (!addUserFrom.Account) {
return message.error('请输入账号!') return message.error('请输入账号!')
} }
if (!addUserFrom.RoleId) { if (!addUserFrom.RoleId) {
return message.error('请选择角色!') return message.error('请选择角色!')
} }
if (!addUserFrom.Pwd && isCreateUser === 'add') { if (!addUserFrom.Pwd && isCreateUser) {
return message.error('请输入密码!') return message.error('请输入密码!')
} }
if (!addUserFrom.UserName && isCreateUser !== 'batch') { if (!addUserFrom.UserName) {
return message.error('请输入用户名称!') return message.error('请输入用户名称!')
} }
if (!addUserFrom.year) { if (isCreateUser) {
return message.error('请输入届!')
}
if (addUserFrom.subject === null) {
return message.error('请选择学科!')
}
if (isCreateUser === 'add') {
await PostUser({ await PostUser({
...addUserFrom, ...addUserFrom,
Pwd: CryptoJS.MD5(addUserFrom.Pwd).toString(CryptoJS.enc.Hex) 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)
res.data ? message.success('添加成功!') : message.error('添加失败!') message.success('添加成功!')
} }
}) })
} else if (isCreateUser === 'edit') { } else {
await PutUser({ await PutUser({
Id: addUserFrom.Id, Id: addUserFrom.Id,
Account: addUserFrom.Account, Account: addUserFrom.Account,
RoleId: addUserFrom.RoleId, RoleId: addUserFrom.RoleId,
UserName: addUserFrom.UserName, UserName: addUserFrom.UserName
subject: addUserFrom.subject,
year: addUserFrom.year,
}).then(res => { }).then(res => {
if (res.code === 200) { if (res.code === 200) {
setAddUserModal(false) setAddUserModal(false)
res.data ? message.success('修改成功!') : message.error('修改失败!') message.success('修改成功!')
}
})
} else {
const param = selectedRowKeys.map((item: any) => {
return {
id: item,
subject: addUserFrom.subject,
year: addUserFrom.year,
RoleId: addUserFrom.RoleId,
}
})
await PutUserBth(param).then(res => {
if (res.code === 200) {
setAddUserModal(false)
res.data ? message.success('修改成功!') : message.error('修改失败!')
} }
}) })
} }
await getUserList() await getUserList()
}}>{isCreateUser === 'add' ? '添加' : '修改'}</Button> }}>{isCreateUser ? '添加' : '修改'}</Button>
</div> </div>
</div> </div>
</Modal> </Modal>
@ -543,6 +442,7 @@ const User: React.FC = () => {
DeleteUser(selectedRowKeys).then(res => { DeleteUser(selectedRowKeys).then(res => {
if (res.code === 200) { if (res.code === 200) {
setDeleteUserPawModal(false) setDeleteUserPawModal(false)
setSelectedRowKeys([])
message.success('删除成功!') message.success('删除成功!')
getUserList() getUserList()
} }

View File

@ -811,7 +811,7 @@
} }
} }
.meetingContentFooterPopoverDel { >div:nth-child(1) {
background-color: #FF5219; background-color: #FF5219;
&:hover { &:hover {
@ -823,7 +823,7 @@
} }
} }
.meetingContentFooterPopoverDefault { >div:nth-child(2) {
background-color: #31353A; background-color: #31353A;
&:hover { &:hover {
@ -835,7 +835,7 @@
} }
} }
.meetingContentFooterPopoverCancel { >div:nth-child(3) {
background-color: #101418; background-color: #101418;
&:hover { &:hover {

View File

@ -160,7 +160,6 @@ const Meeting: React.FC = () => {
const [noViewChatList, setNoViewChatList] = useState(0) const [noViewChatList, setNoViewChatList] = useState(0)
const [currentLookUserAccount, setCurrentLookUserAccount] = useState<any>('') const [currentLookUserAccount, setCurrentLookUserAccount] = useState<any>('')
const [recorder, setRecorder] = useState<any>('') const [recorder, setRecorder] = useState<any>('')
const [_currentRequestSpeakType, setCurrentRequestSpeakType] = useState<'video' | 'audio' | ''>('')
const [_mediaStream, setMediaStream] = useState<any>('') const [_mediaStream, setMediaStream] = useState<any>('')
const [isShare, setIsShare] = useState<any>(null) const [isShare, setIsShare] = useState<any>(null)
const [isSharePopConfirm, setIsSharePopConfirm] = useState<any>(false) const [isSharePopConfirm, setIsSharePopConfirm] = useState<any>(false)
@ -414,23 +413,13 @@ const Meeting: React.FC = () => {
} }
} else { } else {
if (item.user.uid === userInfo.uid) { if (item.user.uid === userInfo.uid) {
if (!item.user.isRoomManager) { if (!item.user.isRoomManage) {
await agora.allLeaveChannelEx() await agora.allLeaveChannelEx()
} }
message.success(`管理员${item.user.isRoomManager ? '设置' : '取消'}您为发言人`) message.success(`管理员${item.user.isRoomManager ? '设置' : '取消'}您为发言人`)
await agora.updateChannelMediaOptions(item.user.isRoomManager) await agora.updateChannelMediaOptions(item.user.isRoomManager)
setCurrentRequestSpeakType(res => { await postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
if (res === 'video') { await postOpenCameraApi(item.user.isRoomManager, userInfo.uid)
postOpenCameraApi(item.user.isRoomManager, userInfo.uid)
} else if (res === 'audio') {
postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
} else {
postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
postOpenCameraApi(item.user.isRoomManager, userInfo.uid)
}
return ''
})
await stopScreenCapture() await stopScreenCapture()
} else { } else {
message.success(`管理员${item.user.isRoomManager ? '设置' : '取消'}${item.user.userName}为发言人`) message.success(`管理员${item.user.isRoomManager ? '设置' : '取消'}${item.user.userName}为发言人`)
@ -613,7 +602,6 @@ const Meeting: React.FC = () => {
if (isClicked) { if (isClicked) {
timer = setTimeout(() => { timer = setTimeout(() => {
setIsClicked(false); setIsClicked(false);
setCurrentRequestSpeakType('')
}, 10000); }, 10000);
} }
@ -1011,25 +999,6 @@ const Meeting: React.FC = () => {
} }
// 操作按钮 // 操作按钮
const changeStatusList = async (row: any, itemIndex: number, rowIndex: number): Promise<void> => { const changeStatusList = async (row: any, itemIndex: number, rowIndex: number): Promise<void> => {
function requestSpeak() {
confirm({
title: '提示',
icon: <ExclamationCircleFilled />,
content: `该操作需向管理员申请权限`,
centered: true,
okText: '申请',
cancelText: '取消',
async onOk() {
GetApplySpeak(state.channelId).then(res => {
if (res.code === 200) {
message.success('申请发言成功')
}
})
},
onCancel() {
}
})
}
const footerListTemplate = [...footerList] const footerListTemplate = [...footerList]
setFooterListIndex({ setFooterListIndex({
itemIndex, itemIndex,
@ -1077,37 +1046,13 @@ const Meeting: React.FC = () => {
await postOpenMicr(false, user.uid) await postOpenMicr(false, user.uid)
break; break;
case '解除静音': case '解除静音':
await getUserRoomInfo().then(async (res) => { await postOpenMicr(true, user.uid)
if (res) {
await postOpenMicr(true, user.uid)
} else {
if (!isClicked) {
setCurrentRequestSpeakType('audio')
setIsClicked(true);
requestSpeak()
} else {
message.error('申请太频繁了,请稍后重试!');
}
}
})
break; break;
case '关闭视频': case '关闭视频':
await postOpenCamera(false, user.uid) await postOpenCamera(false, user.uid)
break; break;
case '开启视频': case '开启视频':
await getUserRoomInfo().then(async (res) => { await postOpenCamera(true, user.uid)
if (res) {
await postOpenCamera(true, user.uid)
} else {
if (!isClicked) {
setCurrentRequestSpeakType('video')
setIsClicked(true);
requestSpeak()
} else {
message.error('申请太频繁了,请稍后重试!');
}
}
})
break; break;
case '设置': case '设置':
stupWizardRef.current.changeModal() stupWizardRef.current.changeModal()
@ -1196,7 +1141,11 @@ const Meeting: React.FC = () => {
case '申请发言': case '申请发言':
if (!isClicked) { if (!isClicked) {
setIsClicked(true); setIsClicked(true);
requestSpeak() GetApplySpeak(state.channelId).then(res => {
if (res.code === 200) {
message.success('申请发言成功')
}
})
} else { } else {
message.error('申请太频繁了,请稍后重试!'); message.error('申请太频繁了,请稍后重试!');
} }
@ -2228,11 +2177,11 @@ const Meeting: React.FC = () => {
okText="结束" okText="结束"
cancelText="取消" cancelText="取消"
> >
<div className='meetingContentFooterPopoverDel'></div> <div></div>
</Popconfirm> </Popconfirm>
: null} : null}
<div className='meetingContentFooterPopoverDefault' onClick={() => leaveChannel()}></div> <div onClick={() => leaveChannel()}></div>
<div className='meetingContentFooterPopoverCancel' onClick={() => { setOpen(false) }}></div> <div onClick={() => { setOpen(false) }}></div>
</div> </div>
} }
title="" title=""
@ -2251,12 +2200,12 @@ const Meeting: React.FC = () => {
</div> </div>
</Popover> </Popover>
case '申请发言': case '申请发言':
// if (!role.ID.includes(user.roleId)) { if (!role.ID.includes(user.roleId)) {
// return <div className='drag' onClick={() => changeStatusList(row, itemIndex, rowIndex)} key={rowIndex}> return <div className='drag' onClick={() => changeStatusList(row, itemIndex, rowIndex)} key={rowIndex}>
// <img src={row.active ? row.iconActive : row.icon} alt="" /> <img src={row.active ? row.iconActive : row.icon} alt="" />
// <span>{row.title}</span> <span>{row.title}</span>
// </div> </div>
// } }
return null return null
case '结束发言': case '结束发言':
if (!role.ID.includes(user.roleId)) { if (!role.ID.includes(user.roleId)) {

View File

@ -1,7 +0,0 @@
.shareScreenWindow {
background-color: red;
color: black;
height: 100%;
width: 100%;
font-size: 30px;
}

View File

@ -1,23 +0,0 @@
import styles from '@/page/ShareScreenWindow/index.module.scss'
import { useEffect } from "react";
const ShareScreenWindow: React.FC = () => {
useEffect(() => {
}, []);
// window.electron.createChildWindow({
// url: location.origin + `/#/shareScreenWindow`,
// width: 600,
// height: 40,
// key: 'shareScreenWindow',
// })
return (
<>
<div className={styles.shareScreenWindow}>
2222
</div>
</>
)
}
export default ShareScreenWindow

1
src/render.d.ts vendored
View File

@ -18,7 +18,6 @@ export interface IElectronAPI {
getVersion: () => Promise<string>; getVersion: () => Promise<string>;
setRegistry: (uuid: string) => any; setRegistry: (uuid: string) => any;
getRegistry: () => any; getRegistry: () => any;
createChildWindow: (config: any) => void;
} }
declare global { declare global {

View File

@ -115,15 +115,15 @@ export const agora = {
rtcEngine.registerEventHandler({ rtcEngine.registerEventHandler({
// 监听本地用户加入频道事件 // 监听本地用户加入频道事件
onJoinChannelSuccess: async (connection: RtcConnection, elapsed: number) => { onJoinChannelSuccess: async (connection: RtcConnection, elapsed: number) => {
await onJoinChannelSuccess?.(connection, elapsed) await onJoinChannelSuccess(connection, elapsed)
}, },
// 监听远端用户加入频道事件 // 监听远端用户加入频道事件
onUserJoined: async (connection: RtcConnection, remoteUid: number, elapsed: number) => { onUserJoined: async (connection: RtcConnection, remoteUid: number, elapsed: number) => {
await onUserJoined?.(connection, remoteUid, elapsed) await onUserJoined(connection, remoteUid, elapsed)
}, },
// 监听用户离开频道事件 // 监听用户离开频道事件
onUserOffline: async (connection: RtcConnection, remoteUid: number, reason: UserOfflineReasonType) => { onUserOffline: async (connection: RtcConnection, remoteUid: number, reason: UserOfflineReasonType) => {
await onUserOffline?.(connection, remoteUid, reason) await onUserOffline(connection, remoteUid, reason)
}, },
// // 视频发布状态改变回调 // // 视频发布状态改变回调
// onVideoPublishStateChanged: (source: any, channel: any, oldState: any, newState: any, elapseSinceLastState: any) => { // onVideoPublishStateChanged: (source: any, channel: any, oldState: any, newState: any, elapseSinceLastState: any) => {
@ -139,19 +139,19 @@ export const agora = {
// }, // },
// // 用户音量提示回调。 // // 用户音量提示回调。
onAudioVolumeIndication: async (_connection: RtcConnection, speakers: AudioVolumeInfo[], _speakerNumber: number, _totalVolume: number) => { onAudioVolumeIndication: async (_connection: RtcConnection, speakers: AudioVolumeInfo[], _speakerNumber: number, _totalVolume: number) => {
await onAudioVolumeIndication?.(speakers) await onAudioVolumeIndication(speakers)
}, },
//通话中每个用户的网络上下行 last mile 质量报告回调。 //通话中每个用户的网络上下行 last mile 质量报告回调。
onNetworkQuality: async (connection: RtcConnection, remoteUid: number, txQuality: QualityType, rxQuality: QualityType) => { onNetworkQuality: async (connection: RtcConnection, remoteUid: number, txQuality: QualityType, rxQuality: QualityType) => {
await onNetworkQuality?.(connection, remoteUid, txQuality, rxQuality) await onNetworkQuality(connection, remoteUid, txQuality, rxQuality)
}, },
//当前通话相关的统计信息回调。 //当前通话相关的统计信息回调。
onRtcStats: async (_connection: RtcConnection, stats: RtcStats) => { onRtcStats: async (_connection: RtcConnection, stats: RtcStats) => {
await onRtcStats?.(stats) await onRtcStats(stats)
}, },
// 网络连接状态已改变回调。 // 网络连接状态已改变回调。
onConnectionStateChanged: async (connection: RtcConnection, state: ConnectionStateType, reason: ConnectionChangedReasonType) => { onConnectionStateChanged: async (connection: RtcConnection, state: ConnectionStateType, reason: ConnectionChangedReasonType) => {
await onConnectionStateChanged?.(connection, state, reason) await onConnectionStateChanged(connection, state, reason)
}, },
}); });
}, },

View File

@ -189,6 +189,8 @@ $pagination-hover-background-color: #5575F2;
.ant-pagination-prev, .ant-pagination-prev,
.ant-pagination-next { .ant-pagination-next {
width: 30px !important;
height: 30px !important;
border-radius: 50%; border-radius: 50%;
background: $pagination-background-color; background: $pagination-background-color;
@ -198,6 +200,9 @@ $pagination-hover-background-color: #5575F2;
} }
.ant-pagination-item { .ant-pagination-item {
width: 30px !important;
height: 30px !important;
line-height: 30px !important;
border-radius: 50%; border-radius: 50%;
background: $pagination-background-color !important; background: $pagination-background-color !important;
margin-right: 10px !important; margin-right: 10px !important;

View File

@ -14,7 +14,6 @@ body {
img { img {
display: block; display: block;
-webkit-user-drag: none;
} }