Files
meeting-client/src/views/meeting.vue
2022-10-18 19:26:59 +08:00

1306 lines
40 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,
notInSharing: !inSharing,
}"
>
<div class="text-label-container" ref="textLabelContainerRef"></div>
<div
id="video-element"
:class="`layout-template-${templateId}`"
ref="videoElementRef"
></div>
<CountDown :start-time="store.getters.startTime" />
<!-- <like
v-if="screenWidth > 900"
:meeting-id="store.getters.meetingId"
:like="likeCount"
:online="onlineCount"
style="position: absolute; bottom: 1vw; right: 6vw"
/> -->
<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" ref="rightChatRef">
<Chat
:is-host="route.name === 'Host'"
place="right"
:account="joinName"
:message-list="messages"
@send="sendMessage"
/>
</div>
</div>
<div class="like-row">
<like
:meeting-id="store.getters.meetingId"
:like="likeCount"
:online="onlineCount"
style="margin: 0 auto"
/>
</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-host="route.name === 'Host'"
place="bottom"
:account="joinName"
:message-list="messages"
@send="sendMessage"
/>
</el-tab-pane>
<el-tab-pane label="考核" v-if="route.name === 'Meeting'">
<!-- // 签到、考试、问卷弹窗 -->
<el-row :gutter="10">
<el-col :span="12"
><el-button
type="primary"
:disabled="
!isDuringExamPeriod || store.state.joinUser.examSubmited
"
@click="handleReOpenExam"
style="width: 100%"
>考试</el-button
></el-col
>
<el-col :span="12"
><el-button
type="primary"
style="width: 100%"
@click="showQuestionnaireDialog = true"
:disabled="
!isDuringQuestionnairePeriod ||
store.state.joinUser.questionnaireSubmited
"
>问卷</el-button
></el-col
>
</el-row>
</el-tab-pane>
</el-tabs>
<el-dialog
v-model="showSignDialog"
:close-on-click-modal="false"
title="签到"
width="30%"
:fullscreen="screenWidth < 900"
>
<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>
<!-- <mediaCheck @close="startMeeting" /> -->
<mediaCheck @close="startMeeting" />
<questions
mode="1"
@stage="getStageExamAnswer"
:questions-list="examQuestionsList"
v-if="showExamDialog && route.name !== 'Host'"
:showDialog="showExamDialog"
@close="showExamDialog = $event"
></questions>
<questions
mode="2"
@stage="getStageQuestionnaireAnswer"
:questions-list="questionnaireQuestionsList"
v-if="showQuestionnaireDialog && route.name !== 'Host'"
:showDialog="showQuestionnaireDialog"
@close="showQuestionnaireDialog = $event"
></questions>
</div>
</template>
<script setup>
import {
computed,
nextTick,
onMounted,
onUnmounted,
reactive,
ref,
watch,
} from "vue";
import { useStore } from "vuex";
import { useRoute, useRouter } 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 } from "@element-plus/icons-vue";
import {
signMeeting,
generateSignature,
getOnlineUserTotalAndLikes,
} from "@/api/meeting";
import axios from "axios";
import Chat from "@/components/chat";
import mediaCheck from "@/components/mediaCheck.vue";
import like from "@/components/like.vue";
import questions from "@/components/questions";
import {
getQuestionsList,
commitQuestionnaire,
commitExam,
} from "@/api/meeting";
import CountDown from "@/components/countDown.vue";
const store = useStore();
const route = useRoute();
const router = useRouter();
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.username ||
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 textLabelContainerRef = 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: "TUgbQFx4RhPHDPa0OQAKVgPL2dPGQoVqZIuW",
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 isDuringExamPeriod = ref(false);
isDuringExamPeriod.value = (() => {
const examStartTime = dayjs(store.state.meeting.examStartTime);
const meetingEndTime = dayjs(store.state.meeting.startTime).add(
store.state.meeting.duration,
"minute"
);
if (!examStartTime) {
return false;
} else {
const now = dayjs();
return now.isAfter(examStartTime) && now.isBefore(meetingEndTime);
}
})();
const handleReOpenExam = () => {
showExamDialog.value = true;
};
const isDuringQuestionnairePeriod = ref(false);
isDuringQuestionnairePeriod.value = (() => {
const questionnaireStartTime = dayjs(
store.state.meeting.questionnaireStartTime
);
const meetingEndTime = dayjs(store.state.meeting.startTime).add(
store.state.meeting.duration,
"minute"
);
if (!questionnaireStartTime) {
return false;
} else {
const now = dayjs();
return now.isAfter(questionnaireStartTime) && now.isBefore(meetingEndTime);
}
})();
// 开始会议
const startMeeting = async () => {
const { sign } = await generateSignature({
meetingNumber: store.getters.meetingNumber,
role: meetingConfig.role,
});
// const resp = await axios.post("http://localhost:4000", {
// meetingNumber: store.getters.meetingNumber,
// role: meetingConfig.role,
// });
// const sign = resp.data.signature;
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,
});
document.querySelector("#suspension-view-tab-thumbnail-gallery").click();
// 自动连接语音
const linkVoiceButton = document.querySelector('button[title="连接语音"]');
if (linkVoiceButton) {
linkVoiceButton.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];
console.log("before click allow btn");
if (allowScreenShare.childElementCount === 0) {
allowScreenShare.click();
console.log("allow btn clicked");
} else {
document.body.click();
}
}
}
isMeetingLoading.value = false;
} catch (error) {
isMeetingLoading.value = false;
}
};
// const setSize = () => {
// meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.88;
// 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`;
// });
// };
// 设置文本标签
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.zIndex = "999";
textEl.style.backgroundColor = labelObj.backgroundColor;
textEl.style.visibility =
labelObj.visibility === "1" ? "visible" : "hidden";
textEl.style.left = `${labelObj.x}`;
textEl.style.top = `${labelObj.y}`;
textLabelContainerRef.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);
};
const inSharing = ref(false); // 共享屏幕是否开启
const attendeeslist = ref("");
setInterval(() => {
// 共享屏幕状态变化
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 onlineCount = ref(0);
const likeCount = ref(0);
const getLikeAndOnline = async () => {
const { data } = await getOnlineUserTotalAndLikes(store.getters.meetingId);
onlineCount.value = data.online;
likeCount.value = data.like;
};
getLikeAndOnline();
// 点击进入全屏模式
const fullscreenWrapRef = ref(null);
const isVerticalFullScreen = ref(false);
const setFullScreen = async () => {
try {
// alert(document.querySelector(".fullscreen-wrap").requestFullscreen());
document.querySelector(".fullscreen-wrap").requestFullscreen();
} catch (error) {
console.log(error);
// alert(document.querySelector(".fullscreen-wrap").requestFullscreen());
document.querySelector(".fullscreen-wrap").webkitRequestFullscreen();
}
isFullScreen.value = true;
nextTick(() => {
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.88;
meetingHeight.value = (meetingWidth.value * 9) / 16;
// 当手机竖屏时
if (window.orientation === 0) {
isVerticalFullScreen.value = true;
videoElementRef.value.style.height = `${
screen.width - screen.height * 0.06
}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.06}px`;
});
});
}
videoElementRef.value.style.height = `${
screen.height - screen.width * 0.06
}px`;
// console.log(`${screen.height - screen.width * 0.06}px`);
document
.querySelectorAll(
"div[id*=suspension-view-tabpanel]>.zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root"
)
.forEach((el) => {
el.style.height = `${screen.height - screen.width * 0.06}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;
store.commit("setJoinUser", {
...store.state.joinUser,
signSubmited: true,
});
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) => {
console.log(JSON.parse(event.data));
console.log(event.data);
let data;
try {
data = JSON.parse(JSON.parse(event.data));
} catch (error) {
console.log(error);
data = JSON.parse(event.data);
}
// 会议信息更新时
if (data.type === "isRefreshMeeting") {
await store.dispatch("getMeetingInfo", store.getters.meetingId);
meetingContainerRef.value.style.background = `url(${
store.getters.templateBackgroundPic || store.getters.defaultBackground
}) 0% 0% / cover no-repeat`;
templateId.value = store.getters.templateId;
setTextLabel();
}
// 收到聊天消息时
else if (data.type === "isChat") {
messages.value.push({
...JSON.parse(data.content),
id: uniqueId(),
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
});
nextTick(() => {
document
.querySelector(".message-list .message-row:last-child")
.scrollIntoView({ behavior: "smooth" });
});
store.commit("setMessagesList", messages.value);
}
// 当检测到敏感词时
else if (data.type === "isSensitive") {
console.log("敏感词");
ElMessage.error(`消息未发送成功,因为包含违禁词:${data.content}`);
}
// 开始签到时
else if (data.type === "isStartSign" && route.name === "Meeting") {
showSignDialog.value = true;
isDuringExamPeriod.value = true;
}
// 签到结束时
else if (data.type === "isEndSign" && route.name === "Meeting") {
showSignDialog.value = false;
}
// 开始考试时
else if (data.type === "isStartExam" && route.name === "Meeting") {
showExamDialog.value = true;
isDuringExamPeriod.value = true;
}
// 开始问卷时
else if (data.type === "isStartQuestionnaire" && route.name === "Meeting") {
showQuestionnaireDialog.value = true;
isDuringQuestionnairePeriod.value = true;
} else if (data.type === "isRefreshOnlineAndLike") {
console.log(data.type);
getLikeAndOnline();
}
// 当检测到异地登陆时,强制退出登录,并清除数据
else if (data.type === "isRemoteLogin") {
ElMessageBox.alert("您的账号在异地登录,将被强制下线", "异地登录", {
type: "warning",
"show-close": false,
"show-confirm-button": false,
"show-cancel-button": false,
});
setTimeout(() => {
leaveConference();
store.commit("setJoinUser", {});
store.commit("setPassword", "");
store.commit("setMessagesList", []);
store.commit("setLiked", false);
router.push(`/verify/${store.getters.meetingId}`);
}, 2000);
}
// 会议结束时
else if (data.type === "isCloseMeeting") {
showExamDialog.value = false;
showQuestionnaireDialog.value = false;
isDuringExamPeriod.value = false;
isDuringQuestionnairePeriod.value = false;
ElMessageBox.alert("会议已结束");
socket.close();
if (route.name === "Meeting") {
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");
}
} else if (route.name === "Host") {
meetingConfig.client.endMeeting();
}
}
});
socket.addEventListener("close", (event) => {
console.log(event, "close");
});
socket.addEventListener("error", (event) => {
console.log(event, "error");
});
};
initWebSocket();
// 消息列表
const messages = ref([]);
messages.value = store.state.messagesList.map((msg) => msg);
const sendMessage = (msgObj) => {
console.log(
JSON.stringify({
account: joinName.value,
msg: msgObj.msg,
})
);
socket.send(
JSON.stringify({
account: joinName.value,
msg: msgObj.msg,
})
);
messages.value.push(msgObj);
nextTick(() => {
document
.querySelector(".message-list .message-row:last-child")
.scrollIntoView({ behavior: "smooth" });
});
store.commit("setMessagesList", messages.value);
};
const examQuestionsList = ref([]);
const getStageExamAnswer = (val) => {
examQuestionsList.value = val.map((el) => el);
};
const questionnaireQuestionsList = ref([]);
const getStageQuestionnaireAnswer = (val) => {
console.log(val);
questionnaireQuestionsList.value = val.map((el) => el);
};
const isFullScreen = ref(false);
const rightChatRef = ref(null);
onMounted(() => {
meetingContainerRef.value.style.background = ` url(${
store.getters.templateBackgroundPic || store.getters.defaultBackground
}) 0% 0% / cover no-repeat`;
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.88;
meetingHeight.value = (meetingWidth.value * 9) / 16;
videoElementRef.value.style.height = `${meetingHeight.value + 42}px`;
rightChatRef.value.style.height = `${
meetingContainerRef.value.offsetWidth * 0.06 + 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.88;
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) => {
screenWidth.value = window.screen.width;
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.88;
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);
window.addEventListener("unload", leaveConference);
onUnmounted(() => {
window.removeEventListener("beforeunload", leaveConference);
});
</script>
<style lang="scss" scoped>
$meetingComponentWitdh: 80vw * 0.88; // 会议组件宽度
$meetingComponentHeight: $meetingComponentWitdh * 9 / 16;
$meetingBackgroundWidth: 80vw; //会议背景宽度
$meetingBackgroundHeight: 80vw * 9 / 16;
:deep(#right-chat .chat-container .message-list) {
// height: $meetingComponentWitdh * 9 / 16;
// height: 100%;
flex-grow: 1;
overflow-y: scroll;
}
#app-container {
.like-row {
padding-right: 20vw;
background-color: #f5f5f5;
}
#meeting-chat-row {
display: flex;
justify-content: space-between;
:deep(.rich-editor) {
width: 14vw !important;
}
:deep(.notInSharing
div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div) {
width: $meetingComponentWitdh;
}
#meeting-container {
box-sizing: border-box;
padding-top: calc(80vw * 0.06);
display: flex;
justify-content: center;
width: $meetingBackgroundWidth;
position: relative;
.text-label-container {
position: absolute;
// z-index: -1;
top: 0;
left: 0;
width: $meetingBackgroundWidth;
height: $meetingComponentHeight + 6.4vw;
}
#video-element {
width: $meetingComponentWitdh;
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
> div) {
padding-top: 3px;
}
:deep(.zmwebsdk-MuiListSubheader-root.zmwebsdk-MuiListSubheader-sticky.zmwebsdk-MuiListSubheader-gutters) {
position: initial;
}
}
.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.15;
height: $meetingComponentWitdh * 0.15 * 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.15;
height: $meetingComponentWitdh * 0.15 * 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;
}
}
.layout-template-5 {
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
display: none;
width: $meetingComponentWitdh;
height: $meetingComponentWitdh * 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: $meetingComponentWitdh;
}
: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: $meetingComponentWitdh * 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;
}
// 适配移动端 屏幕宽度小于 900px
@media screen and (max-width: 900px) {
$meetingComponentWitdh: 88vw;
// $meetingComponentHeight: $meetingComponentWitdh * 9 / 16;
#app-container {
.like-row {
padding-right: 0;
}
#meeting-chat-row {
:deep(.notInSharing
div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div) {
width: $meetingComponentWitdh;
}
#meeting-container {
padding-top: calc(100vw * 0.06);
width: 100vw;
.text-label-container {
width: 100vw;
// height: 100%;
}
#video-element {
width: 88vw;
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.15;
height: $meetingComponentWitdh * 0.15 * 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: $meetingComponentWitdh * 9 / 16;
}
}
:deep(#video-element
> div
> .zmwebsdk-MuiPaper-root
> .zmwebsdk-MuiPaper-root:nth-child(1)) {
width: $meetingComponentWitdh;
}
}
}
}
#right-chat {
display: none !important;
}
}
// 全屏样式
#app-container {
#meeting-chat-row {
.fullscreen-wrap {
width: 80vw;
:deep(.notInSharing.fullscreen
div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div) {
width: 88vw;
}
#meeting-container.fullscreen {
$meetingComponentWitdh: 88vw;
padding-top: calc(100vw * 0.06);
// @media screen and (max-width: 900px) {
// padding-top: calc(80vw * 0.06);
// }
width: 100vw;
height: 100vh;
.text-label-container {
width: 100vw;
height: 100%;
}
#video-element {
width: $meetingComponentWitdh;
}
.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.15;
height: $meetingComponentWitdh * 0.15 * 9 / 16;
}
}
.layout-template-4 {
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.15;
height: $meetingComponentWitdh * 0.15 * 9 / 16;
}
}
.layout-template-5 {
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
display: none;
width: $meetingComponentWitdh;
height: $meetingComponentWitdh * 9 / 16;
}
}
:deep(#video-element
> div
> .zmwebsdk-MuiPaper-root
> .zmwebsdk-MuiPaper-root:nth-child(1)) {
width: 88vw;
}
: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);
// }
}
:deep(.notInSharing.verticalFullScreen
div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div) {
width: 88vh;
}
#meeting-container.verticalFullScreen {
$meetingComponentWitdh: 88vh;
$meetingComponentHeight: $meetingComponentWitdh * 9 / 16;
padding-top: calc(100vh * 0.06);
position: absolute;
transform-origin: 0% 0%;
transform: rotate(90deg);
top: 0;
left: 100vw;
width: 100vh !important;
height: 100vw;
.text-label-container {
width: 100vh;
height: 100vw;
}
#video-element {
width: $meetingComponentWitdh;
:deep(div[id*="suspension-view-tabpanel"]
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
> div[class*="inSharing"]
+ div) {
width: $meetingComponentWitdh * 0.15;
height: $meetingComponentWitdh * 0.15 * 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: $meetingComponentWitdh;
}
: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>