Browse Source

拖拽图标持久化

master
ctw 2 months ago
parent
commit
54fdf44ca5
  1. 31
      ruoyi-ui/src/permission.js
  2. 2
      ruoyi-ui/src/router/index.js
  3. 14
      ruoyi-ui/src/store/modules/permission.js
  4. 85
      ruoyi-ui/src/views/cesiumMap/index.vue
  5. 63
      ruoyi-ui/src/views/childRoom/index.vue

31
ruoyi-ui/src/permission.js

@ -28,20 +28,37 @@ router.beforeEach((to, from, next) => {
} else {
if (store.getters.roles.length === 0) {
isRelogin.show = true
// 超时保护:若 getInfo/getRouters 长时间不返回则关闭加载条并提示,避免页面一直白屏
const timeoutMs = 15000
const timeoutId = setTimeout(() => {
if (store.getters.roles.length === 0) {
isRelogin.show = false
NProgress.done()
Message.error('获取用户信息超时,请确认后端服务已启动(默认 8080 端口)')
store.dispatch('LogOut').then(() => {
next(`/login?redirect=${encodeURIComponent(to.fullPath)}`)
})
}
}, timeoutMs)
const clearTimeoutAndNext = () => {
clearTimeout(timeoutId)
}
// 判断当前用户是否已拉取完user_info信息
store.dispatch('GetInfo').then(() => {
clearTimeoutAndNext()
isRelogin.show = false
store.dispatch('GenerateRoutes').then(accessRoutes => {
// 根据roles权限生成可访问的路由表
router.addRoutes(accessRoutes) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
router.addRoutes(accessRoutes)
next({ ...to, replace: true })
})
}).catch(err => {
store.dispatch('LogOut').then(() => {
Message.error(err)
next({ path: '/' })
})
clearTimeoutAndNext()
isRelogin.show = false
store.dispatch('LogOut').then(() => {
Message.error(err || '获取用户信息失败')
next({ path: '/' })
})
})
} else {
next()
}

2
ruoyi-ui/src/router/index.js

@ -87,7 +87,7 @@ export const constantRoutes = [
{
path: '',
component: Layout,
redirect: 'index',
redirect: '/selectRoom',
children: [
{
path: 'index',

14
ruoyi-ui/src/store/modules/permission.js

@ -52,9 +52,18 @@ const permission = {
}
}
// 确保路由必有 path,避免 [vue-router] "path" is required 报错(后端菜单 path 为空时)
function ensureRoutePath(route, fallback) {
const id = route.menuId || route.id || route.name || ('menu-' + Math.random().toString(36).slice(2, 9))
if (route.path === undefined || route.path === null || (typeof route.path === 'string' && route.path.trim() === '')) {
route.path = fallback || ('/hidden-' + id)
}
}
// 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
return asyncRouterMap.filter(route => {
ensureRoutePath(route)
if (type && route.children) {
route.children = filterChildren(route.children)
}
@ -82,8 +91,9 @@ function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
function filterChildren(childrenMap, lastRouter = false) {
var children = []
childrenMap.forEach(el => {
el.path = lastRouter ? lastRouter.path + '/' + el.path : el.path
childrenMap.forEach((el, idx) => {
ensureRoutePath(el, 'item-' + idx)
el.path = lastRouter ? (lastRouter.path + '/' + el.path).replace(/\/+/g, '/') : el.path
if (el.children && el.children.length && el.component === 'ParentView') {
children = children.concat(filterChildren(el.children, el))
} else {

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

@ -791,6 +791,84 @@ export default {
this.showTransformHandles(entityData);
this.$message && this.$message.success('已放置。上方箭头旋转、四角调大小、拖动图标移动;点击空白收起');
});
return entityData;
},
/** 清除某房间下由 loadRoomPlatformIcons 加载的平台图标(仅从地图与 allEntities 移除) */
clearRoomPlatformIcons(roomId) {
if (!roomId || !this.allEntities) return;
const toRemove = this.allEntities.filter(e => e.type === 'platformIcon' && e.roomId === roomId);
toRemove.forEach(ed => {
this.removeTransformHandles(ed);
if (this.selectedPlatformIcon === ed) this.selectedPlatformIcon = null;
if (ed.entity) this.viewer && this.viewer.entities.remove(ed.entity);
});
this.allEntities = this.allEntities.filter(e => !(e.type === 'platformIcon' && e.roomId === roomId));
},
/** 加载某房间下保存的平台图标到地图;list 项含 id, lng, lat, heading, iconScale, platformId, platformName, platformType, iconUrl */
loadRoomPlatformIcons(roomId, list) {
if (!this.viewer || !roomId || !list || !list.length) return;
this.clearRoomPlatformIcons(roomId);
const baseHalfDeg = 0.00015;
list.forEach((item, idx) => {
const platform = {
id: item.platformId,
name: item.platformName,
type: item.platformType,
imageUrl: item.iconUrl,
iconUrl: item.iconUrl
};
const iconUrl = item.iconUrl || platform.iconUrl;
const imageSrc = iconUrl ? this.formatPlatformIconUrl(iconUrl) : this.getDefaultPlatformIconDataUrl();
this.entityCounter++;
const id = `platformIcon_room_${roomId}_${item.id}`;
const headingDeg = (item.heading != null ? item.heading : 0);
const rotation = Math.PI / 2 - (headingDeg * Math.PI / 180);
const scaleVal = item.iconScale ?? item.icon_scale ?? 1;
const iconScale = Math.max(0.2, Math.min(3, scaleVal));
const size = this.PLATFORM_ICON_BASE_SIZE * iconScale;
const cartesian = Cesium.Cartesian3.fromDegrees(item.lng, item.lat);
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 entityData = {
id,
type: 'platformIcon',
platformId: platform.id,
platform,
name: platform.name || '平台',
heading: headingDeg,
lat: item.lat,
lng: item.lng,
entity,
imageUrl: iconUrl,
label: platform.name || '平台',
iconScale,
transformHandles: null,
serverId: item.id,
roomId
};
this.allEntities.push(entityData);
});
},
/** 为已放置的平台图标设置服务端 ID(保存成功后由父组件调用) */
setPlatformIconServerId(entityId, serverId, roomId) {
const ed = this.allEntities.find(e => e.type === 'platformIcon' && (e.id === entityId || (e.entity && e.entity.id === entityId)));
if (ed) {
ed.serverId = serverId;
if (roomId != null) ed.roomId = roomId;
}
},
//线
renderRouteWaypoints(waypoints, routeId = 'default', platformId, platform, style) {
@ -1735,18 +1813,22 @@ export default {
}
this.clickedOnEmpty = false;
if (this.draggingRotateHandle) {
this.$emit('platform-icon-updated', this.draggingRotateHandle);
this.viewer.scene.screenSpaceCameraController.enableInputs = this.platformIconDragCameraEnabled;
this.draggingRotateHandle = null;
}
if (this.draggingScaleHandle) {
this.$emit('platform-icon-updated', this.draggingScaleHandle.entityData);
this.viewer.scene.screenSpaceCameraController.enableInputs = this.platformIconDragCameraEnabled;
this.draggingScaleHandle = null;
}
if (this.draggingPlatformIcon) {
this.$emit('platform-icon-updated', this.draggingPlatformIcon);
this.viewer.scene.screenSpaceCameraController.enableInputs = this.platformIconDragCameraEnabled;
this.draggingPlatformIcon = null;
}
if (this.rotatingPlatformIcon) {
this.$emit('platform-icon-updated', this.rotatingPlatformIcon);
this.viewer.scene.screenSpaceCameraController.enableInputs = this.platformIconDragCameraEnabled;
this.rotatingPlatformIcon = null;
this.platformIconRotateTip = '';
@ -3877,8 +3959,9 @@ export default {
)
if (index > -1) {
const entity = this.allEntities[index]
//
//
if (entity.type === 'platformIcon') {
if (entity.serverId) this.$emit('platform-icon-removed', { serverId: entity.serverId })
this.removeTransformHandles(entity)
if (this.selectedPlatformIcon === entity) this.selectedPlatformIcon = null
}

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

@ -16,7 +16,9 @@
@drawing-points-update="missionDrawingPointsCount = $event"
@open-waypoint-dialog="handleOpenWaypointEdit"
@open-route-dialog="handleOpenRouteEdit"
@scale-click="handleScaleClick" />
@scale-click="handleScaleClick"
@platform-icon-updated="onPlatformIconUpdated"
@platform-icon-removed="onPlatformIconRemoved" />
<div class="map-overlay-text">
<i class="el-icon-location-outline text-3xl mb-2 block"></i>
<p>二维GIS地图区域</p>
@ -390,6 +392,7 @@ import { updateWaypoints, addWaypoints, delWaypoints } from "@/api/system/waypoi
import { listLib,addLib,delLib} from "@/api/system/lib";
import { getRooms, updateRooms } from "@/api/system/rooms";
import { getMenuConfig, saveMenuConfig } from "@/api/system/userMenuConfig";
import { listByRoomId as listRoomPlatformIcons, addRoomPlatformIcon, updateRoomPlatformIcon, delRoomPlatformIcon } from "@/api/system/roomPlatformIcon";
import PlatformImportDialog from "@/views/dialogs/PlatformImportDialog.vue";
export default {
name: 'MissionPlanningView',
@ -443,6 +446,7 @@ export default {
showNameDialog: false,
newRouteName: '',
tempMapPoints: [],
platformIconSaveTimer: null,
//
showImportDialog: false,
@ -1013,6 +1017,13 @@ export default {
});
});
}
//
const rId = roomId || this.currentRoomId;
if (rId && this.$refs.cesiumMap && typeof this.$refs.cesiumMap.loadRoomPlatformIcons === 'function') {
listRoomPlatformIcons(rId).then(res => {
if (res.code === 200 && res.data) this.$refs.cesiumMap.loadRoomPlatformIcons(rId, res.data);
}).catch(() => {});
}
}
} catch (error) {
console.error("数据加载失败:", error);
@ -1561,20 +1572,60 @@ export default {
if (ev.dataTransfer) ev.dataTransfer.dropEffect = 'copy'
},
/** 将平台图标放置到地图上 */
handleMapDrop(ev) {
/** 将平台图标放置到地图上,并保存到当前房间 */
async handleMapDrop(ev) {
ev.preventDefault()
const raw = ev.dataTransfer && ev.dataTransfer.getData('application/json')
if (!raw) return
try {
const platform = JSON.parse(raw)
if (this.$refs.cesiumMap && typeof this.$refs.cesiumMap.addPlatformIconFromDrag === 'function') {
this.$refs.cesiumMap.addPlatformIconFromDrag(platform, ev.clientX, ev.clientY)
const map = this.$refs.cesiumMap
if (!map || typeof map.addPlatformIconFromDrag !== 'function') return
const entityData = map.addPlatformIconFromDrag(platform, ev.clientX, ev.clientY)
if (!entityData || !this.currentRoomId) return
const payload = {
roomId: this.currentRoomId,
platformId: platform.id,
platformName: platform.name || '',
platformType: platform.type || '',
iconUrl: platform.imageUrl || platform.iconUrl || '',
lng: entityData.lng,
lat: entityData.lat,
heading: entityData.heading != null ? entityData.heading : 0,
iconScale: entityData.iconScale != null ? entityData.iconScale : 1
}
const res = await addRoomPlatformIcon(payload)
if (res.code === 200 && res.data && res.data.id) {
map.setPlatformIconServerId(entityData.id, res.data.id, this.currentRoomId)
entityData.serverId = res.data.id
entityData.roomId = this.currentRoomId
this.$message.success('平台图标已保存到当前房间')
}
} catch (e) {
console.warn('Parse platform drag data failed', e)
console.warn('Parse platform drag data or save failed', e)
this.$message && this.$message.error('保存平台图标失败')
}
},
/** 平台图标移动/旋转/缩放结束:防抖更新到服务端 */
onPlatformIconUpdated(entityData) {
if (!entityData || !entityData.serverId) return
if (this.platformIconSaveTimer) clearTimeout(this.platformIconSaveTimer)
this.platformIconSaveTimer = setTimeout(() => {
this.platformIconSaveTimer = null
updateRoomPlatformIcon({
id: entityData.serverId,
lng: entityData.lng,
lat: entityData.lat,
heading: entityData.heading != null ? entityData.heading : 0,
iconScale: entityData.iconScale != null ? entityData.iconScale : 1
}).then(() => {}).catch(() => {})
}, 500)
},
/** 平台图标从地图删除时同步删除服务端记录 */
onPlatformIconRemoved({ serverId }) {
if (!serverId) return
delRoomPlatformIcon(serverId).then(() => {}).catch(() => {})
},
handleScaleUnitChange(unit) {
this.scaleConfig.unit = unit

Loading…
Cancel
Save