145 lines
3.6 KiB
Vue
145 lines
3.6 KiB
Vue
<template>
|
|
<div class="wrapper-content">
|
|
<div>
|
|
<!-- 未加入时显示按钮 -->
|
|
<div v-if="!hasJoined" class="login-button-container">
|
|
<el-button type="primary" size="large" link @click="joinWhiteboard">
|
|
正在进入互动画板。。。
|
|
</el-button>
|
|
</div>
|
|
|
|
<!-- 已加入时显示白板 -->
|
|
<div v-else class="whiteboard-wrapper">
|
|
<ToolBox v-if="canvas" class="toolbox" :canvas="canvas" />
|
|
<canvas id="whiteboard" class="whiteboard-canvas"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, nextTick, onUnmounted, onMounted } from "vue";
|
|
import { ElLoading, ElMessage } from "element-plus";
|
|
import { v4 as uuidv4 } from "uuid";
|
|
import { useRoute } from "vue-router";
|
|
import { mqttClient } from "@/utils/mqtt";
|
|
import { WhiteboardSync } from "@/utils/whiteboardSync";
|
|
import ToolBox from "@/components/ToolBox/index.vue";
|
|
import Canvas from "@/core/index.js";
|
|
import { getInfo } from "@/api/login";
|
|
|
|
const props = defineProps({
|
|
roomId: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
userId: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
})
|
|
|
|
const hasJoined = ref(false); // 是否加入白板
|
|
const canvas = ref(null);
|
|
const route = useRoute();
|
|
|
|
/** 进入白板 */
|
|
async function joinWhiteboard() {
|
|
const loading = ElLoading.service({
|
|
lock: true,
|
|
text: "正在进入互动画板...",
|
|
background: "rgba(0, 0, 0, 0.4)",
|
|
});
|
|
|
|
try {
|
|
const clientId = `whiteboard-${uuidv4()}`;
|
|
await mqttClient.connect(clientId);
|
|
// console.log("✅ 已连接 MQTT:", clientId);
|
|
|
|
hasJoined.value = true;
|
|
|
|
// 等待 DOM 更新后再初始化画布
|
|
await nextTick();
|
|
initWhiteboard();
|
|
|
|
ElMessage.success("已进入互动画板 🎉");
|
|
} catch (err) {
|
|
console.error("❌ 连接失败:", err);
|
|
ElMessage.error("连接白板失败,请重试");
|
|
} finally {
|
|
loading.close();
|
|
}
|
|
}
|
|
|
|
/** 初始化白板 */
|
|
function initWhiteboard() {
|
|
const el = document.getElementById("whiteboard");
|
|
if (!el) {
|
|
console.error("⚠️ 找不到 canvas 元素");
|
|
return;
|
|
}
|
|
// 初始化画布
|
|
canvas.value = new Canvas("whiteboard");
|
|
|
|
// 获取房间号
|
|
const roomUid = route.query.room_uid || props.roomId || "default-room";
|
|
// 初始化多人同步
|
|
WhiteboardSync.init(canvas.value, roomUid);
|
|
}
|
|
|
|
onMounted(async () => {
|
|
joinWhiteboard()
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
if (canvas.value) canvas.value.destroy();
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* 外层容器全屏居中 */
|
|
.wrapper-content {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #fff;
|
|
position: relative; /* 关键:为绝对定位子元素提供参照 */
|
|
}
|
|
|
|
/* 登录按钮容器居中 */
|
|
.login-button-container {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
/* 白板容器 */
|
|
.whiteboard-wrapper {
|
|
position: relative;
|
|
width: 72vw;
|
|
height: 69vh;
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* 画布占满白板容器 */
|
|
.whiteboard-canvas {
|
|
width: 100%;
|
|
height: 100%;
|
|
display: block;
|
|
}
|
|
|
|
/* 工具栏固定在 wrapper-content 内 */
|
|
.toolbox {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 40px; /* 距离左侧的间距 */
|
|
transform: translateY(-50%);
|
|
z-index: 1000;
|
|
}
|
|
</style> |