|
|
@@ -133,7 +133,7 @@ export default {
|
|
|
},
|
|
|
methods: {
|
|
|
// 检查地图环境是否安全可用
|
|
|
- isMapSafe() {
|
|
|
+ isMapReady() {
|
|
|
return !this._isDestroyed && this.map && typeof this.map.add === 'function';
|
|
|
},
|
|
|
|
|
|
@@ -155,7 +155,7 @@ export default {
|
|
|
|
|
|
updateMapDisplay() {
|
|
|
if (this.infoWindow) this.infoWindow.close();
|
|
|
- if (!this.isMapSafe()) return;
|
|
|
+ if (!this.isMapReady()) return;
|
|
|
|
|
|
Object.keys(this.routeGroups).forEach(name => {
|
|
|
const overlays = this.routeGroups[name];
|
|
|
@@ -196,13 +196,20 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+ // ... 其他代码保持不变
|
|
|
+ isMapReady() {
|
|
|
+ return !this._isDestroyed && this.map && typeof this.map.add === 'function';
|
|
|
+ },
|
|
|
+
|
|
|
drawStaticRoutes() {
|
|
|
- if (!this.isMapSafe()) return;
|
|
|
+ if (!this.isMapReady()) return;
|
|
|
|
|
|
this.legendConfig.forEach((config, index) => {
|
|
|
- // 使用闭包防止异步回调拿到错误的 index 或 config
|
|
|
+ // 使用箭头函数保持 this 指向 Vue 实例
|
|
|
setTimeout(() => {
|
|
|
- if (!this.isMapSafe()) return;
|
|
|
+ if (!this.isMapReady()) return;
|
|
|
|
|
|
const driving = new this.AMap.Driving({
|
|
|
map: null,
|
|
|
@@ -210,9 +217,10 @@ export default {
|
|
|
autoFitView: false
|
|
|
});
|
|
|
|
|
|
+ // 这里必须用箭头函数 (status, result) => { ... }
|
|
|
driving.search(config.start, config.end, (status, result) => {
|
|
|
- // 搜索结果返回时,组件可能已销毁
|
|
|
- if (!this.isMapSafe()) return;
|
|
|
+ // 这里的 this 才能访问到 isMapReady
|
|
|
+ if (!this.isMapReady()) return;
|
|
|
|
|
|
let path = [];
|
|
|
if (status === 'complete' && result.routes[0]) {
|
|
|
@@ -224,30 +232,30 @@ export default {
|
|
|
const markers = [];
|
|
|
let polyline = null;
|
|
|
|
|
|
+ // 路线逻辑
|
|
|
if (["干线协调", "勤务路线"].includes(config.name)) {
|
|
|
polyline = new this.AMap.Polyline({
|
|
|
path: path,
|
|
|
strokeColor: config.color,
|
|
|
- strokeWeight: 8,
|
|
|
- strokeOpacity: 0.8,
|
|
|
+ strokeWeight: 6,
|
|
|
+ strokeOpacity: 0.6,
|
|
|
zIndex: 15
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- // 抽稀取点逻辑
|
|
|
- const step = 10;
|
|
|
- for (let i = 0; i < path.length; i += step) {
|
|
|
+ // --- 稀疏化逻辑 ---
|
|
|
+ const isAbnormalStatus = ["离线", "降级", "故障"].includes(config.name);
|
|
|
+ // 异常状态(离线等)每 40 个点取一个,普通状态每 15 个点取一个
|
|
|
+ const stepSize = isAbnormalStatus ? 40 : 15;
|
|
|
+
|
|
|
+ for (let i = 0; i < path.length; i += stepSize) {
|
|
|
markers.push(this.createTrafficLightMarker(path[i], config));
|
|
|
}
|
|
|
- if ((path.length - 1) % step !== 0) {
|
|
|
- markers.push(this.createTrafficLightMarker(path[path.length - 1], config));
|
|
|
- }
|
|
|
|
|
|
const overlays = [...markers, polyline].filter(Boolean);
|
|
|
this.routeGroups[config.name] = overlays;
|
|
|
|
|
|
- // 最终添加到地图前再检查一次
|
|
|
- if (this.isMapSafe() && this.activeLegends.includes(config.name)) {
|
|
|
+ if (this.isMapReady() && this.activeLegends.includes(config.name)) {
|
|
|
this.map.add(overlays);
|
|
|
}
|
|
|
});
|
|
|
@@ -256,25 +264,44 @@ export default {
|
|
|
},
|
|
|
|
|
|
createTrafficLightMarker(position, config) {
|
|
|
- const needsFlash = ["离线", "降级", "故障"].includes(config.name);
|
|
|
+ const isAbnormal = ["离线", "降级", "故障"].includes(config.name);
|
|
|
const lng = Number(position[0] || position.lng);
|
|
|
const lat = Number(position[1] || position.lat);
|
|
|
|
|
|
+ // 3. 【视觉优化】调整 Marker 大小比例
|
|
|
+ // 异常状态图标略大(为了警示),普通点位略小且半透明
|
|
|
+ const size = isAbnormal ? '18px' : '14px';
|
|
|
+ const opacity = isAbnormal ? '1' : '0.85';
|
|
|
+ const shadow = isAbnormal ? `0 0 10px ${config.color}` : `0 0 5px ${config.color}`;
|
|
|
+
|
|
|
const marker = new this.AMap.Marker({
|
|
|
position: [lng, lat],
|
|
|
- zIndex: 100,
|
|
|
+ zIndex: isAbnormal ? 110 : 100, // 异常图标显示在更上层
|
|
|
content: `
|
|
|
- <div class="pure-light-node ${needsFlash ? 'breathe' : ''}"
|
|
|
- style="background: ${config.color}; box-shadow: 0 0 15px ${config.color}; font-size: 12px; display: flex; justify-content: center; align-items: center; color: #fff; padding: 8px;">
|
|
|
- <span>${config.name.charAt(0)}</span>
|
|
|
+ <div class="pure-light-node ${isAbnormal ? 'breathe abnormal-node' : ''}"
|
|
|
+ style="
|
|
|
+ width: ${size};
|
|
|
+ height: ${size};
|
|
|
+ background: ${config.color};
|
|
|
+ box-shadow: ${shadow};
|
|
|
+ opacity: ${opacity};
|
|
|
+ border: 1.5px solid rgba(255,255,255,0.7);
|
|
|
+ font-size: 12px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ color: #fff;
|
|
|
+ padding: 8px;
|
|
|
+ ">
|
|
|
+ <span style="transform: scale(0.7); font-weight: bold;">${config.name.charAt(0)}</span>
|
|
|
</div>
|
|
|
`,
|
|
|
- offset: new this.AMap.Pixel(-10, -10),
|
|
|
+ offset: new this.AMap.Pixel(-8, -8),
|
|
|
extData: {
|
|
|
...config,
|
|
|
position: [lng, lat],
|
|
|
statusColor: config.color,
|
|
|
- statusLabel: needsFlash ? config.name : "正常运行",
|
|
|
+ statusLabel: isAbnormal ? config.name : "正常运行",
|
|
|
road: '北京路与南京路',
|
|
|
time: '2026.1.23.12:00'
|
|
|
}
|
|
|
@@ -289,7 +316,7 @@ export default {
|
|
|
},
|
|
|
|
|
|
openLightInfo(data, position) {
|
|
|
- if (!this.isMapSafe()) return;
|
|
|
+ if (!this.isMapReady()) return;
|
|
|
|
|
|
const content = `
|
|
|
<div class="custom-info-card">
|
|
|
@@ -323,7 +350,7 @@ export default {
|
|
|
|
|
|
toggleAll() {
|
|
|
const targetState = !this.isAllSelected;
|
|
|
- if (!this.isMapSafe()) return;
|
|
|
+ if (!this.isMapReady()) return;
|
|
|
|
|
|
if (targetState) {
|
|
|
this.activeLegends = this.legendConfig.map(item => item.name);
|
|
|
@@ -340,7 +367,7 @@ export default {
|
|
|
},
|
|
|
|
|
|
toggleRouteVisible(name) {
|
|
|
- if (!this.isMapSafe()) return;
|
|
|
+ if (!this.isMapReady()) return;
|
|
|
|
|
|
const overlays = this.routeGroups[name] || [];
|
|
|
const index = this.activeLegends.indexOf(name);
|
|
|
@@ -355,7 +382,7 @@ export default {
|
|
|
},
|
|
|
|
|
|
focusByLocation(targetPos) {
|
|
|
- if (!this.isMapSafe() || !targetPos || targetPos.length !== 2) return;
|
|
|
+ if (!this.isMapReady() || !targetPos || targetPos.length !== 2) return;
|
|
|
|
|
|
let foundMarker = null;
|
|
|
Object.values(this.routeGroups).forEach(group => {
|
|
|
@@ -704,4 +731,39 @@ export default {
|
|
|
object-fit: contain;
|
|
|
display: block;
|
|
|
}
|
|
|
+
|
|
|
+::v-deep .pure-light-node {
|
|
|
+ border-radius: 50%;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ color: #fff;
|
|
|
+ pointer-events: auto;
|
|
|
+ /* 确保能点击 */
|
|
|
+}
|
|
|
+
|
|
|
+/* 异常状态增加稍微剧烈一点的呼吸感,但缩小范围 */
|
|
|
+@keyframes light-breathe {
|
|
|
+ 0% {
|
|
|
+ transform: scale(0.9);
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+
|
|
|
+ 50% {
|
|
|
+ transform: scale(1.1);
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ 100% {
|
|
|
+ transform: scale(0.9);
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 首页展示时,如果觉得还是太密,可以给非异常节点降权 */
|
|
|
+::v-deep .pure-light-node:not(.abnormal-node) {
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.4);
|
|
|
+}
|
|
|
</style>
|