项目初始化
This commit is contained in:
186
src/views/custom/tabulaRase/index.vue
Normal file
186
src/views/custom/tabulaRase/index.vue
Normal file
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="wrapper-content">
|
||||
<div v-if="showLogin">
|
||||
<!-- 登录界面 -->
|
||||
<Login @loginSuccess="handleLoginSuccess" />
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<!-- 未加入时显示按钮 -->
|
||||
<div v-if="!hasJoined" class="login-button-container">
|
||||
<el-button type="primary" size="large" round plain @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 Login from "@/components/Login/index.vue";
|
||||
import Canvas from "@/core/index.js";
|
||||
import { getInfo } from "@/api/login";
|
||||
|
||||
const showLogin = ref(false); // 是否显示登录页面
|
||||
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 handleLoginSuccess() {
|
||||
showLogin.value = false;
|
||||
}
|
||||
|
||||
/** 初始化白板 */
|
||||
function initWhiteboard() {
|
||||
const el = document.getElementById("whiteboard");
|
||||
if (!el) {
|
||||
console.error("⚠️ 找不到 canvas 元素");
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置画布宽高(保持16:9)
|
||||
const { width, height } = getCanvasSize(el.parentElement);
|
||||
Object.assign(el, { width, height });
|
||||
Object.assign(el.style, {
|
||||
width: `${width}px`,
|
||||
height: `${height}px`,
|
||||
border: "2px solid #000",
|
||||
});
|
||||
|
||||
// 初始化画布
|
||||
canvas.value = new Canvas("whiteboard");
|
||||
|
||||
// 获取房间号
|
||||
const roomUid = route.query.room_uid || "default-room";
|
||||
|
||||
// 初始化多人同步
|
||||
WhiteboardSync.init(canvas.value, roomUid);
|
||||
}
|
||||
|
||||
/** 计算画布大小,保持16:9 */
|
||||
function getCanvasSize(container) {
|
||||
const containerWidth = container.offsetWidth;
|
||||
const containerHeight = container.offsetHeight;
|
||||
|
||||
let width = containerWidth;
|
||||
let height = Math.floor((width * 9) / 16);
|
||||
|
||||
if (height > containerHeight) {
|
||||
height = containerHeight;
|
||||
width = Math.floor((height * 16) / 9);
|
||||
}
|
||||
|
||||
return { width, height };
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await getInfo("self");
|
||||
showLogin.value = false;
|
||||
} catch (err) {
|
||||
if (err.code === 401) {
|
||||
showLogin.value = true;
|
||||
} else {
|
||||
showLogin.value = false;
|
||||
console.warn("⚠️ 用户信息校验失败:", err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (canvas.value) canvas.value.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
/* 外层容器全屏居中 */
|
||||
.wrapper-content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 登录按钮容器居中 */
|
||||
.login-button-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 白板容器 */
|
||||
.whiteboard-wrapper {
|
||||
position: relative;
|
||||
width: 90vw;
|
||||
max-width: 1280px;
|
||||
aspect-ratio: 16 / 9;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 画布占满白板容器 */
|
||||
.whiteboard-canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 工具栏左侧垂直居中 */
|
||||
.toolbox {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 10px;
|
||||
transform: translateY(-50%);
|
||||
z-index: 1000;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user