切换video on
This commit is contained in:
178
src/components/chat.vue
Normal file
178
src/components/chat.vue
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
<template>
|
||||||
|
<div class="chat-container">
|
||||||
|
<div class="message-list">
|
||||||
|
<div
|
||||||
|
v-for="item in messageList"
|
||||||
|
:key="item.id"
|
||||||
|
class="message-row"
|
||||||
|
:style="item.isMe ? `flex-direction: row-reverse;` : ''"
|
||||||
|
>
|
||||||
|
<div class="avatar">
|
||||||
|
{{ item.account[0] }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="message-item">
|
||||||
|
<div class="sender" :style="item.isMe ? `text-align: right;` : ''">
|
||||||
|
{{ item.account }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="text"
|
||||||
|
:style="item.isMe ? `background-color: #89d961;` : ``"
|
||||||
|
v-html="item.msg"
|
||||||
|
></div>
|
||||||
|
<div class="time">{{ item.time }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input-bar">
|
||||||
|
<div
|
||||||
|
v-if="isRich"
|
||||||
|
@click="openRichMessageEditor"
|
||||||
|
v-html="editingMessage"
|
||||||
|
class="display-message"
|
||||||
|
></div>
|
||||||
|
<el-input v-else v-model="editingMessage"></el-input>
|
||||||
|
<el-button @click="sendMessage">发送</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog title="富文本输入框" v-model="showRichEditor">
|
||||||
|
<wangEditor v-model="richMessage" width="100%" :focus="true"></wangEditor>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button type="warning" @click="cancelRichMessage">取消</el-button>
|
||||||
|
<el-button type="primary" @click="saveRichMessage">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup name="Chat">
|
||||||
|
import { ref, toRefs } from "vue";
|
||||||
|
import { uniqueId } from "lodash";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import wangEditor from "@/components/wangEditor";
|
||||||
|
|
||||||
|
const emit = defineEmits(["send"]);
|
||||||
|
const props = defineProps({
|
||||||
|
isRich: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
place: {
|
||||||
|
type: String,
|
||||||
|
default: "right",
|
||||||
|
},
|
||||||
|
messageList: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
account: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const { isRich, messageList, account } = toRefs(props);
|
||||||
|
|
||||||
|
/* 聊天功能 */
|
||||||
|
const editingMessage = ref(""); // 正在编辑的内容
|
||||||
|
const richMessage = ref(""); // 正在编辑的富文本内容 -- 主持人独有
|
||||||
|
const showRichEditor = ref(false);
|
||||||
|
// 保存富文本聊天内容
|
||||||
|
const saveRichMessage = () => {
|
||||||
|
showRichEditor.value = false;
|
||||||
|
editingMessage.value = richMessage.value;
|
||||||
|
richMessage.value = "";
|
||||||
|
};
|
||||||
|
// 取消保存富文本
|
||||||
|
const cancelRichMessage = () => {
|
||||||
|
showRichEditor.value = false;
|
||||||
|
};
|
||||||
|
// 打开富文本编辑器窗口
|
||||||
|
const openRichMessageEditor = () => {
|
||||||
|
showRichEditor.value = true;
|
||||||
|
richMessage.value = editingMessage.value;
|
||||||
|
};
|
||||||
|
// 发送消息
|
||||||
|
const sendMessage = () => {
|
||||||
|
const msgObj = {
|
||||||
|
id: uniqueId(),
|
||||||
|
account,
|
||||||
|
msg: editingMessage.value,
|
||||||
|
isMe: true,
|
||||||
|
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
};
|
||||||
|
emit("send", msgObj);
|
||||||
|
editingMessage.value = "";
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.chat-container {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
.message-list {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
padding: 20px;
|
||||||
|
// min-height: 100px;
|
||||||
|
height: 100%;
|
||||||
|
// margin-bottom: 10px;
|
||||||
|
border-radius: 12px;
|
||||||
|
|
||||||
|
.message-row {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
align-items: center;
|
||||||
|
.avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background-color: #bcbcbc;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.message-item {
|
||||||
|
margin: 0 16px 0;
|
||||||
|
.sender {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
margin: 3px 0 3px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
word-break: break-all;
|
||||||
|
:deep(p) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.time {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: right;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.input-bar {
|
||||||
|
display: flex;
|
||||||
|
margin: 10px 0;
|
||||||
|
.display-message {
|
||||||
|
border: 1px solid #666;
|
||||||
|
width: 80%;
|
||||||
|
min-height: 100%;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
:deep(p) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -31,7 +31,7 @@ export default {
|
|||||||
},
|
},
|
||||||
height: {
|
height: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "300px",
|
default: "320px",
|
||||||
},
|
},
|
||||||
width: {
|
width: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -30,7 +30,7 @@ const router = createRouter({
|
|||||||
{
|
{
|
||||||
path: "/meeting/:meetingId",
|
path: "/meeting/:meetingId",
|
||||||
name: "Meeting",
|
name: "Meeting",
|
||||||
component: () => import("@/views/meeting.vue"),
|
component: () => import("@/views/meeting_new.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/panelist/:meetingId",
|
path: "/panelist/:meetingId",
|
||||||
|
577
src/views/meeting_new.vue
Normal file
577
src/views/meeting_new.vue
Normal file
@ -0,0 +1,577 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app-container" ref="appContainerRef">
|
||||||
|
<!-- zoom 会议组件 -->
|
||||||
|
<div id="meeting-chat-row">
|
||||||
|
<div id="meeting-container" ref="meetingContainerRef">
|
||||||
|
<div
|
||||||
|
id="video-element"
|
||||||
|
class="layout-template-1"
|
||||||
|
ref="videoElementRef"
|
||||||
|
></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"></el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<questions
|
||||||
|
mode="1"
|
||||||
|
v-if="showExamDialog && route.name !== 'Host'"
|
||||||
|
:showDialog="showExamDialog"
|
||||||
|
@close="showExamDialog = $event"
|
||||||
|
></questions>
|
||||||
|
|
||||||
|
<questions
|
||||||
|
mode="2"
|
||||||
|
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 } from "vue-router";
|
||||||
|
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { uniqueId } from "lodash";
|
||||||
|
import ZoomMtgEmbedded from "@zoomus/websdk/embedded";
|
||||||
|
import ReconnectingWebSocket from "reconnecting-websocket";
|
||||||
|
|
||||||
|
import { signMeeting, generateSignature } from "@/api/meeting";
|
||||||
|
import Chat from "@/components/chat";
|
||||||
|
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 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(1);
|
||||||
|
/* 会议配置 */
|
||||||
|
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: store.getters.token,
|
||||||
|
});
|
||||||
|
/* 初始化尺寸 */
|
||||||
|
const initDesktopLayout = () => {
|
||||||
|
// 初始化高度
|
||||||
|
document.querySelectorAll(
|
||||||
|
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root"
|
||||||
|
)[2].style.height = `${meetingHeight.value}px`;
|
||||||
|
|
||||||
|
// 初始化宽度
|
||||||
|
document.querySelectorAll(
|
||||||
|
".zmwebsdk-MuiPaper-root.zmwebsdk-MuiPaper-elevation1.zmwebsdk-MuiPaper-rounded"
|
||||||
|
)[1].style.width = `${meetingWidth.value}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 开始会议
|
||||||
|
const startMeeting = async () => {
|
||||||
|
const { sign } = await generateSignature({
|
||||||
|
meetingNumber: store.getters.meetingNumber,
|
||||||
|
role: meetingConfig.role,
|
||||||
|
});
|
||||||
|
let meetingSDKElement = document.getElementById("video-element");
|
||||||
|
try {
|
||||||
|
meetingConfig.client.init({
|
||||||
|
debug: true,
|
||||||
|
zoomAppRoot: meetingSDKElement,
|
||||||
|
language: "zh-CN",
|
||||||
|
customize: {
|
||||||
|
video: {
|
||||||
|
isResizable: true,
|
||||||
|
popper: {
|
||||||
|
disableDraggable: true,
|
||||||
|
},
|
||||||
|
viewSizes: {
|
||||||
|
default: {
|
||||||
|
width: meetingWidth.value,
|
||||||
|
height: meetingHeight.value, // 不包括顶部toolbar和底部按钮高度
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
meetingInfo: [
|
||||||
|
"topic",
|
||||||
|
"host",
|
||||||
|
"mn",
|
||||||
|
"pwd",
|
||||||
|
"telPwd",
|
||||||
|
"invite",
|
||||||
|
"participant",
|
||||||
|
"dc",
|
||||||
|
"enctype",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await meetingConfig.client.join({
|
||||||
|
sdkKey: meetingConfig.sdkKey,
|
||||||
|
signature: sign,
|
||||||
|
meetingNumber: meetingConfig.meetingNumber,
|
||||||
|
password: meetingConfig.passWord,
|
||||||
|
userName: meetingConfig.userName,
|
||||||
|
userEmail: meetingConfig.userEmail,
|
||||||
|
tk: meetingConfig.registrantToken,
|
||||||
|
});
|
||||||
|
console.log(meetingConfig.client.getAttendeeslist());
|
||||||
|
document.querySelector("#suspension-view-tab-thumbnail-gallery").click();
|
||||||
|
// initDesktopLayout();
|
||||||
|
isMeetingLoading.value = false;
|
||||||
|
} catch (error) {
|
||||||
|
isMeetingLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据id设置布局
|
||||||
|
const setLayout = (templateId) => {
|
||||||
|
console.log(templateId);
|
||||||
|
const videoScreenWrapEl = document.querySelectorAll(
|
||||||
|
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root"
|
||||||
|
)[2]; // 包含视频和课件的容器
|
||||||
|
videoScreenWrapEl.style.flexDirection = "";
|
||||||
|
const videoWrapEl = videoScreenWrapEl.lastChild;
|
||||||
|
|
||||||
|
if (!inSharing.value) return;
|
||||||
|
const screenWrapEl = document.querySelector(
|
||||||
|
`div[class*="zmwebsdk-makeStyles-inSharing"]`
|
||||||
|
);
|
||||||
|
if (templateId === "1") {
|
||||||
|
// 课件|视频 对半分
|
||||||
|
videoWrapEl.style.width = `${meetingWidth.value / 2 - 2}px`;
|
||||||
|
} else if (templateId === "2") {
|
||||||
|
// 视频|课件 对半分
|
||||||
|
videoWrapEl.style.width = `${meetingWidth.value / 2 - 2}px`;
|
||||||
|
videoScreenWrapEl.style.flexDirection = "row-reverse";
|
||||||
|
} else if (templateId === "3") {
|
||||||
|
// 课件|视频 左4/5 | 右边1/5
|
||||||
|
videoWrapEl.style.width = `${(meetingWidth.value - 4) / 5}px`;
|
||||||
|
} else if (templateId === "4") {
|
||||||
|
// 视频|课件 左1/4 | 右边3/4
|
||||||
|
videoWrapEl.style.width = `${(meetingWidth.value - 4) / 5}px`;
|
||||||
|
videoScreenWrapEl.style.flexDirection = "row-reverse";
|
||||||
|
} else if (templateId === "5") {
|
||||||
|
// 只显示课件
|
||||||
|
videoWrapEl.style.display = `none`;
|
||||||
|
} else if (templateId === "6") {
|
||||||
|
// 只显示视频
|
||||||
|
screenWrapEl.style.display = "none";
|
||||||
|
videoWrapEl.style.width = `${meetingWidth.value - 4}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.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"
|
||||||
|
);
|
||||||
|
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);
|
||||||
|
// setTimeout(() => {
|
||||||
|
// const displayLiEl = document.querySelector(
|
||||||
|
// 'ul[class^="zmwebsdk-makeStyles-avatarList"]>li'
|
||||||
|
// );
|
||||||
|
// console.log(displayLiEl);
|
||||||
|
// }, 0);
|
||||||
|
// const displayLiEl = document.querySelector(
|
||||||
|
// 'ul[class^="zmwebsdk-makeStyles-avatarList"]>li'
|
||||||
|
// );
|
||||||
|
// console.log(displayLiEl);
|
||||||
|
// while (!isNextBtnHidden) {
|
||||||
|
// console.log(isNextBtnHidden);
|
||||||
|
// // const displayLiEl = document.querySelector(
|
||||||
|
// // 'ul[class^="zmwebsdk-makeStyles-avatarList"]>li'
|
||||||
|
// // );
|
||||||
|
// // console.log(displayLiEl);
|
||||||
|
// nextBtn.click();
|
||||||
|
// isNextBtnHidden = nextBtn.className.includes(
|
||||||
|
// "zmwebsdk-makeStyles-hidePaginationIcon"
|
||||||
|
// );
|
||||||
|
// // nextTick(() => {
|
||||||
|
// const displayLiEl = document.querySelector(
|
||||||
|
// 'ul[class^="zmwebsdk-makeStyles-avatarList"]>li'
|
||||||
|
// );
|
||||||
|
// console.log(displayLiEl);
|
||||||
|
// // });
|
||||||
|
// }
|
||||||
|
console.log(isNextBtnHidden);
|
||||||
|
// while (!isPrevBtnHidden) {
|
||||||
|
// nextTick(() => {
|
||||||
|
// const displayLiEl = document.querySelector(
|
||||||
|
// 'ul[class^="zmwebsdk-makeStyles-avatarList"]>li'
|
||||||
|
// );
|
||||||
|
// console.log(displayLiEl);
|
||||||
|
// // attenList.unshift({
|
||||||
|
// // videoOn: displayLiEl.className.includes("videoOn"),
|
||||||
|
// // displayName: displayLiEl.firstElementChild.innerHTML,
|
||||||
|
// // });
|
||||||
|
// attenList.unshift(displayLiEl);
|
||||||
|
// });
|
||||||
|
// console.log(isPrevBtnHidden);
|
||||||
|
// prevBtn.click();
|
||||||
|
// nextTick(() => {
|
||||||
|
// isPrevBtnHidden = prevBtn.className.includes(
|
||||||
|
// "zmwebsdk-makeStyles-hidePaginationIcon"
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// const displayLiEl = document.querySelector(
|
||||||
|
// 'ul[class^="zmwebsdk-makeStyles-avatarList"]>li'
|
||||||
|
// );
|
||||||
|
// console.log(displayLiEl);
|
||||||
|
// attenList.unshift({
|
||||||
|
// videoOn: displayLiEl.className.includes("videoOn"),
|
||||||
|
// displayName: displayLiEl.firstElementChild.innerHTML,
|
||||||
|
// });
|
||||||
|
// while (!isPrevBtnHidden) {}
|
||||||
|
// console.log(attenList);
|
||||||
|
};
|
||||||
|
// const attendeeslist = computed(() => {
|
||||||
|
// return meetingConfig.client.getAttendeeslist();
|
||||||
|
// });
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
// ------
|
||||||
|
|
||||||
|
// 检测是否存在"同意被设为嘉宾按钮",存在则自动点击
|
||||||
|
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"
|
||||||
|
);
|
||||||
|
if (isSetAsGuest) {
|
||||||
|
isSetAsGuest.click();
|
||||||
|
}
|
||||||
|
// -------
|
||||||
|
// attendeeslist.value.splice(0, attendeeslist.value.length);
|
||||||
|
attendeeslist.value = meetingConfig.client
|
||||||
|
.getAttendeeslist()
|
||||||
|
.map((el) => JSON.stringify(el))
|
||||||
|
.join("$");
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
// 监听共享屏幕状态
|
||||||
|
watch(inSharing, (val) => {
|
||||||
|
console.log(val);
|
||||||
|
if (val) {
|
||||||
|
setLayout(templateId.value);
|
||||||
|
} else {
|
||||||
|
const galleryViewButton = document.querySelector(
|
||||||
|
"#suspension-view-tab-thumbnail-gallery"
|
||||||
|
);
|
||||||
|
if (galleryViewButton) galleryViewButton.click();
|
||||||
|
const videoScreenWrapEl = document.querySelectorAll(
|
||||||
|
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root"
|
||||||
|
)[2];
|
||||||
|
if (!videoScreenWrapEl) return;
|
||||||
|
const videoWrapEl = videoScreenWrapEl.lastChild;
|
||||||
|
videoWrapEl.style.width = "";
|
||||||
|
videoScreenWrapEl.style.flexDirection = "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(attendeeslist, (val) => {
|
||||||
|
console.log(val);
|
||||||
|
if (inSharing.value) {
|
||||||
|
switchToVideoOn();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 是否显示考试和问卷弹窗
|
||||||
|
const showExamDialog = ref(false);
|
||||||
|
const showQuestionnaireDialog = ref(false);
|
||||||
|
|
||||||
|
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(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 !== "Host") {
|
||||||
|
showSignDialog.value = true;
|
||||||
|
}
|
||||||
|
// 签到结束时
|
||||||
|
else if (data.type === "isEndSign" && route.name !== "Host") {
|
||||||
|
showSignDialog.value = false;
|
||||||
|
}
|
||||||
|
// 开始考试时
|
||||||
|
else if (data.type === "isStartExam" && route.name !== "Host") {
|
||||||
|
showExamDialog.value = true;
|
||||||
|
}
|
||||||
|
// 开始问卷时
|
||||||
|
else if (data.type === "isStartQuestionnaire" && route.name !== "Host") {
|
||||||
|
showQuestionnaireDialog.value = true;
|
||||||
|
}
|
||||||
|
// 会议结束时
|
||||||
|
else if (data.type === "isCloseMeeting") {
|
||||||
|
showExamDialog.value = false;
|
||||||
|
showQuestionnaireDialog.value = false;
|
||||||
|
ElMessageBox.alert("会议已结束");
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
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`;
|
||||||
|
setTextLabel();
|
||||||
|
startMeeting();
|
||||||
|
});
|
||||||
|
window.getCurrentUser = meetingConfig.client.getCurrentUser;
|
||||||
|
window.getAttendeeslist = meetingConfig.client.getAttendeeslist;
|
||||||
|
window.getCurrentMeetingInfo = meetingConfig.client.getCurrentMeetingInfo;
|
||||||
|
const leaveConference = () => {
|
||||||
|
meetingConfig.client.leaveMeeting();
|
||||||
|
};
|
||||||
|
window.addEventListener("beforeunload", leaveConference);
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener("beforeunload", leaveConference);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
// $videoELementWidth: 80% * 0.9;
|
||||||
|
// $videoElementHeight: calc($videoELementWidth * 9 / 16 + 42px);
|
||||||
|
$videoWidth: 240px;
|
||||||
|
$videoHeight: $videoWidth * 9 / 16;
|
||||||
|
#app-container {
|
||||||
|
#meeting-chat-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
#meeting-container {
|
||||||
|
padding-top: calc(80vw * 0.08);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 80%;
|
||||||
|
position: relative;
|
||||||
|
#video-element {
|
||||||
|
// width: $videoELementWidth;
|
||||||
|
// height: $videoElementHeight;
|
||||||
|
background-color: indianred;
|
||||||
|
}
|
||||||
|
:deep(.text-tag) {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 5px;
|
||||||
|
background-color: #fff;
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#right-chat {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-template-1 {
|
||||||
|
:deep(#suspension-view-tabpanel-ribbon
|
||||||
|
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
|
||||||
|
> div:last-child) {
|
||||||
|
width: $videoWidth;
|
||||||
|
height: $videoHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
: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) {
|
||||||
|
width: calc(80vw * 0.9);
|
||||||
|
}
|
||||||
|
:deep(#suspension-view-tabpanel-ribbon
|
||||||
|
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root),
|
||||||
|
:deep(#suspension-view-tabpanel-gallery
|
||||||
|
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root) {
|
||||||
|
height: calc(80vw * 0.9 * 9 / 16);
|
||||||
|
}
|
||||||
|
:deep(#suspension-view-tabpanel-ribbon
|
||||||
|
> .zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root
|
||||||
|
> div:last-child) {
|
||||||
|
// height: calc(240px * 9 / 16);
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
// :deep(.zmwebsdk-MuiPaper-root) {
|
||||||
|
// background: transparent;
|
||||||
|
// box-shadow: 0 0;
|
||||||
|
// }
|
||||||
|
</style>
|
Reference in New Issue
Block a user