主持人参会页面
This commit is contained in:
@ -2,4 +2,4 @@
|
||||
VUE_APP_ENV = 'development'
|
||||
|
||||
# 若依管理系统/开发环境
|
||||
VUE_APP_BASE_API = 'http://120.26.107.74:1618'
|
||||
VUE_APP_BASE_API = '/api'
|
@ -8,15 +8,18 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^1.1.4",
|
||||
"@wangeditor/editor": "^5.0.1",
|
||||
"@wangeditor/editor-for-vue": "^5.1.10",
|
||||
"@zoomus/websdk": "^2.3.5",
|
||||
"@zoomus/websdk": "^2.4.0",
|
||||
"axios": "^0.26.1",
|
||||
"coi-serviceworker": "^0.1.6",
|
||||
"core-js": "^3.8.3",
|
||||
"crypto-js": "^4.1.1",
|
||||
"dayjs": "^1.11.1",
|
||||
"element-plus": "^2.1.9",
|
||||
"lodash": "^4.17.21",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"vue": "^3.2.13",
|
||||
"vue-router": "^4.0.3",
|
||||
"vuex": "^4.0.0"
|
||||
|
@ -71,6 +71,11 @@ const { messageList } = toRefs(props);
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
font-size: 16px;
|
||||
:deep(p) {
|
||||
margin: 0;
|
||||
word-wrap: break-word;
|
||||
word-break:break-all;
|
||||
}
|
||||
}
|
||||
.time {
|
||||
font-size: 12px;
|
||||
|
@ -91,7 +91,7 @@ const { showDialog, mode } = toRefs(props);
|
||||
const emit = defineEmits(["close"]);
|
||||
const joinAccount = ref("");
|
||||
joinAccount.value =
|
||||
store.getters.nickname || store.getters.phone || store.getters.icCard;
|
||||
store.getters.icCard || store.getters.phone || store.getters.nickname;
|
||||
|
||||
// 加载问题列表
|
||||
const form = ref({
|
||||
@ -122,7 +122,7 @@ const submit = async (questionsRef) => {
|
||||
commitExamList: form.value.questionsList.map((item) => {
|
||||
return {
|
||||
questionId: item.id,
|
||||
choiceAnswerIdStr: item.choiceAnswerIdStr.join(","),
|
||||
choiceAnswerIdStr: item.choiceAnswerIdStr.join(",") + ",",
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
@ -1,7 +1,13 @@
|
||||
import { createWebHistory, createRouter } from "vue-router";
|
||||
import store from "@/store";
|
||||
import { whitelistJoinMeeting } from "@/api/meeting";
|
||||
import _ from "lodash";
|
||||
import cryptoJs from "crypto-js";
|
||||
|
||||
import {
|
||||
whitelistJoinMeeting,
|
||||
registerJoinUser,
|
||||
visitorJoinUser,
|
||||
} from "@/api/meeting";
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [
|
||||
@ -20,6 +26,16 @@ const router = createRouter({
|
||||
name: "Meeting",
|
||||
component: () => import("@/views/meeting.vue"),
|
||||
},
|
||||
// {
|
||||
// path: "/host/:meetingId/:hostinfo",
|
||||
// name: "Host",
|
||||
// component: () => import("@/views/host.vue"),
|
||||
// },
|
||||
{
|
||||
path: "/host/:meetingId/:pwd/:username/:nickname",
|
||||
name: "Host",
|
||||
component: () => import("@/views/host.vue"),
|
||||
},
|
||||
{
|
||||
path: "/:pathMatch(.*)*",
|
||||
name: "NotFound",
|
||||
@ -33,10 +49,32 @@ router.beforeEach(async (to) => {
|
||||
if (!store.state.meeting.id && to.params.meetingId) {
|
||||
await store.dispatch("getMeetingInfo", to.params.meetingId);
|
||||
}
|
||||
// 前往主持人页面
|
||||
if (to.name === "Host") {
|
||||
console.log("host");
|
||||
// const bytes = cryptoJs.AES.decrypt(to.params.hostinfo, "secret");
|
||||
// const decryptedData = JSON.parse(bytes.toString(cryptoJs.enc.Utf8));
|
||||
store.commit("setJoinUser", {
|
||||
nickname: to.params.nickname,
|
||||
username: to.params.username,
|
||||
});
|
||||
store.commit("setPassword", to.params.pwd);
|
||||
return true;
|
||||
}
|
||||
// 如果要前往参会页面
|
||||
if (to.name === "Meeting") {
|
||||
// 如果是白名单模式
|
||||
// 如果要去的页面会议号于 vuex中的不一样,则清除数据
|
||||
if (to.params.meetingId !== store.state.joinUser.meetingId) {
|
||||
store.commit("setJoinUser", {});
|
||||
}
|
||||
// 如果参会方式发生更改,则清除数据
|
||||
if (store.state.meeting.joinType !== store.state.joinType) {
|
||||
store.commit("setJoinUser", {});
|
||||
store.commit("setJoinType", store.state.meeting.joinType);
|
||||
return `/verify/${to.params.meetingId}`;
|
||||
}
|
||||
if (store.state.meeting.joinType === "1") {
|
||||
// 如果是白名单模式
|
||||
if (store.state.joinUser.icCard) {
|
||||
// 检测输入的IC卡号是否在白名单范围内,是则放行,否则返回原地址
|
||||
try {
|
||||
@ -55,9 +93,16 @@ router.beforeEach(async (to) => {
|
||||
return `/verify/${to.params.meetingId}`;
|
||||
}
|
||||
} else {
|
||||
if (!store.state.password) {
|
||||
if (_.isEmpty(store.state.joinUser)) {
|
||||
return `/verify/${to.params.meetingId}`;
|
||||
} else {
|
||||
if (store.state.meeting.joinType === "2") {
|
||||
const { data } = await registerJoinUser(store.state.joinUser);
|
||||
store.commit("setPassword", data);
|
||||
} else {
|
||||
const { data } = await visitorJoinUser(store.state.joinUser);
|
||||
store.commit("setPassword", data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,9 @@ const store = createStore({
|
||||
: {},
|
||||
meeting: {},
|
||||
password: "", //参会密码
|
||||
joinType: localStorage.getItem("JOINTYPE")
|
||||
? JSON.parse(localStorage.getItem("JOINTYPE"))
|
||||
: "1",
|
||||
},
|
||||
mutations: {
|
||||
// 设置参会人员信息
|
||||
@ -23,6 +26,11 @@ const store = createStore({
|
||||
// 设置参会密码
|
||||
setPassword(state, data) {
|
||||
state.password = data;
|
||||
// localStorage.setItem("PASSWORD", JSON.stringify(data));
|
||||
},
|
||||
setJoinType(state, data) {
|
||||
state.joinType = data;
|
||||
localStorage.setItem("JOINTYPE", JSON.stringify(data));
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
@ -30,6 +38,7 @@ const store = createStore({
|
||||
async getMeetingInfo(context, meetingId) {
|
||||
const { data } = await getMeetingDetailById(meetingId);
|
||||
context.commit("setMeetingInfo", data);
|
||||
// context.commit("setJoinType", data.joinType);
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
|
@ -2,6 +2,12 @@
|
||||
.meeting-title {
|
||||
font-size: 24px;
|
||||
}
|
||||
.meeting-cover {
|
||||
// width: 100%;
|
||||
height: 70vh;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.meeting-time {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
@ -2,6 +2,12 @@
|
||||
// body {
|
||||
// background-color: indianred;
|
||||
// }
|
||||
.meeting-cover {
|
||||
width: 100%;
|
||||
// height: 70vh;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.meeting-title {
|
||||
font-size: 7vw;
|
||||
}
|
||||
|
@ -449,7 +449,8 @@ loadMeetingDetail(meetingId.value);
|
||||
@import "@/style/appoint-desktop.scss";
|
||||
|
||||
.meeting-cover {
|
||||
width: 100%;
|
||||
// width: 100%;
|
||||
height: 50vh;
|
||||
}
|
||||
.meeting-title {
|
||||
text-align: center;
|
||||
|
550
src/views/host.vue
Normal file
550
src/views/host.vue
Normal file
@ -0,0 +1,550 @@
|
||||
<template>
|
||||
<div
|
||||
id="app-container"
|
||||
v-loading="isMeetingLoading"
|
||||
element-loading-text="会议正在加载中"
|
||||
ref="appContainer"
|
||||
>
|
||||
<div class="row">
|
||||
<div class="meeting-container" ref="meetingContainerRef">
|
||||
<div id="video-element" ref="videoElementRef"></div>
|
||||
<el-button @click="setFullScreen" class="fullscreen-btn">
|
||||
全屏</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="chat-right" ref="chatRightRef">
|
||||
<messageList :messageList="messages"></messageList>
|
||||
<div class="option-bar">
|
||||
<!-- <el-input
|
||||
v-model="editingMessage"
|
||||
style="margin-right: 15px"
|
||||
></el-input> -->
|
||||
<div
|
||||
class="display-message"
|
||||
v-html="editingMessage"
|
||||
@click="showRichEditor = true"
|
||||
></div>
|
||||
<!-- <wangEditor v-model="editingMessage" :height="`100px`"></wangEditor> -->
|
||||
<!-- <div class="btns"> -->
|
||||
<!-- <el-button type="success" @click="showRichEditor = true"
|
||||
>高级输入框</el-button
|
||||
> -->
|
||||
<el-button
|
||||
type="success"
|
||||
@click="sendMessage"
|
||||
:disabled="editingMessage.length === 0"
|
||||
>发送</el-button
|
||||
>
|
||||
<!-- </div> -->
|
||||
</div>
|
||||
</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 < 768"
|
||||
><div class="meeting-info chat">
|
||||
<messageList :messageList="messages"></messageList>
|
||||
<div class="option-bar">
|
||||
<el-input
|
||||
v-model="editingMessage"
|
||||
style="margin-right: 15px"
|
||||
></el-input>
|
||||
<!-- <wangEditor
|
||||
v-model="editingMessage"
|
||||
height="100px"
|
||||
style="margin-right: 15px"
|
||||
></wangEditor> -->
|
||||
<!-- <svg-icon :icon-class="search" style="height: 30px; width: 16px" /> -->
|
||||
<el-button
|
||||
type="success"
|
||||
@click="sendMessage"
|
||||
:disabled="editingMessage.length === 0"
|
||||
>发送</el-button
|
||||
>
|
||||
</div>
|
||||
</div></el-tab-pane
|
||||
>
|
||||
</el-tabs>
|
||||
|
||||
<el-dialog title="高级输入框" v-model="showRichEditor">
|
||||
<wangEditor v-model="editingMessage" width="100%"></wangEditor>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="showRichEditor = false"
|
||||
>确定</el-button
|
||||
>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed, reactive, watch, ref, onMounted, onUnmounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { signMeeting, generateSignature } from "@/api/meeting";
|
||||
import wangEditor from "@/components/wangEditor";
|
||||
import messageList from "@/components/messageList";
|
||||
import dayjs from "dayjs";
|
||||
import ReconnectingWebSocket from "reconnecting-websocket";
|
||||
import ZoomMtgEmbedded from "@zoomus/websdk/embedded";
|
||||
import _ from "lodash";
|
||||
// import { FullScreen } from "@element-plus/icons-vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { useRoute } from "vue-router";
|
||||
const route = useRoute();
|
||||
const store = useStore();
|
||||
console.log(route.name);
|
||||
const showRichEditor = ref(false);
|
||||
const meetingNote = computed(() => store.getters.meetingNote); // 会议介绍
|
||||
const meetingSchedule = computed(() => store.getters.meetingSchedule); // 会议日程
|
||||
const expertInfo = computed(() => store.getters.expertInfo); // 专家信息
|
||||
const isMeetingLoading = ref(true); // 视频课件是否正在加载
|
||||
const templateId = ref(1); // 布局 id
|
||||
if (store.getters.templateId) {
|
||||
templateId.value = store.getters.templateId;
|
||||
}
|
||||
const joinAccount = ref(""); // 参会账号
|
||||
const joinName = ref(""); // 参会名称
|
||||
const screenWidth = ref(0); // 屏幕宽度
|
||||
const meetingWidth = ref(0); // 视频课件容器元素宽度
|
||||
const meetingHeight = ref(0); // 视频课件容器元素高度
|
||||
screenWidth.value = document.body.offsetWidth;
|
||||
|
||||
// screenWidth.value = window.innerWidth;
|
||||
if (route.name === "Host") {
|
||||
joinAccount.value = store.getters.username;
|
||||
joinName.value = store.getters.nickname;
|
||||
} else {
|
||||
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); // 视频课件容器元素
|
||||
const chatRightRef = ref(null); // 右侧聊天元素
|
||||
const appContainer = ref(null);
|
||||
onMounted(() => {
|
||||
// appContainer.value.style.width = window.innerWidth;
|
||||
console.log(window.innerWidth);
|
||||
meetingContainerRef.value.style.background = `url(${store.getters.templateBackgroundPic}) 0% 0% / cover no-repeat`; // 设置背景图片
|
||||
setTextLabel();
|
||||
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.95;
|
||||
meetingHeight.value = (meetingWidth.value * 9) / 16;
|
||||
videoElementRef.value.style.width = meetingWidth.value + "px";
|
||||
videoElementRef.value.style.height = meetingHeight.value + "px";
|
||||
chatRightRef.value.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");
|
||||
console.log(labelObj);
|
||||
textEl.id = `${_.uniqueId("tag-")}`;
|
||||
textEl.innerHTML = labelObj.content;
|
||||
textEl.className = "text-tag";
|
||||
// console.log(labelObj);
|
||||
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);
|
||||
});
|
||||
};
|
||||
// console.log(to.);
|
||||
// 会议配置
|
||||
const meetingConfig = reactive({
|
||||
client: ZoomMtgEmbedded.createClient(),
|
||||
// This Sample App has been updated to use SDK App type credentials https://marketplace.zoom.us/docs/guides/build/sdk-app
|
||||
sdkKey: "TUgbQFx4RhPHDPa0OQAKVgPL2dPGQoVqZIuW",
|
||||
meetingNumber: store.getters.meetingNumber,
|
||||
passWord: store.state.password,
|
||||
role: route.name === "Host" ? 1 : 0,
|
||||
// signatureEndpoint: "http://120.26.107.74:4000",
|
||||
userEmail: "",
|
||||
userName: joinName.value,
|
||||
// pass in the registrant's token if your meeting or webinar requires registration. More info here:
|
||||
// Meetings: https://marketplace.zoom.us/docs/sdk/native-sdks/web/component-view/meetings#join-registered
|
||||
// Webinars: https://marketplace.zoom.us/docs/sdk/native-sdks/web/component-view/webinars#join-registered
|
||||
registrantToken: "",
|
||||
});
|
||||
console.log(meetingConfig);
|
||||
const checkMedia = async () => {
|
||||
const result = {};
|
||||
try {
|
||||
await navigator.mediaDevices.getUserMedia({ video: true });
|
||||
result.video = true;
|
||||
} catch (error) {
|
||||
result.video = false;
|
||||
}
|
||||
try {
|
||||
await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
result.audio = true;
|
||||
} catch (error) {
|
||||
result.audio = false;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const getSignature = async () => {
|
||||
const { sign } = await generateSignature({
|
||||
meetingNumber: store.getters.meetingNumber,
|
||||
role: meetingConfig.role,
|
||||
});
|
||||
startMeeting(sign);
|
||||
};
|
||||
|
||||
const startMeeting = async (signature) => {
|
||||
let meetingSDKElement = document.getElementById("video-element");
|
||||
try {
|
||||
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 - 45,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
meetingInfo: [
|
||||
"topic",
|
||||
"host",
|
||||
"mn",
|
||||
"pwd",
|
||||
"telPwd",
|
||||
"invite",
|
||||
"participant",
|
||||
"dc",
|
||||
"enctype",
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
await meetingConfig.client.join({
|
||||
sdkKey: meetingConfig.sdkKey,
|
||||
signature: signature,
|
||||
meetingNumber: meetingConfig.meetingNumber,
|
||||
password: meetingConfig.passWord,
|
||||
userName: meetingConfig.userName,
|
||||
userEmail: meetingConfig.userEmail,
|
||||
tk: meetingConfig.registrantToken,
|
||||
});
|
||||
initDesktopLayout();
|
||||
isMeetingLoading.value = false;
|
||||
} catch (error) {
|
||||
isMeetingLoading.value = false;
|
||||
}
|
||||
// console.log(meetingConfig.client.checkSystemRequirements());
|
||||
// document.querySelector("#suspension-view-tab-thumbnail-speaker").click();
|
||||
};
|
||||
const setFullScreen = () => {
|
||||
videoElementRef.value.requestFullscreen();
|
||||
};
|
||||
onMounted(() => {
|
||||
getSignature();
|
||||
});
|
||||
// 初始化
|
||||
const initDesktopLayout = () => {
|
||||
console.log(meetingHeight.value);
|
||||
// 切换到 gallery view
|
||||
document.querySelector("#suspension-view-tab-thumbnail-gallery").click();
|
||||
// 初始化高度
|
||||
const heightEl =
|
||||
document.querySelector(
|
||||
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-166.zmwebsdk-makeStyles-root-170"
|
||||
) ||
|
||||
document.querySelector(
|
||||
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-176.zmwebsdk-makeStyles-root-180"
|
||||
);
|
||||
heightEl.style.height = `${meetingHeight.value - 45}px`;
|
||||
|
||||
// 初始化宽度
|
||||
|
||||
document.querySelector(
|
||||
".zmwebsdk-MuiPaper-root.zmwebsdk-makeStyles-root-21.zmwebsdk-MuiPaper-elevation1.zmwebsdk-MuiPaper-rounded"
|
||||
).style.width = `${meetingWidth.value - 4}px`;
|
||||
// 加载完成显示 video element
|
||||
document.querySelector("#video-element").style.visibility = "visible";
|
||||
};
|
||||
// 检测屏幕共享开启状态变化
|
||||
const inSharing = ref(false); // 是否开启屏幕共享
|
||||
setInterval(() => {
|
||||
const elSharing = document.querySelector(".zmwebsdk-makeStyles-inSharing-46");
|
||||
// console.log(elSharing);
|
||||
if (elSharing) {
|
||||
inSharing.value = true;
|
||||
} else {
|
||||
inSharing.value = false;
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// 根据id设置布局
|
||||
const setLayout = (templateId) => {
|
||||
console.log(templateId);
|
||||
const v_s_wrap_el =
|
||||
document.querySelector(
|
||||
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-166.zmwebsdk-makeStyles-root-170"
|
||||
) ||
|
||||
document.querySelector(
|
||||
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-176.zmwebsdk-makeStyles-root-180"
|
||||
);
|
||||
v_s_wrap_el.style.flexDirection = "";
|
||||
|
||||
const v_wrap_el =
|
||||
document.querySelector(
|
||||
".zmwebsdk-makeStyles-wrap-167.zmwebsdk-makeStyles-wrap-171"
|
||||
) ||
|
||||
document.querySelector(
|
||||
".zmwebsdk-makeStyles-wrap-177.zmwebsdk-makeStyles-wrap-181"
|
||||
);
|
||||
if (templateId === "1" && inSharing.value) {
|
||||
v_wrap_el.style.width = `${meetingWidth.value / 2 - 2}px`;
|
||||
} else if (templateId === "2" && inSharing.value) {
|
||||
v_wrap_el.style.width = `${meetingWidth.value / 2 - 2}px`;
|
||||
v_s_wrap_el.style.flexDirection = "row-reverse";
|
||||
} else if (templateId === "3" && inSharing.value) {
|
||||
v_wrap_el.style.width = `${(meetingWidth.value - 4) / 4}px`;
|
||||
} else if (templateId === "4" && inSharing.value) {
|
||||
v_wrap_el.style.width = `${(meetingWidth.value - 4) / 4}px`;
|
||||
v_s_wrap_el.style.flexDirection = "row-reverse";
|
||||
}
|
||||
};
|
||||
|
||||
watch(inSharing, (newVal) => {
|
||||
console.log(newVal);
|
||||
if (newVal) {
|
||||
setLayout(templateId.value);
|
||||
} else {
|
||||
const galleryViewButton = document.querySelector(
|
||||
"#suspension-view-tab-thumbnail-gallery"
|
||||
);
|
||||
galleryViewButton.click();
|
||||
document.querySelector(".zmwebsdk-makeStyles-wrap-171").style.width = "";
|
||||
document.querySelector(
|
||||
".zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-166.zmwebsdk-makeStyles-root-170"
|
||||
).style.flexDirection = "";
|
||||
}
|
||||
});
|
||||
|
||||
let socket = reactive({});
|
||||
const initWebSocket = () => {
|
||||
// 建立websocket连接
|
||||
socket = new ReconnectingWebSocket(
|
||||
`wss://meeting.chuhuankj.com/wss/websocket/meeting/${store.getters.meetingId}/${joinAccount.value}`
|
||||
);
|
||||
socket.addEventListener("open", () => {
|
||||
// socket.send("Hello Server!");
|
||||
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(data.content));
|
||||
messages.value.push({
|
||||
...JSON.parse(data.content),
|
||||
id: _.uniqueId(),
|
||||
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
});
|
||||
}
|
||||
|
||||
// 会议结束时
|
||||
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 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 messages = ref([]); // 消息列表
|
||||
const editingMessage = ref(""); // 正在编辑的内容
|
||||
// 发送消息
|
||||
const sendMessage = () => {
|
||||
console.log(socket);
|
||||
socket.send(editingMessage.value);
|
||||
messages.value.push({
|
||||
id: _.uniqueId(),
|
||||
account: joinName.value,
|
||||
msg: editingMessage.value,
|
||||
isMe: true,
|
||||
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
});
|
||||
editingMessage.value = "";
|
||||
};
|
||||
|
||||
const leaveConference = () => {
|
||||
meetingConfig.client.leaveMeeting();
|
||||
};
|
||||
window.addEventListener("beforeunload", leaveConference);
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("beforeunload", leaveConference);
|
||||
});
|
||||
|
||||
// 是否显示考试和问卷弹窗
|
||||
const showExamDialog = ref(false);
|
||||
const showQuestionnaireDialog = ref(false);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
#app-container {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
:deep(.text-tag) {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
background-color: #fff;
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
.meeting-container {
|
||||
position: relative;
|
||||
width: 80%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chat-right {
|
||||
width: 20%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.option-bar {
|
||||
margin-top: 0;
|
||||
margin: 5px;
|
||||
.display-message {
|
||||
border: 1px solid #666;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
border-radius: 5px;
|
||||
margin-right: 5px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
:deep(.message-list) {
|
||||
overflow-y: scroll;
|
||||
margin-bottom: 0;
|
||||
// height: 80%;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.meeting-container {
|
||||
width: 100%;
|
||||
}
|
||||
.chat-right {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
#video-element {
|
||||
visibility: hidden;
|
||||
// height: 600px;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
width: 100%;
|
||||
.meeting-info {
|
||||
:deep(p) {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
// :deep(.el-tabs__content) {
|
||||
// .chat {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
.option-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
}
|
||||
:deep(.zmwebsdk-MuiPaper-root) {
|
||||
background: transparent;
|
||||
box-shadow: 0 0;
|
||||
}
|
||||
|
||||
:deep(.zmwebsdk-MuiToolbar-root) {
|
||||
display: none;
|
||||
}
|
||||
:deep(.zmwebsdk-makeStyles-singleView-7) {
|
||||
// background-color: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
.fullscreen-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
</style>
|
@ -1,7 +1,28 @@
|
||||
<template>
|
||||
<div id="app-container" ref="appContainer">
|
||||
<div id="app-container" v-loading="isMeetingLoading" ref="appContainer">
|
||||
<div class="row">
|
||||
<div class="meeting-container" ref="meetingContainerRef">
|
||||
<div id="video-element"></div>
|
||||
<div id="video-element" ref="videoElementRef"></div>
|
||||
<el-button @click="setFullScreen" class="fullscreen-btn">
|
||||
<!-- <FullScreen></FullScreen> -->
|
||||
全屏</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="chat-right" ref="chatRightRef">
|
||||
<messageList :messageList="messages"></messageList>
|
||||
<div class="option-bar">
|
||||
<el-input
|
||||
v-model="editingMessage"
|
||||
style="margin-right: 15px"
|
||||
></el-input>
|
||||
<el-button
|
||||
type="success"
|
||||
@click="sendMessage"
|
||||
:disabled="editingMessage.length === 0"
|
||||
>发送</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-tabs class="tabs" type="border-card">
|
||||
@ -17,15 +38,15 @@
|
||||
<el-tab-pane label="专家介绍"
|
||||
><div class="meeting-info expert-info" v-html="expertInfo"></div
|
||||
></el-tab-pane>
|
||||
<el-tab-pane label="聊天"
|
||||
<el-tab-pane label="聊天" class="chat-pane" v-if="screenWidth < 768"
|
||||
><div class="meeting-info chat">
|
||||
<messageList :messageList="messages"></messageList>
|
||||
<div class="option-bar">
|
||||
<wangEditor
|
||||
<el-input
|
||||
v-model="editingMessage"
|
||||
height="100px"
|
||||
width="80%"
|
||||
></wangEditor>
|
||||
style="margin-right: 15px"
|
||||
></el-input>
|
||||
<!-- <svg-icon :icon-class="search" style="height: 30px; width: 16px" /> -->
|
||||
<el-button
|
||||
type="success"
|
||||
@click="sendMessage"
|
||||
@ -55,58 +76,70 @@
|
||||
</el-dialog>
|
||||
<questions
|
||||
mode="1"
|
||||
v-if="showExamDialog"
|
||||
:showDialog="showExamDialog"
|
||||
@close="showExamDialog = $event"
|
||||
></questions>
|
||||
|
||||
<questions
|
||||
mode="2"
|
||||
v-if="showQuestionnaireDialog"
|
||||
:showDialog="showQuestionnaireDialog"
|
||||
@close="showQuestionnaireDialog = $event"
|
||||
></questions>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed, reactive, watch, ref, onMounted } from "vue";
|
||||
import { computed, reactive, watch, ref, onMounted, onUnmounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { signMeeting, generateSignature } from "@/api/meeting";
|
||||
import wangEditor from "@/components/wangEditor";
|
||||
import questions from "@/components/questions";
|
||||
import messageList from "@/components/messageList";
|
||||
import dayjs from "dayjs";
|
||||
import ZoomMtgEmbedded from "@zoomus/websdk/embedded";
|
||||
import axios from "axios";
|
||||
import _ from "lodash";
|
||||
|
||||
// import { FullScreen } from "@element-plus/icons-vue";
|
||||
import ReconnectingWebSocket from "reconnecting-websocket";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
import { useRoute } from "vue-router";
|
||||
const route = useRoute();
|
||||
const store = useStore();
|
||||
|
||||
const meetingNote = computed(() => store.getters.meetingNote);
|
||||
const meetingSchedule = computed(() => store.getters.meetingSchedule);
|
||||
const expertInfo = computed(() => store.getters.expertInfo);
|
||||
|
||||
const templateId = ref(1);
|
||||
console.log(route.name);
|
||||
const meetingNote = computed(() => store.getters.meetingNote); // 会议介绍
|
||||
const meetingSchedule = computed(() => store.getters.meetingSchedule); // 会议日程
|
||||
const expertInfo = computed(() => store.getters.expertInfo); // 专家信息
|
||||
const isMeetingLoading = ref(true); // 视频课件是否正在加载
|
||||
const templateId = ref(1); // 布局 id
|
||||
if (store.getters.templateId) {
|
||||
templateId.value = store.getters.templateId;
|
||||
}
|
||||
const joinAccount = ref("");
|
||||
joinAccount.value =
|
||||
const joinAccount = ref(""); // 参会账号
|
||||
const joinName = ref(""); // 参会名称
|
||||
const screenWidth = ref(0); // 屏幕宽度
|
||||
const meetingWidth = ref(0); // 视频课件容器元素宽度
|
||||
const meetingHeight = ref(0); // 视频课件容器元素高度
|
||||
screenWidth.value = document.body.offsetWidth;
|
||||
if (route.name === "Host") {
|
||||
joinAccount.value = route.params.username;
|
||||
joinName.value = route.params.nickname;
|
||||
} else {
|
||||
joinAccount.value =
|
||||
store.getters.icCard || store.getters.phone || store.getters.nickname;
|
||||
joinName.value =
|
||||
store.getters.nickname || store.getters.phone || store.getters.icCard;
|
||||
const meetingWidth = ref(0);
|
||||
const meetingHeight = ref(0);
|
||||
}
|
||||
// 设置会议背景大小、图片
|
||||
const meetingContainerRef = ref(null);
|
||||
const meetingContainerRef = ref(null); // 会议容器元素(包含背景)
|
||||
const videoElementRef = ref(null); // 视频课件容器元素
|
||||
const chatRightRef = ref(null); // 右侧聊天元素
|
||||
onMounted(() => {
|
||||
meetingContainerRef.value.style.background = `url(${store.getters.templateBackgroundPic}) 0% 0% / cover no-repeat`;
|
||||
meetingContainerRef.value.style.background = `url(${store.getters.templateBackgroundPic}) 0% 0% / cover no-repeat`; // 设置背景图片
|
||||
setTextLabel();
|
||||
console.log(meetingContainerRef.value.offsetWidth);
|
||||
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.8;
|
||||
meetingHeight.value = (meetingWidth.value * 3) / 4;
|
||||
document.querySelector("#video-element").style.width =
|
||||
meetingWidth.value + "px";
|
||||
document.querySelector("#video-element").style.height =
|
||||
meetingHeight.value + "px";
|
||||
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.95;
|
||||
meetingHeight.value = (meetingWidth.value * 9) / 16;
|
||||
videoElementRef.value.style.width = meetingWidth.value + "px";
|
||||
videoElementRef.value.style.height = meetingHeight.value + "px";
|
||||
chatRightRef.value.style.height = meetingHeight.value + "px";
|
||||
});
|
||||
|
||||
// 设置文本标签
|
||||
@ -117,31 +150,38 @@ const setTextLabel = () => {
|
||||
store.getters.textLabelList.forEach((item) => {
|
||||
const labelObj = JSON.parse(item.textLabel);
|
||||
const textEl = document.createElement("div");
|
||||
console.log(labelObj);
|
||||
textEl.id = `${_.uniqueId("tag-")}`;
|
||||
textEl.innerHTML = labelObj.content;
|
||||
textEl.className = "text-tag";
|
||||
console.log(labelObj);
|
||||
// console.log(labelObj);
|
||||
textEl.style.backgroundColor = labelObj.backgroundColor;
|
||||
textEl.style.visibility =
|
||||
labelObj.visibility === "1" ? "visible" : "hidden";
|
||||
|
||||
textEl.style.left = `${labelObj.x}`;
|
||||
textEl.style.top = `${labelObj.y}`;
|
||||
document.querySelector(".meeting-container").appendChild(textEl);
|
||||
meetingContainerRef.value.appendChild(textEl);
|
||||
});
|
||||
};
|
||||
|
||||
// console.log(to.);
|
||||
// 会议配置
|
||||
const meetingConfig = reactive({
|
||||
client: ZoomMtgEmbedded.createClient(),
|
||||
// This Sample App has been updated to use SDK App type credentials https://marketplace.zoom.us/docs/guides/build/sdk-app
|
||||
sdkKey: "TUgbQFx4RhPHDPa0OQAKVgPL2dPGQoVqZIuW",
|
||||
meetingNumber: store.getters.meetingNumber,
|
||||
passWord: store.state.password,
|
||||
role: 0,
|
||||
role: route.name === "Host" ? 1 : 0,
|
||||
// signatureEndpoint: "http://120.26.107.74:4000",
|
||||
userEmail: "",
|
||||
userName: joinAccount.value,
|
||||
userName: joinName.value,
|
||||
// pass in the registrant's token if your meeting or webinar requires registration. More info here:
|
||||
// Meetings: https://marketplace.zoom.us/docs/sdk/native-sdks/web/component-view/meetings#join-registered
|
||||
// Webinars: https://marketplace.zoom.us/docs/sdk/native-sdks/web/component-view/webinars#join-registered
|
||||
registrantToken: "",
|
||||
});
|
||||
console.log(meetingConfig);
|
||||
const checkMedia = async () => {
|
||||
const result = {};
|
||||
try {
|
||||
@ -158,27 +198,18 @@ const checkMedia = async () => {
|
||||
}
|
||||
return result;
|
||||
};
|
||||
// const signature = ref("");
|
||||
|
||||
const getSignature = async () => {
|
||||
const { sign } = await generateSignature({
|
||||
meetingNumber: store.getters.meetingNumber,
|
||||
role: meetingConfig.role,
|
||||
});
|
||||
// signature.value = sign;
|
||||
startMeeting(sign);
|
||||
// const res = await checkMedia();
|
||||
// if (!res.audio || !res.video) {
|
||||
// return ElMessageBox.alert(
|
||||
// `摄像头状态 : ${res.video ? "可用" : "禁用"}\n麦克风状态 : ${
|
||||
// res.audio ? "可用" : "禁用"
|
||||
// }`
|
||||
// );
|
||||
// }
|
||||
};
|
||||
|
||||
const startMeeting = async (signature) => {
|
||||
let meetingSDKElement = document.getElementById("video-element");
|
||||
|
||||
console.log(meetingConfig);
|
||||
try {
|
||||
meetingConfig.client.init({
|
||||
debug: true,
|
||||
zoomAppRoot: meetingSDKElement,
|
||||
@ -192,7 +223,7 @@ const startMeeting = async (signature) => {
|
||||
viewSizes: {
|
||||
default: {
|
||||
width: meetingWidth.value,
|
||||
height: meetingHeight.value,
|
||||
height: meetingHeight.value - 45,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -208,19 +239,9 @@ const startMeeting = async (signature) => {
|
||||
"dc",
|
||||
"enctype",
|
||||
],
|
||||
// toolbar: {
|
||||
// buttons: [
|
||||
// {
|
||||
// text: "Custom Button",
|
||||
// className: "CustomButton",
|
||||
// onClick: () => {
|
||||
// console.log("custom button");
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
},
|
||||
});
|
||||
|
||||
await meetingConfig.client.join({
|
||||
sdkKey: meetingConfig.sdkKey,
|
||||
signature: signature,
|
||||
@ -230,22 +251,41 @@ const startMeeting = async (signature) => {
|
||||
userEmail: meetingConfig.userEmail,
|
||||
tk: meetingConfig.registrantToken,
|
||||
});
|
||||
// console.log(meetingConfig.client.checkSystemRequirements());
|
||||
initDesktopLayout();
|
||||
isMeetingLoading.value = false;
|
||||
} catch (error) {
|
||||
isMeetingLoading.value = false;
|
||||
}
|
||||
// console.log(meetingConfig.client.checkSystemRequirements());
|
||||
// document.querySelector("#suspension-view-tab-thumbnail-speaker").click();
|
||||
};
|
||||
const setFullScreen = () => {
|
||||
videoElementRef.value.requestFullscreen();
|
||||
};
|
||||
onMounted(() => {
|
||||
getSignature();
|
||||
});
|
||||
// 初始化
|
||||
const initDesktopLayout = () => {
|
||||
console.log(meetingHeight.value);
|
||||
// 切换到 gallery view
|
||||
document.querySelector("#suspension-view-tab-thumbnail-gallery").click();
|
||||
// 初始化高度
|
||||
document.querySelector(".MuiBox-root.jss167.jss161.jss165").style.height = `${
|
||||
meetingHeight.value - 45
|
||||
}px`;
|
||||
// 初始化宽度
|
||||
const heightEl =
|
||||
document.querySelector(
|
||||
".MuiPaper-root.jss25.MuiPaper-elevation1.MuiPaper-rounded"
|
||||
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-166.zmwebsdk-makeStyles-root-170"
|
||||
) ||
|
||||
document.querySelector(
|
||||
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-176.zmwebsdk-makeStyles-root-180"
|
||||
);
|
||||
heightEl.style.height = `${meetingHeight.value - 45}px`;
|
||||
// document.querySelector(
|
||||
// ".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-166.zmwebsdk-makeStyles-root-170"
|
||||
// ).style.height = `${meetingHeight.value - 45}px`;
|
||||
// 初始化宽度
|
||||
//
|
||||
document.querySelector(
|
||||
".zmwebsdk-MuiPaper-root.zmwebsdk-makeStyles-root-21.zmwebsdk-MuiPaper-elevation1.zmwebsdk-MuiPaper-rounded"
|
||||
).style.width = `${meetingWidth.value - 4}px`;
|
||||
// 加载完成显示 video element
|
||||
document.querySelector("#video-element").style.visibility = "visible";
|
||||
@ -253,44 +293,49 @@ const initDesktopLayout = () => {
|
||||
// 检测屏幕共享开启状态变化
|
||||
const inSharing = ref(false); // 是否开启屏幕共享
|
||||
setInterval(() => {
|
||||
const elSharing = document.querySelector(".jss51");
|
||||
const elSharing = document.querySelector(".zmwebsdk-makeStyles-inSharing-46");
|
||||
// console.log(elSharing);
|
||||
if (elSharing) {
|
||||
if (elSharing.className.includes("in-sharing")) {
|
||||
// if (elSharing.className.includes("in-sharing")) {
|
||||
// inSharing.value = true;
|
||||
// } else {
|
||||
// inSharing.value = false;
|
||||
// }
|
||||
inSharing.value = true;
|
||||
} else {
|
||||
inSharing.value = false;
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// 根据id设置布局
|
||||
const setLayout = (templateId) => {
|
||||
console.log(templateId);
|
||||
const v_s_wrap_el =
|
||||
document.querySelector(
|
||||
".MuiBox-root.jss167.jss161.jss165"
|
||||
).style.flexDirection = "";
|
||||
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-166.zmwebsdk-makeStyles-root-170"
|
||||
) ||
|
||||
document.querySelector(
|
||||
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-176.zmwebsdk-makeStyles-root-180"
|
||||
);
|
||||
v_s_wrap_el.style.flexDirection = "";
|
||||
|
||||
const v_wrap_el =
|
||||
document.querySelector(
|
||||
".zmwebsdk-makeStyles-wrap-167.zmwebsdk-makeStyles-wrap-171"
|
||||
) ||
|
||||
document.querySelector(
|
||||
".zmwebsdk-makeStyles-wrap-177.zmwebsdk-makeStyles-wrap-181"
|
||||
);
|
||||
if (templateId === "1" && inSharing.value) {
|
||||
document.querySelector(".jss162.jss166").style.width = `${
|
||||
meetingWidth.value / 2 - 2
|
||||
}px`;
|
||||
v_wrap_el.style.width = `${meetingWidth.value / 2 - 2}px`;
|
||||
} else if (templateId === "2" && inSharing.value) {
|
||||
document.querySelector(".jss162.jss166").style.width = `${
|
||||
meetingWidth.value / 2 - 2
|
||||
}px`;
|
||||
document.querySelector(
|
||||
".MuiBox-root.jss167.jss161.jss165"
|
||||
).style.flexDirection = "row-reverse";
|
||||
v_wrap_el.style.width = `${meetingWidth.value / 2 - 2}px`;
|
||||
v_s_wrap_el.style.flexDirection = "row-reverse";
|
||||
} else if (templateId === "3" && inSharing.value) {
|
||||
document.querySelector(".jss162.jss166").style.width = `${
|
||||
(meetingWidth.value - 4) / 4
|
||||
}px`;
|
||||
v_wrap_el.style.width = `${(meetingWidth.value - 4) / 4}px`;
|
||||
} else if (templateId === "4" && inSharing.value) {
|
||||
document.querySelector(".jss162.jss166").style.width = `${
|
||||
(meetingWidth.value - 4) / 4
|
||||
}px`;
|
||||
document.querySelector(
|
||||
".MuiBox-root.jss167.jss161.jss165"
|
||||
).style.flexDirection = "row-reverse";
|
||||
v_wrap_el.style.width = `${(meetingWidth.value - 4) / 4}px`;
|
||||
v_s_wrap_el.style.flexDirection = "row-reverse";
|
||||
}
|
||||
};
|
||||
watch(inSharing, (newVal) => {
|
||||
@ -304,39 +349,27 @@ watch(inSharing, (newVal) => {
|
||||
"#suspension-view-tab-thumbnail-gallery"
|
||||
);
|
||||
galleryViewButton.click();
|
||||
document.querySelector(".jss162.jss166").style.width = "";
|
||||
document.querySelector(".zmwebsdk-makeStyles-wrap-171").style.width = "";
|
||||
document.querySelector(
|
||||
".MuiBox-root.jss167.jss161.jss165"
|
||||
".zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-166.zmwebsdk-makeStyles-root-170"
|
||||
).style.flexDirection = "";
|
||||
}
|
||||
});
|
||||
|
||||
getSignature();
|
||||
|
||||
// 建立websocket连接
|
||||
const socket = new WebSocket(
|
||||
`ws://118.195.192.58:1618/websocket/meeting/${store.getters.meetingId}/${joinAccount.value}`
|
||||
);
|
||||
socket.addEventListener("open", () => {
|
||||
// const reconnectCount = ref(0); //重连次数
|
||||
let socket = reactive({});
|
||||
const initWebSocket = () => {
|
||||
// 建立websocket连接
|
||||
socket = new ReconnectingWebSocket(
|
||||
`wss://meeting.chuhuankj.com/wss/websocket/meeting/${store.getters.meetingId}/${joinAccount.value}`
|
||||
);
|
||||
socket.addEventListener("open", () => {
|
||||
// socket.send("Hello Server!");
|
||||
console.log("websocket,已连接");
|
||||
});
|
||||
|
||||
/* 签到功能 */
|
||||
// 提交签到
|
||||
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("签到成功");
|
||||
};
|
||||
|
||||
// 监听websocket消息
|
||||
socket.addEventListener("message", async (event) => {
|
||||
// 监听websocket消息
|
||||
socket.addEventListener("message", async (event) => {
|
||||
const data = JSON.parse(JSON.parse(event.data));
|
||||
console.log(data);
|
||||
// 会议信息更新时
|
||||
@ -378,8 +411,29 @@ socket.addEventListener("message", async (event) => {
|
||||
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 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 messages = ref([]); // 消息列表
|
||||
@ -390,7 +444,7 @@ const sendMessage = () => {
|
||||
socket.send(editingMessage.value);
|
||||
messages.value.push({
|
||||
id: _.uniqueId(),
|
||||
account: joinAccount.value,
|
||||
account: joinName.value,
|
||||
msg: editingMessage.value,
|
||||
isMe: true,
|
||||
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
@ -398,13 +452,21 @@ const sendMessage = () => {
|
||||
editingMessage.value = "";
|
||||
};
|
||||
|
||||
const leaveConference = () => {
|
||||
meetingConfig.client.leaveMeeting();
|
||||
};
|
||||
window.addEventListener("beforeunload", leaveConference);
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("beforeunload", leaveConference);
|
||||
});
|
||||
|
||||
// 是否显示考试和问卷弹窗
|
||||
const showExamDialog = ref(false);
|
||||
const showQuestionnaireDialog = ref(false);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
#app-container {
|
||||
width: 85%;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
:deep(.text-tag) {
|
||||
position: absolute;
|
||||
@ -418,14 +480,49 @@ const showQuestionnaireDialog = ref(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
.meeting-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
width: 80%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chat-right {
|
||||
width: 20%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.option-bar {
|
||||
margin-top: 0;
|
||||
margin: 5px;
|
||||
}
|
||||
:deep(.message-list) {
|
||||
overflow-y: scroll;
|
||||
margin-bottom: 0;
|
||||
// height: 80%;
|
||||
flex: 1;
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.meeting-container {
|
||||
width: 100%;
|
||||
}
|
||||
.chat-right {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
#video-element {
|
||||
visibility: hidden;
|
||||
// height: 600px;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
@ -435,25 +532,31 @@ const showQuestionnaireDialog = ref(false);
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
:deep(.el-tabs__content) {
|
||||
.chat {
|
||||
.option-bar {
|
||||
// :deep(.el-tabs__content) {
|
||||
// .chat {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
.option-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.MuiPaper-root) {
|
||||
:deep(.zmwebsdk-MuiPaper-root) {
|
||||
background: transparent;
|
||||
box-shadow: 0 0;
|
||||
}
|
||||
:deep(.MuiToolbar-root) {
|
||||
|
||||
:deep(.zmwebsdk-MuiToolbar-root) {
|
||||
display: none;
|
||||
}
|
||||
:deep(.MuiPaper-root.jss2.jss9.MuiPaper-elevation1.MuiPaper-rounded) {
|
||||
:deep(.zmwebsdk-makeStyles-singleView-7) {
|
||||
// background-color: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
.fullscreen-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -335,11 +335,7 @@
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, toRefs } from "vue";
|
||||
import {
|
||||
whitelistJoinMeeting,
|
||||
registerJoinUser,
|
||||
visitorJoinUser,
|
||||
} from "@/api/meeting";
|
||||
import { registerJoinUser, visitorJoinUser } from "@/api/meeting";
|
||||
import { useStore } from "vuex";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
|
||||
@ -570,9 +566,12 @@ const submitVerify = async (newJoinUserRef) => {
|
||||
@import "@/style/appoint-mobile.scss";
|
||||
@import "@/style/appoint-desktop.scss";
|
||||
|
||||
.meeting-cover {
|
||||
width: 100%;
|
||||
}
|
||||
// .meeting-cover {
|
||||
// // width: 100%;
|
||||
// height: 70vh;
|
||||
// display: block;
|
||||
// margin: 0 auto;
|
||||
// }
|
||||
.meeting-title {
|
||||
text-align: center;
|
||||
}
|
||||
|
18
yarn.lock
18
yarn.lock
@ -1952,10 +1952,10 @@
|
||||
resolved "https://registry.npmmirror.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
|
||||
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
|
||||
|
||||
"@zoomus/websdk@^2.3.5":
|
||||
version "2.3.5"
|
||||
resolved "https://registry.npmmirror.com/@zoomus/websdk/-/websdk-2.3.5.tgz#3d8bf39d0561ab4a4aa39eca4dda08db3a9aa6b0"
|
||||
integrity sha512-EAgeoh6CV22ljO8AFbRV7Zv6APL66JuUt/EKqQwcnDRW8T9/dyFFsZF3OqJAjSE2eU3k9FR827dUk9ecTGTbXg==
|
||||
"@zoomus/websdk@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.npmmirror.com/@zoomus/websdk/-/websdk-2.4.0.tgz#cc1ca3af63ca9406589ae16c35eb156471630a8e"
|
||||
integrity sha512-/Dil6u7gfHzWvUmvT6shtDI6JBcCJlohsYbMIJ2SGHShIt2WxbyqktBtOjdmV/4jhsYVH+h3Bn2epOCuG69+lg==
|
||||
dependencies:
|
||||
lodash "^4.17.21"
|
||||
react "16.8.6"
|
||||
@ -2699,6 +2699,11 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
crypto-js@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf"
|
||||
integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==
|
||||
|
||||
css-declaration-sorter@^6.2.2:
|
||||
version "6.2.2"
|
||||
resolved "https://registry.npmmirror.com/css-declaration-sorter/-/css-declaration-sorter-6.2.2.tgz#bfd2f6f50002d6a3ae779a87d3a0c5d5b10e0f02"
|
||||
@ -5459,6 +5464,11 @@ readdirp@~3.6.0:
|
||||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
reconnecting-websocket@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.npmmirror.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783"
|
||||
integrity sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==
|
||||
|
||||
redux-thunk@2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmmirror.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5"
|
||||
|
Reference in New Issue
Block a user