ctw 2 months ago
parent
commit
20d6fb0828
  1. 257
      ruoyi-ui/src/views/cesiumMap/LocateDialog.vue
  2. 126
      ruoyi-ui/src/views/cesiumMap/index.vue

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

@ -0,0 +1,257 @@
<template>
<div>
<el-dialog
:title="title"
:visible.sync="dialogVisible"
width="500px"
:append-to-body="true"
:modal-append-to-body="true"
:close-on-click-modal="false"
:close-on-press-escape="true"
:destroy-on-close="true"
:before-close="handleCancel"
custom-class="locate-dialog"
:style="{ marginTop: '15vh' }"
>
<el-form ref="form" :model="formData" label-width="80px">
<el-form-item label="方案:">
<el-select
v-model="formData.scenarioId"
placeholder="请选择方案"
clearable
style="width: 100%"
@change="handleScenarioChange"
>
<el-option
v-for="item in scenarioList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="航线:">
<el-select
v-model="formData.routeId"
placeholder="请选择航线"
clearable
style="width: 100%"
:disabled="!formData.scenarioId"
@change="handleRouteChange"
>
<el-option
v-for="item in routeList"
:key="item.id"
:label="item.callSign"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="航点:">
<el-select
v-model="formData.waypointId"
placeholder="请选择航点"
clearable
style="width: 100%"
:disabled="!formData.routeId"
@change="handleWaypointChange"
>
<el-option
v-for="item in waypointList"
:key="item.id"
:label="`${item.name} (${item.lng}, ${item.lat})`"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="经度:">
<el-input
v-model="formData.lng"
type="number"
placeholder="例如 116.40"
step="0.000001"
clearable
/>
</el-form-item>
<el-form-item label="纬度:">
<el-input
v-model="formData.lat"
type="number"
placeholder="例如 39.90"
step="0.000001"
clearable
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listScenario } from '@/api/system/scenario'
import { listRoutes } from '@/api/system/routes'
import { listWaypoints } from '@/api/system/waypoints'
export default {
name: 'LocateDialog',
props: {
title: {
type: String,
default: '定位'
},
visible: {
type: Boolean,
default: false
}
},
data() {
return {
dialogVisible: false,
formData: {
scenarioId: null,
routeId: null,
waypointId: null,
lng: '116.3974',
lat: '39.9093'
},
scenarioList: [],
routeList: [],
waypointList: []
}
},
watch: {
visible: {
handler(newVal) {
this.dialogVisible = newVal
},
immediate: true
},
dialogVisible(newVal) {
if (newVal) {
this.resetForm()
this.loadScenarios()
}
this.$emit('update:visible', newVal)
}
},
methods: {
resetForm() {
this.formData = {
scenarioId: null,
routeId: null,
waypointId: null,
lng: '116.3974',
lat: '39.9093'
}
this.routeList = []
this.waypointList = []
},
async loadScenarios() {
try {
const res = await listScenario({})
this.scenarioList = res.rows || []
} catch (error) {
console.error('加载方案列表失败:', error)
this.$message.error('加载方案列表失败')
}
},
async handleScenarioChange(value) {
this.formData.routeId = null
this.formData.waypointId = null
this.routeList = []
this.waypointList = []
if (value) {
try {
const res = await listRoutes({ scenarioId: value })
this.routeList = res.rows || []
} catch (error) {
console.error('加载航线列表失败:', error)
this.$message.error('加载航线列表失败')
}
}
},
async handleRouteChange(value) {
this.formData.waypointId = null
this.waypointList = []
if (value) {
try {
const res = await listWaypoints({ routeId: value })
this.waypointList = res.rows || []
} catch (error) {
console.error('加载航点列表失败:', error)
this.$message.error('加载航点列表失败')
}
}
},
handleWaypointChange(value) {
if (value) {
const waypoint = this.waypointList.find(w => w.id === value)
if (waypoint) {
this.formData.lng = waypoint.lng
this.formData.lat = waypoint.lat
}
}
},
handleCancel() {
this.$emit('update:visible', false)
this.$emit('cancel')
},
handleConfirm() {
const { lng, lat } = this.formData
if (!lng || !lat || isNaN(parseFloat(lng)) || isNaN(parseFloat(lat))) {
this.$message.error('请输入有效的经度和纬度!')
return
}
if (lng < -180 || lng > 180 || lat < -90 || lat > 90) {
this.$message.error('经纬度超出有效范围!')
return
}
this.$emit('confirm', {
lng: parseFloat(lng),
lat: parseFloat(lat)
})
this.$emit('update:visible', false)
}
}
}
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
.locate-dialog {
z-index: 99999 !important;
}
.locate-dialog >>> .el-dialog {
margin-top: 15vh !important;
position: fixed !important;
top: 15vh !important;
}
.locate-dialog >>> .el-dialog__body {
padding: 20px;
}
</style>

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

@ -35,6 +35,15 @@
@delete="deleteEntityFromContextMenu"
@update-property="updateEntityProperty"
/>
<!-- 定位弹窗 -->
<locate-dialog
:visible="locateDialogVisible"
@update:visible="locateDialogVisible = $event"
@confirm="handleLocateConfirm"
@cancel="handleLocateCancel"
/>
<!-- 地图右下角比例尺 + 经纬度 -->
<div class="map-info-panel">
<div class="scale-bar">
@ -57,6 +66,7 @@ import DrawingToolbar from './DrawingToolbar.vue'
import MeasurementPanel from './MeasurementPanel.vue'
import HoverTooltip from './HoverTooltip.vue'
import ContextMenu from './ContextMenu.vue'
import LocateDialog from './LocateDialog.vue'
import axios from 'axios'
import request from '@/utils/request'
import { getToken } from '@/utils/auth'
@ -138,14 +148,17 @@ export default {
coordinatesText: '经度: --, 纬度: --',
//
scaleBarText: '--',
scaleBarWidthPx: 80
scaleBarWidthPx: 80,
//
locateDialogVisible: false
}
},
components: {
DrawingToolbar,
MeasurementPanel,
HoverTooltip,
ContextMenu
ContextMenu,
LocateDialog
},
mounted() {
console.log(this.drawDomClick,999999)
@ -2770,75 +2783,48 @@ export default {
}
},
handleLocate() {
const h = this.$createElement
this.$msgbox({
title: '定位',
message: h('div', {style: 'padding: 10px 0;'}, [
h('div', {style: 'margin-bottom: 15px;'}, [
h('label', {style: 'display: block; margin-bottom: 5px; color: #606266;'}, '经度:'),
h('input', {
attrs: {
type: 'number',
placeholder: '例如 116.40',
step: '0.000001',
value: '116.3974'
},
style: 'width: 100%; padding: 8px; border: 1px solid #dcdfe6; border-radius: 4px; box-sizing: border-box;',
ref: 'lngInput'
})
]),
h('div', null, [
h('label', {style: 'display: block; margin-bottom: 5px; color: #606266;'}, '纬度:'),
h('input', {
attrs: {
type: 'number',
placeholder: '例如 39.90',
step: '0.000001',
value: '39.9093'
},
style: 'width: 100%; padding: 8px; border: 1px solid #dcdfe6; border-radius: 4px; box-sizing: border-box;',
ref: 'latInput'
})
])
]),
showCancelButton: true,
confirmButtonText: '确定',
cancelButtonText: '取消',
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
const lngInput = instance.$el.querySelector('input[placeholder="例如 116.40"]')
const latInput = instance.$el.querySelector('input[placeholder="例如 39.90"]')
const lng = parseFloat(lngInput.value)
const lat = parseFloat(latInput.value)
if (!lng || !lat || isNaN(lng) || isNaN(lat)) {
this.$message.error('请输入有效的经度和纬度!')
return
}
if (lng < -180 || lng > 180 || lat < -90 || lat > 90) {
this.$message.error('经纬度超出有效范围!')
return
}
if (this.viewer) {
this.viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(lng, lat, 5000),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: 0.0
},
duration: 2
})
this.$message.success(`已定位到经度 ${lng.toFixed(4)},纬度 ${lat.toFixed(4)}`)
}
done()
} else {
this.$message.info('已取消定位')
done()
}
}
}).catch(() => {
this.$message.info('已取消定位')
this.locateDialogVisible = true
},
handleLocateConfirm(location) {
const { lng, lat } = location
if (this.viewer) {
this.viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(lng, lat, 100000),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: 0.0
},
duration: 2
})
this.$message.success(`已定位到经度 ${lng.toFixed(4)},纬度 ${lat.toFixed(4)}`)
}
},
handleLocateCancel() {
this.$message.info('已取消定位')
},
updateSelectOptions(refName, dataList, labelField) {
const select = document.querySelector(`select[ref="${refName}"]`)
if (!select) return
const currentValue = select.value
select.innerHTML = ''
const defaultOption = document.createElement('option')
defaultOption.value = ''
defaultOption.textContent = refName === 'routeSelect' ? '请选择航线' : '请选择航点'
select.appendChild(defaultOption)
dataList.forEach(item => {
const option = document.createElement('option')
option.value = item.id
option.textContent = typeof labelField === 'function' ? labelField(item) : item[labelField]
select.appendChild(option)
})
select.value = currentValue
},
initScaleBar() {
const that = this

Loading…
Cancel
Save