更新巡检线路编辑功能,同步地图上点击设备的点位到巡检点位表
This commit is contained in:
14
UpdateLog.md
14
UpdateLog.md
@@ -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日 - 巡检路径管理功能开发
|
## 2024年4月17日 - 巡检路径管理功能开发
|
||||||
|
|
||||||
### 巡检路径模块
|
### 巡检路径模块
|
||||||
|
@@ -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组件多个显示问题
|
- 修复CarManager组件多个显示问题
|
||||||
- 移除了formRef和applyFormRef的冗余初始化定义
|
- 移除了formRef和applyFormRef的冗余初始化定义
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { inject, ref, watch, computed } from "vue"
|
import { inject, ref, watch, computed } from "vue"
|
||||||
import { useDisplayColor } from "../hooks/useDisplayColor"
|
import { useDisplayColor } from "@/hooks/useDisplayColor"
|
||||||
|
|
||||||
// 可以使用pinia等管理全局数据,这里只是方便演示, 直接注入了上层提供的数据
|
// 可以使用pinia等管理全局数据,这里只是方便演示, 直接注入了上层提供的数据
|
||||||
const map = inject("map")
|
const map = inject("map")
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { inject } from "vue"
|
import { inject } from "vue"
|
||||||
import { useNavi } from "../hooks/useNavi"
|
import { useNavi } from "@/hooks/useNavi"
|
||||||
|
|
||||||
// 可以使用pinia等管理全局数据,这里只是方便演示, 直接注入了上层提供的数据
|
// 可以使用pinia等管理全局数据,这里只是方便演示, 直接注入了上层提供的数据
|
||||||
const map = inject("map")
|
const map = inject("map")
|
||||||
|
61
src/components/EditDisplayRouteLine.vue
Normal file
61
src/components/EditDisplayRouteLine.vue
Normal 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>
|
125
src/components/EditorFilter.vue
Normal file
125
src/components/EditorFilter.vue
Normal 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>
|
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { inject, onBeforeUnmount } from "vue"
|
import { inject, onBeforeUnmount } from "vue"
|
||||||
import { useFence } from "../hooks/useFence"
|
import { useFence } from "@/hooks/useFence"
|
||||||
|
|
||||||
const { THREE } = VgoMap
|
const { THREE } = VgoMap
|
||||||
|
|
||||||
|
@@ -1,14 +1,18 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { inject, ref, watch, onBeforeUnmount } from "vue"
|
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
|
const { THREE } = VgoMap
|
||||||
|
|
||||||
|
// 获取设备store实例
|
||||||
|
const deviceStore = useDeviceStore()
|
||||||
|
|
||||||
// 可以使用pinia等管理全局数据,这里只是方便演示, 直接注入了上层提供的数据
|
// 可以使用pinia等管理全局数据,这里只是方便演示, 直接注入了上层提供的数据
|
||||||
const map = inject("map")
|
const map = inject("map")
|
||||||
const polygonDataAll = inject("polygonDataAll")
|
const polygonDataAll = inject("polygonDataAll")
|
||||||
const routeLineRef = inject("routeLineRef")
|
const routeLineRef = inject("routeLineRef")
|
||||||
|
console.log(map.value,'Filter.map.value')
|
||||||
// 仅取有分类的点位
|
// 仅取有分类的点位
|
||||||
const { classPoiList, classDict } = useClassPolygon(polygonDataAll)
|
const { classPoiList, classDict } = useClassPolygon(polygonDataAll)
|
||||||
|
|
||||||
@@ -18,10 +22,13 @@ onBeforeUnmount(() => {
|
|||||||
markerGroup.dispose()
|
markerGroup.dispose()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log(map.value.status.floor,'editMap.value.status.floor')
|
||||||
|
console.log(map.value.outerFloor,'editMap.value?.outerFloor')
|
||||||
// 根据有分类点位,创建marker
|
// 根据有分类点位,创建marker
|
||||||
const markerStatus = ref({});
|
const markerStatus = ref({});
|
||||||
|
|
||||||
(map.value.status?.floor ?? map.value?.outerFloor).on('floorModelAllLoaded', () => {
|
(map.value.status?.floor ?? map.value?.outerFloor).on('floorModelAllLoaded', () => {
|
||||||
|
console.log('lkasdfjalksdjfklasjdf')
|
||||||
// 清理所有marker
|
// 清理所有marker
|
||||||
while (markerGroup.children.length) {
|
while (markerGroup.children.length) {
|
||||||
markerGroup.children?.[0]?.dispose()
|
markerGroup.children?.[0]?.dispose()
|
||||||
@@ -29,24 +36,32 @@ const markerStatus = ref({});
|
|||||||
markerStatus.value = {}
|
markerStatus.value = {}
|
||||||
|
|
||||||
// 创建新的marker
|
// 创建新的marker
|
||||||
const listGroup = Object.entries(classPoiList.value)
|
const listGroup = Object.entries(classPoiList.value)
|
||||||
listGroup.forEach(([key, list]) => {
|
listGroup.forEach(([key, list]) => {
|
||||||
list.forEach((item) => {
|
list.forEach((item) => {
|
||||||
const marker = createDivMarker(classDict[key].name, item)
|
const model = map.value.getModelById(item.extrasModelId) // 获取点位关联的模型信息
|
||||||
const model = map.value.getModelById(item.extrasModelId) // 获取点位关联的模型信息
|
const modelName = model.userData.modelData.name
|
||||||
if (model) {
|
const modelId=item.id
|
||||||
marker.position.copy(model.position)
|
console.log(modelName, ' ', item.id)
|
||||||
} else {
|
|
||||||
marker.position.copy(item.center).setZ(10)
|
// 将设备信息添加到全局store
|
||||||
}
|
deviceStore.addDevice(modelId, modelName)
|
||||||
markerGroup.add(marker)
|
|
||||||
|
const marker = createDivMarker(modelName, item)
|
||||||
|
|
||||||
if (!markerStatus.value?.[key]) {
|
if (model) {
|
||||||
markerStatus.value[key] = []
|
marker.position.copy(model.position)
|
||||||
}
|
} else {
|
||||||
markerStatus.value[key].push(marker)
|
marker.position.copy(item.center).setZ(10)
|
||||||
})
|
}
|
||||||
})
|
markerGroup.add(marker)
|
||||||
|
|
||||||
|
if (!markerStatus.value?.[key]) {
|
||||||
|
markerStatus.value[key] = []
|
||||||
|
}
|
||||||
|
markerStatus.value[key].push(marker)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// 根据选中状态,控制marker显示
|
// 根据选中状态,控制marker显示
|
||||||
@@ -54,7 +69,7 @@ const checkedStatus = ref({})
|
|||||||
watch(checkedStatus, (checked) => {
|
watch(checkedStatus, (checked) => {
|
||||||
for (let key in checked) {
|
for (let key in checked) {
|
||||||
markerStatus.value?.[key]?.forEach((marker) => {
|
markerStatus.value?.[key]?.forEach((marker) => {
|
||||||
marker.visible = !checked[key]
|
marker.visible = checked[key]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { inject, ref, watch, onBeforeUnmount } from "vue"
|
import { inject, ref, watch, onBeforeUnmount } from "vue"
|
||||||
import { useSkyLight } from "../hooks/useSkyLight"
|
import { useSkyLight } from "@/hooks/useSkyLight"
|
||||||
|
|
||||||
const map = inject("map")
|
const map = inject("map")
|
||||||
const { skyGroup, init, setTime } = useSkyLight(map.value)
|
const { skyGroup, init, setTime } = useSkyLight(map.value)
|
||||||
|
96
src/hooks/useEditNavi.js
Normal file
96
src/hooks/useEditNavi.js
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
@@ -9,7 +9,7 @@ export function useNavi(map) {
|
|||||||
const modelId = polygon.extrasModelId;
|
const modelId = polygon.extrasModelId;
|
||||||
const model = map.value.getModelById(modelId)
|
const model = map.value.getModelById(modelId)
|
||||||
const modelName = model.userData.modelData.name
|
const modelName = model.userData.modelData.name
|
||||||
console.log(modelName, 'model.name')
|
console.log(modelName, 'model.name', polygon.id,'polygon.id')
|
||||||
|
|
||||||
addPathId(polygon.id)
|
addPathId(polygon.id)
|
||||||
}
|
}
|
||||||
|
37
src/stores/device.js
Normal file
37
src/stores/device.js
Normal 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
49
src/stores/pathStore.js
Normal 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
87
src/views/EditMap.vue
Normal 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>
|
@@ -6,6 +6,14 @@ import Sky from "../components/Sky.vue"
|
|||||||
import DisplayColor from "../components/DisplayColor.vue"
|
import DisplayColor from "../components/DisplayColor.vue"
|
||||||
import DisplayRouteLine from "../components/DisplayRouteLine.vue"
|
import DisplayRouteLine from "../components/DisplayRouteLine.vue"
|
||||||
|
|
||||||
|
// 在Map.vue中添加props定义
|
||||||
|
const props = defineProps({
|
||||||
|
elId: {
|
||||||
|
type: String,
|
||||||
|
default: 'mapContainer'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const { VgoMap } = window
|
const { VgoMap } = window
|
||||||
let mapId = "1977947221534052352"
|
let mapId = "1977947221534052352"
|
||||||
const isLoaded = ref(false)
|
const isLoaded = ref(false)
|
||||||
@@ -30,7 +38,7 @@ provide('polygonDataAll', computed(() => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
map.value = new VgoMap.Map({
|
map.value = new VgoMap.Map({
|
||||||
el: "mapContainer",
|
el: props.elId, // 使用传入的elId,
|
||||||
id: mapId,
|
id: mapId,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -43,7 +51,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div id="mapContainer"></div>
|
<div :id="elId"></div>
|
||||||
<div v-if="isLoaded" class="ui">
|
<div v-if="isLoaded" class="ui">
|
||||||
<!-- <Fence/> -->
|
<!-- <Fence/> -->
|
||||||
<DisplayRouteLine ref="routeLineRef"/>
|
<DisplayRouteLine ref="routeLineRef"/>
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 巡检路径编辑组件 -->
|
<!-- 巡检路径编辑组件 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
|
id="path-editor-root"
|
||||||
v-model="dialogVisible"
|
v-model="dialogVisible"
|
||||||
:title="isEdit ? '编辑巡检路径' : '新增巡检路径'"
|
:title="isEdit ? '编辑巡检路径' : '新增巡检路径'"
|
||||||
width="90%"
|
width="90%"
|
||||||
@@ -47,7 +48,7 @@
|
|||||||
<div class="border border-blue-400 rounded-lg overflow-hidden relative">
|
<div class="border border-blue-400 rounded-lg overflow-hidden relative">
|
||||||
<!-- 地图容器,设置固定高度 -->
|
<!-- 地图容器,设置固定高度 -->
|
||||||
<div class="path-map-container">
|
<div class="path-map-container">
|
||||||
<Map el-id="etsfs"/>
|
<EditMap el-id="etsfs"/>
|
||||||
</div>
|
</div>
|
||||||
<!-- 地图操作提示 -->
|
<!-- 地图操作提示 -->
|
||||||
<div class="map-tip">
|
<div class="map-tip">
|
||||||
@@ -75,21 +76,23 @@
|
|||||||
>
|
>
|
||||||
<el-table-column prop="index" label="序号" width="80" align="center" sortable="custom" />
|
<el-table-column prop="index" label="序号" width="80" align="center" sortable="custom" />
|
||||||
<el-table-column prop="deviceName" label="路径点设备" min-width="200" align="center">
|
<el-table-column prop="deviceName" label="路径点设备" min-width="200" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="scope.row.deviceName"
|
v-model="scope.row.deviceName"
|
||||||
placeholder="请选择设备"
|
placeholder="请输入设备名称"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
>
|
@change="(value) => handleDeviceSelect(value, scope.row)"
|
||||||
<el-option
|
>
|
||||||
v-for="device in deviceList"
|
<el-option
|
||||||
:key="device.value"
|
v-for="device in deviceList"
|
||||||
:label="device.label"
|
:key="device.value"
|
||||||
:value="device.value"
|
:label="device.label"
|
||||||
/>
|
:value="device.value"
|
||||||
</el-select>
|
/>
|
||||||
</template>
|
</el-select>
|
||||||
</el-table-column>
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="modelId" label="地图模型ID" min-width="150" align="center" />
|
||||||
<el-table-column label="操作" width="120" align="center">
|
<el-table-column label="操作" width="120" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div class="flex gap-2 justify-center">
|
<div class="flex gap-2 justify-center">
|
||||||
@@ -129,13 +132,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<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 { 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定义
|
// Props定义
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -180,26 +187,15 @@ const formRules = reactive({
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
// 模拟设备列表
|
// 获取设备store实例
|
||||||
const deviceList = ref([
|
const deviceStore = useDeviceStore()
|
||||||
{ value: '入口门禁', label: '入口门禁' },
|
// 获取路径store实例
|
||||||
{ value: '出口门禁', label: '出口门禁' },
|
const pathStore = usePathStore()
|
||||||
{ value: '1号仓库温度传感器', label: '1号仓库温度传感器' },
|
|
||||||
{ value: '1号仓库湿度传感器', label: '1号仓库湿度传感器' },
|
// 使用computed从store获取设备列表选项
|
||||||
{ value: '2号仓库温度传感器', label: '2号仓库温度传感器' },
|
const deviceList = computed(() => {
|
||||||
{ value: '2号仓库湿度传感器', label: '2号仓库湿度传感器' },
|
return deviceStore.getSelectOptions()
|
||||||
{ 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: '出口监控摄像头' }
|
|
||||||
])
|
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
const isEdit = computed(() => !!props.pathData)
|
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变化
|
// 监听props变化
|
||||||
watch(() => props.pathData, (newVal) => {
|
watch(() => props.pathData, (newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
@@ -226,6 +267,15 @@ watch(() => props.pathData, (newVal) => {
|
|||||||
pathForm.name = newVal.name || ''
|
pathForm.name = newVal.name || ''
|
||||||
pathForm.description = newVal.description || ''
|
pathForm.description = newVal.description || ''
|
||||||
pathForm.points = newVal.points ? JSON.parse(JSON.stringify(newVal.points)) : []
|
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 {
|
} else {
|
||||||
// 新增模式:重置表单
|
// 新增模式:重置表单
|
||||||
resetForm()
|
resetForm()
|
||||||
@@ -247,7 +297,8 @@ const handleAddPathPoint = () => {
|
|||||||
pathForm.points.push({
|
pathForm.points.push({
|
||||||
id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
||||||
index: newIndex,
|
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调用延迟
|
// 模拟API调用延迟
|
||||||
await new Promise(resolve => setTimeout(resolve, 500))
|
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)
|
emit('save', saveData)
|
||||||
|
|
||||||
|
@@ -151,48 +151,40 @@ const generateMockPaths = () => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
name: '东区仓库巡检路径',
|
name: '新库区巡检路径',
|
||||||
description: '覆盖东区所有仓库区域的标准巡检路径',
|
description: '覆盖新库区所有仓库区域的标准巡检路径',
|
||||||
pointCount: 5,
|
pointCount: 12,
|
||||||
points: [
|
points: [
|
||||||
{ id: '1-1', index: 1, deviceName: '入口门禁' },
|
{ id: '1-1', index: 1, deviceName: '摄像头1', modelId: 'mgt1aol3kro' },
|
||||||
{ id: '1-2', index: 2, deviceName: '1号仓库温度传感器' },
|
{ id: '1-2', index: 2, deviceName: '摄像头2', modelId: 'mgt1gz9s54s' },
|
||||||
{ id: '1-3', index: 3, deviceName: '消防设施检查点' },
|
{ id: '1-3', index: 3, deviceName: '摄像头3', modelId: 'mgt1ho9dzhn' },
|
||||||
{ id: '1-4', index: 4, deviceName: '2号仓库湿度传感器' },
|
{ id: '1-4', index: 4, deviceName: '摄像头4', modelId: 'mgt1n0wylmd' },
|
||||||
{ id: '1-5', index: 5, deviceName: '出口监控摄像头' }
|
{ 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',
|
createTime: '2024-04-01 10:30:00',
|
||||||
updateTime: '2024-04-10 14:20:00'
|
updateTime: '2024-04-10 14:20:00'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
name: '西区安全巡检路线',
|
name: '新库区入口巡检路径',
|
||||||
description: '西区安全检查专用路线',
|
description: '新库区入口安全检查专用路线',
|
||||||
pointCount: 3,
|
pointCount: 5,
|
||||||
points: [
|
points: [
|
||||||
{ id: '2-1', index: 1, deviceName: '西区大门' },
|
{ id: '2-1', index: 1, deviceName: '摄像头18', modelId: 'mgt24lo3m4e' },
|
||||||
{ id: '2-2', index: 2, deviceName: '安全监控室' },
|
{ id: '2-2', index: 2, deviceName: '摄像头17', modelId: 'mgt24kocdw' },
|
||||||
{ id: '2-3', index: 3, deviceName: '应急出口' }
|
{ 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',
|
createTime: '2024-04-05 09:15:00',
|
||||||
updateTime: '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'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user