You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
7.2 KiB
277 lines
7.2 KiB
<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} (${degreesToDMS(item.lng)}, ${degreesToDMS(item.lat)})`"
|
|
:value="item.id"
|
|
/>
|
|
</el-select>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="经度:">
|
|
<el-input
|
|
v-model="formData.lng"
|
|
placeholder="例如 116°23'48.64""
|
|
clearable
|
|
/>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="纬度:">
|
|
<el-input
|
|
v-model="formData.lat"
|
|
placeholder="例如 39°54'33.48""
|
|
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°23\'48.64"',
|
|
lat: '39°54\'33.48"'
|
|
},
|
|
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: {
|
|
degreesToDMS(decimalDegrees) {
|
|
const degrees = Math.floor(decimalDegrees)
|
|
const minutesDecimal = (decimalDegrees - degrees) * 60
|
|
const minutes = Math.floor(minutesDecimal)
|
|
const seconds = ((minutesDecimal - minutes) * 60).toFixed(2)
|
|
return `${degrees}°${minutes}'${seconds}"`
|
|
},
|
|
dmsToDegrees(dms) {
|
|
const match = dms.match(/^(-?\d+)°(\d+)'([\d.]+)"$/)
|
|
if (!match) return null
|
|
const degrees = parseFloat(match[1])
|
|
const minutes = parseFloat(match[2])
|
|
const seconds = parseFloat(match[3])
|
|
const sign = degrees < 0 ? -1 : 1
|
|
return sign * (Math.abs(degrees) + minutes / 60 + seconds / 3600)
|
|
},
|
|
resetForm() {
|
|
this.formData = {
|
|
scenarioId: null,
|
|
routeId: null,
|
|
waypointId: null,
|
|
lng: '116°23\'48.64"',
|
|
lat: '39°54\'33.48"'
|
|
}
|
|
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 = this.degreesToDMS(waypoint.lng)
|
|
this.formData.lat = this.degreesToDMS(waypoint.lat)
|
|
}
|
|
}
|
|
},
|
|
|
|
handleCancel() {
|
|
this.$emit('update:visible', false)
|
|
this.$emit('cancel')
|
|
},
|
|
|
|
handleConfirm() {
|
|
const { lng, lat } = this.formData
|
|
|
|
if (!lng || !lat) {
|
|
this.$message.error('请输入有效的经度和纬度!')
|
|
return
|
|
}
|
|
|
|
const lngDegrees = this.dmsToDegrees(lng)
|
|
const latDegrees = this.dmsToDegrees(lat)
|
|
|
|
if (lngDegrees === null || latDegrees === null || isNaN(lngDegrees) || isNaN(latDegrees)) {
|
|
this.$message.error('请输入有效的度分秒格式!格式:116°23\'48.64"')
|
|
return
|
|
}
|
|
|
|
if (lngDegrees < -180 || lngDegrees > 180 || latDegrees < -90 || latDegrees > 90) {
|
|
this.$message.error('经纬度超出有效范围!')
|
|
return
|
|
}
|
|
|
|
this.$emit('confirm', {
|
|
lng: lngDegrees,
|
|
lat: latDegrees
|
|
})
|
|
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>
|