|
|
|
@ -45,6 +45,8 @@ |
|
|
|
@copy-route="handleCopyRouteFromMenu" |
|
|
|
@edit-platform="openEditPlatformDialog" |
|
|
|
@power-zone="openPowerZoneDialog" |
|
|
|
@open-waypoint-dialog="handleContextMenuOpenWaypointDialog" |
|
|
|
@add-waypoint-at="handleAddWaypointAt" |
|
|
|
/> |
|
|
|
|
|
|
|
<!-- 定位弹窗 --> |
|
|
|
@ -270,7 +272,7 @@ export default { |
|
|
|
fontSize: 16, |
|
|
|
fontColor: '#333333', |
|
|
|
iconSize: 144, |
|
|
|
iconColor: '#ffffff' |
|
|
|
iconColor: '#000000' |
|
|
|
}, |
|
|
|
// 编辑平台属性:字体颜色、平台颜色预选 |
|
|
|
presetColors: [ |
|
|
|
@ -357,7 +359,10 @@ export default { |
|
|
|
// 航线复制预览:整条航线跟随鼠标,左键放置 |
|
|
|
copyPreviewWaypoints: null, |
|
|
|
copyPreviewEntity: null, |
|
|
|
copyPreviewMouseCartesian: null |
|
|
|
copyPreviewMouseCartesian: null, |
|
|
|
// 在航点前/后增加航点:{ routeId, waypointIndex, mode: 'before'|'after', waypoints },预览折线实体 |
|
|
|
addWaypointContext: null, |
|
|
|
addWaypointPreviewEntity: null |
|
|
|
} |
|
|
|
}, |
|
|
|
components: { |
|
|
|
@ -1614,11 +1619,31 @@ export default { |
|
|
|
} |
|
|
|
return !!nextLogical; |
|
|
|
}; |
|
|
|
// 遍历并绘制航点标记:转弯半径处不画中心点;盘旋处也不画圆心点,只保留圆弧,避免主折线出现穿过圆心的直线 |
|
|
|
// 遍历并绘制航点标记:转弯半径处不画中心点;盘旋处在圆心画一小点便于右键“向前/向后增加航点” |
|
|
|
waypoints.forEach((wp, index) => { |
|
|
|
if (isTurnWaypointWithArc(index)) return; |
|
|
|
if (this.isHoldWaypoint(wp)) return; |
|
|
|
const pos = originalPositions[index]; |
|
|
|
if (this.isHoldWaypoint(wp)) { |
|
|
|
this.viewer.entities.add({ |
|
|
|
id: `wp_${routeId}_${wp.id}`, |
|
|
|
name: wp.name || `盘旋${index + 1}`, |
|
|
|
position: pos, |
|
|
|
properties: { |
|
|
|
isMissionWaypoint: true, |
|
|
|
routeId: routeId, |
|
|
|
dbId: wp.id, |
|
|
|
}, |
|
|
|
point: { |
|
|
|
pixelSize: Math.max(4, pixelSize - 2), |
|
|
|
color: Cesium.Color.fromCssColorString(wpColor), |
|
|
|
outlineColor: Cesium.Color.fromCssColorString(wpOutline), |
|
|
|
outlineWidth: wpOutlineW, |
|
|
|
disableDepthTestDistance: Number.POSITIVE_INFINITY |
|
|
|
}, |
|
|
|
label: { show: false } |
|
|
|
}); |
|
|
|
return; |
|
|
|
} |
|
|
|
this.viewer.entities.add({ |
|
|
|
id: `wp_${routeId}_${wp.id}`, |
|
|
|
name: wp.name || `WP${index + 1}`, |
|
|
|
@ -1712,8 +1737,10 @@ export default { |
|
|
|
platformId: platId |
|
|
|
}).then(res => { |
|
|
|
const style = res.data; |
|
|
|
const color = (style && style.platformColor) ? style.platformColor : '#ffffff'; |
|
|
|
const size = (style && style.platformSize != null) ? Math.max(48, Math.min(256, Number(style.platformSize))) : 144; |
|
|
|
const defaultColor = '#000000'; |
|
|
|
const defaultSize = 144; |
|
|
|
const color = (style && style.platformColor) ? style.platformColor : defaultColor; |
|
|
|
const size = (style && style.platformSize != null) ? Math.max(48, Math.min(256, Number(style.platformSize))) : defaultSize; |
|
|
|
this.$set(this.platformCustomStyles, routeId, { |
|
|
|
labelFontSize: style && style.labelFontSize, |
|
|
|
labelFontColor: style && style.labelFontColor, |
|
|
|
@ -1726,11 +1753,24 @@ export default { |
|
|
|
if (style && style.powerZoneRadius != null && Number(style.powerZoneRadius) > 0) { |
|
|
|
this.ensurePowerZoneForRoute(routeId, style.powerZoneRadius, style.powerZoneColor || 'rgba(255, 0, 0, 0.3)'); |
|
|
|
} |
|
|
|
// 无 Redis 样式时,将默认黑色写入 Redis,便于下次加载一致 |
|
|
|
if (!style || style.platformColor == null) { |
|
|
|
savePlatformStyle({ |
|
|
|
roomId: String(currentRoomId), |
|
|
|
routeId: routeId, |
|
|
|
platformId: platId, |
|
|
|
platformName: (platform && platform.name) || undefined, |
|
|
|
labelFontSize: style && style.labelFontSize != null ? style.labelFontSize : 16, |
|
|
|
labelFontColor: (style && style.labelFontColor) || '#333333', |
|
|
|
platformSize: size, |
|
|
|
platformColor: defaultColor |
|
|
|
}).catch(() => {}); |
|
|
|
} |
|
|
|
}).catch(() => { |
|
|
|
addPlatformBillboard('#ffffff', 144); |
|
|
|
addPlatformBillboard('#000000', 144); |
|
|
|
}); |
|
|
|
} else { |
|
|
|
addPlatformBillboard('#ffffff', 144); |
|
|
|
addPlatformBillboard('#000000', 144); |
|
|
|
} |
|
|
|
|
|
|
|
// 飞机标牌:显示名字、高度、速度、航向,随飞机实时运动 |
|
|
|
@ -2621,6 +2661,29 @@ export default { |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
// 增加航点模式:左键放置新航点 |
|
|
|
if (this.addWaypointContext) { |
|
|
|
const ctx = this.addWaypointContext; |
|
|
|
const waypoints = ctx.waypoints || []; |
|
|
|
const refAlt = ctx.mode === 'before' |
|
|
|
? (waypoints[ctx.waypointIndex - 1] && Number(waypoints[ctx.waypointIndex - 1].alt)) || (waypoints[ctx.waypointIndex] && Number(waypoints[ctx.waypointIndex].alt)) || 5000 |
|
|
|
: (waypoints[ctx.waypointIndex] && Number(waypoints[ctx.waypointIndex].alt)) || (waypoints[ctx.waypointIndex + 1] && Number(waypoints[ctx.waypointIndex + 1].alt)) || 5000; |
|
|
|
const placePosition = this.getClickPositionWithHeight(click.position, refAlt); |
|
|
|
if (placePosition) { |
|
|
|
const carto = Cesium.Cartographic.fromCartesian(placePosition); |
|
|
|
const lng = Cesium.Math.toDegrees(carto.longitude); |
|
|
|
const lat = Cesium.Math.toDegrees(carto.latitude); |
|
|
|
const alt = carto.height; |
|
|
|
this.$emit('add-waypoint-placed', { |
|
|
|
routeId: ctx.routeId, |
|
|
|
waypointIndex: ctx.waypointIndex, |
|
|
|
mode: ctx.mode, |
|
|
|
position: { lng, lat, alt } |
|
|
|
}); |
|
|
|
} |
|
|
|
this.clearAddWaypointContext(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const pickedObject = this.viewer.scene.pick(click.position); |
|
|
|
if (Cesium.defined(pickedObject) && pickedObject.id) { |
|
|
|
@ -2768,6 +2831,14 @@ export default { |
|
|
|
if (this.viewer.scene.requestRender) this.viewer.scene.requestRender(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (this.addWaypointContext) { |
|
|
|
const cartesian = this.getClickPosition(movement.endPosition); |
|
|
|
if (cartesian) { |
|
|
|
this.addWaypointContext.mouseCartesian = cartesian; |
|
|
|
this.updateAddWaypointPreview(); |
|
|
|
if (this.viewer.scene.requestRender) this.viewer.scene.requestRender(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); |
|
|
|
|
|
|
|
// 拖拽结束:恢复地图操作、持久化新位置并清除状态;未超过阈值则只清 pending(视为点击) |
|
|
|
@ -2811,6 +2882,13 @@ export default { |
|
|
|
this.contextMenu.visible = false; |
|
|
|
return; |
|
|
|
} |
|
|
|
// 若处于“增加航点”预览,右键取消 |
|
|
|
if (this.addWaypointContext) { |
|
|
|
this.clearAddWaypointContext(); |
|
|
|
this.contextMenu.visible = false; |
|
|
|
this.$message && this.$message.info('已取消增加航点'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 隐藏之前可能显示的菜单 |
|
|
|
this.contextMenu.visible = false; |
|
|
|
@ -2870,20 +2948,37 @@ export default { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// 特殊处理:右键点击航点或航线时,从实体属性解析出 routeId,用于显示航线“上锁/解锁”菜单 |
|
|
|
// 特殊处理:右键点击航点或航线时,从实体属性解析出 routeId;航点需区分为 routeWaypoint 以支持“向前/向后增加航点” |
|
|
|
if (!entityData && pickedEntity.properties) { |
|
|
|
const now = Cesium.JulianDate.now(); |
|
|
|
const props = pickedEntity.properties.getValue ? pickedEntity.properties.getValue(now) : null; |
|
|
|
if (props) { |
|
|
|
const isWp = props.isMissionWaypoint && props.isMissionWaypoint.getValue ? props.isMissionWaypoint.getValue() : props.isMissionWaypoint; |
|
|
|
const isLine = props.isMissionRouteLine && props.isMissionRouteLine.getValue ? props.isMissionRouteLine.getValue() : props.isMissionRouteLine; |
|
|
|
if (isWp || isLine) { |
|
|
|
if (isWp) { |
|
|
|
let rId = props.routeId; |
|
|
|
if (rId && rId.getValue) rId = rId.getValue(); |
|
|
|
let dbId = props.dbId; |
|
|
|
if (dbId && dbId.getValue) dbId = dbId.getValue(); |
|
|
|
const ids = this._routeWaypointIdsByRoute && this._routeWaypointIdsByRoute[rId]; |
|
|
|
const waypointIndex = ids && dbId != null ? ids.indexOf(dbId) : -1; |
|
|
|
if (rId != null) entityData = { type: 'routeWaypoint', routeId: rId, dbId, waypointIndex }; |
|
|
|
} else if (isLine) { |
|
|
|
let rId = props.routeId; |
|
|
|
if (rId && rId.getValue) rId = rId.getValue(); |
|
|
|
if (rId) entityData = { type: 'route', routeId: rId }; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// 盘旋弧线(hold-line-routeId-i)右键视为在该盘旋航点处,waypointIndex = i+1 |
|
|
|
if (!entityData && idStr && idStr.startsWith('hold-line-')) { |
|
|
|
const parts = idStr.split('-'); |
|
|
|
if (parts.length >= 4) { |
|
|
|
const routeId = parts[2]; |
|
|
|
const segIdx = parseInt(parts[3], 10); |
|
|
|
if (!isNaN(segIdx)) entityData = { type: 'routeWaypoint', routeId, waypointIndex: segIdx + 1, fromHold: true }; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// 航线实体在 allEntities 中可能没有 routeId,从 id 解析 |
|
|
|
if (entityData && entityData.type === 'route' && entityData.id && !entityData.routeId) { |
|
|
|
@ -2967,7 +3062,7 @@ export default { |
|
|
|
const routeId = ed.routeId |
|
|
|
const platformEntity = this.viewer && this.viewer.entities && this.viewer.entities.getById(`route-platform-${routeId}`) |
|
|
|
let size = 144 |
|
|
|
let color = '#ffffff' |
|
|
|
let color = '#000000' |
|
|
|
if (platformEntity && platformEntity.billboard) { |
|
|
|
const now = Cesium.JulianDate.now() |
|
|
|
const widthValue = platformEntity.billboard.width && platformEntity.billboard.width.getValue |
|
|
|
@ -3000,7 +3095,7 @@ export default { |
|
|
|
const entity = this.viewer.entities.getById(`route-platform-${routeId}`) |
|
|
|
if (entity && entity.billboard) { |
|
|
|
const size = Math.max(48, Math.min(256, Number(this.editPlatformStyleForm.size) || 144)) |
|
|
|
const color = this.editPlatformStyleForm.color || '#ffffff' |
|
|
|
const color = this.editPlatformStyleForm.color || '#000000' |
|
|
|
entity.billboard.width = size |
|
|
|
entity.billboard.height = size |
|
|
|
entity.billboard.color = Cesium.Color.fromCssColorString(color) |
|
|
|
@ -5323,6 +5418,86 @@ export default { |
|
|
|
this.copyPreviewWaypoints = null; |
|
|
|
this.copyPreviewMouseCartesian = null; |
|
|
|
}, |
|
|
|
/** 右键菜单:打开航点编辑(支持 dbId 或 waypointIndex) */ |
|
|
|
handleContextMenuOpenWaypointDialog(dbId, routeId, waypointIndex) { |
|
|
|
this.contextMenu.visible = false; |
|
|
|
this.$emit('open-waypoint-dialog', dbId, routeId, waypointIndex); |
|
|
|
}, |
|
|
|
/** 右键菜单:选择向前/向后增加航点,由父组件调用 startAddWaypointAt 传入 waypoints */ |
|
|
|
handleAddWaypointAt(payload) { |
|
|
|
this.contextMenu.visible = false; |
|
|
|
this.$emit('add-waypoint-at', payload); |
|
|
|
}, |
|
|
|
/** 开始“在航点前/后增加航点”模式:显示预览折线,左键放置、右键取消。waypoints 为当前航线航点数组。 */ |
|
|
|
startAddWaypointAt(routeId, waypointIndex, mode, waypoints) { |
|
|
|
if (!waypoints || waypoints.length === 0) return; |
|
|
|
this.clearAddWaypointContext(); |
|
|
|
const ctx = { |
|
|
|
routeId, |
|
|
|
waypointIndex: Math.max(0, Math.min(waypointIndex, waypoints.length - 1)), |
|
|
|
mode, |
|
|
|
waypoints, |
|
|
|
mouseCartesian: null |
|
|
|
}; |
|
|
|
const toCartesian = (wp) => Cesium.Cartesian3.fromDegrees(parseFloat(wp.lng), parseFloat(wp.lat), Number(wp.alt) || 5000); |
|
|
|
ctx.mouseCartesian = toCartesian(waypoints[ctx.waypointIndex]); |
|
|
|
this.addWaypointContext = ctx; |
|
|
|
this.$message && this.$message.info(mode === 'before' ? '点击地图在当前位置前插入新航点,右键取消' : '点击地图在当前位置后插入新航点,右键取消'); |
|
|
|
this.updateAddWaypointPreview(); |
|
|
|
}, |
|
|
|
/** 更新“增加航点”预览折线:上一/当前/下一与鼠标位置连线,含盘旋段视觉效果 */ |
|
|
|
updateAddWaypointPreview() { |
|
|
|
const ctx = this.addWaypointContext; |
|
|
|
if (!ctx || !this.viewer || !ctx.waypoints || ctx.waypoints.length === 0) return; |
|
|
|
const waypoints = ctx.waypoints; |
|
|
|
const idx = ctx.waypointIndex; |
|
|
|
const toCartesian = (wp) => { |
|
|
|
const lon = parseFloat(wp.lng); |
|
|
|
const lat = parseFloat(wp.lat); |
|
|
|
const alt = Number(wp.alt) || 5000; |
|
|
|
return Cesium.Cartesian3.fromDegrees(lon, lat, alt); |
|
|
|
}; |
|
|
|
let positions = []; |
|
|
|
if (ctx.mode === 'before') { |
|
|
|
const prev = idx > 0 ? toCartesian(waypoints[idx - 1]) : null; |
|
|
|
const curr = toCartesian(waypoints[idx]); |
|
|
|
if (ctx.mouseCartesian) { |
|
|
|
if (prev) positions = [prev, ctx.mouseCartesian, curr]; |
|
|
|
else positions = [ctx.mouseCartesian, curr]; |
|
|
|
} |
|
|
|
} else { |
|
|
|
const curr = toCartesian(waypoints[idx]); |
|
|
|
const next = idx + 1 < waypoints.length ? toCartesian(waypoints[idx + 1]) : null; |
|
|
|
if (ctx.mouseCartesian) { |
|
|
|
if (next) positions = [curr, ctx.mouseCartesian, next]; |
|
|
|
else positions = [curr, ctx.mouseCartesian]; |
|
|
|
} |
|
|
|
} |
|
|
|
if (positions.length < 2) return; |
|
|
|
if (this.addWaypointPreviewEntity) { |
|
|
|
this.viewer.entities.remove(this.addWaypointPreviewEntity); |
|
|
|
this.addWaypointPreviewEntity = null; |
|
|
|
} |
|
|
|
this.addWaypointPreviewEntity = this.viewer.entities.add({ |
|
|
|
polyline: { |
|
|
|
positions: positions, |
|
|
|
width: 3, |
|
|
|
material: new Cesium.PolylineDashMaterialProperty({ |
|
|
|
color: Cesium.Color.fromCssColorString('#2E5C3E'), |
|
|
|
dashLength: 16 |
|
|
|
}), |
|
|
|
arcType: Cesium.ArcType.NONE |
|
|
|
} |
|
|
|
}); |
|
|
|
}, |
|
|
|
/** 清除“增加航点”模式及预览折线 */ |
|
|
|
clearAddWaypointContext() { |
|
|
|
if (this.addWaypointPreviewEntity) { |
|
|
|
this.viewer.entities.remove(this.addWaypointPreviewEntity); |
|
|
|
this.addWaypointPreviewEntity = null; |
|
|
|
} |
|
|
|
this.addWaypointContext = null; |
|
|
|
}, |
|
|
|
toggleRouteLock() { |
|
|
|
const ed = this.contextMenu.entityData; |
|
|
|
if (!ed || ed.type !== 'route' || ed.routeId == null) { |
|
|
|
@ -5391,7 +5566,7 @@ export default { |
|
|
|
// 读取平台设置 |
|
|
|
const platformEntity = this.viewer.entities.getById(`route-platform-${routeId}`) |
|
|
|
let iconSize = 144 |
|
|
|
let iconColor = '#ffffff' |
|
|
|
let iconColor = '#000000' |
|
|
|
let platformName = '平台' // 默认名称 |
|
|
|
|
|
|
|
// 尝试获取平台名称 |
|
|
|
@ -5493,7 +5668,7 @@ export default { |
|
|
|
const platformEntity = this.viewer.entities.getById(`route-platform-${routeId}`) |
|
|
|
if (platformEntity && platformEntity.billboard) { |
|
|
|
const size = Math.max(48, Math.min(256, Number(this.editPlatformForm.iconSize) || 144)) |
|
|
|
const color = this.editPlatformForm.iconColor || '#ffffff' |
|
|
|
const color = this.editPlatformForm.iconColor || '#000000' |
|
|
|
platformEntity.billboard.width = size |
|
|
|
platformEntity.billboard.height = size |
|
|
|
platformEntity.billboard.color = Cesium.Color.fromCssColorString(color) |
|
|
|
@ -5504,7 +5679,7 @@ export default { |
|
|
|
labelFontSize: fontSize, |
|
|
|
labelFontColor: fontColor, |
|
|
|
platformSize: Math.max(48, Math.min(256, Number(this.editPlatformForm.iconSize) || 144)), |
|
|
|
platformColor: this.editPlatformForm.iconColor || '#ffffff' |
|
|
|
platformColor: this.editPlatformForm.iconColor || '#000000' |
|
|
|
}); |
|
|
|
|
|
|
|
// 调用后端接口保存样式到Redis |
|
|
|
@ -5519,7 +5694,7 @@ export default { |
|
|
|
labelFontSize: fontSize, |
|
|
|
labelFontColor: fontColor, |
|
|
|
platformSize: Math.max(48, Math.min(256, Number(this.editPlatformForm.iconSize) || 144)), |
|
|
|
platformColor: this.editPlatformForm.iconColor || '#ffffff' |
|
|
|
platformColor: this.editPlatformForm.iconColor || '#000000' |
|
|
|
}; |
|
|
|
savePlatformStyle(styleData).then(() => { |
|
|
|
// console.log("样式保存成功"); |
|
|
|
@ -5660,7 +5835,7 @@ export default { |
|
|
|
labelFontSize: style.labelFontSize, |
|
|
|
labelFontColor: style.labelFontColor, |
|
|
|
platformSize: style.platformSize != null ? style.platformSize : 144, |
|
|
|
platformColor: style.platformColor != null ? style.platformColor : '#ffffff', |
|
|
|
platformColor: style.platformColor != null ? style.platformColor : '#000000', |
|
|
|
powerZoneRadius: style.powerZoneRadius, |
|
|
|
powerZoneColor: style.powerZoneColor |
|
|
|
}); |
|
|
|
@ -5729,7 +5904,7 @@ export default { |
|
|
|
// 应用平台图标样式 |
|
|
|
if (entity.billboard) { |
|
|
|
const size = Math.max(48, Math.min(256, Number(style.platformSize) || 144)); |
|
|
|
const color = style.platformColor || '#ffffff'; |
|
|
|
const color = style.platformColor || '#000000'; |
|
|
|
entity.billboard.width = size; |
|
|
|
entity.billboard.height = size; |
|
|
|
entity.billboard.color = Cesium.Color.fromCssColorString(color); |
|
|
|
|