|
|
@@ -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%;
|