This commit is contained in:
yj 2025-10-15 17:05:32 +08:00
parent 106d19a8cb
commit 486714bc10
3 changed files with 71 additions and 73 deletions

View File

@ -703,9 +703,9 @@ app.on('ready', () => {
childWindow[config.key].setBounds({ width: config.width, height: config.height }) childWindow[config.key].setBounds({ width: config.width, height: config.height })
break; break;
default: default:
mainWindow.setMinimumSize(250, config.height); mainWindow.setMinimumSize(config.width, config.height);
mainWindow.setMaximumSize(250, config.height); mainWindow.setMaximumSize(config.width, config.height);
mainWindow.setSize(250, config.height) mainWindow.setSize(config.width, config.height)
break; break;
} }
}); });

View File

@ -103,20 +103,6 @@
background-color: #1F2022; background-color: #1F2022;
left: 0; left: 0;
top: 0; top: 0;
z-index: 3000;
.meetingAbsoluteLoading {
background: black;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 1;
}
.meetingAbsoluteText { .meetingAbsoluteText {
position: absolute; position: absolute;
@ -124,7 +110,7 @@
left: 0; left: 0;
color: white; color: white;
text-align: center; text-align: center;
z-index: 2; z-index: 3;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
cursor: pointer; cursor: pointer;
font-size: 14px; font-size: 14px;
@ -234,7 +220,6 @@
#videoView { #videoView {
position: relative; position: relative;
border: 1px red solid;
} }
.standardModeIcon { .standardModeIcon {
@ -424,7 +409,11 @@
height: 160px; height: 160px;
} }
} }
.meetingContentBodyLeftSpeakerModeNoScrollbar{
&::-webkit-scrollbar {
display: none;
}
}
// 单画面模式 // 单画面模式
.meetingContentBodyLeftSingleScreenMode { .meetingContentBodyLeftSingleScreenMode {
width: 100%; width: 100%;

View File

@ -639,7 +639,10 @@ const Meeting: React.FC = () => {
if (isShare) { if (isShare) {
const item = roomUserList.find((item: any) => item.screenShareId === String(isShare)) const item = roomUserList.find((item: any) => item.screenShareId === String(isShare))
setIsShareUser(item || null) setIsShareUser(item || null)
setMeetingMode('StandardMode') setIsScreenCapture(isScreenCaptureValue => {
setMeetingMode(isScreenCaptureValue ? 'SpeakerMode' : 'StandardMode')
return isScreenCaptureValue
})
} }
}, [isShare, roomUserList]); }, [isShare, roomUserList]);
@ -745,7 +748,10 @@ const Meeting: React.FC = () => {
const temp = JSON.parse(item.contentString) const temp = JSON.parse(item.contentString)
if (temp.type === 'mode') { if (temp.type === 'mode') {
temp.msg ? message.success(`管理员已将会议室显示模式更新为${getMeetingContentBodyLeftModeText(temp.mode)}`) : null; temp.msg ? message.success(`管理员已将会议室显示模式更新为${getMeetingContentBodyLeftModeText(temp.mode)}`) : null;
setMeetingMode(temp.mode) setIsScreenCapture(isScreenCaptureValue => {
setMeetingMode(isScreenCaptureValue ? 'SpeakerMode' : temp.mode)
return isScreenCaptureValue
})
} }
} catch (error) { } catch (error) {
@ -1164,13 +1170,7 @@ const Meeting: React.FC = () => {
useEffect(() => { useEffect(() => {
if (isScreenCapture) { if (isScreenCapture) {
agora.setupLocalVideo({
uid: Number(user.uid),
view: document.getElementById(`meetingAbsoluteVideo`) as HTMLElement,
channelId: state.channelId,
sourceType: VideoSourceType.VideoSourceCameraPrimary,
type: true
})
} }
}, [isScreenCapture]); }, [isScreenCapture]);
@ -1289,18 +1289,11 @@ const Meeting: React.FC = () => {
observer?.unobserve(element); observer?.unobserve(element);
}); });
const observerObject = new IntersectionObserver(async (entries: IntersectionObserverEntry[], _observer: IntersectionObserver) => { const observerObject = new IntersectionObserver(async (entries: IntersectionObserverEntry[], _observer: IntersectionObserver) => {
setIsScreenCapture((bool: boolean) => { entries.forEach(async (entry) => {
entries.forEach(async (entry) => { if (entry.target.id !== user.uid) {
if (entry.target.id !== user.uid) { await agora.muteRemoteVideoStreamEx(Number(entry.target.id), !entry.isIntersecting)
await agora.muteRemoteVideoStreamEx(Number(entry.target.id), bool ? true : !entry.isIntersecting) }
} });
});
return bool
})
setIsScreenCapture((bool: boolean) => {
agora.muteRemoteVideoStreamEx(Number(currentVideoId), bool)
return bool
})
}, { threshold: 0, root: document.getElementById('videoView') }); }, { threshold: 0, root: document.getElementById('videoView') });
setObserver(observerObject) setObserver(observerObject)
elements.forEach(element => { elements.forEach(element => {
@ -1608,7 +1601,10 @@ const Meeting: React.FC = () => {
const peoPleLength = res.filter((item: any) => (role.ID.includes(item.roleId) || item.isRoomManager) && item.isRoom).length const peoPleLength = res.filter((item: any) => (role.ID.includes(item.roleId) || item.isRoomManager) && item.isRoom).length
setIsAdmin(peoPleLength) setIsAdmin(peoPleLength)
if (peoPleLength > 6) { if (peoPleLength > 6) {
setMeetingMode('StandardMode') setIsScreenCapture(isScreenCaptureValue => {
setMeetingMode(isScreenCaptureValue ? 'SpeakerMode' : 'StandardMode')
return isScreenCaptureValue
})
} }
return res return res
}) })
@ -2143,7 +2139,7 @@ const Meeting: React.FC = () => {
window.electron.createChildWindow('show') window.electron.createChildWindow('show')
setKeyOpenChildWindow('shareScreenWindow', true) setKeyOpenChildWindow('shareScreenWindow', true)
window.electron.setMainWindowSize({ window.electron.setMainWindowSize({
width: 250, width: 270,
height: 160, height: 160,
}) })
window.electron.setPosition('right') window.electron.setPosition('right')
@ -2205,7 +2201,6 @@ const Meeting: React.FC = () => {
} }
// 停止共享 // 停止共享
const stopScreenCapture = async (): Promise<void> => { const stopScreenCapture = async (): Promise<void> => {
await agora.destroyRendererByView(`meetingAbsoluteVideo`)
const footerListTemplate = [...footerList] const footerListTemplate = [...footerList]
await agora.leaveChannelEx(userInfo.screenShareId) await agora.leaveChannelEx(userInfo.screenShareId)
agora.stopScreenCapture() agora.stopScreenCapture()
@ -2274,7 +2269,10 @@ const Meeting: React.FC = () => {
const handleCustomStorageChange = async (e: any): Promise<void> => { const handleCustomStorageChange = async (e: any): Promise<void> => {
switch (e.key) { switch (e.key) {
case 'meetingMode': case 'meetingMode':
setMeetingMode(e.value) setIsScreenCapture(isScreenCaptureValue => {
setMeetingMode(isScreenCaptureValue ? 'SpeakerMode' : e.value)
return isScreenCaptureValue
})
break; break;
case 'quitMeeting': case 'quitMeeting':
if (e.value) { if (e.value) {
@ -2528,7 +2526,7 @@ const Meeting: React.FC = () => {
case 'StandardMode': case 'StandardMode':
return styles.meetingContentBodyLeftStandardMode return styles.meetingContentBodyLeftStandardMode
case 'SpeakerMode': case 'SpeakerMode':
return styles.meetingContentBodyLeftSpeakerMode return `${styles.meetingContentBodyLeftSpeakerMode} ${isScreenCapture ? styles.meetingContentBodyLeftSpeakerModeNoScrollbar : ''}`
case 'SingleScreenMode': case 'SingleScreenMode':
return styles.meetingContentBodyLeftSingleScreenMode return styles.meetingContentBodyLeftSingleScreenMode
case 'DualScreenMode': case 'DualScreenMode':
@ -2699,18 +2697,23 @@ 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', borderRadius: '10px 10px 0 0' }} className={`${styles.meetingAbsoluteText}`}>{currentSpeakUser.length ? '正在说话:' + currentSpeakUser.join(';') : '正在说话:'}</div>
{footerList[0][1].active ? <div className={styles.meetingAbsoluteLoading}> <div style={{ bottom: '0px', borderRadius: '0 0 10px 10px' }} className={`${styles.meetingAbsoluteText}`} onClick={() => {
<Avatar name={user.userName} />
</div> : null}
<div style={{ bottom: '0px' }} className={`${styles.meetingAbsoluteText} drag`} onClick={() => {
setIsExpand(!isExpand) setIsExpand(!isExpand)
window.electron.setChildWindow({ // 临时方案
height: isExpand ? 160 : 40, window.electron.setMainWindowSize({
key: 'main' width: 270,
height: !isExpand ? 160 * 4 : 160,
}) })
}}><span>{isExpand ? '展开' : '收起'}</span></div> window.electron.setPosition('right')
// 更新壳子
// window.electron.setChildWindow({
// height: !isExpand ? 160 * 4 : 160,
// width: 270,
// key: 'main'
// })
}}><span className='drag'>{isExpand ? '收起' : '查看参会者'}</span></div>
</div> : null} </div> : null}
{contextMenu ? <div className={styles.meetingContentSwiperCardPopover} style={ {contextMenu ? <div className={styles.meetingContentSwiperCardPopover} style={
{ {
@ -2809,9 +2812,9 @@ const Meeting: React.FC = () => {
></Button> : null} ></Button> : null}
</div> : null} </div> : null}
{contextHolder} {contextHolder}
<div className={styles.meetingHeader}> {isScreenCapture ? null : <div className={styles.meetingHeader}>
<div> <div>
{isScreenCapture ? null : <Popover <Popover
open={isNetworkQuality} open={isNetworkQuality}
content={ content={
<div style={{ color: 'white' }} onMouseLeave={() => setIsNetworkQuality(false)}> <div style={{ color: 'white' }} onMouseLeave={() => setIsNetworkQuality(false)}>
@ -2859,7 +2862,7 @@ const Meeting: React.FC = () => {
{networkIcon(currentEffective)} {networkIcon(currentEffective)}
<span></span> <span></span>
</div> </div>
</Popover>} </Popover>
<div>{changeCurrentSeconds()}</div> <div>{changeCurrentSeconds()}</div>
</div> </div>
<div style={{ display: 'flex', alignItems: 'center' }}>{state.channelId} {state.roomName} <div style={{ display: 'flex', alignItems: 'center' }}>{state.channelId} {state.roomName}
@ -2911,11 +2914,11 @@ const Meeting: React.FC = () => {
</Popover> : null} </Popover> : null}
<Operation></Operation> <Operation></Operation>
</div> </div>
</div> </div>}
<div className={styles.meetingContent}> <div className={styles.meetingContent}>
<div className={styles.meetingContentBody}> <div className={styles.meetingContentBody}>
<div className={`${styles.meetingContentBodyLeft} drag`}> <div className={`${styles.meetingContentBodyLeft} drag`}>
{isAdmin && currentLookUserAccount ? getSettingIcon() : null} {isAdmin && currentLookUserAccount && !isScreenCapture ? getSettingIcon() : null}
<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
@ -2923,6 +2926,9 @@ const Meeting: React.FC = () => {
className={`${styles.meetingContentSwiperCard} intersectionObserver-view`} className={`${styles.meetingContentSwiperCard} intersectionObserver-view`}
key={index} key={index}
onClick={() => { onClick={() => {
if (isScreenCapture) {
return
}
if (String(isShare) === item.screenShareId) { if (String(isShare) === item.screenShareId) {
renderVideo(item.screenShareId) renderVideo(item.screenShareId)
} else { } else {
@ -2930,6 +2936,9 @@ const Meeting: React.FC = () => {
} }
}} }}
onContextMenu={(e: any) => { onContextMenu={(e: any) => {
if (isScreenCapture) {
return
}
if (role.ID.includes(userInfo.roleId)) { if (role.ID.includes(userInfo.roleId)) {
setContextMenuStyle({ setContextMenuStyle({
top: e.clientY, top: e.clientY,
@ -2944,12 +2953,12 @@ const Meeting: React.FC = () => {
<Avatar name={item.userName} /> <Avatar name={item.userName} />
</div> </div>
</div> </div>
{meetingContentUser(item)} {meetingContentUser(item, false, isScreenCapture)}
{item.enableCamera ? null : meetingContentError(item)} {item.enableCamera ? null : meetingContentError(item)}
{String(isShare) === item.screenShareId ? <div className={styles.meetingContentSwiperCardShare}> {String(isShare) === item.screenShareId && !isScreenCapture ? <div className={styles.meetingContentSwiperCardShare}>
</div> : null} </div> : null}
{role.ID.includes(user.roleId) ? <Popover placement="bottom" title={''} content={ {role.ID.includes(user.roleId) && !isScreenCapture ? <Popover placement="bottom" title={''} content={
<div className={styles.meetingContentSwiperCardPopover}> <div className={styles.meetingContentSwiperCardPopover}>
{item.isRoomManager || role.ID.includes(item.roleId) ? <Button {item.isRoomManager || role.ID.includes(item.roleId) ? <Button
type="primary" type="primary"
@ -3053,7 +3062,7 @@ const Meeting: React.FC = () => {
container.scrollLeft -= 100 container.scrollLeft -= 100
}}> }}>
<CaretLeftOutlined /> <CaretLeftOutlined />
</div> : <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: '115px', top: '20px' }} onClick={() => { </div> : <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: isScreenCapture ? '120px' : '115px', top: '20px' }} onClick={() => {
const container = document.getElementById('videoView') as HTMLElement; const container = document.getElementById('videoView') as HTMLElement;
container.scrollTop -= 100 container.scrollTop -= 100
}}> }}>
@ -3064,7 +3073,7 @@ const Meeting: React.FC = () => {
container.scrollLeft += 100 container.scrollLeft += 100
}}> }}>
<CaretRightOutlined /> <CaretRightOutlined />
</div> : <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: '115px', bottom: '20px' }} onClick={() => { </div> : <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: isScreenCapture ? '120px' : '115px', bottom: '20px' }} onClick={() => {
const container = document.getElementById('videoView') as HTMLElement; const container = document.getElementById('videoView') as HTMLElement;
container.scrollTop += 100 container.scrollTop += 100
}}> }}>
@ -3072,7 +3081,7 @@ const Meeting: React.FC = () => {
</div>} </div>}
</div> : null} </div> : null}
{meetingMode !== "FreedomMode" && currentLookUserStatus === 0 ? {meetingMode !== "FreedomMode" && currentLookUserStatus === 0 ?
<div className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass()} ${setMeetingContentSwiperCardFullScreenClass()}`}> <div style={{ visibility: isScreenCapture ? 'hidden' : 'visible' }} className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass()} ${setMeetingContentSwiperCardFullScreenClass()}`}>
<div className={`${styles.meetingContentSwiperCardVdeio}`} id='video-source-camera-primary'> <div className={`${styles.meetingContentSwiperCardVdeio}`} id='video-source-camera-primary'>
{<div className={styles.meetingContentSwiperCardVdeioLoading}> {<div className={styles.meetingContentSwiperCardVdeioLoading}>
<img src={ImageUrl.loading} alt="" style={{ width: '50px' }} /> <img src={ImageUrl.loading} alt="" style={{ width: '50px' }} />
@ -3083,7 +3092,7 @@ const Meeting: React.FC = () => {
{meetingContentUser(currentLookUserAccount, true)} {meetingContentUser(currentLookUserAccount, true)}
</div> : null} </div> : null}
{meetingMode !== "FreedomMode" && currentLookUserStatus === 1 ? {meetingMode !== "FreedomMode" && currentLookUserStatus === 1 ?
<div className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass()} ${setMeetingContentSwiperCardFullScreenClass()}`}> <div style={{ visibility: isScreenCapture ? 'hidden' : 'visible' }} className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass()} ${setMeetingContentSwiperCardFullScreenClass()}`}>
<div className={`${styles.meetingContentSwiperCardVdeio}`} id='video-source-camera-primary'> <div className={`${styles.meetingContentSwiperCardVdeio}`} id='video-source-camera-primary'>
{<div className={styles.meetingContentSwiperCardVdeioLoading}> {<div className={styles.meetingContentSwiperCardVdeioLoading}>
<Avatar name={currentLookUserAccount.userName} /> <Avatar name={currentLookUserAccount.userName} />
@ -3095,7 +3104,7 @@ const Meeting: React.FC = () => {
{currentLookUserAccount.enableCamera ? null : meetingContentError(currentLookUserAccount)} {currentLookUserAccount.enableCamera ? null : meetingContentError(currentLookUserAccount)}
</div> : null} </div> : null}
{meetingMode !== "FreedomMode" && currentLookUserStatus === 2 ? {meetingMode !== "FreedomMode" && currentLookUserStatus === 2 ?
<div className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass()} ${setMeetingContentSwiperCardFullScreenClass()}`}> <div style={{ visibility: isScreenCapture ? 'hidden' : 'visible' }} className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass()} ${setMeetingContentSwiperCardFullScreenClass()}`}>
<div className={`${styles.meetingContentSwiperCardVdeio}`} id='video-source-screen'> <div className={`${styles.meetingContentSwiperCardVdeio}`} id='video-source-screen'>
<div className={styles.meetingContentSwiperCardVdeioLoading}> <div className={styles.meetingContentSwiperCardVdeioLoading}>
<Avatar name={currentLookUserAccount.userName} /> <Avatar name={currentLookUserAccount.userName} />
@ -3106,7 +3115,7 @@ const Meeting: React.FC = () => {
{meetingContentUser(currentLookUserAccount, true)} {meetingContentUser(currentLookUserAccount, true)}
</div> : null} </div> : null}
{meetingMode !== "FreedomMode" && currentLookUserStatus === 3 ? {meetingMode !== "FreedomMode" && currentLookUserStatus === 3 ?
<div className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass()} ${setMeetingContentSwiperCardFullScreenClass()}`}> <div style={{ visibility: isScreenCapture ? 'hidden' : 'visible' }} className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass()} ${setMeetingContentSwiperCardFullScreenClass()}`}>
<div className={`${styles.meetingContentSwiperCardVdeio}`} id='video-source-remote-screen'> <div className={`${styles.meetingContentSwiperCardVdeio}`} id='video-source-remote-screen'>
<div className={styles.meetingContentSwiperCardVdeioLoading}> <div className={styles.meetingContentSwiperCardVdeioLoading}>
<Avatar name={currentLookUserAccount.userName} /> <Avatar name={currentLookUserAccount.userName} />
@ -3117,7 +3126,7 @@ const Meeting: React.FC = () => {
{meetingContentUser(currentLookUserAccount, true)} {meetingContentUser(currentLookUserAccount, true)}
</div> : null} </div> : null}
{meetingMode !== "FreedomMode" && currentLookUserStatus === 4 ? {meetingMode !== "FreedomMode" && currentLookUserStatus === 4 ?
<div className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass()} ${setMeetingContentSwiperCardFullScreenClass()}`}> <div style={{ visibility: isScreenCapture ? 'hidden' : 'visible' }} className={`${styles.meetingContentSwiperCard} ${setMeetingContentSwiperCardClass()} ${setMeetingContentSwiperCardFullScreenClass()}`}>
<div className={`${styles.meetingContentSwiperCardVdeio}`} id='video-source-remote-camera'> <div className={`${styles.meetingContentSwiperCardVdeio}`} id='video-source-remote-camera'>
<div className={styles.meetingContentSwiperCardVdeioLoading}> <div className={styles.meetingContentSwiperCardVdeioLoading}>
<Avatar name={currentLookUserAccount.userName} /> <Avatar name={currentLookUserAccount.userName} />
@ -3781,7 +3790,7 @@ const Meeting: React.FC = () => {
) )
} }
const meetingContentUser = (item: any, bool?: boolean) => { const meetingContentUser = (item: any, bool?: boolean, isScreenCapture?: boolean) => {
return ( return (
<> <>
<div className={styles.meetingContentUser}> <div className={styles.meetingContentUser}>
@ -3798,7 +3807,7 @@ const meetingContentUser = (item: any, bool?: boolean) => {
</div> : ''} </div> : ''}
</label> </label>
} }
<span style={{ maxWidth: bool ? '' : '8vw' }} title={`${item.userName}${role.ID.includes(item.roleId) || item.isRoomManager ? role.ID.includes(item.roleId) ? '(管理员)' : '(发言人)' : ''}`}> <span style={{ maxWidth: bool ? '' : isScreenCapture ? '66vw' : '8vw' }} title={`${item.userName}${role.ID.includes(item.roleId) || item.isRoomManager ? role.ID.includes(item.roleId) ? '(管理员)' : '(发言人)' : ''}`}>
{item.userName} {item.userName}
{role.ID.includes(item.roleId) || item.isRoomManager ? role.ID.includes(item.roleId) ? '(管理员)' : '(发言人)' : ''} {role.ID.includes(item.roleId) || item.isRoomManager ? role.ID.includes(item.roleId) ? '(管理员)' : '(发言人)' : ''}
</span> </span>