Selaa lähdekoodia

干线菜单数据由地图动态生成,扫描线样式优化

  1. TongzhouTrafficMap 绘制干线完成后统计实际生成的线段数,通过 bindTrunkMenuTree 事件通知父组件
  2. 三个页面(TrunkCoordination、StatusMonitoring、SpecialSituationMonitoring)监听事件动态构建干线菜单树,
     移除静态 apiGetTrunkLineMenuTree 调用,菜单数量与地图实际显示的干线数精确同步
  3. 点击地图干线 marker 时通过 lineIdx/segmentIdx 匹配菜单节点,弹窗使用对应的 intersections 和 distances 数据
  4. 绿波图扫描线颜色改为 #1a9bff,虚线改为实线,移动速度改为1秒一动
画安 2 viikkoa sitten
vanhempi
commit
158458b7b0

+ 22 - 0
src/components/TongzhouTrafficMap.vue

@@ -348,6 +348,7 @@ export default {
         // 2. 处理路线类(干线/特勤)
         this.routeGroups[config.name] = [];
         const lines = realRouteConfigs[config.name] || [];
+        const trunkSegments = [];
 
         for (let lineIdx = 0; lineIdx < lines.length; lineIdx += 1) {
           if (this.isComponentDestroyed || drawSeq !== this.drawSeq) return;
@@ -368,6 +369,22 @@ export default {
             path
           });
 
+          // 统计干线协调实际生成的线段数
+          if (config.name === '干线协调' && overlays.length > 0) {
+            const polylineCount = overlays.filter(o => o instanceof this.AMap.Polyline).length;
+            for (let s = 0; s < polylineCount; s++) {
+              const idx = trunkSegments.length + 1;
+              trunkSegments.push({
+                id: 'trunk_' + idx,
+                label: '干线' + idx,
+                intersections: Array.from({ length: 6 }, (_, k) => '干线' + idx + '_路口' + (k + 1)),
+                distances: Array.from({ length: 6 }, (_, k) => k * 1000),
+                _lineIdx: lineIdx,
+                _segmentIdx: s
+              });
+            }
+          }
+
           if (this.isComponentDestroyed || drawSeq !== this.drawSeq) return;
 
           if (overlays.length > 0) {
@@ -377,6 +394,11 @@ export default {
 
           await this.sleep(80);
         }
+
+        // 干线协调绘制完成后,通知父组件用于菜单渲染
+        if (config.name === '干线协调' && trunkSegments.length > 0) {
+          this.$emit('bindTrunkMenuTree', trunkSegments);
+        }
       }
     },
 

+ 4 - 4
src/components/ui/TrafficTimeSpace.vue

@@ -22,7 +22,7 @@ export default {
     downWaveColor: { type: String, default: 'rgba(104, 231, 95, 0.4)' },
     waveLabelColor: { type: String, default: '#e0f7fa' },
     // 【新增】扫描线颜色配置
-    timeLineColor: { type: String, default: '#FFD54F' }
+    timeLineColor: { type: String, default: '#1a9bff' }
   },
   data() {
     return {
@@ -256,7 +256,7 @@ export default {
         style: {
           stroke: this.timeLineColor, // 线条颜色
           lineWidth: px2echarts(5), // 线条粗细
-          lineDash: [px2echarts(5), px2echarts(5)] // 设置为虚线,如果想实线可以删掉这行
+          lineDash: null // 实线
         }
       };
     },
@@ -276,7 +276,7 @@ export default {
         elapsed += delta;
         speedChangeTimer += delta;
 
-        this.currentTimeIndicator += delta;
+        this.currentTimeIndicator += 1;
 
         // 在 viewWindow 范围内循环,循环时重置所有速度
         if (this.currentTimeIndicator > this.viewWindow) {
@@ -331,7 +331,7 @@ export default {
             });
           }
         }
-      }, 16);
+      }, 1000);
     },
 
     // 【新增】停止扫描线动画

+ 26 - 7
src/views/SpecialSituationMonitoring.vue

@@ -21,7 +21,7 @@
                 @map-crossing-click="handleMapCrossingClick"
                 @map-crossing-mouseover="handleMapCrossingMouseover"
                 @map-crossing-mouseout="handleMapCrossingMouseout"
-
+                @bindTrunkMenuTree="handleTrunkMenuUpdate"
             />
         </template>
 
@@ -113,7 +113,7 @@ import TaskCardList from '@/components/ui/TaskCardList.vue';
 import CrossingListPanel from '@/components/ui/CrossingListPanel.vue';
 import OnlineStatusTabs from '@/components/ui/OnlineStatusTabs.vue';
 import DeviceStatusTabs from '@/components/ui/DeviceStatusTabs.vue';
-import { apiGetTongzhouMenuTree, apiGetTrunkLineMenuTree, apiGetTasks, apiGetTrafficTimeSpace, apiGetCrossingTopCharts, apiGetSpecialTaskMonitorData, apiGetCrossingDetailData } from '@/api';
+import { apiGetTongzhouMenuTree, apiGetTasks, apiGetTrafficTimeSpace, apiGetCrossingTopCharts, apiGetSpecialTaskMonitorData, apiGetCrossingDetailData } from '@/api';
 
 
 export default {
@@ -175,13 +175,12 @@ export default {
     },
     async mounted() {
         // 加载菜单和任务数据
-        const [menuData, trunkData, taskData] = await Promise.all([
+        const [menuData, taskData] = await Promise.all([
             apiGetTongzhouMenuTree(),
-            apiGetTrunkLineMenuTree(),
             apiGetTasks({ pageSize: 5 }),
         ]);
         this.menuData = menuData || [];
-        this.trunkLineMenuData = trunkData || [];
+        this.trunkLineMenuData = [];
         this.tableData = taskData?.list || taskData || [];
 
         // 组件挂载时检查路由
@@ -480,7 +479,6 @@ export default {
             const parts = markerId.split('-');
             const lineIdx = parseInt(parts[2], 10);
             const segmentIdx = parseInt(parts[3], 10);
-            const trunkIdx = lineIdx < 4 ? lineIdx * 2 + segmentIdx : 8;
             const leaves = [];
             const walk = (nodes) => {
                 if (!Array.isArray(nodes)) return;
@@ -490,7 +488,28 @@ export default {
                 }
             };
             walk(this.trunkLineMenuData);
-            return leaves[trunkIdx] || null;
+            return leaves.find(n => n._lineIdx === lineIdx && n._segmentIdx === segmentIdx) || null;
+        },
+        handleTrunkMenuUpdate(segments) {
+            this.trunkLineMenuData = [{
+                id: 'trunk_root',
+                label: '主控中心',
+                icon: 'icon-control',
+                isOpen: true,
+                children: [{
+                    id: 'trunk_beijing',
+                    label: '北京市交警总队',
+                    icon: 'icon-police',
+                    isOpen: true,
+                    children: [{
+                        id: 'trunk_tongzhou',
+                        label: '通州区',
+                        icon: 'icon-district',
+                        isOpen: true,
+                        children: segments
+                    }]
+                }]
+            }];
         },
         async showTrunkLineDalogs(nodeData) {
             console.log('显示干线弹窗组', nodeData.id, nodeData.label);

+ 26 - 7
src/views/StatusMonitoring.vue

@@ -21,7 +21,7 @@
                 @map-crossing-click="handleMapCrossingClick"
                 @map-crossing-mouseover="handleMapCrossingMouseover"
                 @map-crossing-mouseout="handleMapCrossingMouseout"
-
+                @bindTrunkMenuTree="handleTrunkMenuUpdate"
             />
         </template>
 
@@ -113,7 +113,7 @@ import TaskCardList from '@/components/ui/TaskCardList.vue';
 import CrossingListPanel from '@/components/ui/CrossingListPanel.vue';
 import OnlineStatusTabs from '@/components/ui/OnlineStatusTabs.vue';
 import DeviceStatusTabs from '@/components/ui/DeviceStatusTabs.vue';
-import { apiGetTongzhouMenuTree, apiGetTrunkLineMenuTree, apiGetTasks, apiGetTrafficTimeSpace, apiGetCrossingTopCharts, apiGetSpecialTaskMonitorData, apiGetCrossingDetailData } from '@/api';
+import { apiGetTongzhouMenuTree, apiGetTasks, apiGetTrafficTimeSpace, apiGetCrossingTopCharts, apiGetSpecialTaskMonitorData, apiGetCrossingDetailData } from '@/api';
 
 
 export default {
@@ -175,13 +175,12 @@ export default {
     },
     async mounted() {
         // 加载菜单和任务数据
-        const [menuData, trunkData, taskData] = await Promise.all([
+        const [menuData, taskData] = await Promise.all([
             apiGetTongzhouMenuTree(),
-            apiGetTrunkLineMenuTree(),
             apiGetTasks({ pageSize: 5 }),
         ]);
         this.menuData = menuData || [];
-        this.trunkLineMenuData = trunkData || [];
+        this.trunkLineMenuData = [];
         this.tableData = taskData?.list || taskData || [];
 
         // 组件挂载时检查路由
@@ -486,7 +485,6 @@ export default {
             const parts = markerId.split('-');
             const lineIdx = parseInt(parts[2], 10);
             const segmentIdx = parseInt(parts[3], 10);
-            const trunkIdx = lineIdx < 4 ? lineIdx * 2 + segmentIdx : 8;
             const leaves = [];
             const walk = (nodes) => {
                 if (!Array.isArray(nodes)) return;
@@ -496,7 +494,28 @@ export default {
                 }
             };
             walk(this.trunkLineMenuData);
-            return leaves[trunkIdx] || null;
+            return leaves.find(n => n._lineIdx === lineIdx && n._segmentIdx === segmentIdx) || null;
+        },
+        handleTrunkMenuUpdate(segments) {
+            this.trunkLineMenuData = [{
+                id: 'trunk_root',
+                label: '主控中心',
+                icon: 'icon-control',
+                isOpen: true,
+                children: [{
+                    id: 'trunk_beijing',
+                    label: '北京市交警总队',
+                    icon: 'icon-police',
+                    isOpen: true,
+                    children: [{
+                        id: 'trunk_tongzhou',
+                        label: '通州区',
+                        icon: 'icon-district',
+                        isOpen: true,
+                        children: segments
+                    }]
+                }]
+            }];
         },
         async showTrunkLineDalogs(nodeData) {
             console.log('显示干线弹窗组', nodeData.id, nodeData.label);

+ 27 - 9
src/views/TrunkCoordination.vue

@@ -21,7 +21,7 @@
                 @map-crossing-click="handleMapCrossingClick"
                 @map-crossing-mouseover="handleMapCrossingMouseover"
                 @map-crossing-mouseout="handleMapCrossingMouseout"
-
+                @bindTrunkMenuTree="handleTrunkMenuUpdate"
             />
         </template>
 
@@ -113,7 +113,7 @@ import TaskCardList from '@/components/ui/TaskCardList.vue';
 import CrossingListPanel from '@/components/ui/CrossingListPanel.vue';
 import OnlineStatusTabs from '@/components/ui/OnlineStatusTabs.vue';
 import DeviceStatusTabs from '@/components/ui/DeviceStatusTabs.vue';
-import { apiGetTongzhouMenuTree, apiGetTrunkLineMenuTree, apiGetTasks, apiGetTrafficTimeSpace, apiGetCrossingTopCharts, apiGetSpecialTaskMonitorData, apiGetCrossingDetailData } from '@/api';
+import { apiGetTongzhouMenuTree, apiGetTasks, apiGetTrafficTimeSpace, apiGetCrossingTopCharts, apiGetSpecialTaskMonitorData, apiGetCrossingDetailData } from '@/api';
 
 
 export default {
@@ -175,13 +175,12 @@ export default {
     },
     async mounted() {
         // 加载菜单和任务数据
-        const [menuData, trunkData, taskData] = await Promise.all([
+        const [menuData, taskData] = await Promise.all([
             apiGetTongzhouMenuTree(),
-            apiGetTrunkLineMenuTree(),
             apiGetTasks({ pageSize: 5 }),
         ]);
         this.menuData = menuData || [];
-        this.trunkLineMenuData = trunkData || [];
+        this.trunkLineMenuData = [];
         this.tableData = taskData?.list || taskData || [];
 
         // 组件挂载时检查路由
@@ -481,9 +480,7 @@ export default {
             const parts = markerId.split('-');
             const lineIdx = parseInt(parts[2], 10);
             const segmentIdx = parseInt(parts[3], 10);
-            // 前4条路线各拆2段,第5条1段,计算干线编号
-            const trunkIdx = lineIdx < 4 ? lineIdx * 2 + segmentIdx : 8;
-            // 从菜单树中找叶子节点
+            // 从菜单叶子节点中找 _lineIdx 和 _segmentIdx 匹配的
             const leaves = [];
             const walk = (nodes) => {
                 if (!Array.isArray(nodes)) return;
@@ -493,7 +490,28 @@ export default {
                 }
             };
             walk(this.trunkLineMenuData);
-            return leaves[trunkIdx] || null;
+            return leaves.find(n => n._lineIdx === lineIdx && n._segmentIdx === segmentIdx) || null;
+        },
+        handleTrunkMenuUpdate(segments) {
+            this.trunkLineMenuData = [{
+                id: 'trunk_root',
+                label: '主控中心',
+                icon: 'icon-control',
+                isOpen: true,
+                children: [{
+                    id: 'trunk_beijing',
+                    label: '北京市交警总队',
+                    icon: 'icon-police',
+                    isOpen: true,
+                    children: [{
+                        id: 'trunk_tongzhou',
+                        label: '通州区',
+                        icon: 'icon-district',
+                        isOpen: true,
+                        children: segments
+                    }]
+                }]
+            }];
         },
         async showTrunkLineDalogs(nodeData) {
             console.log('显示干线弹窗组', nodeData.id, nodeData.label);