@@ -174,7 +182,25 @@ export default {
currentScaleUnit: 'm',
isApplyingScale: false,
// 定位相关
- locateDialogVisible: false
+ locateDialogVisible: false,
+ // 平台图标图形化编辑:拖拽移动、旋转、伸缩框
+ draggingPlatformIcon: null,
+ rotatingPlatformIcon: null,
+ platformIconRotateTip: '',
+ platformIconDragCameraEnabled: true,
+ selectedPlatformIcon: null,
+ pendingDragIcon: null,
+ dragStartScreenPos: null,
+ draggingRotateHandle: null,
+ draggingScaleHandle: null,
+ clickedOnEmpty: false,
+ PLATFORM_ICON_BASE_SIZE: 72,
+ PLATFORM_SCALE_BOX_HALF_DEG: 0.0005,
+ PLATFORM_SCALE_BOX_MIN_HALF_DEG: 0.0007,
+ PLATFORM_ROTATE_HANDLE_OFFSET_DEG: 0.0009,
+ PLATFORM_DRAG_THRESHOLD_PX: 10,
+ DESIRED_BOX_HALF_PX: 58,
+ DESIRED_ROTATE_OFFSET_PX: 50
}
},
components: {
@@ -538,6 +564,234 @@ export default {
const backendUrl = process.env.VUE_APP_BACKEND_URL || '';
return backendUrl + cleanPath;
},
+
+ /** 默认平台图标(无 imageUrl 时使用):简单飞机剪影 SVG */
+ getDefaultPlatformIconDataUrl() {
+ const svg = '
';
+ return 'data:image/svg+xml,' + encodeURIComponent(svg);
+ },
+
+ /** 伸缩框旋转手柄图标 SVG:蓝底、白边、白色弧形箭头 */
+ getRotationHandleIconDataUrl() {
+ const svg = '
';
+ return 'data:image/svg+xml,' + encodeURIComponent(svg);
+ },
+
+ /** 从手柄实体 id 解析出平台图标 entityData 与类型(rotate / scale-0~3) */
+ getPlatformIconDataFromHandleId(handleEntityId) {
+ if (!handleEntityId || typeof handleEntityId !== 'string') return null;
+ if (handleEntityId.endsWith('-rotate-handle')) {
+ const baseId = handleEntityId.replace(/-rotate-handle$/, '');
+ const ed = this.allEntities.find(e => e.type === 'platformIcon' && e.id === baseId);
+ return ed ? { entityData: ed, type: 'rotate' } : null;
+ }
+ const scaleIdx = handleEntityId.lastIndexOf('-scale-');
+ if (scaleIdx !== -1) {
+ const baseId = handleEntityId.substring(0, scaleIdx);
+ const cornerIndex = parseInt(handleEntityId.substring(scaleIdx + 7), 10);
+ if (!isNaN(cornerIndex) && cornerIndex >= 0 && cornerIndex <= 3) {
+ const ed = this.allEntities.find(e => e.type === 'platformIcon' && e.id === baseId);
+ return ed ? { entityData: ed, type: 'scale', cornerIndex } : null;
+ }
+ }
+ return null;
+ },
+
+ /** 在当前视野下,图标位置处 1 像素对应的经纬度(用于伸缩框固定屏幕尺寸) */
+ getDegreesPerPixelAt(lng, lat) {
+ if (!this.viewer || this.viewer.scene.mode !== Cesium.SceneMode.SCENE2D) {
+ return { degPerPxLng: this.PLATFORM_SCALE_BOX_HALF_DEG / this.DESIRED_BOX_HALF_PX, degPerPxLat: this.PLATFORM_SCALE_BOX_HALF_DEG / this.DESIRED_BOX_HALF_PX };
+ }
+ const center = Cesium.Cartesian3.fromDegrees(lng, lat);
+ const east = Cesium.Cartesian3.fromDegrees(lng + 0.005, lat);
+ const north = Cesium.Cartesian3.fromDegrees(lng, lat + 0.005);
+ const sc = Cesium.SceneTransforms.worldToWindowCoordinates(this.viewer.scene, center);
+ const se = Cesium.SceneTransforms.worldToWindowCoordinates(this.viewer.scene, east);
+ const sn = Cesium.SceneTransforms.worldToWindowCoordinates(this.viewer.scene, north);
+ if (!sc || !se || !sn) {
+ return { degPerPxLng: this.PLATFORM_SCALE_BOX_HALF_DEG / this.DESIRED_BOX_HALF_PX, degPerPxLat: this.PLATFORM_SCALE_BOX_HALF_DEG / this.DESIRED_BOX_HALF_PX };
+ }
+ const pxLng = Math.max(1, Math.abs(se.x - sc.x));
+ const pxLat = Math.max(1, Math.abs(sn.y - sc.y));
+ return {
+ degPerPxLng: 0.005 / pxLng,
+ degPerPxLat: 0.005 / pxLat
+ };
+ },
+
+ /** 更新平台图标 billboard 的宽高(根据 iconScale) */
+ updatePlatformIconBillboardSize(entityData) {
+ if (!entityData || !entityData.entity || !entityData.entity.billboard) return;
+ const scale = Math.max(0.2, Math.min(3, entityData.iconScale || 1));
+ entityData.iconScale = scale;
+ const size = this.PLATFORM_ICON_BASE_SIZE * scale;
+ entityData.entity.billboard.width = new Cesium.ConstantProperty(size);
+ entityData.entity.billboard.height = new Cesium.ConstantProperty(size);
+ },
+
+ /** 显示伸缩框:旋转手柄 + 四角缩放手柄 + 矩形边线(按屏幕像素固定尺寸,任意缩放都易点) */
+ showTransformHandles(entityData) {
+ if (!this.viewer || !entityData || entityData.type !== 'platformIcon') return;
+ this.removeTransformHandles(entityData);
+ const id = entityData.id;
+ const lng = entityData.lng;
+ const lat = entityData.lat;
+ const dpp = this.getDegreesPerPixelAt(lng, lat);
+ const baseHalfDeg = this.DESIRED_BOX_HALF_PX * Math.min(dpp.degPerPxLng, dpp.degPerPxLat);
+ const half = Math.max((entityData.iconScale || 1) * baseHalfDeg, baseHalfDeg * 0.5);
+ const rotOffsetLat = this.DESIRED_ROTATE_OFFSET_PX * dpp.degPerPxLat;
+ const rotOffset = Math.max(rotOffsetLat, this.PLATFORM_ROTATE_HANDLE_OFFSET_DEG);
+ const rotationHandle = this.viewer.entities.add({
+ id: id + '-rotate-handle',
+ position: Cesium.Cartesian3.fromDegrees(lng, lat + rotOffset),
+ billboard: {
+ image: this.getRotationHandleIconDataUrl(),
+ width: 36,
+ height: 36,
+ verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+ horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
+ disableDepthTestDistance: Number.POSITIVE_INFINITY
+ }
+ });
+ const corners = [
+ Cesium.Cartesian3.fromDegrees(lng + half, lat + half),
+ Cesium.Cartesian3.fromDegrees(lng - half, lat + half),
+ Cesium.Cartesian3.fromDegrees(lng - half, lat - half),
+ Cesium.Cartesian3.fromDegrees(lng + half, lat - half)
+ ];
+ const scaleHandles = corners.map((pos, i) =>
+ this.viewer.entities.add({
+ id: id + '-scale-' + i,
+ position: pos,
+ point: {
+ pixelSize: 14,
+ color: Cesium.Color.WHITE,
+ outlineColor: Cesium.Color.fromCssColorString('#008aff'),
+ outlineWidth: 3,
+ disableDepthTestDistance: Number.POSITIVE_INFINITY
+ }
+ })
+ );
+ const linePositions = [corners[0], corners[1], corners[2], corners[3], corners[0]];
+ const frameLine = this.viewer.entities.add({
+ id: id + '-scale-frame',
+ polyline: {
+ positions: linePositions,
+ width: 3,
+ material: Cesium.Color.fromCssColorString('#008aff'),
+ clampToGround: true,
+ disableDepthTestDistance: Number.POSITIVE_INFINITY
+ }
+ });
+ entityData.transformHandles = {
+ rotation: rotationHandle,
+ scale: scaleHandles,
+ frame: frameLine
+ };
+ },
+
+ /** 移除伸缩框手柄与边线 */
+ removeTransformHandles(entityData) {
+ if (!entityData || !entityData.transformHandles) return;
+ const h = entityData.transformHandles;
+ if (h.rotation) this.viewer.entities.remove(h.rotation);
+ if (h.scale) h.scale.forEach(e => this.viewer.entities.remove(e));
+ if (h.frame) this.viewer.entities.remove(h.frame);
+ entityData.transformHandles = null;
+ },
+
+ /** 根据图标当前位置、iconScale 与当前视野更新伸缩框(保持固定像素尺寸) */
+ updateTransformHandlePositions(entityData) {
+ if (!entityData || !entityData.transformHandles) return;
+ const lng = entityData.lng;
+ const lat = entityData.lat;
+ const dpp = this.getDegreesPerPixelAt(lng, lat);
+ const baseHalfDeg = this.DESIRED_BOX_HALF_PX * Math.min(dpp.degPerPxLng, dpp.degPerPxLat);
+ const half = Math.max((entityData.iconScale || 1) * baseHalfDeg, baseHalfDeg * 0.5);
+ const rotOffsetLat = this.DESIRED_ROTATE_OFFSET_PX * dpp.degPerPxLat;
+ const rotOffset = Math.max(rotOffsetLat, this.PLATFORM_ROTATE_HANDLE_OFFSET_DEG);
+ entityData.transformHandles.rotation.position = Cesium.Cartesian3.fromDegrees(lng, lat + rotOffset);
+ const corners = [
+ Cesium.Cartesian3.fromDegrees(lng + half, lat + half),
+ Cesium.Cartesian3.fromDegrees(lng - half, lat + half),
+ Cesium.Cartesian3.fromDegrees(lng - half, lat - half),
+ Cesium.Cartesian3.fromDegrees(lng + half, lat - half)
+ ];
+ entityData.transformHandles.scale.forEach((ent, i) => { ent.position = corners[i]; });
+ const linePositions = [corners[0], corners[1], corners[2], corners[3], corners[0]];
+ entityData.transformHandles.frame.polyline.positions = new Cesium.ConstantProperty(linePositions);
+ this.viewer.scene.requestRender();
+ },
+
+ /**
+ * 从右侧平台列表拖拽放置到地图:在放置点添加平台图标实体,支持后续修改位置与朝向。
+ * @param {Object} platform - 平台数据 { id, name, type, imageUrl, iconUrl, icon, color }
+ * @param {number} clientX - 放置点的视口 X
+ * @param {number} clientY - 放置点的视口 Y
+ */
+ addPlatformIconFromDrag(platform, clientX, clientY) {
+ if (!this.viewer || !platform) return;
+ const canvas = this.viewer.scene.canvas;
+ const rect = canvas.getBoundingClientRect();
+ const x = clientX - rect.left;
+ const y = clientY - rect.top;
+ const cartesian = this.viewer.camera.pickEllipsoid(new Cesium.Cartesian2(x, y), this.viewer.scene.globe.ellipsoid);
+ if (!cartesian) {
+ this.$message && this.$message.warning('请将图标放置到地图有效区域内');
+ return;
+ }
+ const iconUrl = platform.imageUrl || platform.iconUrl;
+ const imageSrc = iconUrl ? this.formatPlatformIconUrl(iconUrl) : this.getDefaultPlatformIconDataUrl();
+ this.entityCounter++;
+ const id = `platformIcon_${this.entityCounter}`;
+ const headingDeg = 0;
+ const rotation = Math.PI / 2 - (headingDeg * Math.PI / 180);
+ const iconScale = 1.0;
+ const size = this.PLATFORM_ICON_BASE_SIZE * iconScale;
+ const entity = this.viewer.entities.add({
+ id,
+ name: platform.name || '平台',
+ position: cartesian,
+ billboard: {
+ image: imageSrc,
+ width: size,
+ height: size,
+ verticalOrigin: Cesium.VerticalOrigin.CENTER,
+ horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
+ rotation,
+ scaleByDistance: new Cesium.NearFarScalar(500, 1.2, 200000, 0.35),
+ translucencyByDistance: new Cesium.NearFarScalar(1000, 1.0, 500000, 0.6)
+ }
+ });
+ const { lat, lng } = this.cartesianToLatLng(cartesian);
+ const entityData = {
+ id,
+ type: 'platformIcon',
+ platformId: platform.id,
+ platform,
+ name: platform.name || '平台',
+ heading: headingDeg,
+ lat,
+ lng,
+ entity,
+ imageUrl: iconUrl,
+ label: platform.name || '平台',
+ iconScale,
+ transformHandles: null
+ };
+ this.allEntities.push(entityData);
+ this.$nextTick(() => {
+ if (this.selectedPlatformIcon) this.removeTransformHandles(this.selectedPlatformIcon);
+ this.selectedPlatformIcon = entityData;
+ this.showTransformHandles(entityData);
+ this.$message && this.$message.success('已放置。上方箭头旋转、四角调大小、拖动图标移动;点击空白收起');
+ });
+ },
//正式航线渲染函数
renderRouteWaypoints(waypoints, routeId = 'default', platformId, platform, style) {
if (!waypoints || waypoints.length < 1) return;
@@ -1238,6 +1492,7 @@ export default {
})
this.initScaleBar()
this.initPointMovement()
+ this.initPlatformIconInteraction()
this.initRightClickHandler()
this.initHoverHandler()
this.initMouseCoordinates()
@@ -1254,6 +1509,10 @@ export default {
const pickedObject = this.viewer.scene.pick(click.position);
if (Cesium.defined(pickedObject) && pickedObject.id) {
const entity = pickedObject.id;
+ const idStr = (entity && entity.id) ? entity.id : '';
+ if (idStr && (idStr.endsWith('-rotate-handle') || idStr.indexOf('-scale-') !== -1)) return;
+ const platformIconData = this.allEntities.find(e => e.type === 'platformIcon' && e.entity === entity);
+ if (platformIconData) return;
// --- 修正后的安全日志 ---
console.log(">>> [点击检测] 实体ID:", entity.id);
@@ -1328,6 +1587,183 @@ export default {
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
},
+
+ /** 平台图标图形化操作:伸缩框(旋转手柄 + 四角缩放)、拖拽移动、单击选中 */
+ initPlatformIconInteraction() {
+ const canvas = this.viewer.scene.canvas;
+ this.platformIconHandler = new Cesium.ScreenSpaceEventHandler(canvas);
+
+ this.platformIconHandler.setInputAction((click) => {
+ if (this.isDrawing || this.rotatingPlatformIcon) return;
+ const picked = this.viewer.scene.pick(click.position);
+ this.clickedOnEmpty = !Cesium.defined(picked) || !picked.id;
+ if (picked && picked.id) {
+ const idStr = typeof picked.id === 'string' ? picked.id : (picked.id.id || '');
+ if (idStr.endsWith('-scale-frame')) {
+ this.clickedOnEmpty = false;
+ return;
+ }
+ const handleInfo = this.getPlatformIconDataFromHandleId(idStr);
+ if (handleInfo) {
+ this.clickedOnEmpty = false;
+ if (handleInfo.type === 'rotate') {
+ this.draggingRotateHandle = handleInfo.entityData;
+ this.platformIconDragCameraEnabled = this.viewer.scene.screenSpaceCameraController.enableInputs;
+ this.viewer.scene.screenSpaceCameraController.enableInputs = false;
+ return;
+ }
+ if (handleInfo.type === 'scale') {
+ this.draggingScaleHandle = { entityData: handleInfo.entityData, cornerIndex: handleInfo.cornerIndex };
+ this.platformIconDragCameraEnabled = this.viewer.scene.screenSpaceCameraController.enableInputs;
+ this.viewer.scene.screenSpaceCameraController.enableInputs = false;
+ return;
+ }
+ }
+ const entityData = this.allEntities.find(e => e.type === 'platformIcon' && e.entity === picked.id);
+ if (entityData) {
+ this.pendingDragIcon = entityData;
+ this.dragStartScreenPos = { x: click.position.x, y: click.position.y };
+ return;
+ }
+ }
+ }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
+
+ this.platformIconHandler.setInputAction((movement) => {
+ if (this.draggingRotateHandle) {
+ const ed = this.draggingRotateHandle;
+ if (ed.entity && ed.entity.position) {
+ const now = Cesium.JulianDate.now();
+ const position = ed.entity.position.getValue(now);
+ if (position) {
+ const screenPos = Cesium.SceneTransforms.worldToWindowCoordinates(this.viewer.scene, position);
+ if (screenPos) {
+ const dx = movement.endPosition.x - screenPos.x;
+ const dy = movement.endPosition.y - screenPos.y;
+ const screenAngle = Math.atan2(dy, dx);
+ ed.entity.billboard.rotation = -screenAngle;
+ let headingDeg = (screenAngle + Math.PI / 2) * (180 / Math.PI);
+ if (headingDeg < 0) headingDeg += 360;
+ if (headingDeg >= 360) headingDeg -= 360;
+ ed.heading = Math.round(headingDeg);
+ }
+ }
+ }
+ this.viewer.scene.requestRender();
+ return;
+ }
+ if (this.draggingScaleHandle) {
+ const { entityData: ed, cornerIndex } = this.draggingScaleHandle;
+ const cartesian = this.viewer.camera.pickEllipsoid(movement.endPosition, this.viewer.scene.globe.ellipsoid);
+ if (cartesian) {
+ const { lat: newLat, lng: newLng } = this.cartesianToLatLng(cartesian);
+ const lng = ed.lng;
+ const lat = ed.lat;
+ const dpp = this.getDegreesPerPixelAt(lng, lat);
+ const baseHalf = this.DESIRED_BOX_HALF_PX * Math.min(dpp.degPerPxLng, dpp.degPerPxLat);
+ let newHalfDeg;
+ if (cornerIndex === 0) newHalfDeg = Math.min(newLng - lng, newLat - lat);
+ else if (cornerIndex === 1) newHalfDeg = Math.min(lng - newLng, newLat - lat);
+ else if (cornerIndex === 2) newHalfDeg = Math.min(lng - newLng, lat - newLat);
+ else newHalfDeg = Math.min(newLng - lng, lat - newLat);
+ if (newHalfDeg > 0.0001 && baseHalf > 1e-10) {
+ ed.iconScale = Math.max(0.2, Math.min(3, newHalfDeg / baseHalf));
+ this.updatePlatformIconBillboardSize(ed);
+ this.updateTransformHandlePositions(ed);
+ }
+ }
+ return;
+ }
+ if (this.pendingDragIcon) {
+ const dx = movement.endPosition.x - this.dragStartScreenPos.x;
+ const dy = movement.endPosition.y - this.dragStartScreenPos.y;
+ if (Math.sqrt(dx * dx + dy * dy) > (this.PLATFORM_DRAG_THRESHOLD_PX || 10)) {
+ this.draggingPlatformIcon = this.pendingDragIcon;
+ this.pendingDragIcon = null;
+ this.platformIconDragCameraEnabled = this.viewer.scene.screenSpaceCameraController.enableInputs;
+ this.viewer.scene.screenSpaceCameraController.enableInputs = false;
+ }
+ }
+ if (this.draggingPlatformIcon) {
+ const cartesian = this.viewer.camera.pickEllipsoid(movement.endPosition, this.viewer.scene.globe.ellipsoid);
+ if (cartesian) {
+ this.draggingPlatformIcon.entity.position = cartesian;
+ const { lat, lng } = this.cartesianToLatLng(cartesian);
+ this.draggingPlatformIcon.lat = lat;
+ this.draggingPlatformIcon.lng = lng;
+ if (this.selectedPlatformIcon === this.draggingPlatformIcon) {
+ this.updateTransformHandlePositions(this.draggingPlatformIcon);
+ }
+ }
+ this.viewer.scene.requestRender();
+ }
+ if (this.rotatingPlatformIcon && this.rotatingPlatformIcon.entity && this.rotatingPlatformIcon.entity.position) {
+ const now = Cesium.JulianDate.now();
+ const position = this.rotatingPlatformIcon.entity.position.getValue(now);
+ if (position) {
+ const screenPos = Cesium.SceneTransforms.worldToWindowCoordinates(this.viewer.scene, position);
+ if (screenPos) {
+ const dx = movement.endPosition.x - screenPos.x;
+ const dy = movement.endPosition.y - screenPos.y;
+ const screenAngle = Math.atan2(dy, dx);
+ this.rotatingPlatformIcon.entity.billboard.rotation = -screenAngle;
+ let headingDeg = (screenAngle + Math.PI / 2) * (180 / Math.PI);
+ if (headingDeg < 0) headingDeg += 360;
+ if (headingDeg >= 360) headingDeg -= 360;
+ this.rotatingPlatformIcon.heading = Math.round(headingDeg);
+ }
+ }
+ this.viewer.scene.requestRender();
+ }
+ }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
+
+ this.platformIconHandler.setInputAction(() => {
+ if (this.pendingDragIcon) {
+ if (this.selectedPlatformIcon === this.pendingDragIcon) {
+ this.removeTransformHandles(this.selectedPlatformIcon);
+ this.selectedPlatformIcon = null;
+ } else {
+ if (this.selectedPlatformIcon) this.removeTransformHandles(this.selectedPlatformIcon);
+ this.selectedPlatformIcon = this.pendingDragIcon;
+ this.showTransformHandles(this.pendingDragIcon);
+ }
+ this.pendingDragIcon = null;
+ this.dragStartScreenPos = null;
+ }
+ if (this.clickedOnEmpty && this.selectedPlatformIcon) {
+ this.removeTransformHandles(this.selectedPlatformIcon);
+ this.selectedPlatformIcon = null;
+ }
+ this.clickedOnEmpty = false;
+ if (this.draggingRotateHandle) {
+ this.viewer.scene.screenSpaceCameraController.enableInputs = this.platformIconDragCameraEnabled;
+ this.draggingRotateHandle = null;
+ }
+ if (this.draggingScaleHandle) {
+ this.viewer.scene.screenSpaceCameraController.enableInputs = this.platformIconDragCameraEnabled;
+ this.draggingScaleHandle = null;
+ }
+ if (this.draggingPlatformIcon) {
+ this.viewer.scene.screenSpaceCameraController.enableInputs = this.platformIconDragCameraEnabled;
+ this.draggingPlatformIcon = null;
+ }
+ if (this.rotatingPlatformIcon) {
+ this.viewer.scene.screenSpaceCameraController.enableInputs = this.platformIconDragCameraEnabled;
+ this.rotatingPlatformIcon = null;
+ this.platformIconRotateTip = '';
+ }
+ }, Cesium.ScreenSpaceEventType.LEFT_UP);
+
+ const onCameraMoveEnd = () => {
+ if (this.selectedPlatformIcon && this.selectedPlatformIcon.transformHandles) {
+ this.updateTransformHandlePositions(this.selectedPlatformIcon);
+ }
+ };
+ this.viewer.camera.moveEnd.addEventListener(onCameraMoveEnd);
+ this.platformIconCameraListener = () => {
+ this.viewer.camera.moveEnd.removeEventListener(onCameraMoveEnd);
+ };
+ },
+
// 初始化鼠标悬停事件处理器
initHoverHandler() {
// 创建屏幕空间事件处理器
@@ -3385,6 +3821,53 @@ export default {
this.contextMenu.visible = false
}
},
+
+ /** 右键「显示伸缩框」:选中该图标并显示旋转/缩放手柄 */
+ showPlatformIconTransformBox() {
+ const fromMenu = this.contextMenu.entityData
+ if (!fromMenu || fromMenu.type !== 'platformIcon' || !fromMenu.entity) {
+ this.contextMenu.visible = false
+ return
+ }
+ const ed = this.allEntities.find(e => e.type === 'platformIcon' && e.id === fromMenu.id) || fromMenu
+ if (!ed.entity) {
+ this.contextMenu.visible = false
+ return
+ }
+ if (ed.lat == null || ed.lng == null) {
+ const now = Cesium.JulianDate.now()
+ const pos = ed.entity.position && ed.entity.position.getValue(now)
+ if (pos) {
+ const ll = this.cartesianToLatLng(pos)
+ ed.lat = ll.lat
+ ed.lng = ll.lng
+ }
+ }
+ if (this.selectedPlatformIcon) this.removeTransformHandles(this.selectedPlatformIcon)
+ this.selectedPlatformIcon = ed
+ this.showTransformHandles(ed)
+ this.contextMenu.visible = false
+ this.viewer.scene.requestRender()
+ this.$message && this.$message.success('已显示伸缩框')
+ },
+
+ /** 位置改为图形化:直接拖动图标即可,无需弹窗 */
+ openPlatformIconPositionDialog() {
+ this.contextMenu.visible = false
+ this.$message && this.$message.info('请直接拖动图标以修改位置')
+ },
+
+ /** 进入旋转模式:移动鼠标设置朝向,单击结束(期间锁定地图) */
+ openPlatformIconHeadingDialog() {
+ const ed = this.contextMenu.entityData
+ if (!ed || ed.type !== 'platformIcon' || !ed.entity) return
+ this.rotatingPlatformIcon = ed
+ this.platformIconRotateTip = '移动鼠标设置朝向,单击结束'
+ this.platformIconDragCameraEnabled = this.viewer.scene.screenSpaceCameraController.enableInputs
+ this.viewer.scene.screenSpaceCameraController.enableInputs = false
+ this.contextMenu.visible = false
+ this.$message && this.$message.info('移动鼠标可调整朝向,单击地图任意处结束')
+ },
removeEntity(id) {
// 查找对应的实体数据
const index = this.allEntities.findIndex(e =>
@@ -3394,23 +3877,23 @@ export default {
)
if (index > -1) {
const entity = this.allEntities[index]
+ // 平台图标:移除伸缩框并清除选中
+ if (entity.type === 'platformIcon') {
+ this.removeTransformHandles(entity)
+ if (this.selectedPlatformIcon === entity) this.selectedPlatformIcon = null
+ }
// 从地图中移除
if (entity instanceof Cesium.Entity) {
- // 情况 A: 直接是 Cesium Entity 对象
this.viewer.entities.remove(entity)
} else if (entity.entity) {
- // 情况 B: 包装对象,包含 entity 属性
this.viewer.entities.remove(entity.entity)
}
- // 移除线实体相关的点实体
if (entity.type === 'line' && entity.pointEntities) {
entity.pointEntities.forEach(pointEntity => {
this.viewer.entities.remove(pointEntity)
})
}
- // 从数组中移除
this.allEntities.splice(index, 1)
- // 如果删除的是选中的实体,清空选中状态
if (this.selectedEntity && (this.selectedEntity.id === id || (this.selectedEntity.entity && this.selectedEntity.entity.id === id))) {
this.selectedEntity = null
}
@@ -3466,12 +3949,15 @@ export default {
this.viewer.entities.remove(entity);
}
- // 移除线实体相关的点实体
if (item.type === 'line' && item.pointEntities) {
item.pointEntities.forEach(pointEntity => {
this.viewer.entities.remove(pointEntity);
});
}
+ if (item.type === 'platformIcon') {
+ this.removeTransformHandles(item);
+ if (this.selectedPlatformIcon === item) this.selectedPlatformIcon = null;
+ }
} catch (e) {
console.warn('删除实体失败:', e);
}
@@ -4093,6 +4579,15 @@ export default {
this.pointMovementHandler = null
}
+ if (this.platformIconHandler) {
+ this.platformIconHandler.destroy()
+ this.platformIconHandler = null
+ }
+ if (typeof this.platformIconCameraListener === 'function') {
+ this.platformIconCameraListener()
+ this.platformIconCameraListener = null
+ }
+
if (this.rightClickHandler) {
this.rightClickHandler.destroy()
this.rightClickHandler = null
@@ -4209,6 +4704,23 @@ export default {
display: none !important;
}
+/* 平台图标旋转模式提示条:放在顶部菜单下方,避免被遮挡(顶部栏约 60px) */
+.platform-icon-rotate-tip {
+ position: absolute;
+ top: 72px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 99;
+ background: rgba(0, 138, 255, 0.95);
+ color: #fff;
+ padding: 10px 20px;
+ border-radius: 6px;
+ font-size: 14px;
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25);
+ pointer-events: none;
+ white-space: nowrap;
+}
+
/* 地图右下角信息面板:比例尺在上、经纬度在下,整体略下移减少遮挡 */
.map-info-panel {
position: absolute;
diff --git a/ruoyi-ui/src/views/childRoom/RightPanel.vue b/ruoyi-ui/src/views/childRoom/RightPanel.vue
index 17eaaa0..27c6bbb 100644
--- a/ruoyi-ui/src/views/childRoom/RightPanel.vue
+++ b/ruoyi-ui/src/views/childRoom/RightPanel.vue
@@ -164,8 +164,10 @@