feat:iot-map

This commit is contained in:
alwayssuper
2025-07-04 17:54:05 +08:00
parent 10ca38c609
commit 7115a84a76
3 changed files with 104 additions and 27 deletions

View File

@@ -26,6 +26,12 @@ export enum DeviceTypeEnum {
GATEWAY_SUB = 1, // 网关子设备
GATEWAY = 2 // 网关设备
}
// IOT 产品定位类型枚举类 0: 手动定位, 1: IP 定位, 2: 定位模块定位
export enum LocationTypeEnum {
MANUAL = 0, // 手动定位
IP = 1, // IP 定位
MODULE = 2 // 定位模块定位
}
// IOT 数据格式(编解码器类型)枚举类
export enum CodecTypeEnum {
ALINK = 'Alink' // 阿里云 Alink 协议

View File

@@ -1,7 +1,7 @@
<template>
<div v-if="props.isWrite">
<el-form ref="form" label-width="120px">
<el-form-item label="设备位置:">
<el-form-item label="定位位置:">
<el-select
style="width: 100%"
v-model="state.address"
@@ -9,7 +9,7 @@
filterable
remote
reserve-keyword
placeholder="输入地址"
placeholder="输入地址查询经纬度"
:remote-method="autoSearch"
@change="regeoCode"
:loading="state.loading"
@@ -176,6 +176,10 @@ const getAddress = (lnglat) => {
}
})
}
// 显式暴露方法,使其可以被父组件访问
defineExpose({
regeoCode
})
onMounted(() => {
loadMap()

View File

@@ -77,30 +77,33 @@
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="设备经度" prop="longitude" type="number">
<el-input v-model="formData.longitude" placeholder="请输入设备经度">
<template #append>
<el-link
:underline="false"
href="https://api.map.baidu.com/lbsapi/getpoint/index.html"
target="_blank"
>坐标拾取</el-link
>
</template>
</el-input>
</el-form-item>
<el-form-item label="设备维度" prop="latitude" type="number">
<el-input v-model="formData.latitude" placeholder="请输入设备维度">
<template #append>
<el-link
:underline="false"
href="https://api.map.baidu.com/lbsapi/getpoint/index.html"
target="_blank"
>坐标拾取</el-link
>
</template>
</el-input>
</el-form-item>
<!-- 只在定位类型为GPS时显示坐标和地图 -->
<template v-if="showCoordinates">
<el-form-item label="设备经度" prop="longitude" type="number">
<el-input
v-model="formData.longitude"
placeholder="请输入设备经度"
@blur="updateLocationFromCoordinates"
/>
</el-form-item>
<el-form-item label="设备维度" prop="latitude" type="number">
<el-input
v-model="formData.latitude"
placeholder="请输入设备维度"
@blur="updateLocationFromCoordinates"
/>
</el-form-item>
<div class="pl-0 w-full ml-[-18px]" v-if="showMap">
<Map
:isWrite="true"
:clickMap="true"
:center="formData.location"
@locateChange="handleLocationChange"
ref="mapRef"
class="h-[400px] w-full"
/>
</div>
</template>
</el-collapse-item>
</el-collapse>
</el-form>
@@ -113,9 +116,11 @@
<script setup lang="ts">
import { DeviceApi, DeviceVO } from '@/api/iot/device/device'
import { DeviceGroupApi } from '@/api/iot/device/group'
import { DeviceTypeEnum, ProductApi, ProductVO } from '@/api/iot/product/product'
import { DeviceTypeEnum, LocationTypeEnum, ProductApi, ProductVO } from '@/api/iot/product/product'
import { UploadImg } from '@/components/UploadFile'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import Map from '@/components/Map/index.vue'
import { ref } from 'vue'
/** IoT 设备表单 */
defineOptions({ name: 'IoTDeviceForm' })
@@ -127,6 +132,17 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formType = ref('') // 表单的类型create - 新增update - 修改
const showMap = ref(false) // 是否显示地图组件
const mapRef = ref(null)
// 是否显示坐标信息(经度、纬度、地图)
const showCoordinates = computed(() => {
return (
formData.value.locationType !== LocationTypeEnum.IP &&
formData.value.locationType !== LocationTypeEnum.MODULE
)
})
const formData = ref({
id: undefined,
productId: undefined,
@@ -139,8 +155,19 @@ const formData = ref({
locationType: undefined as number | undefined,
longitude: undefined,
latitude: undefined,
location: '', // 格式: "经度,纬度"
groupIds: [] as number[]
})
// 监听经纬度变化更新location
watch([() => formData.value.longitude, () => formData.value.latitude], ([newLong, newLat]) => {
if (newLong && newLat) {
formData.value.location = `${newLong},${newLat}`
// 有了经纬度数据后显示地图
showMap.value = true
}
})
const formRules = reactive({
productId: [{ required: true, message: '产品不能为空', trigger: 'blur' }],
deviceName: [
@@ -191,15 +218,25 @@ const open = async (type: string, id?: number) => {
formType.value = type
resetForm()
// 默认不显示地图,等待数据加载
showMap.value = false
// 修改时,设置数据
if (id) {
formLoading.value = true
try {
formData.value = await DeviceApi.getDevice(id)
// 如果有经纬度设置location字段用于地图显示
if (formData.value.longitude && formData.value.latitude) {
formData.value.location = `${formData.value.longitude},${formData.value.latitude}`
}
} finally {
formLoading.value = false
}
}
// 如果有经纬信息,则数据加载完成后,显示地图
showMap.value = true
// 加载网关设备列表
try {
@@ -228,6 +265,16 @@ const submitForm = async () => {
formLoading.value = true
try {
const data = formData.value as unknown as DeviceVO
// 如果定位类型是IP或MODULE清空经纬度信息
if (
data.locationType === LocationTypeEnum.IP ||
data.locationType === LocationTypeEnum.MODULE
) {
data.longitude = undefined
data.latitude = undefined
}
if (formType.value === 'create') {
await DeviceApi.createDevice(data)
message.success(t('common.createSuccess'))
@@ -257,9 +304,12 @@ const resetForm = () => {
locationType: undefined,
longitude: undefined,
latitude: undefined,
location: '',
groupIds: []
}
formRef.value?.resetFields()
// 重置表单时,隐藏地图
showMap.value = false
}
/** 产品选择变化 */
@@ -272,4 +322,21 @@ const handleProductChange = (productId: number) => {
formData.value.deviceType = product?.deviceType
formData.value.locationType = product?.locationType
}
/** 处理位置变化 */
const handleLocationChange = (lnglat) => {
formData.value.longitude = lnglat[0]
formData.value.latitude = lnglat[1]
}
/** 根据经纬度更新地图位置 */
const updateLocationFromCoordinates = () => {
// 验证经纬度是否有效
if (formData.value.longitude && formData.value.latitude) {
// 更新location字段地图组件会根据此字段更新
formData.value.location = `${formData.value.longitude},${formData.value.latitude}`
console.log('更新location字段:', formData.value.location)
mapRef.value.regeoCode(formData.value.location)
}
}
</script>