yangjie #51

Open
yangqiang wants to merge 34 commits from yangjie into master
31 changed files with 1729 additions and 210 deletions

15
build.js Normal file
View File

@ -0,0 +1,15 @@
const fs = require('fs');
const path = require('path');
const indexPath = path.resolve(__dirname, 'dist/index.html');
let indexHtml = fs.readFileSync(indexPath, 'utf-8');
const timestamp = new Date().getTime();
// 正则表达式匹配JS文件引用并添加时间戳
indexHtml = indexHtml.replace(/<script type="module" crossorigin src="([^"]+)">/g, (match, p1) => {
if (p1.endsWith('.js')) {
return `<script type="module" crossorigin src="${p1}?t=${timestamp}"></script>`;
}
return match;
});
fs.writeFileSync(indexPath, indexHtml);

BIN
build/start-my.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
build/start-xatyz.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

57
config/my.json Normal file
View File

@ -0,0 +1,57 @@
{
"appId": "agora.io.ElectronApiExample",
"asar": true,
"asarUnpack": [
"node_modules/agora-electron-sdk"
],
"buildDependenciesFromSource": true,
"compression": "normal",
"productName": "绵阳中学人工智能教育发展共同体 · 教研平台",
"publish": [
{
"provider": "generic",
"url": "https://meeting-api.23544.com/meeting/my"
}
],
"files": [
"!*.log"
],
"win": {
"icon": "build/start-my.ico",
"requestedExecutionLevel": "highestAvailable",
"target": [
{
"target": "nsis",
"arch": [
"ia32"
]
}
]
},
"directories": {
"output": "electron"
},
"extraResources": [
{
"from": "src/assets/virtualBackground",
"to": "images",
"filter": [
"**/*"
]
}
],
"nsis": {
"oneClick": false,
"installerIcon": "build/start-my.ico",
"uninstallerIcon": "build/start-my.ico",
"installerHeaderIcon": "build/start-my.ico",
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"deleteAppDataOnUninstall": true,
"shortcutName": "绵阳中学人工智能教育发展共同体 · 教研平台",
"allowElevation": true,
"perMachine": true,
"include": "build/install.nsh"
}
}

57
config/xatyz.json Normal file
View File

@ -0,0 +1,57 @@
{
"appId": "agora.io.ElectronApiExample",
"asar": true,
"asarUnpack": [
"node_modules/agora-electron-sdk"
],
"buildDependenciesFromSource": true,
"compression": "normal",
"productName": "西安铁一中教研平台",
"publish": [
{
"provider": "generic",
"url": "https://meeting-api.23544.com/meeting/xatyz"
}
],
"files": [
"!*.log"
],
"win": {
"icon": "build/start-xatyz.ico",
"requestedExecutionLevel": "highestAvailable",
"target": [
{
"target": "nsis",
"arch": [
"ia32"
]
}
]
},
"directories": {
"output": "electron"
},
"extraResources": [
{
"from": "src/assets/virtualBackground",
"to": "images",
"filter": [
"**/*"
]
}
],
"nsis": {
"oneClick": false,
"installerIcon": "build/start-xatyz.ico",
"uninstallerIcon": "build/start-xatyz.ico",
"installerHeaderIcon": "build/start-xatyz.ico",
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"deleteAppDataOnUninstall": true,
"shortcutName": "西安铁一中教研平台",
"allowElevation": true,
"perMachine": true,
"include": "build/install.nsh"
}
}

View File

@ -6,6 +6,10 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Security-Policy" content="script-src 'self'"> <meta http-equiv="Content-Security-Policy" content="script-src 'self'">
<meta name="build-time" content="<%- buildTime%>" id="build-time">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<!-- <meta http-equiv="Content-Security-Policy" <!-- <meta http-equiv="Content-Security-Policy"
content="script-src 'self' https://www.google-analytics.com; style-src 'self' https://animate.style"> --> content="script-src 'self' https://www.google-analytics.com; style-src 'self' https://animate.style"> -->
<title></title> <title></title>

20
main.js
View File

@ -25,14 +25,12 @@ app.allowRendererProcessReuse = false;
let mainWindow = null; let mainWindow = null;
let childWindow = {} let childWindow = {}
let isMaximized = false; let isMaximized = false;
let env = 'development'; //development production xy
let regKey; let regKey;
let connection = null; let connection = null;
let startNumber = 0; let startNumber = 0;
let buildStatus = false; //true 打包开发版本 false 本地开发 let env = 'my'; //development production xy xatyz my
let buildStatus = true; //true 打包开发版本 false 本地开发
powerSaveBlocker.start('prevent-display-sleep') powerSaveBlocker.start('prevent-display-sleep')
const id = powerSaveBlocker.start('prevent-display-sleep')
powerSaveBlocker.stop(id)
class AppWindow extends BrowserWindow { class AppWindow extends BrowserWindow {
constructor(config) { constructor(config) {
@ -74,7 +72,13 @@ let tray;
// 检查网络状态 // 检查网络状态
function checkNetworkStatus() { function checkNetworkStatus() {
if (!net.isOnline()) { if (!net.isOnline()) {
dialog.showErrorBox(`${env === 'xy' ? '湖北襄阳四中教研平台' : '智汇享'}-网络连接错误', '当前无网络连接,请检查您的网络设置。`); const titleMap = {
xy: '湖北襄阳四中教研平台',
xatyz: '西安铁一中教研平台',
my: '绵阳中学人工智能教育发展共同体 · 教研平台'
};
const title = `${titleMap[env] || '智汇享'}-网络连接错误`;
dialog.showErrorBox(title, '当前无网络连接,请检查您的网络设置。');
app.quit(); app.quit();
return false; return false;
} }
@ -705,9 +709,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;
} }
}); });

960
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,9 +9,11 @@
"dev": "concurrently \"electron .\" \"cross-env BROWSER=none vite\"", "dev": "concurrently \"electron .\" \"cross-env BROWSER=none vite\"",
"build": "vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",
"build:dev": "vite build & electron-builder -w --config=./config/development.json", "build:dev": "vite build & node build.js & electron-builder -w --config=./config/development.json",
"build:prod": "vite build & electron-builder -w --config=./config/production.json", "build:prod": "vite build & node build.js & electron-builder -w --config=./config/production.json",
"build:xy": "vite build & electron-builder -w --config=./config/xy.json" "build:xy": "vite build & node build.js & electron-builder -w --config=./config/xy.json",
"build:xatyz": "vite build & node build.js & electron-builder -w --config=./config/xatyz.json",
"build:my": "vite build & node build.js & electron-builder -w --config=./config/my.json"
}, },
"agora_electron": { "agora_electron": {
"platform": "win32", "platform": "win32",
@ -53,6 +55,7 @@
"electron-builder": "^23.1.0", "electron-builder": "^23.1.0",
"typescript": "^4.5.4", "typescript": "^4.5.4",
"vite": "^2.8.0", "vite": "^2.8.0",
"vite-plugin-html": "^3.2.2",
"vite-plugin-resolve": "^2.5.1" "vite-plugin-resolve": "^2.5.1"
} }
} }

BIN
src/assets/icon57.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

BIN
src/assets/icon58.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
src/assets/icon59.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

BIN
src/assets/icon60.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

BIN
src/assets/icon61.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

BIN
src/assets/icon62.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
src/assets/icon63.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -53,14 +53,14 @@ const SpeakerModeModal = forwardRef((props: any, ref: any) => {
}) })
const FreedomMode: React.FC<Props> = ({ onClick, meetingMode }) => { const FreedomMode: React.FC<Props> = ({ onClick, meetingMode }) => {
// 自由者模式 // 宫格模式
return ( return (
<> <>
<div className={styles.freedomMode} onClick={onClick}> <div className={styles.freedomMode} onClick={onClick}>
<div className={`${meetingMode === 'FreedomMode' ? styles.active : ''}`}> <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>)} {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16].map(item => <div key={item}></div>)}
</div> </div>
<span></span> <span></span>
</div> </div>
</> </>
) )

View File

@ -123,7 +123,7 @@
>div:nth-child(1) { >div:nth-child(1) {
color: #ccc; color: #ccc;
font-size: 16px; font-size: 14px;
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -45,6 +45,7 @@ const Home: React.FC = () => {
]); ]);
const [userInfo, setUserInfo] = useState<any>({}) const [userInfo, setUserInfo] = useState<any>({})
const [version, setVersion] = useState<string>('') const [version, setVersion] = useState<string>('')
const [buildTime, setBuildTime] = useState<string>('0')
const [update, setUpdate] = useState(false) const [update, setUpdate] = useState(false)
const [dateInfo, setDateInfo] = useState<{ const [dateInfo, setDateInfo] = useState<{
work: string; work: string;
@ -60,6 +61,13 @@ const Home: React.FC = () => {
window.electron.getVersion().then(res => { window.electron.getVersion().then(res => {
setVersion(res) setVersion(res)
}) })
try {
const buildStr = document.getElementById('build-time')?.getAttribute('content');
const formattedTime = dayjs(Number(buildStr)).format('YYYYMMDDHHmm');
setBuildTime(formattedTime)
} catch {
}
const updateTime = () => { const updateTime = () => {
setDateInfo({ setDateInfo({
work: dayjs().format('ddd'), work: dayjs().format('ddd'),
@ -136,7 +144,9 @@ const Home: React.FC = () => {
</div> </div>
<div className='drag'> <div className='drag'>
<div> <div>
<span>:{version}</span> <span>V{version}-
<span style={{ fontSize: '12px', color: 'gray' }}>{buildTime}</span>
</span>
{update ? <span>new</span> : null} {update ? <span>new</span> : null}
</div> </div>
{update ? <div> {update ? <div>

View File

@ -129,7 +129,7 @@
flex-shrink: 0; flex-shrink: 0;
color: #ccc; color: #ccc;
text-align: right; text-align: right;
font-size: 16px; font-size: 14px;
} }
} }
} }

View File

@ -11,6 +11,7 @@ import { v4 as uuidv4 } from 'uuid';
import { GetCheckoutRoomNum, GetRoomInfo, GetRoomRtcToken } from '@/api/Home/Index'; import { GetCheckoutRoomNum, GetRoomInfo, GetRoomRtcToken } from '@/api/Home/Index';
import { ExclamationCircleFilled } from '@ant-design/icons'; import { ExclamationCircleFilled } from '@ant-design/icons';
import { isVersion } from '@/utils/package/public'; import { isVersion } from '@/utils/package/public';
import dayjs from 'dayjs';
const { confirm } = Modal; const { confirm } = Modal;
const Login: React.FC = () => { const Login: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@ -39,6 +40,7 @@ const Login: React.FC = () => {
nickName: '', nickName: '',
roomNum: '', roomNum: '',
}) })
const [buildTime, setBuildTime] = useState<string>('0')
const [nameModal, setNameModal] = useState(false) const [nameModal, setNameModal] = useState(false)
const [env, setEnv] = useState('') const [env, setEnv] = useState('')
useEffect(() => { useEffect(() => {
@ -50,6 +52,13 @@ const Login: React.FC = () => {
window.electron.getEnv().then(res => { window.electron.getEnv().then(res => {
setEnv(res) setEnv(res)
}) })
try {
const buildStr = document.getElementById('build-time')?.getAttribute('content');
const formattedTime = dayjs(Number(buildStr)).format('YYYYMMDDHHmm');
setBuildTime(formattedTime)
} catch {
}
if (storage.getItem('login')) { if (storage.getItem('login')) {
const login = JSON.parse(storage.getItem('login') as string); const login = JSON.parse(storage.getItem('login') as string);
const data = { const data = {
@ -204,7 +213,23 @@ const Login: React.FC = () => {
<> <>
<div className={styles.login}> <div className={styles.login}>
<div className={styles.loginBg}> <div className={styles.loginBg}>
{env ? <img src={env === 'xy' ? ImageUrl.icon53 : ImageUrl.icon1} alt="" /> : null} {env && (
<img
src={(() => {
switch (env) {
case 'xy':
return ImageUrl.icon53
case 'xatyz':
return ImageUrl.icon58
case 'my':
return ImageUrl.icon63
default:
return ImageUrl.icon1
}
})()}
alt=""
/>
)}
</div> </div>
<div className={styles.loginContent}> <div className={styles.loginContent}>
<div> <div>
@ -319,7 +344,8 @@ const Login: React.FC = () => {
><img src={ImageUrl.icon3} alt="" /></div> ><img src={ImageUrl.icon3} alt="" /></div>
</div> </div>
<div> <div>
{version} V{version}-
<span style={{ fontSize: '12px', color: 'gray' }}>{buildTime}</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -52,9 +52,15 @@
align-items: center; align-items: center;
>span { >span {
font-size: 14px; display: flex;
flex-direction: column;
color: #F3F3F5; color: #F3F3F5;
margin-left: 4px; margin-left: 4px;
font-size: 13px;
>span {
font-size: 12px;
}
} }
>div { >div {

View File

@ -83,10 +83,10 @@ const UserListWindow: React.FC = () => {
<div> <div>
<div><Avatar name={item.userName} /></div> <div><Avatar name={item.userName} /></div>
<span> <span>
{item.userName}{item.uid === user.uid ? '(我)' : ''} {item.userName}
{role.ID.includes(item.roleId) || item.isRoomManager ? {role.ID.includes(item.roleId) || item.isRoomManager ?
<span style={{ color: '#02B188', marginLeft: '4px' }}> <span>
{role.ID.includes(item.roleId) ? '管理员' : '发言人'} {role.ID.includes(item.roleId) ? item.uid === user.uid ? '(管理员,我)' : '(管理员)' : item.uid === user.uid ? '(发言人,我)' : '(发言人)'}
</span> </span>
: null} : null}
</span> </span>

View File

@ -10,7 +10,7 @@
.meetingContentUserName { .meetingContentUserName {
display: flex; display: flex;
align-items: center; align-items: center;
background-color: #0000009E; background-color: rgba(0, 0, 0, 0.62);
border-radius: 6px; border-radius: 6px;
height: 24px; height: 24px;
padding: 0 4px; padding: 0 4px;
@ -103,19 +103,43 @@
background-color: #1F2022; background-color: #1F2022;
left: 0; left: 0;
top: 0; top: 0;
z-index: 3000;
.meetingAbsoluteLoading { .meetingAbsoluteHeader {
background: black;
position: absolute; position: absolute;
left: 0;
top: 0;
width: 100%; width: 100%;
height: 100%; left: 0;
z-index: 3;
display: flex; display: flex;
justify-content: center; flex-direction: column;
align-items: center; background-color: rgba(0, 0, 0, 0.5);
z-index: 1;
>div {
width: 100%;
padding: 2px 10px;
box-sizing: border-box;
display: flex;
align-items: flex-start;
>span {
display: flex;
align-items: center;
>img {
height: 24px;
}
}
}
>span {
font-size: 14px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
color: white;
width: 100%;
padding: 0 10px;
box-sizing: border-box;
}
} }
.meetingAbsoluteText { .meetingAbsoluteText {
@ -124,7 +148,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 +258,6 @@
#videoView { #videoView {
position: relative; position: relative;
border: 1px red solid;
} }
.standardModeIcon { .standardModeIcon {
@ -285,14 +308,126 @@
} }
} }
// 宫格模式
// 1
.meetingContentBodyLeftFreedomModeOne {
width: 100%;
height: 100%;
// 自由者模式 .meetingContentSwiperCard {
.meetingContentBodyLeftFreedomMode { width: 100%;
height: 100%;
}
}
// 2
.meetingContentBodyLeftFreedomModeTwo {
width: 100%;
height: 100%;
display: flex;
.meetingContentSwiperCard {
width: 50%;
height: 100%;
}
}
// 3 4
.meetingContentBodyLeftFreedomModeThree {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
overflow-y: auto; justify-content: center;
.meetingContentSwiperCard {
width: 50%;
height: 50%;
}
}
//5 6
.meetingContentBodyLeftFreedomModeFour {
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
.meetingContentSwiperCard {
width: calc(100% / 3);
height: 50%;
}
}
// 7
.meetingContentBodyLeftFreedomModeFive {
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
.meetingContentSwiperCard {
width: calc(100% / 4);
height: 50%;
}
}
//8 9
.meetingContentBodyLeftFreedomModeSix {
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
.meetingContentSwiperCard {
width: calc(100% / 3);
height: calc(100% / 3);
}
}
// 10 11 12
.meetingContentBodyLeftFreedomModeSeven {
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
.meetingContentSwiperCard {
width: calc(100% / 4);
height: calc(100% / 3);
}
}
// 13 14 15 16
.meetingContentBodyLeftFreedomModeEight {
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
.meetingContentSwiperCard {
width: calc(100% / 4);
height: calc(100% / 4);
}
}
// 17 18 19 20
.meetingContentBodyLeftFreedomModeNine {
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
.meetingContentSwiperCard {
width: calc(100% / 5);
height: calc(100% / 4);
}
} }
// 标准模式 // 标准模式
@ -309,13 +444,18 @@
.meetingContentSwiperCard { .meetingContentSwiperCard {
width: 100%; width: 100%;
}
.meetingContentSwiperCard {
height: 160px; height: 160px;
} }
} }
.meetingContentBodyLeftSpeakerModeNoScrollbar {
width: 246px !important;
&::-webkit-scrollbar {
display: none;
}
}
// 单画面模式 // 单画面模式
.meetingContentBodyLeftSingleScreenMode { .meetingContentBodyLeftSingleScreenMode {
width: 100%; width: 100%;
@ -920,40 +1060,72 @@
} }
.modePopover { .modePopover {
display: flex;
flex-direction: column;
align-items: center;
>div { >div {
width: 140px;
height: 30px;
line-height: 30px;
border-radius: 5px;
margin-bottom: 8px;
cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center;
>span { >div {
color: #EEEEEE; width: 100px;
padding: 10px 0;
line-height: 30px;
border-radius: 5px;
cursor: pointer;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
margin-right: 20px;
>span {
color: #EEEEEE;
}
>img {
height: 30px;
margin-bottom: 4px;
}
} }
>img { >div {
height: 16px; background-color: #101418;
margin-right: 10px;
&:hover {
background-color: lighten(#101418, 4%);
}
&:active {
background-color: darken(#101418, 4%);
}
} }
&:last-child { .active {
margin: 0; background-color: lighten(#101418, 8%);
cursor: not-allowed;
&:hover {
background-color: lighten(#101418, 8%);
}
&:active {
background-color: lighten(#101418, 8%);
}
}
:last-child {
margin-right: 0px;
} }
} }
>div { >span {
background-color: #101418; margin-top: 4px;
color: white;
&:hover { >span {
background-color: lighten(#101418, 4%); margin-left: 4px;
}
&:active {
background-color: darken(#101418, 4%);
} }
} }
} }

View File

@ -184,7 +184,8 @@ const Meeting: React.FC = () => {
const [isClickLock, setIsClickLock] = useState(false) const [isClickLock, setIsClickLock] = useState(false)
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [modeOpen, setModeOpen] = useState(false) const [modeOpen, setModeOpen] = useState(false)
const [meetingMode, setMeetingMode] = useState('') const [showCaret, setShowCaret] = useState(false)
const [meetingMode, setMeetingMode] = useState('FreedomMode')
const [userSearchValue, setUserSearchValue] = useState('') const [userSearchValue, setUserSearchValue] = useState('')
const [noViewChatList, setNoViewChatList] = useState(0) const [noViewChatList, setNoViewChatList] = useState(0)
const [currentLookUserAccount, setCurrentLookUserAccount] = useState<any>('') const [currentLookUserAccount, setCurrentLookUserAccount] = useState<any>('')
@ -217,6 +218,7 @@ const Meeting: React.FC = () => {
} }
}); });
const [isVideoFullScreen, setIsVideoFullScreen] = useState<boolean>(false) const [isVideoFullScreen, setIsVideoFullScreen] = useState<boolean>(false)
const [_freedomModeStatus, setFreedomModeStatus] = useState<boolean>(false)
const [observer, setObserver] = useState<IntersectionObserver>() const [observer, setObserver] = useState<IntersectionObserver>()
const [_activeSpeaker, setActiveSpeaker] = useState('') const [_activeSpeaker, setActiveSpeaker] = useState('')
let userInfo = JSON.parse(storage.getItem('user') as string) let userInfo = JSON.parse(storage.getItem('user') as string)
@ -235,7 +237,6 @@ const Meeting: React.FC = () => {
} }
}) })
setKeyOpenChildWindow('shareScreenWindow', false) setKeyOpenChildWindow('shareScreenWindow', false)
setMeetingMode('StandardMode');
agoraInit() agoraInit()
storage.setItem('noViewChatList', 0) storage.setItem('noViewChatList', 0)
window.addEventListener('customStorageChange', handleCustomStorageChange); window.addEventListener('customStorageChange', handleCustomStorageChange);
@ -489,7 +490,7 @@ const Meeting: React.FC = () => {
title: '录制' title: '录制'
}, 1, 3) }, 1, 3)
} else { } else {
message.error('当前不在会议室!') handleMessage().error('当前不在会议室!')
} }
showSingIn() showSingIn()
}, },
@ -639,18 +640,39 @@ 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)
setIsScreenCapture(isScreenCaptureValue => {
setMeetingMode(isScreenCaptureValue ? 'SpeakerMode' : 'StandardMode')
return isScreenCaptureValue
})
} }
}, [isShare, roomUserList]); }, [isShare, roomUserList]);
useEffect(() => {
setFreedomModeStatus((res: boolean) => {
if (meetingMode === 'FreedomMode') {
return true
} else {
if (res) {
getShowUser(true)
}
return false
}
})
}, [meetingMode]);
useEffect(() => { useEffect(() => {
roomUserList.forEach(async (item: any) => { roomUserList.forEach(async (item: any) => {
if (item.uid === currentVideoId) { if (meetingMode === "FreedomMode") {
await agora.setRemoteVideoStreamType(item.uid, VideoStreamType.VideoStreamHigh, true) await agora.setRemoteVideoStreamType(item.uid, VideoStreamType.VideoStreamHigh, true)
} else { } else {
await agora.setRemoteVideoStreamType(item.uid, VideoStreamType.VideoStreamLow, true) if (item.uid === currentVideoId) {
await agora.setRemoteVideoStreamType(item.uid, VideoStreamType.VideoStreamHigh, true)
} else {
await agora.setRemoteVideoStreamType(item.uid, VideoStreamType.VideoStreamLow, true)
}
} }
}); });
}, [currentVideoId, roomUserList]); }, [currentVideoId, roomUserList, meetingMode]);
useEffect(() => { useEffect(() => {
let item = roomUserList.find((item: any) => currentVideoId == item.uid) let item = roomUserList.find((item: any) => currentVideoId == item.uid)
@ -723,32 +745,41 @@ const Meeting: React.FC = () => {
break; break;
// 扩展操作 // 扩展操作
case 'Operation': case 'Operation':
switch (item.contentString) { try {
const temp = JSON.parse(item.contentString)
if (temp.type === 'mode') {
temp.msg ? handleMessage().success(`管理员已将会议室显示模式更新为${getMeetingContentBodyLeftModeText(temp.mode)}`) : null;
setIsScreenCapture(isScreenCaptureValue => {
setMeetingMode(isScreenCaptureValue ? 'SpeakerMode' : temp.mode)
return isScreenCaptureValue
})
}
} catch (error) {
} }
break; break;
// 全员离开房间 // 全员离开房间
case 'AllLeave': case 'AllLeave':
message.success('管理员已结束会议!') handleMessage().success('管理员已结束会议!')
leaveChannel(false) leaveChannel(false)
break; break;
// 移出会议 // 移出会议
case 'ForceExitRoom': case 'ForceExitRoom':
message.success('管理员已将你移出会议!') handleMessage().success('管理员已将你移出会议!')
leaveChannel() leaveChannel()
break; break;
// 更新视图模式 // 更新视图模式
case 'RefreshView': case 'RefreshView':
setMeetingMode(item.type)
break; break;
// 全员看他 // 全员看他
case 'ShowUser': case 'ShowUser':
if (item.operUid && item.operUserName) { if (item.operUid && item.operUserName) {
if (item.operUid !== userInfo.uid) { if (item.operUid !== userInfo.uid) {
if (item.uid === userInfo.uid) { if (item.uid === userInfo.uid) {
message.success(`${item.operUserName}设置全员看你`) handleMessage().success(`${item.operUserName}设置全员看你`)
} else { } else {
message.success(`${item.operUserName}设置全员看${item.uname}`) handleMessage().success(`${item.operUserName}设置全员看${item.uname}`)
} }
} }
} }
@ -770,7 +801,7 @@ const Meeting: React.FC = () => {
case 'OperMicr': case 'OperMicr':
if (item.operUid !== userInfo.uid) { if (item.operUid !== userInfo.uid) {
if (item.user.uid === userInfo.uid) { if (item.user.uid === userInfo.uid) {
message.success(item.user.enableMicr ? '管理员已取消你的静音' : '你已被管理员静音') handleMessage().success(item.user.enableMicr ? '管理员已取消你的静音' : '你已被管理员静音')
} }
} }
setAllUserListData('OperMicr', item) setAllUserListData('OperMicr', item)
@ -779,7 +810,7 @@ const Meeting: React.FC = () => {
case 'OperCamera': case 'OperCamera':
if (item.operUid !== userInfo.uid) { if (item.operUid !== userInfo.uid) {
if (item.user.uid === userInfo.uid) { if (item.user.uid === userInfo.uid) {
message.success(item.user.enableCamera ? '管理员已开启你的摄像头' : '管理员已关闭你摄像头') handleMessage().success(item.user.enableCamera ? '管理员已开启你的摄像头' : '管理员已关闭你摄像头')
} }
} }
setAllUserListData('OperCamera', item) setAllUserListData('OperCamera', item)
@ -798,20 +829,20 @@ const Meeting: React.FC = () => {
if (item.user.uid === item.uid) { if (item.user.uid === item.uid) {
if (item.user.uid === userInfo.uid) { if (item.user.uid === userInfo.uid) {
await agora.allLeaveChannelEx() await agora.allLeaveChannelEx()
message.success(`操作成功`) handleMessage().success(`操作成功`)
await agora.updateChannelMediaOptions(item.user.isRoomManager) await agora.updateChannelMediaOptions(item.user.isRoomManager)
await postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false) await postOpenMicrApi(item.user.isRoomManager, userInfo.uid, false)
await postOpenCameraApi(false, userInfo.uid) // 不管身份如何改变都关闭摄像头 await postOpenCameraApi(false, userInfo.uid) // 不管身份如何改变都关闭摄像头
await stopScreenCapture() await stopScreenCapture()
} else { } else {
message.success(`${item.user.userName}已结束发言`) handleMessage().success(`${item.user.userName}已结束发言`)
} }
} else { } else {
if (item.user.uid === userInfo.uid) { if (item.user.uid === userInfo.uid) {
if (item.user.isRoomManager) { if (item.user.isRoomManager) {
await agora.allLeaveChannelEx() await agora.allLeaveChannelEx()
} }
message.success(`管理员${item.user.isRoomManager ? '设置' : '取消'}您为发言人`) handleMessage().success(`管理员${item.user.isRoomManager ? '设置' : '取消'}您为发言人`)
await agora.updateChannelMediaOptions(item.user.isRoomManager) await agora.updateChannelMediaOptions(item.user.isRoomManager)
setCurrentRequestSpeakType(res => { setCurrentRequestSpeakType(res => {
if (res === 'video') { if (res === 'video') {
@ -826,7 +857,7 @@ const Meeting: React.FC = () => {
}) })
await stopScreenCapture() await stopScreenCapture()
} else { } else {
message.success(`管理员${item.user.isRoomManager ? '设置' : '取消'}${item.user.userName}为发言人`) handleMessage().success(`管理员${item.user.isRoomManager ? '设置' : '取消'}${item.user.userName}为发言人`)
} }
} }
}) })
@ -990,7 +1021,7 @@ const Meeting: React.FC = () => {
uid: temp.uid, uid: temp.uid,
enableMicr: temp.enableMicr enableMicr: temp.enableMicr
}) })
} else { } else if (temp.type === 'video') {
await PostOpenCamera({ await PostOpenCamera({
roomNum: temp.roomNum, roomNum: temp.roomNum,
uid: temp.uid, uid: temp.uid,
@ -1016,7 +1047,7 @@ const Meeting: React.FC = () => {
if (recorder) { if (recorder) {
recorder.start() recorder.start()
recorder.onstart = async () => { recorder.onstart = async () => {
message.success('开始录制') handleMessage().success('开始录制')
} }
recorder.onerror = async () => { recorder.onerror = async () => {
setRecorder('') setRecorder('')
@ -1025,7 +1056,7 @@ const Meeting: React.FC = () => {
changeStatusList({ changeStatusList({
title: '录制中' title: '录制中'
}, 1, 3) }, 1, 3)
message.error('录制失败,请重新录制!') handleMessage().error('录制失败,请重新录制!')
} }
recorder.onstop = async () => { recorder.onstop = async () => {
@ -1140,13 +1171,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]);
@ -1189,7 +1214,7 @@ const Meeting: React.FC = () => {
// GetApplySpeak(state.channelId).then(res => { // GetApplySpeak(state.channelId).then(res => {
// if (res.code === 200) { // if (res.code === 200) {
// setIsClicked(true); // setIsClicked(true);
// message.success('申请发言成功') // handleMessage().success('申请发言成功')
// } // }
// }) // })
// }, // },
@ -1233,7 +1258,7 @@ const Meeting: React.FC = () => {
} else { } else {
item.status-- item.status--
if (item.status <= 0) { if (item.status <= 0) {
message.error(`设置${user.userName}发言人失败!`) handleMessage().error(`设置${user.userName}发言人失败!`)
newApplyUserList.splice(index, 1) newApplyUserList.splice(index, 1)
} }
} }
@ -1265,18 +1290,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 => {
@ -1466,7 +1484,7 @@ const Meeting: React.FC = () => {
return bool return bool
}) })
} else if (reason === 3 || reason === 4) { } else if (reason === 3 || reason === 4) {
message.error({ handleMessage().error({
content: <div><span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => { content: <div><span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
stupWizardRef.current.changeModal(1); stupWizardRef.current.changeModal(1);
}}></span></div>, }}></span></div>,
@ -1480,7 +1498,7 @@ const Meeting: React.FC = () => {
uid: userInfo.uid, uid: userInfo.uid,
enableCamera: false enableCamera: false
}) })
message.error({ handleMessage().error({
content: <div><span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => { content: <div><span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
stupWizardRef.current.changeModal(1); stupWizardRef.current.changeModal(1);
}}></span></div>, }}></span></div>,
@ -1581,7 +1599,14 @@ const Meeting: React.FC = () => {
item.isShow = true; item.isShow = true;
} }
}); });
setIsAdmin(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)
if (peoPleLength > 6) {
setIsScreenCapture(isScreenCaptureValue => {
setMeetingMode(isScreenCaptureValue ? 'SpeakerMode' : 'StandardMode')
return isScreenCaptureValue
})
}
return res return res
}) })
} }
@ -1713,16 +1738,18 @@ const Meeting: React.FC = () => {
}) })
} }
// 渲染视频 // 渲染视频
const renderVideo = async (uid: string = ''): Promise<void> => { const renderVideo = async (uid: string = '', bool: boolean = false): Promise<void> => {
if (isClickLock) { if (!bool) {
return if (isClickLock) {
}
if (uid) {
if (currentVideoId === uid || currentVideoUid === uid) {
return return
} }
} else { if (uid) {
uid = userInfo.uid if (currentVideoId === uid || currentVideoUid === uid) {
return
}
} else {
uid = userInfo.uid
}
} }
await agora.destroyRendererByView(`video-source-camera-primary`) await agora.destroyRendererByView(`video-source-camera-primary`)
await agora.destroyRendererByView(`video-source-screen`) await agora.destroyRendererByView(`video-source-screen`)
@ -1760,11 +1787,11 @@ const Meeting: React.FC = () => {
}, 500); }, 500);
} }
// 全员观看 // 全员观看
const getShowUser = async (): Promise<void> => { const getShowUser = async (bool: boolean = false): Promise<void> => {
if (location.href.indexOf('/meeting') !== -1) { if (location.href.indexOf('/meeting') !== -1) {
await GetShowUser(state.channelId).then(async (res) => { await GetShowUser(state.channelId).then(async (res) => {
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
renderVideo(res.data) renderVideo(res.data, bool)
} }
}) })
} }
@ -1814,7 +1841,7 @@ const Meeting: React.FC = () => {
GetApplySpeak(state.channelId).then(res => { GetApplySpeak(state.channelId).then(res => {
if (res.code === 200) { if (res.code === 200) {
setIsClicked(true); setIsClicked(true);
message.success('申请发言成功') handleMessage().success('申请发言成功')
} }
}) })
}, },
@ -1858,7 +1885,7 @@ const Meeting: React.FC = () => {
} }
}) })
} else { } else {
message.error(msgTips) handleMessage().error(msgTips)
} }
}) })
break; break;
@ -1868,7 +1895,7 @@ const Meeting: React.FC = () => {
if (res) { if (res) {
await stopScreenCapture() await stopScreenCapture()
} else { } else {
message.error(msgTips) handleMessage().error(msgTips)
} }
}) })
if (row.title === '停止共享') { if (row.title === '停止共享') {
@ -1887,7 +1914,7 @@ const Meeting: React.FC = () => {
setCurrentRequestSpeakType('audio') setCurrentRequestSpeakType('audio')
requestSpeak() requestSpeak()
} else { } else {
message.error('申请太频繁了,请稍后重试!'); handleMessage().error('申请太频繁了,请稍后重试!');
} }
} }
}) })
@ -1904,7 +1931,7 @@ const Meeting: React.FC = () => {
setCurrentRequestSpeakType('video') setCurrentRequestSpeakType('video')
requestSpeak() requestSpeak()
} else { } else {
message.error('申请太频繁了,请稍后重试!'); handleMessage().error('申请太频繁了,请稍后重试!');
} }
} }
}) })
@ -1919,7 +1946,7 @@ const Meeting: React.FC = () => {
if (res) { if (res) {
invitingPersonnelRef.current.changeInvitingPersonnelModal() invitingPersonnelRef.current.changeInvitingPersonnelModal()
} else { } else {
message.error(msgTips) handleMessage().error(msgTips)
} }
}) })
break; break;
@ -1975,25 +2002,25 @@ const Meeting: React.FC = () => {
setRecorder(mediaRecorder); setRecorder(mediaRecorder);
}); });
} else { } else {
message.error('录制太频繁了,请稍后重试!'); handleMessage().error('录制太频繁了,请稍后重试!');
} }
} catch (error: any) { } catch (error: any) {
if (error.code === 'ENOENT') { if (error.code === 'ENOENT') {
message.error({ handleMessage().error({
content: <div> <span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => { content: <div> <span style={{ color: '#606fc7', cursor: 'pointer' }} onClick={() => {
stupWizardRef.current.changeModal(3); stupWizardRef.current.changeModal(3);
}}></span></div> }}></span></div>
}); });
return; return;
} else { } else {
message.error(error); handleMessage().error(error);
} }
} }
break; break;
case '录制中': case '录制中':
if (isClickedMediaSteam) { if (isClickedMediaSteam) {
message.error('录制时长不足3秒请稍后重试'); handleMessage().error('录制时长不足3秒请稍后重试');
} else { } else {
footerListTemplate[itemIndex][rowIndex].title = '录制' footerListTemplate[itemIndex][rowIndex].title = '录制'
footerListTemplate[itemIndex][rowIndex].active = false footerListTemplate[itemIndex][rowIndex].active = false
@ -2008,7 +2035,7 @@ const Meeting: React.FC = () => {
if (!isClicked) { if (!isClicked) {
requestSpeak() requestSpeak()
} else { } else {
message.error('申请太频繁了,请稍后重试!'); handleMessage().error('申请太频繁了,请稍后重试!');
} }
break; break;
case '会议监控': case '会议监控':
@ -2114,7 +2141,7 @@ const Meeting: React.FC = () => {
setKeyOpenChildWindow('shareScreenWindow', true) setKeyOpenChildWindow('shareScreenWindow', true)
window.electron.setMainWindowSize({ window.electron.setMainWindowSize({
width: 250, width: 250,
height: 160, height: 230,
}) })
window.electron.setPosition('right') window.electron.setPosition('right')
} }
@ -2144,12 +2171,20 @@ const Meeting: React.FC = () => {
await PostStopSharedScreen(state.channelId) await PostStopSharedScreen(state.channelId)
} else { } else {
await PostShowUser(state.channelId, uid, name) await PostShowUser(state.channelId, uid, name)
await window.electron.onInvoke('sendOper', {
roomNum: state.channelId,
contentString: JSON.stringify({
mode: 'StandardMode',
type: 'mode',
msg: false
})
})
} }
} }
// 设置发言人 // 设置发言人
const postRoomManager = async (data: any): Promise<void> => { const postRoomManager = async (data: any): Promise<void> => {
if (isAdmin >= 20) { if (isAdmin >= 20) {
message.error('设置失败已达最大发言人20个') handleMessage().error('设置失败已达最大发言人20个')
} else { } else {
await PostRoomManager({ await PostRoomManager({
roomId: data.roomId, roomId: data.roomId,
@ -2167,7 +2202,7 @@ const Meeting: React.FC = () => {
} }
// 停止共享 // 停止共享
const stopScreenCapture = async (): Promise<void> => { const stopScreenCapture = async (): Promise<void> => {
await agora.destroyRendererByView(`meetingAbsoluteVideo`) setMeetingMode('StandardMode')
const footerListTemplate = [...footerList] const footerListTemplate = [...footerList]
await agora.leaveChannelEx(userInfo.screenShareId) await agora.leaveChannelEx(userInfo.screenShareId)
agora.stopScreenCapture() agora.stopScreenCapture()
@ -2236,7 +2271,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) {
@ -2245,7 +2283,7 @@ const Meeting: React.FC = () => {
break; break;
case 'reconnect': case 'reconnect':
if (e.value == true) { if (e.value == true) {
message.success('网络已连接。') handleMessage().success('网络已连接。')
meetingDisconnectedRef.current.changeModal(false) meetingDisconnectedRef.current.changeModal(false)
setIsAgoraDisconnected(false) setIsAgoraDisconnected(false)
async function setUserStatus(res: any) { async function setUserStatus(res: any) {
@ -2311,7 +2349,7 @@ const Meeting: React.FC = () => {
return res return res
}) })
} else { } else {
message.error('请输入内容!') handleMessage().error('请输入内容!')
} }
} }
// 聊天框滚动到底部 // 聊天框滚动到底部
@ -2341,19 +2379,20 @@ const Meeting: React.FC = () => {
}) })
} }
if (msg) { if (msg) {
message.error(msg) handleMessage().error(msg)
return return
} }
} }
if (enableMicr) { if (enableMicr) {
const enableMicrLenght = roomUserList.filter((item: any) => item.enableMicr).length const enableMicrLenght = roomUserList.filter((item: any) => item.enableMicr).length
if (enableMicrLenght >= 20) { if (enableMicrLenght >= 20) {
return message.error('房间内最多20个开启麦克风') handleMessage().error('房间内最多20个开启麦克风')
return
} }
} }
await postOpenMicrApi(enableMicr, uid, isAll, true) await postOpenMicrApi(enableMicr, uid, isAll, true)
} else { } else {
message.error(msgTips) handleMessage().error(msgTips)
} }
}) })
} }
@ -2381,7 +2420,7 @@ const Meeting: React.FC = () => {
// }) // })
} }
if (isMessage) { if (isMessage) {
// message.success('操作成功') // handleMessage().success('操作成功')
} }
} }
// 开关视频 // 开关视频
@ -2397,18 +2436,19 @@ const Meeting: React.FC = () => {
}) })
} }
if (msg) { if (msg) {
message.error(msg) handleMessage().error(msg)
return return
} }
if (enableCamera) { if (enableCamera) {
const enableCameraLenght = roomUserList.filter((item: any) => item.enableCamera).length const enableCameraLenght = roomUserList.filter((item: any) => item.enableCamera).length
if (enableCameraLenght >= 20) { if (enableCameraLenght >= 20) {
return message.error('房间内最多20个开启摄像头') handleMessage().error('房间内最多20个开启摄像头')
return
} }
} }
await postOpenCameraApi(enableCamera, uid, true) await postOpenCameraApi(enableCamera, uid, true)
} else { } else {
message.error(msgTips) handleMessage().error(msgTips)
} }
}) })
} }
@ -2434,7 +2474,7 @@ const Meeting: React.FC = () => {
// enableCamera // enableCamera
// }) // })
if (isMessage) { if (isMessage) {
// message.success('操作成功') // handleMessage().success('操作成功')
} }
} }
// 演讲者模式 // 演讲者模式
@ -2456,14 +2496,41 @@ const Meeting: React.FC = () => {
}) })
} }
// 获取当前模式样式 // 获取当前模式样式
const getMeetingContentBodyLeftModeClass = (): string => { const getMeetingContentBodyLeftModeClass = (people: Number): string => {
switch (meetingMode) { switch (meetingMode) {
case 'FreedomMode': case 'FreedomMode':
return styles.meetingContentBodyLeftFreedomMode switch (people) {
case 1:
return styles.meetingContentBodyLeftFreedomModeOne;
case 2:
return styles.meetingContentBodyLeftFreedomModeTwo;
case 3:
case 4:
return styles.meetingContentBodyLeftFreedomModeThree;
case 5:
case 6:
return styles.meetingContentBodyLeftFreedomModeFour;
case 7:
return styles.meetingContentBodyLeftFreedomModeFive;
case 8:
case 9:
return styles.meetingContentBodyLeftFreedomModeSix;
case 10:
case 11:
case 12:
return styles.meetingContentBodyLeftFreedomModeSeven;
case 13:
case 14:
case 15:
case 16:
return styles.meetingContentBodyLeftFreedomModeEight;
default:
return styles.meetingContentBodyLeftFreedomModeNine;
}
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':
@ -2474,10 +2541,10 @@ const Meeting: React.FC = () => {
return '' return ''
} }
// 获取当前模式文字 // 获取当前模式文字
const getMeetingContentBodyLeftModeText = (): string => { const getMeetingContentBodyLeftModeText = (mode?: string): string => {
switch (meetingMode) { switch (mode || meetingMode) {
case 'FreedomMode': case 'FreedomMode':
return '自由者模式' return '宫格模式'
case 'StandardMode': case 'StandardMode':
return '标准模式' return '标准模式'
case 'SpeakerMode': case 'SpeakerMode':
@ -2573,7 +2640,35 @@ const Meeting: React.FC = () => {
} else { } else {
await allUserLook(item.uid, item.userName) await allUserLook(item.uid, item.userName)
} }
message.success('操作成功') handleMessage().success('操作成功')
}
// 设置模式
const setSyncView = (mode: string) => {
if (meetingMode === mode) {
setModeOpen(false)
handleMessage().error(`${getMeetingContentBodyLeftModeText(mode)}已开启,请勿重复操作!`)
return
}
if (isAdmin > 6 && mode === 'FreedomMode') {
setModeOpen(false)
handleMessage().error('发言人数超过6人,无法使用宫格模式!')
return
}
if (isShare && mode === 'FreedomMode') {
setModeOpen(false)
handleMessage().error('共享中,无法切换模式')
return
}
window.electron.onInvoke('sendOper', {
roomNum: state.channelId,
contentString: JSON.stringify({
mode,
type: 'mode',
msg: true,
})
})
setModeOpen(false)
storage.setItem('meetingMode', mode)
} }
// 判断是否出现滚动条 // 判断是否出现滚动条
const hasScrollbar = () => { const hasScrollbar = () => {
@ -2594,30 +2689,64 @@ const Meeting: React.FC = () => {
cancelText: '取消', cancelText: '取消',
async onOk() { async onOk() {
await GetRoomKickout(channelId, uid) await GetRoomKickout(channelId, uid)
message.success('操作成功') handleMessage().success('操作成功')
}, },
onCancel() { onCancel() {
}, },
}); });
} }
const handleMessage = () => {
const displayMessage = (
fn: (msg: any) => void,
msg: any
) => {
setIsScreenCapture(bool => {
if (!bool) {
fn(msg);
}
return bool;
});
};
return {
error: (msg: any) => displayMessage(message.error, msg),
success: (msg: any) => displayMessage(message.success, msg)
};
};
return ( return (
<> <>
<div className={styles.meeting} onClick={() => { <div className={styles.meeting} onClick={() => {
setContextMenu('') setContextMenu('')
if (modeOpen) {
setModeOpen(false)
}
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.meetingAbsoluteHeader}`}>
{footerList[0][1].active ? <div className={styles.meetingAbsoluteLoading}> <div>
<Avatar name={user.userName} /> <span className='drag' onClick={() => {
</div> : null} setIsExpand(!isExpand)
<div style={{ bottom: '0px' }} className={`${styles.meetingAbsoluteText} drag`} onClick={() => { window.electron.setChildWindow({
height: !isExpand ? 160 * 4 + 20 : 230,
width: 250,
key: 'main'
})
}}>
<img src={isExpand ? ImageUrl.icon61 : ImageUrl.icon61Active} alt="" />
<img src={!isExpand ? ImageUrl.icon60 : ImageUrl.icon60Active} alt="" style={{ marginLeft: '10px' }} />
</span>
</div>
<span>{currentSpeakUser.length ? '正在说话:' + currentSpeakUser.join(';') : '正在说话:'}</span>
</div>
<div style={{ bottom: '0px', borderRadius: '0 0 10px 10px' }} className={`${styles.meetingAbsoluteText}`} onClick={() => {
setIsExpand(!isExpand) setIsExpand(!isExpand)
window.electron.setChildWindow({ window.electron.setChildWindow({
height: isExpand ? 160 : 40, height: !isExpand ? 160 * 4 + 20 : 230,
width: 250,
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={
{ {
@ -2716,9 +2845,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)}>
@ -2766,35 +2895,40 @@ 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}
<span className='drag' style={{ marginTop: '2px', marginLeft: '4px' }}><Code roomNum={state.channelId}></Code></span> <span className='drag' style={{ marginTop: '2px', marginLeft: '4px' }}><Code roomNum={state.channelId}></Code></span>
</div> </div>
<div className='drag'> <div className='drag'>
<Popover {role.ID.includes(userInfo.roleId) ? <Popover
content={ content={
<div className='modePopover'> <div className='modePopover'>
<div onClick={() => { <div>
setModeOpen(false) <div className={meetingMode === 'FreedomMode' ? 'active' : ''} onClick={() => {
storage.setItem('meetingMode', 'StandardMode') setSyncView('FreedomMode')
}}> }}>
<img src={ImageUrl.icon43} alt="" /> <img src={ImageUrl.icon57} alt="" />
<span></span> <span></span>
</div> </div>
<div onClick={() => { <div className={meetingMode === 'StandardMode' ? 'active' : ''} onClick={() => {
setModeOpen(false) setSyncView('StandardMode')
storage.setItem('meetingMode', 'SpeakerMode') }}>
}}> <img src={ImageUrl.icon43} alt="" />
<img src={ImageUrl.icon44} alt="" /> <span></span>
<span></span> </div>
</div> <div className={meetingMode === 'SpeakerMode' ? 'active' : ''} onClick={() => {
<div onClick={() => { setSyncView('SpeakerMode')
setModeOpen(false) }}>
}}> <img src={ImageUrl.icon44} alt="" />
<span></span> <span></span>
</div>
</div> </div>
<span>
<ExclamationCircleFilled />
<span></span>
</span>
</div> </div>
} }
title="" title=""
@ -2803,24 +2937,35 @@ const Meeting: React.FC = () => {
onOpenChange={() => setModeOpen(true)} onOpenChange={() => setModeOpen(true)}
> >
<div className={styles.meetingGrayButton}> <div className={styles.meetingGrayButton}>
{meetingMode === 'StandardMode' ? <img src={ImageUrl.icon43} alt="" /> : <img src={ImageUrl.icon44} alt="" />} {meetingMode === 'StandardMode' ?
<img src={ImageUrl.icon43} alt="" /> :
meetingMode === 'FreedomMode' ?
<img src={ImageUrl.icon57} alt="" /> :
<img src={ImageUrl.icon44} alt="" />}
<span>{getMeetingContentBodyLeftModeText()}</span> <span>{getMeetingContentBodyLeftModeText()}</span>
</div> </div>
</Popover> </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`} style={{
{isAdmin && currentLookUserAccount ? getSettingIcon() : null} marginTop: isScreenCapture ? '46px' : '0',
<div className={getMeetingContentBodyLeftModeClass()} id='videoView' style={meetingMode === 'SpeakerMode' && isVideoFullScreen ? { width: '0' } : {}}> paddingBottom: isScreenCapture ? '66px' : '0'
}} onMouseEnter={() => setShowCaret(true)}
onMouseLeave={() => setShowCaret(false)}>
{isAdmin && currentLookUserAccount && !isScreenCapture ? getSettingIcon() : null}
<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} id={item.uid}
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 {
@ -2828,6 +2973,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,
@ -2842,12 +2990,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"
@ -2939,7 +3087,13 @@ const Meeting: React.FC = () => {
</div> : null) </div> : null)
} }
)} )}
{hasScrollbar() ? <div> {/* <div className={`${styles.meetingContentSwiperCard}`}>
<div className={`${styles.meetingContentSwiperCardVdeio}`}>
<div className={styles.meetingContentSwiperCardVdeioLoading}>
</div>
</div>
</div> */}
{meetingMode !== "FreedomMode" && hasScrollbar() && showCaret ? <div>
{meetingMode === "StandardMode" ? <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: '20px', top: '66px' }} onClick={() => { {meetingMode === "StandardMode" ? <div className={`${styles.meetingContentSwiperCaret}`} style={{ left: '20px', top: '66px' }} onClick={() => {
const container = document.getElementById('videoView') as HTMLElement; const container = document.getElementById('videoView') as HTMLElement;
container.scrollLeft -= 100 container.scrollLeft -= 100
@ -2956,15 +3110,15 @@ 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: '115px', bottom: isScreenCapture ? '70px' : '20px' }} onClick={() => {
const container = document.getElementById('videoView') as HTMLElement; const container = document.getElementById('videoView') as HTMLElement;
container.scrollTop += 100 container.scrollTop += 100
}}> }}>
<CaretDownOutlined /> <CaretDownOutlined />
</div>} </div>}
</div> : null} </div> : null}
{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' }} />
@ -2974,8 +3128,8 @@ const Meeting: React.FC = () => {
<FullscreenOutlined className={styles.meetingContentSwiperCardFullScreenIcon} title='全屏' onClick={() => setIsVideoFullScreen(true)} />} <FullscreenOutlined className={styles.meetingContentSwiperCardFullScreenIcon} title='全屏' onClick={() => setIsVideoFullScreen(true)} />}
{meetingContentUser(currentLookUserAccount, true)} {meetingContentUser(currentLookUserAccount, true)}
</div> : null} </div> : null}
{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} />
@ -2986,8 +3140,8 @@ const Meeting: React.FC = () => {
{meetingContentUser(currentLookUserAccount, true)} {meetingContentUser(currentLookUserAccount, true)}
{currentLookUserAccount.enableCamera ? null : meetingContentError(currentLookUserAccount)} {currentLookUserAccount.enableCamera ? null : meetingContentError(currentLookUserAccount)}
</div> : null} </div> : null}
{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} />
@ -2997,8 +3151,8 @@ const Meeting: React.FC = () => {
<FullscreenOutlined className={styles.meetingContentSwiperCardFullScreenIcon} title='全屏' onClick={() => setIsVideoFullScreen(true)} />} <FullscreenOutlined className={styles.meetingContentSwiperCardFullScreenIcon} title='全屏' onClick={() => setIsVideoFullScreen(true)} />}
{meetingContentUser(currentLookUserAccount, true)} {meetingContentUser(currentLookUserAccount, true)}
</div> : null} </div> : null}
{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} />
@ -3008,8 +3162,8 @@ const Meeting: React.FC = () => {
<FullscreenOutlined className={styles.meetingContentSwiperCardFullScreenIcon} title='全屏' onClick={() => setIsVideoFullScreen(true)} />} <FullscreenOutlined className={styles.meetingContentSwiperCardFullScreenIcon} title='全屏' onClick={() => setIsVideoFullScreen(true)} />}
{meetingContentUser(currentLookUserAccount, true)} {meetingContentUser(currentLookUserAccount, true)}
</div> : null} </div> : null}
{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} />
@ -3026,7 +3180,7 @@ const Meeting: React.FC = () => {
</div> </div>
</div> </div>
{ {
(statusList.userList || statusList.userChatList || statusList.userVideo) ? ( (statusList.userList || statusList.userChatList || statusList.userVideo) && !isScreenCapture ? (
<div className={`${styles.meetingContentBodyRight} drag`}> <div className={`${styles.meetingContentBodyRight} drag`}>
{statusList.userList ? {statusList.userList ?
<div className={styles.meetingUserList}> <div className={styles.meetingUserList}>
@ -3070,10 +3224,10 @@ const Meeting: React.FC = () => {
<div> <div>
<div><Avatar name={item.userName} /></div> <div><Avatar name={item.userName} /></div>
<span> <span>
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: role.ID.includes(item.roleId) || item.isRoomManager ? '50px' : '80px' }} title={item.userName}>{item.userName}</span>{item.uid === user.uid ? '(我)' : ''} <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: role.ID.includes(item.roleId) || item.isRoomManager ? '200px' : '200px' }} title={item.userName}>{item.userName}</span>
{role.ID.includes(item.roleId) || item.isRoomManager ? {role.ID.includes(item.roleId) || item.isRoomManager ?
<span style={{ color: '#02B188', marginLeft: '4px' }}> <span>
{role.ID.includes(item.roleId) ? '管理员' : '发言人'} {role.ID.includes(item.roleId) ? item.uid === user.uid ? '(管理员,我)' : '(管理员)' : item.uid === user.uid ? '(发言人,我)' : '(发言人)'}
</span> </span>
: null} : null}
</span> </span>
@ -3673,7 +3827,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}>
@ -3690,7 +3844,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>

View File

@ -86,6 +86,15 @@ import icon54 from '@/assets/icon54.png'
import icon55 from '@/assets/icon55.png' import icon55 from '@/assets/icon55.png'
import icon56 from '@/assets/icon56.png' import icon56 from '@/assets/icon56.png'
import icon56Active from '@/assets/icon56-active.png' import icon56Active from '@/assets/icon56-active.png'
import icon57 from '@/assets/icon57.png'
import icon58 from '@/assets/icon58.png'
import icon59 from '@/assets/icon59.png'
import icon60 from '@/assets/icon60.png'
import icon61 from '@/assets/icon61.png'
import icon60Active from '@/assets/icon60-active.png'
import icon61Active from '@/assets/icon61-active.png'
import icon62 from '@/assets/icon62.png'
import icon63 from '@/assets/icon63.png'
export default { export default {
loading, loading,
icon, icon,
@ -174,5 +183,14 @@ export default {
icon54, icon54,
icon55, icon55,
icon56, icon56,
icon56Active icon56Active,
icon57,
icon58,
icon59,
icon60,
icon61,
icon60Active,
icon61Active,
icon62,
icon63,
} }

View File

@ -62,6 +62,10 @@ export const getUpdateUrl = (env: string) => {
switch (env) { switch (env) {
case 'xy': case 'xy':
return 'https://meeting-api.23544.com/meeting/xysz' return 'https://meeting-api.23544.com/meeting/xysz'
case 'xatyz':
return 'https://meeting-api.23544.com/meeting/xatyz'
case 'my':
return 'https://meeting-api.23544.com/meeting/my'
case 'development': case 'development':
return 'http://192.168.2.9:8827' return 'http://192.168.2.9:8827'
default: default:
@ -75,6 +79,12 @@ export const getTitle = async () => {
case 'xy': case 'xy':
str = '湖北襄阳四中教研平台' str = '湖北襄阳四中教研平台'
break; break;
case 'xatyz':
str = '西安铁一中教研平台'
break;
case 'my':
str = '绵阳中学人工智能教育发展共同体 · 教研平台'
break;
case 'development': case 'development':
str = '智汇享' str = '智汇享'
break; break;

View File

@ -3,6 +3,10 @@ module.exports = {
switch (env) { switch (env) {
case 'xy': case 'xy':
return 'https://meeting-api.23544.com/meeting/xysz' return 'https://meeting-api.23544.com/meeting/xysz'
case 'xatyz':
return 'https://meeting-api.23544.com/meeting/xatyz'
case 'my':
return 'https://meeting-api.23544.com/meeting/my'
case 'development': case 'development':
return 'http://192.168.2.9:8827' return 'http://192.168.2.9:8827'
default: default:
@ -13,6 +17,10 @@ module.exports = {
switch (env) { switch (env) {
case 'xy': case 'xy':
return '湖北襄阳四中教研平台' return '湖北襄阳四中教研平台'
case 'xatyz':
return '西安铁一中教研平台'
case 'my':
return '绵阳中学人工智能教育发展共同体 · 教研平台'
case 'development': case 'development':
return '智汇享' return '智汇享'
default: default:
@ -23,6 +31,10 @@ module.exports = {
switch (env) { switch (env) {
case 'xy': case 'xy':
return 'icon54' return 'icon54'
case 'xatyz':
return 'icon59'
case 'my':
return 'icon62'
case 'development': case 'development':
return 'icon' return 'icon'
default: default:

View File

@ -3,6 +3,7 @@ import react from '@vitejs/plugin-react'
import pxtovw from 'postcss-px-to-viewport-8-plugin' import pxtovw from 'postcss-px-to-viewport-8-plugin'
import { resolve as resolvePath } from 'path' import { resolve as resolvePath } from 'path'
import resolve from 'vite-plugin-resolve'; import resolve from 'vite-plugin-resolve';
import { createHtmlPlugin } from 'vite-plugin-html';
const loder_pxtovw = pxtovw({ const loder_pxtovw = pxtovw({
viewportWidth: 1900, viewportWidth: 1900,
viewportUnit: 'vw', viewportUnit: 'vw',
@ -51,6 +52,20 @@ export default defineConfig({
base: './', // 这里更改打包相对绝对路径 base: './', // 这里更改打包相对绝对路径
plugins: [ plugins: [
react(), react(),
createHtmlPlugin({
minify: false,
pages: [
{
template: 'index.html',
filename: 'index.html',
injectOptions: {
data: {
buildTime: +new Date()
}
}
}
]
}),
resolve({ resolve({
'agora-electron-sdk': ` 'agora-electron-sdk': `
const { const {