Browse Source

一些优化

master
ctw 1 month ago
parent
commit
5dd0eea865
  1. 2
      ruoyi-admin/src/main/resources/application-druid.yml
  2. 61
      ruoyi-ui/src/views/cesiumMap/index.vue
  3. 20
      ruoyi-ui/src/views/childRoom/RightPanel.vue
  4. 190
      ruoyi-ui/src/views/childRoom/index.vue

2
ruoyi-admin/src/main/resources/application-druid.yml

@ -8,7 +8,7 @@ spring:
master: master:
url: jdbc:mysql://localhost:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 url: jdbc:mysql://localhost:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root username: root
password: 123456 password: A20040303ctw!
# 从库数据源 # 从库数据源
slave: slave:
# 从数据源开关/默认关闭 # 从数据源开关/默认关闭

61
ruoyi-ui/src/views/cesiumMap/index.vue

@ -100,7 +100,7 @@
<el-input-number <el-input-number
v-model="editPlatformForm.iconSize" v-model="editPlatformForm.iconSize"
:min="48" :min="48"
:max="256" :max="256"
controls-position="right" controls-position="right"
style="width: 100%;" style="width: 100%;"
/> />
@ -123,11 +123,12 @@
width="300px" width="300px"
> >
<el-form :model="powerZoneForm" label-width="80px" size="small"> <el-form :model="powerZoneForm" label-width="80px" size="small">
<el-form-item label="半径(米)"> <el-form-item label="半径(米)">
<el-input-number <el-input-number
v-model="powerZoneForm.radius" v-model="powerZoneForm.radius"
:min="100" :min="0.1"
:step="100" :step="0.5"
:precision="2"
controls-position="right" controls-position="right"
style="width: 100%;" style="width: 100%;"
/> />
@ -283,7 +284,7 @@ export default {
powerZoneDialogVisible: false, powerZoneDialogVisible: false,
powerZoneForm: { powerZoneForm: {
routeId: null, routeId: null,
radius: 1000, radius: 10,
color: 'rgba(255, 0, 0, 0.3)' color: 'rgba(255, 0, 0, 0.3)'
}, },
// 线routeId -> true / false // 线routeId -> true / false
@ -621,7 +622,7 @@ export default {
polyline: { polyline: {
positions: solidPositions, positions: solidPositions,
width: 3, width: 3,
material: Cesium.Color.fromCssColorString('#800080'), material: Cesium.Color.fromCssColorString('#2E5C3E'),
arcType: Cesium.ArcType.NONE arcType: Cesium.ArcType.NONE
} }
}); });
@ -643,7 +644,7 @@ export default {
}, false), }, false),
width: 3, width: 3,
material: new Cesium.PolylineDashMaterialProperty({ material: new Cesium.PolylineDashMaterialProperty({
color: Cesium.Color.fromCssColorString('#800080'), color: Cesium.Color.fromCssColorString('#2E5C3E'),
dashLength: 16 dashLength: 16
}), }),
arcType: Cesium.ArcType.NONE arcType: Cesium.ArcType.NONE
@ -785,7 +786,7 @@ export default {
}, false), }, false),
width: 3, width: 3,
material: new Cesium.PolylineDashMaterialProperty({ material: new Cesium.PolylineDashMaterialProperty({
color: Cesium.Color.fromCssColorString('#800080'), color: Cesium.Color.fromCssColorString('#2E5C3E'),
dashLength: 16 dashLength: 16
}), }),
arcType: Cesium.ArcType.NONE arcType: Cesium.ArcType.NONE
@ -845,7 +846,7 @@ export default {
polyline: { polyline: {
positions: solidPositions, positions: solidPositions,
width: 3, width: 3,
material: Cesium.Color.fromCssColorString('#800080'), material: Cesium.Color.fromCssColorString('#2E5C3E'),
arcType: Cesium.ArcType.NONE arcType: Cesium.ArcType.NONE
} }
}); });
@ -859,7 +860,7 @@ export default {
}, false), }, false),
width: 3, width: 3,
material: new Cesium.PolylineDashMaterialProperty({ material: new Cesium.PolylineDashMaterialProperty({
color: Cesium.Color.fromCssColorString('#800080'), color: Cesium.Color.fromCssColorString('#2E5C3E'),
dashLength: 16 dashLength: 16
}), }),
arcType: Cesium.ArcType.NONE arcType: Cesium.ArcType.NONE
@ -975,7 +976,7 @@ export default {
polyline: { polyline: {
positions: solidPositions, positions: solidPositions,
width: 3, width: 3,
material: Cesium.Color.fromCssColorString('#800080'), material: Cesium.Color.fromCssColorString('#2E5C3E'),
arcType: Cesium.ArcType.NONE arcType: Cesium.ArcType.NONE
} }
}); });
@ -1532,9 +1533,9 @@ export default {
const wpColor = wpStyle.color || '#ffffff'; const wpColor = wpStyle.color || '#ffffff';
const wpOutline = wpStyle.outlineColor || '#0078FF'; const wpOutline = wpStyle.outlineColor || '#0078FF';
const wpOutlineW = wpStyle.outlineWidth != null ? wpStyle.outlineWidth : 2; const wpOutlineW = wpStyle.outlineWidth != null ? wpStyle.outlineWidth : 2;
// 线线 3线线线 // 线绿线 3线线线
const lineWidth = lineStyle.width != null ? lineStyle.width : 3; const lineWidth = lineStyle.width != null ? lineStyle.width : 3;
const lineColor = lineStyle.color || '#800080'; const lineColor = lineStyle.color || '#2E5C3E';
const gapColor = lineStyle.gapColor != null ? lineStyle.gapColor : '#000000'; const gapColor = lineStyle.gapColor != null ? lineStyle.gapColor : '#000000';
const dashLen = lineStyle.dashLength != null ? lineStyle.dashLength : 20; const dashLen = lineStyle.dashLength != null ? lineStyle.dashLength : 20;
const useDash = (lineStyle.style || 'solid') === 'dash'; const useDash = (lineStyle.style || 'solid') === 'dash';
@ -1570,9 +1571,10 @@ export default {
} }
return !!nextLogical; return !!nextLogical;
}; };
// 线 // 线穿线
waypoints.forEach((wp, index) => { waypoints.forEach((wp, index) => {
if (isTurnWaypointWithArc(index)) return; if (isTurnWaypointWithArc(index)) return;
if (this.isHoldWaypoint(wp)) return;
const pos = originalPositions[index]; const pos = originalPositions[index];
this.viewer.entities.add({ this.viewer.entities.add({
id: `wp_${routeId}_${wp.id}`, id: `wp_${routeId}_${wp.id}`,
@ -1740,9 +1742,11 @@ export default {
} }
for (let k = 1; k < arcPoints.length; k++) finalPathPositions.push(arcPoints[k]); for (let k = 1; k < arcPoints.length; k++) finalPathPositions.push(arcPoints[k]);
finalPathPositions.push(exit); finalPathPositions.push(exit);
// 线show:false 线线 lineWidth/lineMaterial
this.viewer.entities.add({ this.viewer.entities.add({
id: `hold-line-${routeId}-${i}`, id: `hold-line-${routeId}-${i}`,
polyline: { positions: [entry, ...arcPoints.slice(1), exit], width: 8, material: Cesium.Color.ORANGE, arcType: Cesium.ArcType.NONE, zIndex: 20 }, show: false,
polyline: { positions: [entry, ...arcPoints.slice(1), exit], width: lineWidth, material: lineMaterial, arcType: Cesium.ArcType.NONE, zIndex: 20 },
properties: { routeId: routeId } properties: { routeId: routeId }
}); });
lastPos = exit; lastPos = exit;
@ -1830,6 +1834,15 @@ export default {
const now = Cesium.JulianDate.now(); const now = Cesium.JulianDate.now();
const positions = []; const positions = [];
for (let i = 0; i < ids.length; i++) { for (let i = 0; i < ids.length; i++) {
// 线线穿线
const holdEnt = this.viewer.entities.getById(`hold-line-${routeId}-${i}`);
if (holdEnt && holdEnt.polyline && holdEnt.polyline.positions) {
const arr = holdEnt.polyline.positions.getValue(now);
if (arr && arr.length) {
for (let k = 0; k < arr.length; k++) positions.push(Cesium.Cartesian3.clone(arr[k]));
continue;
}
}
const ent = this.viewer.entities.getById(`wp_${routeId}_${ids[i]}`); const ent = this.viewer.entities.getById(`wp_${routeId}_${ids[i]}`);
if (ent && ent.position) { if (ent && ent.position) {
const pos = ent.position.getValue(now); const pos = ent.position.getValue(now);
@ -1846,14 +1859,6 @@ export default {
continue; continue;
} }
} }
const holdEnt = this.viewer.entities.getById(`hold-line-${routeId}-${i}`);
if (holdEnt && holdEnt.polyline && holdEnt.polyline.positions) {
const arr = holdEnt.polyline.positions.getValue(now);
if (arr && arr.length) {
for (let k = 0; k < arr.length; k++) positions.push(Cesium.Cartesian3.clone(arr[k]));
continue;
}
}
} }
return positions.length > 0 ? positions : null; return positions.length > 0 ? positions : null;
}, },
@ -5369,10 +5374,10 @@ export default {
this.contextMenu.visible = false this.contextMenu.visible = false
return return
} }
// routeId // routeId
this.powerZoneForm = { this.powerZoneForm = {
routeId: ed.routeId, routeId: ed.routeId,
radius: 1000, radius: 10,
color: 'rgba(255, 0, 0, 0.3)' color: 'rgba(255, 0, 0, 0.3)'
} }
this.contextMenu.visible = false this.contextMenu.visible = false
@ -5406,8 +5411,8 @@ export default {
return platformEntity.position.getValue(now) return platformEntity.position.getValue(now)
}, false), }, false),
ellipse: { ellipse: {
semiMinorAxis: this.powerZoneForm.radius, semiMinorAxis: this.powerZoneForm.radius * 1000,
semiMajorAxis: this.powerZoneForm.radius, semiMajorAxis: this.powerZoneForm.radius * 1000,
material: Cesium.Color.fromCssColorString(this.powerZoneForm.color), material: Cesium.Color.fromCssColorString(this.powerZoneForm.color),
outline: true, outline: true,
outlineColor: Cesium.Color.fromCssColorString(this.powerZoneForm.color).withAlpha(1.0), outlineColor: Cesium.Color.fromCssColorString(this.powerZoneForm.color).withAlpha(1.0),
@ -5419,7 +5424,7 @@ export default {
this.viewer.scene.requestRender() this.viewer.scene.requestRender()
} }
this.powerZoneDialogVisible = false this.powerZoneDialogVisible = false
this.$message.success(`已添加半径 ${this.powerZoneForm.radius} 米的威力区`) this.$message.success(`已添加半径 ${this.powerZoneForm.radius} 米的威力区`)
}, },
// //
deleteEntityFromContextMenu() { deleteEntityFromContextMenu() {

20
ruoyi-ui/src/views/childRoom/RightPanel.vue

@ -119,16 +119,24 @@
<div class="conflict-details"> <div class="conflict-details">
<div class="detail-item"> <div class="detail-item">
<span class="label">{{ $t('rightPanel.involvedRoutes') }}</span> <span class="label">{{ $t('rightPanel.involvedRoutes') }}</span>
<span class="value">{{ conflict.routes.join('、') }}</span> <span class="value">{{ conflict.routeName || (conflict.routes && conflict.routes.join('、')) }}</span>
</div> </div>
<div class="detail-item"> <div v-if="conflict.fromWaypoint && conflict.toWaypoint" class="detail-item">
<span class="label">问题航段</span>
<span class="value">{{ conflict.fromWaypoint }} {{ conflict.toWaypoint }}</span>
</div>
<div v-if="conflict.time" class="detail-item">
<span class="label">{{ $t('rightPanel.conflictTime') }}</span> <span class="label">{{ $t('rightPanel.conflictTime') }}</span>
<span class="value">{{ conflict.time }}</span> <span class="value">{{ conflict.time }}</span>
</div> </div>
<div class="detail-item"> <div v-if="conflict.position" class="detail-item">
<span class="label">{{ $t('rightPanel.conflictPosition') }}</span> <span class="label">{{ $t('rightPanel.conflictPosition') }}</span>
<span class="value">{{ conflict.position }}</span> <span class="value">{{ conflict.position }}</span>
</div> </div>
<div v-if="conflict.suggestion" class="detail-item suggestion">
<span class="label">建议</span>
<span class="value">{{ conflict.suggestion }}</span>
</div>
</div> </div>
<div class="conflict-actions"> <div class="conflict-actions">
<el-button type="text" size="mini" class="blue-text-btn" @click="handleViewConflict(conflict)"> <el-button type="text" size="mini" class="blue-text-btn" @click="handleViewConflict(conflict)">
@ -831,6 +839,12 @@ export default {
font-weight: 500; font-weight: 500;
} }
.detail-item.suggestion .value {
white-space: normal;
word-break: break-word;
color: #008aff;
}
.conflict-actions { .conflict-actions {
display: flex; display: flex;
gap: 10px; gap: 10px;

190
ruoyi-ui/src/views/childRoom/index.vue

@ -218,7 +218,6 @@
<div class="popup-hide-btn" @click="hideKTimePopup" title="隐藏K时"> <div class="popup-hide-btn" @click="hideKTimePopup" title="隐藏K时">
<i class="el-icon-arrow-down"></i> <i class="el-icon-arrow-down"></i>
</div> </div>
<p class="deduction-hint">仅推演当前展示的航线K 时可随时由房主/管理员在右上角作战时间处修改</p>
<div class="timeline-controls"> <div class="timeline-controls">
<div class="current-time blue-time"> <div class="current-time blue-time">
<i class="el-icon-time"></i> <i class="el-icon-time"></i>
@ -261,14 +260,6 @@
</div> </div>
</div> </div>
</div> </div>
<div v-if="deductionWarnings.length > 0 || hasEarlyArrivalLegs" class="deduction-warnings">
<i class="el-icon-warning-outline"></i>
<span>{{ deductionWarnings[0] || '存在航段将提前到达下一航点。' }}</span>
<el-tooltip v-if="deductionWarnings.length > 1" :content="deductionWarnings.join(';')" placement="top">
<span class="warnings-more"> {{ deductionWarnings.length }} </span>
</el-tooltip>
<el-button v-if="hasEarlyArrivalLegs" type="text" size="mini" @click="openAddHoldFromFirstEarly">在此添加盘旋</el-button>
</div>
<el-dialog :title="addHoldDialogTitle" :visible.sync="showAddHoldDialog" width="420px" append-to-body> <el-dialog :title="addHoldDialogTitle" :visible.sync="showAddHoldDialog" width="420px" append-to-body>
<div v-if="addHoldContext" class="add-hold-tip">{{ addHoldDialogTip }}</div> <div v-if="addHoldContext" class="add-hold-tip">{{ addHoldDialogTip }}</div>
<el-form :model="addHoldForm" label-width="100px" size="small"> <el-form :model="addHoldForm" label-width="100px" size="small">
@ -598,26 +589,9 @@ export default {
activeRouteIds: [], // 线ID activeRouteIds: [], // 线ID
/** 航线上锁状态:routeId -> true 上锁,与地图右键及右侧列表锁图标同步 */ /** 航线上锁状态:routeId -> true 上锁,与地图右键及右侧列表锁图标同步 */
routeLocked: {}, routeLocked: {},
// // runConflictCheck 线
conflictCount: 2, conflictCount: 0,
conflicts: [ conflicts: [],
{
id: 1,
title: '航线空间冲突',
routes: ['Alpha进场航线', 'Beta巡逻航线'],
time: 'K+01:20:00',
position: 'E116° N39°',
severity: 'high'
},
{
id: 2,
title: '时间窗口重叠',
routes: ['侦察覆盖区', '无人机巡逻'],
time: 'K+02:15:00',
position: 'E117° N38°',
severity: 'medium'
}
],
// //
activePlatformTab: 'air', activePlatformTab: 'air',
@ -743,12 +717,16 @@ export default {
const response = await getRoutes(routeId); const response = await getRoutes(routeId);
if (response.code === 200 && response.data) { if (response.code === 200 && response.data) {
const fullRouteData = response.data; const fullRouteData = response.data;
// selectRoute const fromList = this.routes.find(r => r.id === routeId);
// list platform 便
this.selectedRouteId = fullRouteData.id; this.selectedRouteId = fullRouteData.id;
this.selectedRouteDetails = { this.selectedRouteDetails = {
id: fullRouteData.id, id: fullRouteData.id,
name: fullRouteData.callSign, name: fullRouteData.callSign,
waypoints: fullRouteData.waypoints || [] waypoints: fullRouteData.waypoints || [],
platformId: fromList?.platformId,
platform: fromList?.platform,
attributes: fromList?.attributes
}; };
} }
} catch (error) { } catch (error) {
@ -908,11 +886,13 @@ export default {
if (i !== -1) this.selectedRouteDetails.waypoints.splice(i, 1, merged); if (i !== -1) this.selectedRouteDetails.waypoints.splice(i, 1, merged);
} }
if (this.$refs.cesiumMap) { if (this.$refs.cesiumMap) {
// list routeselectedRouteDetails getRoutes platformId/platform
const routeForPlatform = this.routes.find(r => r.id === routeId) || route;
this.$refs.cesiumMap.renderRouteWaypoints( this.$refs.cesiumMap.renderRouteWaypoints(
waypoints, waypoints,
routeId, routeId,
route.platformId, routeForPlatform.platformId,
route.platform, routeForPlatform.platform,
this.parseRouteStyle(route.attributes) this.parseRouteStyle(route.attributes)
); );
} }
@ -1000,11 +980,11 @@ export default {
// //
this.showPlatformDialog = false; this.showPlatformDialog = false;
}, },
/** 新建航线时写入数据库的默认样式(与地图默认显示一致:色实线线宽3) */ /** 新建航线时写入数据库的默认样式(与地图默认显示一致:墨绿色实线线宽3) */
getDefaultRouteAttributes() { getDefaultRouteAttributes() {
const defaultAttrs = { const defaultAttrs = {
waypointStyle: { pixelSize: 7, color: '#ffffff', outlineColor: '#0078FF', outlineWidth: 2 }, waypointStyle: { pixelSize: 7, color: '#ffffff', outlineColor: '#0078FF', outlineWidth: 2 },
lineStyle: { style: 'solid', width: 3, color: '#800080', gapColor: '#000000', dashLength: 20 } lineStyle: { style: 'solid', width: 3, color: '#2E5C3E', gapColor: '#000000', dashLength: 20 }
}; };
return JSON.stringify(defaultAttrs); return JSON.stringify(defaultAttrs);
}, },
@ -1238,9 +1218,24 @@ export default {
} }
// 2. pointTypeholdParams 14 #333333 // 2. pointTypeholdParams 14 #333333
// 线 0 45° // K ÷
const wpCount = this.tempMapPoints.length; const wpCount = this.tempMapPoints.length;
const finalWaypoints = this.tempMapPoints.map((p, index) => { let cumulativeMinutes = 0;
const pointsWithStartTime = this.tempMapPoints.map((p, index) => {
const startTime = this.minutesToStartTime(index === 0 ? 0 : Math.ceil(cumulativeMinutes));
if (index < wpCount - 1) {
const next = this.tempMapPoints[index + 1];
const dist = this.segmentDistance(
{ lat: p.lat, lng: p.lng, alt: p.alt != null ? p.alt : 5000 },
{ lat: next.lat, lng: next.lng, alt: next.alt != null ? next.alt : 5000 }
);
const speedKmh = Number(p.speed) || 800;
cumulativeMinutes += (dist / 1000) * (60 / speedKmh);
}
return { ...p, startTime };
});
// 线 0 45°
const finalWaypoints = pointsWithStartTime.map((p, index) => {
const isFirstOrLast = index === 0 || index === wpCount - 1; const isFirstOrLast = index === 0 || index === wpCount - 1;
const defaultTurnAngle = isFirstOrLast ? 0.0 : 45.0; const defaultTurnAngle = isFirstOrLast ? 0.0 : 45.0;
return { return {
@ -1249,7 +1244,7 @@ export default {
lng: p.lng, lng: p.lng,
alt: p.alt != null ? p.alt : 5000.0, alt: p.alt != null ? p.alt : 5000.0,
speed: p.speed != null ? p.speed : 800.0, speed: p.speed != null ? p.speed : 800.0,
startTime: p.startTime || 'K+00:00:00', startTime: p.startTime,
turnAngle: p.turnAngle != null ? p.turnAngle : defaultTurnAngle, turnAngle: p.turnAngle != null ? p.turnAngle : defaultTurnAngle,
labelFontSize: p.labelFontSize != null ? p.labelFontSize : 14, labelFontSize: p.labelFontSize != null ? p.labelFontSize : 14,
labelColor: p.labelColor || '#333333', labelColor: p.labelColor || '#333333',
@ -2354,11 +2349,14 @@ export default {
const pos = { lng: p.lng, lat: p.lat, alt: p.alt }; const pos = { lng: p.lng, lat: p.lat, alt: p.alt };
return { return {
segments: [{ startTime: globalMin, endTime: globalMax, startPos: pos, endPos: pos, type: 'wait' }], segments: [{ startTime: globalMin, endTime: globalMax, startPos: pos, endPos: pos, type: 'wait' }],
warnings warnings,
earlyArrivalLegs: [],
lateArrivalLegs: []
}; };
} }
const effectiveTime = [points[0].minutes]; const effectiveTime = [points[0].minutes];
const segments = []; const segments = [];
const lateArrivalLegs = []; //
const path = pathData && pathData.path; const path = pathData && pathData.path;
const segmentEndIndices = pathData && pathData.segmentEndIndices; const segmentEndIndices = pathData && pathData.segmentEndIndices;
const holdArcRanges = pathData && pathData.holdArcRanges || {}; const holdArcRanges = pathData && pathData.holdArcRanges || {};
@ -2425,6 +2423,13 @@ export default {
warnings.push( warnings.push(
`某航段:距离约 ${(dist / 1000).toFixed(1)}km,计划 ${(scheduled - points[i].minutes).toFixed(0)} 分钟,当前速度 ${speedKmh}km/h 无法按时到达,约需 ≥${Math.ceil(requiredSpeedKmh)}km/h,请调整相对K时或速度。` `某航段:距离约 ${(dist / 1000).toFixed(1)}km,计划 ${(scheduled - points[i].minutes).toFixed(0)} 分钟,当前速度 ${speedKmh}km/h 无法按时到达,约需 ≥${Math.ceil(requiredSpeedKmh)}km/h,请调整相对K时或速度。`
); );
lateArrivalLegs.push({
legIndex: i,
fromName: waypoints[i].name,
toName: waypoints[i + 1].name,
requiredSpeedKmh: Math.ceil(requiredSpeedKmh),
speedKmh
});
} else if (actualArrival < scheduled - 0.5) { } else if (actualArrival < scheduled - 0.5) {
warnings.push('存在航段将提前到达下一航点,平台将在该点等待至计划时间再飞往下一段。'); warnings.push('存在航段将提前到达下一航点,平台将在该点等待至计划时间再飞往下一段。');
} }
@ -2449,7 +2454,7 @@ export default {
earlyArrivalLegs.push({ legIndex: i, scheduled, actualArrival, fromName: waypoints[i].name, toName: waypoints[i + 1].name }); earlyArrivalLegs.push({ legIndex: i, scheduled, actualArrival, fromName: waypoints[i].name, toName: waypoints[i + 1].name });
} }
} }
return { segments, warnings, earlyArrivalLegs }; return { segments, warnings, earlyArrivalLegs, lateArrivalLegs };
}, },
/** 从路径片段中按比例 t(0~1)取点:按弧长比例插值 */ /** 从路径片段中按比例 t(0~1)取点:按弧长比例插值 */
@ -2800,10 +2805,14 @@ export default {
const waypoints = fullRouteData.waypoints || []; const waypoints = fullRouteData.waypoints || [];
this.activeRouteIds.push(route.id); this.activeRouteIds.push(route.id);
this.selectedRouteId = fullRouteData.id; this.selectedRouteId = fullRouteData.id;
// list platformId/platform便
this.selectedRouteDetails = { this.selectedRouteDetails = {
id: fullRouteData.id, id: fullRouteData.id,
name: fullRouteData.callSign, name: fullRouteData.callSign,
waypoints: waypoints waypoints: waypoints,
platformId: route.platformId,
platform: route.platform,
attributes: route.attributes
}; };
// routes 线 waypoints // routes 线 waypoints
@ -2952,11 +2961,15 @@ export default {
const lastId = this.activeRouteIds[this.activeRouteIds.length - 1]; const lastId = this.activeRouteIds[this.activeRouteIds.length - 1];
getRoutes(lastId).then(res => { getRoutes(lastId).then(res => {
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
const fromList = this.routes.find(r => r.id === lastId);
this.selectedRouteId = res.data.id; this.selectedRouteId = res.data.id;
this.selectedRouteDetails = { this.selectedRouteDetails = {
id: res.data.id, id: res.data.id,
name: res.data.callSign, name: res.data.callSign,
waypoints: res.data.waypoints || [] waypoints: res.data.waypoints || [],
platformId: fromList?.platformId,
platform: fromList?.platform,
attributes: fromList?.attributes
}; };
} }
}).catch(e => { }).catch(e => {
@ -2973,10 +2986,58 @@ export default {
} }
}, },
// // 线
runConflictCheck() { runConflictCheck() {
this.conflictCount = 2; const list = [];
this.$message.warning('检测到2处航线冲突'); let id = 1;
const routeIds = this.activeRouteIds && this.activeRouteIds.length > 0 ? this.activeRouteIds : this.routes.map(r => r.id);
const { minMinutes, maxMinutes } = this.getDeductionTimeRange();
routeIds.forEach(routeId => {
const route = this.routes.find(r => r.id === routeId);
if (!route || !route.waypoints || route.waypoints.length < 2) return;
let pathData = null;
if (this.$refs.cesiumMap && this.$refs.cesiumMap.getRoutePathWithSegmentIndices) {
const ret = this.$refs.cesiumMap.getRoutePathWithSegmentIndices(route.waypoints);
if (ret.path && ret.path.length > 0 && ret.segmentEndIndices) {
pathData = { path: ret.path, segmentEndIndices: ret.segmentEndIndices, holdArcRanges: ret.holdArcRanges || {} };
}
}
const { earlyArrivalLegs, lateArrivalLegs } = this.buildRouteTimeline(route.waypoints, minMinutes, maxMinutes, pathData);
const routeName = route.name || `航线${route.id}`;
(earlyArrivalLegs || []).forEach(leg => {
list.push({
id: id++,
title: '提前到达',
routeName,
fromWaypoint: leg.fromName,
toWaypoint: leg.toName,
time: this.minutesToStartTime(leg.actualArrival),
suggestion: '该航段将提前到达下一航点,建议在此段加入盘旋或延后下一航点计划时间。',
severity: 'high'
});
});
(lateArrivalLegs || []).forEach(leg => {
list.push({
id: id++,
title: '无法按时到达',
routeName,
fromWaypoint: leg.fromName,
toWaypoint: leg.toName,
suggestion: `当前速度不足,建议将本段速度提升至 ≥${leg.requiredSpeedKmh} km/h,或延后下一航点计划时间。`,
severity: 'high'
});
});
});
this.conflicts = list;
this.conflictCount = list.length;
if (list.length > 0) {
this.$message.warning(`检测到 ${list.length} 处航线时间问题`);
} else {
this.$message.success('未发现航线时间冲突');
}
}, },
viewConflict(conflict) { viewConflict(conflict) {
@ -3011,7 +3072,7 @@ export default {
overflow: hidden; overflow: hidden;
} }
/* 地图背景 - 保持不变 */ /* 地图背景:使用相对路径便于 IDE 与构建解析;若需图片请将 map-background.png 放到 src/assets/ */
.map-background { .map-background {
position: absolute; position: absolute;
top: 0; top: 0;
@ -3019,8 +3080,7 @@ export default {
width: 100%; width: 100%;
height: 100%; height: 100%;
background: linear-gradient(135deg, #1a2f4b 0%, #2c3e50 100%); background: linear-gradient(135deg, #1a2f4b 0%, #2c3e50 100%);
/* 正确的写法,直接复制这行替换 */ /* 若已存在 src/assets/map-background.png,可改为:background: url('../../assets/map-background.png'); 并注释掉上一行 */
background: url('~@/assets/map-background.png');
background-size: cover; background-size: cover;
background-position: center; background-position: center;
z-index: 1; z-index: 1;
@ -3244,40 +3304,6 @@ export default {
line-height: 1.5; line-height: 1.5;
} }
.deduction-hint {
margin: 0 0 8px 0;
font-size: 12px;
color: #909399;
line-height: 1.4;
}
.deduction-warnings {
display: flex;
align-items: center;
gap: 6px;
margin-top: 8px;
padding: 6px 10px;
background: rgba(230, 162, 60, 0.15);
border: 1px solid rgba(230, 162, 60, 0.5);
border-radius: 6px;
font-size: 12px;
color: #b88230;
}
.deduction-warnings i {
flex-shrink: 0;
}
.deduction-warnings span {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.deduction-warnings .warnings-more {
flex-shrink: 0;
color: #008aff;
cursor: help;
}
.popup-hide-btn { .popup-hide-btn {
position: absolute; position: absolute;
top: -28px; top: -28px;

Loading…
Cancel
Save