Forráskód Böngészése

修改特勤弹窗面板的缩放自适应;

画安 1 hónapja%!(EXTRA string=óta)
szülő
commit
a3d4000096

+ 25 - 9
src/components/ui/IntersectionControlCard.vue

@@ -14,7 +14,7 @@
                 <div class="info-item">驻留阶段:<span>{{ data.stage }}</span></div>
                 <div class="info-item">执行方式:<span>{{ data.mode }}</span></div>
                 <div class="info-item">剩余时间:<span class="time">{{ data.timeLeft }}s</span></div>
-                <button :class="{'btn btn-view': data.btnType === 'normal', 'action-btn primary': data.btnType === 'primary'}">{{ data.btnText }}</button>
+                <button :class="{'btn btn-view margin-top-auto': data.btnType === 'normal', 'action-btn primary': data.btnType === 'primary'}">{{ data.btnText }}</button>
             </div>
         </div>
 
@@ -68,20 +68,23 @@ export default {
 <style scoped>
 .control-card {
     background: #112445;
-    padding: 16px;
+    padding: 12px 16px;
     border-radius: 6px;
     border: 1px solid rgba(68, 138, 255, 0.15);
     display: flex;
     flex-direction: column;
+    height: 100%;
+    box-sizing: border-box;
 }
 
 .card-header {
     color: #fff;
     font-size: 14px;
-    margin-bottom: 16px;
+    margin-bottom: 12px;
     display: flex;
     align-items: center;
     gap: 8px;
+    flex-shrink: 0;
 }
 
 .dot {
@@ -102,16 +105,19 @@ export default {
 .card-body {
     display: flex;
     gap: 16px;
-    margin-bottom: 16px;
+    margin-bottom: 12px;
+    flex: 1;
+    min-height: 0;
 }
 
 .micro-map-container {
-    width: 140px;
-    height: 140px;
+    flex: 0 0 45%; /* 大概占据左侧 45% 的宽度 */
+    max-width: 140px;
+    height: auto;
+    aspect-ratio: 1 / 1; /* 保持正方形比例 */
     background: #050a17;
     border-radius: 4px;
     overflow: hidden;
-    flex-shrink: 0;
     border: 1px solid rgba(255, 255, 255, 0.05);
 }
 
@@ -120,6 +126,8 @@ export default {
     font-size: 13px;
     display: flex;
     flex-direction: column;
+    /* flex: 1; */
+    min-width: 0;
 }
 
 .info-item {
@@ -147,6 +155,7 @@ export default {
     font-size: 14px;
     font-weight: bold;
     transition: opacity 0.3s;
+    flex-shrink: 0; /* 防止按钮高度被压缩 */
 }
 
 .action-btn:hover {
@@ -163,12 +172,16 @@ export default {
     justify-content: space-between;
     gap: 8px;
     margin-top: auto;
+    flex-shrink: 0; /* 防止压缩 */
+    height: 20%; /* 动态高度 */
+    max-height: 56px; /* 封顶高度 */
+    min-height: 40px; /* 兜底高度 */
 }
 
 .phase-box {
     position: relative;
-    flex: 0 0 56px; 
-    height: 56px;
+    flex: 1; /* 平分剩余空间 */
+    height: 100%; /* 撑满 footer 的高 */
     background: #E6F0FF; 
     border-radius: 4px;
     display: flex;
@@ -211,4 +224,7 @@ export default {
 .phase-box.is-active::after {
     opacity: 1; 
 }
+.margin-top-auto {
+    margin-top: auto;
+}
 </style>

+ 38 - 12
src/components/ui/SpecialTaskMonitorPanel.vue

@@ -4,17 +4,21 @@
     <swiper class="my-swiper" :options="swiperOptions" ref="mySwiper">
       <swiper-slide v-for="(item, index) in combinedList" :key="index" class="custom-slide">
         
-        <VideoMonitorBox 
-          v-if="item.video" 
-          :videoUrl="item.video.url" 
-        />
-        <div v-else class="empty-placeholder"></div>
-
-        <IntersectionControlCard 
-          v-if="item.card" 
-          :data="item.card" 
-          class="margin-top-20"
-        />
+        <div class="top-monitor">
+          <VideoMonitorBox 
+            v-if="item.video" 
+            :videoUrl="item.video.url" 
+          />
+          <div v-else class="empty-placeholder"></div>
+        </div>
+
+        <div class="bottom-card">
+          <IntersectionControlCard 
+            v-if="item.card" 
+            :data="item.card" 
+            class="margin-top-20"
+          />
+        </div>
         
       </swiper-slide>
     </swiper>
@@ -46,6 +50,10 @@ export default {
         spaceBetween: 20,      // 列间距 20px
         simulateTouch: true,   // 允许鼠标拖拽
         speed: 600,            // 滑动动画 600ms,更加优雅
+        // 开启内部监听,当 SmartDialog 缩放导致容器尺寸变化时,Swiper 自动重新计算
+        observer: true,
+        observeParents: true,
+        observeSlideChildren: true,
         navigation: {
           nextEl: '.swiper-button-next',
           prevEl: '.swiper-button-prev'
@@ -92,13 +100,31 @@ export default {
 .custom-slide {
   display: flex;
   flex-direction: column;
+  height: 100%;
+  box-sizing: border-box;
+}
+
+/* 分配上下比例 */
+.top-monitor {
+  height: 40%; /* 视频区域占 40% */
+  min-height: 120px; /* 防止缩太小导致完全看不见 */
+  width: 100%;
+}
+
+.bottom-card {
+  height: calc(60% - 15px); /* 卡片占 60% 减去间距 */
+  margin-top: 15px;
+  width: 100%;
+  min-height: 180px; 
 }
 
 .empty-placeholder {
-  height: 220px; /* 需与 VideoMonitorBox 的高度一致 */
+  height: 100%; 
+  width: 100%;
   background: rgba(255,255,255,0.02);
   border-radius: 6px;
   border: 1px dashed rgba(255,255,255,0.1);
+  box-sizing: border-box;
 }
 
 .margin-top-20 {

+ 2 - 1
src/components/ui/VideoMonitorBox.vue

@@ -45,7 +45,8 @@ export default {
 .video-box {
   background: #112445;
   border-radius: 6px;
-  height: 220px;
+  height: 100%;
+  width: 100%;
   position: relative;
   overflow: hidden;
   border: 1px solid rgba(68, 138, 255, 0.15);

+ 9 - 8
src/views/StatusMonitoring.vue

@@ -319,7 +319,7 @@ export default {
             } else if (this.activeLeftTab === 'trunkLine') { // 干线
                 // TODO: 干线Tab的顶部图表
             } else if (this.activeLeftTab === 'specialDuty') { // 特勤
-                this.openDutyDetailDialog();
+                this.openDutyDetailDialog({id: 'route_' + new Date().getTime(), label: '特勤路口'});
             }
         },
         // 显示总览弹窗组
@@ -491,7 +491,7 @@ export default {
                 // 这里判断的条件改为 id
                 if (action === 'open-dialog' && id) {
                     this.$nextTick(() => {
-                        this.openDutyDetailDialog(id); // 打开特勤弹窗
+                        this.openDutyDetailDialog({id: id, label: '特勤路口'}); // 打开特勤弹窗
                     });
                 }
             }
@@ -514,14 +514,16 @@ export default {
         },
 
         // === 特勤详情弹窗 (你需要根据实际组件名替换) ===
-        async openDutyDetailDialog(dutyId) {
-            console.log('准备打开特勤线路详情,ID:', dutyId);
+        async openDutyDetailDialog(nodeData) {
+            console.log('准备打开特勤线路详情:', nodeData);
             // 1. 获取数据
             const panelData = await this.fetchSpecialTaskData();
-
+            
+            panelData.taskInfo.name = nodeData.label;
+            const id = 'special-task-dialog' + new Date().getTime();
             // 2. 呼出弹窗
             this.$refs.layout.openDialog({
-                id: 'special-task-dialog',
+                id: id,
                 title: ' ', // 留空以隐藏默认标题,使用自定义 Header
                 width: 1400, // 弹窗宽一点,容纳 3 列
                 height: 700,
@@ -532,14 +534,13 @@ export default {
                 // 挂载主体组件和数据
                 component: 'SpecialTaskMonitorPanel',
                 data: { panelData: panelData },
-
                 // 挂载自定义 Header 和数据
                 headerComponent: 'TaskMonitorHeader',
                 headerProps: {
                     taskData: panelData.taskInfo,
                     onEndTask: () => {
                         console.log('点击了结束任务');
-                        this.$refs.layout.handleDialogClose('special-task-dialog');
+                        this.$refs.layout.handleDialogClose(id);
                     }
                 }
             });