+
{{ filteredConflicts.length > 0 ? $t('rightPanel.noMatchFilter') : $t('rightPanel.noConflict') }}
@@ -111,6 +114,10 @@ export default {
conflicts: {
type: Array,
default: () => []
+ },
+ loading: {
+ type: Boolean,
+ default: false
}
},
data() {
@@ -322,6 +329,15 @@ export default {
padding: 12px;
}
+.conflict-loading {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 24px;
+ color: #909399;
+ font-size: 14px;
+}
+
.conflict-list {
display: flex;
flex-direction: column;
diff --git a/ruoyi-ui/src/views/childRoom/index.vue b/ruoyi-ui/src/views/childRoom/index.vue
index 27d2a4c..04185c8 100644
--- a/ruoyi-ui/src/views/childRoom/index.vue
+++ b/ruoyi-ui/src/views/childRoom/index.vue
@@ -416,6 +416,7 @@
v-if="!screenshotMode"
:visible.sync="showConflictDrawer"
:conflicts="conflicts"
+ :loading="conflictCheckRunning"
@view-conflict="viewConflict"
@resolve-conflict="resolveConflict"
/>
@@ -706,6 +707,8 @@ export default {
show4TPanel: false,
/** 冲突列表弹窗(点击左侧冲突按钮即打开并自动执行检测) */
showConflictDrawer: false,
+ /** 冲突检测进行中(避免主线程长时间阻塞导致页面卡死) */
+ conflictCheckRunning: false,
/** 定位冲突时让右侧面板展开的航线 ID 列表 */
expandRouteIdsForPanel: [],
/** 打开航线编辑弹窗时默认选中的 tab(解决冲突时传 'waypoints' 直接打开航点列表) */
@@ -3966,9 +3969,15 @@ export default {
// 白板:进入/退出白板模式
this.toggleWhiteboardMode();
} else if (item.id === 'start') {
- // 冲突:打开可拖动冲突列表弹窗,并立即执行检测(无需再点“重新检测”)
+ // 冲突:打开弹窗并异步执行检测,避免航线多时主线程阻塞导致页面卡死
this.showConflictDrawer = true;
- this.$nextTick(() => { this.runConflictCheck(); });
+ this.conflictCheckRunning = true;
+ this.$nextTick(() => {
+ setTimeout(() => {
+ this.runConflictCheck();
+ this.conflictCheckRunning = false;
+ }, 0);
+ });
} else if (item.id === 'insert') {
// 如果当前已经是平台标签页,则关闭右侧面板
if (this.activeRightTab === 'platform' && !this.isRightPanelHidden) {
@@ -5219,6 +5228,8 @@ export default {
const waypointStartTimeToMinutes = (s) => this.waypointStartTimeToMinutes(s);
const allRaw = [];
+ /** 按航线缓存 timeline(segments+path),供航迹间隔检测复用,避免每 (routeId,t) 重复 buildRouteTimeline 导致航线多时卡死 */
+ const routeIdToTimeline = {};
// ---------- 时间冲突:单航线内(提前到达、无法按时到达、盘旋时间不足)----------
routeIds.forEach(routeId => {
@@ -5231,10 +5242,16 @@ export default {
pathData = { path: ret.path, segmentEndIndices: ret.segmentEndIndices, holdArcRanges: ret.holdArcRanges || {} };
}
}
- const { earlyArrivalLegs, lateArrivalLegs, holdDelayConflicts } = this.buildRouteTimeline(route.waypoints, minMinutes, maxMinutes, pathData);
+ const timeline = this.buildRouteTimeline(route.waypoints, minMinutes, maxMinutes, pathData);
+ const { earlyArrivalLegs, lateArrivalLegs, holdDelayConflicts } = timeline;
+ routeIdToTimeline[routeId] = {
+ segments: timeline.segments,
+ path: pathData && pathData.path ? pathData.path : null,
+ segmentEndIndices: pathData && pathData.segmentEndIndices ? pathData.segmentEndIndices : null
+ };
const routeName = route.name || `航线${route.id}`;
(earlyArrivalLegs || []).forEach(leg => {
- // 提前到达:给出多种可选思路,统一在提示里说明“视定速/定时约束优先调整未受约束量”
+ // 提前到达:相对K时=离开该点时间;到达早于该时间时可降速/盘旋等待/调晚下一航点相对K时;受定速/定时约束时只调未锁定参数
allRaw.push({
type: CONFLICT_TYPE.TIME,
subType: 'early_arrival',
@@ -5244,12 +5261,12 @@ export default {
fromWaypoint: leg.fromName,
toWaypoint: leg.toName,
time: this.minutesToStartTime(leg.actualArrival),
- suggestion: '该航段将提前到达下一航点。可选措施:① 适当降低本段巡航速度;② 在本段或下一航点前增加盘旋等待;③ 视任务需要调整下一航点相对K时/计划时间。若存在定速点或定时点,请优先调整未受约束的速度或时间。',
+ suggestion: '① 降低本段速度 ② 下一航点为盘旋点时依靠盘旋等待 ③ 将下一航点相对K时调晚',
severity: 'high'
});
});
(lateArrivalLegs || []).forEach(leg => {
- // 无法按时到达:同时提示“提速”和“调整时间/路径”等多种方案
+ // 无法按时到达:需在下一航点相对K时前到达;可提速或调早下一航点相对K时;受定速/定时约束时只调未锁定参数
allRaw.push({
type: CONFLICT_TYPE.TIME,
subType: 'late_arrival',
@@ -5258,12 +5275,12 @@ export default {
routeIds: [routeId],
fromWaypoint: leg.fromName,
toWaypoint: leg.toName,
- suggestion: `当前速度不足,理论上需将本段速度提升至 ≥${leg.requiredSpeedKmh} km/h 才能按时到达。可选措施:① 在安全范围内提高本段或前一段速度;② 适当提前下一航点相对K时/计划时间;③ 结合任务需要调整上游航段或加入盘旋缓冲。若存在定速点或定时点,请优先从未锁定的速度或时间入手。`,
+ suggestion: `① 将本段速度提升至 ≥${leg.requiredSpeedKmh} km/h ② 将下一航点相对K时调早 ③ 调整上游航段速度或时间`,
severity: 'high'
});
});
(holdDelayConflicts || []).forEach(conf => {
- // 盘旋时间不足:提示可修改盘旋圈数/时间、速度或切出时刻
+ // 盘旋时间不足:项目不控制盘旋圈数。定时盘旋时盘旋时间=该点相对K时-到达时间、速度由半径与时间反算;非定时时速度继承上一航点。只能通过延长相对K时/调半径或上一航点速度等改善
allRaw.push({
type: CONFLICT_TYPE.TIME,
subType: 'hold_delay',
@@ -5274,7 +5291,7 @@ export default {
toWaypoint: conf.toName,
time: this.minutesToStartTime(conf.setExitTime),
position: conf.holdCenter ? `经度 ${conf.holdCenter.lng.toFixed(5)}°, 纬度 ${conf.holdCenter.lat.toFixed(5)}°` : undefined,
- suggestion: `警告:设定的盘旋时间不足以支撑战斗机完成最后一圈,实际切出将延迟 ${conf.delaySeconds} 秒。可选措施:① 增加盘旋圈数或调整盘旋结束时间;② 在允许范围内调整盘旋段速度;③ 结合上下游航段,微调相关航点的相对K时/计划时间。若存在定速点或定时点,请优先调整未受约束的参数。`,
+ suggestion: `实际切出将延迟 ${conf.delaySeconds} 秒。① 延长该盘旋点相对K时 ② 定时盘旋调转弯半径,非定时调上一航点速度或本点相对K时 ③ 微调上下游航点相对K时`,
severity: 'high',
holdCenter: conf.holdCenter,
positionLng: conf.holdCenter && conf.holdCenter.lng,
@@ -5287,12 +5304,12 @@ export default {
// 时间窗重叠:仅“时间段有交集”不算冲突(不同地点飞机可同时起飞)。后续若有跑道/频段等资源绑定,再按“同一资源占用时间重叠”报冲突。
// 故此处不再调用 detectTimeWindowOverlap。
- // ---------- 空间冲突:航迹最小间隔 ----------
+ // ---------- 空间冲突:航迹最小间隔(使用缓存的 timeline,避免每 (routeId,t) 重复 buildRouteTimeline)----------
const getPositionAtMinutesForConflict = (routeId, minutesFromK) => {
- const route = this.routes.find(r => r.id === routeId);
- if (!route || !route.waypoints || route.waypoints.length === 0) return null;
- const { position } = this.getPositionAtMinutesFromK(route.waypoints, minutesFromK, minMinutes, maxMinutes, routeId);
- return position;
+ const c = routeIdToTimeline[routeId];
+ if (!c || !c.segments || c.segments.length === 0) return null;
+ const pos = this.getPositionFromTimeline(c.segments, minutesFromK, c.path, c.segmentEndIndices);
+ return pos || null;
};
const trackConflicts = detectTrackSeparation(routeIds, minMinutes, maxMinutes, getPositionAtMinutesForConflict, config);
trackConflicts.forEach(c => allRaw.push(c));