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

413 lines
15 KiB
TypeScript

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 } from "antd";
import { GetRoom, PostRoom, GetCheckoutRoomNum, GetRoomRtcToken, DeleteRoom, GetRecord } 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 { useNavigate } from 'react-router-dom';
import { role } from '@/config/role';
import dayjs from 'dayjs';
import StupWizard from '@/components/StupWizard';
const fs = require('fs').promises;
const { exec } = require('child_process');
const { RangePicker } = DatePicker;
const { confirm } = Modal;
const Index: React.FC = () => {
const navigate = useNavigate();
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<{ roomName: string, roomNum: string }>({
roomName: "",
roomNum: ""
})
const joinSettingRef = useRef<any>();
const stupWizardRef = useRef<any>();
const [user, setUser] = useState<any>({});
const [currentRoomInfo, setCurrentRoomInfo] = useState<any>({});
const userInfo = JSON.parse(storage.getItem('user') as string)
useEffect(() => {
setUser(userInfo)
}, [])
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,
})
}
})
}
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 getRoomRtcToken = async (roomNum: string, callBack: Function): Promise<void> => {
Promise.all([GetRoomRtcToken(roomNum), GetRoomRtcToken(roomNum + 'a')]).then(res => {
if (res[0].code === 200 && res[1].code === 200) {
callBack({
token: res[0].data,
tokenA: res[1].data,
})
}
})
}
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)
}
})
}
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: ""
})
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 onClick={() => copyRoomNum(item.roomNum)} title='复制房间号'>
<span>{item.roomNum}</span>
<img src={ImageUrl.icon10} alt="" />
</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></div>
</Popconfirm> : null}
<div onClick={() => {
changeOpen(index, false)
setTimeSelectModal(true)
}}></div>
<div 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 () => {
if (role.ID.includes(userInfo.roleId)) {
joinSettingRef.current.changeModal(item.roomNum)
} else {
postRefresh(() => {
getRoomRtcToken(item.roomNum, (options: any) => {
if (options) {
navigate(`/meeting`, {
state: {
channelId: item.roomNum,
token: options.token,
tokenA: options.tokenA,
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) => {
setList({
...list,
pageIndex: e
})
}} pageSize={list.pageSize} />
</div>
</div>
</div>
<Modal title="新建会议室" open={createRoomModal} footer={null} closable={false} centered width={'400px'}>
<div>
<div>
<Input
placeholder="请输入房间号"
style={{ marginBottom: '14px' }}
className={styles.letterSpacing}
showCount
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>
}
/>
<Input.TextArea
placeholder="请输入房间名字"
style={{ marginBottom: '14px' }}
showCount
maxLength={30}
value={createRoomFrom.roomName}
onChange={(e) => {
setCreateRoomFrom({
...createRoomFrom,
roomName: e.target.value
})
}}
autoSize />
</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('请输入房间号!')
}
isGetCheckoutRoomNum(createRoomFrom.roomNum, (bool: boolean) => {
if (bool) {
message.error('房间号已存在!')
} else {
PostRoom(createRoomFrom).then(res => {
if (res.code === 200) {
message.success('创建成功!')
setCreateRoomModal(false)
getRoomList()
}
})
}
})
}}></Button>
</div>
</div>
</Modal>
<Modal title="选择时间段" destroyOnClose={true} open={timeSelectModal} footer={null} onCancel={() => setTimeSelectModal(false)} centered width={'400px'}>
<div>
<RangePicker
showTime={{ format: 'YYYY-MM-DD HH:mm:ss' }}
format="YYYY-MM-DD HH:mm:ss"
onChange={(_value, dateString) => {
const setting = JSON.parse(storage.getItem('setting') as string)
if (dateString.length === 2) {
GetRecord(dayjs(dateString[0]).unix(), dayjs(dateString[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)
})
}
}}
/>
</div>
</Modal>
<JoinSetting ref={joinSettingRef} />
<StupWizard ref={stupWizardRef} />
</>
)
}
export default Index