共享屏幕小弹窗优化

This commit is contained in:
yj 2025-10-15 10:46:57 +08:00
parent 1f0cfc9a70
commit 5a99ec21a0
2 changed files with 120 additions and 42 deletions

View File

@ -105,6 +105,34 @@
top: 0; top: 0;
z-index: 3000; z-index: 3000;
.meetingAbsoluteVideoView {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
left: 0;
top: 0;
>div {
height: 160px;
position: relative;
.meetingAbsoluteUser {
position: absolute;
left: 0;
bottom: 0;
font-size: 13px;
color: #EEEEEE;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
background-color: rgba(0, 0, 0, 0.62);
z-index: 1;
padding: 2px 4px;
box-sizing: border-box;
width: 100%;
}
.meetingAbsoluteLoading { .meetingAbsoluteLoading {
background: black; background: black;
position: absolute; position: absolute;
@ -117,6 +145,8 @@
align-items: center; align-items: center;
z-index: 1; z-index: 1;
} }
}
}
.meetingAbsoluteText { .meetingAbsoluteText {
position: absolute; position: absolute;
@ -234,7 +264,6 @@
#videoView { #videoView {
position: relative; position: relative;
border: 1px red solid;
} }
.standardModeIcon { .standardModeIcon {

View File

@ -1164,13 +1164,25 @@ const Meeting: React.FC = () => {
useEffect(() => { useEffect(() => {
if (isScreenCapture) { if (isScreenCapture) {
agora.setupLocalVideo({ roomUserList
.filter((item: any) => item.isRoom && item.isAdmin).forEach(async (item: any) => {
if (user.uid === item.uid) {
await agora.setupLocalVideo({
uid: Number(user.uid), uid: Number(user.uid),
view: document.getElementById(`meetingAbsoluteVideo`) as HTMLElement, view: document.getElementById(`meetingAbsoluteVideo`) as HTMLElement,
channelId: state.channelId, channelId: state.channelId,
sourceType: VideoSourceType.VideoSourceCameraPrimary, sourceType: VideoSourceType.VideoSourceCameraPrimary,
type: true type: true
}) })
} else {
await agora.setupRemoteVideoJoin({
uid: Number(item.uid),
view: document.getElementById(`meeting-absolute-video-${item.uid}`),
channelId: state.channelId,
renderMode: RenderModeType.RenderModeHidden,
})
}
});
} }
}, [isScreenCapture]); }, [isScreenCapture]);
@ -1283,26 +1295,27 @@ const Meeting: React.FC = () => {
}, [applyUserList]); }, [applyUserList]);
useEffect(() => { useEffect(() => {
const elements = document.querySelectorAll('.intersectionObserver-view'); const className = isScreenCapture ? '.intersectionAbsoluteObserver-view' : '.intersectionObserver-view';
if (elements.length && currentVideoId) { const rootId = isScreenCapture ? 'meetingAbsoluteVideoView' : 'videoView';
const rootElement = document.getElementById(rootId);
const elements = document.querySelectorAll(className);
elements.forEach(element => { elements.forEach(element => {
observer?.unobserve(element); observer?.unobserve(element);
}); });
const observerObject = new IntersectionObserver(async (entries: IntersectionObserverEntry[], _observer: IntersectionObserver) => { observer?.disconnect();
setIsScreenCapture((bool: boolean) => { if (elements.length && currentVideoId && rootElement) {
entries.forEach(async (entry) => { const observerObject = new IntersectionObserver(
if (entry.target.id !== user.uid) { (entries: IntersectionObserverEntry[]) => {
await agora.muteRemoteVideoStreamEx(Number(entry.target.id), bool ? true : !entry.isIntersecting) entries.forEach(entry => {
const dataUid = (entry.target as HTMLElement).getAttribute('data-uid');
if (dataUid !== user.uid) {
agora.muteRemoteVideoStreamEx(Number(dataUid), !entry.isIntersecting);
} }
}); });
return bool },
}) { threshold: 0, root: rootElement }
setIsScreenCapture((bool: boolean) => { );
agora.muteRemoteVideoStreamEx(Number(currentVideoId), bool) setObserver(observerObject);
return bool
})
}, { threshold: 0, root: document.getElementById('videoView') });
setObserver(observerObject)
elements.forEach(element => { elements.forEach(element => {
observerObject.observe(element); observerObject.observe(element);
}); });
@ -1334,7 +1347,7 @@ const Meeting: React.FC = () => {
}); });
observer?.disconnect(); observer?.disconnect();
} }
}, [roomUserList, currentVideoId, footerList]); }, [roomUserList, currentVideoId, footerList, isScreenCapture]);
// 声网初始化 // 声网初始化
const agoraInit = async () => { const agoraInit = async () => {
@ -1397,6 +1410,17 @@ const Meeting: React.FC = () => {
return res return res
}) })
}, 1000); }, 1000);
setIsScreenCapture(bool => {
if (bool) {
agora.setupRemoteVideoJoin({
uid: Number(remoteUid),
view: document.getElementById(`meeting-absolute-video-${remoteUid}`),
channelId: connection.channelId,
renderMode: RenderModeType.RenderModeHidden,
})
}
return bool
})
} }
} }
}, },
@ -2140,6 +2164,7 @@ const Meeting: React.FC = () => {
const isOpen = await getKeyOpenChildWindow('shareScreenWindow') const isOpen = await getKeyOpenChildWindow('shareScreenWindow')
setIsScreenCapture(true) setIsScreenCapture(true)
if (!isOpen) { if (!isOpen) {
setIsExpand(false)
window.electron.createChildWindow('show') window.electron.createChildWindow('show')
setKeyOpenChildWindow('shareScreenWindow', true) setKeyOpenChildWindow('shareScreenWindow', true)
window.electron.setMainWindowSize({ window.electron.setMainWindowSize({
@ -2206,6 +2231,9 @@ const Meeting: React.FC = () => {
// 停止共享 // 停止共享
const stopScreenCapture = async (): Promise<void> => { const stopScreenCapture = async (): Promise<void> => {
await agora.destroyRendererByView(`meetingAbsoluteVideo`) await agora.destroyRendererByView(`meetingAbsoluteVideo`)
roomUserList.forEach(async (item: any) => {
await agora.destroyRendererByConfig(Number(item.uid), state.channelId)
});
const footerListTemplate = [...footerList] const footerListTemplate = [...footerList]
await agora.leaveChannelEx(userInfo.screenShareId) await agora.leaveChannelEx(userInfo.screenShareId)
agora.stopScreenCapture() agora.stopScreenCapture()
@ -2699,18 +2727,39 @@ const Meeting: React.FC = () => {
} }
setIsNetworkQuality(false) setIsNetworkQuality(false)
}}> }}>
{isScreenCapture ? <div className={`${styles.meetingAbsolute}`} id='meetingAbsoluteVideo'> {isScreenCapture ? <div className={`${styles.meetingAbsolute}`}>
<div style={{ top: '0px' }} className={`${styles.meetingAbsoluteText}`}>{currentSpeakUser.length ? '正在说话:' + currentSpeakUser.join(';') : '正在说话:'}</div> <div style={{ top: '0px' }} className={`${styles.meetingAbsoluteText}`}>{currentSpeakUser.length ? '正在说话:' + currentSpeakUser.join(';') : '正在说话:'}</div>
<div className={`${styles.meetingAbsoluteVideoView}`} id='meetingAbsoluteVideoView' style={{ overflowY: roomUserList.filter((item: any) => item.isRoom).length > 4 && isExpand ? 'auto' : 'hidden' }}>
<div id='meetingAbsoluteVideo' style={{
margin: !isExpand ? '0' : '0 auto 5px',
width: !isExpand ? '100%' : '96%',
}}>
{footerList[0][1].active ? <div className={styles.meetingAbsoluteLoading}> {footerList[0][1].active ? <div className={styles.meetingAbsoluteLoading}>
<Avatar name={user.userName} /> <Avatar name={user.userName} />
</div> : null} </div> : null}
{!footerList[0][1].active && isExpand ? <div className={styles.meetingAbsoluteUser}>{user.userName}</div> : null}
</div>
{roomUserList
.filter((item: any) => item.isRoom && item.isAdmin && item.uid !== user.uid)
.map((item: any) => (
<div id={`meeting-absolute-video-${item.uid}`} style={{
margin: !isExpand ? '0' : '0 auto 5px',
width: !isExpand ? '100%' : '96%',
}} data-uid={item.uid} className={`intersectionAbsoluteObserver-view`}>
{item.enableCamera && isExpand ? <div className={styles.meetingAbsoluteUser}>{item.userName}</div> : null}
{item.enableCamera ? null : <div className={styles.meetingAbsoluteLoading}>
<Avatar name={item.userName} />
</div>}
</div>
))}
</div>
<div style={{ bottom: '0px' }} className={`${styles.meetingAbsoluteText} drag`} onClick={() => { <div style={{ bottom: '0px' }} className={`${styles.meetingAbsoluteText} drag`} onClick={() => {
setIsExpand(!isExpand) setIsExpand(!isExpand)
window.electron.setChildWindow({ window.electron.setChildWindow({
height: isExpand ? 160 : 40, height: !isExpand ? 4 * 160 + 15 : 160,
key: 'main' key: 'main'
}) })
}}><span>{isExpand ? '展开' : '收起'}</span></div> }}><span>{isExpand ? '收起' : '查看参会者'}</span></div>
</div> : null} </div> : null}
{contextMenu ? <div className={styles.meetingContentSwiperCardPopover} style={ {contextMenu ? <div className={styles.meetingContentSwiperCardPopover} style={
{ {
@ -2919,7 +2968,7 @@ const Meeting: React.FC = () => {
<div className={getMeetingContentBodyLeftModeClass(isAdmin)} id='videoView' style={meetingMode === 'SpeakerMode' && isVideoFullScreen ? { width: '0' } : {}}> <div className={getMeetingContentBodyLeftModeClass(isAdmin)} id='videoView' style={meetingMode === 'SpeakerMode' && isVideoFullScreen ? { width: '0' } : {}}>
{roomUserList.map((item: any, index: number) => { {roomUserList.map((item: any, index: number) => {
return (item.isRoom && item.isAdmin ? <div return (item.isRoom && item.isAdmin ? <div
id={item.uid} data-uid={item.uid}
className={`${styles.meetingContentSwiperCard} intersectionObserver-view`} className={`${styles.meetingContentSwiperCard} intersectionObserver-view`}
key={index} key={index}
onClick={() => { onClick={() => {