From 9f1f028beed601648033c7bfdd3d51dc959512bb Mon Sep 17 00:00:00 2001 From: menghao <1584479611@qq.com> Date: Fri, 23 Jan 2026 16:36:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=88=AA=E7=BA=BF=E7=9A=84?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E3=80=81=E5=8F=AF=E5=A4=9A=E9=80=89=E3=80=81?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E8=88=AA=E7=BA=BF=E7=9A=84=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E5=8F=98=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ruoyi/system/domain/RouteWaypoints.java | 20 +- .../system/service/impl/RoutesServiceImpl.java | 13 +- .../main/resources/mapper/system/RoutesMapper.xml | 1 + ruoyi-ui/src/views/cesiumMap/index.vue | 230 ++++++++++++++++-- ruoyi-ui/src/views/childRoom/RightPanel.vue | 18 +- ruoyi-ui/src/views/childRoom/TopHeader.vue | 218 ++++++++--------- ruoyi-ui/src/views/childRoom/index.vue | 265 ++++++++++++++++----- ruoyi-ui/vue.config.js | 2 +- 8 files changed, 564 insertions(+), 203 deletions(-) diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/RouteWaypoints.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/RouteWaypoints.java index f8349fc..45bc77e 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/RouteWaypoints.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/RouteWaypoints.java @@ -41,11 +41,11 @@ public class RouteWaypoints extends BaseEntity /** 高度 (米) */ @Excel(name = "高度 (米)") - private Long alt; + private Double alt; /** 速度 (km/h) */ @Excel(name = "速度 (km/h)") - private Long speed; + private Double speed; /** 起始时间 (如: K+00:40:00) */ @Excel(name = "起始时间 (如: K+00:40:00)") @@ -53,7 +53,7 @@ public class RouteWaypoints extends BaseEntity /** 转弯角度 (用于计算转弯半径) */ @Excel(name = "转弯角度 (用于计算转弯半径)") - private Long turnAngle; + private Double turnAngle; public void setId(Long id) { @@ -115,22 +115,22 @@ public class RouteWaypoints extends BaseEntity return lng; } - public void setAlt(Long alt) + public void setAlt(Double alt) { this.alt = alt; } - public Long getAlt() + public Double getAlt() { return alt; } - public void setSpeed(Long speed) + public void setSpeed(Double speed) { this.speed = speed; } - public Long getSpeed() + public Double getSpeed() { return speed; } @@ -145,12 +145,12 @@ public class RouteWaypoints extends BaseEntity return startTime; } - public void setTurnAngle(Long turnAngle) + public void setTurnAngle(Double turnAngle) { this.turnAngle = turnAngle; } - public Long getTurnAngle() + public Double getTurnAngle() { return turnAngle; } @@ -183,7 +183,7 @@ public class RouteWaypoints extends BaseEntity // 单位换算:速度从 km/h 转为 m/s double v_mps = this.speed / 3.6; // 单位换算:角度从 度(Degree) 转为 弧度(Radians) - double radians = Math.toRadians(this.turnAngle.doubleValue()); + double radians = Math.toRadians(this.turnAngle); // 重力加速度 g double g = 9.8; // 计算半径 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/RoutesServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/RoutesServiceImpl.java index 93b1ded..b3ee040 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/RoutesServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/RoutesServiceImpl.java @@ -35,7 +35,18 @@ public class RoutesServiceImpl implements IRoutesService @Override public Routes selectRoutesById(Long id) { - return routesMapper.selectRoutesById(id); + // 查出航线基本信息 + Routes routes = routesMapper.selectRoutesById(id); + // 如果查到了航线,就再去查属于它的航点 + if (routes != null) { + RouteWaypoints queryWp = new RouteWaypoints(); + queryWp.setRouteId(id); // 根据航线ID查询 + List wpList = routeWaypointsService.selectRouteWaypointsList(queryWp); + + // 把查出来的航点列表塞进 routes 对象的 waypoints 属性里 + routes.setWaypoints(wpList); + } + return routes; } /** diff --git a/ruoyi-system/src/main/resources/mapper/system/RoutesMapper.xml b/ruoyi-system/src/main/resources/mapper/system/RoutesMapper.xml index e51edf9..2a99e7f 100644 --- a/ruoyi-system/src/main/resources/mapper/system/RoutesMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/RoutesMapper.xml @@ -10,6 +10,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + diff --git a/ruoyi-ui/src/views/cesiumMap/index.vue b/ruoyi-ui/src/views/cesiumMap/index.vue index e17cf32..c674cc9 100644 --- a/ruoyi-ui/src/views/cesiumMap/index.vue +++ b/ruoyi-ui/src/views/cesiumMap/index.vue @@ -100,6 +100,204 @@ export default { }, methods: { + preventContextMenu(e) { + e.preventDefault(); + }, + clearRoute() { + // 1. 清除记录在 allEntities 中的实体 + this.allEntities.forEach(item => { + this.viewer.entities.remove(item.entity); + }); + this.allEntities = []; + + // 2. 额外保险:清除所有带业务标记的航点 + const entities = this.viewer.entities.values; + for (let i = entities.length - 1; i >= 0; i--) { + const entity = entities[i]; + if (entity.properties && entity.properties.isMissionWaypoint) { + this.viewer.entities.remove(entity); + } + } + }, + updateWaypointGraphic(oldName, newName) { + // 根据旧名字找到对应的实体 + const entities = this.viewer.entities.values; + const target = entities.find(e => e.name === oldName && e.properties.isMissionWaypoint); + + if (target) { + target.name = newName; // 更新实体名 + target.label.text = newName; // 更新地图上显示的文字 + } + }, + // 新建航线绘制 + startMissionRouteDrawing() { + this.stopDrawing(); // 停止其他可能存在的绘制 + this.drawingPoints = []; + let activeCursorPosition = null; + this.isDrawing = true; + this.drawingHandler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas); + + window.addEventListener('contextmenu', this.preventContextMenu, true); + // 鼠标移动预览逻辑 + this.drawingHandler.setInputAction((movement) => { + const newPosition = this.getClickPosition(movement.endPosition); + if (newPosition) { + activeCursorPosition = newPosition; + } + }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); + // 左键点击逻辑 + this.drawingHandler.setInputAction((click) => { + const position = this.getClickPosition(click.position); + if (!position) return; + this.drawingPoints.push(position); + const wpIndex = this.drawingPoints.length; + // 绘制业务航点 + this.viewer.entities.add({ + name: `WP${wpIndex}`, + position: position, + properties: { + isMissionWaypoint: true, // 这是一个永久的业务标记 + originalIndex: wpIndex // 存下它是第几个点 + }, + point: { + pixelSize: 10, + color: Cesium.Color.WHITE, + outlineColor: Cesium.Color.fromCssColorString('#0078FF'), + outlineWidth: 3, + disableDepthTestDistance: Number.POSITIVE_INFINITY // 保证不被地形遮挡 + }, + label: { + text: `WP${wpIndex}`, + font: '12px MicroSoft YaHei', + pixelOffset: new Cesium.Cartesian2(0, -20), + fillColor: Cesium.Color.WHITE, + outlineColor: Cesium.Color.BLACK, + outlineWidth: 2, + style: Cesium.LabelStyle.FILL_AND_OUTLINE + } + }); + // 第一次点击后,创建动态黑白斑马线 + if (this.drawingPoints.length === 1) { + this.tempPreviewEntity = this.viewer.entities.add({ + polyline: { + positions: new Cesium.CallbackProperty(() => { + if (this.drawingPoints.length > 0 && activeCursorPosition) { + return [...this.drawingPoints, activeCursorPosition]; + } + return this.drawingPoints; + }, false), + width: 4, + // 黑白斑马材质 + material: new Cesium.PolylineDashMaterialProperty({ + color: Cesium.Color.WHITE, // 主色:白 + gapColor: Cesium.Color.BLACK, // 间隙色:黑 + dashLength: 20.0 // 斑马纹长度 + }), + clampToGround: true + } + }); + } + }, Cesium.ScreenSpaceEventType.LEFT_CLICK); + + // 右键点击逻辑(结束绘制、抛出数据、恢复右键) + this.drawingHandler.setInputAction(() => { + if (this.drawingPoints.length > 1) { + // 转换坐标并传回给 childRoom/index.vue + const latLngPoints = this.drawingPoints.map((p, index) => { + const coords = this.cartesianToLatLng(p); + return { + id: index + 1, + name: `WP${index + 1}`, + lat: coords.lat, + lng: coords.lng, + alt: 500, // 默认业务属性 + speed: 600 // 默认业务属性 + }; + }); + this.$emit('draw-complete', latLngPoints); + } else { + this.$message.info('点数不足,航线已取消'); + } + // 清理并恢复环境 + this.stopDrawing(); + setTimeout(() => { + window.removeEventListener('contextmenu', this.preventContextMenu, true); + }, 200); + }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); + }, + + renderRouteWaypoints(waypoints, routeId = 'default') { + if (!waypoints || waypoints.length < 1) return; + const positions = []; + // 1. 遍历并绘制航点标记 + waypoints.forEach((wp, index) => { + const lon = parseFloat(wp.lng); + const lat = parseFloat(wp.lat); + const pos = Cesium.Cartesian3.fromDegrees(lon, lat, parseFloat(wp.alt || 500)); + positions.push(pos); + + this.viewer.entities.add({ + name: wp.name || `WP${index + 1}`, + position: pos, + properties: { + isMissionWaypoint: true, + routeId: routeId + }, + point: { + pixelSize: 10, + color: Cesium.Color.WHITE, + outlineColor: Cesium.Color.fromCssColorString('#0078FF'), + outlineWidth: 3, + disableDepthTestDistance: Number.POSITIVE_INFINITY + }, + label: { + text: wp.name || `WP${index + 1}`, + font: '12px MicroSoft YaHei', + pixelOffset: new Cesium.Cartesian2(0, -20), + fillColor: Cesium.Color.WHITE, + outlineColor: Cesium.Color.BLACK, + outlineWidth: 2, + style: Cesium.LabelStyle.FILL_AND_OUTLINE + } + }); + }); + + // 2. 绘制连线(仅当点数 > 1 时) + if (positions.length > 1) { + const routeEntity = this.viewer.entities.add({ + id: `route-line-${routeId}`, + polyline: { + positions: positions, + width: 4, + material: new Cesium.PolylineDashMaterialProperty({ + color: Cesium.Color.WHITE, + gapColor: Cesium.Color.BLACK, + dashLength: 20.0 + }), + clampToGround: true + }, + properties: { isMissionRouteLine: true, routeId: routeId } + }); + this.allEntities.push({ id: `route-line-${routeId}`, entity: routeEntity, type: 'line' }); + } + }, + removeRouteById(routeId) { + // 从地图上移除所有属于该 routeId 的实体 + const entityList = this.viewer.entities.values; + for (let i = entityList.length - 1; i >= 0; i--) { + const entity = entityList[i]; + // 获取 entity 身上绑定的 routeId 属性 + if (entity.properties && entity.properties.routeId) { + // Cesium 的属性系统比较特殊,需要 getValue() 拿原始值 + const id = entity.properties.routeId.getValue(); + if (id === routeId) { + this.viewer.entities.remove(entity); + } + } + } + // 同时清理你本地维护的 allEntities 数组 + this.allEntities = this.allEntities.filter(item => item.id !== routeId); + }, checkCesiumLoaded() { if (typeof Cesium === 'undefined') { console.error('Cesium未加载,请检查CDN链接'); @@ -155,6 +353,23 @@ export default { this.initScaleBar() console.log('Cesium离线二维地图已加载') + // 1. 定义全局拾取处理器 + this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas); + + this.handler.setInputAction((click) => { + // 如果正在画线,则屏蔽掉详情弹窗逻辑,互不干扰 + if (this.isDrawing) return; + // 2. 拾取点击位置的对象 + const pickedObject = this.viewer.scene.pick(click.position); + if (Cesium.defined(pickedObject) && pickedObject.id) { + const entity = pickedObject.id; + // 3. 判断是否点中了业务航点 + if (entity.properties && entity.properties.isMissionWaypoint) { + // 这里的 name 依然可以用作查询标识,或者用 ID + this.$emit('open-waypoint-dialog', entity.name); + } + } + }, Cesium.ScreenSpaceEventType.LEFT_CLICK); } catch (error) { console.error('地图错误:', error) @@ -625,6 +840,7 @@ export default { this.drawingHandler.setInputAction(() => { this.cancelDrawing(); }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); + }, finishRectangleDrawing() { @@ -1060,19 +1276,6 @@ export default { return area }, - calculateRectangleArea(coordinates) { - const rect = coordinates.getValue ? coordinates.getValue() : coordinates - const width = Cesium.Cartesian3.distance( - Cesium.Cartesian3.fromRadians(rect.west, rect.north), - Cesium.Cartesian3.fromRadians(rect.east, rect.north) - ) - const height = Cesium.Cartesian3.distance( - Cesium.Cartesian3.fromRadians(rect.west, rect.north), - Cesium.Cartesian3.fromRadians(rect.west, rect.south) - ) - - return width * height - }, // ================== 实体管理 ================== @@ -1167,7 +1370,6 @@ export default { } } }, - clearAll() { // 1. 检查数组是否有内容 if (this.allEntities && this.allEntities.length > 0) { diff --git a/ruoyi-ui/src/views/childRoom/RightPanel.vue b/ruoyi-ui/src/views/childRoom/RightPanel.vue index e73c744..5e00650 100644 --- a/ruoyi-ui/src/views/childRoom/RightPanel.vue +++ b/ruoyi-ui/src/views/childRoom/RightPanel.vue @@ -32,8 +32,8 @@ v-for="route in routes" :key="route.id" class="route-item" - :class="{ selected: selectedRouteId === route.id }" - @click="handleSelectRoute(route)" + :class="{ 'active': activeRouteIds.includes(route.id) }" + @click="$emit('select-route', route)" >
@@ -222,9 +222,9 @@ export default { type: Array, default: () => [] }, - selectedRouteId: { - type: [String, Number], - default: null + activeRouteIds: { + type: Array, + default: () => [] }, selectedRouteDetails: { type: Object, @@ -261,11 +261,7 @@ export default { this.$emit('hide') }, - handleSelectRoute(route) { - this.$emit('select-route', route) - }, - - // 新增:新建航线事件 + // 新建航线事件 handleCreateRoute() { this.$emit('create-route') }, @@ -432,7 +428,7 @@ export default { box-shadow: 0 2px 8px rgba(0, 138, 255, 0.15); } -.route-item.selected { +.route-item.active { background: rgba(0, 138, 255, 0.15); border-color: rgba(0, 138, 255, 0.3); box-shadow: 0 2px 10px rgba(0, 138, 255, 0.25); diff --git a/ruoyi-ui/src/views/childRoom/TopHeader.vue b/ruoyi-ui/src/views/childRoom/TopHeader.vue index 6192637..29c5695 100644 --- a/ruoyi-ui/src/views/childRoom/TopHeader.vue +++ b/ruoyi-ui/src/views/childRoom/TopHeader.vue @@ -3,19 +3,19 @@
- 系统logo 网络化任务规划系统
- +
-
{{ item.name }} - + - 新建计划 打开 保存 - + 导入 - @@ -57,15 +57,15 @@ - + 导出 - + - 军事标绘 图标编辑 属性修改 - + 推演编辑 - @@ -96,11 +96,11 @@ - + - 比例尺 - + - 航空图 - + - 威胁区 - + - 坐标换算 - + - 设置 - @@ -194,11 +194,11 @@ 系统说明 - + - {{ roomCode }}
- +
@@ -233,7 +233,7 @@
{{ onlineCount }}人
- +
@@ -242,7 +242,7 @@
{{ combatTime }}
- +
@@ -252,31 +252,31 @@
- +
- + - - + - - + - \ No newline at end of file + diff --git a/ruoyi-ui/src/views/childRoom/index.vue b/ruoyi-ui/src/views/childRoom/index.vue index 555e796..d015614 100644 --- a/ruoyi-ui/src/views/childRoom/index.vue +++ b/ruoyi-ui/src/views/childRoom/index.vue @@ -4,7 +4,8 @@
- +

二维GIS地图区域

@@ -21,6 +22,17 @@
+ + + + + + + +
@@ -30,7 +42,6 @@ :combat-time="combatTime" :astro-time="astroTime" :user-avatar="userAvatar" - @select-nav="selectTopNav" @save-plan="savePlan" @import-plan-file="importPlanFile" @import-acd="importACD" @@ -88,7 +99,7 @@ :is-hidden="isRightPanelHidden" :active-tab="activeRightTab" :routes="routes" - :selected-route-id="selectedRouteId" + :active-route-ids="activeRouteIds" :selected-route-details="selectedRouteDetails" :conflicts="conflicts" :conflict-count="conflictCount" @@ -208,6 +219,8 @@ import LeftMenu from './LeftMenu' import RightPanel from './RightPanel' import BottomLeftPanel from './BottomLeftPanel' import TopHeader from './TopHeader' +import { listRoutes, getRoutes, addRoutes } from "@/api/system/routes"; +import { updateWaypoints } from "@/api/system/waypoints"; export default { name: 'MissionPlanningView', components: { @@ -233,6 +246,9 @@ export default { selectedRoute: null, showWaypointDialog: false, selectedWaypoint: null, + showNameDialog: false, + newRouteName: '', + tempMapPoints: [], // 作战信息 roomCode: 'JTF-7-ALPHA', @@ -270,7 +286,7 @@ export default { // 右侧面板 activeRightTab: 'plan', - selectedRouteId: 101, + activeRouteIds: [], // 存储当前所有选中的航线ID selectedRouteDetails: null, // 冲突数据 @@ -314,11 +330,7 @@ export default { ], // 航线数据 - routes: [ - { id: 101, name: 'Alpha进场航线', points: 8, conflict: true }, - { id: 102, name: 'Beta巡逻航线', points: 6, conflict: false }, - { id: 103, name: '侦察覆盖区', points: 4, conflict: false }, - ], + routes: [], // 时间控制 timeProgress: 45, @@ -332,11 +344,11 @@ export default { }; }, mounted() { + this.getList(); // 初始化时左侧菜单隐藏 this.isMenuHidden = true; // 初始化时右侧面板隐藏 this.isRightPanelHidden = true; - // 更新时间 this.updateTime(); setInterval(this.updateTime, 1000); @@ -351,6 +363,25 @@ export default { } }, methods: { + // 处理从地图点击传来的编辑请求 + handleOpenWaypointEdit(wpName) { + // 1. 确保当前有选中的航线详情 + if (!this.selectedRouteDetails || !this.selectedRouteDetails.waypoints) { + this.$message.warning('请先在右侧列表选择一条航线'); + return; + } + // 2. 根据点击的航点名称在数据列表中查找 + const wpData = this.selectedRouteDetails.waypoints.find(item => item.name === wpName); + if (wpData) { + // 3. 深拷贝给编辑弹窗绑定的变量,防止直接修改原始数组 + this.selectedWaypoint = JSON.parse(JSON.stringify(wpData)); + // 4. 打开弹窗 + this.showWaypointDialog = true; + } + else { + this.$message.info('未找到该航点的业务数据'); + } + }, // 显示在线成员弹窗 showOnlineMembersDialog() { this.showOnlineMembers = true; @@ -385,41 +416,114 @@ export default { this.$message.success('航线名称更新成功'); } }, - // 新建航线(占位) + // 新建航线 createRoute() { - this.$message.info('新建航线功能开发中...'); + if (this.$refs.cesiumMap) { + this.$refs.cesiumMap.startMissionRouteDrawing(); + this.$message.success('进入航线规划模式'); + } + + }, + /** 从数据库拉取最新的航线列表数据 */ + async getList() { + const query = { scenarioId: 1 }; + try { + const response = await listRoutes(query); + if (response.code === 200) { + this.routes = response.rows.map(item => ({ + id: item.id, + name: item.callSign, + points: item.waypoints ? item.waypoints.length : 0, + conflict: false + })); + } + } catch (error) { + this.$message.error("获取航线列表失败"); + } + }, + handleMapDrawComplete(points) { + if (!points || points.length < 2) { + this.$message.error('航点太少,无法生成航线'); + this.drawDom = false; + return; + } + this.tempMapPoints = points; // 暂存坐标点 + this.showNameDialog = true; // 弹出对话框起名 + }, + /** 弹窗点击“确定”:正式将数据保存到后端数据库 */ + async confirmSaveNewRoute() { + // 严格校验起名逻辑 + if (!this.newRouteName || this.newRouteName.trim() === '') { + this.$message.error('新增航线未命名,请输入名称后保存!'); + return; + } + // 构造符合后端 Routes 实体类的数据结构 + const routeData = { + callSign: this.newRouteName, + scenarioId: 1, // 示例:当前归属方案ID(实际应从全局状态获取) + platformId: 1, + attributes: "{}", + waypoints: this.tempMapPoints.map((p, index) => ({ + name: `WP${index + 1}`, + lat: p.lat, + lng: p.lng, + alt: 5000.0, + speed: 800.0, + startTime: 'K+00:00:00', + turnAngle: 0.0 + })) + }; + + try { + // 调用后端 API 保存到数据库 + const response = await addRoutes(routeData); + if (response.code === 200) { + this.$message.success('航线及其航点已成功保存至数据库'); + // 重置 UI 状态 + this.showNameDialog = false; + this.drawDom = false; + this.newRouteName = ''; + this.tempMapPoints = []; + // 重新拉取右侧航线列表以保持同步 + await this.getList(); + } + } catch (error) { + console.error("保存航线失败:", error); + this.$message.error('保存失败,请检查后端服务'); + } }, // 航点编辑弹窗相关方法 openWaypointDialog(waypoint) { this.selectedWaypoint = waypoint; this.showWaypointDialog = true; }, - updateWaypoint(updatedWaypoint) { - // 1. 检查是否有正在编辑的航线详情 - if (this.selectedRouteDetails && this.selectedRouteDetails.waypoints) { - - // 2. 找到当前被编辑的这个航点在数组中的位置 - const index = this.selectedRouteDetails.waypoints.indexOf(this.selectedWaypoint); - - if (index !== -1) { - // 3. 使用 splice 方法替换数据 - this.selectedRouteDetails.waypoints.splice(index, 1, updatedWaypoint); - - // 4. 更新当前的选中引用,以便连续编辑 - this.selectedWaypoint = updatedWaypoint; - - this.$message.success('航点更新成功'); - } else { - // 如果用 indexOf 没找到,尝试用名字匹配兜底 - const nameIndex = this.selectedRouteDetails.waypoints.findIndex(p => p.name === this.selectedWaypoint.name); - if (nameIndex !== -1) { - this.selectedRouteDetails.waypoints.splice(nameIndex, 1, updatedWaypoint); - this.selectedWaypoint = updatedWaypoint; - this.$message.success('航点更新成功'); - } else { - this.$message.error('更新失败:未找到对应航点'); + /** 航点编辑保存:更新数据库并同步地图显示 */ + async updateWaypoint(updatedWaypoint) { + // 确保有选中的航线详情 + if (!this.selectedRouteDetails || !this.selectedRouteDetails.waypoints) return; + try { + const response = await updateWaypoints(updatedWaypoint); + if (response.code === 200) { + // 找到当前编辑点在本地数组中的位置 + const index = this.selectedRouteDetails.waypoints.findIndex(p => p.id === updatedWaypoint.id); + if (index !== -1) { + // 记录旧名称,用于地图组件定位 Entity + const oldName = this.selectedRouteDetails.waypoints[index].name; + const newName = updatedWaypoint.name; + // 使用 splice 触发 Vue 响应式更新右侧面板 UI + this.selectedRouteDetails.waypoints.splice(index, 1, { ...updatedWaypoint }); + // 5. 同步更新地图上的图形 + if (this.$refs.cesiumMap) { + this.$refs.cesiumMap.updateWaypointGraphic(oldName, newName); + } + + this.showWaypointDialog = false; + this.$message.success('航点信息已持久化至数据库'); } } + } catch (error) { + console.error("更新航点失败:", error); + this.$message.error('数据库更新失败,请重试'); } }, updateTime() { @@ -677,9 +781,9 @@ export default { this.isRightPanelHidden = false; } } else if(item.id === 'modify'){ - this.drawDom = !this.drawDom - console.log(this.drawDom,999999) - } + this.drawDom = !this.drawDom + console.log(this.drawDom,999999) + } if (item.id === 'deduction') { // 点击推演按钮,显示/隐藏K时弹出框 this.showKTimePopup = !this.showKTimePopup; @@ -774,23 +878,64 @@ export default { const minutes = (val % 4) * 15; return `K+${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:00`; }, + /** 切换航线:实现多选/开关逻辑 */ + async selectRoute(route) { + const index = this.activeRouteIds.indexOf(route.id); - // 航线操作 - selectRoute(route) { - this.selectedRouteId = route.id; - // 模拟获取航点数据 - this.selectedRouteDetails = { - name: route.name, - waypoints: [ - { name: 'WP1', altitude: 5000, speed: '800km/h', eta: 'K+00:40:00' }, - { name: 'WP2', altitude: 6000, speed: '850km/h', eta: 'K+00:55:00' }, - { name: 'WP3', altitude: 5500, speed: '820km/h', eta: 'K+01:10:00' }, - { name: 'WP4', altitude: 5800, speed: '830km/h', eta: 'K+01:25:00' }, - ] - }; - // 移除原有的 this.openRouteDialog(route); + // 航线已在选中列表中 + if (index > -1) { + this.activeRouteIds.splice(index, 1); + if (this.$refs.cesiumMap) { + this.$refs.cesiumMap.removeRouteById(route.id); + } + if (this.selectedRouteDetails && this.selectedRouteDetails.id === route.id) { + if (this.activeRouteIds.length > 0) { + const lastId = this.activeRouteIds[this.activeRouteIds.length - 1]; + try { + const res = await getRoutes(lastId); + if (res.code === 200 && res.data) { + this.selectedRouteDetails = { + id: res.data.id, + name: res.data.callSign, + waypoints: res.data.waypoints || [] + }; + } + } catch (e) { + console.error("回显剩余航线失败", e); + } + } else { + this.selectedRouteDetails = null; + } + } + this.$message.info(`已移除航线: ${route.name}`); + return; + } + // 航线未被选中 + try { + const response = await getRoutes(route.id); + if (response.code === 200 && response.data) { + const fullRouteData = response.data; + const waypoints = fullRouteData.waypoints || []; + this.activeRouteIds.push(route.id); + this.selectedRouteDetails = { + id: fullRouteData.id, + name: fullRouteData.callSign, + waypoints: waypoints + }; + if (waypoints.length > 0) { + // 通知地图渲染 + if (this.$refs.cesiumMap) { + this.$refs.cesiumMap.renderRouteWaypoints(waypoints, route.id); + } + } else { + this.$message.warning('该航线暂无坐标数据,无法在地图展示'); + } + } + } catch (error) { + console.error("获取航线详情失败:", error); + this.$message.error('无法加载该航线的详细航点数据'); + } }, - addWaypoint() { if (this.selectedRouteDetails) { const count = this.selectedRouteDetails.waypoints.length + 1; @@ -805,9 +950,15 @@ export default { }, cancelRoute() { - this.selectedRouteId = null; + // 清空所有选中的航线 + if (this.$refs.cesiumMap) { + this.activeRouteIds.forEach(id => { + this.$refs.cesiumMap.removeRouteById(id); + }); + } + this.activeRouteIds = []; this.selectedRouteDetails = null; - this.$message.info('已取消选中'); + this.$message.info('已清空所有选中航线'); }, // 冲突操作 @@ -857,7 +1008,7 @@ export default { height: 100%; background: linear-gradient(135deg, #1a2f4b 0%, #2c3e50 100%); /* 正确的写法,直接复制这行替换 */ -background: url('~@/assets/map-background.png'); + background: url('~@/assets/map-background.png'); background-size: cover; background-position: center; z-index: 1; diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js index e2698e5..25854e2 100644 --- a/ruoyi-ui/vue.config.js +++ b/ruoyi-ui/vue.config.js @@ -10,7 +10,7 @@ const CompressionPlugin = require('compression-webpack-plugin') const CopyWebpackPlugin = require('copy-webpack-plugin') const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题 -const baseUrl = 'http://192.168.50.30:8080' // 后端接口 +const baseUrl = 'http://127.0.0.1:8080' // 后端接口 const port = process.env.port || process.env.npm_config_port || 80 // 端口 // 定义 Cesium 源码路径