Преглед на файлове

路口地图视频组件交互优化:改为点击"关联视频"后才播放

  - IntersectionMapVideos组件四角视频区域默认显示"关联视频"空状态,点击后才加载播放器
  - 新增关闭按钮,支持关闭已播放的视频回到空状态
  - 空状态样式(文字、图标、关闭按钮)全部使用百分比和clamp自适应,窗口缩小时自动等比缩放
画安 преди 3 седмици
родител
ревизия
ef44d7d90d
променени са 1 файла, в които са добавени 103 реда и са изтрити 4 реда
  1. 103 4
      src/components/ui/IntersectionMapVideos.vue

+ 103 - 4
src/components/ui/IntersectionMapVideos.vue

@@ -5,19 +5,47 @@
     <div class="corner-videos-overlay" v-if="hasAnyVideo" :style="{ width: stageWidth + 'px', height: stageHeight + 'px' }">
       
       <div v-if="videoUrls.nw" class="video-corner top-left">
-        <XgVideoPlayer :src="videoUrls.nw" />
+        <template v-if="activeVideos.nw">
+          <XgVideoPlayer :src="videoUrls.nw" />
+          <div class="close-btn" title="关闭视频" @click="closeVideo('nw')">✕</div>
+        </template>
+        <div v-else class="empty-state" @click="openVideo('nw')" title="点击关联视频">
+          <span class="empty-tag">关联视频</span>
+          <img :src="require('@/assets/images/camera.png')" alt="camera" class="camera-image" />
+        </div>
       </div>
 
       <div v-if="videoUrls.ne" class="video-corner top-right">
-        <XgVideoPlayer :src="videoUrls.ne" />
+        <template v-if="activeVideos.ne">
+          <XgVideoPlayer :src="videoUrls.ne" />
+          <div class="close-btn" title="关闭视频" @click="closeVideo('ne')">✕</div>
+        </template>
+        <div v-else class="empty-state" @click="openVideo('ne')" title="点击关联视频">
+          <span class="empty-tag">关联视频</span>
+          <img :src="require('@/assets/images/camera.png')" alt="camera" class="camera-image" />
+        </div>
       </div>
 
       <div v-if="videoUrls.sw" class="video-corner bottom-left">
-        <XgVideoPlayer :src="videoUrls.sw" />
+        <template v-if="activeVideos.sw">
+          <XgVideoPlayer :src="videoUrls.sw" />
+          <div class="close-btn" title="关闭视频" @click="closeVideo('sw')">✕</div>
+        </template>
+        <div v-else class="empty-state" @click="openVideo('sw')" title="点击关联视频">
+          <span class="empty-tag">关联视频</span>
+          <img :src="require('@/assets/images/camera.png')" alt="camera" class="camera-image" />
+        </div>
       </div>
 
       <div v-if="videoUrls.se" class="video-corner bottom-right">
-        <XgVideoPlayer :src="videoUrls.se" />
+        <template v-if="activeVideos.se">
+          <XgVideoPlayer :src="videoUrls.se" />
+          <div class="close-btn" title="关闭视频" @click="closeVideo('se')">✕</div>
+        </template>
+        <div v-else class="empty-state" @click="openVideo('se')" title="点击关联视频">
+          <span class="empty-tag">关联视频</span>
+          <img :src="require('@/assets/images/camera.png')" alt="camera" class="camera-image" />
+        </div>
       </div>
 
     </div>
@@ -68,6 +96,7 @@ export default {
       },
       stageWidth: 900,  // 当前画布缩放后的真实宽度
       stageHeight: 900, // 当前画布缩放后的真实高度
+      activeVideos: { nw: false, ne: false, sw: false, se: false },
     };
   },
   computed: {
@@ -105,6 +134,12 @@ export default {
     }
   },
   methods: {
+    openVideo(corner) {
+      this.$set(this.activeVideos, corner, true);
+    },
+    closeVideo(corner) {
+      this.$set(this.activeVideos, corner, false);
+    },
     // ================= 以下为原有的 Konva 绘制逻辑,完全保持不变 =================
     initKonvaStage() {
       const { stageSize, halfRoad, roadWidth } = this.sizeConfig;
@@ -351,6 +386,70 @@ export default {
 .bottom-left { bottom: 0; left: 0; }
 .bottom-right { bottom: 0; right: 0; }
 
+/* ================= 关联视频空状态 & 关闭按钮 ================= */
+.close-btn {
+  position: absolute;
+  top: 4%;
+  right: 4%;
+  background: rgba(0, 0, 0, 0.6);
+  color: #fff;
+  width: 8%;
+  height: 8%;
+  min-width: 14px;
+  min-height: 14px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  transition: background 0.3s;
+  z-index: 10;
+  font-size: clamp(8px, 4%, 14px);
+}
+.close-btn:hover { background: rgba(0, 0, 0, 1); }
+
+.empty-state {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 100%;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  background: #112445;
+}
+.empty-state:hover {
+  background: rgba(68, 138, 255, 0.1);
+}
+.empty-state:hover .empty-tag {
+  background: rgba(68, 138, 255, 1);
+  box-shadow: 0 0 10px rgba(68, 138, 255, 0.5);
+}
+.empty-state:hover .camera-image {
+  transform: scale(1.05);
+  transition: transform 0.3s ease;
+}
+
+.empty-tag {
+  background: rgba(68, 138, 255, 0.8);
+  color: #fff;
+  padding: 2% 6%;
+  border-radius: 4px;
+  font-size: clamp(8px, 5%, 14px);
+  margin-bottom: 6%;
+  letter-spacing: 1px;
+  transition: all 0.3s ease;
+  white-space: nowrap;
+}
+
+.camera-image {
+  width: 30%;
+  max-width: 50px;
+  height: auto;
+  object-fit: contain;
+  opacity: 0.8;
+}
+
 /* xgplayer 填满角落容器 */
 .video-corner .xg-video-player {
   width: 100%;