WGShare.Client.Electron/src/page/Home/Index/index.tsx

554 lines
21 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import styles from '@/page/Home/Index/index.module.scss'
import { useEffect, useState, useRef } from "react";
import Operation from '@/components/Operation';
import { Button, Input, Modal, Pagination, Empty, message, Popover, Popconfirm, DatePicker, Select, Radio } from "antd";
import { GetRoom, PostRoom, GetCheckoutRoomNum, GetRoomRtcToken, DeleteRoom, GetRecord, PostRoomInfo } from '@/api/Home/Index';
import ImageUrl from '@/utils/package/imageUrl'
import { ExclamationCircleFilled, ReloadOutlined } from '@ant-design/icons';
import JoinSetting from '@/components/JoinSetting';
import { storage } from '@/utils';
import { PostRefresh } from '@/api/Login';
import { useLocation, useNavigate } from 'react-router-dom';
import { role } from '@/config/role';
import dayjs from 'dayjs';
import StupWizard from '@/components/StupWizard';
import { GetSubDpList } from '@/api/Home/User';
import FeedBackModel from '@/components/FeedBackModel';
import { PostHomeVerLog } from '@/api/Meeting';
import Code from '@/components/Code';
import { isVersion } from "@/utils/package/public";
const { setInterval, clearInterval } = require('timers');
const fs = require('fs').promises;
const { exec } = require('child_process');
const { RangePicker } = DatePicker;
const { confirm } = Modal;
const Index: React.FC = () => {
const navigate = useNavigate();
const { state } = useLocation();
const [list, setList] = useState({
data: [],
total: 0,
pageIndex: 1,
pageSize: 12,
})
const [createRoomModal, setCreateRoomModal] = useState(false)
const [timeSelectModal, setTimeSelectModal] = useState(false)
const [createRoomFrom, setCreateRoomFrom] = useState<{ id: string, roomName: string, roomNum: string, subject: number, year: string }>({
id: "",
roomName: "",
roomNum: "",
subject: 0,
year: "0"
})
const joinSettingRef = useRef<any>();
const stupWizardRef = useRef<any>();
const feedBackModelRef = useRef<any>();
const [user, setUser] = useState<any>({});
const [currentRoomInfo, setCurrentRoomInfo] = useState<any>({});
const [subjectList, setSubjectList] = useState<any>([]);
const [timeData, setTimeData] = useState<any>([]);
const [isCreateRoom, setIsCreateRoom] = useState<boolean>(false);
const [allowAnonymous, setAllowAnonymous] = useState(true);
const userInfo = JSON.parse(storage.getItem('user') as string)
useEffect(() => {
setUser(userInfo)
if (state?.currentSeconds >= 600) {
feedBackModelRef.current.changeModal()
}
}, [])
useEffect(() => {
let time = null as any
if (time) {
clearInterval(time)
} else {
time = setInterval(() => {
getRoomList()
}, 1000 * 30)
}
getRoomList()
return () => {
clearInterval(time)
}
}, [list.pageIndex]);
const getRoomList = async (): Promise<void> => {
await GetRoom({
pageIndex: list.pageIndex,
pageSize: list.pageSize,
}).then(res => {
if (res.code === 200) {
setList({
...list,
total: res.data.total,
data: res.data.items.map((item: any) => {
return {
...item,
open: false
}
}),
})
}
})
}
const copyRoomNum = (roomNum: string): void => {
window.electron.setWriteText(roomNum)
message.success('复制成功')
}
const isGetCheckoutRoomNum = async (roomNum: string, callBack: Function): Promise<void> => {
await GetCheckoutRoomNum(roomNum).then(res => {
if (res.code === 200) {
callBack(res.data)
}
})
}
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> => {
GetRoomRtcToken(roomNum).then(res => {
if (res.code === 200) {
callBack({
token: res.data,
})
}
}).finally(() => {
storage.setItem('loading', false)
})
}
const postRefresh = async (callBack: Function): Promise<void> => {
await PostRefresh(user.refresh_token).then(res => {
if (res.code === 200) {
storage.setItem('user', JSON.stringify(res.data))
storage.setItem('userLogin', true)
callBack(res.data)
} else {
storage.setItem('loading', false)
}
}).catch(() => {
storage.setItem('loading', false)
})
}
const changeOpen = (index: number, bool: boolean): void => {
const newList = [...list.data] as any;
newList[index].open = bool
setList({
...list,
data: newList
})
}
const fileUpLoad = async (data: { url: string, content: string, fileName: string }): Promise<void> => {
const setting = await JSON.parse(storage.getItem('setting') as string)
try {
const response = await fetch(data.url);
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
await fs.writeFile(`${setting.shareFilesPath}\\${data.fileName}`, buffer, {});
confirm({
title: '提示',
icon: <ExclamationCircleFilled />,
content: data.content,
centered: true,
okText: '打开文件夹',
cancelText: '关闭',
async onOk() {
await fs.access(setting.shareFilesPath, fs.constants.F_OK);
if (process.platform === 'win32') {
exec(`explorer "${setting.shareFilesPath}"`);
} else if (process.platform === 'darwin') {
exec(`open "${setting.shareFilesPath}"`);
}
},
onCancel() {
}
})
} catch (error: any) {
if (error.code === 'ENOENT') {
message.error({
content: <div> <span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
stupWizardRef.current.changeModal(4)
}}></span></div>
})
return
} else {
message.error(error)
}
}
}
return (
<>
<div className={styles.index}>
<div className={styles.indexOperation}>
<Operation></Operation>
</div>
<div className={styles.indexBtns}>
{user?.roleId === '1' ? <Button type="primary"
icon={<img src={ImageUrl.icon8} alt="" />}
className='m-ant-btn drag'
onClick={() => {
setCreateRoomFrom({
roomName: "",
roomNum: "",
subject: 0,
year: "0",
id: "",
})
getSubDpList()
setIsCreateRoom(true)
setCreateRoomModal(true)
}}
style={{ marginRight: '22px' }}
>
</Button> : null}
<Button type="primary" onClick={() => {
joinSettingRef.current.changeModal()
}}
icon={<img src={ImageUrl.icon8} alt="" />}
className={`${styles.indexBtnsJoin} drag`}>
</Button>
</div>
<div className={styles.indexContent}>
<div className={`drag ${styles.indexContentTitle}`}>
<span></span>
<ReloadOutlined
title='刷新'
style={{
cursor: 'pointer',
}}
onClick={() => {
message.success('刷新成功')
getRoomList()
}}
/>
</div>
{list.data.length ? <div className={`drag ${styles.indexContentList}`}>
{list.data.map((item: any, index: number) => {
return (
<div className={`${styles.indexContentListItem}`} key={index}>
<div>
<div>{item.roomName}</div>
<div>
<img src={ImageUrl.icon11} alt="" />
<span>{item.onlineUserCount}</span>
</div>
</div>
<div>
<div>
<div onClick={() => copyRoomNum(item.roomNum)} title='复制房间号'>
<span>{item.roomNum}</span>
<img src={ImageUrl.icon10} alt="" />
</div>
<Code roomNum={item.roomNum}></Code>
</div>
<div>
{role.ID.includes(userInfo.roleId) ? <Popover
content={
<div className='meetingContentFooterPopover'>
{userInfo.roleId === '1' ? <Popconfirm
title="提示"
description={`确定删除该会议吗`}
onConfirm={async () => {
DeleteRoom(item.id).then((res) => {
if (res.code === 200) {
message.success('删除成功')
changeOpen(index, false)
getRoomList()
}
})
}}
onCancel={() => {
changeOpen(index, false)
}}
okText="确定"
cancelText="取消"
>
<div className='meetingContentFooterPopoverDel'></div>
</Popconfirm> : null}
<div className='meetingContentFooterPopoverDefault' onClick={() => {
changeOpen(index, false)
setTimeSelectModal(true)
}}></div>
<div className='meetingContentFooterPopoverDefault' onClick={() => {
changeOpen(index, false)
setCreateRoomFrom({
roomName: item.roomName,
roomNum: item.roomNum,
subject: item.subject,
year: item.year,
id: item.id,
})
setAllowAnonymous(item.allowAnonymous)
getSubDpList()
setIsCreateRoom(false)
setCreateRoomModal(true)
}}></div>
<div className='meetingContentFooterPopoverCancel' onClick={() => {
changeOpen(index, false)
}}></div>
</div>
}
title=""
trigger="click"
open={item.open}
onOpenChange={() => {
setCurrentRoomInfo(list.data[index])
changeOpen(index, true)
}}
>
<Button type="primary" danger></Button>
</Popover> : null}
<Button type="primary"
iconPosition={'end'}
onClick={async () => {
storage.setItem('loading', true)
isVersion((bool: boolean) => {
storage.setItem('loading', false)
if (bool) {
window.electron.onDownload('3')
} else {
if (role.ID.includes(userInfo.roleId)) {
joinSettingRef.current.changeModal(item.roomNum)
} else {
storage.setItem('loading', true)
postRefresh(() => {
getRoomRtcToken(item.roomNum, async (options: any) => {
if (options) {
await window.electron.getVersion().then(async req => {
await PostHomeVerLog({
version: req,
platformType: 1,
roomNum: item.roomNum,
})
})
navigate(`/meeting`, {
state: {
channelId: item.roomNum,
token: options.token,
roomId: item.id,
roomName: item.roomName,
enableMicr: false,
enableCamera: false,
}
})
}
})
})
}
}
})
}}
icon={<img src={ImageUrl.icon9} alt="" />}
className='m-ant-btn'>
</Button>
</div>
</div>
</div>
)
})}
<div style={{ visibility: 'hidden', margin: 0, padding: 0 }} className={`${styles.indexContentListItem} drag`}></div>
<div style={{ visibility: 'hidden', margin: 0, padding: 0 }} className={`${styles.indexContentListItem} drag`}></div>
</div> :
<div className={styles.indexContentEmpty}>
<Empty />
</div>
}
<div className={styles.indexContentPagination}>
<Pagination size="small" total={list.total} onChange={(e: number) => {
setList({
...list,
pageIndex: e
})
}} pageSize={list.pageSize} showSizeChanger={false} />
</div>
</div>
</div>
<Modal title={isCreateRoom ? '新建会议室' : '修改会议信息'} open={createRoomModal} footer={null} closable={false} centered width={'400px'}>
<div>
<div className={styles.createRoom}>
{isCreateRoom ? <div>
<span></span>
<Input
placeholder="请输入房间号"
style={{ flexGrow: 1 }}
className={styles.letterSpacing}
maxLength={8}
value={createRoomFrom.roomNum}
onChange={(e) => {
const regex = /^[0-9]*$/;
if (regex.test(e.target.value)) {
setCreateRoomFrom({
...createRoomFrom,
roomNum: e.target.value
})
}
}}
suffix={
<span
style={{ color: '#47D3D0', cursor: 'pointer' }}
onClick={() => {
function generateTimestampWithRandom(): string {
const timestamp = new Date().getTime();
const lastSixDigits = timestamp.toString().slice(-6);
const randomTwoDigits = ('0' + Math.floor(Math.random() * 100)).slice(-2);
return lastSixDigits + randomTwoDigits;
}
setCreateRoomFrom({
...createRoomFrom,
roomNum: generateTimestampWithRandom(),
})
}}
>
</span>
}
/>
</div> : null}
<div>
<span></span>
<Input.TextArea
placeholder="请输入房间名字"
style={{ flexGrow: 1 }}
maxLength={30}
value={createRoomFrom.roomName}
onChange={(e) => {
setCreateRoomFrom({
...createRoomFrom,
roomName: e.target.value
})
}}
autoSize />
</div>
<div>
<span></span>
<Input
placeholder="请输入届"
maxLength={4}
style={{ flexGrow: 1 }}
value={createRoomFrom.year}
onChange={(e) => {
const regex = /^[0-9]*$/;
if (regex.test(e.target.value)) {
setCreateRoomFrom({
...createRoomFrom,
year: e.target.value
})
}
}}
/>
</div>
<div>
<span></span>
<Select
placeholder='请选择学科'
style={{ flexGrow: 1 }}
options={subjectList}
value={createRoomFrom.subject} onChange={(e) => {
setCreateRoomFrom({
...createRoomFrom,
subject: e
})
}} />
</div>
<div>
<span></span>
<Radio.Group onChange={(e) => {
setAllowAnonymous(e.target.value);
}} value={allowAnonymous}>
<Radio value={true}></Radio>
<Radio value={false}></Radio>
</Radio.Group>
</div>
</div>
<div style={{
display: 'flex', justifyContent: 'center'
}}>
<Button type="primary" style={{ backgroundColor: '#31353A', marginRight: '14px' }} onClick={() => setCreateRoomModal(false)}></Button>
<Button type="primary" className='m-ant-btn' onClick={() => {
if (!createRoomFrom.roomName) {
return message.error('请输入房间名字!')
}
if (!createRoomFrom.roomNum) {
return message.error('请输入房间号!')
}
if (createRoomFrom.year === "") {
return message.error('请输入届!')
}
if (isCreateRoom) {
isGetCheckoutRoomNum(createRoomFrom.roomNum, (bool: boolean) => {
if (bool) {
message.error('房间号已存在!')
} else {
PostRoom({ ...createRoomFrom, allowAnonymous }).then(res => {
if (res.code === 200) {
message.success('创建成功!')
setCreateRoomModal(false)
setAllowAnonymous(true)
getRoomList()
}
})
}
})
} else {
PostRoomInfo({ ...createRoomFrom, allowAnonymous }).then(res => {
if (res.code === 200) {
message.success('更新成功!')
setCreateRoomModal(false)
setAllowAnonymous(true)
getRoomList()
}
})
}
}}>{isCreateRoom ? '创建' : '更新'}</Button>
</div>
</div>
</Modal>
<Modal title="选择时间段" destroyOnClose={true} open={timeSelectModal} footer={null} onCancel={() => setTimeSelectModal(false)} centered maskClosable={false} width={'400px'}>
<div>
<RangePicker
showTime={{ format: 'YYYY-MM-DD HH:mm:ss' }}
format="YYYY-MM-DD HH:mm:ss"
onChange={(_value, dateString) => {
setTimeData(dateString)
}}
/>
<div style={{ display: 'flex', justifyContent: 'center', marginTop: '10px' }}>
<Button type="primary"
style={{ backgroundColor: '#31353A', marginRight: '10px' }}
onClick={() => setTimeSelectModal(false)}></Button>
<Button type="primary" className='m-ant-btn' onClick={async () => {
const setting = JSON.parse(storage.getItem('setting') as string)
if (timeData.length === 2) {
GetRecord(dayjs(timeData[0]).unix(), dayjs(timeData[1]).unix(), currentRoomInfo.roomNum).then(res => {
if (res.code === 200) {
const fileName = res.data.split('/').pop().split('?')[0];
fileUpLoad({
url: res.data,
content: `下载参会记录成功!文件已保存至:${setting.shareFilesPath}`,
fileName
})
}
setTimeSelectModal(false)
})
}
}}></Button>
</div>
</div>
</Modal>
<JoinSetting ref={joinSettingRef} />
<StupWizard ref={stupWizardRef} />
<FeedBackModel ref={feedBackModelRef} />
</>
)
}
export default Index