Files
meeting-client/src/views/meeting.vue
2022-06-07 17:36:04 +08:00

1189 lines
36 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div id="app-container" ref="appContainerRef">
<!-- zoom 会议组件 -->
<div id="meeting-chat-row">
<div class="fullscreen-wrap" ref="fullscreenWrapRef">
<div
id="meeting-container"
ref="meetingContainerRef"
:class="{
fullscreen: isFullScreen && !isVerticalFullScreen,
verticalFullScreen: isVerticalFullScreen,
}"
>
<div
id="video-element"
:class="`layout-template-${templateId}`"
ref="videoElementRef"
></div>
<el-button
v-if="!isFullScreen"
:icon="FullScreen"
circle
@click="setFullScreen"
></el-button>
<el-button
v-else
:icon="CloseBold"
circle
@click="quitFullScreen"
></el-button>
</div>
</div>
<div id="right-chat">
<Chat
:is-rich="route.name === 'Host'"
place="right"
:account="joinName"
:message-list="messages"
@send="sendMessage"
/>
</div>
</div>
<el-tabs class="tabs" type="border-card">
<el-tab-pane label="会议介绍">
<div class="meeting-info meeting-note" v-html="meetingNote"></div>
</el-tab-pane>
<el-tab-pane label="会议日程"
><div
class="meeting-info meeting-schedule"
v-html="meetingSchedule"
></div
></el-tab-pane>
<el-tab-pane label="专家介绍"
><div class="meeting-info expert-info" v-html="expertInfo"></div
></el-tab-pane>
<el-tab-pane label="聊天" class="chat-pane" v-if="screenWidth < 900">
<Chat
:is-rich="route.name === 'Host'"
place="bottom"
:account="joinName"
:message-list="messages"
@send="sendMessage"
/>
</el-tab-pane>
</el-tabs>
<el-dialog
v-model="showSignDialog"
:close-on-click-modal="false"
title="签到"
width="30%"
>
<span>是否确认签到</span>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="submitSign">确定</el-button>
<el-button type="primary" @click="showSignDialog = false"
>取消</el-button
>
</span>
</template>
</el-dialog>
<el-dialog
custom-class="check-media"
destroy-on-close
v-model="showCheckMediaVideo"
:close-on-click-modal="false"
title="摄像头和麦克风"
:fullscreen="screenWidth < 900"
width="60%"
>
<el-alert
v-if="isVideoAvailable === undefined || isAudioAvailable === undefined"
>检测中。</el-alert
>
<el-alert
v-else-if="isVideoAvailable === true && isAudioAvailable === true"
type="success"
>摄像头工作正常,麦克风工作正常。</el-alert
>
<el-alert
v-else-if="isVideoAvailable === true && isAudioAvailable === false"
type="warning"
>摄像头工作正常,麦克风无法正常工作。</el-alert
>
<el-alert
v-else-if="isVideoAvailable === false && isAudioAvailable === true"
type="warning"
>摄像头无法正常工作,麦克风工作正常。</el-alert
>
<el-alert v-else type="error"
>摄像头无法正常工作,麦克风无法正常工作。</el-alert
>
<!-- <div id="row"> -->
<div id="check-media-wrap" ref="checkMediaWrapRef">
<video id="check-media-video" ref="checkMediaVideoRef"></video>
<!-- <el-icon class="microphone-icon" :size="50"> -->
<Microphone
v-if="isAudioAvailable === undefined"
class="microphone-loading"
/>
<Microphone
v-else-if="isAudioAvailable === true"
class="microphone-on"
/>
<Mute v-else class="microphone-off" />
<!-- </el-icon> -->
</div>
<!-- </div> -->
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="showCheckMediaVideo = false"
>关闭</el-button
>
</span>
</template>
</el-dialog>
<questions
mode="1"
@stage="getStageExamAnswer"
v-if="showExamDialog && route.name !== 'Host'"
:showDialog="showExamDialog"
@close="showExamDialog = $event"
></questions>
<questions
mode="2"
@state="getStageQuestionnaireAnswer"
v-if="showQuestionnaireDialog && route.name !== 'Host'"
:showDialog="showQuestionnaireDialog"
@close="showQuestionnaireDialog = $event"
></questions>
<el-dialog v-model="showHorizontalScreen" fullscreen :show-close="false">
<el-result icon="warning" title="无法全屏" sub-title="请先将手机横过来">
<template #icon>
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-hengping"></use>
</svg>
</template>
</el-result>
</el-dialog>
</div>
</template>
<script setup>
import {
computed,
nextTick,
onMounted,
onUnmounted,
reactive,
ref,
watch,
} from "vue";
import { useStore } from "vuex";
import { useRoute } from "vue-router";
import dayjs from "dayjs";
import { uniqueId } from "lodash";
import ZoomMtgEmbedded from "@zoomus/websdk/embedded";
import ReconnectingWebSocket from "reconnecting-websocket";
import { ElMessage, ElMessageBox } from "element-plus";
import {
FullScreen,
CloseBold,
Microphone,
Mute,
} from "@element-plus/icons-vue";
import { signMeeting, generateSignature } from "@/api/meeting";
import Chat from "@/components/chat";
import questions from "@/components/questions";
import {
getQuestionsList,
commitQuestionnaire,
commitExam,
} from "@/api/meeting";
const store = useStore();
const route = useRoute();
const meetingNote = computed(() => store.getters.meetingNote); // 会议介绍
const meetingSchedule = computed(() => store.getters.meetingSchedule); // 会议日程
const expertInfo = computed(() => store.getters.expertInfo); // 专家信息
const screenWidth = ref(0);
screenWidth.value = window.screen.width;
const joinName = ref(""); // 显示昵称
const joinAccount = ref(""); // 用于连接 websocket提交考试
joinAccount.value =
store.getters.icCard || store.getters.phone || store.getters.nickname;
joinName.value =
store.getters.nickname || store.getters.phone || store.getters.icCard;
const meetingContainerRef = ref(null); // 会议组件容器,包含背景和会议组件
const videoElementRef = ref(null); // zoom会议组件
const meetingWidth = ref(0); // 视频和共享屏幕宽度
const meetingHeight = ref(0); // 视频和共享屏幕高度
const isMeetingLoading = ref(false);
const templateId = ref(0);
templateId.value = store.getters.templateId;
/* 会议配置 */
const meetingConfig = reactive({
client: ZoomMtgEmbedded.createClient(),
sdkKey: "99Spa64AWHYVZD95imUpVyMD0KF9CpEIrIb1",
meetingNumber: store.getters.meetingNumber,
passWord: store.state.password,
role: route.name === "Host" ? 1 : 0,
userEmail: store.getters.email,
userName: joinName.value,
registrantToken: route.name === "Host" ? "" : store.getters.token,
});
// 开始会议
const isJoinFirstTime = ref(true);
const startMeeting = async () => {
const { sign } = await generateSignature({
meetingNumber: store.getters.meetingNumber,
role: meetingConfig.role,
});
let meetingSDKElement = document.getElementById("video-element");
try {
await meetingConfig.client.init({
// debug: true,
zoomAppRoot: meetingSDKElement,
language: "zh-CN",
customize: {
video: {
isResizable: false,
popper: {
disableDraggable: true,
},
viewSizes: {
default: {
width: meetingWidth.value,
height: meetingHeight.value, // 不包括顶部toolbar和底部按钮高度
},
},
},
// meetingInfo: [
// "topic",
// "host",
// "mn",
// "pwd",
// "telPwd",
// "invite",
// "participant",
// "dc",
// "enctype",
// ],
},
});
console.log(meetingWidth.value, meetingHeight.value);
await meetingConfig.client.join({
sdkKey: meetingConfig.sdkKey,
signature: sign,
meetingNumber: meetingConfig.meetingNumber,
password: meetingConfig.passWord,
userName: meetingConfig.userName,
userEmail: meetingConfig.userEmail,
tk: meetingConfig.registrantToken,
});
isJoinFirstTime.value = false;
console.log(meetingConfig.client.getAttendeeslist());
document.querySelector("#suspension-view-tab-thumbnail-gallery").click();
// 自动点击允许共享屏幕 //TODO:自动点击按钮
if (route.name === "Host") {
const safeButton = document.querySelector('button[title="安全"]');
if (safeButton) {
safeButton.click();
const allowScreenShare = document.querySelectorAll(
".zmwebsdk-MuiButtonBase-root.zmwebsdk-MuiListItem-root.zmwebsdk-MuiMenuItem-root.zmwebsdk-MuiMenuItem-gutters.zmwebsdk-MuiListItem-gutters.zmwebsdk-MuiListItem-button"
)[1];
if (allowScreenShare.childElementCount === 0) {
allowScreenShare.click();
}
}
}
isMeetingLoading.value = false;
} catch (error) {
isMeetingLoading.value = false;
}
};
const setSize = () => {
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.9;
meetingHeight.value = (meetingWidth.value * 9) / 16;
// videoElementRef.value.style.width = `${meetingWidth.value}px`;
videoElementRef.value.style.height = `${meetingHeight.value + 42}px`;
document.querySelector(
"#video-element> div> .zmwebsdk-MuiPaper-root> .zmwebsdk-MuiPaper-root:nth-child(1)"
).style.width = `${meetingWidth.value}px`;
document
.querySelectorAll(
'div[id*="suspension-view-tabpanel"] > .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root'
)
.forEach((el) => {
el.style.height = `${meetingHeight.value}px`;
});
};
window.client = meetingConfig.client;
window.startMeeting = startMeeting;
const checkMediaVideoRef = ref(null);
const checkMediaWrapRef = ref(null);
const showCheckMediaVideo = ref(true);
const isVideoAvailable = ref(undefined);
const isAudioAvailable = ref(undefined);
// TODO:可能有摄像头占用问题。
onMounted(() => {
nextTick(() => {
const videoWidth = checkMediaWrapRef.value.offsetWidth;
const videoHeight = checkMediaWrapRef.value.offsetHeight;
console.log(checkMediaVideoRef.value);
navigator.mediaDevices
.getUserMedia({ video: { width: videoWidth, height: videoHeight } })
.then((stream) => {
checkMediaVideoRef.value.srcObject = stream;
checkMediaVideoRef.value.play();
isVideoAvailable.value = true;
})
.catch((err) => {
console.log(err);
isVideoAvailable.value = false;
});
});
navigator.mediaDevices
.getUserMedia({ audio: true })
.then((stream) => {
console.log(stream);
isAudioAvailable.value = true;
})
.catch((err) => {
console.log(err);
isAudioAvailable.value = false;
});
});
// 设置文本标签
const setTextLabel = () => {
document.querySelectorAll(".text-tag").forEach((el) => {
el.remove();
});
store.getters.textLabelList.forEach((item) => {
const labelObj = JSON.parse(item.textLabel);
const textEl = document.createElement("div");
textEl.id = `${uniqueId("tag-")}`;
textEl.innerHTML = labelObj.content;
textEl.className = "text-tag";
textEl.style.backgroundColor = labelObj.backgroundColor;
textEl.style.visibility =
labelObj.visibility === "1" ? "visible" : "hidden";
textEl.style.left = `${labelObj.x}`;
textEl.style.top = `${labelObj.y}`;
meetingContainerRef.value.appendChild(textEl);
});
};
const switchToVideoOn = () => {
const prevBtn = document.querySelector(
"#suspension-view-tabpanel-ribbon>div>div:last-child>.zmwebsdk-MuiBox-root>button:first-child"
);
const nextBtn = document.querySelector(
"#suspension-view-tabpanel-ribbon>div>div:last-child>.zmwebsdk-MuiBox-root>button:last-child"
);
if (!prevBtn || !nextBtn) {
return;
}
let isNextBtnHidden = nextBtn.className.includes(
"zmwebsdk-makeStyles-hidePaginationIcon"
);
let isPrevBtnHidden = prevBtn.className.includes(
"zmwebsdk-makeStyles-hidePaginationIcon"
);
while (!isPrevBtnHidden) {
prevBtn.click();
isPrevBtnHidden = prevBtn.className.includes(
"zmwebsdk-makeStyles-hidePaginationIcon"
);
}
let timer = setInterval(() => {
const displayLiEl = document.querySelector(
'ul[class^="zmwebsdk-makeStyles-avatarList"]>li'
);
console.log(displayLiEl);
if (displayLiEl.className.includes("videoOn")) {
console.log("开启了视频");
clearInterval(timer);
return;
}
nextBtn.click();
isNextBtnHidden = nextBtn.className.includes(
"zmwebsdk-makeStyles-hidePaginationIcon"
);
if (isNextBtnHidden) {
setTimeout(() => {
const displayLiEl = document.querySelector(
'ul[class^="zmwebsdk-makeStyles-avatarList"]>li'
);
console.log(displayLiEl);
}, 100);
clearInterval(timer);
}
}, 100);
// console.log(isNextBtnHidden);
};
const inSharing = ref(false); // 共享屏幕是否开启
const attendeeslist = ref("");
setInterval(() => {
screenWidth.value = window.screen.width;
// 共享屏幕状态变化
const screenShareEl = document.querySelector(
`div[class*="zmwebsdk-makeStyles-inSharing"]`
);
inSharing.value = screenShareEl ? true : false;
// ------
// 检测是否是ribbon视图, 如果是, 则切换到gallery view, 当观众被设为嘉宾或嘉宾被设为观众时需要切换视图.
const isRibbon = document.querySelector(
"#suspension-view-tab-thumbnail-ribbon.zmwebsdk-MuiTab-selected"
);
if (isRibbon && !inSharing.value) {
const galleryViewButton = document.querySelector(
"#suspension-view-tab-thumbnail-gallery"
);
if (galleryViewButton) galleryViewButton.click();
}
// ------
// TODO:
// 检测是否存在"同意被设为嘉宾按钮",存在则自动点击
const isSetAsGuest = document.querySelector(
".zmwebsdk-MuiButtonBase-root.zmwebsdk-MuiButton-root.zmwebsdk-MuiButton-contained.zmwebsdk-MuiButton-containedPrimary.zmwebsdk-MuiButton-containedSizeSmall.zmwebsdk-MuiButton-sizeSmall.zmwebsdk-MuiButton-disableElevation"
);
const setAsGuestLabel = document.querySelector(
".zmwebsdk-MuiButtonBase-root.zmwebsdk-MuiButton-root.zmwebsdk-MuiButton-contained.zmwebsdk-MuiButton-containedPrimary.zmwebsdk-MuiButton-containedSizeSmall.zmwebsdk-MuiButton-sizeSmall.zmwebsdk-MuiButton-disableElevation>span"
);
if (isSetAsGuest && setAsGuestLabel.innerHTML === "以嘉宾身份加入") {
isSetAsGuest.click();
}
// -------
// 检测参会嘉宾及其摄像头开关状态
attendeeslist.value = meetingConfig.client
.getAttendeeslist()
.map((el) => JSON.stringify({ userId: el.userId, bVideoOn: el.bVideoOn }))
.join("$");
// -------
// 检测共享屏幕canvas距离父元素顶部距离
const shareScreenCanvasEl = document.querySelector(
'div[id*="suspension-view-tabpanel"]>.zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root>div[class*="inSharing"]>div:first-child'
);
// console.log(shareScreenCanvasEl);
if (shareScreenCanvasEl) {
if (templateId.value == 3 || templateId.value == 4 || screen.width < 900) {
document.querySelector(
`div[id*="suspension-view-tabpanel"] > .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root > div[class*="inSharing"] + div`
).style.top = `${shareScreenCanvasEl.offsetTop}px`;
} else {
document.querySelector(
`div[id*="suspension-view-tabpanel"] > .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root > div[class*="inSharing"] + div`
).style.top = "";
}
}
}, 500);
// 监听共享屏幕状态
watch(inSharing, (val) => {
console.log(val);
if (val) {
// setLayout(templateId.value);
// makeVideoTop();
} else {
const galleryViewButton = document.querySelector(
"#suspension-view-tab-thumbnail-gallery"
);
if (galleryViewButton) galleryViewButton.click();
/* 在手机上关闭共享屏幕时未能把去掉摄像头的top样式 (?), 需要在此处再次清除top样式 */
document
.querySelectorAll(
`div[id*="suspension-view-tabpanel"] > .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root>div:last-child`
)
.forEach((el) => {
el.style.top = "";
});
}
});
// 监听参会人员videoOn状态变化自动切换到已开启摄像头的用户
watch(attendeeslist, (val) => {
console.log(val);
if (inSharing.value) {
switchToVideoOn();
}
});
// 点击进入全屏模式
const fullscreenWrapRef = ref(null);
const isVerticalFullScreen = ref(false);
const showHorizontalScreen = ref(false);
const setFullScreen = async () => {
// if (window.orientation === 0) {
// // ElMessageBox.prompt("请将手机横过来");
// showHorizontalScreen.value = true;
// setTimeout(() => {
// showHorizontalScreen.value = false;
// }, 1500);
// return;
// }
try {
document.querySelector(".fullscreen-wrap").requestFullscreen();
} catch (error) {
console.log(error);
document.querySelector(".fullscreen-wrap").webkitRequestFullscreen();
}
isFullScreen.value = true;
nextTick(() => {
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.9;
meetingHeight.value = (meetingWidth.value * 9) / 16;
// 当手机竖屏时
if (window.orientation === 0) {
isVerticalFullScreen.value = true;
videoElementRef.value.style.height = `${
screen.width - screen.height * 0.08
}px`;
nextTick(() => {
document
.querySelectorAll(
"div[id*=suspension-view-tabpanel]>.zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root"
)
.forEach((el) => {
el.style.height = `${screen.width - screen.height * 0.08}px`;
});
});
}
videoElementRef.value.style.height = `${
screen.height - screen.width * 0.08
}px`;
console.log(`${screen.height - screen.width * 0.08}px`);
document
.querySelectorAll(
"div[id*=suspension-view-tabpanel]>.zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root"
)
.forEach((el) => {
el.style.height = `${screen.height - screen.width * 0.08}px`;
});
});
};
const quitFullScreen = () => {
document.exitFullscreen();
};
// 是否显示考试和问卷弹窗
const showExamDialog = ref(false);
const showQuestionnaireDialog = ref(false);
const examStarted = ref(false); //考试是否开始
/* 签到功能 */
// 提交签到
const showSignDialog = ref(false); //是否显示签到窗口
const submitSign = async () => {
await signMeeting({
meetingId: store.getters.meetingId,
signTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
account: joinAccount.value,
});
showSignDialog.value = false;
ElMessage.success("签到成功");
};
// 当考试和问卷弹框未能正确弹出时,(即考试开始时,未加入会议),加载题目列表
const loadQuestionsList = async (mode) => {
const { data } = await getQuestionsList({
meetingId: store.getters.meetingId,
type: mode,
});
return data.map((item) => {
return {
...item,
choiceAnswerIdStr: [],
};
});
};
// 当会议结束时,如果没有手动点击提交则自动提交试卷
const submitQuestion = async (mode) => {
if (mode == "1") {
await commitExam({
meetingId: store.getters.meetingId,
userAccount: joinAccount.value,
commitExamList: examQuestionsList.value.map((item) => {
return {
questionId: item.id,
choiceAnswerIdStr: item.choiceAnswerIdStr.join(",") + ",",
};
}),
});
ElMessage.success("提交考试成功");
} else if (mode == "2") {
await commitQuestionnaire({
meetingId: store.getters.meetingId,
userAccount: joinAccount.value,
commitExamList: questionnaireQuestionsList.value.map((item) => {
return {
questionId: item.id,
choiceAnswerIdStr: item.choiceAnswerIdStr.join(",") + ",",
};
}),
});
ElMessage.success("提交问卷成功");
}
// closeDialog();
};
// loadQuestionsList("1");
let socket = reactive({});
const initWebSocket = () => {
// 建立websocket连接
socket = new ReconnectingWebSocket(
`wss://meeting.chuhuankj.com/wss/websocket/meeting/${store.getters.meetingId}/${joinAccount.value}`
);
socket.addEventListener("open", () => {
console.log("websocket,已连接");
});
// 监听websocket消息
socket.addEventListener("message", async (event) => {
const data = JSON.parse(JSON.parse(event.data));
console.log(data);
// 会议信息更新时
if (data.type === "isRefreshMeeting") {
await store.dispatch("getMeetingInfo", store.getters.meetingId);
meetingContainerRef.value.style.background = `url(${store.getters.templateBackgroundPic}) 0% 0% / cover no-repeat`;
templateId.value = store.getters.templateId;
// setLayout(templateId.value);
setTextLabel();
}
// 收到聊天消息时
else if (data.type === "isChat") {
console.log(data.content);
console.log(JSON.parse(JSON.parse(JSON.parse(data.content).msg)));
messages.value.push({
...JSON.parse(JSON.parse(JSON.parse(data.content).msg)),
id: uniqueId(),
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
});
}
// 开始签到时
else if (data.type === "isStartSign" && route.name === "Meeting") {
showSignDialog.value = true;
}
// 签到结束时
else if (data.type === "isEndSign" && route.name === "Meeting") {
showSignDialog.value = false;
}
// 开始考试时
else if (data.type === "isStartExam" && route.name === "Meeting") {
showExamDialog.value = true;
}
// 开始问卷时
else if (data.type === "isStartQuestionnaire" && route.name === "Meeting") {
showQuestionnaireDialog.value = true;
}
// 会议结束时
else if (data.type === "isCloseMeeting") {
showExamDialog.value = false;
showQuestionnaireDialog.value = false;
ElMessageBox.alert("会议已结束");
socket.close();
if (store.getters.bankId && !store.state.joinUser.examSubmited) {
if (examQuestionsList.value.length === 0) {
examQuestionsList.value = await loadQuestionsList("1");
}
submitQuestion("1");
}
if (
store.getters.questionnaireId &&
!store.state.joinUser.questionnaireSubmited
) {
if (questionnaireQuestionsList.value.length === 0) {
questionnaireQuestionsList.value = await loadQuestionsList("2");
}
submitQuestion("2");
}
}
});
socket.addEventListener("close", (event) => {
console.log(event, "close");
});
socket.addEventListener("error", (event) => {
console.log(event, "error");
});
};
initWebSocket();
// 消息列表
const messages = ref([]);
const sendMessage = (msgObj) => {
console.log(JSON.stringify(JSON.stringify(msgObj)));
socket.send(
JSON.stringify(
JSON.stringify({
account: joinName.value,
msg: msgObj.msg,
})
)
);
messages.value.push(msgObj);
};
const examQuestionsList = ref([]);
const getStageExamAnswer = (val) => {
examQuestionsList.value = val.map((el) => el);
};
const questionnaireQuestionsList = ref([]);
const getStageQuestionnaireAnswer = (val) => {
questionnaireQuestionsList.value = val.map((el) => el);
};
const isFullScreen = ref(false);
onMounted(() => {
meetingContainerRef.value.style.background = ` url(${store.getters.templateBackgroundPic}) 0% 0% / cover no-repeat`;
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.9;
meetingHeight.value = (meetingWidth.value * 9) / 16;
videoElementRef.value.style.height = `${meetingHeight.value + 42}px`;
const handleFullscreenChange = () => {
if (document.fullscreenElement) {
isFullScreen.value = true;
} else {
isFullScreen.value = false;
isVerticalFullScreen.value = false;
nextTick(() => {
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.9;
meetingHeight.value = (meetingWidth.value * 9) / 16;
// videoElementRef.value.style.width = `${meetingWidth.value}px`;
videoElementRef.value.style.height = `${meetingHeight.value + 42}px`;
document
.querySelectorAll(
"div[id*=suspension-view-tabpanel]>.zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root"
)
.forEach((el) => {
console.log(`${meetingHeight.value}px`);
// el.style.height = `${meetingHeight.value}px`;
el.style.height = "";
});
});
}
};
// 当全屏状态改变时
fullscreenWrapRef.value.addEventListener(
"fullscreenchange",
handleFullscreenChange
);
fullscreenWrapRef.value.addEventListener(
"onwebkitfullscreenchange",
handleFullscreenChange
);
setTextLabel();
startMeeting();
});
// 当修改窗口尺寸时
window.addEventListener("resize", (e) => {
console.log(e);
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.9;
meetingHeight.value = (meetingWidth.value * 9) / 16;
if (!document.fullscreenElement) {
videoElementRef.value.style.height = `${meetingHeight.value + 42}px`;
}
});
window.addEventListener("orientationchange", function () {
if (window.orientation === 90) {
if (isFullScreen.value === true) {
isVerticalFullScreen.value = false;
videoElementRef.value.style.height = ``;
nextTick(() => {
document
.querySelectorAll(
"div[id*=suspension-view-tabpanel]>.zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root"
)
.forEach((el) => {
el.style.height = ``;
});
setFullScreen();
});
}
} else if (window.orientation === 0) {
if (isFullScreen.value === true) {
setFullScreen();
}
}
});
window.getCurrentUser = meetingConfig.client.getCurrentUser;
window.getAttendeeslist = meetingConfig.client.getAttendeeslist;
window.getCurrentMeetingInfo = meetingConfig.client.getCurrentMeetingInfo;
window.checkSystemRequirements = meetingConfig.client.checkSystemRequirements;
const leaveConference = () => {
meetingConfig.client.leaveMeeting();
};
window.addEventListener("beforeunload", leaveConference);
onUnmounted(() => {
window.removeEventListener("beforeunload", leaveConference);
});
</script>
<style lang="scss" scoped>
$meetingComponentWitdh: 80vw * 0.9;
$meetingComponentHeight: $meetingComponentWitdh * 9 / 16;
:deep(#right-chat .chat-container .message-list) {
height: $meetingComponentWitdh * 9 / 16;
overflow-y: scroll;
}
#app-container {
#meeting-chat-row {
display: flex;
justify-content: space-between;
#meeting-container {
box-sizing: border-box;
padding-top: calc(80vw * 0.08);
display: flex;
justify-content: center;
width: 80vw;
position: relative;
#video-element {
width: 72vw;
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
> div) {
padding-top: 6px;
}
}
.el-button {
position: absolute;
right: 1vw;
bottom: 1vw;
}
:deep(.text-tag) {
position: absolute;
z-index: 999;
border-radius: 4px;
padding: 5px;
background-color: #fff;
* {
margin: 0;
padding: 0;
}
}
}
#right-chat {
width: 20vw;
}
}
}
.layout-template-1 {
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.5;
height: $meetingComponentWitdh * 0.5 * 9 / 16;
align-self: center;
}
}
.layout-template-2 {
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.5;
height: $meetingComponentWitdh * 0.5 * 9 / 16;
align-self: center;
}
:deep(#suspension-view-tabpanel-ribbon
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root),
:deep(#suspension-view-tabpanel-speaker
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root) {
flex-direction: row-reverse;
}
}
.layout-template-3 {
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.2;
height: $meetingComponentWitdh * 0.2 * 9 / 16;
position: relative;
}
}
.layout-template-4 {
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.2;
height: $meetingComponentWitdh * 0.2 * 9 / 16;
position: relative;
}
:deep(#suspension-view-tabpanel-ribbon
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root),
:deep(#suspension-view-tabpanel-speaker
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root) {
flex-direction: row-reverse;
}
}
:deep(.zmwebsdk-MuiToolbar-root.zmwebsdk-MuiToolbar-regular) {
display: none; // 隐藏顶部 toolbar
}
:deep(div[class*="zmwebsdk-makeStyles-singleView"]) {
padding: 0; // 去掉会议组件边距
}
:deep(#video-element
> div
> .zmwebsdk-MuiPaper-root
> .zmwebsdk-MuiPaper-root:nth-child(1)) {
width: calc(80vw * 0.9);
}
:deep(#video-element
> div
> .zmwebsdk-MuiPaper-root
> .zmwebsdk-MuiPaper-root:nth-child(2)) {
width: 270px;
background: #ccc;
}
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root) {
height: calc(80vw * 0.9 * 9 / 16);
}
:deep(.zmwebsdk-MuiPaper-root) {
background: transparent;
box-shadow: 0 0;
}
// 隐藏共享屏幕上方提示
:deep(div[id*="suspension-view-tabpanel"]
div[class*="inSharing"]
> .zmwebsdk-MuiBox-root) {
display: none;
}
:deep(.check-media) {
.el-dialog__body {
text-align: center;
#check-media-wrap {
display: inline-block;
margin: 1vw auto;
border-radius: 1vw;
overflow: hidden;
width: 36vw;
height: 24vw;
background-color: #000;
position: relative;
// #check-media-video {
// width: 100%;
// height: 100%;
// }
svg {
position: absolute;
left: 1vw;
bottom: 1vw;
width: 3vw;
height: 3vw;
}
.microphone-loading {
color: #fff;
}
.microphone-on {
color: springgreen;
}
.microphone-off {
color: indianred;
}
}
}
}
// 适配移动端 屏幕宽度小于 900px
@media screen and (max-width: 900px) {
$meetingComponentWitdh: 90vw;
// $meetingComponentHeight: $meetingComponentWitdh * 9 / 16;
#app-container {
#meeting-chat-row {
#meeting-container {
padding-top: calc(100vw * 0.08);
width: 100vw;
#video-element {
width: 90vw;
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.2;
height: $meetingComponentWitdh * 0.2 * 9 / 14.5;
position: relative;
align-self: initial;
}
// width: 72vw;
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
> div) {
padding-top: initial;
}
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root) {
height: calc(100vw * 0.9 * 9 / 16);
}
}
:deep(#video-element
> div
> .zmwebsdk-MuiPaper-root
> .zmwebsdk-MuiPaper-root:nth-child(1)) {
width: 90vw;
}
}
}
}
#right-chat {
display: none !important;
}
:deep(.check-media) {
.el-dialog__body {
#check-media-wrap {
margin: 2vw auto;
width: 80vw;
height: 54vw;
svg {
width: 6vw;
height: 6vw;
}
}
}
}
}
// 全屏样式
#app-container {
#meeting-chat-row {
.fullscreen-wrap {
width: 80vw;
#meeting-container.fullscreen {
$meetingComponentWitdh: 90vw;
padding-top: calc(80vw * 0.08);
width: 100vw;
height: 100vh;
#video-element {
width: 90vw;
}
.layout-template-1 {
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.5;
height: $meetingComponentWitdh * 0.5 * 9 / 16;
}
}
.layout-template-2 {
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.5;
height: $meetingComponentWitdh * 0.5 * 9 / 16;
}
}
.layout-template-3 {
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.2;
height: $meetingComponentWitdh * 0.2 * 9 / 16;
}
}
.layout-template-4 {
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.2;
height: $meetingComponentWitdh * 0.2 * 9 / 16;
}
}
:deep(#video-element
> div
> .zmwebsdk-MuiPaper-root
> .zmwebsdk-MuiPaper-root:nth-child(1)) {
width: 90vw;
}
:deep(#video-element
> div
> .zmwebsdk-MuiPaper-root
> .zmwebsdk-MuiPaper-root:nth-child(2)) {
display: none;
}
// :deep(div[id*="suspension-view-tabpanel"]
// > .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root) {
// height: calc(100vw * 0.9 * 9 / 16);
// }
}
#meeting-container.verticalFullScreen {
$meetingComponentWitdh: 90vh;
$meetingComponentHeight: $meetingComponentWitdh * 9 / 16;
padding-top: calc(80vh * 0.08);
position: absolute;
transform-origin: 0% 0%;
transform: rotate(90deg);
top: 0;
left: 100vw;
width: 100vh !important;
height: 100vw;
#video-element {
width: 90vh;
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.2;
height: $meetingComponentWitdh * 0.2 * 9 / 14.5;
}
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
> div) {
padding-top: initial;
}
}
:deep(#video-element
> div
> .zmwebsdk-MuiPaper-root
> .zmwebsdk-MuiPaper-root:nth-child(1)) {
// width: calc(100vh * 0.9) !important;
width: 90vh;
}
:deep(#video-element
> div
> .zmwebsdk-MuiPaper-root
> .zmwebsdk-MuiPaper-root:nth-child(2)) {
display: none;
}
// :deep(div[id*="suspension-view-tabpanel"]
// > .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root) {
// height: calc(100vh * 0.9 * 9 / 16) !important;
// }
}
}
}
}
</style>