This commit is contained in:
parent
d3977ea0ae
commit
704d79b0f7
2
main.js
2
main.js
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
49
src/App.tsx
49
src/App.tsx
|
|
@ -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 |
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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}>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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="" />
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}`} />
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue