This commit is contained in:
yj 2024-08-06 15:09:39 +08:00
parent 20132c3086
commit 1b02462e4b
10 changed files with 282 additions and 259 deletions

View File

@ -93,3 +93,8 @@ export const PostRoomInvite = (roomId: string, data: any) =>
method: 'post', method: 'post',
data data
}) })
export const GetShowUser = (roomNum: string) =>
request({
url: `/room/show-user?roomNum=${roomNum}`,
method: 'get'
})

View File

@ -1,35 +1,47 @@
.sharedFilesModel { .sharedFilesModel {
> div:nth-child(1) { >div:nth-child(1) {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
> span { >div:nth-child(1) {
color: #EEEEEE;
font-size: 16px;
}
> div {
display: flex; display: flex;
align-items: center; align-items: center;
> span { >span {
color: #EEEEEE;
font-size: 16px;
}
>div {
display: flex;
align-items: center;
margin-left: 10px;
>span {
color: #EEEEEE;
font-size: 14px;
white-space: nowrap;
}
}
}
>div:nth-child(2) {
display: flex;
align-items: center;
>span {
margin-right: 20px; margin-right: 20px;
cursor: pointer; cursor: pointer;
font-size: 16px; font-size: 16px;
} }
} }
} }
> div:nth-child(2) { >div:nth-child(2) {
margin: 20px 0; margin: 20px 0;
} }
.updateDiv {
color: #ffffff;
.ant-progress .ant-progress-text {
color: #ffffff;
}
}
} }

View File

@ -6,14 +6,14 @@ import {
SearchOutlined, SearchOutlined,
VerticalAlignBottomOutlined VerticalAlignBottomOutlined
} from '@ant-design/icons'; } from '@ant-design/icons';
import {Button, Input, message, Modal, Pagination, Progress, Table} from 'antd'; import { Button, Input, message, Modal, Pagination, Progress, Table } from 'antd';
import {forwardRef, useEffect, useImperativeHandle, useState} from "react"; import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import {DeleteRoomFile, GetRoomFile, GetRoomFileDwUrl, GetRoomUpFileurl, PostRoomFile} from '@/api/Meeting'; import { DeleteRoomFile, GetRoomFile, GetRoomFileDwUrl, GetRoomUpFileurl, PostRoomFile } from '@/api/Meeting';
import axios from 'axios'; import axios from 'axios';
import {useLocation} from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import {storage} from '@/utils'; import { storage } from '@/utils';
const {Column} = Table const { Column } = Table
const SharedFilesModel = forwardRef((props: any, ref: any) => { const SharedFilesModel = forwardRef((props: any, ref: any) => {
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
@ -21,7 +21,7 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
setIsSharedFilesModel(true) setIsSharedFilesModel(true)
} }
})) }))
const {state} = useLocation(); const { state } = useLocation();
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [showRowSelection, setShowRowSelection] = useState(false); const [showRowSelection, setShowRowSelection] = useState(false);
const [isSharedFilesModel, setIsSharedFilesModel] = useState(false); const [isSharedFilesModel, setIsSharedFilesModel] = useState(false);
@ -74,18 +74,24 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
> >
<div> <div>
<div className={styles.sharedFilesModel}> <div className={styles.sharedFilesModel}>
<div className={styles.updateDiv}> <div>
<span>{fileList.total}</span>
<div> <div>
<Progress percent={uploadProgress} strokeColor={'green'} trailColor={'#e8e8e8'} <span>
percentPosition={{align: 'center', type: 'inner'}} {fileList.total}
size={{width: 100, height: 20}}/> </span>
<div>
<span></span>
{/* <span>{uploadProgress === 100 ? '上传完成' : '上传中'} </span> */}
<Progress percent={uploadProgress} trailColor={'#e8e8e8'}
percentPosition={{ align: 'center', type: 'inner' }}
size={{ width: 100, height: 20 }} />
</div>
</div> </div>
<div style={{color: 'white'}}> <div style={{ color: 'white' }}>
<Input <Input
placeholder="搜索" placeholder="搜索"
style={{width: '200px'}} style={{ width: '200px' }}
prefix={<SearchOutlined style={{color: 'white'}}/>} prefix={<SearchOutlined style={{ color: 'white' }} />}
onChange={(e) => { onChange={(e) => {
setFileList({ setFileList({
...fileList, ...fileList,
@ -122,10 +128,10 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
pageIndex: 1 pageIndex: 1
}) })
} }
}}/> }} />
<ProfileOutlined title={showRowSelection ? '取消框选' : '显示框选'} onClick={() => { <ProfileOutlined title={showRowSelection ? '取消框选' : '显示框选'} onClick={() => {
setShowRowSelection(!showRowSelection) setShowRowSelection(!showRowSelection)
}} style={{color: showRowSelection ? '#5575F2' : 'white'}}/> }} style={{ color: showRowSelection ? '#5575F2' : 'white' }} />
{showRowSelection ? <DeleteOutlined title='删除' onClick={() => { {showRowSelection ? <DeleteOutlined title='删除' onClick={() => {
if (selectedRowKeys.length) { if (selectedRowKeys.length) {
DeleteRoomFile(selectedRowKeys).then(res => { DeleteRoomFile(selectedRowKeys).then(res => {
@ -137,57 +143,56 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
} else { } else {
message.error('请选择文件!') message.error('请选择文件!')
} }
}}/> : null} }} /> : null}
<Button type="primary" style={{backgroundColor: '#31353A'}} <Button type="primary" style={{ backgroundColor: '#31353A' }}
onClick={() => { onClick={() => {
const file = document.createElement("input") as any; const file = document.createElement("input") as any;
file.accept = "image/*,.doc,.docx,.ppt,.pptx,.xls,.xlsx,application/pdf"; file.accept = "image/*,.doc,.docx,.ppt,.pptx,.xls,.xlsx,application/pdf";
file.type = "file"; file.type = "file";
file.onchange = async () => { file.onchange = async () => {
const fileInfo = file.files[0]; const fileInfo = file.files[0];
const maxSize = 100 * 1024 * 1024; // 100MB in bytes const maxSize = 100 * 1024 * 1024; // 100MB in bytes
if (fileInfo.size > maxSize) { if (fileInfo.size > maxSize) {
message.error('文件太大请上传小于100MB的文件。') message.error('文件太大请上传小于100MB的文件。')
// 清除文件输入框的值,以便用户可以选择其他文件 // 清除文件输入框的值,以便用户可以选择其他文件
return return
} }
const fileType = fileInfo.name.split('.'); const fileType = fileInfo.name.split('.');
const fileTypeName = fileType[fileType.length - 1]; const fileTypeName = fileType[fileType.length - 1];
await GetRoomUpFileurl(state.channelId, fileTypeName).then(async res => { await GetRoomUpFileurl(state.channelId, fileTypeName).then(async res => {
const formData = new FormData(); const formData = new FormData();
formData.append("name", fileInfo.name); formData.append("name", fileInfo.name);
formData.append("OSSAccessKeyId", res.data.ossAccessKeyId); formData.append("OSSAccessKeyId", res.data.ossAccessKeyId);
formData.append("key", res.data.key); formData.append("key", res.data.key);
formData.append("policy", res.data.policy); formData.append("policy", res.data.policy);
formData.append("signature", res.data.signature); formData.append("signature", res.data.signature);
formData.append("success_action_status", res.data.success_action_status); formData.append("success_action_status", res.data.success_action_status);
formData.append("file", fileInfo); formData.append("file", fileInfo);
await axios.post(res.data.host, formData, { await axios.post(res.data.host, formData, {
headers: { headers: {
"Content-Type": "multipart/form-data", "Content-Type": "multipart/form-data",
"Authorization": `Bearer ${user.token}` "Authorization": `Bearer ${user.token}`
}, },
withCredentials: false, withCredentials: false,
onUploadProgress: (progressEvent: any) => { onUploadProgress: (progressEvent: any) => {
// 获取上传进度 // 获取上传进度
const {loaded, total} = progressEvent; const { loaded, total } = progressEvent;
const progress = Math.round((loaded * 100) / total); const progress = Math.round((loaded * 100) / total);
console.log(`上传进度: ${progress}%`); setUploadProgress(progress)
setUploadProgress(progress) }
}
})
await PostRoomFile({
fileUrl: res.data.key,
size: fileInfo.size,
fileName: fileInfo.name,
roomId: state.roomId
})
getRoomFile()
}) })
}; await PostRoomFile({
file.click(); fileUrl: res.data.key,
}} size: fileInfo.size,
fileName: fileInfo.name,
roomId: state.roomId
})
getRoomFile()
})
};
file.click();
}}
></Button> ></Button>
</div> </div>
</div> </div>
@ -202,130 +207,97 @@ const SharedFilesModel = forwardRef((props: any, ref: any) => {
} : undefined} } : undefined}
dataSource={fileList.data} dataSource={fileList.data}
pagination={false} pagination={false}
scroll={{y: '40vh'}} scroll={{ y: '40vh' }}
style={{width: '100%'}} style={{ width: '100%' }}
> >
<Column title="文件" dataIndex="fileName" key="fileName" width={140}/> <Column title="文件" width={140}
<Column title="更新时间" dataIndex="modifyTime" key="modifyTime" width={200}/> render={(item) => (
<>
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
<span>{item.fileName}</span>
<span>
{item.showPercentComplete ? <Progress percent={item.percentComplete} trailColor={'#e8e8e8'}
percentPosition={{ align: 'center', type: 'inner' }}
size={{ width: 40, height: 10 }} /> : null}
</span>
</div>
</>
)}
/>
<Column title="更新时间" dataIndex="modifyTime" key="modifyTime" width={200} />
<Column title="大小" render={(item) => ( <Column title="大小" render={(item) => (
<> <>
<span>{item.size / 1024 > 1000 ? (item.size / (1024 * 1024)).toFixed(2) + 'MB' : (item.size / 1024).toFixed(2) + 'KB'}</span> <span>{item.size / 1024 > 1000 ? (item.size / (1024 * 1024)).toFixed(2) + 'MB' : (item.size / 1024).toFixed(2) + 'KB'}</span>
</> </>
)}/> )} />
<Column title="上传者" dataIndex="userName" key="userName"/> <Column title="上传者" dataIndex="userName" key="userName" />
<Column title="下载次数" <Column title="下载次数"
render={(item) => ( render={(item) => (
<> <>
<span>{item.downloadCount}</span> <span>{item.downloadCount}</span>
</> </>
)} )}
/> />
<Column title="操作" render={(item) => ( <Column title="操作" render={(item) => (
<> <>
<VerticalAlignBottomOutlined title='下载' <VerticalAlignBottomOutlined title='下载'
style={{color: '#5575F2', cursor: 'pointer'}} style={{ color: '#5575F2', cursor: 'pointer' }}
onClick={async () => { onClick={async () => {
GetRoomFileDwUrl(item.fileUrl, item.id).then(res => { GetRoomFileDwUrl(item.fileUrl, item.id).then(res => {
console.log(res) if (res.code === 200) {
if (res.code === 200) { axios({
// const downloadLink = document.createElement("a"); url: res.data,
// downloadLink.href = res.data; method: 'GET',
// downloadLink.download = item.fileName; onDownloadProgress: (progressEvent: any) => {
axios({ const totalLength = item.size;
url: res.data, if (totalLength !== null) {
method: 'GET', const percentComplete = (progressEvent.loaded / totalLength * 100).toFixed(2);
// headers: { const fileIndex = fileList.data.findIndex((row: any) => row.id === item.id);
// "Authorization": `Bearer ${user.token}`, let fileItem = [...fileList.data] as any;
// "responseType": 'stream' fileItem[fileIndex].percentComplete = percentComplete
// }, fileItem[fileIndex].showPercentComplete = true
onDownloadProgress: (progressEvent: any) => { setFileList({
const totalLength = item.size; ...fileList,
console.log(2222222) data: fileItem,
if (totalLength !== null) { })
const percentComplete = (progressEvent.loaded / totalLength * 100).toFixed(2); }
console.log(`下载进度: ${percentComplete}%`); }
item.percentComplete = percentComplete }).then(() => {
} const fileIndex = fileList.data.findIndex((row: any) => row.id === item.id);
} let fileItem = [...fileList.data] as any;
}).then(() => { fileItem[fileIndex].percentComplete = 100
const downloadLink = document.createElement("a"); setTimeout(() => {
downloadLink.href = res.data; fileItem[fileIndex].showPercentComplete = false
downloadLink.download = item.fileName; }, 3000)
downloadLink.click(); setFileList({
getRoomFile() ...fileList,
}) data: fileItem,
// downloadLink.click(); })
// getRoomFile() const downloadLink = document.createElement("a");
} downloadLink.href = res.data;
}) downloadLink.download = item.fileName;
downloadLink.click();
getRoomFile()
})
}
})
// const url = "https://wgshare.oss-cn-chengdu.aliyuncs.com/share_file/559167236182085/20421555/b24e2c41f47140308c47cdd77e6305c7.jpg?Expires=1722923931&OSSAccessKeyId=LTAI5tQYVQHkkXxXTmjwiSDv&Signature=eJTWD93ifV2v1R6XCHSOa6j1R%2FE%3D" }} />
// axios({
// url,
// method: 'GET',
// // headers: {
// // "Authorization": `Bearer ${user.token}`,
// // "responseType": 'stream'
// // },
// onDownloadProgress: (progressEvent: any) => {
// const totalLength = item.size;
// console.log(2222222)
// if (totalLength !== null) {
// const percentComplete = (progressEvent.loaded / totalLength * 100).toFixed(2);
// console.log(`下载进度: ${percentComplete}%`);
// }
// }
// })
// .then((response: any) => {
// const downloadLink = document.createElement("a");
// downloadLink.href = response.data;
// downloadLink.download = item.fileName;
// downloadLink.click();
// getRoomFile()
// })
// await axios.get(`${import.meta.env.VITE_BASE_URL_API}/room/file-dw-url?fileUrl=${item.fileUrl}&fileId=${item.id}`, {
// headers: {
// "Authorization": `Bearer ${user.token}`,
// "responseType": 'stream'
// },
// onDownloadProgress: (progressEvent: any) => {
// const totalLength = item.size;
// const percentComplete = (progressEvent.loaded / totalLength * 100).toFixed(2);
// console.log(`下载进度: ${percentComplete}%`);
// }
// })
// await axios.get(`${import.meta.env.VITE_BASE_URL_API}/room/file-dw-url?fileUrl=${item.fileUrl}&fileId=${item.id}`, {
// headers: {
// "ResponseType": "blob",
// "Authorization": `Bearer ${user.token}`
// },
// withCredentials: false,
// onDownloadProgress: (progressEvent: any) => {
// console.log(progressEvent, 33333)
// // 获取上传进度
// const {loaded, total} = progressEvent;
// const progress = Math.round((loaded * 100) / total);
// console.log(`下载进度: ${progress}%`);
// setUploadProgress(progress)
// }
// })
}}/>
{/* <FolderOutlined title='文件' style={{ color: '#FFA000', cursor: 'pointer' }} /> */} {/* <FolderOutlined title='文件' style={{ color: '#FFA000', cursor: 'pointer' }} /> */}
</> </>
)}/> )} />
</Table> </Table>
<div style={{display: 'flex', justifyContent: 'center', marginTop: '10px'}}> <div style={{ display: 'flex', justifyContent: 'center', marginTop: '10px' }}>
<Pagination size="small" total={fileList.total} onChange={(e) => { <Pagination size="small" total={fileList.total} onChange={(e) => {
setFileList({ setFileList({
...fileList, ...fileList,
pageIndex: e pageIndex: e
}) })
}} pageSize={fileList.pageSize} current={fileList.pageIndex} hideOnSinglePage={true}/> }} pageSize={fileList.pageSize} current={fileList.pageIndex} hideOnSinglePage={true} />
</div> </div>
</div> </div>
</div> </div>
<div style={{display: 'flex', alignItems: 'center', justifyContent: 'flex-end'}}> <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}>
</div> </div>
</div> </div>

View File

@ -187,7 +187,7 @@ const Index: React.FC = () => {
maxLength={8} maxLength={8}
value={createRoomFrom.roomNum} value={createRoomFrom.roomNum}
onChange={(e) => { onChange={(e) => {
const regex = /^[0-9 ]*$/; const regex = /^[0-9]*$/;
if (regex.test(e.target.value)) { if (regex.test(e.target.value)) {
setCreateRoomFrom({ setCreateRoomFrom({
...createRoomFrom, ...createRoomFrom,

View File

@ -225,10 +225,13 @@ const User: React.FC = () => {
showCount={true} showCount={true}
value={addUserFrom.Account} value={addUserFrom.Account}
onChange={(e) => { onChange={(e) => {
setAddUserFrom({ const regex = /^[0-9]*$/;
...addUserFrom, if (regex.test(e.target.value)) {
Account: e.target.value, setAddUserFrom({
}); ...addUserFrom,
Account: e.target.value,
});
}
}} }}
/> />
</div> </div>

View File

@ -82,7 +82,6 @@ const Login: React.FC = () => {
if (!operation.account) { if (!operation.account) {
return message.error('请输入账号!') return message.error('请输入账号!')
} }
operation.password = "";
GetCheckUser(operation.account).then(res => { GetCheckUser(operation.account).then(res => {
if (res.code === 200) { if (res.code === 200) {
res.data ? setAccountPasswordStatus(true) : message.error('账号不存在!') res.data ? setAccountPasswordStatus(true) : message.error('账号不存在!')

View File

@ -694,7 +694,7 @@
.active { .active {
>div { >div {
// border: 1px solid #EBEBEB; border: 1px solid #EBEBEB;
} }
} }
} }

View File

@ -8,7 +8,7 @@ import { SearchOutlined } from '@ant-design/icons';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import { thumbImageBufferToBase64 } from '@/utils/package/base64' import { thumbImageBufferToBase64 } from '@/utils/package/base64'
import { storage } from '@/utils'; import { storage } from '@/utils';
import { GetRoomUser, PostOpenMicr, PostOpenCamera, PostRoomManager, DeleteRoomManager, GetRoomKickout } from '@/api/Meeting'; import { GetRoomUser, PostOpenMicr, PostOpenCamera, PostRoomManager, DeleteRoomManager, GetRoomKickout, GetShowUser } from '@/api/Meeting';
import ImageUrl from '@/utils/package/ImageUrl' import ImageUrl from '@/utils/package/ImageUrl'
import agora from '@/utils/package/agora' import agora from '@/utils/package/agora'
import { onInvoke, onSignalr, offSignalr, onStart } from '@/utils/package/signalr'; import { onInvoke, onSignalr, offSignalr, onStart } from '@/utils/package/signalr';
@ -112,6 +112,7 @@ const Meeting: React.FC = () => {
const [meetingMode, setMeetingMode] = useState('') const [meetingMode, setMeetingMode] = useState('')
const [userSearchValue, setUserSearchValue] = useState('') const [userSearchValue, setUserSearchValue] = useState('')
const [noViewChatList, setNoViewChatList] = useState(0) const [noViewChatList, setNoViewChatList] = useState(0)
const [currentLookUserAccount, setCurrentLookUserAccount] = useState<string>('')
useEffect(() => { useEffect(() => {
let time = null as any; let time = null as any;
let userInfo = JSON.parse(storage.getItem('user') as string) let userInfo = JSON.parse(storage.getItem('user') as string)
@ -131,7 +132,9 @@ const Meeting: React.FC = () => {
account: Number(info.localUid), account: Number(info.localUid),
view: document.getElementById(`video-${info.localUid}`) as HTMLElement, view: document.getElementById(`video-${info.localUid}`) as HTMLElement,
channelId: info.channelId, channelId: info.channelId,
sourceType: VideoSourceType.VideoSourceCameraPrimary,
}) })
getShowUser();
}, 1000); }, 1000);
}, },
onUserJoined: async (info: any, remoteUid: any, _elapsed: any) => { onUserJoined: async (info: any, remoteUid: any, _elapsed: any) => {
@ -155,7 +158,7 @@ const Meeting: React.FC = () => {
}, 1000); }, 1000);
} }
}) })
agora.setCameraCapture(VideoSourceType.VideoSourceCameraPrimary) agora.setCameraCapture()
agora.setJoinChannel({ agora.setJoinChannel({
channelId: state.channelId, channelId: state.channelId,
userid: userInfo.account, userid: userInfo.account,
@ -249,6 +252,27 @@ const Meeting: React.FC = () => {
}, [currentVideoId]) }, [currentVideoId])
useEffect(() => {
const userItem = allUserList.find((item: any) => item.account === currentLookUserAccount)
if (userItem) {
if (userItem.account === user.account) {
// agora.setupLocalVideo({
// account: Number(userItem.account),
// view: document.getElementById(`look-video`) as HTMLElement,
// channelId: state.channelId,
// sourceType: VideoSourceType.VideoSourceCameraPrimary,
// })
} else {
// agora.setupRemoteVideoJoin({
// account: Number(userItem.account),
// view: document.getElementById(`look-video`) as HTMLElement,
// channelId: state.channelId,
// sourceType: VideoSourceType.VideoSourceCameraPrimary,
// })
}
}
}, [allUserList, currentLookUserAccount])
// 网络 // 网络
const handleNetworkChange = (): void => { const handleNetworkChange = (): void => {
if (navigator.onLine) { if (navigator.onLine) {
@ -267,6 +291,14 @@ const Meeting: React.FC = () => {
message.error('网络已断开!') message.error('网络已断开!')
} }
} }
// 全员观看
const getShowUser = async (): Promise<void> => {
await GetShowUser(state.channelId).then(res => {
if (res.code === 200 && res.data) {
setCurrentLookUserAccount(res.data)
}
})
}
// 加入房间时间 // 加入房间时间
const changeCurrentSeconds = (): string => { const changeCurrentSeconds = (): string => {
const duration = dayjs.duration(currentSeconds, 'seconds'); const duration = dayjs.duration(currentSeconds, 'seconds');
@ -304,7 +336,7 @@ const Meeting: React.FC = () => {
setIsSharedScreenModal(true) setIsSharedScreenModal(true)
break; break;
case '停止共享': case '停止共享':
agora.setCameraCapture(VideoSourceType.VideoSourceCameraPrimary) agora.setCameraCapture()
footerListTemplate[itemIndex][rowIndex].title = '共享屏幕' footerListTemplate[itemIndex][rowIndex].title = '共享屏幕'
break; break;
case '关闭声音': case '关闭声音':
@ -386,7 +418,7 @@ const Meeting: React.FC = () => {
const footerListTemplate = [...footerList] const footerListTemplate = [...footerList]
footerListTemplate[footerListIndex.itemIndex][footerListIndex.rowIndex].title = '停止共享' footerListTemplate[footerListIndex.itemIndex][footerListIndex.rowIndex].title = '停止共享'
setIsSharedScreenModal(false) setIsSharedScreenModal(false)
agora.setDesktopCapturerVideo(sharedScreenItem, VideoSourceType.VideoSourceScreen) agora.setDesktopCapturerVideo(sharedScreenItem)
} else { } else {
message.error('请选择应用!') message.error('请选择应用!')
} }
@ -538,8 +570,8 @@ const Meeting: React.FC = () => {
return '' return ''
} }
// 设置单个视频样式 // 设置单个视频样式
const setMeetingContentSwiperCardClass = (account: string): string => { const setMeetingContentSwiperCardClass = (account: string, bool: boolean = false): string => {
if (currentVideoId === account && (meetingMode === 'StandardMode' || meetingMode === 'SpeakerMode')) { if ((bool || currentVideoId === account) && (meetingMode === 'StandardMode' || meetingMode === 'SpeakerMode')) {
switch (meetingMode) { switch (meetingMode) {
case 'StandardMode': case 'StandardMode':
return styles.meetingContentSwiperCardStandardMode return styles.meetingContentSwiperCardStandardMode
@ -569,11 +601,12 @@ const Meeting: React.FC = () => {
<div className={styles.meetingContentBody}> <div className={styles.meetingContentBody}>
<div className={`${styles.meetingContentBodyLeft} drag`}> <div className={`${styles.meetingContentBodyLeft} drag`}>
<div className={getMeetingContentBodyLeftModeClass()} > <div className={getMeetingContentBodyLeftModeClass()} >
{/* ${setMeetingContentSwiperCardClass(item.account)} */}
{allUserList.map((item: any, index: number) => { {allUserList.map((item: any, index: number) => {
return ( return (
item.isRoom ? item.isRoom ?
<div <div
className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass(item.account)}`} className={`${styles.meetingContentSwiperCard}`}
key={index} key={index}
onClick={() => { onClick={() => {
if (footerList[1][3].active) { if (footerList[1][3].active) {
@ -593,6 +626,19 @@ const Meeting: React.FC = () => {
) )
} }
)} )}
{currentLookUserAccount ?
<div className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass(currentLookUserAccount)}`}>
<div className={`${styles.meetingContentSwiperCardVdeio}`} id={`look-video`}>
</div>
</div>
:
<div className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass(currentLookUserAccount, true)}`}>
<div className={`${styles.meetingContentSwiperCardVdeio}`} style={{ color: 'white', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
</div>
</div>
}
</div> </div>
</div> </div>
{ {

View File

@ -17,7 +17,6 @@ const option: any = {
token: '', token: '',
channelId: '', channelId: '',
userid: '', userid: '',
sourceType: VideoSourceType.VideoSourceCameraPrimary,
} }
let iMediaRecorder: any = ''; let iMediaRecorder: any = '';
let rtcEngine: any = ''; let rtcEngine: any = '';
@ -80,19 +79,11 @@ const agora = {
setupLocalVideo: async (item: any) => { setupLocalVideo: async (item: any) => {
await rtcEngine.setupLocalVideo({ await rtcEngine.setupLocalVideo({
renderMode: RenderModeType.RenderModeFit, renderMode: RenderModeType.RenderModeFit,
sourceType: option.sourceType, sourceType: item.sourceType,
uid: item.account, uid: item.account,
view: item.view, view: item.view,
setupMode: VideoViewSetupMode.VideoViewSetupAdd, setupMode: VideoViewSetupMode.VideoViewSetupAdd,
}); });
switch (option.sourceType) {
case VideoSourceType.VideoSourceCameraPrimary:
agora.updateChannelMediaOptions(true)
break;
case VideoSourceType.VideoSourceScreen:
agora.updateChannelMediaOptions(false)
break;
}
}, },
// 远端加入 // 远端加入
setupRemoteVideoJoin: async (item: any) => { setupRemoteVideoJoin: async (item: any) => {
@ -135,33 +126,14 @@ const agora = {
}, },
// 加入频道 // 加入频道
joinChannel: () => { joinChannel: () => {
rtcEngine.joinChannel(option.token, option.channelId, option.userid, {}); rtcEngine.joinChannel(option.token, option.channelId, option.userid, {
}, autoSubscribeAudio: true,
// 更新频道信息 autoSubscribeVideo: true,
updateChannelMediaOptions: (bool: boolean) => { publishMicrophoneTrack: true,
if (bool) { publishCameraTrack: true,
// 摄像头 clientRoleType: ClientRoleType.ClientRoleBroadcaster,
rtcEngine.updateChannelMediaOptions({ publishScreenTrack: false,
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景 });
clientRoleType: ClientRoleType.ClientRoleBroadcaster, //设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可
publishMicrophoneTrack: true, //发布麦克风采集的音频
publishCameraTrack: true, //发布摄像头采集的视频
publishScreenTrack: false, //设置是否发布屏幕采集的视频
autoSubscribeAudio: true, //自动订阅所有音频流
autoSubscribeVideo: true, //自动订阅所有视频流
})
} else {
// 屏幕
rtcEngine.updateChannelMediaOptions({
channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景
clientRoleType: ClientRoleType.ClientRoleBroadcaster, //用户角色 1主播 2观众
publishMicrophoneTrack: true, //设置是否发布麦克风采集到的音频
publishCameraTrack: false, //设置是否发布摄像头采集的视频
publishScreenTrack: true, //设置是否发布屏幕采集的视频
autoSubscribeAudio: true, //设置是否自动订阅所有音频流
autoSubscribeVideo: true, //设置是否自动订阅所有视频流
})
}
}, },
// 停止共享屏幕 // 停止共享屏幕
stopScreenCapture: () => { stopScreenCapture: () => {
@ -176,17 +148,15 @@ const agora = {
rtcEngine.muteLocalVideoStream(mute) rtcEngine.muteLocalVideoStream(mute)
}, },
// 摄像头采集 // 摄像头采集
setCameraCapture: (sourceType: number) => { setCameraCapture: () => {
agora.stopScreenCapture() agora.stopScreenCapture()
if (sourceType !== option.sourceType) { // rtcEngine.destroyRendererByConfig(option.sourceType, option.channelId, option.account)
rtcEngine.destroyRendererByConfig(option.sourceType, option.channelId, option.account) agora.setupLocalVideo({
option.sourceType = sourceType account: Number(option.userid),
agora.setupLocalVideo({ view: document.getElementById(`video-${option.userid}`),
account: Number(option.userid), channelId: option.channelId,
view: document.getElementById(`video-${option.userid}`), sourceType: VideoSourceType.VideoSourceCameraPrimary,
channelId: option.channelId, })
})
}
rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {}) rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {})
}, },
// 加入频道 // 加入频道
@ -201,18 +171,28 @@ const agora = {
return rtcEngine.getScreenCaptureSources({ width: 300, height: 300 }, { width: 300, height: 300 }, true); return rtcEngine.getScreenCaptureSources({ width: 300, height: 300 }, { width: 300, height: 300 }, true);
}, },
// 共享屏幕采集 // 共享屏幕采集
setDesktopCapturerVideo: async (targetSource: any, sourceType: number) => { setDesktopCapturerVideo: async (targetSource: any) => {
if (sourceType !== option.sourceType) { // await rtcEngine.stopCameraCapture(option.sourceType)
await rtcEngine.stopCameraCapture(option.sourceType) // rtcEngine.destroyRendererByConfig(option.sourceType, option.channelId, option.account)
rtcEngine.destroyRendererByConfig(option.sourceType, option.channelId, option.account) await agora.setupLocalVideo({
option.sourceType = sourceType account: Number(option.userid),
agora.setupLocalVideo({ view: document.getElementById(`look-video`),
account: Number(option.userid), channelId: option.channelId,
view: document.getElementById(`video-${option.userid}`), sourceType: VideoSourceType.VideoSourceScreen,
channelId: option.channelId, })
})
}
agora.stopScreenCapture(); agora.stopScreenCapture();
rtcEngine.joinChannelEx(
option.token,
{ channelId: option.channelId, localUid: option.account },
{
autoSubscribeAudio: false,
autoSubscribeVideo: false,
publishMicrophoneTrack: false,
publishCameraTrack: false,
clientRoleType: ClientRoleType.ClientRoleBroadcaster,
publishScreenTrack: true,
}
);
if ( if (
targetSource.type === targetSource.type ===
ScreenCaptureSourceType.ScreencapturesourcetypeScreen ScreenCaptureSourceType.ScreencapturesourcetypeScreen

View File

@ -58,6 +58,12 @@ class Request {
message.error(resData.message) message.error(resData.message)
} }
} }
if (resData.code === 1403) {
setTimeout(() => {
storage.removeItem('user')
location.href = location.origin + '/#/login'
}, 3000)
}
return resData return resData
}, },
(err: any) => { (err: any) => {