<!-- 巡检导航 --> <script setup lang="ts"> import { ElMessage, ElMessageBox } from 'element-plus' import addRouteDialog from './dialog/editRouteDialog.vue' import threeCom from '@/components/threejs/index.vue' import { controlDevice, delRoute, getRouteByDog, getRouteList } from '@/api/patrol/navigation' import useSocket from '@/store/modules/websocket' import changeDeviceDialog from '@/views/patrol/navigation/dialog/changeDeviceDialog.vue' import { getDeviceList } from '@/api/patrol/manage' const socket = useSocket() const currentDevice = ref({ // 当前设备信息 id: '', robotName: '--', // 设备名称 robotCode: '--', // 设备编号 robotStatus: '--', // 1,有效,0无效 robotCell: '--', // 电量 routeId: '', // 正在执行路线id route: '--', speed: '--', communityName: '--', // 小区名称 communityAddress: '--', // 小区地址 }) const routeInfoDetailList: any = ref([]) // 巡检路线的点的集合 // -----------------------------------------更换、解除设备---------------------------------------- const changeDeviceDialogRef = ref() // 点击更换设备 const changeDevice = () => { changeDeviceDialogRef.value.initDialog(currentDevice.value.id) } // 确认更换设备 const confirmChangeDevice = (value: any) => { currentDevice.value.id = value[0].id currentDevice.value.robotName = value[0].robotName // 设备名称 currentDevice.value.robotCode = value[0].robotCode // 设备编号 currentDevice.value.robotStatus = `${value[0].robotStatus}` === '1' ? '工作中' : '离线' // 1,有效,0无效 currentDevice.value.robotCell = `${value[0].robotCell}` ? `${value[0].robotCell}%` : '--' // 电量 fetchRouteByDog(currentDevice.value.id) // 根据设备区查询当前巡检路线 fetchRouteList() // 查询巡检路线 } // 点击解除绑定 const unbind = () => { ElMessageBox.confirm( '确定解除绑定吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }, ).then(() => { ElMessage.info('敬请期待') }) } // -----------------------------------------------表格------------------------------------------------------ const addRouteDialogRef = ref() // 表格表头 const columns: any = ref([ { text: '巡检路线名称', value: 'routeName', align: 'center' }, { text: '街道/小区名称', value: 'communityName', align: 'center' }, { text: '小区地址', value: 'communityAddress', align: 'center' }, { text: '机器人', value: 'robotName', align: 'center' }, { text: '更新时间', value: 'time', align: 'center', width: '120' }, ]) const listQuery = ref({ communityAddress: '', // 小区地址 communityName: '', // 小区名称 robotName: '', // 机器人名称 routeName: '', // 巡航线名称 robotId: '', // 狗id limit: 10, offset: 1, }) const list: any = ref([]) // 数据列表 const listLoading = ref(false) const total = ref(0) // 获取路线列表 function fetchRouteList() { listLoading.value = true listQuery.value.robotId = currentDevice.value.id getRouteList(listQuery.value).then((res) => { list.value = res.data.rows.map((item: { updateTime: string; createTime: string }) => { return { ...item, time: !item.updateTime ? item.createTime : item.updateTime, // 更新时间 } }) total.value = res.data.total listLoading.value = false // 小区信息默认最新的路线的信息 if (list.value.length) { currentDevice.value.communityName = list.value[0].communityName // 小区名称 currentDevice.value.communityAddress = list.value[0].communityAddress // 小区地址 } else { currentDevice.value.communityName = '--' // 小区名称 currentDevice.value.communityAddress = '--' // 小区地址 } }).catch(() => { listLoading.value = false }) } // 页数发生变化后的操作,可能是页码变化,可能是每页容量变化,此函数必写 function changePage(val: { size: number; page: number }) { if (val && val.size) { listQuery.value.limit = val.size } if (val && val.page) { listQuery.value.offset = val.page } fetchRouteList() } // 编辑、详情、删除 const handleRouteEdit = (row: any, type: 'detail' | 'edit' | 'del') => { if (type === 'detail' || type === 'edit') { addRouteDialogRef.value.initDialog(type, { ...currentDevice.value, robotId: currentDevice.value.id }, row) } else if (type === 'del') { ElMessageBox.confirm( '确认删除吗?', '提示', { confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning', }, ) .then(() => { delRoute({ ids: [row.id] }).then((res) => { ElMessage({ type: 'success', message: '删除成功', }) fetchRouteList() }) }) } } // ------------------------------------------------控制-------------------------------------------------- const map: any = { startRecordMap: 'w/', // 开始地图录入 endRecordMap: 'e/', // 完成地图录入 startRecordRoutInfo: 'x/', // 添加巡检点 endRecordRoutInfo: 'c/', // 保存巡检点和地图 delRecordRoutInfo: 'v/', // 删除所有的巡检点和地图 startNavigation: 'a/', // 开始巡检 pauseNavigation: 's/', // 暂停巡检 recoverNavigation: 'd/', // 恢复巡检 } // 开始录制地图、完成点云图录制、添加巡检点、完成巡检点录制 const control = (type: string) => { if (type === 'endRecordRoutInfo') { if (!routeInfoDetailList.value.length) { ElMessage.warning('没有巡检点-点云数据,请排查是否未添加巡检点或者上次添加是否还未完成并返回数据') return false } addRouteDialogRef.value.initDialog('add', { ...currentDevice.value, robotId: currentDevice.value.id }, null, routeInfoDetailList.value) } else { if (currentDevice.value.id) { const params = { command: map[type], robotDogId: currentDevice.value.id, } controlDevice(params).then(() => { ElMessage.success('操作成功') }) } } } // -------------------------------------------------设备相关------------------------------------------------- // 根据设备区查询当前巡检路线 function fetchRouteByDog(id: string) { getRouteByDog({ id }).then((res) => { if (res && res.data && res.data.length) { currentDevice.value.routeId = res.data[0].id // 正在执行路线id currentDevice.value.route = res.data[0].id // 正在执行路线id } else { currentDevice.value.routeId = '' currentDevice.value.route = '' } }) } // 获取设备列表 const fetchDeviceList = () => { const params = { robotName: '', } getDeviceList(params).then((res) => { currentDevice.value.id = res.data.rows[0].id currentDevice.value.robotName = res.data.rows[0].robotName // 设备名称 currentDevice.value.robotCode = res.data.rows[0].robotCode // 设备编号 currentDevice.value.robotStatus = `${res.data.rows[0].robotStatus}` === '1' ? '工作中' : '闲置' // 1,有效,0无效 currentDevice.value.robotCell = `${res.data.rows[0].robotCell}%` // 电量 // currentDevice.value.routeId = res.data.rows[0].routeId // 正在执行路线id fetchRouteByDog(currentDevice.value.id) }) } // ---------------------------------------------------websocket---------------------------------------------------------- watch(() => socket.data, (newVal: any) => { console.log('socket监听到数据:', newVal) if (newVal && newVal.type === 'sendPoints') { if (Array.isArray(newVal.points) && newVal.points.length) { routeInfoDetailList.value = newVal.points console.log('socket监听到数据:', routeInfoDetailList.value) } } }, { deep: true, immediate: true, }) // -------------------------------------------------------------------------------------------------------------- onMounted(() => { list.value = [ { content: '燃气管线周边是否施工', situation: '现场周边无施工现象', picture: '', route: '路线1', communityName: '二街坊社区', communityAddress: '北京市海淀区永定路街道', robotName: '机器狗1号', updateTime: '2025-03-10 14:42:00', }, { content: '闸井燃气浓度是否正常', situation: '正常', picture: '', route: '路线2', communityName: '永定路57号院', communityAddress: '北京市海淀区永定路街道', robotName: '机器狗2号', updateTime: '2025-03-10 10:00:00', }, ] fetchDeviceList() // 获取设备列表,默认第一个设备为当前设备 fetchRouteList() // 获取巡检路线 }) </script> <template> <app-container> <div class="patrol-manage"> <div class="box box-top"> <div> <div class="button-area"> <div> <span style="margin-right: 30px;">巡检导航测试</span> <el-button type="primary" :disabled="!currentDevice.id" @click="control('startRecordMap')"> 开始录制地图 </el-button> <el-button type="success" :disabled="!currentDevice.id" @click="control('endRecordMap')"> 完成点云图录制 </el-button> </div> <div style="margin: 20px 0;"> <span style="margin-right: 30px;">巡检点录入</span> <el-button type="primary" :disabled="!currentDevice.id" @click="control('startRecordRoutInfo')"> 添加巡检点 </el-button> <el-button type="danger" :disabled="!currentDevice.id" @click="control('endRecordMap')"> 删除上一个巡检点 </el-button> <el-button type="success" :disabled="!currentDevice.id" @click="control('endRecordRoutInfo')"> 完成巡航点录入 </el-button> </div> </div> <div class="box-top-item"> <three-com style="width: 100%; height: 400px" class="three-area" /> </div> </div> <div style="height: 100%; background-color: #ccc; width: 1px;" /> <div class="box-top-item"> <div class="box-title"> <div class="title"> <span>关联设备</span> <img style="width: 20px; height: 20px" src="../../../assets/tempImages/icon-link.svg" > </div> <div> <el-button type="primary" link @click="changeDevice"> 更换设备 </el-button> <el-button type="danger" link @click="unbind"> 解除绑定 </el-button> </div> </div> <div class="box-main"> <img style="width: 200px; height: 200px" src="../../../assets/tempImages/dog.png" > <div class="box-device"> <span> <span class="title">设备名称: </span> <span class="text">{{ currentDevice.robotName }}</span> </span> <span> <span class="title">设备状态: </span> <!-- <span class="text" style="color: #afcc85">{{ currentDevice.robotStatus }}</span> --> <span class="text" :style="{ color: `${currentDevice.robotStatus}` === '工作中' ? '#afcc85' : '#ccc' }">{{ currentDevice.robotStatus }}</span> </span> <span> <span class="title">设备电量: </span> <span class="text">{{ currentDevice.robotCell }}</span> </span> <span> <span class="title">小区名称: </span> <span class="text">{{ currentDevice.communityName }}</span> </span> <span> <span class="title">小区地址: </span> <span class="text">{{ currentDevice.communityAddress }}</span> </span> </div> </div> </div> </div> <div class="box-bottom"> <table-container title="路线管理" style="margin-top: 0px !important;"> <normal-table :data="list" :total="total" :pagination="true" :columns="columns" :query="listQuery" :list-loading="listLoading" @change="changePage" > <template #preColumns> <el-table-column label="序号" width="55" align="center"> <template #default="scope"> {{ (listQuery.offset - 1) * listQuery.limit + scope.$index + 1 }} </template> </el-table-column> </template> <template #columns> <el-table-column label="操作" width="160" align="center" fixed="right"> <template #default="scope"> <el-button type="primary" link size="small" class="table-text-button" @click="handleRouteEdit(scope.row, 'edit')" > 编辑 </el-button> <el-button type="primary" link size="small" class="table-text-button" @click="handleRouteEdit(scope.row, 'detail')" > 详情 </el-button> <el-button type="danger" link size="small" class="table-text-button" @click="handleRouteEdit(scope.row, 'del')" > 删除 </el-button> </template> </el-table-column> </template> </normal-table> </table-container> </div> </div> </app-container> <add-route-dialog ref="addRouteDialogRef" @close-refresh="fetchRouteList()" /> <change-device-dialog ref="changeDeviceDialogRef" @confirm="confirmChangeDevice" /> </template> <style scoped lang="scss"> .patrol-manage { display: flex; flex-direction: column; // gap: 10px; } .box { width: 100%; background-color: #fff; padding: 10px; border-radius: 7px; } .box-top { display: grid; /* 将容器划分为两列,左边占 2 份,右边占 1 份 */ grid-template-columns: 2fr 0.05fr 0.6fr; /* 设置列之间的间距为 20 像素 */ gap: 20px; .button-area { } .box-top-item { display: flex; flex-direction: column; // justify-content: center; // align-items: center; .three-area { position: relative; width: 100%; height: 400px; } .box-title { font-size: 14px; font-weight: 600; display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; .title { display: flex; justify-content: space-between; align-items: center; } } .box-main { display:flex; height: 100%; flex-direction: column; justify-content: space-around; align-items: center; .box-device { display: flex; flex-direction: column; line-height: 29px; color: rgba(0,0,0,1); font-size: 14px; text-align: left; font-family: SourceHanSansSC-regular; .text { font-weight: 600; } } } } } .box-bottom { display: flex; flex-direction: column; .title { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .control-title { color: white; background-color: #ff9f11; border-bottom-right-radius: 10px; border-top-right-radius: 10px; line-height: 30px; font-weight: bold; text-align: center; letter-spacing: 1px; font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", SimSun, sans-serif; writing-mode: vertical-rl; text-orientation: upright; width: 30px; height: 100px; } .round-btn { position: absolute; top: 14px; left: 129px; width: 42px; height: 42px; z-index: 111111; border-radius: 21px; cursor: pointer; &:hover { background-color: rgb(61 125 254 / 53%); } } } </style>