更新巡检线路编辑功能,同步地图上点击设备的点位到巡检点位表

This commit is contained in:
g82tt
2025-10-18 08:21:58 +08:00
parent e1c2e6e4aa
commit 04e2a9ec43
17 changed files with 690 additions and 102 deletions

View File

@@ -1,5 +1,19 @@
# 仓库管理操作端项目更新记录
## 2024年4月18日 - 路径管理功能优化
### 路径管理模块
* 📝**[修改]**为路径点增加地图模型ID属性支持
* 📝**[修改]**在PathManager.vue中更新模拟数据为每个路径点添加modelId字段
* 📝**[修改]**在PathEditor.vue中增加modelId字段的显示和处理
* 📝**[修改]**实现设备选择时自动同步modelId的功能
* 📝**[修改]**优化PathEditor.vue中地图实例获取和应用方式
* 📝**[修改]**:重构地图初始化逻辑,将其与组件生命周期解耦
* 📝**[修改]**实现基于Intersection Observer的组件可见性监测
* 📝**[修改]**确保地图只在组件实际显示时才初始化避免DOM未渲染问题
* 📝**[修改]**为dialog组件添加ID标识便于可见性监测
* 📝**[修改]**:添加降级方案,确保即使在特殊情况下也能初始化地图
## 2024年4月17日 - 巡检路径管理功能开发
### 巡检路径模块

View File

@@ -1,4 +1,27 @@
2024-6-7
## 2024年6月8日 - 路径管理功能增强
### 状态管理
- **[新增]**添加pathStore.js用于管理全局路径点信息
- 实现了pathPoints数组存储{modelId, deviceName}结构的数据
- 提供syncPathPoints方法同步路径点数据
- 提供clearPathPoints方法清空路径点
- 提供getPathPoints方法获取路径点列表
### 路径编辑功能
- 📝**[修改]**更新useEditNavi.js
- 导入pathStore实现全局数据同步
- 在pathIdList变化时自动同步到全局store
- 实现了从deviceList查找对应设备名称的功能
- 📝**[修改]**更新PathEditor.vue
- 导入pathStore并获取实例
- 添加对话框可见性监听器在打开时清空pathPoints数组
- 根据编辑/新增状态动态同步pathForm.points到pathStore
- 新增对pathStore.pathPoints数组的深度监听实现双向数据同步
- 添加变更检测机制,避免循环更新问题
- 实现全局状态到表单数据的智能转换和映射
## 2024-6-7
- 修复CarManager组件多个显示问题
- 移除了formRef和applyFormRef的冗余初始化定义

View File

@@ -1,6 +1,6 @@
<script setup>
import { inject, ref, watch, computed } from "vue"
import { useDisplayColor } from "../hooks/useDisplayColor"
import { useDisplayColor } from "@/hooks/useDisplayColor"
// 可以使用pinia等管理全局数据这里只是方便演示, 直接注入了上层提供的数据
const map = inject("map")

View File

@@ -1,6 +1,6 @@
<script setup>
import { inject } from "vue"
import { useNavi } from "../hooks/useNavi"
import { useNavi } from "@/hooks/useNavi"
// 可以使用pinia等管理全局数据这里只是方便演示, 直接注入了上层提供的数据
const map = inject("map")

View File

@@ -0,0 +1,61 @@
<script setup>
import { inject } from "vue"
import { useNavi } from "@/hooks/useEditNavi"
// 可以使用pinia等管理全局数据这里只是方便演示, 直接注入了上层提供的数据
const map = inject("editMap")
const {
pathIdList,
addPath,
startNavi,
pauseNavi,
restoreNavi,
stopNavi,
} = useNavi(map)
map.value.on('click', (e) => {
const polygon = e.object?.userData?.polygonData // 获取点位数据
if(!polygon?.isNavi) return
addPath(polygon)
})
defineExpose({
addPath,
})
</script>
<template>
<div class="navi">
<div class="path-list-status">
<div>点击具有分类的标签或模型生成线路:</div>
<div class="selected">{{ pathIdList.join(",") }}</div>
<button @click="() => pathIdList.pop()">删除末尾</button>
<button @click="() => pathIdList = []">清空</button>
<button @click="() => startNavi()" :disabled="pathIdList.length < 2">开始导航</button>
<button @click="() => pauseNavi()" :disabled="pathIdList.length < 2">暂停</button>
<button @click="() => restoreNavi()" :disabled="pathIdList.length < 2">继续</button>
<button @click="() => stopNavi()" :disabled="pathIdList.length < 2">结束导航</button>
</div>
</div>
</template>
<style scoped>
.path-list-status {
display: flex;
align-items: center;
gap: 5px;
}
.selected {
min-height: 1.5em;
width: 300px;
padding: 0 5px;
background-color: #fff;
border: 1px solid #767676;
display: flex;
align-items: center;
overflow: auto;
}
</style>

View File

@@ -0,0 +1,125 @@
<script setup>
import { inject, ref, watch, onBeforeUnmount } from "vue"
import { useClassPolygon } from "@/hooks/useClassPolygon"
import { useDeviceStore } from "@/stores/device" // 导入设备store
const { THREE } = VgoMap
// 获取设备store实例
const deviceStore = useDeviceStore()
// 可以使用pinia等管理全局数据这里只是方便演示, 直接注入了上层提供的数据
const editMap = inject("editMap")
const editPolygonDataAll = inject("editPolygonDataAll")
const editRouteLineRef = inject("editRouteLineRef")
console.log(editMap.value,'editorFilter.editMap.value')
// 仅取有分类的点位
const { classPoiList, classDict } = useClassPolygon(editPolygonDataAll)
console.log(classPoiList.value,'classPoiList.value')
console.log(classDict.value,'classDict.value')
const markerGroup = new THREE.Group()
editMap.value.scene.add(markerGroup)
onBeforeUnmount(() => {
markerGroup.dispose()
})
// 根据有分类点位创建marker
console.log(editMap.value,'editorFilter.editMap.value')
console.log(editMap.value.status.floor,'editMap.value.status.floor')
console.log(editMap.value.outerFloor,'editMap.value?.outerFloor')
const markerStatus = ref({});
(editMap.value.status?.floor ?? editMap.value?.outerFloor).on('floorModelAllLoaded', () => {
console.log('lkasdfjalksdjfklasjdf')
// 清理所有marker
while (markerGroup.children.length) {
markerGroup.children?.[0]?.dispose()
}
markerStatus.value = {}
// 创建新的marker
const listGroup = Object.entries(classPoiList.value)
listGroup.forEach(([key, list]) => {
list.forEach((item) => {
const model = editMap.value.getModelById(item.extrasModelId) // 获取点位关联的模型信息
const modelName = model.userData.modelData.name
const modelId=item.id
console.log(modelName, ' ', item.id)
// 将设备信息添加到全局store
//deviceStore.addDevice(modelId, modelName)
const marker = createDivMarker(modelName, item)
if (model) {
marker.position.copy(model.position)
} else {
marker.position.copy(item.center).setZ(10)
}
markerGroup.add(marker)
if (!markerStatus.value?.[key]) {
markerStatus.value[key] = []
}
markerStatus.value[key].push(marker)
})
})
})
// 根据选中状态控制marker显示
const checkedStatus = ref({})
watch(checkedStatus, (checked) => {
for (let key in checked) {
markerStatus.value?.[key]?.forEach((marker) => {
marker.visible = checked[key]
})
}
}, {
deep: true,
})
function createDivMarker(content, polygon) {
const wrapper = document.createElement("div")
const contentNode = document.createElement("div")
contentNode.className = "marker"
contentNode.textContent = content
contentNode.onclick = (e) => {
if(!polygon?.isNavi) return
editRouteLineRef.value.addPath(polygon)
}
wrapper.appendChild(contentNode)
const floorId = editMap.status?.floor?.data?.id || '1'
return editMap.value.addDomMarker(floorId, wrapper) // 之前记错了这边直接传dom元素也是可以的
}
</script>
<template>
<ul class="filter">
<li v-for="key in Object.keys(classPoiList)" :key="key">
<label :for="key">{{ classDict[key].name }}</label>
<input type="checkbox" :id="key" v-model="checkedStatus[key]">
</li>
</ul>
</template>
<style scoped>
.filter {
margin: 0;
li,
label,
input {
cursor: pointer;
}
}
</style>
<style>
.marker {
background-color: #fff;
padding: 2px 10px;
border-radius: 20px;
transform: scale(0.7);
}
</style>

View File

@@ -1,6 +1,6 @@
<script setup>
import { inject, onBeforeUnmount } from "vue"
import { useFence } from "../hooks/useFence"
import { useFence } from "@/hooks/useFence"
const { THREE } = VgoMap

View File

@@ -1,14 +1,18 @@
<script setup>
import { inject, ref, watch, onBeforeUnmount } from "vue"
import { useClassPolygon } from "../hooks/useClassPolygon"
import { useClassPolygon } from "@/hooks/useClassPolygon"
import { useDeviceStore } from "@/stores/device" // 导入设备store
const { THREE } = VgoMap
// 获取设备store实例
const deviceStore = useDeviceStore()
// 可以使用pinia等管理全局数据这里只是方便演示, 直接注入了上层提供的数据
const map = inject("map")
const polygonDataAll = inject("polygonDataAll")
const routeLineRef = inject("routeLineRef")
console.log(map.value,'Filter.map.value')
// 仅取有分类的点位
const { classPoiList, classDict } = useClassPolygon(polygonDataAll)
@@ -18,10 +22,13 @@ onBeforeUnmount(() => {
markerGroup.dispose()
})
console.log(map.value.status.floor,'editMap.value.status.floor')
console.log(map.value.outerFloor,'editMap.value?.outerFloor')
// 根据有分类点位创建marker
const markerStatus = ref({});
(map.value.status?.floor ?? map.value?.outerFloor).on('floorModelAllLoaded', () => {
console.log('lkasdfjalksdjfklasjdf')
// 清理所有marker
while (markerGroup.children.length) {
markerGroup.children?.[0]?.dispose()
@@ -32,8 +39,16 @@ const markerStatus = ref({});
const listGroup = Object.entries(classPoiList.value)
listGroup.forEach(([key, list]) => {
list.forEach((item) => {
const marker = createDivMarker(classDict[key].name, item)
const model = map.value.getModelById(item.extrasModelId) // 获取点位关联的模型信息
const modelName = model.userData.modelData.name
const modelId=item.id
console.log(modelName, ' ', item.id)
// 将设备信息添加到全局store
deviceStore.addDevice(modelId, modelName)
const marker = createDivMarker(modelName, item)
if (model) {
marker.position.copy(model.position)
} else {
@@ -54,7 +69,7 @@ const checkedStatus = ref({})
watch(checkedStatus, (checked) => {
for (let key in checked) {
markerStatus.value?.[key]?.forEach((marker) => {
marker.visible = !checked[key]
marker.visible = checked[key]
})
}
}, {

View File

@@ -1,6 +1,6 @@
<script setup>
import { inject, ref, watch, onBeforeUnmount } from "vue"
import { useSkyLight } from "../hooks/useSkyLight"
import { useSkyLight } from "@/hooks/useSkyLight"
const map = inject("map")
const { skyGroup, init, setTime } = useSkyLight(map.value)

96
src/hooks/useEditNavi.js Normal file
View File

@@ -0,0 +1,96 @@
import { ref, watch } from "vue"
import { usePathStore } from "@/stores/pathStore"
export function useNavi(map) {
const pathIdList = ref([])
function addPath(polygon) {
if(polygon?.id && pathIdList.value[pathIdList.value.length - 1] === polygon?.id) return // 不连续添加相同的项
const modelId = polygon.extrasModelId;
const model = map.value.getModelById(modelId)
const modelName = model.userData.modelData.name
console.log(modelName, 'model.name', polygon.id,'polygon.id')
addPathId(polygon.id)
}
function addPathId(id) {
if(id && pathIdList.value[pathIdList.value.length - 1] === id) return
pathIdList.value.push(id)
}
function startNavi() {
if(pathIdList.value.length < 2) return
map.value.navi.simulate()
map.value.navi.setSimulateSpeed(10)
}
function pauseNavi () {
// 判断当前是否处于导航中
if (map.value.navi.status.isSimulate) {
map.value.navi.pauseSimulate()
}
}
function restoreNavi () {
// 判断当前是否处于暂停中
if (!map.value.navi.isSimulatePause) {
map.value.navi.resumeSimulate()
}
}
function stopNavi () {
// 退出模拟导航
map.value.navi.stopSimulate()
removePathLine()
pathIdList.value = []
}
function removePathLine() {
// 销毁箭头
map.value.navi.removeNaviArrow()
// 销毁线路
map.value.navi.removeNaviLine()
//移除途径点
map.value.navi.removeAllWaypoint()
//移除起点
map.value.navi.removeStart()
//移除终点
map.value.navi.removeEnd()
}
watch(pathIdList, (pathIdList) => {
// 同步路径点到全局store
const pathStore = usePathStore()
pathStore.syncPathPoints(pathIdList)
if(pathIdList?.length < 2) {
removePathLine()
return
}
const end = pathIdList[pathIdList.length - 1]
const [start, ...passPoints]= pathIdList.slice(0, -1);
map.value.navi.removeAllWaypoint()
map.value.navi.setStart(start)
map.value.navi.setWaypoints(passPoints)
map.value.navi.setEnd(end)
map.value.navi.find()
}, {
deep: true,
})
return {
pathIdList,
addPath,
addPathId,
startNavi,
pauseNavi,
restoreNavi,
stopNavi,
}
}

View File

@@ -9,7 +9,7 @@ export function useNavi(map) {
const modelId = polygon.extrasModelId;
const model = map.value.getModelById(modelId)
const modelName = model.userData.modelData.name
console.log(modelName, 'model.name')
console.log(modelName, 'model.name', polygon.id,'polygon.id')
addPathId(polygon.id)
}

37
src/stores/device.js Normal file
View File

@@ -0,0 +1,37 @@
import { defineStore } from 'pinia'
// 定义全局设备数组的store
export const useDeviceStore = defineStore('device', {
state: () => ({
// 全局设备数组:包含{ modelId, modelName }结构的对象
deviceList: []
}),
actions: {
// 添加设备到全局数组
addDevice(modelId, modelName) {
// 检查是否已存在相同的modelId
const existingIndex = this.deviceList.findIndex(device => device.modelId === modelId)
if (existingIndex === -1 && modelId && modelName) {
this.deviceList.push({
modelId,
modelName
})
}
},
// 清空设备列表
clearDevices() {
this.deviceList = []
},
// 获取用于Select组件的选项格式
getSelectOptions() {
return this.deviceList.map(device => ({
value: device.modelId, // 设备id作为value
label: device.modelName // 设备名称作为label
}))
}
}
})

49
src/stores/pathStore.js Normal file
View File

@@ -0,0 +1,49 @@
import { defineStore } from 'pinia'
import { useDeviceStore } from './device'
// 定义路径点store
export const usePathStore = defineStore('path', {
state: () => ({
// 路径点数组:包含{ modelId, deviceName }结构的对象
pathPoints: []
}),
actions: {
// 同步路径点数据
syncPathPoints(pathIdList) {
const deviceStore = useDeviceStore()
// 清空当前路径点数组
this.pathPoints = []
// 根据pathIdList中的id顺序查找对应的设备信息并同步
pathIdList.forEach(modelId => {
// 从deviceList中查找对应的设备信息
const device = deviceStore.deviceList.find(d => d.modelId === modelId)
if (device) {
this.pathPoints.push({
modelId: modelId,
deviceName: device.modelName
})
} else {
// 如果没有找到对应的设备信息仍添加modelId但deviceName为空或默认值
this.pathPoints.push({
modelId: modelId,
deviceName: `未知设备(${modelId})`
})
}
})
},
// 清空路径点
clearPathPoints() {
this.pathPoints = []
},
// 获取路径点列表
getPathPoints() {
return this.pathPoints
}
}
})

87
src/views/EditMap.vue Normal file
View File

@@ -0,0 +1,87 @@
<script setup>
import { onMounted, ref, computed, provide, useTemplateRef } from "vue"
import Filter from "@/components/EditorFilter.vue"
import DisplayRouteLine from "@/components/EditDisplayRouteLine.vue"
// 在Map.vue中添加props定义
const props = defineProps({
elId: {
type: String,
default: 'mapContainer'
}
})
const { VgoMap } = window
let mapId = "1977947221534052352"
const isLoaded = ref(false)
const map = ref()
console.log(map.value)
const routeLineRef = useTemplateRef('routeLineRef')
provide("editMap", computed(() => map.value))
provide('editRouteLineRef', computed(() => routeLineRef.value))
provide('editPolygonDataAll', computed(() => {
const outDoor = map.value?.mapData?.polygonData ?? []
const inDoor = map?.mapData?.build?.reduce((result, build) => {
build.floor.forEach(fItem => {
result.push(...fItem.polygonData)
})
return result
}, []) ?? []
return [...outDoor, ...inDoor]
}))
onMounted(() => {
map.value = new VgoMap.Map({
el: props.elId, // 使用传入的elId,
id: mapId,
})
map.value.on("loaded", () => {
window.$editmap = map.value
isLoaded.value = true
})
})
</script>
<template>
<div class="wrapper">
<div :id="elId"></div>
<div v-if="isLoaded" class="ui">
<!-- <Fence/> -->
<DisplayRouteLine ref="routeLineRef"/>
<!-- <DisplayColor/> -->
<Filter/>
</div>
</div>
</template>
<style lang="css">
html,
body,
.app,
.wrapper {
width: 100vw;
height: 100vh;
overflow: hidden;
position: relative;
}
#mapContainer {
position: relative;
z-index: 1;
}
.ui {
position: absolute;
right: 50px;
bottom: 50px;
z-index: 2;
display: flex;
align-items: flex-end;
gap: 30px;
}
</style>

View File

@@ -6,6 +6,14 @@ import Sky from "../components/Sky.vue"
import DisplayColor from "../components/DisplayColor.vue"
import DisplayRouteLine from "../components/DisplayRouteLine.vue"
// 在Map.vue中添加props定义
const props = defineProps({
elId: {
type: String,
default: 'mapContainer'
}
})
const { VgoMap } = window
let mapId = "1977947221534052352"
const isLoaded = ref(false)
@@ -30,7 +38,7 @@ provide('polygonDataAll', computed(() => {
onMounted(() => {
map.value = new VgoMap.Map({
el: "mapContainer",
el: props.elId, // 使用传入的elId,
id: mapId,
})
@@ -43,7 +51,7 @@ onMounted(() => {
<template>
<div class="wrapper">
<div id="mapContainer"></div>
<div :id="elId"></div>
<div v-if="isLoaded" class="ui">
<!-- <Fence/> -->
<DisplayRouteLine ref="routeLineRef"/>

View File

@@ -1,6 +1,7 @@
<template>
<!-- 巡检路径编辑组件 -->
<el-dialog
id="path-editor-root"
v-model="dialogVisible"
:title="isEdit ? '编辑巡检路径' : '新增巡检路径'"
width="90%"
@@ -47,7 +48,7 @@
<div class="border border-blue-400 rounded-lg overflow-hidden relative">
<!-- 地图容器设置固定高度 -->
<div class="path-map-container">
<Map el-id="etsfs"/>
<EditMap el-id="etsfs"/>
</div>
<!-- 地图操作提示 -->
<div class="map-tip">
@@ -78,8 +79,9 @@
<template #default="scope">
<el-select
v-model="scope.row.deviceName"
placeholder="请选择设备"
placeholder="请输入设备名称"
style="width: 100%"
@change="(value) => handleDeviceSelect(value, scope.row)"
>
<el-option
v-for="device in deviceList"
@@ -90,6 +92,7 @@
</el-select>
</template>
</el-table-column>
<el-table-column prop="modelId" label="地图模型ID" min-width="150" align="center" />
<el-table-column label="操作" width="120" align="center">
<template #default="scope">
<div class="flex gap-2 justify-center">
@@ -129,13 +132,17 @@
</template>
<script lang="ts" setup>
/**
/**
* 巡检路径编辑组件
* 用于新增和编辑巡检路径信息,包含地图展示和路径点配置
*/
import { ref, reactive, watch, computed, onMounted } from 'vue'
// 导入inject用于从Map组件获取map实例
import { ref, reactive, computed, onMounted, watch, inject } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import Map from '../Map.vue' // 导入地图组件
import EditMap from '../EditMap.vue' // 导入地图组件
import { useDeviceStore } from '@/stores/device' // 导入设备store
import { usePathStore } from '@/stores/pathStore' // 导入路径store
import { useNavi } from '@/hooks/useNavi' // 导入导航hook
// Props定义
const props = defineProps({
@@ -180,26 +187,15 @@ const formRules = reactive({
]
})
// 模拟设备列表
const deviceList = ref([
{ value: '入口门禁', label: '入口门禁' },
{ value: '出口门禁', label: '出口门禁' },
{ value: '1号仓库温度传感器', label: '1号仓库温度传感器' },
{ value: '1号仓库湿度传感器', label: '1号仓库湿度传感器' },
{ value: '2号仓库温度传感器', label: '2号仓库温度传感器' },
{ value: '2号仓库湿度传感器', label: '2号仓库湿度传感器' },
{ value: '消防设施检查点', label: '消防设施检查点' },
{ value: 'UPS电源', label: 'UPS电源' },
{ value: '服务器机架1', label: '服务器机架1' },
{ value: '服务器机架2', label: '服务器机架2' },
{ value: '空调系统', label: '空调系统' },
{ value: '网络设备柜', label: '网络设备柜' },
{ value: '机房环境监控', label: '机房环境监控' },
{ value: '西区大门', label: '西区大门' },
{ value: '安全监控室', label: '安全监控室' },
{ value: '应急出口', label: '应急出口' },
{ value: '出口监控摄像头', label: '出口监控摄像头' }
])
// 获取设备store实例
const deviceStore = useDeviceStore()
// 获取路径store实例
const pathStore = usePathStore()
// 使用computed从store获取设备列表选项
const deviceList = computed(() => {
return deviceStore.getSelectOptions()
})
// 计算属性
const isEdit = computed(() => !!props.pathData)
@@ -218,6 +214,51 @@ const resetForm = () => {
}
}
// 监听对话框可见性变化
watch(() => props.visible, (isVisible) => {
if (isVisible) {
// 对话框打开时清空pathStore中的pathPoints数组
pathStore.clearPathPoints()
// 判断是否为编辑状态
if (isEdit.value && pathForm.points.length > 0) {
// 编辑状态将pathForm.points同步到pathStore的pathPoints数组
const pathPointsData = pathForm.points.map(point => ({
modelId: point.modelId,
deviceName: point.deviceName
}))
// 直接设置pathStore的pathPoints数组
pathStore.pathPoints = pathPointsData
}
// 新增状态保持pathStore中的pathPoints数组为空已通过clearPathPoints实现
}
}, { immediate: true })
// 监听pathStore中pathPoints数组的变更实现从全局到局部的同步
watch(() => pathStore.pathPoints, (newPathPoints) => {
if (newPathPoints && newPathPoints.length > 0) {
// 确保不重复同步(避免循环更新)
const currentModelIds = pathForm.points.map(p => p.modelId)
const newModelIds = newPathPoints.map(p => p.modelId)
// 检查是否有变化需要同步
const hasChanges = currentModelIds.length !== newModelIds.length ||
!currentModelIds.every((id, index) => id === newModelIds[index])
if (hasChanges) {
// 将全局pathPoints同步到表单的pathPoints中
const synchronizedPoints = newPathPoints.map((point, index) => ({
id: `${Date.now()}-${index}`, // 生成新的唯一ID
index: index + 1, // 序号从1开始
modelId: point.modelId,
deviceName: point.deviceName
}))
pathForm.points = synchronizedPoints
}
}
}, { deep: true })
// 监听props变化
watch(() => props.pathData, (newVal) => {
if (newVal) {
@@ -226,6 +267,15 @@ watch(() => props.pathData, (newVal) => {
pathForm.name = newVal.name || ''
pathForm.description = newVal.description || ''
pathForm.points = newVal.points ? JSON.parse(JSON.stringify(newVal.points)) : []
// 如果对话框已经可见且是编辑状态同步到pathStore
if (props.visible) {
const pathPointsData = pathForm.points.map(point => ({
modelId: point.modelId,
deviceName: point.deviceName
}))
pathStore.pathPoints = pathPointsData
}
} else {
// 新增模式:重置表单
resetForm()
@@ -247,7 +297,8 @@ const handleAddPathPoint = () => {
pathForm.points.push({
id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
index: newIndex,
deviceName: ''
deviceName: '',
modelId: ''
})
// 更新序号
@@ -305,6 +356,17 @@ const handleMoveDown = (row, index) => {
}
}
/**
* 处理设备选择变化
*/
const handleDeviceSelect = (value, row) => {
// 查找对应的modelId
const selectedDevice = deviceList.value.find(device => device.value === value)
if (selectedDevice) {
row.modelId = selectedDevice.value // 设备的value已经是modelId
}
}
/**
* 更新路径点序号
*/
@@ -377,6 +439,25 @@ const handleSave = async () => {
// 模拟API调用延迟
await new Promise(resolve => setTimeout(resolve, 500))
// 将路径点信息添加到导航系统
console.log(map.value)
console.log(pathForm.points)
if (map.value && pathForm.points.length > 0) {
// 先清空现有路径
//stopNavi()
// 按顺序添加所有路径点的modelId到导航系统
pathForm.points.forEach(point => {
if (point.modelId) {
addPathId(point.modelId)
}
})
// 如果路径点数量足够,可以自动启动导航
if (pathForm.points.length >= 2) {
// 这里可以根据需要决定是否自动启动导航
// startNavi()
}
}
// 触发保存事件
emit('save', saveData)

View File

@@ -151,48 +151,40 @@ const generateMockPaths = () => {
return [
{
id: '1',
name: '东区仓库巡检路径',
description: '覆盖区所有仓库区域的标准巡检路径',
pointCount: 5,
name: '新库区巡检路径',
description: '覆盖新库区所有仓库区域的标准巡检路径',
pointCount: 12,
points: [
{ id: '1-1', index: 1, deviceName: '入口门禁' },
{ id: '1-2', index: 2, deviceName: '1号仓库温度传感器' },
{ id: '1-3', index: 3, deviceName: '消防设施检查点' },
{ id: '1-4', index: 4, deviceName: '2号仓库湿度传感器' },
{ id: '1-5', index: 5, deviceName: '出口监控摄像头' }
{ id: '1-1', index: 1, deviceName: '摄像头1', modelId: 'mgt1aol3kro' },
{ id: '1-2', index: 2, deviceName: '摄像头2', modelId: 'mgt1gz9s54s' },
{ id: '1-3', index: 3, deviceName: '摄像头3', modelId: 'mgt1ho9dzhn' },
{ id: '1-4', index: 4, deviceName: '摄像头4', modelId: 'mgt1n0wylmd' },
{ id: '1-5', index: 5, deviceName: '摄像头5', modelId: 'mgt1nboirj' },
{ id: '1-6', index: 6, deviceName: '摄像头6', modelId: 'mguoz4gy4x' },
{ id: '1-7', index: 7, deviceName: '摄像头7', modelId: 'mgt2cbv7k2d' },
{ id: '1-8', index: 8, deviceName: '摄像头8', modelId: 'mgt1njgpgpt' },
{ id: '1-9', index: 9, deviceName: '摄像头9', modelId: 'mgt1nuwisti' },
{ id: '1-10', index: 10, deviceName: '摄像头10', modelId: 'mgt1o6aqek' },
{ id: '1-11', index: 11, deviceName: '摄像头11', modelId: 'mgulf1e5mi' },
{ id: '1-12', index: 12, deviceName: '摄像头14', modelId: 'mgt1oylmwuf' }
],
createTime: '2024-04-01 10:30:00',
updateTime: '2024-04-10 14:20:00'
},
{
id: '2',
name: '西区安全巡检路线',
description: '西区安全检查专用路线',
pointCount: 3,
name: '新库区入口巡检路',
description: '新库区入口安全检查专用路线',
pointCount: 5,
points: [
{ id: '2-1', index: 1, deviceName: '西区大门' },
{ id: '2-2', index: 2, deviceName: '安全监控室' },
{ id: '2-3', index: 3, deviceName: '应急出口' }
{ id: '2-1', index: 1, deviceName: '摄像头18', modelId: 'mgt24lo3m4e' },
{ id: '2-2', index: 2, deviceName: '摄像头17', modelId: 'mgt24kocdw' },
{ id: '2-3', index: 3, deviceName: '摄像头16', modelId: 'mgt24gkj4on' },
{ id: '2-4', index: 4, deviceName: '摄像头12', modelId: 'mgt1oi96hsf' },
{ id: '2-5', index: 5, deviceName: '摄像头13', modelId: 'mgt1op9e61d' }
],
createTime: '2024-04-05 09:15:00',
updateTime: '2024-04-05 09:15:00'
},
{
id: '3',
name: '设备机房巡检路线',
description: '针对设备机房的详细巡检路线,包括所有关键设备',
pointCount: 7,
points: [
{ id: '3-1', index: 1, deviceName: 'UPS电源' },
{ id: '3-2', index: 2, deviceName: '服务器机架1' },
{ id: '3-3', index: 3, deviceName: '服务器机架2' },
{ id: '3-4', index: 4, deviceName: '空调系统' },
{ id: '3-5', index: 5, deviceName: '消防系统' },
{ id: '3-6', index: 6, deviceName: '网络设备柜' },
{ id: '3-7', index: 7, deviceName: '机房环境监控' }
],
createTime: '2024-04-08 16:45:00',
updateTime: '2024-04-12 11:30:00'
}
]
}