嘉宾参会
This commit is contained in:
@ -41,6 +41,13 @@ export function registerJoinUser(data) {
|
|||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
export function panelistJoinMeeting(params) {
|
||||||
|
return request({
|
||||||
|
url: `/app/panelistJoinMeeting`,
|
||||||
|
method: "post",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// /app/visitorJoinUser
|
// /app/visitorJoinUser
|
||||||
// 游客参会
|
// 游客参会
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
whitelistJoinMeeting,
|
whitelistJoinMeeting,
|
||||||
registerJoinUser,
|
registerJoinUser,
|
||||||
visitorJoinUser,
|
visitorJoinUser,
|
||||||
|
panelistJoinMeeting,
|
||||||
} from "@/api/meeting";
|
} from "@/api/meeting";
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHistory(),
|
||||||
@ -21,20 +22,30 @@ const router = createRouter({
|
|||||||
name: "Verify",
|
name: "Verify",
|
||||||
component: () => import("@/views/verify.vue"),
|
component: () => import("@/views/verify.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/panelist-verify/:meetingId",
|
||||||
|
name: "PanelistVerify",
|
||||||
|
component: () => import("@/views/panelist-verify.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/meeting/:meetingId",
|
path: "/meeting/:meetingId",
|
||||||
name: "Meeting",
|
name: "Meeting",
|
||||||
component: () => import("@/views/meeting.vue"),
|
component: () => import("@/views/meeting.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/panelist/:meetingId",
|
||||||
|
name: "Panelist",
|
||||||
|
component: () => import("@/views/meeting.vue"),
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// path: "/host/:meetingId/:hostinfo",
|
// path: "/host/:meetingId/:hostinfo",
|
||||||
// name: "Host",
|
// name: "Host",
|
||||||
// component: () => import("@/views/host.vue"),
|
// component: () => import("@/views/host.vue"),
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
path: "/host/:meetingId/:pwd/:username/:nickname",
|
path: "/host/:meetingId/:createEmail/:pwd/:username/:nickname",
|
||||||
name: "Host",
|
name: "Host",
|
||||||
component: () => import("@/views/host.vue"),
|
component: () => import("@/views/host_new.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/:pathMatch(.*)*",
|
path: "/:pathMatch(.*)*",
|
||||||
@ -57,6 +68,7 @@ router.beforeEach(async (to) => {
|
|||||||
store.commit("setJoinUser", {
|
store.commit("setJoinUser", {
|
||||||
nickname: to.params.nickname,
|
nickname: to.params.nickname,
|
||||||
username: to.params.username,
|
username: to.params.username,
|
||||||
|
email: to.params.createEmail,
|
||||||
});
|
});
|
||||||
store.commit("setPassword", to.params.pwd);
|
store.commit("setPassword", to.params.pwd);
|
||||||
return true;
|
return true;
|
||||||
@ -81,11 +93,11 @@ router.beforeEach(async (to) => {
|
|||||||
if (store.state.joinUser.icCard) {
|
if (store.state.joinUser.icCard) {
|
||||||
// 检测输入的IC卡号是否在白名单范围内,是则放行,否则返回原地址
|
// 检测输入的IC卡号是否在白名单范围内,是则放行,否则返回原地址
|
||||||
try {
|
try {
|
||||||
const { data } = await whitelistJoinMeeting({
|
const { meetingPassword } = await whitelistJoinMeeting({
|
||||||
meetingId: to.params.meetingId,
|
meetingId: to.params.meetingId,
|
||||||
icCard: store.state.joinUser.icCard,
|
icCard: store.state.joinUser.icCard,
|
||||||
});
|
});
|
||||||
store.commit("setPassword", data);
|
store.commit("setPassword", meetingPassword);
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
store.commit("setJoinUser", {});
|
store.commit("setJoinUser", {});
|
||||||
@ -101,16 +113,54 @@ router.beforeEach(async (to) => {
|
|||||||
return `/verify/${to.params.meetingId}`;
|
return `/verify/${to.params.meetingId}`;
|
||||||
} else {
|
} else {
|
||||||
if (store.state.meeting.joinType === "2") {
|
if (store.state.meeting.joinType === "2") {
|
||||||
const { data } = await registerJoinUser(store.state.joinUser);
|
const { meetingPassword, email } = await registerJoinUser(
|
||||||
store.commit("setPassword", data);
|
store.state.joinUser
|
||||||
|
);
|
||||||
|
store.commit("setJoinUser", {
|
||||||
|
...store.state.joinUser,
|
||||||
|
email: email.email,
|
||||||
|
token: email.token,
|
||||||
|
});
|
||||||
|
store.commit("setPassword", meetingPassword);
|
||||||
} else {
|
} else {
|
||||||
const { data } = await visitorJoinUser(store.state.joinUser);
|
const { meetingPassword } = await visitorJoinUser(
|
||||||
store.commit("setPassword", data);
|
store.state.joinUser
|
||||||
|
);
|
||||||
|
store.commit("setPassword", meetingPassword);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (to.name === "Panelist") {
|
||||||
|
console.log("Panelist");
|
||||||
|
// 如果要去的页面会议号于 vuex中的不一样,则清除数据
|
||||||
|
if (to.params.meetingId !== store.state.joinUser.meetingId) {
|
||||||
|
console.log('dis');
|
||||||
|
store.commit("setJoinUser", {});
|
||||||
|
}
|
||||||
|
if (store.state.joinUser.icCard) {
|
||||||
|
try {
|
||||||
|
const { meetingPassword, email } = await panelistJoinMeeting({
|
||||||
|
meetingId: to.params.meetingId,
|
||||||
|
icCard: store.state.joinUser.icCard,
|
||||||
|
});
|
||||||
|
store.commit("setJoinUser", {
|
||||||
|
...store.state.joinUser,
|
||||||
|
email: email.email,
|
||||||
|
token: email.token,
|
||||||
|
});
|
||||||
|
store.commit("setPassword", meetingPassword);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
store.commit("setJoinUser", {});
|
||||||
|
return `/panelist-verify/${to.params.meetingId}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
store.commit("setJoinUser", {});
|
||||||
|
return `/panelist-verify/${to.params.meetingId}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
@ -43,7 +43,10 @@ const store = createStore({
|
|||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
nickname: (state) => state.joinUser.nickname, // 姓名
|
nickname: (state) => state.joinUser.nickname, // 姓名
|
||||||
icCard: (state) => state.joinUser.icCard, // 姓名
|
username: (state) => state.joinUser.username, // 姓名
|
||||||
|
email: (state) => state.joinUser.email, //
|
||||||
|
token: (state) => state.joinUser.token, //
|
||||||
|
icCard: (state) => state.joinUser.icCard, //
|
||||||
meetingPic: (state) => state.meeting.meetingPic, // 会议封面
|
meetingPic: (state) => state.meeting.meetingPic, // 会议封面
|
||||||
templateBackgroundPic: (state) => state.meeting.templateBackgroundPic, // 会议封面
|
templateBackgroundPic: (state) => state.meeting.templateBackgroundPic, // 会议封面
|
||||||
meetingNote: (state) => state.meeting.meetingNote, // 会议信息
|
meetingNote: (state) => state.meeting.meetingNote, // 会议信息
|
||||||
|
@ -15,27 +15,17 @@
|
|||||||
<div class="chat-right" ref="chatRightRef">
|
<div class="chat-right" ref="chatRightRef">
|
||||||
<messageList :messageList="messages"></messageList>
|
<messageList :messageList="messages"></messageList>
|
||||||
<div class="option-bar">
|
<div class="option-bar">
|
||||||
<!-- <el-input
|
|
||||||
v-model="editingMessage"
|
|
||||||
style="margin-right: 15px"
|
|
||||||
></el-input> -->
|
|
||||||
<div
|
<div
|
||||||
class="display-message"
|
class="display-message"
|
||||||
v-html="editingMessage"
|
v-html="editingMessage"
|
||||||
@click="openRichMessageEditor"
|
@click="openRichMessageEditor"
|
||||||
></div>
|
></div>
|
||||||
<!-- <wangEditor v-model="editingMessage" :height="`100px`"></wangEditor> -->
|
|
||||||
<!-- <div class="btns"> -->
|
|
||||||
<!-- <el-button type="success" @click="showRichEditor = true"
|
|
||||||
>高级输入框</el-button
|
|
||||||
> -->
|
|
||||||
<el-button
|
<el-button
|
||||||
type="success"
|
type="success"
|
||||||
@click="sendMessage"
|
@click="sendMessage"
|
||||||
:disabled="editingMessage.length === 0"
|
:disabled="editingMessage.length === 0"
|
||||||
>发送</el-button
|
>发送</el-button
|
||||||
>
|
>
|
||||||
<!-- </div> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
555
src/views/host_new.vue
Normal file
555
src/views/host_new.vue
Normal file
@ -0,0 +1,555 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app-container" v-loading="isMeetingLoading" 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">
|
||||||
|
<div
|
||||||
|
class="display-message"
|
||||||
|
v-html="editingMessage"
|
||||||
|
@click="openRichMessageEditor"
|
||||||
|
></div>
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
@click="sendMessage"
|
||||||
|
:disabled="editingMessage.length === 0"
|
||||||
|
>发送</el-button
|
||||||
|
>
|
||||||
|
</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>
|
||||||
|
<!-- <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="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>
|
||||||
|
import { computed, reactive, watch, ref, onMounted, onUnmounted } from "vue";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import axios from "axios";
|
||||||
|
import { signMeeting, generateSignature } from "@/api/meeting";
|
||||||
|
import questions from "@/components/questions";
|
||||||
|
import wangEditor from "@/components/wangEditor";
|
||||||
|
import messageList from "@/components/messageList";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import ZoomMtgEmbedded from "@zoomus/websdk/embedded";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
|
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 isMeetingLoading = ref(true); // 视频课件是否正在加载
|
||||||
|
const templateId = ref(6); // 布局 id
|
||||||
|
if (store.getters.templateId) {
|
||||||
|
templateId.value = store.getters.templateId;
|
||||||
|
}
|
||||||
|
const showRichEditor = ref(false);
|
||||||
|
const joinAccount = ref(""); // 参会账号
|
||||||
|
const joinName = ref(""); // 参会名称
|
||||||
|
const screenWidth = ref(0); // 屏幕宽度
|
||||||
|
const meetingWidth = ref(0); // 视频课件容器元素宽度
|
||||||
|
const meetingHeight = ref(0); // 视频课件容器元素高度
|
||||||
|
screenWidth.value = document.body.offsetWidth;
|
||||||
|
|
||||||
|
joinAccount.value = store.getters.username;
|
||||||
|
joinName.value = store.getters.nickname;
|
||||||
|
// 设置会议背景大小、图片
|
||||||
|
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`; // 设置背景图片
|
||||||
|
setTextLabel();
|
||||||
|
meetingWidth.value = meetingContainerRef.value.offsetWidth * 0.95; // zoom 会议组件宽度是父元素宽度的 95%
|
||||||
|
meetingHeight.value = (meetingWidth.value * 9) / 16; // 根据 zoom 会议组件长宽比 16:9 计算出会议组件高度
|
||||||
|
meetingContainerRef.value.style.paddingTop = `${meetingHeight.value * 0.2}px`; // 父元素顶部padding 是会议组件高度的20%
|
||||||
|
videoElementRef.value.style.width = meetingWidth.value + "px";
|
||||||
|
videoElementRef.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");
|
||||||
|
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 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: "99Spa64AWHYVZD95imUpVyMD0KF9CpEIrIb1",
|
||||||
|
// meetingNumber: store.getters.meetingNumber,
|
||||||
|
meetingNumber: store.getters.meetingNumber,
|
||||||
|
passWord: store.state.password,
|
||||||
|
// sdkKey: "99Spa64AWHYVZD95imUpVyMD0KF9CpEIrIb1",
|
||||||
|
// meetingNumber: "97097842319",
|
||||||
|
// passWord: "111916",
|
||||||
|
// role: route.name === "Host" ? 1 : 0,
|
||||||
|
role: 1,
|
||||||
|
// signatureEndpoint: "http://120.26.107.74:4000",
|
||||||
|
userEmail: store.getters.email,
|
||||||
|
// userEmail: "934510341@qq.com",
|
||||||
|
userName: joinName.value,
|
||||||
|
// userName: "afasde1",
|
||||||
|
// 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:
|
||||||
|
// "Xhi0bKUzyNBnJwe2EJWZ0JZ3IYqtPgyyWE1CXW3z2X4.DQMAAAAWm3t-jxZqSS14R0dCSFRDNkFibVQwakpHbFd3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
||||||
|
registrantToken: "",
|
||||||
|
});
|
||||||
|
console.log(meetingConfig);
|
||||||
|
|
||||||
|
// 生成签名
|
||||||
|
const getSignature = async () => {
|
||||||
|
const { sign } = await generateSignature({
|
||||||
|
meetingNumber: store.getters.meetingNumber,
|
||||||
|
role: meetingConfig.role,
|
||||||
|
});
|
||||||
|
console.log(sign);
|
||||||
|
startMeeting(sign);
|
||||||
|
// axios
|
||||||
|
// .post("http://localhost:4000", {
|
||||||
|
// meetingNumber: store.getters.meetingNumber,
|
||||||
|
// role: meetingConfig.role,
|
||||||
|
// })
|
||||||
|
// .then((res) => {
|
||||||
|
// console.log(res.data.signature);
|
||||||
|
// startMeeting(res.data.signature);
|
||||||
|
// })
|
||||||
|
// .catch((error) => {
|
||||||
|
// console.log(error);
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 开始会议
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const setFullScreen = () => {
|
||||||
|
videoElementRef.value.requestFullscreen();
|
||||||
|
};
|
||||||
|
onMounted(() => {
|
||||||
|
getSignature();
|
||||||
|
});
|
||||||
|
// 初始化
|
||||||
|
const initDesktopLayout = () => {
|
||||||
|
// 切换到 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-252"
|
||||||
|
);
|
||||||
|
heightEl.style.height = `${meetingHeight.value - 45}px`;
|
||||||
|
console.log(meetingHeight.value);
|
||||||
|
|
||||||
|
// 初始化宽度
|
||||||
|
// zmwebsdk-MuiPaper-root zmwebsdk-makeStyles-root-21 zmwebsdk-MuiPaper-elevation1 zmwebsdk-MuiPaper-rounded
|
||||||
|
document.querySelector(
|
||||||
|
".zmwebsdk-MuiPaper-root.zmwebsdk-makeStyles-root-21.zmwebsdk-MuiPaper-elevation1.zmwebsdk-MuiPaper-rounded"
|
||||||
|
).style.width = `${meetingWidth.value - 4}px`;
|
||||||
|
console.log(`${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"
|
||||||
|
) ||
|
||||||
|
document.querySelector(
|
||||||
|
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-176"
|
||||||
|
); // 包含视频和课件的容器
|
||||||
|
v_s_wrap_el.style.flexDirection = "";
|
||||||
|
|
||||||
|
const v_wrap_el =
|
||||||
|
document.querySelector(".zmwebsdk-makeStyles-wrap-167") ||
|
||||||
|
document.querySelector(".zmwebsdk-makeStyles-wrap-177");
|
||||||
|
if (!inSharing.value) return;
|
||||||
|
|
||||||
|
const s_wrap_el = document.querySelector(".zmwebsdk-makeStyles-inSharing-46");
|
||||||
|
if (templateId === "1") {
|
||||||
|
// 课件|视频 对半分
|
||||||
|
v_wrap_el.style.width = `${meetingWidth.value / 2 - 2}px`;
|
||||||
|
} else if (templateId === "2") {
|
||||||
|
// 视频|课件 对半分
|
||||||
|
v_wrap_el.style.width = `${meetingWidth.value / 2 - 2}px`;
|
||||||
|
v_s_wrap_el.style.flexDirection = "row-reverse";
|
||||||
|
} else if (templateId === "3") {
|
||||||
|
// 课件|视频 左4/5 | 右边1/5
|
||||||
|
v_wrap_el.style.width = `${(meetingWidth.value - 4) / 5}px`;
|
||||||
|
} else if (templateId === "4") {
|
||||||
|
// 视频|课件 左1/4 | 右边3/4
|
||||||
|
v_wrap_el.style.width = `${(meetingWidth.value - 4) / 5}px`;
|
||||||
|
v_s_wrap_el.style.flexDirection = "row-reverse";
|
||||||
|
} else if (templateId === "5") {
|
||||||
|
// 只显示课件
|
||||||
|
v_wrap_el.style.display = `none`;
|
||||||
|
} else if (templateId === "6") {
|
||||||
|
// 只显示视频
|
||||||
|
s_wrap_el.style.display = "none";
|
||||||
|
v_wrap_el.style.width = `${meetingWidth.value - 4}px`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
watch(inSharing, (newVal) => {
|
||||||
|
console.log(newVal);
|
||||||
|
if (newVal) {
|
||||||
|
setLayout(templateId.value);
|
||||||
|
} else {
|
||||||
|
const galleryViewButton = document.querySelector(
|
||||||
|
"#suspension-view-tab-thumbnail-gallery"
|
||||||
|
);
|
||||||
|
galleryViewButton.click();
|
||||||
|
const v_wrap_el =
|
||||||
|
document.querySelector(".zmwebsdk-makeStyles-wrap-167") ||
|
||||||
|
document.querySelector(".zmwebsdk-makeStyles-wrap-177");
|
||||||
|
v_wrap_el.style.width = "";
|
||||||
|
const v_s_wrap_el =
|
||||||
|
document.querySelector(
|
||||||
|
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-166"
|
||||||
|
) ||
|
||||||
|
document.querySelector(
|
||||||
|
".zmwebsdk-MuiBox-root.zmwebsdk-MuiBox-root.zmwebsdk-makeStyles-root-176"
|
||||||
|
);
|
||||||
|
v_s_wrap_el.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(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 === "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 editingMessage = ref(""); // 正在编辑的内容
|
||||||
|
const richMessage = ref(""); // 正在编辑的富文本内容--主持人独有
|
||||||
|
|
||||||
|
// 保存富文本聊天内容
|
||||||
|
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 = () => {
|
||||||
|
socket.send(
|
||||||
|
JSON.stringify(
|
||||||
|
JSON.stringify({
|
||||||
|
account: joinName.value,
|
||||||
|
msg: editingMessage.value,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// 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);
|
||||||
|
});
|
||||||
|
</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: 80%;
|
||||||
|
min-height: 100%;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
:deep(p) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: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 {
|
||||||
|
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>
|
@ -4,7 +4,6 @@
|
|||||||
<div class="meeting-container" ref="meetingContainerRef">
|
<div class="meeting-container" ref="meetingContainerRef">
|
||||||
<div id="video-element" ref="videoElementRef"></div>
|
<div id="video-element" ref="videoElementRef"></div>
|
||||||
<el-button @click="setFullScreen" class="fullscreen-btn">
|
<el-button @click="setFullScreen" class="fullscreen-btn">
|
||||||
<!-- <FullScreen></FullScreen> -->
|
|
||||||
全屏</el-button
|
全屏</el-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@ -166,25 +165,24 @@ const meetingConfig = reactive({
|
|||||||
// This Sample App has been updated to use SDK App type credentials https://marketplace.zoom.us/docs/guides/build/sdk-app
|
// This Sample App has been updated to use SDK App type credentials https://marketplace.zoom.us/docs/guides/build/sdk-app
|
||||||
sdkKey: "99Spa64AWHYVZD95imUpVyMD0KF9CpEIrIb1",
|
sdkKey: "99Spa64AWHYVZD95imUpVyMD0KF9CpEIrIb1",
|
||||||
// meetingNumber: store.getters.meetingNumber,
|
// meetingNumber: store.getters.meetingNumber,
|
||||||
// meetingNumber: store.getters.meetingNumber,
|
meetingNumber: store.getters.meetingNumber,
|
||||||
// passWord: store.state.password,
|
passWord: store.state.password,
|
||||||
// sdkKey: "99Spa64AWHYVZD95imUpVyMD0KF9CpEIrIb1",
|
// sdkKey: "99Spa64AWHYVZD95imUpVyMD0KF9CpEIrIb1",
|
||||||
meetingNumber: "97097842319",
|
// meetingNumber: "97097842319",
|
||||||
passWord: "111916",
|
// passWord: "111916",
|
||||||
// role: route.name === "Host" ? 1 : 0,
|
// role: route.name === "Host" ? 1 : 0,
|
||||||
role: 0,
|
role: 0,
|
||||||
// signatureEndpoint: "http://120.26.107.74:4000",
|
// signatureEndpoint: "http://120.26.107.74:4000",
|
||||||
// userEmail:
|
userEmail: store.getters.email,
|
||||||
// Number(Math.random().toString().substr(3, 8) + Date.now()).toString(36) +
|
// userEmail: "934510341@qq.com",
|
||||||
// "@163.com",
|
userName: joinName.value,
|
||||||
userEmail: "934510341@qq.com",
|
// userName: "afasde1",
|
||||||
// userName: joinName.value,
|
|
||||||
userName: "afasde1",
|
|
||||||
// pass in the registrant's token if your meeting or webinar requires registration. More info here:
|
// 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
|
// 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
|
// Webinars: https://marketplace.zoom.us/docs/sdk/native-sdks/web/component-view/webinars#join-registered
|
||||||
registrantToken:
|
// registrantToken:
|
||||||
"Xhi0bKUzyNBnJwe2EJWZ0JZ3IYqtPgyyWE1CXW3z2X4.DQMAAAAWm3t-jxZqSS14R0dCSFRDNkFibVQwakpHbFd3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
// "Xhi0bKUzyNBnJwe2EJWZ0JZ3IYqtPgyyWE1CXW3z2X4.DQMAAAAWm3t-jxZqSS14R0dCSFRDNkFibVQwakpHbFd3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
||||||
|
registrantToken: store.getters.token,
|
||||||
});
|
});
|
||||||
console.log(meetingConfig);
|
console.log(meetingConfig);
|
||||||
|
|
||||||
@ -402,9 +400,9 @@ const initWebSocket = () => {
|
|||||||
}
|
}
|
||||||
// 收到聊天消息时
|
// 收到聊天消息时
|
||||||
else if (data.type === "isChat") {
|
else if (data.type === "isChat") {
|
||||||
console.log(JSON.parse(data.content));
|
console.log(JSON.parse(JSON.parse(JSON.parse(data.content).msg)));
|
||||||
messages.value.push({
|
messages.value.push({
|
||||||
...JSON.parse(data.content),
|
...JSON.parse(JSON.parse(JSON.parse(data.content).msg)),
|
||||||
id: _.uniqueId(),
|
id: _.uniqueId(),
|
||||||
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
});
|
});
|
||||||
@ -451,8 +449,23 @@ const messages = ref([]); // 消息列表
|
|||||||
const editingMessage = ref(""); // 正在编辑的内容
|
const editingMessage = ref(""); // 正在编辑的内容
|
||||||
// 发送消息
|
// 发送消息
|
||||||
const sendMessage = () => {
|
const sendMessage = () => {
|
||||||
console.log(socket);
|
console.log(
|
||||||
socket.send(editingMessage.value);
|
JSON.stringify(
|
||||||
|
JSON.stringify({
|
||||||
|
account: joinName.value,
|
||||||
|
msg: editingMessage.value,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
socket.send(
|
||||||
|
JSON.stringify(
|
||||||
|
JSON.stringify({
|
||||||
|
account: joinName.value,
|
||||||
|
msg: editingMessage.value,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// socket.send(editingMessage.value);
|
||||||
messages.value.push({
|
messages.value.push({
|
||||||
id: _.uniqueId(),
|
id: _.uniqueId(),
|
||||||
account: joinName.value,
|
account: joinName.value,
|
||||||
|
98
src/views/panelist-verify.vue
Normal file
98
src/views/panelist-verify.vue
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<template>
|
||||||
|
<img class="meeting-cover" :src="meeting.meetingPic" alt="" />
|
||||||
|
<h3 class="meeting-title">{{ meeting.meetingName }}</h3>
|
||||||
|
<p class="meeting-time">
|
||||||
|
<span class="title">会议时间</span>
|
||||||
|
<span class="time">{{ meeting.startTime }}</span>
|
||||||
|
</p>
|
||||||
|
<div class="form-container">
|
||||||
|
<el-form
|
||||||
|
:model="newJoinUser"
|
||||||
|
ref="newJoinUserRef"
|
||||||
|
:rules="joinUserRules"
|
||||||
|
label-position="left"
|
||||||
|
>
|
||||||
|
<div class="joinuser-wrap" style="display: flex; flex-wrap: wrap">
|
||||||
|
<div class="joinuser-item">
|
||||||
|
<el-form-item label="IC卡号" prop="icCard">
|
||||||
|
<el-input v-model="newJoinUser.icCard" placeholder="请输入IC卡号" />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<div class="joinuser-item">
|
||||||
|
<el-form-item label="姓名" prop="nickname">
|
||||||
|
<el-input v-model="newJoinUser.nickname" placeholder="请输入姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-row type="flex" justify="center"> </el-row>
|
||||||
|
</el-form>
|
||||||
|
<div style="display: flex; justify-content: center">
|
||||||
|
<el-button type="primary" @click="submitVerify(newJoinUserRef)"
|
||||||
|
>加入会议</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { reactive, ref, toRefs } from "vue";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
|
import _ from "lodash";
|
||||||
|
const store = useStore();
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
const data = reactive({
|
||||||
|
newJoinUser: {},
|
||||||
|
fieldConfig: {
|
||||||
|
icCard: true,
|
||||||
|
},
|
||||||
|
meeting: {},
|
||||||
|
joinUserRules: {
|
||||||
|
icCard: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
trigger: "blur",
|
||||||
|
message: "必填",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
nickname: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
trigger: "blur",
|
||||||
|
message: "必填",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const { newJoinUser, joinUserRules, meeting } = toRefs(data);
|
||||||
|
const meetingId = ref(route.params.meetingId);
|
||||||
|
|
||||||
|
meeting.value = _.cloneDeep(store.state.meeting);
|
||||||
|
newJoinUser.value.meetingId = meetingId.value;
|
||||||
|
const newJoinUserRef = ref(null);
|
||||||
|
const submitVerify = async (newJoinUserRef) => {
|
||||||
|
console.log(newJoinUser.value);
|
||||||
|
const valid = await newJoinUserRef.validate();
|
||||||
|
console.log(valid);
|
||||||
|
store.commit("setJoinUser", newJoinUser.value);
|
||||||
|
router.push(`/panelist/${meetingId.value}`);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "@/style/appoint-mobile.scss";
|
||||||
|
@import "@/style/appoint-desktop.scss";
|
||||||
|
|
||||||
|
.meeting-title {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.meeting-time {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.form-item-container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
</style>
|
Reference in New Issue
Block a user