Просмотр исходного кода

修改ButtonGroup组件可以自定义参数;调整状态监控页面添加路口的地图和列表模式切换按钮及功能逻辑实现;

画安 дней назад: 2
Родитель
Сommit
7d57fc5a30
2 измененных файлов с 86 добавлено и 50 удалено
  1. 46 37
      src/components/ui/ButtonGroup.vue
  2. 40 13
      src/views/StatusMonitoring.vue

+ 46 - 37
src/components/ui/ButtonGroup.vue

@@ -1,11 +1,11 @@
 <template>
   <div class="custom-button-group">
     <div
-      v-for="(item, index) in tabs"
-      :key="index"
+      v-for="(item, index) in options"
+      :key="item.value || index"
       class="group-item"
-      :class="{ 'is-active': activeIndex === index }"
-      @click="handleTabClick(index, item)"
+      :class="{ 'is-active': value === item.value }"
+      @click="handleTabClick(item)"
     >
       {{ item.label }}
     </div>
@@ -15,34 +15,33 @@
 <script>
 export default {
   name: 'ButtonGroup',
-  // 如果你想从外部传入初始选中的值,可以通过 props
+  // 配置自定义 v-model
+  model: {
+    prop: 'value',
+    event: 'change'
+  },
   props: {
-    defaultIndex: {
-      type: Number,
-      default: 0
+    // 接收外部传入的当前选中值
+    value: {
+      type: [String, Number],
+      default: ''
+    },
+    // 接收外部传入的按钮配置列表
+    options: {
+      type: Array,
+      default: () => [] 
+      // 数据格式应为: [{ label: '展示文本', value: '唯一标识' }]
     }
   },
-  data() {
-    return {
-      activeIndex: this.defaultIndex,
-      // 定义按钮组的数据和对应的标识(value)
-      tabs: [
-        { label: '总览', value: 'overview' },
-        { label: '路口', value: 'intersection' },
-        { label: '干线', value: 'arterial' },
-        { label: '特勤', value: 'special' }
-      ]
-    };
-  },
   methods: {
-    handleTabClick(index, item) {
-      // 如果点击的是当前已选中的,则不重复触发
-      if (this.activeIndex === index) return;
+    handleTabClick(item) {
+      // 避免重复点击触发
+      if (this.value === item.value) return;
       
-      this.activeIndex = index;
-      
-      // 向父组件抛出 change 事件,并传递当前选中的 value
+      // 抛出 change 事件,更新 v-model 绑定的值
       this.$emit('change', item.value);
+      // 额外抛出一个完整对象的事件,方便父组件需要获取 label 时使用
+      this.$emit('select', item);
     }
   }
 };
@@ -52,27 +51,37 @@ export default {
 /* 整个按钮组的外层容器 */
 .custom-button-group {
   display: flex;
-  align-items: center;
-  /* 假设整体宽度 400px,高度 40px,pxtorem 会自动转换 */
-  width: 700px; 
-  height: 50px;
+  align-items: stretch; /* 让子元素填满高度 */
+  width: 100%; /* 自适应父容器宽度 */
+  min-height: 40px; /* 给一个基础最小高度,或者完全靠子元素的 padding 撑起 */
+  
   /* 整体边框颜色:淡蓝色半透明 */
   border: 1px solid rgba(100, 150, 255, 0.6);
-  background: rgba(20, 40, 80, 0.4); /* 未选中的底层背景色 */
+  background: rgba(20, 40, 80, 0.4); 
   box-sizing: border-box;
+  
+  /* 可选:加上微小的圆角会让组件看起来更精致 */
+  border-radius: 4px; 
+  overflow: hidden; 
 }
 
 /* 单个按钮项 */
 .group-item {
-  flex: 1; /* 平分宽度 */
-  height: 100%;
+  flex: 1; /* 平分剩余宽度 */
   display: flex;
   justify-content: center;
   align-items: center;
-  color: #a0a5b0; /* 未选中时的灰白色字体 */
+  
+  /* 使用 padding 替代固定的 height,自适应更好 */
+  padding: 8px 16px; 
+  
+  color: #a0a5b0; 
   font-size: 14px;
   cursor: pointer;
   transition: all 0.3s ease;
+  user-select: none; /* 防止双击选中文本 */
+  white-space: nowrap; /* 防止文字换行 */
+  
   /* 右侧分割线 */
   border-right: 1px solid rgba(100, 150, 255, 0.6);
   box-sizing: border-box;
@@ -92,8 +101,8 @@ export default {
 /* 选中状态(激活态)的样式 */
 .group-item.is-active {
   /* 选中时的背景色:更亮、不透明度更高的蓝色 */
-  background: rgba(70, 130, 255, 0.2); 
-  color: #ffffff; /* 选中时字体纯白 */
-  font-weight: bold; /* 选中时字体加粗 */
+  background: rgba(70, 130, 255, 0.3); 
+  color: #ffffff; 
+  font-weight: bold; 
 }
 </style>

+ 40 - 13
src/views/StatusMonitoring.vue

@@ -10,10 +10,8 @@
 
         <template #map>
             <!-- 地图 -->
-            <TongzhouTrafficMap
-            amapKey="db2da7e3e248c3b2077d53fc809be63f"
-            securityJsCode="a7413c674852c5eaf01d90813c5b7ef6"
-            />
+            <TongzhouTrafficMap amapKey="db2da7e3e248c3b2077d53fc809be63f"
+                securityJsCode="a7413c674852c5eaf01d90813c5b7ef6" />
         </template>
 
         <template #left>
@@ -41,18 +39,21 @@
         </template>
 
         <template #right>
-
+            <!-- 模式切换按钮组 -->
+            <div class="mode-switch" v-if="activeLeftTab === 'crossing'">
+                <ButtonGroup v-model="currentView" :options="viewOptions" @select="onViewSelect" />
+            </div>
         </template>
 
         <template #center>
-            
+
         </template>
 
         <template #dialogs>
             <SmartDialog v-for="dialog in activeDialogs" :key="dialog.id" :id="dialog.id" :visible.sync="dialog.visible"
                 :title="dialog.title" :defaultWidth="dialog.width || 400" :defaultHeight="dialog.height || 300"
-                :center="dialog.center !== false" :position="dialog.position" :showClose="dialog.showClose" :enableDblclickExpand="dialog.enableDblclickExpand" :noPadding="dialog.noPadding"
-
+                :center="dialog.center !== false" :position="dialog.position" :showClose="dialog.showClose"
+                :enableDblclickExpand="dialog.enableDblclickExpand" :noPadding="dialog.noPadding"
                 @close="handleDialogClose(dialog.id)" @expand="handleDoubleClickExpend(dialog.data)">
 
                 <component :is="dialog.componentName" v-bind="dialog.data"></component>
@@ -78,6 +79,7 @@ import MenuItem from '@/components/ui/MenuItem.vue';
 import RingDonutChart from '@/components/ui/RingDonutChart.vue';
 import CrossingPanel from '@/components/ui/CrossingPanel.vue';
 import CrossingDetailPanel from '@/components/ui/CrossingDetailPanel.vue';
+import ButtonGroup from '@/components/ui/ButtonGroup.vue';
 import { getIntersectionData, makeTrafficTimeSpaceData } from '@/mock/data';
 
 
@@ -98,7 +100,8 @@ export default {
         TrafficTimeSpace,
         RingDonutChart,
         CrossingPanel,
-        CrossingDetailPanel
+        CrossingDetailPanel,
+        ButtonGroup
     },
     data() {
         return {
@@ -227,6 +230,12 @@ export default {
                         }
                     ]
                 }
+            ],
+            // 地图模式切换数据
+            currentView: 'map-mode',
+            viewOptions: [
+                { label: '列表模式', value: 'list-mode' },
+                { label: '地图模式', value: 'map-mode' },
             ]
         };
     },
@@ -249,6 +258,11 @@ export default {
         //     });
     },
     methods: {
+        // 模式切换
+        onViewSelect(item) {
+            console.log('你点击了:', item.label);
+            this.currentView = item.value;
+        },
         // 处理tab点击
         handleTabClick(nodeData) {
             console.log('父组件接收到了tab点击事件:', nodeData);
@@ -284,9 +298,9 @@ export default {
             } else if (this.activeLeftTab === 'crossing') { // 路口
                 this.showCrossingDetailDialogs(nodeData);
             } else if (this.activeLeftTab === 'trunkLine') { // 干线
-                
+
             } else if (this.activeLeftTab === 'specialDuty') { // 特勤
-               
+
             }
         },
         openDialog(config) {
@@ -331,6 +345,12 @@ export default {
         showCrossingDalogs(nodeData) {
             console.log('显示干线弹窗组', nodeData.id, nodeData.label);
 
+            // 列表模式弹窗
+            if (this.currentView === 'list-mode') {
+                
+                return;
+            }
+
             this.openDialog({
                 id: 'crossing_' + nodeData.id, // 这里的 ID 可以根据实际业务场景动态生成
                 title: '',
@@ -392,7 +412,7 @@ export default {
 
         showCrossingDetailDialogs(nodeData) {
             console.log('显示干线弹窗组', nodeData.id, nodeData.label);
-             this.openDialog({
+            this.openDialog({
                 id: 'crossing_detail' + nodeData.id, // 这里的 ID 可以根据实际业务场景动态生成,例如 'dev-security-route' 代表特勤安保路线弹窗
                 title: nodeData.label,
                 component: 'CrossingDetailPanel',
@@ -523,5 +543,12 @@ export default {
 }
 </script>
 <style scoped>
-
+.mode-switch {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-end;
+}
+.mode-switch>div {
+    width: 200px;
+}
 </style>