|
|
@@ -208,23 +208,25 @@ export default {
|
|
|
// 将真实路口数据按状态类型分类
|
|
|
classifyIntersectionsByStatus() {
|
|
|
const remainingData = this.intersectionData;
|
|
|
- const normalStatusCount = 6;
|
|
|
- const abnormalStatusCount = 3;
|
|
|
- const chunkSize = Math.floor(remainingData.length / (normalStatusCount + abnormalStatusCount));
|
|
|
const maxAbnormalCount = 4;
|
|
|
+ // 异常状态各取4个,剩余全部按比例分配给6个正常状态
|
|
|
+ const abnormalTotal = maxAbnormalCount * 3;
|
|
|
+ const normalData = remainingData.slice(0, remainingData.length - abnormalTotal);
|
|
|
+ const abnormalData = remainingData.slice(remainingData.length - abnormalTotal);
|
|
|
+ const normalChunk = Math.ceil(normalData.length / 6);
|
|
|
|
|
|
this.statusIntersections = {
|
|
|
- "中心计划": remainingData.slice(0, 20),
|
|
|
+ "中心计划": normalData.slice(0, normalChunk),
|
|
|
"干线协调": [], // 清空,改为动态生成
|
|
|
"勤务路线": [], // 清空,改为动态生成
|
|
|
- "定周期控制": remainingData.slice(chunkSize, chunkSize * 2),
|
|
|
- "感应控制": remainingData.slice(chunkSize * 2, chunkSize * 3),
|
|
|
- "自适应控制": remainingData.slice(chunkSize * 3, chunkSize * 4),
|
|
|
- "手动控制": remainingData.slice(chunkSize * 4, chunkSize * 5),
|
|
|
- "特殊控制": remainingData.slice(chunkSize * 5, chunkSize * 6),
|
|
|
- "离线": remainingData.slice(chunkSize * 6, Math.min(chunkSize * 7, chunkSize * 6 + maxAbnormalCount)),
|
|
|
- "降级": remainingData.slice(chunkSize * 7, Math.min(chunkSize * 8, chunkSize * 7 + maxAbnormalCount)),
|
|
|
- "故障": remainingData.slice(chunkSize * 8, Math.min(chunkSize * 9, chunkSize * 8 + maxAbnormalCount))
|
|
|
+ "定周期控制": normalData.slice(normalChunk, normalChunk * 2),
|
|
|
+ "感应控制": normalData.slice(normalChunk * 2, normalChunk * 3),
|
|
|
+ "自适应控制": normalData.slice(normalChunk * 3, normalChunk * 4),
|
|
|
+ "手动控制": normalData.slice(normalChunk * 4, normalChunk * 5),
|
|
|
+ "特殊控制": normalData.slice(normalChunk * 5),
|
|
|
+ "离线": abnormalData.slice(0, maxAbnormalCount),
|
|
|
+ "降级": abnormalData.slice(maxAbnormalCount, maxAbnormalCount * 2),
|
|
|
+ "故障": abnormalData.slice(maxAbnormalCount * 2, maxAbnormalCount * 3)
|
|
|
};
|
|
|
},
|
|
|
|
|
|
@@ -311,11 +313,12 @@ export default {
|
|
|
|
|
|
const realRouteConfigs = {
|
|
|
"干线协调": [
|
|
|
- { start: [116.6421, 39.9272], end: [116.6825, 39.9272], color: "#13C373" },
|
|
|
- { start: [116.6426, 39.9221], end: [116.6830, 39.9221], color: "#13C373" },
|
|
|
- { start: [116.6432, 39.9171], end: [116.6833, 39.9171], color: "#13C373" },
|
|
|
- { start: [116.6438, 39.9123], end: [116.6841, 39.9123], color: "#13C373" },
|
|
|
- { start: [116.6445, 39.9075], end: [116.6846, 39.9075], color: "#13C373" }
|
|
|
+ { start: [116.6421, 39.9272], end: [116.6623, 39.9272], color: "#13C373", trunkId: 'trunk_1', trunkName: '古城南路与古城大街' },
|
|
|
+ { start: [116.6623, 39.9272], end: [116.6825, 39.9272], color: "#13C373", trunkId: 'trunk_2', trunkName: '古城西路东口南一过街' },
|
|
|
+ { start: [116.6426, 39.9221], end: [116.6628, 39.9221], color: "#13C373", trunkId: 'trunk_3', trunkName: '古城大街与古城北路' },
|
|
|
+ { start: [116.6628, 39.9221], end: [116.683, 39.9221], color: "#13C373", trunkId: 'trunk_4', trunkName: '八角北路与八角东街' },
|
|
|
+ { start: [116.6432, 39.9171], end: [116.66325, 39.9171], color: "#13C373", trunkId: 'trunk_5', trunkName: '古城西路与古城大街' },
|
|
|
+ { start: [116.66325, 39.9171], end: [116.6833, 39.9171], color: "#13C373", trunkId: 'trunk_6', trunkName: '张台路与湖亦路路口' },
|
|
|
],
|
|
|
"勤务路线": [
|
|
|
// 第一段:未执行(全红)— 通州大街西段,干线协调下方约600m
|
|
|
@@ -336,6 +339,7 @@ export default {
|
|
|
const markers = intersections.map(item =>
|
|
|
this.createTrafficLightMarker([item["位置-经度"], item["位置-纬度"]], {
|
|
|
...config,
|
|
|
+ id: item["路口编号"],
|
|
|
road: item["路口名称"] || '规划路口'
|
|
|
})
|
|
|
).filter(Boolean);
|
|
|
@@ -368,25 +372,16 @@ export default {
|
|
|
path
|
|
|
});
|
|
|
|
|
|
- // 统计干线协调实际生成的线段数
|
|
|
+ // 每条路线配置对应一条干线菜单项
|
|
|
if (config.name === '干线协调' && overlays.length > 0) {
|
|
|
- const trunkNames = [
|
|
|
- '古城南路与古城大街', '古城西路东口南一过街', '古城大街与古城北路',
|
|
|
- '八角北路与八角东街', '古城西路与古城大街'
|
|
|
- ];
|
|
|
- const polylineCount = overlays.filter(o => o instanceof this.AMap.Polyline).length;
|
|
|
- for (let s = 0; s < polylineCount; s++) {
|
|
|
- const idx = trunkSegments.length + 1;
|
|
|
- const name = trunkNames[idx - 1] || ('干线' + idx);
|
|
|
- trunkSegments.push({
|
|
|
- id: 'trunk_' + idx,
|
|
|
- label: name,
|
|
|
- intersections: Array.from({ length: 6 }, (_, k) => name + '_路口' + (k + 1)),
|
|
|
- distances: Array.from({ length: 6 }, (_, k) => k * 1000),
|
|
|
- _lineIdx: lineIdx,
|
|
|
- _segmentIdx: s
|
|
|
- });
|
|
|
- }
|
|
|
+ const name = line.trunkName || ('干线' + (lineIdx + 1));
|
|
|
+ trunkSegments.push({
|
|
|
+ id: line.trunkId || ('trunk_' + (lineIdx + 1)),
|
|
|
+ label: name,
|
|
|
+ intersections: Array.from({ length: 6 }, (_, k) => name + '_路口' + (k + 1)),
|
|
|
+ distances: Array.from({ length: 6 }, (_, k) => k * 500),
|
|
|
+ _lineIdx: lineIdx
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
if (this.isComponentDestroyed || drawSeq !== this.drawSeq) return;
|
|
|
@@ -497,7 +492,11 @@ export default {
|
|
|
return [lng + offsetVal, lat + offsetVal];
|
|
|
};
|
|
|
|
|
|
- const segments = this.extractMainStraightSegments(basePath);
|
|
|
+ const allSegments = this.extractMainStraightSegments(basePath);
|
|
|
+ // 干线协调每条路线只取最长的1段,保证6条配置 = 6条线
|
|
|
+ const segments = configName === '干线协调'
|
|
|
+ ? allSegments.slice(0, 1)
|
|
|
+ : allSegments;
|
|
|
const overlays = [];
|
|
|
|
|
|
segments.forEach((rawSegmentPath, segmentIdx) => {
|
|
|
@@ -690,10 +689,18 @@ export default {
|
|
|
else if (i === indices.length - 1) markerType = 'end';
|
|
|
}
|
|
|
|
|
|
+ // 干线协调:id 用干线编号,road 用干线名称(与菜单标题一致)
|
|
|
+ const markerId = (configName === '干线协调' && line.trunkId)
|
|
|
+ ? `${line.trunkId}_point_${i + 1}`
|
|
|
+ : `MOCK-${configName.charAt(0)}-${lineIdx}-${segmentIdx}-${idx}`;
|
|
|
+ const markerRoad = (configName === '干线协调' && line.trunkName)
|
|
|
+ ? line.trunkName
|
|
|
+ : `${configName}路口-${lineIdx}-${segmentIdx}-${idx}`;
|
|
|
+
|
|
|
const marker = this.createTrafficLightMarker([lng, lat], {
|
|
|
...config,
|
|
|
- id: `MOCK-${configName.charAt(0)}-${lineIdx}-${segmentIdx}-${idx}`,
|
|
|
- road: `${configName}路口-${lineIdx}-${segmentIdx}-${idx}`
|
|
|
+ id: markerId,
|
|
|
+ road: markerRoad
|
|
|
}, markerType);
|
|
|
if (marker) overlays.push(marker);
|
|
|
}
|
|
|
@@ -1135,13 +1142,13 @@ export default {
|
|
|
const dx = markerPos[0] - targetLng;
|
|
|
const dy = markerPos[1] - targetLat;
|
|
|
const distSq = dx * dx + dy * dy;
|
|
|
-
|
|
|
+
|
|
|
// 容差范围内(约 20 米),寻找最接近的点
|
|
|
if (distSq < 0.000001) {
|
|
|
// 优先规则:如果距离相同或非常接近,优先选择异常状态点(离线/降级/故障)
|
|
|
const isAbnormal = ["离线", "降级", "故障"].includes(markerExt.name);
|
|
|
const currentIsAbnormal = bestMarker ? ["离线", "降级", "故障"].includes(bestMarker.getExtData().name) : false;
|
|
|
-
|
|
|
+
|
|
|
if (distSq < minDistanceSq || (isAbnormal && !currentIsAbnormal)) {
|
|
|
minDistanceSq = distSq;
|
|
|
bestMarker = item;
|
|
|
@@ -1162,6 +1169,34 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
+ // 通过路口编号定位到对应的 marker,弹出信息窗
|
|
|
+ focusById(id) {
|
|
|
+ if (!this.isMapReady() || !id) return null;
|
|
|
+
|
|
|
+ let bestMarker = null;
|
|
|
+ Object.values(this.routeGroups).forEach(group => {
|
|
|
+ if (!Array.isArray(group) || bestMarker) return;
|
|
|
+ group.forEach(item => {
|
|
|
+ if (bestMarker) return;
|
|
|
+ if (!(item instanceof this.AMap.Marker)) return;
|
|
|
+ const ext = item.getExtData();
|
|
|
+ if (ext.id === id || ext['路口编号'] === id) {
|
|
|
+ bestMarker = item;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ if (bestMarker) {
|
|
|
+ const finalPos = bestMarker.getPosition();
|
|
|
+ this.map.setZoomAndCenter(17, finalPos, false, 500);
|
|
|
+ setTimeout(() => {
|
|
|
+ if (!this.isComponentDestroyed) this.openLightInfo(bestMarker.getExtData(), finalPos);
|
|
|
+ }, 600);
|
|
|
+ return finalPos;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ },
|
|
|
+
|
|
|
toggleLegend() {
|
|
|
this.legendVisible = !this.legendVisible;
|
|
|
},
|