Browse Source

Merge branch 'ctw' of http://124.70.32.114:3100/woka/cesium-map-object into mh

# Conflicts:
#	ruoyi-ui/src/views/cesiumMap/ContextMenu.vue
#	ruoyi-ui/src/views/cesiumMap/index.vue
mh
menghao 1 month ago
parent
commit
b7ca5a89b8
  1. 14
      ruoyi-system/src/main/java/com/ruoyi/system/domain/Rooms.java
  2. 6
      ruoyi-system/src/main/resources/mapper/system/RoomsMapper.xml
  3. 39
      ruoyi-ui/src/views/cesiumMap/ContextMenu.vue
  4. 2
      ruoyi-ui/src/views/cesiumMap/DrawingToolbar.vue
  5. 75
      ruoyi-ui/src/views/cesiumMap/LocateDialog.vue
  6. 1715
      ruoyi-ui/src/views/cesiumMap/index.vue
  7. 10
      ruoyi-ui/src/views/childRoom/RightPanel.vue
  8. 261
      ruoyi-ui/src/views/childRoom/index.vue
  9. 13
      ruoyi-ui/src/views/dialogs/RadiusDialog.vue

14
ruoyi-system/src/main/java/com/ruoyi/system/domain/Rooms.java

@ -37,6 +37,9 @@ public class Rooms extends BaseEntity
@Excel(name = "K0基准时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date kAnchorTime;
/** 房间内空域/威力区等前端图形JSON */
private String frontendDrawings;
public void setId(Long id)
{
this.id = id;
@ -87,6 +90,16 @@ public class Rooms extends BaseEntity
return kAnchorTime;
}
public void setFrontendDrawings(String frontendDrawings)
{
this.frontendDrawings = frontendDrawings;
}
public String getFrontendDrawings()
{
return frontendDrawings;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@ -95,6 +108,7 @@ public class Rooms extends BaseEntity
.append("ownerId", getOwnerId())
.append("name", getName())
.append("kAnchorTime", getkAnchorTime())
.append("frontendDrawings", getFrontendDrawings())
.toString();
}
}

6
ruoyi-system/src/main/resources/mapper/system/RoomsMapper.xml

@ -10,10 +10,11 @@
<result property="ownerId" column="owner_id" />
<result property="name" column="name" />
<result property="kAnchorTime" column="k_anchor_time" />
<result property="frontendDrawings" column="frontend_drawings" />
</resultMap>
<sql id="selectRoomsVo">
select id, parent_id, owner_id, name, k_anchor_time from ry.rooms
select id, parent_id, owner_id, name, k_anchor_time, frontend_drawings from ry.rooms
</sql>
<select id="selectRoomsList" parameterType="Rooms" resultMap="RoomsResult">
@ -38,12 +39,14 @@
<if test="ownerId != null">owner_id,</if>
<if test="name != null and name != ''">name,</if>
<if test="kAnchorTime != null">k_anchor_time,</if>
<if test="frontendDrawings != null">frontend_drawings,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="parentId != null">#{parentId},</if>
<if test="ownerId != null">#{ownerId},</if>
<if test="name != null and name != ''">#{name},</if>
<if test="kAnchorTime != null">#{kAnchorTime},</if>
<if test="frontendDrawings != null">#{frontendDrawings},</if>
</trim>
</insert>
@ -54,6 +57,7 @@
<if test="ownerId != null">owner_id = #{ownerId},</if>
<if test="name != null and name != ''">name = #{name},</if>
<if test="kAnchorTime != null">k_anchor_time = #{kAnchorTime},</if>
<if test="frontendDrawings != null">frontend_drawings = #{frontendDrawings},</if>
</trim>
where id = #{id}
</update>

39
ruoyi-ui/src/views/cesiumMap/ContextMenu.vue

@ -7,13 +7,17 @@
</div>
</div>
<!-- 航线上锁/解锁上锁后不可编辑 -->
<!-- 航线上锁/解锁复制 -->
<div class="menu-section" v-if="entityData && entityData.type === 'route'">
<div class="menu-title">航线编辑</div>
<div class="menu-item" @click="handleToggleRouteLock">
<span class="menu-icon">{{ isRouteLocked ? '🔓' : '🔒' }}</span>
<span>{{ isRouteLocked ? '解锁' : '上锁' }}</span>
</div>
<div class="menu-item" @click="handleCopyRoute">
<span class="menu-icon">📋</span>
<span>复制</span>
</div>
</div>
<!-- 航线上飞机显示/隐藏/编辑标牌编辑平台 -->
@ -134,6 +138,11 @@
<!-- 多边形特有选项 -->
<div class="menu-section" v-if="entityData.type === 'polygon' || entityData.type === 'rectangle' || entityData.type === 'circle' || entityData.type === 'sector' || entityData.type === 'powerZone'">
<div class="menu-title">填充属性</div>
<div class="menu-item" @click="editName" v-if="entityData.type === 'powerZone'">
<span class="menu-icon">📝</span>
<span>名称</span>
<span class="menu-value">{{ entityData.name || '' }}</span>
</div>
<div class="menu-item" @click="toggleColorPicker('color')">
<span class="menu-icon">🎨</span>
<span>填充色</span>
@ -315,6 +324,15 @@
<span>修改朝向</span>
<span class="menu-value">{{ entityData.heading != null ? entityData.heading + '°' : '0°' }}</span>
</div>
<div class="menu-title" style="margin-top:8px;">航线</div>
<div class="menu-item" @click="handleStartRouteBeforePlatform">
<span class="menu-icon"></span>
<span>在此之前插入航线</span>
</div>
<div class="menu-item" @click="handleStartRouteAfterPlatform">
<span class="menu-icon"></span>
<span>在此之后插入航线</span>
</div>
</div>
</div>
</template>
@ -388,10 +406,25 @@ export default {
this.$emit('edit-platform-heading')
},
handleStartRouteBeforePlatform() {
this.$emit('start-route-before-platform', this.entityData)
},
handleStartRouteAfterPlatform() {
this.$emit('start-route-after-platform', this.entityData)
},
handleToggleRouteLabel() {
this.$emit('toggle-route-label')
},
editName() {
const newName = prompt('请输入威力区名称:', this.entityData.name || '')
if (newName !== null && newName.trim() !== '') {
this.$emit('update-property', 'name', newName.trim())
}
},
handleToggleRouteLock() {
this.$emit('toggle-route-lock')
},
@ -404,6 +437,10 @@ export default {
this.$emit('power-zone')
},
handleCopyRoute() {
this.$emit('copy-route')
},
toggleColorPicker(property) {
if (this.showColorPickerFor === property) {
this.showColorPickerFor = null

2
ruoyi-ui/src/views/cesiumMap/DrawingToolbar.vue

@ -41,7 +41,7 @@ export default {
return {
// 线
allToolbarItems: [
{ id: 'mouse', name: '鼠标', icon: 'el-icon-position' },
{ id: 'mouse', name: '鼠标', icon: 'cursor' },
{ id: 'polygon', name: '多边形空域', icon: 'el-icon-house' },
{ id: 'rectangle', name: '矩形空域', icon: 'jx' },
{ id: 'circle', name: '圆形空域', icon: 'circle' },

75
ruoyi-ui/src/views/cesiumMap/LocateDialog.vue

@ -61,7 +61,7 @@
<el-option
v-for="item in waypointList"
:key="item.id"
:label="`${item.name} (${degreesToDMS(item.lng)}, ${degreesToDMS(item.lat)})`"
:label="`${item.name} (${formatCoordinate(item.lng)}, ${formatCoordinate(item.lat)})`"
:value="item.id"
/>
</el-select>
@ -70,7 +70,7 @@
<el-form-item label="经度:">
<el-input
v-model="formData.lng"
placeholder="例如 116°23'48.64""
:placeholder="coordinateFormat === 'dms' ? '例如 116°23\'48.64&quot;' : '例如 116.396844'"
clearable
/>
</el-form-item>
@ -78,7 +78,7 @@
<el-form-item label="纬度:">
<el-input
v-model="formData.lat"
placeholder="例如 39°54'33.48""
:placeholder="coordinateFormat === 'dms' ? '例如 39°54\'33.48&quot;' : '例如 39.909289'"
clearable
/>
</el-form-item>
@ -107,6 +107,10 @@ export default {
visible: {
type: Boolean,
default: false
},
coordinateFormat: {
type: String,
default: 'dms' // 'decimal' 'dms'
}
},
data() {
@ -137,9 +141,44 @@ export default {
this.loadScenarios()
}
this.$emit('update:visible', newVal)
},
coordinateFormat: {
handler(newVal) {
this.updateCoordinateFormat(newVal)
}
}
},
methods: {
updateCoordinateFormat(newFormat) {
if (!this.formData.lng || !this.formData.lat) return
let lngDegrees, latDegrees
if (this.coordinateFormat === 'dms') {
lngDegrees = this.dmsToDegrees(this.formData.lng)
latDegrees = this.dmsToDegrees(this.formData.lat)
} else {
lngDegrees = parseFloat(this.formData.lng)
latDegrees = parseFloat(this.formData.lat)
}
if (lngDegrees !== null && latDegrees !== null && !isNaN(lngDegrees) && !isNaN(latDegrees)) {
if (newFormat === 'dms') {
this.formData.lng = this.degreesToDMS(lngDegrees)
this.formData.lat = this.degreesToDMS(latDegrees)
} else {
this.formData.lng = lngDegrees.toFixed(6)
this.formData.lat = latDegrees.toFixed(6)
}
}
},
formatCoordinate(value) {
if (this.coordinateFormat === 'dms') {
return this.degreesToDMS(value)
} else {
return value.toFixed(6)
}
},
degreesToDMS(decimalDegrees) {
const degrees = Math.floor(decimalDegrees)
const minutesDecimal = (decimalDegrees - degrees) * 60
@ -157,6 +196,7 @@ export default {
return sign * (Math.abs(degrees) + minutes / 60 + seconds / 3600)
},
resetForm() {
if (this.coordinateFormat === 'dms') {
this.formData = {
scenarioId: null,
routeId: null,
@ -164,6 +204,15 @@ export default {
lng: '116°23\'48.64"',
lat: '39°54\'33.48"'
}
} else {
this.formData = {
scenarioId: null,
routeId: null,
waypointId: null,
lng: '116.396844',
lat: '39.909289'
}
}
this.routeList = []
this.waypointList = []
},
@ -214,8 +263,8 @@ export default {
if (value) {
const waypoint = this.waypointList.find(w => w.id === value)
if (waypoint) {
this.formData.lng = this.degreesToDMS(waypoint.lng)
this.formData.lat = this.degreesToDMS(waypoint.lat)
this.formData.lng = this.formatCoordinate(waypoint.lng)
this.formData.lat = this.formatCoordinate(waypoint.lat)
}
}
},
@ -233,13 +282,25 @@ export default {
return
}
const lngDegrees = this.dmsToDegrees(lng)
const latDegrees = this.dmsToDegrees(lat)
let lngDegrees, latDegrees
if (this.coordinateFormat === 'dms') {
lngDegrees = this.dmsToDegrees(lng)
latDegrees = this.dmsToDegrees(lat)
if (lngDegrees === null || latDegrees === null || isNaN(lngDegrees) || isNaN(latDegrees)) {
this.$message.error('请输入有效的度分秒格式!格式:116°23\'48.64"')
return
}
} else {
lngDegrees = parseFloat(lng)
latDegrees = parseFloat(lat)
if (isNaN(lngDegrees) || isNaN(latDegrees)) {
this.$message.error('请输入有效的十进制格式!')
return
}
}
if (lngDegrees < -180 || lngDegrees > 180 || latDegrees < -90 || latDegrees > 90) {
this.$message.error('经纬度超出有效范围!')

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

File diff suppressed because it is too large

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

@ -70,6 +70,11 @@
</el-tag>
<div class="tree-item-actions">
<i class="el-icon-view" title="显示/隐藏" @click.stop="handleToggleRouteVisibility(route)"></i>
<i
:class="routeLocked[route.id] ? 'el-icon-lock' : 'el-icon-unlock'"
:title="routeLocked[route.id] ? '解锁' : '上锁'"
@click.stop="$emit('toggle-route-lock', route)"
></i>
<i class="el-icon-edit" title="编辑" @click.stop="handleOpenRouteDialog(route)"></i>
<i class="el-icon-delete" title="删除" @click.stop="$emit('delete-route', route)"></i>
</div>
@ -278,6 +283,11 @@ export default {
type: Array,
default: () => []
},
/** 航线上锁状态:routeId -> true 上锁,与地图右键上锁/解锁同步 */
routeLocked: {
type: Object,
default: () => ({})
},
selectedPlanId: {
type: [String, Number],
default: null

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

@ -12,13 +12,23 @@
<cesiumMap ref="cesiumMap" :drawDomClick="drawDom || airspaceDrawDom"
:tool-mode="drawDom ? 'ranging' : (airspaceDrawDom ? 'airspace' : 'airspace')"
:scaleConfig="scaleConfig"
:coordinateFormat="coordinateFormat"
:route-locked="routeLocked"
@draw-complete="handleMapDrawComplete"
@route-lock-changed="handleRouteLockChanged"
@drawing-points-update="missionDrawingPointsCount = $event"
@platform-route-drawing-started="missionDrawingActive = true"
@drawing-cancelled="missionDrawingActive = false"
@open-waypoint-dialog="handleOpenWaypointEdit"
@open-route-dialog="handleOpenRouteEdit"
@copy-route="handleCopyRoute"
@route-copy-placed="handleRouteCopyPlaced"
@waypoint-position-changed="handleWaypointPositionChanged"
@scale-click="handleScaleClick"
@platform-icon-updated="onPlatformIconUpdated"
@platform-icon-removed="onPlatformIconRemoved" />
@platform-icon-removed="onPlatformIconRemoved"
@viewer-ready="onViewerReady"
@drawing-entities-changed="onDrawingEntitiesChanged" />
<div v-show="!screenshotMode" class="map-overlay-text">
<!-- <i class="el-icon-location-outline text-3xl mb-2 block"></i> -->
<!-- <p>二维GIS地图区域</p>
@ -40,11 +50,17 @@
<div class="red-dot"></div>
<i class="el-icon-s-unfold icon-inside"></i>
</div>
<el-dialog title="保存新航线" :visible.sync="showNameDialog" width="30%" :append-to-body="true">
<el-dialog title="保存新航线" :visible.sync="showNameDialog" width="30%" :append-to-body="true" @open="onSaveRouteDialogOpen" @close="tempMapPlatform = null; saveDialogScenarioId = null">
<el-form label-width="80px">
<el-form-item label="航线名称">
<el-input v-model="newRouteName" placeholder="例如:航线一"></el-input>
</el-form-item>
<el-form-item label="所属方案">
<el-select v-model="saveDialogScenarioId" placeholder="请选择方案" style="width:100%" clearable>
<el-option v-for="p in plans" :key="p.id" :label="p.name" :value="p.id" />
</el-select>
<div v-if="plans.length === 0" class="el-form-item__error" style="margin-top:4px;">暂无方案请先点击地图左侧红点展开菜单选择方案并新建方案后再保存</div>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="showNameDialog = false"> </el-button>
@ -162,6 +178,7 @@
:selected-route-id="selectedRouteId"
:routes="routes"
:active-route-ids="activeRouteIds"
:route-locked="routeLocked"
:selected-route-details="selectedRouteDetails"
:conflicts="conflicts"
:conflict-count="conflictCount"
@ -181,6 +198,7 @@
@add-waypoint="addWaypoint"
@cancel-route="cancelRoute"
@toggle-route-visibility="toggleRouteVisibility"
@toggle-route-lock="handleToggleRouteLockFromPanel"
@view-conflict="viewConflict"
@resolve-conflict="resolveConflict"
@run-conflict-check="runConflictCheck"
@ -467,6 +485,10 @@ export default {
showNameDialog: false,
newRouteName: '',
tempMapPoints: [],
/** 从平台右键「在此之前/在此之后插入航线」完成时传入,保存航线时用作 platformId */
tempMapPlatform: null,
/** 保存新航线弹窗内选择的方案 ID(弹窗内可直接选方案,无需先展开侧边) */
saveDialogScenarioId: null,
platformIconSaveTimer: null,
//
showImportDialog: false,
@ -485,6 +507,7 @@ export default {
roomDetail: null,
showKTimeSetDialog: false,
kTimeForm: { dateTime: null },
saveRoomDrawingsTimer: null,
//
isMenuHidden: true, //
@ -563,6 +586,9 @@ export default {
showLandmark: true,
showRoute: true,
//
coordinateFormat: 'dms', // 'decimal' 'dms'
menuItems: [],
//
@ -570,6 +596,8 @@ export default {
plans: [],
activeRightTab: 'plan',
activeRouteIds: [], // 线ID
/** 航线上锁状态:routeId -> true 上锁,与地图右键及右侧列表锁图标同步 */
routeLocked: {},
//
conflictCount: 2,
conflicts: [
@ -799,6 +827,106 @@ export default {
}
},
/** 右键「复制航线」:拉取航点后进入复制预览,左键放置后弹窗保存 */
async handleCopyRoute(routeId) {
try {
const res = await getRoutes(routeId);
if (res.code !== 200 || !res.data) {
this.$message.error('获取航线数据失败');
return;
}
const waypoints = res.data.waypoints || [];
if (waypoints.length < 2) {
this.$message.warning('航线航点不足,无法复制');
return;
}
if (this.$refs.cesiumMap && typeof this.$refs.cesiumMap.startRouteCopyPreview === 'function') {
this.$refs.cesiumMap.startRouteCopyPreview(waypoints);
this.$message.info('移动鼠标到目标位置,左键放置复制航线;右键取消');
}
} catch (e) {
this.$message.error('获取航线数据失败');
console.error(e);
}
},
/** 复制航线已放置:用当前偏移后的航点打开「保存新航线」弹窗 */
handleRouteCopyPlaced(points) {
this.tempMapPoints = points || [];
this.tempMapPlatform = null;
this.showNameDialog = true;
},
/** 地图上拖拽航点结束:将新位置写回数据库并刷新显示 */
async handleWaypointPositionChanged({ dbId, routeId, lat, lng, alt }) {
let waypoints = null;
let route = null;
if (this.selectedRouteDetails && this.selectedRouteDetails.id === routeId) {
waypoints = this.selectedRouteDetails.waypoints;
route = this.selectedRouteDetails;
}
if (!waypoints) {
const r = this.routes.find(r => r.id === routeId);
if (r && r.waypoints) {
waypoints = r.waypoints;
route = r;
}
}
if (!waypoints || !route) {
this.$message.error('未找到对应航线数据');
return;
}
const wp = waypoints.find(p => p.id === dbId);
if (!wp) {
this.$message.error('未找到对应航点');
return;
}
const payload = {
id: wp.id,
routeId: wp.routeId != null ? wp.routeId : routeId,
name: wp.name,
seq: wp.seq,
lat: Number(lat),
lng: Number(lng),
alt: Number(alt),
speed: wp.speed,
startTime: (wp.startTime != null && wp.startTime !== '') ? wp.startTime : 'K+00:00:00',
turnAngle: wp.turnAngle
};
if (wp.pointType != null) payload.pointType = wp.pointType;
if (wp.holdParams != null) payload.holdParams = wp.holdParams;
if (wp.labelFontSize != null) payload.labelFontSize = wp.labelFontSize;
if (wp.labelColor != null) payload.labelColor = wp.labelColor;
try {
const response = await updateWaypoints(payload);
if (response.code === 200) {
const merged = { ...wp, ...payload };
const idx = waypoints.findIndex(p => p.id === dbId);
if (idx !== -1) waypoints.splice(idx, 1, merged);
if (this.selectedRouteDetails && this.selectedRouteDetails.id === routeId) {
const i = this.selectedRouteDetails.waypoints.findIndex(p => p.id === dbId);
if (i !== -1) this.selectedRouteDetails.waypoints.splice(i, 1, merged);
}
if (this.$refs.cesiumMap) {
this.$refs.cesiumMap.renderRouteWaypoints(
waypoints,
routeId,
route.platformId,
route.platform,
this.parseRouteStyle(route.attributes)
);
}
this.$message.success('航点位置已更新');
this.$nextTick(() => this.updateDeductionPositions());
} else {
throw new Error(response.msg || '更新失败');
}
} catch (error) {
console.error('更新航点位置失败:', error);
this.$message.error(error.message || '更新失败,请重试');
}
},
// 线
showOnlineMembersDialog() {
this.showOnlineMembers = true;
@ -998,7 +1126,7 @@ export default {
if (idx > -1) {
this.activeRouteIds.splice(idx, 1);
}
await this.getList();
await this.getList({ skipRoomPlatformIcons: true });
}
} catch (e) {
if (e !== 'cancel') {
@ -1007,8 +1135,12 @@ export default {
}
}
},
/** 从数据库拉取最新的航线列表数据 */
async getList() {
/**
* 从数据库拉取最新的航线列表数据
* @param {Object} opts - 可选{ skipRoomPlatformIcons: true } 时不再加载房间平台图标用于删除航线等仅航线变化的场景避免地图上的平台图标被清空再重画导致闪一下
*/
async getList(opts = {}) {
const { skipRoomPlatformIcons = false } = opts;
try {
const roomId = this.$route.query.roomId || this.currentRoomId;
const scenarioRes = await listScenario({ roomId: roomId });
@ -1016,6 +1148,7 @@ export default {
this.plans = scenarioRes.rows.map(s => ({
id: s.id,
name: s.name,
frontendDrawings: s.frontendDrawings || null,
routes: []
}));
}
@ -1054,7 +1187,8 @@ export default {
});
});
}
//
// 线
if (!skipRoomPlatformIcons) {
const rId = roomId || this.currentRoomId;
if (rId && this.$refs.cesiumMap && typeof this.$refs.cesiumMap.loadRoomPlatformIcons === 'function') {
listRoomPlatformIcons(rId).then(res => {
@ -1062,20 +1196,26 @@ export default {
}).catch(() => {});
}
}
}
} catch (error) {
console.error("数据加载失败:", error);
this.$message.error("获取方案列表失败");
}
},
handleMapDrawComplete(points) {
handleMapDrawComplete(points, options) {
this.missionDrawingActive = false;
if (!points || points.length < 2) {
this.$message.error('航点太少,无法生成航线');
this.drawDom = false;
return;
}
this.tempMapPoints = points; //
this.showNameDialog = true; //
this.tempMapPoints = points;
this.tempMapPlatform = (options && (options.platformId != null || options.platform)) ? options : null;
this.showNameDialog = true;
},
/** 保存新航线弹窗打开时:若当前未选方案则用已选方案或第一个方案填充,便于在弹窗内直接选择 */
onSaveRouteDialogOpen() {
this.saveDialogScenarioId = this.selectedPlanId || (this.plans[0] && this.plans[0].id) || null;
},
openAddHoldDuringDrawing() {
@ -1091,9 +1231,9 @@ export default {
this.$message.error('新增航线未命名,请输入名称后保存!');
return;
}
const currentScenarioId = this.selectedPlanId;
const currentScenarioId = this.saveDialogScenarioId != null ? this.saveDialogScenarioId : this.selectedPlanId;
if (!currentScenarioId) {
this.$message.warning('请先在左侧选择一个方案,再保存航线!');
this.$message.warning(this.plans.length === 0 ? '暂无方案,请先点击地图左侧红点展开菜单,选择「方案」并新建方案后再保存。' : '请在上方选择所属方案后再保存。');
return;
}
@ -1121,7 +1261,7 @@ export default {
const routeData = {
callSign: this.newRouteName,
scenarioId: currentScenarioId,
platformId: 1,
platformId: (this.tempMapPlatform && this.tempMapPlatform.platformId != null) ? this.tempMapPlatform.platformId : 1,
attributes: this.getDefaultRouteAttributes(),
waypoints: finalWaypoints
};
@ -1148,25 +1288,37 @@ export default {
this.activeRouteIds.push(newRouteId);
}
// 3. UI
// 3. 线
const platformToRemove = this.tempMapPlatform;
// 4. UI
this.drawDom = false;
this.showNameDialog = false;
this.newRouteName = '';
this.tempMapPoints = [];
this.tempMapPlatform = null;
// 4. B clearAllWaypoints()
// 线
// 5. B clearAllWaypoints
if (this.$refs.cesiumMap) {
//
// tempPreviewEntity
if (this.$refs.cesiumMap.tempPreviewEntity) {
this.viewer.entities.remove(this.$refs.cesiumMap.tempPreviewEntity);
this.$refs.cesiumMap.tempPreviewEntity = null;
}
// clearAllWaypoints
}
// 5. 线getList activeRouteIds 线
// 6. 线 getList
if (platformToRemove && this.$refs.cesiumMap) {
if (platformToRemove.serverId) {
await delRoomPlatformIcon(platformToRemove.serverId).catch(() => {});
if (typeof this.$refs.cesiumMap.removePlatformIconByServerId === 'function') {
this.$refs.cesiumMap.removePlatformIconByServerId(platformToRemove.serverId);
}
} else if (platformToRemove.mapEntityId && typeof this.$refs.cesiumMap.removeEntity === 'function') {
this.$refs.cesiumMap.removeEntity(platformToRemove.mapEntityId);
}
}
// 7. 线getList
await this.getList();
const routeFromList = this.routes.find(r => r.id === newRouteId);
if (routeFromList) {
@ -1290,9 +1442,43 @@ export default {
getRoomDetail() {
if (!this.currentRoomId) return;
getRooms(this.currentRoomId).then(res => {
if (res.code === 200 && res.data) this.roomDetail = res.data;
if (res.code === 200 && res.data) {
this.roomDetail = res.data;
this.$nextTick(() => this.loadRoomDrawings());
}
}).catch(() => {});
},
/** 加载当前房间的空域/威力区图形(与房间 ID 绑定,进入该房间即显示) */
loadRoomDrawings() {
if (!this.roomDetail || !this.$refs.cesiumMap || typeof this.$refs.cesiumMap.loadFrontendDrawings !== 'function') return;
if (this.roomDetail.frontendDrawings) {
this.$refs.cesiumMap.loadFrontendDrawings(this.roomDetail.frontendDrawings);
} else {
this.$refs.cesiumMap.clearDrawingEntities();
}
},
/** 地图 viewer 就绪时加载当前房间图形(可能 getRoomDetail 尚未返回,此处再试一次) */
onViewerReady() {
this.loadRoomDrawings();
},
/** 空域/威力区图形增删时防抖自动保存到当前房间 */
onDrawingEntitiesChanged() {
if (!this.currentRoomId) return;
if (this.saveRoomDrawingsTimer) clearTimeout(this.saveRoomDrawingsTimer);
this.saveRoomDrawingsTimer = setTimeout(() => {
this.saveRoomDrawingsTimer = null;
this.saveRoomDrawingsToServer();
}, 600);
},
/** 将当前地图上的空域图形写入当前房间(静默保存,不弹成功提示;失败时抛出供调用方处理) */
async saveRoomDrawingsToServer() {
if (!this.currentRoomId || !this.$refs.cesiumMap) return;
if (typeof this.$refs.cesiumMap.getFrontendDrawingsData !== 'function') return;
const drawingsData = this.$refs.cesiumMap.getFrontendDrawingsData();
const frontendDrawingsStr = JSON.stringify(drawingsData);
await updateRooms({ id: this.currentRoomId, frontendDrawings: frontendDrawingsStr });
if (this.roomDetail) this.roomDetail.frontendDrawings = frontendDrawingsStr;
},
/** 将任意日期字符串格式化为 yyyy-MM-dd HH:mm:ss,供日期选择器使用 */
formatKTimeForPicker(val) {
if (!val) return null;
@ -1365,9 +1551,18 @@ export default {
this.activeMenu = item.id;
},
//
savePlan() {
this.$message.success('保存计划');
// /
async savePlan() {
if (!this.currentRoomId) {
this.$message.warning('请先进入任务房间');
return;
}
try {
await this.saveRoomDrawingsToServer();
this.$message.success('房间空域图形已保存');
} catch (e) {
this.$message.error('保存失败,请检查网络');
}
},
importPlanFile() {
@ -1796,8 +1991,8 @@ export default {
},
coordinateConversion() {
this.$message.success('坐标换算');
//
this.coordinateFormat = this.coordinateFormat === 'decimal' ? 'dms' : 'decimal'
this.$message.success(`坐标格式已切换为:${this.coordinateFormat === 'decimal' ? '十进制' : '度分秒'}`)
},
//
@ -2549,11 +2744,11 @@ export default {
this.selectedRouteDetails = null;
this.activeRouteIds = [];
//
// /线
if (this.$refs.cesiumMap && this.$refs.cesiumMap.clearAllWaypoints) {
this.$refs.cesiumMap.clearAllWaypoints();
}
console.log(`>>> [切换成功] 已进入方案: ${plan.name},地图已清空,列表已展开。`);
console.log(`>>> [切换成功] 已进入方案: ${plan && plan.name},地图已清空,列表已展开。`);
},
/** 切换航线:实现多选/开关逻辑 */
async selectRoute(route) {
@ -2730,6 +2925,18 @@ export default {
},
// 线/
/** 地图右键上锁/解锁后同步到列表 */
handleRouteLockChanged({ routeId, locked }) {
this.$set(this.routeLocked, routeId, locked);
},
/** 右侧列表锁图标点击:切换该航线上锁状态,与地图右键状态同步 */
handleToggleRouteLockFromPanel(route) {
if (!route || route.id == null) return;
const nextLocked = !this.routeLocked[route.id];
this.$set(this.routeLocked, route.id, nextLocked);
this.$message.success(nextLocked ? '航线已上锁,无法修改' : '航线已解锁,可以编辑');
},
toggleRouteVisibility(route) {
const index = this.activeRouteIds.indexOf(route.id);

13
ruoyi-ui/src/views/dialogs/RadiusDialog.vue

@ -8,6 +8,14 @@
<div class="dialog-body">
<el-form :model="formData" :rules="rules" ref="formRef" label-width="80px" size="small">
<el-form-item label="名称" prop="name">
<el-input
v-model="formData.name"
placeholder="请输入威力区名称"
style="width: 100%;"
></el-input>
</el-form-item>
<el-form-item label="半径" prop="radius">
<el-input-number
v-model="formData.radius"
@ -47,10 +55,14 @@ export default {
data() {
return {
formData: {
name: '',
radius: 50,
unit: 'km'
},
rules: {
name: [
{ required: true, message: '请输入威力区名称', trigger: 'blur' }
],
radius: [
{ required: true, message: '请输入半径', trigger: 'blur' }
]
@ -65,6 +77,7 @@ export default {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$emit('confirm', {
name: this.formData.name,
radius: this.formData.radius,
unit: this.formData.unit
})

Loading…
Cancel
Save