This commit is contained in:
yj 2024-07-23 14:01:03 +08:00
parent d3977ea0ae
commit 704d79b0f7
27 changed files with 277 additions and 217 deletions

View File

@ -98,7 +98,7 @@ function createNotification(user) {
const notification = new Notification({
title: `${user.name} 邀请你加入`,
body: user.body,
icon: path.join(`${__dirname}/src/assets/avatar.png`)
// icon: path.join(`${__dirname}/src/assets/avatar.png`)
});
notification.show();
mainWindow.focus();

11
package-lock.json generated
View File

@ -12,6 +12,7 @@
"@microsoft/signalr": "^8.0.0",
"@types/node": "^20.14.9",
"agora-electron-sdk": "^4.3.2",
"animate.css": "^4.1.1",
"antd": "^5.18.2",
"axios": "^1.7.2",
"crypto-js": "^4.2.0",
@ -2686,6 +2687,11 @@
"ajv": "^6.9.1"
}
},
"node_modules/animate.css": {
"version": "4.1.1",
"resolved": "https://registry.npmmirror.com/animate.css/-/animate.css-4.1.1.tgz",
"integrity": "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ=="
},
"node_modules/ansi-colors": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-1.1.0.tgz",
@ -13827,6 +13833,11 @@
"dev": true,
"requires": {}
},
"animate.css": {
"version": "4.1.1",
"resolved": "https://registry.npmmirror.com/animate.css/-/animate.css-4.1.1.tgz",
"integrity": "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ=="
},
"ansi-colors": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-1.1.0.tgz",

View File

@ -27,6 +27,7 @@
"@microsoft/signalr": "^8.0.0",
"@types/node": "^20.14.9",
"agora-electron-sdk": "^4.3.2",
"animate.css": "^4.1.1",
"antd": "^5.18.2",
"axios": "^1.7.2",
"crypto-js": "^4.2.0",
@ -81,4 +82,4 @@
},
"extraResources": []
}
}
}

View File

@ -12,6 +12,8 @@ import { storage } from '@/utils'
import { Spin } from "antd";
import { onInvitation } from "@/utils/package/signalr";
import JoinMeetingModal from "./components/JoinMeetingModal";
import * as CryptoJS from 'crypto-js';
import { PostLogin } from "@/api/Login";
const App: React.FC = () => {
const navigate = useNavigate();
@ -22,28 +24,47 @@ const App: React.FC = () => {
});
const [spinning, setSpinning] = useState(false);
useEffect(() => {
if (storage.getItem('user')) {
try {
window.electron.setMainWindowSize({
width: 1200,
height: 800,
})
} catch {
}
navigate('/home')
} else {
function toLogin() {
try {
window.electron.setMainWindowSize({
width: 752,
height: 520,
key: 'login'
})
} catch {
}
} catch { }
storage.removeItem('user')
navigate('/login')
}
function toHome() {
try {
window.electron.setMainWindowSize({
width: 1200,
height: 800,
})
} catch { }
navigate('/home')
}
let userInfo = JSON.parse(storage.getItem('user') as string)
let loginInfo = JSON.parse(storage.getItem('login') as string)
if (userInfo) {
if (loginInfo && loginInfo.isAutoLogin) {
PostLogin({
account: loginInfo.account,
pwd: CryptoJS.MD5(loginInfo.password).toString(CryptoJS.enc.Hex)
}).then(res => {
if (res.code === 200) {
storage.setItem('user', JSON.stringify(res.data))
toHome()
} else {
toLogin()
}
})
} else {
toLogin()
}
} else {
toLogin()
}
if (import.meta.env.VITE_ENV !== 'development') {
document.addEventListener('keydown', (event) => {
if ((event.ctrlKey || event.metaKey) && event.key === 'r') {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 414 B

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 245 B

View File

@ -0,0 +1,11 @@
.avatar {
background-color: #3F51B5;
height: 36px;
width: 36px;
border-radius: 50%;
overflow: hidden;
color: white;
font-size: 14px;
line-height: 36px;
text-align: center;
}

View File

@ -0,0 +1,18 @@
import styles from '@/components/Avatar/index.module.scss'
import { useState, useImperativeHandle, forwardRef } from "react";
const Avatar = forwardRef((props: any, ref: any) => {
useImperativeHandle(ref, () => ({
getData: () => {
}
}))
return (
<>
<div className={styles.avatar}>
{props.name ? props.name.slice(-2) : '访客'}
</div>
</>
)
})
export default Avatar

View File

@ -29,17 +29,7 @@
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 {
@ -86,17 +76,7 @@
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 {

View File

@ -1,15 +1,17 @@
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';
import { storage } from '@/utils';
import Avatar from '@/components/Avatar';
const InvitingPersonnelModal = forwardRef((props: any, ref: any) => {
useImperativeHandle(ref, () => ({
changeInvitingPersonnelModal: () => {
let userInfo = JSON.parse(storage.getItem('user') as string)
setUser(userInfo)
getUserList()
setIsInvitingPersonnelModal(true)
}
@ -17,6 +19,7 @@ const InvitingPersonnelModal = forwardRef((props: any, ref: any) => {
const { state } = useLocation();
const [isInvitingPersonnelModal, setIsInvitingPersonnelModal] = useState(false);
const [isFirstRender, setIsFirstRender] = useState(true);
const [user, setUser] = useState<any>({});
const [operation, setOperation] = useState<{
options: { label: string; value: number }[];
optionsValue: number[];
@ -96,7 +99,7 @@ const InvitingPersonnelModal = forwardRef((props: any, ref: any) => {
footer={null}
onCancel={() => setIsInvitingPersonnelModal(false)}
centered
width={'560px'}
width={'700px'}
>
<div className={styles.invitingPersonnelModal}>
<div className={styles.invitingPersonnelModalContent}>
@ -147,8 +150,8 @@ const InvitingPersonnelModal = forwardRef((props: any, ref: any) => {
return checkedList
}
})
}} defaultChecked={item.checked}></Checkbox>
<div><img src={ImageUrl.avatar} alt="" /></div>
}} defaultChecked={item.checked} disabled={!item.isOnline || item.account === user.account}></Checkbox>
<div><Avatar name={item.userName} /></div>
<span>{item.userName}</span>
</div>
<div style={{ color: item.isOnline ? '#02B188' : 'rgb(221 11 11)' }}>{item.isOnline ? '在线' : '离线'}</div>
@ -159,13 +162,13 @@ const InvitingPersonnelModal = forwardRef((props: any, ref: any) => {
...list,
pageIndex: e
})
}} pageSize={list.pageSize} current={list.pageIndex} hideOnSinglePage={true} />
}} pageSize={list.pageSize} current={list.pageIndex} hideOnSinglePage={true} showLessItems={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>
<div><Avatar name={item.userName} /></div>
<span>{item.userName}</span>
</div>)}
</div>
@ -175,8 +178,7 @@ const InvitingPersonnelModal = forwardRef((props: any, ref: any) => {
<Button type="primary" onClick={() => { setIsInvitingPersonnelModal(false) }} style={{ backgroundColor: '#31353A', marginRight: '14px' }}></Button>
<Button type="primary" className='m-ant-btn' onClick={() => {
if (checkedList.length) {
let userInfo = JSON.parse(storage.getItem('user') as string)
let me = checkedList.find((item: any) => item.id === userInfo.uid)
let me = checkedList.find((item: any) => item.id === user.uid)
if (me) {
message.error('您不能邀请自己')
} else {

View File

@ -3,18 +3,7 @@
display: flex;
align-items: center;
>div:nth-child(1) {
width: 44px;
height: 40px;
border-radius: 50%;
overflow: hidden;
>img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
>div:nth-child(1) {}
>div:nth-child(2) {
margin-left: 10px;

View File

@ -4,6 +4,7 @@ import ImageUrl from '@/utils/package/imageUrl';
import { Modal, message } from 'antd';
import { useState, useImperativeHandle, forwardRef } from "react";
import { useNavigate } from 'react-router-dom';
import Avatar from '@/components/Avatar';
const JoinMeetingModal = forwardRef((props: any, ref: any) => {
useImperativeHandle(ref, () => ({
changeModal: (item: any) => {
@ -40,7 +41,7 @@ const JoinMeetingModal = forwardRef((props: any, ref: any) => {
>
<div className={styles.joinMeetingModal}>
<div>
<div><img src={ImageUrl.avatar} alt="" /></div>
<div><Avatar name={info.InviterName} /></div>
<div>
<span>{info.InviterName} </span>
<span>{info.roomName}</span>

View File

@ -19,6 +19,7 @@
width: 144px;
}
>span {
color: white;
font-size: 16px;
@ -26,6 +27,10 @@
}
}
.active {
border: 2px #4096ff solid;
}
.freedomMode {
>div {
@ -104,6 +109,11 @@
box-sizing: border-box;
background-color: #101317;
}
.active {
border: 2px #4096ff solid;
}
}
.dualScreenMode {

View File

@ -6,6 +6,7 @@ import { useLocation } from 'react-router-dom';
import { GetSyncView } from '@/api/Meeting';
interface Props {
onClick: () => void;
meetingMode: string;
}
const SpeakerModeModal = forwardRef((props: any, ref: any) => {
useImperativeHandle(ref, () => ({
@ -13,6 +14,7 @@ const SpeakerModeModal = forwardRef((props: any, ref: any) => {
setIsSpeakerModeModal(true)
}
}))
const [meetingMode, setMeetingMode] = useState('StandardMode')
const { state } = useLocation();
const [isSpeakerModeModal, setIsSpeakerModeModal] = useState(false);
const [isView, setIsView] = useState(false);
@ -21,6 +23,7 @@ const SpeakerModeModal = forwardRef((props: any, ref: any) => {
await GetSyncView(state.channelId, mode)
}
storage.setItem('meetingMode', mode)
setMeetingMode(mode);
setIsSpeakerModeModal(false)
}
return (
@ -34,27 +37,27 @@ const SpeakerModeModal = forwardRef((props: any, ref: any) => {
width={'560px'}
>
<div className={styles.speakerModeModal}>
<FreedomMode onClick={() => setMode('FreedomMode')} />
<StandardMode onClick={() => setMode('StandardMode')} />
<SpeakerMode onClick={() => setMode('SpeakerMode')} />
<SingleScreenMode onClick={() => setMode('SingleScreenMode')} />
<DualScreenMode onClick={() => setMode('DualScreenMode')} />
<FourScreenMode onClick={() => setMode('FourScreenMode')} />
<FreedomMode onClick={() => setMode('FreedomMode')} meetingMode={meetingMode} />
<StandardMode onClick={() => setMode('StandardMode')} meetingMode={meetingMode} />
<SpeakerMode onClick={() => setMode('SpeakerMode')} meetingMode={meetingMode} />
<SingleScreenMode onClick={() => setMode('SingleScreenMode')} meetingMode={meetingMode} />
<DualScreenMode onClick={() => setMode('DualScreenMode')} meetingMode={meetingMode} />
<FourScreenMode onClick={() => setMode('FourScreenMode')} meetingMode={meetingMode} />
</div>
<Checkbox onChange={(e) => {
setIsView(e.target.checked)
}} value={isView}></Checkbox>
}} defaultChecked={isView}></Checkbox>
</Modal>
</>
)
})
const FreedomMode: React.FC<Props> = ({ onClick }) => {
const FreedomMode: React.FC<Props> = ({ onClick, meetingMode }) => {
// 自由者模式
return (
<>
<div className={styles.freedomMode} onClick={onClick}>
<div>
<div className={`${meetingMode === 'FreedomMode' ? styles.active : ''}`}>
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16].map(item => <div key={item}></div>)}
</div>
<span></span>
@ -62,12 +65,12 @@ const FreedomMode: React.FC<Props> = ({ onClick }) => {
</>
)
}
const StandardMode: React.FC<Props> = ({ onClick }) => {
const StandardMode: React.FC<Props> = ({ onClick, meetingMode }) => {
// 标准模式
return (
<>
<div className={styles.standardMode} onClick={onClick}>
<div>
<div className={`${meetingMode === 'StandardMode' ? styles.active : ''}`}>
<div>
<div></div>
<div></div>
@ -81,12 +84,12 @@ const StandardMode: React.FC<Props> = ({ onClick }) => {
</>
)
}
const SpeakerMode: React.FC<Props> = ({ onClick }) => {
const SpeakerMode: React.FC<Props> = ({ onClick, meetingMode }) => {
// 演讲者模式
return (
<>
<div className={styles.speakerMode} onClick={onClick}>
<div>
<div className={`${meetingMode === 'SpeakerMode' ? styles.active : ''}`}>
<div>
<div></div>
<div></div>
@ -100,12 +103,12 @@ const SpeakerMode: React.FC<Props> = ({ onClick }) => {
</>
)
}
const SingleScreenMode: React.FC<Props> = ({ onClick }) => {
const SingleScreenMode: React.FC<Props> = ({ onClick, meetingMode }) => {
// 单画面模式
return (
<>
<div className={styles.singleScreenMode} onClick={onClick}>
<div>
<div className={`${meetingMode === 'SingleScreenMode' ? styles.active : ''}`}>
<div></div>
</div>
<span></span>
@ -113,12 +116,12 @@ const SingleScreenMode: React.FC<Props> = ({ onClick }) => {
</>
)
}
const DualScreenMode: React.FC<Props> = ({ onClick }) => {
const DualScreenMode: React.FC<Props> = ({ onClick, meetingMode }) => {
// 二分屏模式
return (
<>
<div className={styles.dualScreenMode} onClick={onClick}>
<div>
<div className={`${meetingMode === 'DualScreenMode' ? styles.active : ''}`}>
<div></div>
<div></div>
</div>
@ -127,12 +130,12 @@ const DualScreenMode: React.FC<Props> = ({ onClick }) => {
</>
)
}
const FourScreenMode: React.FC<Props> = ({ onClick }) => {
const FourScreenMode: React.FC<Props> = ({ onClick, meetingMode }) => {
// 四分屏模式
return (
<>
<div className={styles.fourScreenMode} onClick={onClick}>
<div>
<div className={`${meetingMode === 'FourScreenMode' ? styles.active : ''}`}>
<div></div>
<div></div>
<div></div>

View File

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

View File

@ -16,18 +16,19 @@
border-bottom: 1px solid #2C2C2C;
.indexBtnsJoin {
background-color: #FFCFEB;
color: red;
background-color: #3A1457;
box-shadow: none;
color: white;
margin-left: 22px;
&:hover {
background-color: lighten(#FFCFEB, 5%) !important;
color: red;
background-color: lighten(#3A1457, 5%) !important;
color: white;
}
&:active {
background-color: darken(#FFCFEB, 5%) !important;
color: red;
background-color: darken(#3A1457, 5%) !important;
color: white;
}
}
}

View File

@ -84,7 +84,7 @@ const Index: React.FC = () => {
setJoinRoomFrom('')
setJoinRoomModal(true)
}}
icon={<img src={ImageUrl.icon7} alt="" />}
icon={<img src={ImageUrl.icon8} alt="" />}
className={`${styles.indexBtnsJoin} drag`}>
</Button>
@ -157,17 +157,6 @@ const Index: React.FC = () => {
<Modal title="新建会议室" open={createRoomModal} footer={null} closable={false} centered width={'400px'}>
<div>
<div>
<Input
placeholder="请输入房间名字"
style={{ marginBottom: '14px' }}
value={createRoomFrom.roomName}
onChange={(e) => {
setCreateRoomFrom({
...createRoomFrom,
roomName: e.target.value
})
}}
/>
<Input
placeholder="请输入房间号"
style={{ marginBottom: '14px' }}
@ -187,15 +176,34 @@ const Index: React.FC = () => {
<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: Math.floor(+new Date() / 1000).toString().slice(-8),
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'

View File

@ -22,18 +22,19 @@
align-items: center;
.userBtnsDel {
background-color: #FFCFEB;
color: red;
background-color: #3A1457;
box-shadow: none;
color: white;
margin-left: 22px;
&:hover {
background-color: lighten(#FFCFEB, 5%) !important;
color: red;
background-color: lighten(#3A1457, 5%) !important;
color: white;
}
&:active {
background-color: darken(#FFCFEB, 5%) !important;
color: red;
background-color: darken(#3A1457, 5%) !important;
color: white;
}
}
}

View File

@ -116,7 +116,7 @@ const User: React.FC = () => {
</div>
<div className={`${styles.userBtnsRight} drag`}>
<Input
placeholder="请输入用户名"
placeholder="请输入用户名或账号"
prefix={<SearchOutlined style={{ color: 'white' }} />}
value={list.searchKeywod}
onChange={(e) => {

View File

@ -21,18 +21,8 @@
cursor: pointer;
>div {
height: 40px;
width: 40px;
border-radius: 50%;
overflow: hidden;
margin-right: 14px;
flex-shrink: 0;
>img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
>span {

View File

@ -7,6 +7,7 @@ import 'dayjs/locale/zh-cn'
import { storage } from '@/utils';
import ImageUrl from '@/utils/package/imageUrl'
import { startSignalr } from '@/utils/package/signalr';
import Avatar from '@/components/Avatar';
dayjs.locale('zh-cn');
type navListType = {
title: string;
@ -84,9 +85,9 @@ const Home: React.FC = () => {
<div className={styles.homeLeft}>
<div className='drag'>
<div>
<img src={ImageUrl.avatar} alt="" />
<Avatar name={userInfo.userName} />
</div>
<span>{userInfo?.userName}</span>
<span>{userInfo.userName}</span>
</div>
<div>
<img src={ImageUrl.icon14} alt="" />

View File

@ -106,18 +106,19 @@
display: flex;
justify-content: center;
align-items: center;
background-color: #FFCFEB;
background-color: #3A1457;
box-shadow: none;
border-radius: 10px;
width: 56px;
margin-left: 4px;
transition: 0.3s;
&:hover {
background-color: lighten(#FFCFEB, 5%) !important;
background-color: lighten(#3A1457, 5%) !important;
}
&:active {
background-color: darken(#FFCFEB, 5%) !important;
background-color: darken(#3A1457, 5%) !important;
}
}
}
@ -139,6 +140,7 @@
.ant-input {
height: 34px;
line-height: 34px;
text-align: center;
}
}
}

View File

@ -77,7 +77,10 @@ const Login: React.FC = () => {
setAccountPasswordStatus(false)
}
// 继续
const continueClick = (): void => {
const continueClick = (): any => {
if (!operation.account) {
return message.error('请输入账号!')
}
GetCheckUser(operation.account).then(res => {
if (res.code === 200) {
res.data ? setAccountPasswordStatus(true) : message.error('账号不存在!')
@ -87,6 +90,9 @@ const Login: React.FC = () => {
// 设置勾选
const changeOptionsValue = (checkedValues: string[]): void => {
if (checkedValues.indexOf('isAutoLogin') >= 0 && checkedValues.indexOf('isRememberPassword') === -1) {
checkedValues.push('isRememberPassword')
}
setOperation({
...operation,
optionsValue: checkedValues,
@ -159,22 +165,22 @@ const Login: React.FC = () => {
placeholder="请输入账号"
prefix={<img src={ImageUrl.icon5} alt="" />}
suffix={
<span
(accountPasswordStatus && operation.account ? <span
style={{ color: '#47D3D0', cursor: 'pointer' }}
onClick={resetClick}
>
</span>
</span> : null)
}
/>
{!accountPasswordStatus ? <div style={{ marginTop: '36px' }} className='drag'>
{!accountPasswordStatus ? <div style={{ marginTop: '36px' }} className={`drag`}>
<Button type="primary"
onClick={continueClick}
style={{ width: '100%' }}
className={`${styles.loginButton} m-ant-btn`}
></Button>
</div> : null}
{accountPasswordStatus ? <div>
{accountPasswordStatus ? <div className={`animate__animated animate__fadeIn`}>
<Input.Password
value={operation.password}
onChange={e => {
@ -200,11 +206,11 @@ const Login: React.FC = () => {
</div>
</div>
<div>
<div className={styles.footer}>
{/* <div className={styles.footer}>
<div></div>
<span>or</span>
<div></div>
</div>
</div> */}
{/* <div className={`${styles.code} drag`}>
<div>
<Input placeholder="输入会议号" className={`${styles.loginInput}`} />

View File

@ -340,16 +340,6 @@
>div {
flex-shrink: 0;
width: 30px;
height: 30px;
overflow: hidden;
border-radius: 50%;
>img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
}
@ -482,18 +472,7 @@
margin-left: 4px;
}
>div {
width: 30px;
height: 30px;
overflow: hidden;
border-radius: 50%;
>img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
>div {}
}
>div:nth-child(2) {
@ -597,6 +576,19 @@
color: #EEEEEE;
font-size: 14px;
}
&:hover {
>span {
color: #4096ff;
}
}
&:active {
>span {
color: darken(#4096ff, 10%) !important;
;
}
}
}
}
}

View File

@ -17,6 +17,7 @@ import dayjs from 'dayjs';
import durationPlugin from 'dayjs/plugin/duration';
import { VideoSourceType } from 'agora-electron-sdk';
import { GetUserList } from '@/api/Home/User';
import Avatar from '@/components/Avatar';
dayjs.extend(durationPlugin);
const { Column } = Table
const Meeting: React.FC = () => {
@ -122,7 +123,7 @@ const Meeting: React.FC = () => {
let time = null as any;
if (isInit) {
let userInfo = JSON.parse(storage.getItem('user') as string)
setMeetingMode(storage.getItem('meetingMode') as string || 'FreedomMode');
setMeetingMode('StandardMode');
agora.init()
agora.registerEventHandler({
onJoinChannelSuccess: async (info: any, _elapsed: any) => {
@ -258,14 +259,14 @@ const Meeting: React.FC = () => {
switch (row.title) {
case '成员列表':
setStatusList({
userList: true,
userList: statusList.userList ? false : true,
userChatList: false,
})
break;
case '聊天':
setStatusList({
userList: false,
userChatList: true,
userChatList: statusList.userChatList ? false : true,
})
break;
case '共享屏幕':
@ -606,75 +607,73 @@ const Meeting: React.FC = () => {
<div className={styles.meetingUserListContent}>
{roomUserList.map((item: any, index: number) => {
return (
<>
{item.isShow ? <div key={index + item.id} className='drag'>
<div>
<div><img src={ImageUrl.avatar} alt="" /></div>
<span>
{item.userName}
{item.roleId === '1' || item.isManager ?
<span style={{ color: '#02B188', marginLeft: '4px' }}>
{item.roleId === '1' ? '主持人' : '临时主持人'}
</span>
: null}
</span>
</div>
<div>
<img src={item.enableMicr ? ImageUrl.icon22 : ImageUrl.icon22Active} alt="" />
<img src={item.enableCamera ? ImageUrl.icon23 : ImageUrl.icon23Active} alt="" />
</div>
{item.account !== user.account && user.roleId === '1' ? <div className='drag'>
{!item.isManager ? <Button
type="primary"
className='m-ant-btn'
style={{ marginBottom: '10px', width: '80%' }}
size={'small'}
onClick={() => {
PostRoomManager(state.roomId, [item.id]).then(res => {
if (res.code === 200) {
onInvoke('sendOper', {
roomNum: state.channelId,
type: 2,
})
}
})
}}
></Button> : <Button
type="primary"
className='m-ant-btn'
style={{ marginBottom: '10px', width: '80%' }}
size={'small'}
onClick={() => {
DeleteRoomManager(state.roomId, [item.id]).then(res => {
if (res.code === 200) {
onInvoke('sendOper', {
roomNum: state.channelId,
type: 2,
})
}
})
}}
></Button>}
item.isShow ? <div key={index + item.id} className='drag'>
<div>
<div><Avatar name={item.userName} /></div>
<span>
{item.userName}
{item.roleId === '1' || item.isManager ?
<span style={{ color: '#02B188', marginLeft: '4px' }}>
{item.roleId === '1' ? '主持人' : '临时主持人'}
</span>
: null}
</span>
</div>
<div>
<img src={item.enableMicr ? ImageUrl.icon22 : ImageUrl.icon22Active} alt="" />
<img src={item.enableCamera ? ImageUrl.icon23 : ImageUrl.icon23Active} alt="" />
</div>
{item.account !== user.account && user.roleId === '1' ? <div className='drag'>
{!item.isManager ? <Button
type="primary"
className='m-ant-btn'
style={{ marginBottom: '10px', width: '80%' }}
size={'small'}
onClick={() => {
PostRoomManager(state.roomId, [item.id]).then(res => {
if (res.code === 200) {
onInvoke('sendOper', {
roomNum: state.channelId,
type: 2,
})
}
})
}}
></Button> : <Button
type="primary"
className='m-ant-btn'
style={{ marginBottom: '10px', width: '80%' }}
size={'small'}
onClick={() => {
DeleteRoomManager(state.roomId, [item.id]).then(res => {
if (res.code === 200) {
onInvoke('sendOper', {
roomNum: state.channelId,
type: 2,
})
}
})
}}
></Button>}
<Button
type="primary"
className='m-ant-btn'
style={{ width: '80%' }}
size={'small'}
onClick={() => {
GetRoomKickout(state.channelId, item.id).then(res => {
if (res.code === 200) {
onInvoke('sendOper', {
roomNum: state.channelId,
type: 3,
})
}
})
}}
></Button>
</div> : null}
<Button
type="primary"
className='m-ant-btn'
style={{ width: '80%' }}
size={'small'}
onClick={() => {
GetRoomKickout(state.channelId, item.id).then(res => {
if (res.code === 200) {
onInvoke('sendOper', {
roomNum: state.channelId,
type: 3,
})
}
})
}}
></Button>
</div> : null}
</>
</div> : null
)
}
)}
@ -701,7 +700,7 @@ const Meeting: React.FC = () => {
key={index}
className={`${item.uid !== state.uid ? styles.meetingUserChatContentLeft : styles.meetingUserChatContentRight} drag`}>
<div>
<div><img src={ImageUrl.avatar} alt="" /></div>
<div><Avatar name={item.userName} /></div>
<span>{item.userName}</span>
</div>
<div>{item.message}</div>

View File

@ -68,6 +68,11 @@ class Request {
if (res.code == 200) {
storage.setItem('user', JSON.stringify(res.data))
location.reload()
} else {
setTimeout(() => {
storage.removeItem('user')
location.href = location.origin + '/#/login'
}, 3000)
}
})
} else {

View File

@ -40,6 +40,10 @@ $pagination-hover-background-color: #5575F2;
}
}
.ant-input-data-count {
color: white !important;
}
.ant-input-affix-wrapper {
background-color: $input-background-color !important;
border: 1px solid $input-border-color;
@ -208,6 +212,9 @@ $pagination-hover-background-color: #5575F2;
color: black !important;
}
}
.ant-pagination-item-ellipsis{
color: white !important;
}
}
// popover