This commit is contained in:
parent
77578dd8a8
commit
a5e58c2898
17
main.js
17
main.js
|
|
@ -1,4 +1,4 @@
|
||||||
const { app, BrowserWindow, screen, Tray, nativeImage, Menu, ipcMain, clipboard, dialog, webFrame } = require('electron');
|
const { app, BrowserWindow, screen, Tray, nativeImage, Menu, ipcMain, clipboard, dialog, webFrame, Notification } = require('electron');
|
||||||
const path = require('node:path')
|
const path = require('node:path')
|
||||||
app.allowRendererProcessReuse = false;
|
app.allowRendererProcessReuse = false;
|
||||||
let mainWindow = null;
|
let mainWindow = null;
|
||||||
|
|
@ -94,6 +94,16 @@ function createWindow() {
|
||||||
mainWindow.focus();
|
mainWindow.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createNotification(user) {
|
||||||
|
const notification = new Notification({
|
||||||
|
title: `${user.name} 邀请你加入`,
|
||||||
|
body: user.body,
|
||||||
|
icon: path.join(`${__dirname}/src/assets/avatar.png`)
|
||||||
|
});
|
||||||
|
notification.show();
|
||||||
|
mainWindow.focus();
|
||||||
|
}
|
||||||
|
|
||||||
app.on('ready', () => {
|
app.on('ready', () => {
|
||||||
createWindow()
|
createWindow()
|
||||||
createTray()
|
createTray()
|
||||||
|
|
@ -146,6 +156,11 @@ app.on('ready', () => {
|
||||||
clipboard.writeText(text)
|
clipboard.writeText(text)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 加入房间通知
|
||||||
|
ipcMain.handle('joinNotification', (event, user) => {
|
||||||
|
createNotification(user)
|
||||||
|
});
|
||||||
|
|
||||||
// 设置桌面应用基础属性
|
// 设置桌面应用基础属性
|
||||||
ipcMain.handle('setMainWindowSize', (event, config) => {
|
ipcMain.handle('setMainWindowSize', (event, config) => {
|
||||||
// 设置最小窗口尺寸
|
// 设置最小窗口尺寸
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,9 @@ window.electron = {
|
||||||
// 复制文字
|
// 复制文字
|
||||||
setWriteText: (text) => {
|
setWriteText: (text) => {
|
||||||
return ipcRenderer.invoke('setWriteText', text)
|
return ipcRenderer.invoke('setWriteText', text)
|
||||||
|
},
|
||||||
|
// 加入房间通知
|
||||||
|
joinNotification: (user) => {
|
||||||
|
ipcRenderer.invoke('joinNotification', user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
21
src/App.tsx
21
src/App.tsx
|
|
@ -10,6 +10,7 @@ import Meeting from '@/page/Meeting/index'
|
||||||
import NotFound from '@/page/NotFound/index'
|
import NotFound from '@/page/NotFound/index'
|
||||||
import { storage } from '@/utils'
|
import { storage } from '@/utils'
|
||||||
import { Spin } from "antd";
|
import { Spin } from "antd";
|
||||||
|
import { onSignalr, offSignalr } from "@/utils/package/signalr";
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
@ -19,7 +20,7 @@ const App: React.FC = () => {
|
||||||
});
|
});
|
||||||
const [spinning, setSpinning] = useState(false);
|
const [spinning, setSpinning] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (storage.getItem('TOKEN')) {
|
if (storage.getItem('user')) {
|
||||||
try {
|
try {
|
||||||
window.electron.setMainWindowSize({
|
window.electron.setMainWindowSize({
|
||||||
width: 1200,
|
width: 1200,
|
||||||
|
|
@ -57,7 +58,21 @@ const App: React.FC = () => {
|
||||||
window.removeEventListener('customStorageChange', handleCustomStorageChange);
|
window.removeEventListener('customStorageChange', handleCustomStorageChange);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
onSignalr((item: any) => {
|
||||||
|
switch (item.key) {
|
||||||
|
case 'Invitation':
|
||||||
|
window.electron.joinNotification({
|
||||||
|
body: item.roomName,
|
||||||
|
name: item.InviterName,
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
offSignalr()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
const handleResize = (): void => {
|
const handleResize = (): void => {
|
||||||
setWindowSize({
|
setWindowSize({
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
|
|
@ -75,6 +90,8 @@ const App: React.FC = () => {
|
||||||
setSpinning(Boolean(e.value))
|
setSpinning(Boolean(e.value))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Routes>
|
<Routes>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { request } from '@/utils'
|
import { request } from '@/utils'
|
||||||
export const GetUserList = (data: { pageIndex: number, pageSize: number, searchKeywod: string }) =>
|
export const GetUserList = (data: any) =>
|
||||||
request({
|
request({
|
||||||
url: `/user/list?pageIndex=${data.pageIndex}&pageSize=${data.pageSize}&searchKeywod=${data.searchKeywod}`,
|
url: `/user/list`,
|
||||||
method: 'get'
|
method: 'get',
|
||||||
|
data
|
||||||
})
|
})
|
||||||
|
|
||||||
export const PostUser = (data: any) =>
|
export const PostUser = (data: any) =>
|
||||||
|
|
|
||||||
|
|
@ -86,3 +86,10 @@ export const GetSyncView = (roomNum: string, type: string) =>
|
||||||
url: `/room/sync-view?roomNum=${roomNum}&type=${type}`,
|
url: `/room/sync-view?roomNum=${roomNum}&type=${type}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const PostRoomInvite = (roomId: string, data: any) =>
|
||||||
|
request({
|
||||||
|
url: `/room/invite?roomId=${roomId}`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
.invitingPersonnelModal {
|
||||||
|
.invitingPersonnelModalContent {
|
||||||
|
height: 382px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.invitingPersonnelModalContentLeft {
|
||||||
|
height: 100%;
|
||||||
|
background-color: #181A1D;
|
||||||
|
width: 50%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.invitingPersonnelModalContentLeftUserList {
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
>div:nth-child(1) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
>div:nth-child(2) {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 0 10px;
|
||||||
|
|
||||||
|
>img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
>span {
|
||||||
|
font-size: 14px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
>div:nth-child(2) {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.invitingPersonnelModalContentRight {
|
||||||
|
height: 100%;
|
||||||
|
background-color: #101317;
|
||||||
|
width: 50%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
>span {
|
||||||
|
font-size: 16px;
|
||||||
|
color: white;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
>div {
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 0 10px;
|
||||||
|
|
||||||
|
>img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
>span {
|
||||||
|
font-size: 14px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.invitingPersonnelModalFooter {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,180 @@
|
||||||
|
import styles from '@/components/InvitingPersonnelModal/index.module.scss'
|
||||||
|
import { Button, Checkbox, Input, Modal, Pagination, message } from 'antd';
|
||||||
|
import { useState, useImperativeHandle, forwardRef, useEffect } from "react";
|
||||||
|
import ImageUrl from '@/utils/package/imageUrl';
|
||||||
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
|
import { GetUserList } from '@/api/Home/User';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { PostRoomInvite } from '@/api/Meeting';
|
||||||
|
const InvitingPersonnelModal = forwardRef((props: any, ref: any) => {
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
changeInvitingPersonnelModal: () => {
|
||||||
|
setIsInvitingPersonnelModal(true)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
const { state } = useLocation();
|
||||||
|
const [isInvitingPersonnelModal, setIsInvitingPersonnelModal] = useState(false);
|
||||||
|
const [operation, setOperation] = useState<{
|
||||||
|
options: { label: string; value: number }[];
|
||||||
|
optionsValue: number[];
|
||||||
|
}>({
|
||||||
|
options: [
|
||||||
|
{ label: '在线', value: 1 },
|
||||||
|
{ label: '不在线', value: 2 },
|
||||||
|
],
|
||||||
|
optionsValue: [1, 2]
|
||||||
|
});
|
||||||
|
const [list, setList] = useState<any>({
|
||||||
|
data: [],
|
||||||
|
searchKeywod: '',
|
||||||
|
total: 0,
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 5,
|
||||||
|
})
|
||||||
|
const [checkedList, setCheckedList] = useState<any>([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getUserList()
|
||||||
|
}, [list.pageIndex]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (list.pageIndex === 1) {
|
||||||
|
getUserList()
|
||||||
|
} else {
|
||||||
|
setList({
|
||||||
|
...list,
|
||||||
|
pageIndex: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [operation.optionsValue]);
|
||||||
|
|
||||||
|
// 设置勾选
|
||||||
|
const changeOptionsValue = (checkedValues: number[]): void => {
|
||||||
|
setOperation({
|
||||||
|
...operation,
|
||||||
|
optionsValue: checkedValues,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
// 获取用户列表
|
||||||
|
const getUserList = async (): Promise<void> => {
|
||||||
|
await GetUserList({
|
||||||
|
pageIndex: list.pageIndex,
|
||||||
|
pageSize: list.pageSize,
|
||||||
|
searchKeywod: list.searchKeywod,
|
||||||
|
isOnline: operation.optionsValue.length === 1 ? operation.optionsValue[0] === 1 ? true : false : '',
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
setList({
|
||||||
|
...list,
|
||||||
|
total: res.data.total,
|
||||||
|
data: res.data.items.map((item: any) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
checked: checkedList.find((checkedItem: any) => checkedItem.id === item.id) ? true : false,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Modal
|
||||||
|
title="邀请成员"
|
||||||
|
open={isInvitingPersonnelModal}
|
||||||
|
footer={null}
|
||||||
|
onCancel={() => setIsInvitingPersonnelModal(false)}
|
||||||
|
centered
|
||||||
|
width={'560px'}
|
||||||
|
>
|
||||||
|
<div className={styles.invitingPersonnelModal}>
|
||||||
|
<div className={styles.invitingPersonnelModalContent}>
|
||||||
|
<div className={styles.invitingPersonnelModalContentLeft}>
|
||||||
|
<Input
|
||||||
|
placeholder="请输入成员名称"
|
||||||
|
style={{ width: '100%', flexShrink: 0 }}
|
||||||
|
prefix={<SearchOutlined style={{ color: 'white' }} />}
|
||||||
|
value={list.searchKeywod}
|
||||||
|
onChange={(e) => {
|
||||||
|
setList({
|
||||||
|
...list,
|
||||||
|
searchKeywod: e.target.value,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
onPressEnter={() => {
|
||||||
|
if (list.pageIndex === 1) {
|
||||||
|
getUserList()
|
||||||
|
} else {
|
||||||
|
setList({
|
||||||
|
...list,
|
||||||
|
pageIndex: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Checkbox.Group
|
||||||
|
style={{ flexShrink: 0, margin: '10px 0' }}
|
||||||
|
options={operation.options}
|
||||||
|
value={operation.optionsValue}
|
||||||
|
onChange={changeOptionsValue}
|
||||||
|
/>
|
||||||
|
<div className={styles.invitingPersonnelModalContentLeftUserList}>
|
||||||
|
{list.data.length ? list.data.map((item: any, index: number) => <div key={item.id}>
|
||||||
|
<div >
|
||||||
|
<Checkbox onChange={(e) => {
|
||||||
|
const newData = [...list.data] as any;
|
||||||
|
newData[index].checked = e.target.checked
|
||||||
|
setList({
|
||||||
|
...list,
|
||||||
|
data: newData,
|
||||||
|
})
|
||||||
|
setCheckedList((checkedList: any) => {
|
||||||
|
if (newData[index].checked) {
|
||||||
|
return [...checkedList, newData[index]]
|
||||||
|
} else {
|
||||||
|
checkedList.splice(checkedList.findIndex((item: any) => item.id === newData[index].id), 1);
|
||||||
|
return checkedList
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}} defaultChecked={item.checked}></Checkbox>
|
||||||
|
<div><img src={ImageUrl.avatar} alt="" /></div>
|
||||||
|
<span>{item.userName}</span>
|
||||||
|
</div>
|
||||||
|
<div style={{ color: item.isOnline ? '#02B188' : 'rgb(221 11 11)' }}>{item.isOnline ? '在线' : '离线'}</div>
|
||||||
|
</div>) : <span style={{ display: 'block', textAlign: 'center', color: 'white', padding: '30px 0' }}>暂无数据</span>}
|
||||||
|
</div>
|
||||||
|
<Pagination size="small" total={list.total} style={{ flexShrink: 0, margin: '10px 0 0' }} onChange={(e) => {
|
||||||
|
setList({
|
||||||
|
...list,
|
||||||
|
pageIndex: e
|
||||||
|
})
|
||||||
|
}} pageSize={list.pageSize} current={list.pageIndex} hideOnSinglePage={true} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.invitingPersonnelModalContentRight}>
|
||||||
|
<span>已选成员</span>
|
||||||
|
<div>
|
||||||
|
{checkedList.map((item: any, index: number) => <div key={item.id + index}>
|
||||||
|
<div><img src={ImageUrl.avatar} alt="" /></div>
|
||||||
|
<span>{item.userName}</span>
|
||||||
|
</div>)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.invitingPersonnelModalFooter}>
|
||||||
|
<Button type="primary" onClick={() => { setIsInvitingPersonnelModal(false) }} style={{ backgroundColor: '#31353A', marginRight: '14px' }}>取消</Button>
|
||||||
|
<Button type="primary" className='m-ant-btn' onClick={() => {
|
||||||
|
if (checkedList.length) {
|
||||||
|
PostRoomInvite(state.roomId, checkedList.map((item: any) => item.id))
|
||||||
|
} else {
|
||||||
|
message.error('请选择人员')
|
||||||
|
}
|
||||||
|
}}>呼叫</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export default InvitingPersonnelModal
|
||||||
|
|
@ -124,7 +124,8 @@ const Index: React.FC = () => {
|
||||||
state: {
|
state: {
|
||||||
channelId: item.roomNum,
|
channelId: item.roomNum,
|
||||||
token: res,
|
token: res,
|
||||||
roomId: item.id
|
roomId: item.id,
|
||||||
|
roomName: item.roomName,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -263,7 +264,8 @@ const Index: React.FC = () => {
|
||||||
state: {
|
state: {
|
||||||
channelId: joinRoomFrom,
|
channelId: joinRoomFrom,
|
||||||
token,
|
token,
|
||||||
roomId: res.data.id
|
roomId: res.data.id,
|
||||||
|
roomName: res.data.roomName,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,7 @@ const User: React.FC = () => {
|
||||||
<Input
|
<Input
|
||||||
placeholder="请输入用户名"
|
placeholder="请输入用户名"
|
||||||
prefix={<SearchOutlined style={{ color: 'white' }} />}
|
prefix={<SearchOutlined style={{ color: 'white' }} />}
|
||||||
|
value={list.searchKeywod}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setList({
|
setList({
|
||||||
...list,
|
...list,
|
||||||
|
|
@ -156,7 +157,7 @@ const User: React.FC = () => {
|
||||||
<Column title="角色" dataIndex="roleName" key="roleName" />
|
<Column title="角色" dataIndex="roleName" key="roleName" />
|
||||||
<Column title="在线状态" render={(item) => (
|
<Column title="在线状态" render={(item) => (
|
||||||
<>
|
<>
|
||||||
<div style={{ color: '#02B188' }}>{item.account}</div>
|
<div style={{ color: item.isOnline ? '#02B188' : 'rgb(221 11 11)' }}>{item.isOnline ? '在线' : '离线'}</div>
|
||||||
</>
|
</>
|
||||||
)} />
|
)} />
|
||||||
<Column title="操作" render={(item) => (
|
<Column title="操作" render={(item) => (
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import dayjs from 'dayjs';
|
||||||
import 'dayjs/locale/zh-cn'
|
import 'dayjs/locale/zh-cn'
|
||||||
import { storage } from '@/utils';
|
import { storage } from '@/utils';
|
||||||
import ImageUrl from '@/utils/package/imageUrl'
|
import ImageUrl from '@/utils/package/imageUrl'
|
||||||
|
import { startSignalr } from '@/utils/package/signalr';
|
||||||
dayjs.locale('zh-cn');
|
dayjs.locale('zh-cn');
|
||||||
type navListType = {
|
type navListType = {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
@ -48,9 +49,8 @@ const Home: React.FC = () => {
|
||||||
})
|
})
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const user = JSON.parse(storage.getItem('user') as string);
|
const user = JSON.parse(storage.getItem('user') as string);
|
||||||
if (user) {
|
setUserInfo(user)
|
||||||
setUserInfo(user)
|
startSignalr()
|
||||||
}
|
|
||||||
const updateTime = () => {
|
const updateTime = () => {
|
||||||
setDateInfo({
|
setDateInfo({
|
||||||
work: dayjs().format('ddd'),
|
work: dayjs().format('ddd'),
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import { Input, Button, Checkbox, message } from "antd"
|
||||||
import { storage } from '@/utils'
|
import { storage } from '@/utils'
|
||||||
import { GetCheckUser, PostLogin } from '@/api/Login'
|
import { GetCheckUser, PostLogin } from '@/api/Login'
|
||||||
import * as CryptoJS from 'crypto-js';
|
import * as CryptoJS from 'crypto-js';
|
||||||
import { startSignalr } from '@/utils/package/signalr'
|
|
||||||
import ImageUrl from '@/utils/package/imageUrl'
|
import ImageUrl from '@/utils/package/imageUrl'
|
||||||
|
|
||||||
const Login: React.FC = () => {
|
const Login: React.FC = () => {
|
||||||
|
|
@ -127,7 +126,6 @@ const Login: React.FC = () => {
|
||||||
|
|
||||||
}
|
}
|
||||||
navigate('/home')
|
navigate('/home')
|
||||||
startSignalr()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,14 @@ import { onInvoke, onSignalr, offSignalr } from '@/utils/package/signalr';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import durationPlugin from 'dayjs/plugin/duration';
|
import durationPlugin from 'dayjs/plugin/duration';
|
||||||
import { VideoSourceType } from 'agora-electron-sdk';
|
import { VideoSourceType } from 'agora-electron-sdk';
|
||||||
|
import InvitingPersonnelModal from '@/components/InvitingPersonnelModal';
|
||||||
dayjs.extend(durationPlugin);
|
dayjs.extend(durationPlugin);
|
||||||
const { Column } = Table
|
const { Column } = Table
|
||||||
const Meeting: React.FC = () => {
|
const Meeting: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { state } = useLocation();
|
const { state } = useLocation();
|
||||||
const speakerModeModalRef = useRef<any>();
|
const speakerModeModalRef = useRef<any>();
|
||||||
|
const invitingPersonnelRef = useRef<any>();
|
||||||
const [statusList, setStatusList] = useState({
|
const [statusList, setStatusList] = useState({
|
||||||
userList: false,
|
userList: false,
|
||||||
userChatList: false,
|
userChatList: false,
|
||||||
|
|
@ -270,6 +272,9 @@ const Meeting: React.FC = () => {
|
||||||
break;
|
break;
|
||||||
case '设置向导':
|
case '设置向导':
|
||||||
|
|
||||||
|
break;
|
||||||
|
case '邀请人员':
|
||||||
|
invitingPersonnelRef.current.changeInvitingPersonnelModal()
|
||||||
break;
|
break;
|
||||||
case '录制':
|
case '录制':
|
||||||
if (currentVideoId === user.account) {
|
if (currentVideoId === user.account) {
|
||||||
|
|
@ -561,7 +566,7 @@ const Meeting: React.FC = () => {
|
||||||
{roomUserList.map((item: any, index: number) => {
|
{roomUserList.map((item: any, index: number) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{item.isShow ? <div key={index} className='drag'>
|
{item.isShow ? <div key={index + item.id} className='drag'>
|
||||||
<div>
|
<div>
|
||||||
<div><img src={ImageUrl.avatar} alt="" /></div>
|
<div><img src={ImageUrl.avatar} alt="" /></div>
|
||||||
<span>
|
<span>
|
||||||
|
|
@ -906,6 +911,7 @@ const Meeting: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
<SpeakerModeModal ref={speakerModeModalRef} />
|
<SpeakerModeModal ref={speakerModeModalRef} />
|
||||||
|
<InvitingPersonnelModal ref={invitingPersonnelRef} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ export interface IElectronAPI {
|
||||||
setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize') => void;
|
setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize') => void;
|
||||||
getIsMaximized: () => Promise<boolean>;
|
getIsMaximized: () => Promise<boolean>;
|
||||||
setWriteText: (text: string) => void;
|
setWriteText: (text: string) => void;
|
||||||
|
joinNotification: (data: { name: string, body: string }) => void
|
||||||
}
|
}
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,12 @@ export const onSignalr = (callBack: Function) => {
|
||||||
type
|
type
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
connection.on("Invitation", (roomNum: string, roomName: string, InviterName: string) => {
|
||||||
|
callBack({
|
||||||
|
key: 'Invitation',
|
||||||
|
roomNum, roomName, InviterName
|
||||||
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const offSignalr = () => {
|
export const offSignalr = () => {
|
||||||
|
|
@ -54,6 +60,7 @@ export const offSignalr = () => {
|
||||||
connection.off('RefreshUserList');
|
connection.off('RefreshUserList');
|
||||||
connection.off('Operation');
|
connection.off('Operation');
|
||||||
connection.off('ForceExitRoom');
|
connection.off('ForceExitRoom');
|
||||||
|
connection.off('Invitation');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const onInvoke = async (str: string, data: any) => {
|
export const onInvoke = async (str: string, data: any) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue