|
|
@@ -0,0 +1,261 @@
|
|
|
+<template>
|
|
|
+ <div class="sidebar-wrapper">
|
|
|
+ <div class="sidebar-buttons">
|
|
|
+ <button class="sidebar-btn" title="返回主视角" @click="handleClick('home')">
|
|
|
+ <img src="/src/assets/images/home.png" alt="首页" />
|
|
|
+ </button>
|
|
|
+ <button class="sidebar-btn" title="天气" @click="toggleWeatherPanel">
|
|
|
+ <img src="/src/assets/images/weather.png" alt="天气" />
|
|
|
+ </button>
|
|
|
+ <button class="sidebar-btn" title="导览" @click="playVideo">
|
|
|
+ <img src="/src/assets/images/walk.png" alt="导览" />
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <transition name="slide-left">
|
|
|
+ <div v-if="showWeatherPanel" class="weather-panel">
|
|
|
+ <div class="weather-content">
|
|
|
+ <button
|
|
|
+ v-for="(weather, index) in weatherTypes"
|
|
|
+ :key="weather.id"
|
|
|
+ class="weather-btn"
|
|
|
+ :title="weather.label"
|
|
|
+ @click="selectWeather(weather.id)"
|
|
|
+ >
|
|
|
+ <span class="weather-icon">{{ weather.icon }}</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </transition>
|
|
|
+
|
|
|
+ <teleport to="body">
|
|
|
+ <transition name="fade">
|
|
|
+ <div v-if="showVideo" class="video-modal" @click="closeVideo">
|
|
|
+ <div class="video-container" @click.stop>
|
|
|
+ <button class="close-btn" @click="closeVideo">×</button>
|
|
|
+ <video
|
|
|
+ ref="videoPlayer"
|
|
|
+ class="video-player"
|
|
|
+ :src="videoSrc"
|
|
|
+ loop
|
|
|
+ muted
|
|
|
+ autoplay
|
|
|
+ ></video>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </transition>
|
|
|
+ </teleport>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ name: 'SidebarButtons',
|
|
|
+ emits: ['button-click'],
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ showWeatherPanel: false,
|
|
|
+ showVideo: false,
|
|
|
+ videoSrc: '/src/assets/video/TSQRoam.mp4',
|
|
|
+ weatherTypes: [
|
|
|
+ { id: 'sunny', label: '晴朗', icon: '☀️' },
|
|
|
+ { id: 'cloudy', label: '阴天', icon: '☁️' },
|
|
|
+ { id: 'rainy', label: '下雨', icon: '🌧️' },
|
|
|
+ { id: 'snowy', label: '下雪', icon: '❄️' }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleClick(type) {
|
|
|
+ this.$emit('button-click', type)
|
|
|
+ },
|
|
|
+ toggleWeatherPanel() {
|
|
|
+ this.showWeatherPanel = !this.showWeatherPanel
|
|
|
+ },
|
|
|
+ selectWeather(weatherId) {
|
|
|
+ this.$emit('button-click', { type: 'weather', value: weatherId })
|
|
|
+ },
|
|
|
+ playVideo() {
|
|
|
+ this.showVideo = true
|
|
|
+ this.showWeatherPanel = false
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (this.$refs.videoPlayer) {
|
|
|
+ this.$refs.videoPlayer.play()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ closeVideo() {
|
|
|
+ this.showVideo = false
|
|
|
+ if (this.$refs.videoPlayer) {
|
|
|
+ this.$refs.videoPlayer.pause()
|
|
|
+ this.$refs.videoPlayer.currentTime = 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.sidebar-wrapper {
|
|
|
+ position: absolute;
|
|
|
+ left: -55px;
|
|
|
+ top: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ gap: 0;
|
|
|
+ z-index: 100;
|
|
|
+}
|
|
|
+
|
|
|
+.sidebar-buttons {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.sidebar-btn {
|
|
|
+ width: 60px;
|
|
|
+ height: 60px;
|
|
|
+ border: none;
|
|
|
+ background: transparent;
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ outline: none;
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.sidebar-btn:focus {
|
|
|
+ outline: none;
|
|
|
+ box-shadow: none;
|
|
|
+}
|
|
|
+
|
|
|
+.sidebar-btn:hover {
|
|
|
+ opacity: 0.8;
|
|
|
+}
|
|
|
+
|
|
|
+.sidebar-btn img {
|
|
|
+ width: 44px;
|
|
|
+ height: 44px;
|
|
|
+ object-fit: contain;
|
|
|
+}
|
|
|
+
|
|
|
+.weather-panel {
|
|
|
+ position: absolute;
|
|
|
+ left: -200px;
|
|
|
+ top: 64px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.weather-content {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ background: rgba(0, 60, 120, 0.5);
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 8px 12px;
|
|
|
+ gap: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.weather-btn {
|
|
|
+ width: 44px;
|
|
|
+ height: 44px;
|
|
|
+ border: none;
|
|
|
+ background: transparent;
|
|
|
+ border-right: 1px solid rgba(0, 212, 255, 0.3);
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ outline: none;
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.weather-btn:last-child {
|
|
|
+ border-right: none;
|
|
|
+}
|
|
|
+
|
|
|
+.weather-btn:hover {
|
|
|
+ background: rgba(0, 212, 255, 0.2);
|
|
|
+}
|
|
|
+
|
|
|
+.weather-icon {
|
|
|
+ font-size: 24px;
|
|
|
+ line-height: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.video-modal {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100vw;
|
|
|
+ height: 100vh;
|
|
|
+ z-index: 9999;
|
|
|
+ background: rgba(0, 0, 0, 0.7);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.video-container {
|
|
|
+ position: relative;
|
|
|
+ width: 80%;
|
|
|
+ max-width: 1200px;
|
|
|
+ aspect-ratio: 16 / 9;
|
|
|
+ background: #000;
|
|
|
+ border-radius: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.video-player {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: contain;
|
|
|
+}
|
|
|
+
|
|
|
+.close-btn {
|
|
|
+ position: absolute;
|
|
|
+ top: 10px;
|
|
|
+ right: 10px;
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ border: none;
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
+ color: #fff;
|
|
|
+ font-size: 18px;
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ border-radius: 50%;
|
|
|
+ z-index: 10;
|
|
|
+}
|
|
|
+
|
|
|
+.close-btn:hover {
|
|
|
+ background: rgba(255, 0, 0, 0.7);
|
|
|
+}
|
|
|
+
|
|
|
+.slide-left-enter-active,
|
|
|
+.slide-left-leave-active {
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.slide-left-enter-from,
|
|
|
+.slide-left-leave-to {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateX(-20px);
|
|
|
+}
|
|
|
+
|
|
|
+.fade-enter-active,
|
|
|
+.fade-leave-active {
|
|
|
+ transition: opacity 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.fade-enter-from,
|
|
|
+.fade-leave-to {
|
|
|
+ opacity: 0;
|
|
|
+}
|
|
|
+</style>
|