Explorar el Código

机器人实时界面;机器人巡检记录界面

fbw hace 2 años
padre
commit
f563a82c0b
Se han modificado 38 ficheros con 4257 adiciones y 852 borrados
  1. 2 0
      public/js/config.js
  2. 1 0
      public/static/images/finishP.svg
  3. 1 0
      public/static/images/robot.svg
  4. 1 0
      public/static/images/waitP.svg
  5. 61 13
      src/api/robotSLG/public.js
  6. 1 0
      src/assets/icons/svg/left.svg
  7. 1 0
      src/assets/icons/svg/right.svg
  8. BIN
      src/assets/images/dashboard/gas/gas_0.png
  9. BIN
      src/assets/images/dashboard/gas/gas_1.png
  10. BIN
      src/assets/images/dashboard/gas/plate1.png
  11. BIN
      src/assets/images/dashboard/gas/plate2.png
  12. BIN
      src/assets/images/dashboard/gas/plate3.png
  13. BIN
      src/assets/images/dashboard/parameter/control.png
  14. BIN
      src/assets/images/dashboard/parameter/presure.png
  15. BIN
      src/assets/images/dashboard/parameter/robotspeed.png
  16. BIN
      src/assets/images/dashboard/parameter/water.png
  17. BIN
      src/assets/images/dashboard/parameter/workspeed.png
  18. BIN
      src/assets/images/dashboard/planpiechart/task.png
  19. BIN
      src/assets/images/dashboard/robot.png
  20. BIN
      src/assets/images/dashboard/state/alarm-0.png
  21. BIN
      src/assets/images/dashboard/state/alarm-1.png
  22. BIN
      src/assets/images/dashboard/state/online-0.png
  23. BIN
      src/assets/images/dashboard/state/online-1.png
  24. BIN
      src/assets/images/dashboard/title-line.png
  25. BIN
      src/assets/images/dashboard/title-triangle.png
  26. BIN
      src/assets/images/dashboard/title_bg_429.png
  27. BIN
      src/assets/images/dashboard/title_bg_653.png
  28. BIN
      src/assets/images/dashboard/title_bg_729.png
  29. 2 2
      src/utils/request.js
  30. 91 0
      src/utils/requestRobot.js
  31. 282 161
      src/views/robotSLG/patrolRecord/index.vue
  32. 60 0
      src/views/robotSLG/robot/components/Container2/index.vue
  33. 142 0
      src/views/robotSLG/robot/components/Device/index.vue
  34. 287 0
      src/views/robotSLG/robot/components/ImageVideo/index.vue
  35. 1713 0
      src/views/robotSLG/robot/components/map/index.vue
  36. 776 652
      src/views/robotSLG/robot/index.vue
  37. 803 0
      src/views/robotSLG/robot2/index.vue
  38. 33 24
      src/views/robotSLG/tableConfig.js

+ 2 - 0
public/js/config.js

@@ -6,3 +6,5 @@ const VISUAL_PAGE_PATH = `http://${window.location.hostname}:8081/#/stationMap`
 const TOOLS_PAGE_PATH = `http://${window.location.hostname}:8082/#/`
 
 const TOP_MENUS = []
+
+const ROBOT = { username: 'robot', pass: '123456' }

+ 1 - 0
public/static/images/finishP.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1684477222762" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2387" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M512 320a192.064 192.064 0 0 1 0 384 192 192 0 0 1 0-384z" fill="#108118" p-id="2388"></path></svg>

+ 1 - 0
public/static/images/robot.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1684405139465" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2542" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M852 64H172c-17.7 0-32 14.3-32 32v660c0 17.7 14.3 32 32 32h680c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32zM300 328c0-33.1 26.9-60 60-60s60 26.9 60 60-26.9 60-60 60-60-26.9-60-60z m372 248c0 4.4-3.6 8-8 8H360c-4.4 0-8-3.6-8-8v-60c0-4.4 3.6-8 8-8h304c4.4 0 8 3.6 8 8v60z m-8-188c-33.1 0-60-26.9-60-60s26.9-60 60-60 60 26.9 60 60-26.9 60-60 60z m135 476H225c-13.8 0-25 14.3-25 32v56c0 4.4 2.8 8 6.2 8h611.5c3.4 0 6.2-3.6 6.2-8v-56c0.1-17.7-11.1-32-24.9-32z" fill="#d81e06" p-id="2543"></path></svg>

+ 1 - 0
public/static/images/waitP.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1684477222762" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2387" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M512 320a192.064 192.064 0 0 1 0 384 192 192 0 0 1 0-384z" fill="#13227a" p-id="2388"></path></svg>

+ 61 - 13
src/api/robotSLG/public.js

@@ -1,4 +1,4 @@
-import request from '@/utils/request'
+import request from '@/utils/requestRobot'
 
 //登录获取token
 export function getRobotToken(data) {
@@ -13,7 +13,10 @@ export function getRobotList(data) {
   return request({
     url: `explosive-api/robot/list`,
     method: 'post',
-    data
+    data,
+    headers:{
+      'token':data.token
+    }
   })
 }
 // 获取识别类型
@@ -21,7 +24,10 @@ export function getRecognizeList(data) {
   return request({
     url: 'explosive-api/indicator/recognize/list',
     method: 'post',
-    data
+    data,
+    headers:{
+      'token':data.token
+    }
   })
 }
 // 查询区域
@@ -29,7 +35,10 @@ export function getAreaTree(data) {
   return request({
     url: 'explosive-api/area/tree',
     method: 'post',
-    data
+    data,
+    headers:{
+      'token':data.token
+    }
   })
 }
 
@@ -38,7 +47,10 @@ export function getNaviList(data) {
   return request({
     url: 'explosive-api/navi/list',
     method: 'post',
-    data
+    data,
+    headers:{
+      'token':data.token
+    }
   })
 }
 
@@ -47,7 +59,10 @@ export function getPositionList(data) {
   return request({
     url: 'explosive-api/position/list',
     method: 'post',
-    data
+    data,
+    headers:{
+      'token':data.token
+    }
   })
 }
 
@@ -56,7 +71,10 @@ export function getSenceList(data) {
   return request({
     url: 'explosive-api/indicator/scene/list',
     method: 'post',
-    data
+    data,
+    headers:{
+      'token':data.token
+    }
   })
 }
 
@@ -65,7 +83,10 @@ export function createTask(data) {
   return request({
     url: 'explosive-api/task/create',
     method: 'post',
-    data
+    data,
+    headers:{
+      'token':data.token
+    }
   })
 }
 
@@ -74,7 +95,10 @@ export function getTaskList(data) {
   return request({
     url: 'explosive-api/task/list',
     method: 'post',
-    data
+    data,
+    headers:{
+      'token':data.token
+    }
   })
 }
 
@@ -83,7 +107,10 @@ export function getTask(id) {
   return request({
     url: 'explosive-api/task/get',
     method: 'post',
-    id:id
+    id:id,
+    headers:{
+      'token':data.token
+    }
   })
 }
 
@@ -92,7 +119,10 @@ export function getPatrolRecordList(data) {
   return request({
     url: 'explosive-api/patrol-record/list',
     method: 'post',
-    data
+    data,
+    headers:{
+      'token':data.token
+    }
   })
 }
 
@@ -101,7 +131,10 @@ export function getPatrolRecord(id) {
   return request({
     url: 'explosive-api/patrol-record/get',
     method: 'post',
-    id:id
+    id:id,
+    headers:{
+      'token':data.token
+    }
   })
 }
 
@@ -110,6 +143,21 @@ export function getRealtimeList(data) {
   return request({
     url: 'explosive-api/realtime/list',
     method: 'post',
-    data
+    data,
+    headers:{
+      'token':data.token
+    }
+  })
+}
+
+// 查询报警信息
+export function getAlarmList(data) {
+  return request({
+    url: 'explosive-api/alarm/list',
+    method: 'post',
+    data,
+    headers:{
+      'token':data.token
+    }
   })
 }

+ 1 - 0
src/assets/icons/svg/left.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1682506556393" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="17129" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M514.02405737 161.66396l1.06833201 350.318644-3.10982801 352.151385c0 21.406542-1.158383 40.22411999-5.945409 46.476521-11.55721999 15.095813-35.162848 13.446243-48.549739 0L49.34685237 537.873274c-7.135514-7.104815-10.18599-16.587793-9.727549-25.919323-0.459464-9.333576 2.592035-18.78687801 9.727549-25.922393L457.48638937 113.29534601c13.386892-13.415544 36.776601-14.879895 48.518017 0C511.46374537 120.218012 514.02405737 132.26641901 514.02405737 161.66396z" p-id="17130" fill="#707070"></path></svg>

+ 1 - 0
src/assets/icons/svg/right.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1682506581469" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="17562" width="64" height="64" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M-2.02405729 862.33604l-1.06833201-350.318644 3.10982801-352.151385c0-21.406542 1.158383-40.22411999 5.945409-46.476521 11.55721999-15.095813 35.162848-13.446243 48.549739 0L462.65314771 486.126726c7.135514 7.104815 10.18599 16.587793 9.72754901 25.919323 0.459464 9.333576-2.592035 18.78687801-9.72754901 25.922393L54.51361071 910.70465399c-13.386892 13.415544-36.776601 14.879895-48.518017 0C0.53625471 903.781988-2.02405729 891.73358099-2.02405729 862.33604z" p-id="17563" fill="#707070"></path></svg>

BIN
src/assets/images/dashboard/gas/gas_0.png


BIN
src/assets/images/dashboard/gas/gas_1.png


BIN
src/assets/images/dashboard/gas/plate1.png


BIN
src/assets/images/dashboard/gas/plate2.png


BIN
src/assets/images/dashboard/gas/plate3.png


BIN
src/assets/images/dashboard/parameter/control.png


BIN
src/assets/images/dashboard/parameter/presure.png


BIN
src/assets/images/dashboard/parameter/robotspeed.png


BIN
src/assets/images/dashboard/parameter/water.png


BIN
src/assets/images/dashboard/parameter/workspeed.png


BIN
src/assets/images/dashboard/planpiechart/task.png


BIN
src/assets/images/dashboard/robot.png


BIN
src/assets/images/dashboard/state/alarm-0.png


BIN
src/assets/images/dashboard/state/alarm-1.png


BIN
src/assets/images/dashboard/state/online-0.png


BIN
src/assets/images/dashboard/state/online-1.png


BIN
src/assets/images/dashboard/title-line.png


BIN
src/assets/images/dashboard/title-triangle.png


BIN
src/assets/images/dashboard/title_bg_429.png


BIN
src/assets/images/dashboard/title_bg_653.png


BIN
src/assets/images/dashboard/title_bg_729.png


+ 2 - 2
src/utils/request.js

@@ -46,8 +46,8 @@ service.interceptors.response.use(
     // const res = jsonKeysToCase(response.data)
     const res = response.data
     //console.log(response)
-    // if the custom code is not 20000, it is judged as an error.
-    if (res.code !== 20000) {
+    // if the custom code is not 20000 / 1, it is judged as an error.
+    if (res.code !== 20000 && res.code !== 1) {
       Message({
         message: res.msg || 'Error',
         type: 'error',

+ 91 - 0
src/utils/requestRobot.js

@@ -0,0 +1,91 @@
+import axios from 'axios'
+import { MessageBox, Message } from 'element-ui'
+import store from '@/store'
+import { getToken } from '@/utils/auth'
+
+// create an axios instance
+const service = axios.create({
+  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
+  // baseURL: process.env.YAPI_BASE_API, //本地yapi模拟接口
+  // withCredentials: true, // send cookies when cross-domain requests
+  timeout: 5000, // request timeout
+})
+
+// request interceptor
+service.interceptors.request.use(
+  (config) => {
+    // do something before request is sent
+    if (store.getters.token) {
+      // let each request carry token
+      // ['X-Token'] is a custom headers key
+      // please modify it according to the actual situation
+      config.headers['token'] = getToken()
+    }
+    return config
+  },
+  (error) => {
+    // do something with request error
+    console.log(error) // for debug
+    return Promise.reject(error)
+  }
+)
+
+// response interceptor
+service.interceptors.response.use(
+  /**
+   * If you want to get http information such as headers or status
+   * Please return  response => response
+   */
+
+  /**
+   * Determine the request status by custom code
+   * Here is just an example
+   * You can also judge the status by HTTP Status code
+   */
+  (response) => {
+    // const res = jsonKeysToCase(response.data)
+    const res = response.data
+    //console.log(response)
+    // if the custom code is not 20000 / 1, it is judged as an error.
+    if (res.code !== 20000 && res.code !== 1) {
+      Message({
+        message: res.msg || 'Error',
+        type: 'error',
+        duration: 5 * 1000,
+      })
+
+      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
+      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
+        // to re-login
+        MessageBox.confirm(
+          'You have been logged out, you can cancel to stay on this page, or log in again',
+          'Confirm logout',
+          {
+            confirmButtonText: 'Re-Login',
+            cancelButtonText: 'Cancel',
+            type: 'warning',
+          }
+        ).then(() => {
+          store.dispatch('user/resetToken').then(() => {
+            location.reload()
+          })
+        })
+      }
+      return Promise.reject(new Error(res.msg || 'Error'))
+    } else {
+      return res
+    }
+  },
+  (error) => {
+    // console.log('err' + error) // for debug
+    console.error(error)
+    Message({
+      message: error.message,
+      type: 'error',
+      duration: 5 * 1000,
+    })
+    return Promise.reject(error)
+  }
+)
+
+export default service

+ 282 - 161
src/views/robotSLG/patrolRecord/index.vue

@@ -4,62 +4,13 @@
     <div class="head-container">
       <div v-if="crud.props.searchToggle">
         <el-select
-          v-model="query.idList"
+          v-model="queryParams.robotId"
           filterable
           clearable
           size="small"
-          placeholder="记录ID"
+          placeholder="机器人"
           class="filter-item"
           style="width: 160px"
-          @change="crud.toQuery"
-        >
-          <el-option v-for="item in crud.data" :key="item.id" :label="item.id" :value="+item.id" />
-        </el-select>
-        <el-select
-          v-model="query.taskIdList"
-          filterable
-          clearable
-          size="small"
-          placeholder="任务ID"
-          class="filter-item"
-          style="width: 160px"
-          @change="crud.toQuery"
-        >
-          <el-option
-            v-for="item in taskList"
-            :key="item.value"
-            :label="item.label"
-            :value="+item.value"
-          />
-        </el-select>
-        <el-input
-          v-model="query.taskIdLike"
-          clearable
-          size="small"
-          placeholder="输入任务ID"
-          style="width: 160px"
-          class="filter-item"
-          @keyup.enter.native="crud.toQuery"
-        />
-        <el-input
-          v-model="query.taskTitleLike"
-          clearable
-          size="small"
-          placeholder="输入任务名称"
-          style="width: 160px"
-          class="filter-item"
-          @keyup.enter.native="crud.toQuery"
-        />
-
-        <el-select
-          v-model="query.robotId"
-          filterable
-          clearable
-          size="small"
-          placeholder="机器人ID"
-          class="filter-item"
-          style="width: 160px"
-          @change="handleChangeBuildId"
         >
           <el-option
             v-for="item in robotList"
@@ -69,14 +20,13 @@
           />
         </el-select>
         <el-select
-          v-model="query.mapId"
+          v-model="queryParams.mapId"
           filterable
           clearable
           size="small"
-          placeholder="地图ID"
+          placeholder="地图"
           class="filter-item"
           style="width: 160px"
-          @change="crud.toQuery"
         >
           <el-option
             v-for="item in sceneList"
@@ -85,90 +35,103 @@
             :value="item.value"
           />
         </el-select>
-        <el-select
-          v-model="query.areaList"
-          filterable
+        <el-cascader
+          :options="areaTree"
           clearable
+          :props="{ multiple: true }"
           size="small"
           placeholder="区域ID"
           class="filter-item"
-          style="width: 160px"
-          @change="handleChangeBuildId"
-        >
-          <el-option
-            v-for="item in areaList"
-            :key="item.value"
-            :label="item.label"
-            :value="item.value"
-          />
-        </el-select>
+          style="width: 160px;"
+          collapse-tags
+        />
         <el-select
-          v-model="query.positionList"
-          filterable
+          v-model="queryParams.recognizeIdList"
           clearable
+          multiple
+          collapse-tags
           size="small"
-          placeholder="点位ID"
+          placeholder="识别类型"
           class="filter-item"
-          style="width: 160px"
-          @change="crud.toQuery"
+          style="width: 280px"
         >
           <el-option
-            v-for="item in positionList"
+            v-for="item in recognizeTypeList"
             :key="item.value"
             :label="item.label"
             :value="item.value"
           />
         </el-select>
-        <el-select
-          v-model="query.defectGradeList"
+        <el-input
+          v-model="queryParams.positionList"
           clearable
+          multiple
           size="small"
-          placeholder="缺陷等级"
+          placeholder="输入点位名称"
+          style="width: 160px"
           class="filter-item"
+        />
+        <el-input
+          v-model="queryParams.taskIdLike"
+          clearable
+          size="small"
+          placeholder="输入任务编号"
           style="width: 160px"
-          @change="crud.toQuery"
-        >
-          <el-option
-            v-for="item in defectGradeList"
-            :key="item.value"
-            :label="item.label"
-            :value="item.value"
-          />
-        </el-select>
+          class="filter-item"
+        />
+        <el-input
+          v-model="queryParams.taskTitleLike"
+          clearable
+          size="small"
+          placeholder="输入任务名称"
+          style="width: 160px"
+          class="filter-item"
+        />
+
         <el-select
-          v-model="query.recognizeIdList"
+          v-model="queryParams.defectGradeList"
           clearable
+          multiple
+          collapse-tags
           size="small"
-          placeholder="识别类型"
+          placeholder="缺陷等级"
           class="filter-item"
           style="width: 160px"
-          @change="crud.toQuery"
         >
           <el-option
-            v-for="item in recognizeTypeList"
+            v-for="item in defectGradeList"
             :key="item.value"
             :label="item.label"
             :value="item.value"
           />
         </el-select>
+
         <el-input
-          v-model="query.indicatorNameLike"
+          v-model="queryParams.indicatorNameLike"
           clearable
           size="small"
           placeholder="输入指标名称"
           style="width: 160px"
           class="filter-item"
-          @keyup.enter.native="crud.toQuery"
         />
         <date-range-picker
           type="datetimerange"
-          v-model="customs.timeRange"
+          v-model="timeRange"
           class="date-item"
           style="width: 400px !important"
-          @change="crud.toQuery"
+          @change="setTime"
         />
-
-        <rrOperation />
+        <span>
+          <el-button
+            class="filter-item"
+            size="mini"
+            type="success"
+            icon="el-icon-search"
+            @click="searchPatrolRecord()"
+            >搜索</el-button
+          >
+        </span>
+        <!-- <rrOperation /> -->
       </div>
       <crudOperation :permission="permission" />
     </div>
@@ -179,11 +142,11 @@
       :before-close="crud.cancelCU"
       :visible.sync="crudCU"
       title="巡检记录"
-      width="1200px"
+      width="900px"
     >
       <el-row :gutter="40">
         <el-form ref="form" :model="form" :rules="rules" size="small" label-width="100px">
-          <el-col :span="8">
+          <el-col :span="12">
             <el-form-item label="机器人名称" prop="robot">
               <el-input v-model="form.robot" size="small" class="filter-item" disabled />
             </el-form-item>
@@ -211,14 +174,14 @@
             <el-form-item label="指标名称" prop="indicatorName">
               <el-input v-model="form.indicatorName" size="small" cvlass="filter-item" disabled />
             </el-form-item>
+          </el-col>
+          <el-col :span="12">
             <el-form-item label="识别类型编码" prop="recognizeCode">
               <el-input v-model="form.recognizeCode" size="small" class="filter-item" disabled />
             </el-form-item>
             <el-form-item label="识别类型名称" prop="recognizeName">
               <el-input v-model="form.recognizeName" size="small" class="filter-item" disabled />
             </el-form-item>
-          </el-col>
-          <el-col :span="8">
             <el-form-item label="单位" prop="unit">
               <el-input v-model="form.unit" size="small" class="filter-item" disabled />
             </el-form-item>
@@ -228,7 +191,7 @@
             <el-form-item label="巡检时间" prop="patrolTime">
               <el-input v-model="form.patrolTime" size="small" class="filter-item" disabled />
             </el-form-item>
-            <el-form-item label="识别状态" prop="recognizeState">
+            <!-- <el-form-item label="识别状态" prop="recognizeState">
               <el-switch
                 disabled
                 v-model="form.recognizeState"
@@ -238,6 +201,9 @@
                 :inactive-value="false"
               >
               </el-switch>
+            </el-form-item> -->
+            <el-form-item label="识别状态" prop="recognizeState">
+              <el-input v-model="form.recognizeState" size="small" class="filter-item" disabled />
             </el-form-item>
             <el-form-item label="识别阈值ID" prop="thresholdId">
               <el-input v-model="form.thresholdId" size="small" class="filter-item" disabled />
@@ -248,7 +214,7 @@
             <el-form-item label="检测值" prop="value">
               <el-input v-model="form.value" size="small" class="filter-item" disabled />
             </el-form-item>
-            <el-form-item label="检测值明细" prop="detail">
+            <!-- <el-form-item label="检测值明细" prop="detail">
               <el-input v-model="form.detail" size="small" class="filter-item" disabled />
             </el-form-item>
             <el-form-item label="矫正时间" prop="adjustTime">
@@ -259,9 +225,9 @@
             </el-form-item>
             <el-form-item label="修正后等级" prop="modifiedGrade">
               <el-input v-model="form.modifiedGrade" size="small" class="filter-item" disabled />
-            </el-form-item>
+            </el-form-item> -->
           </el-col>
-          <el-col :span="8">
+          <!-- <el-col :span="8">
             <el-form-item label="缺陷追溯" prop="defectReview">
               <el-input v-model="form.defectReview" size="small" class="filter-item" disabled />
             </el-form-item>
@@ -286,40 +252,27 @@
             <el-form-item label="警戒线" prop="guardLine">
               <el-input v-model="form.guardLine" size="small" class="filter-item" disabled />
             </el-form-item>
-          </el-col>
+          </el-col> -->
         </el-form>
       </el-row>
-      <el-row :gutter="40">
-        <div style="margin-left: 22px;color:#000;font-weight:bold">
+      <!-- <el-row :gutter="40">
+        <div style="margin-left: 22px; color: #000; font-weight: bold">
           <div>算法资源列表:</div>
           <el-table :data="resourceList" style="width: 98%" :height="'100%'">
             <el-table-column prop="index" label="序号" align="center" />
             <el-table-column prop="tye" label="资源类型" align="center" />
             <el-table-column prop="originUrl" label="原始资源路径" align="center" />
             <el-table-column prop="processedUrl" label="已处理资源路径" />
-            <!-- <template slot-scope="scope">
-                <el-progress
-                  :show-text="false"
-                  :stroke-width="10"
-                  :percentage="scope.row.a"
-                ></el-progress>
-              </template> -->
           </el-table>
         </div>
-      </el-row>
+      </el-row> -->
 
-      <!-- <div slot="footer" class="dialog-footer">
-        <el-button type="text" @click="crud.cancelCU"> 取消 </el-button>
-        <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">
-          确认
-        </el-button>
-      </div> -->
     </el-dialog>
     <!--表格渲染-->
     <el-table
       ref="table"
       v-loading="crud.loading"
-      :data="crud.data"
+      :data="patrolRecordList.list"
       style="width: 100%"
       @selection-change="crud.selectionChangeHandler"
     >
@@ -337,7 +290,9 @@
       </el-table-column>
       <!--   编辑与删除   -->
       <el-table-column
-        v-if="checkPer(['admin', 'visualintercom:config:edit', 'visualintercom:config:del'])"
+        v-if="
+          checkPer(['admin', 'robotSLG:patrolRecord:list:edit', 'robotSLG:patrolRecord:list:del'])
+        "
         label="操作"
         width="130px"
         align="center"
@@ -349,7 +304,17 @@
       </el-table-column>
     </el-table>
     <!--分页组件-->
-    <pagination />
+    <el-pagination
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+      :current-page="pageIndex"
+      :page-sizes="[10, 20, 50, 100, 200, 500]"
+      :page-size="pageSize"
+      layout="total, sizes, prev, pager, next, jumper"
+      :total="+patrolRecordList.totalCount"
+      style="margin-top:4px;"
+    >
+    </el-pagination>
   </div>
 </template>
 
@@ -371,17 +336,9 @@ import {
   getPositionList,
   getSenceList,
   getTaskList,
+  getRobotToken,
+  getPatrolRecordList,
 } from '@/api/robotSLG/public'
-//import CameraMap from './cameraMap'
-import {
-  isPosNumber,
-  isNegNumber,
-  isNumber,
-  isPosInteger,
-  isNegInteger,
-  isInteger,
-} from '@/utils/validate'
-import RelativeMap from '@/components/RelativeMap'
 
 const defaultForm = {
   id: '', //主键ID
@@ -443,11 +400,12 @@ export default {
   name: 'PatrolRecord',
   directives: { permission },
   mixins: [presenter(), header(), form(defaultForm), crud()],
-  components: { ...crudComps, DateRangePicker, RelativeMap },
+  components: { ...crudComps, DateRangePicker },
   cruds() {
     return CRUD({
       title: '巡检记录',
-      url: 'visualIntercom/config/getPageListJson',
+      url: 'explosive-api/patrol-record/list',
+      query: { pageIndex: 1, pageSize: 10 },
       listOrder: [],
       crudMethod: { ...crudVisualIntercom },
       optShow: {
@@ -475,9 +433,9 @@ export default {
     return {
       patrolRecordTableOptions,
       permission: {
-        add: ['admin', 'visualintercom:config:add'],
-        edit: ['admin', 'visualintercom:config:edit'],
-        del: ['admin', 'visualintercom:config:del'],
+        add: ['admin', 'robotSLG:patrolRecord:list:add'],
+        edit: ['admin', 'robotSLG:patrolRecord:list:edit'],
+        del: ['admin', 'robotSLG:patrolRecord:list:del'],
       },
       rules: {
         // code: [{ required: true, message: '请选输入编号', trigger: 'blur' }],
@@ -488,7 +446,31 @@ export default {
         FloorNo: [],
         VisualIntercomType: [],
       },
-
+      //分页
+      pageIndex: 1,
+      pageSize: 10,
+      timeRange: [],
+      //搜索条件
+      queryParams: {
+        token: this.robotToken,
+        idList: null, //记录ID列表
+        taskIdList: null, //任务ID列表
+        taskIdLike: '', //任务ID模糊查询
+        taskTitleLike: '', //任务标题(模糊查询)
+        robotId: '', //机器人ID
+        mapId: '', //地图ID
+        areaList: null, //区域ID列表
+        positionList: null, //点位ID列表
+        defectGradeList: null, //缺陷等级
+        recognizeIdList: null, //识别类型列表
+        indicatorNameLike: '', //指标名称模糊查询
+        minPatrolTime: '', //最小巡检时间
+        maxPatrolTime: '', //最大巡检时间
+        pageIndex: this.pageIndex, //页号
+        pageSize: this.pageSize, //每页记录数
+      },
+      //机器人登录token
+      robotToken: null,
       robotList: [
         {
           id: '', //主键ID
@@ -809,11 +791,49 @@ export default {
           createTime: '', //创建时间
         },
       ],
-      defectGradeList: [],
+      defectGradeList: [
+        {
+          value: 0,
+          label: '正常',
+        },
+        {
+          value: 1,
+          label: '轻微',
+        },
+        {
+          value: 2,
+          label: '预警',
+        },
+        {
+          value: 3,
+          label: '严重',
+        },
+        {
+          value: 4,
+          label: '危及',
+        },
+        {
+          value: -1,
+          label: '未识别',
+        },
+      ],
+      resourceList: [],
     }
   },
   created() {
     this.getOptions()
+    // console.log(`${ROBOT}`)
+    this.init().then((data) => {
+      setTimeout(() => {
+        this.getAreaOption()
+        this.getRobotOption()
+        this.getSenceOption()
+        this.getRecognizeOption()
+        this.getPositionOption()
+        this.getTaskListOption()
+        this.getPatrolRecordListOption()
+      }, 500)
+    })
   },
   methods: {
     getOptions() {
@@ -827,85 +847,129 @@ export default {
         }
       })
     },
-
-
+    async init() {
+      try {
+        let res = await getRobotToken(ROBOT)
+        // console.log(res)
+        if (res.code === 1) {
+          this.robotToken = res.data
+        }
+      } catch (error) {}
+    },
     async getAreaOption() {
       try {
-        let res = await getAreaTree({ pageIndex: 1, pageSize: 100 })
-        let arr = []
+        let res = await getAreaTree({ token: this.robotToken, id: '' })
         if (res.code === 1) {
-          res.data.forEach((a) => {
-            arr.push({
-              label: a.name,
-              value: a.id,
-            })
-          })
+          this.areaTree = {
+            value: res.data.id,
+            label: res.data.name,
+            children: res.data.subList.map((a) => {
+              return {
+                value: a.id,
+                label: a.name,
+              }
+            }),
+          }
+        } else {
+          this.getRobotToken()
         }
-        this.robotList = arr
       } catch (error) {}
     },
     async getRobotOption() {
       try {
-        let res = await getRobotList({ pageIndex: 1, pageSize: 100 })
+        let res = await getRobotList({ token: this.robotToken, pageIndex: 1, pageSize: 100 })
         if (res.code === 1) {
-          this.robotList = res.data.map((a) => {
+          this.robotList = res.data.list.map((a) => {
             return {
               label: a.title,
               value: a.id,
             }
           })
+          // console.log(this.robotList)
+        } else {
+          this.getRobotToken()
         }
       } catch (error) {}
     },
     async getSenceOption() {
       try {
-        let res = await getSenceList({ pageIndex: 1, pageSize: 100 })
+        let res = await getSenceList({ token: this.robotToken, pageIndex: 1, pageSize: 100 })
         if (res.code === 1) {
-          this.robotList = res.data.map((a) => {
+          this.sceneList = res.data.map((a) => {
             return {
               label: a.title,
               value: a.id,
             }
           })
+          // console.log(this.sceneList)
+        } else {
+          this.getRobotToken()
         }
       } catch (error) {}
     },
     async getPositionOption() {
       try {
-        let res = await getPositionList({ pageIndex: 1, pageSize: 100 })
+        let res = await getPositionList({ token: this.robotToken, pageIndex: 1, pageSize: 100 })
         if (res.code === 1) {
-          this.robotList = res.data.map((a) => {
+          this.positionList = res.data.map((a) => {
             return {
               label: a.naviSequence,
               value: a.id,
             }
           })
+        } else {
+          this.getRobotToken()
         }
       } catch (error) {}
     },
+    //
     async getRecognizeOption() {
       try {
-        let res = await getRecognizeList({ pageIndex: 1, pageSize: 100 })
+        let res = await getRecognizeList({ token: this.robotToken, pageIndex: 1, pageSize: 100 })
         if (res.code === 1) {
-          this.robotList = res.data.map((a) => {
+          this.recognizeTypeList = res.data.map((a) => {
             return {
               label: a.name,
               value: a.id,
             }
           })
+        } else {
+          this.getRobotToken()
         }
       } catch (error) {}
     },
+    //获取任务
     async getTaskListOption() {
       try {
-        let res = await getTaskList({ pageIndex: 1, pageSize: 100 })
+        let res = await getTaskList({
+          token: this.robotToken,
+          pageIndex: 1,
+          pageSize: 100,
+        })
         if (res.code === 1) {
-          this.robotList = res.data.map((a) => {
+          this.taskList = res.data.list.map((a) => {
             return {
               label: a.name,
               value: a.id,
             }
           })
+        } else {
+          this.getRobotToken()
+        }
+      } catch (error) {}
+    },
+    //获取巡检记录
+    async getPatrolRecordListOption() {
+      try {
+        let res = await getPatrolRecordList({
+          token: this.robotToken,
+          pageIndex: this.pageIndex,
+          pageSize: this.pageSize,
+        })
+        if (res.code === 1) {
+          this.patrolRecordList = res.data
+        } else {
+          this.getRobotToken()
         }
       } catch (error) {}
     },
@@ -921,6 +985,63 @@ export default {
         console.log(error)
       }
     },
+    //分页调整单页条数
+    handleSizeChange(val) {
+      this.pageSize = val
+      this.searchPatrolRecord()
+      // console.log(`每页 ${val} 条`)
+    },
+    //分页调整页码
+    handleCurrentChange(val) {
+      this.pageIndex = val
+      this.searchPatrolRecord()
+      // console.log(`当前页: ${val}`)
+    },
+    setTime() {
+      console.log(this.timeRange)
+      if (this.timeRange && this.timeRange.length > 1) {
+        this.queryParams.minPatrolTime = this.timeRange[0]
+        this.queryParams.maxPatrolTime = this.timeRange[1]
+      }
+    },
+    //条件搜索巡检记录
+    async searchPatrolRecord() {
+      ;(this.queryParams.token = this.robotToken),
+        (this.queryParams.pageIndex = this.pageIndex),
+        (this.queryParams.pageSize = this.pageSize),
+        console.log(this.queryParams)
+      try {
+        let res = await getPatrolRecordList({
+          token: this.robotToken,
+          pageIndex: this.pageIndex,
+          pageSize: this.pageSize,
+          idList: this.queryParams.idList ? this.queryParams.idList : null, //记录ID列表
+          taskIdList: this.queryParams.taskIdList ? this.queryParams.taskIdList : null, //任务ID列表
+          taskIdLike: this.queryParams.taskIdLike ? this.queryParams.taskIdLike : null, //任务ID模糊查询
+          taskTitleLike: this.queryParams.taskTitleLike ? this.queryParams.taskTitleLike : null, //任务标题(模糊查询)
+          robotId: this.queryParams.robotId ? this.queryParams.robotId : null, //机器人ID
+          mapId: this.queryParams.mapId ? this.queryParams.mapId : null, //地图ID
+          areaList: this.queryParams.areaList ? this.queryParams.areaList : null, //区域ID列表
+          positionList: this.queryParams.positionList ? this.queryParams.positionList : null, //点位ID列表
+          defectGradeList: this.queryParams.defectGradeList
+            ? this.queryParams.defectGradeList
+            : null, //缺陷等级
+          recognizeIdList: this.queryParams.recognizeIdList
+            ? this.queryParams.recognizeIdList
+            : null, //识别类型列表
+          indicatorNameLike: this.queryParams.indicatorNameLike
+            ? this.queryParams.indicatorNameLike
+            : null, //指标名称模糊查询
+          minPatrolTime: this.queryParams.minPatrolTime ? this.queryParams.minPatrolTime : null, //最小巡检时间
+          maxPatrolTime: this.queryParams.maxPatrolTime ? this.queryParams.maxPatrolTime : null, //最大巡检时间
+        })
+        if (res.code === 1) {
+          this.patrolRecordList = res.data
+        } else {
+          this.getRobotToken()
+        }
+      } catch (error) {}
+    },
   },
 }
 </script>

+ 60 - 0
src/views/robotSLG/robot/components/Container2/index.vue

@@ -0,0 +1,60 @@
+<template>
+  <div class="container2">
+    <div class="title">
+      <div class="titletext">{{ setting.title }}</div>
+      <div class="subtitle">{{ setting.subtitle }}</div>
+      <div class="titleline"></div>
+    </div>
+    <div class="content">
+      <slot>未填充内容</slot>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Container2',
+  props: {
+    setting: {
+      type: Object,
+      default: {
+        title: '主标题',
+        subtitle: '副标题',
+      },
+    },
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+.container2 {
+  height: 100%;
+  color: white;
+  .title {
+    height: 43px;
+    background-image: url('~@/assets/images/dashboard/title-triangle.png');
+    background-repeat: no-repeat;
+    background-position: 9px 9px;
+    font-size: 18px;
+    line-height: 40px;
+    .titletext {
+      display: inline-block;
+      margin-left: 40px;
+    }
+    .subtitle {
+      display: inline-block;
+      padding-left: 20px;
+      font-size: 10px;
+    }
+    .titleline {
+      height: 2px;
+      background-image: url('~@/assets/images/dashboard/title-line.png');
+    }
+  }
+  .content {
+    height: calc(100% - 46px);
+    border: 0px white solid;
+    box-sizing: content-box;
+  }
+}
+</style>

+ 142 - 0
src/views/robotSLG/robot/components/Device/index.vue

@@ -0,0 +1,142 @@
+<template>
+  <div class="robotbar" @click="changeRobot">
+    <div class="name">{{ deviceInfo.name }}</div>
+    <div class="online-state">
+      <div class="light" :style="{ backgroundColor: getOnlineColor }"></div>
+      <div class="text">{{ getOnlineState }}</div>
+    </div>
+    <div class="alarm-state">
+      <div class="light" :style="{ backgroundColor: getAlarmColor }"></div>
+      <div class="text">{{ getAlarmState }}</div>
+    </div>
+    <div></div>
+  </div>
+</template>
+
+<script>
+import lodash from 'lodash'
+
+export default {
+  props: {
+    deviceInfo: {
+      type: Object,
+      default: {
+        id: '1',
+        name: '机器人1#',
+        onlineState: '1',
+        alarmState: '0',
+      },
+    },
+  },
+  data() {
+    return {
+      onlineStateOptions: [
+        { code: '0', text: '离线', color: '#526891' },
+        { code: '1', text: '运行', color: '#28b973' },
+        { code: '2', text: '急停', color: '#f32727' },
+      ],
+      alarmStateOptions: [
+        { code: '0', text: '正常', color: '#28b973' },
+        { code: '1', text: '故障', color: '#f32727' },
+      ],
+    }
+  },
+  computed: {
+    getOnlineState() {
+      return lodash.find(this.onlineStateOptions, (o) => {
+        return o.code == this.deviceInfo.onlineState
+      }).text
+    },
+    getAlarmState() {
+      return lodash.find(this.alarmStateOptions, (o) => {
+        return o.code == this.deviceInfo.alarmState
+      }).text
+    },
+    getOnlineColor() {
+      return lodash.find(this.onlineStateOptions, (o) => {
+        return o.code == this.deviceInfo.onlineState
+      }).color
+    },
+    getAlarmColor() {
+      return lodash.find(this.alarmStateOptions, (o) => {
+        return o.code == this.deviceInfo.alarmState
+      }).color
+    },
+  },
+  methods: {
+    //回传选中设备
+    changeRobot() {
+      this.$emit('changeRobot', this.deviceInfo)
+    },
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+.robotbar {
+  background-color: #1278e1;
+  color: white;
+  height: 47px;
+  display: flex;
+  gap: 10px;
+  width: 100%;
+  border-radius: 5px !important;
+  .name {
+    margin-top: 10px;
+    width: 150px;
+    height: 27px;
+    min-width: 80px;
+    line-height: 27px;
+    font-size: 16px;
+    display: inline-block;
+    vertical-align: middle;
+    text-align: center;
+  }
+  .online-state {
+    margin-top: 10px;
+    width: 82px;
+    min-width: 82px;
+    height: 27px;
+    display: inline-block;
+    border-radius: 15px;
+    background-color: #063e92;
+    .light {
+      width: 12px;
+      height: 12px;
+      display: inline-block;
+      margin-left: 12px;
+      margin-top: 8px;
+      border-radius: 5px;
+    }
+    .text {
+      display: inline-block;
+      margin-left: 12px;
+      font-size: 14px;
+      height: 10px;
+    }
+  }
+  .alarm-state {
+    margin-top: 10px;
+    width: 82px;
+    min-width: 82px;
+    height: 27px;
+    display: inline-block;
+    border-radius: 15px;
+    background-color: #063e92;
+    .light {
+      width: 12px;
+      height: 12px;
+      display: inline-block;
+      margin-left: 12px;
+      margin-top: 8px;
+      border-radius: 5px;
+    }
+    .text {
+      display: inline-block;
+      margin-left: 12px;
+      font-size: 14px;
+      height: 10px;
+    }
+  }
+}
+</style>

+ 287 - 0
src/views/robotSLG/robot/components/ImageVideo/index.vue

@@ -0,0 +1,287 @@
+<template>
+  <div :style="imgStyle">
+    <img style="width: 100%; height: 100%; object-fit: contain" :src="url" v-if="url" />
+    <div class="image-slot" v-if="!url">
+      <i class="el-icon-video-camera"></i>
+    </div>
+  </div>
+</template>
+
+<script>
+import Dayjs from 'dayjs'
+
+export default {
+  name: 'ImageVideo',
+  components: {},
+  data() {
+    return {
+      url: '',
+      lastUrl: '',
+      ws: null,
+      zoom: false,
+      addWidth: 0,
+      addHeight: 0,
+      startTime: null,
+      speed: 5,
+      presetIndex: 1,
+      datePickerOptions: {
+        disabledDate: (currData) => currData > new Date(),
+      },
+      onPlayBack: false,
+    }
+  },
+  props: {
+    visible: false,
+    cameraData: {
+      type: Object,
+      required: true,
+    },
+    size: {
+      type: Object,
+      default: () => {
+        return { height: 420, width: 680 }
+      },
+    },
+  },
+  computed: {
+    dialogStyle() {
+      if (this.zoom) {
+        let clientHeight = document.documentElement.clientHeight
+        return {
+          height: clientHeight - 174 + this.addHeight + 'px',
+          width:
+            ((clientHeight - 234) / (this.size.height - 60)) * (this.size.width - 40) +
+            40 +
+            this.addWidth +
+            'px',
+        }
+      } else {
+        return {
+          height: this.size.height + this.addHeight + 'px',
+          width: this.size.width + this.addWidth + 'px',
+        }
+      }
+    },
+    imgStyle() {
+      return {
+        position: 'absolute',
+        left: '0px',
+        top: '0px',
+        right: this.addWidth + 'px',
+        bottom: this.addHeight + 'px',
+        'object-fit': 'contain',
+      }
+    },
+  },
+  watch: {
+    cameraData(val) {
+      if (val.id) {
+        //console.log(val)
+        if (val.canPlayBack) this.addHeight = 1
+        else this.addHeight = 0
+        if (val.ptzEnable) this.addWidth = 1
+        else this.addWidth = 0
+        if (this.ws && this.ws.readyState == 1) {
+          this.ws.send(JSON.stringify({ id: val.id, canControl: val.ptzEnable }))
+        } else {
+          this.init(JSON.stringify({ id: val.id, canControl: val.ptzEnable }))
+        }
+        setTimeout(() => {
+          this.url = ''
+          if (this.lastUrl) URL.revokeObjectURL(this.lastUrl)
+          this.lastUrl = ''
+        }, 500)
+      }
+    },
+  },
+  mounted() {},
+  created() {
+    //this.init()
+  },
+  methods: {
+    init(str) {
+      this.ws = new WebSocket(
+        'ws://' + window.location.host + process.env.VUE_APP_BASE_API + '/VideoOverWebSocket'
+      )
+      let _this = this
+      this.ws.onmessage = function (evt) {
+        if (typeof evt.data === 'string') {
+          console.log(JSON.parse(evt.data).Msg)
+        } else {
+          let currUrl = URL.createObjectURL(evt.data)
+          if (_this.lastUrl) URL.revokeObjectURL(_this.lastUrl)
+          _this.lastUrl = currUrl
+          _this.url = currUrl
+        }
+      }
+      if (str) {
+        setTimeout(() => {
+          this.ws.send(str)
+        }, 500)
+      }
+    },
+    zoomHandler() {
+      this.zoom = this.zoom ? false : true
+    },
+    closeHandler() {
+      if (this.ws && this.ws.readyState == 1) {
+        this.ws.send(JSON.stringify({ id: '0' }))
+      }
+      setTimeout(() => {
+        this.ws.close()
+        if (this.url) URL.revokeObjectURL(this.url)
+        this.url = ''
+        this.lastUrl = ''
+        this.zoom = false
+        this.$emit('update:cameraData', {})
+        this.$emit('update:visible', false)
+      }, 500)
+    },
+    playBackHandle() {
+      this.onPlayBack = true
+      if (this.ws && this.ws.readyState == 1) {
+        let time = Dayjs(this.startTime).format('YYYY-MM-DD HH:mm:ss')
+        this.ws.send(JSON.stringify({ id: this.cameraData.id, startTime: time }))
+      } else {
+        this.init(JSON.stringify({ id: this.cameraData.id, startTime: time }))
+      }
+      setTimeout(() => {
+        this.url = ''
+        if (this.lastUrl) URL.revokeObjectURL(this.lastUrl)
+        this.lastUrl = ''
+      }, 500)
+    },
+    realTimekHandle() {
+      this.onPlayBack = false
+      this.startTime = null
+      if (this.ws && this.ws.readyState == 1) {
+        this.ws.send(
+          JSON.stringify({ id: this.cameraData.id, canControl: this.cameraData.ptzEnable })
+        )
+      } else {
+        this.init(JSON.stringify({ id: this.cameraData.id, canControl: this.cameraData.ptzEnable }))
+      }
+      setTimeout(() => {
+        this.url = ''
+        if (this.lastUrl) URL.revokeObjectURL(this.lastUrl)
+        this.lastUrl = ''
+      }, 500)
+    },
+    ptzCommHandle(comm, stop) {
+      if (this.ws && this.ws.readyState == 1) {
+        this.ws.send(
+          JSON.stringify({
+            id: this.cameraData.id,
+            canControl: true,
+            ptzCommand: comm,
+            ptzStop: stop,
+            ptzSpeed: this.speed,
+          })
+        )
+      } else {
+        this.init(
+          JSON.stringify({
+            id: this.cameraData.id,
+            canControl: true,
+            ptzCommand: comm,
+            ptzStop: stop,
+            ptzSpeed: this.speed,
+          })
+        )
+      }
+    },
+    ptzPresetHandle(comm) {
+      if (this.ws && this.ws.readyState == 1) {
+        this.ws.send(
+          JSON.stringify({
+            id: this.cameraData.id,
+            canControl: true,
+            ptzPreset: comm,
+            ptzPresetIndex: this.presetIndex,
+          })
+        )
+      } else {
+        this.init(
+          JSON.stringify({
+            id: this.cameraData.id,
+            canControl: true,
+            ptzPreset: comm,
+            ptzPresetIndex: this.presetIndex,
+          })
+        )
+      }
+    },
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+.dialog-container {
+  position: absolute;
+  right: 20px;
+  bottom: 20px;
+  z-index: 5;
+  color: white;
+  background-color: #10316b;
+  // background-color: rgba(48, 65, 86, 0.8);
+  box-sizing: border-box;
+  border-radius: 20px;
+}
+.dialog-header {
+  position: absolute;
+  left: 20px;
+  top: 0px;
+  right: 20px;
+  height: 40px;
+  font-size: 20px;
+  padding-top: 10px;
+  float: left;
+}
+.close-icon {
+  margin-left: 10px;
+  float: right;
+}
+.close-icon:hover {
+  color: #368ae8;
+  // color: rgb(28, 188, 156);
+}
+.zoom-icon {
+  float: right;
+}
+.zoom-icon:hover {
+  color: #368ae8;
+  // color: rgb(28, 188, 156);
+}
+.dialog-body {
+  position: absolute;
+  left: 20px;
+  top: 40px;
+  right: 20px;
+  bottom: 20px;
+}
+.ptz-panel {
+  position: absolute;
+  top: 0px;
+  right: 0px;
+  bottom: 0px;
+  width: 150px;
+}
+.playback-panel {
+  position: absolute;
+  left: 0px;
+  right: 0px;
+  bottom: 0px;
+  height: 50px;
+  padding-top: 15px;
+}
+::v-deep .image-slot {
+  width: 100%;
+  height: 100%;
+  background-color: #063e92;
+  color: #909399;
+  font-size: 30px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+</style>

+ 1713 - 0
src/views/robotSLG/robot/components/map/index.vue

@@ -0,0 +1,1713 @@
+<template>
+  <div>
+    <div id="map" class="map-container"></div>
+    <!-- <countarea-panel
+      :buildid="tbuildId"
+      :countdic="countDic"
+      :show="buildData ? buildData.CountareaPanelOpen : false"
+      v-if="buildData ? buildData.CountareaPanelDisplay : false"
+    ></countarea-panel> -->
+    <image-video :cameraData.sync="cameraData" :visible.sync="cameraVisible"></image-video>
+  </div>
+</template>
+
+<script>
+import 'maptalks/dist/maptalks.css'
+import * as maptalks from 'maptalks'
+import * as mqtt from 'mqtt'
+import { getMQTTCilentId } from '@/utils/mqtt'
+import {
+  getRailListJson,
+  getAreaListJson,
+  getCameraListJson,
+  getPerimeterListJson,
+} from '@/api/positioning/map'
+import CountareaPanel from '@/components/CountareaPanel'
+import ImageVideo from '@/components/ImageVideo'
+
+import {
+  getRobotList,
+  getRecognizeList,
+  getAreaTree,
+  getNaviList,
+  getPositionList,
+  getSenceList,
+  getTaskList,
+  getRobotToken,
+  getPatrolRecordList,
+  getAlarmList,
+  getRealtimeList,
+} from '@/api/robotSLG/public'
+
+export default {
+  name: 'Map',
+  components: { CountareaPanel, ImageVideo },
+  data() {
+    return {
+      locationData: null,
+      baseRelativeCoordinate0: null,
+      baseRelativeCoordinate1: null,
+      baseRelativeExtent: null,
+      baseGPSCoordinate0: null,
+      baseGPSCoordinate1: null,
+      baseGPSExtent: null,
+      baseExtent: null,
+      //
+      buildNo: 0, //默认建筑编号,和建筑数据内容在数组中的下标一致
+      buildPanelPos: 0,
+      floorNo: 0, //默认楼层编号,和楼层数据在FloorList数组的下标一致
+      floorPanelPos: 0,
+      floorNoArray: [], //楼层数据,需为数组格式(接口参数规定)
+      postExtent: null,
+      //
+      buildData: null,
+      //
+      map: null,
+      mapLayer: null,
+      personLayer: null,
+      railLayer: null,
+      railAlarmLayer: null,
+      cameraLayer: null,
+      perimeterLayer: null,
+      perimeterAlarmLayer: null,
+      historyLayer: null,
+      //巡检机器人增加
+      robotNavLayer: null,
+      robotLayer: null,
+      //
+      debugPanel: null,
+      floorPanel: null,
+      buildPanel: null,
+
+      mqttClient: null,
+      topicArray: [],
+      topicCount: null,
+
+      areaList: [],
+      perimeterList: [],
+
+      personAlarm: {},
+      railAlarm: {},
+      areaAlarm: {},
+      arearailAlarm: {},
+      alarmingPerson: [],
+      alarmingRail: [],
+      countDic: {},
+
+      cameraData: {},
+      cameraVisible: false,
+
+      //机器人修改
+      robotToken: '',
+      patrolRecord: [],
+      realltimeData: [],
+      naviList: [],
+      runningTaskList: [],
+    }
+  },
+  computed: {
+    VUE_APP_BASE_API() {
+      return process.env.VUE_APP_BASE_API
+    },
+    VUE_APP_BASE_WS() {
+      return 'ws://' + window.location.host + process.env.VUE_APP_BASE_API
+    },
+    tbuildId() {
+      return this.buildData ? this.buildData.BuildId || '' : ''
+    },
+  },
+  created() {
+    window.moveBuildPanel = this.moveBuildPanel
+    window.changeBuild = this.changeBuild
+    window.moveFloorPanel = this.moveFloorPanel
+    window.changeFloor = this.changeFloor
+    //机器人相关
+    this.initRobotInfo().then(() => {
+      this.getNaviListOption().then(() => {
+        this.addRobotNav() //添加机器人
+        this.getRunningTask()
+      })
+      // 获取正在执行巡检任务
+      setInterval(() => {
+        if (this.runningTask == null || this.runningTask.id === '23') {
+          console.log('寻找执行中任务')
+          this.getRunningTask()
+        }
+      }, 5000)
+    })
+  },
+  mounted() {
+    this.$nextTick(async (_) => {
+      await this.getLocationData()
+    })
+    this.$nextTick(() => {
+      if (this.$route.query.type) {
+        this.railLayer.show()
+      }
+    })
+  },
+  beforeDestroy() {
+    this.mqttClient?.end()
+  },
+  methods: {
+    // 机器人登录获取token
+    async initRobotInfo() {
+      try {
+        let res = await getRobotToken(ROBOT)
+        if (res.code === 1) {
+          this.robotToken = res.data
+        }
+      } catch (error) {}
+    },
+    //机器人最新巡检记录实时信息
+    async getPatrolRealltimeROption() {
+      try {
+        let res = await getRealtimeList({
+          token: this.robotToken,
+          pageIndex: 1,
+          pageSize: 100,
+          robotId: this.patrolRecord.id,
+        })
+        if (res.code === 1) {
+          this.realltimeData = res.data.list
+          console.log('实时信息')
+          console.log(this.realltimeData)
+        } else {
+          this.initRobotInfo()
+        }
+        PatrolR
+      } catch (error) {}
+    },
+
+    //机器人导航点数据
+    async getNaviListOption() {
+      try {
+        let res = await getNaviList({ token: this.robotToken, pageIndex: 1, pageSize: 100 })
+        if (res.code === 1) {
+          this.naviList = res.data.list
+          //设置添加所有导航点并隐藏
+          this.setNavPointList()
+        } else {
+          this.initRobotInfo()
+        }
+      } catch (error) {}
+    },
+    //机器人正在执行任务
+    async getRunningTask() {
+      try {
+        let res = await getTaskList({
+          token: this.robotToken,
+          pageIndex: 1,
+          pageSize: 10,
+          state: 'RUNNING',
+          // titleList: '20230519120000',
+        })
+        if (res.code === 1) {
+          if (res.data.list && res.data.list.length > 0) {
+            this.runningTaskList = res.data.list[0]
+            // console.log(this.runningTaskList)
+            if (this.runningTaskList.id !== '23') {
+              //更新地图为巡检任务点
+              this.showTaskPoint()
+              //实时获取任务对应巡检记录更新导航点状态
+              this.getPatrolRecordROption(this.runningTaskList)
+            }
+          }
+        } else {
+          this.initRobotInfo()
+        }
+      } catch (error) {}
+    },
+    //机器人最新巡检记录
+    async getPatrolRecordROption(c) {
+      // console.log(c);
+      try {
+        let res = await getPatrolRecordList({
+          token: this.robotToken,
+          pageIndex: 1,
+          pageSize: 100,
+          taskIdList: [c.id],
+          // taskIdList: ["4121"],
+        })
+        if (res.code === 1) {
+          this.patrolRecord = res.data.list[0]
+          console.log('记录信息')
+          console.log(this.patrolRecord)
+          //根据最新巡检记录更新导航点状态
+          this.updateTaskPointState()
+          // this.chengeRobot(this.)
+          this.getPatrolRealltimeROption()
+        } else {
+          this.initRobotInfo()
+        }
+        PatrolR
+      } catch (error) {}
+    },
+    //导航图层添加所有导航点
+    setNavPointList() {
+      this.robotNavLayer.clear()
+      if (this.naviList) {
+        this.naviList.forEach((check) => {
+          var m = new maptalks.Marker(
+            this.getNewCoordinate(+check.coordinateY * 100, +check.coordinateX * 100),
+            {
+              id: check.id,
+              visible: false,
+              symbol: {
+                markerFile: this.VUE_APP_BASE_API + '/../static/images/waitP.svg',
+                markerWidth: 40,
+                markerHeight: 40,
+                markerDx: 0,
+                markerDy: 20,
+              },
+              properties: {
+                id: check.id,
+                name: check.alias,
+                data: check,
+              },
+            }
+          ).addTo(this.robotNavLayer)
+          m.on('click', '')
+        })
+      }
+      return m
+    },
+    //显示任务点
+    showTaskPoint() {
+      if (this.runningTaskList) {
+        this.runningTaskList.positionList.forEach((a) => {
+          let p = this.robotNavLayer.getGeometryById(a.naviId)
+          // console.log(p)
+          p.options.visible = true
+        })
+      }
+    },
+    //更新任务状态
+    updateTaskPointState() {
+      if (this.patrolRecord) {
+        let p = this.robotNavLayer.getGeometryById(this.patrolRecord.naviId)
+        // console.log(p)
+        p.updateSymbol({
+          markerFile: this.VUE_APP_BASE_API + '/../static/images/finishP.svg',
+          markerWidth: 40,
+          markerHeight: 40,
+          markerDx: 0,
+          markerDy: 20,
+        })
+
+        return marker
+      }
+    },
+    //初始化机器人位置
+    addRobotNav() {
+      //获取一个初始点
+      if (this.naviList) {
+        let p = this.naviList[0]
+        let marker = new maptalks.Marker(
+          this.getNewCoordinate(+p.coordinateY * 100, +p.coordinateX * 100),
+          {
+            id: p.Id,
+            visible: true,
+            symbol: [
+              {
+                markerFile: this.VUE_APP_BASE_API + '/../static/images/robot.svg',
+                // markerFile: this.VUE_APP_BASE_API + '/../static/images/waitP.svg',
+                markerWidth: 40,
+                markerHeight: 40,
+                markerDx: 0,
+                markerDy: 20,
+                textName: p.alias,
+                textDx: 0,
+                textDy: 20,
+              },
+              {
+                textName: '',
+                textWeight: 'bold',
+                textStyle: 'normal',
+                textSize: 0,
+                textFill: '#FF0000',
+                textOpacity: 1,
+                textDx: 0,
+                textDy: -20,
+              },
+            ],
+            properties: {
+              id: p.Id,
+              name: p.alias,
+            },
+          }
+        ).addTo(this.robotLayer)
+        return marker
+      }
+      // marker.setInfoWindow({
+      //   title: person.Name,
+      //   width: 300,
+      //   autoCloseOn: 'click contextmenu',
+      //   content:
+      //     '<table width = "100%" style="border-bottom: 0px solid rgb(231, 234, 236) !important">\
+      //                   <tr>\
+      //                     <td width = "40%" rowspan="5" align="center">\
+      //                       <img src="' +
+      //     (person.PhotoPath
+      //       ? this.VUE_APP_BASE_API + person.PhotoPath
+      //       : 'static/images/default.png') +
+      //     '" style="width: 85px; height: 140px; object-fit: contain"/>\
+      //                     </td>\
+      //                     <td class="tdname">类型:</td>\
+      //                     <td class="tddata">' +
+      //     person.TypeName +
+      //     '</td>\
+      //                   <tr>\
+      //                     <td class="tdname">部门:</td>\
+      //                     <td class="tddata">' +
+      //     person.DepartmentName +
+      //     '</td>\
+      //                   </tr>\
+      //                   <tr>\
+      //                     <td class="tdname">职位:</td>\
+      //                     <td class="tddata">' +
+      //     person.PositionName +
+      //     '</td>\
+      //                   </tr>\
+      //                   <tr>\
+      //                     <td class="tdname">电话:</td>\
+      //                     <td class="tddata">' +
+      //     person.Telephone +
+      //     '</td>\
+      //                   </tr>\
+      //                   <tr>\
+      //                     <td class="tdname">SN:</td>\
+      //                     <td class="tddata">' +
+      //     person.LabelMAC +
+      //     '</td>\
+      //                   </tr>\
+      //                   <tr style="height:10px"/>\
+      //                </table>',
+      // })
+
+      // this.personAlarming(person.Id)
+    },
+    //
+    chengeRobot(robot) {
+      let p = this.robotLayer.getGeometryById(robot.naviId)
+      if (p) {
+        p.animate(
+          {
+            translate: this.getRobotOffset(p, robot),
+          },
+          {
+            duration: 1000,
+          }
+        )
+      } else {
+        this.addRobotNav(robot)
+      }
+    },
+    //机器人移动
+    getRobotOffset(geometry, robot) {
+      let start = geometry.getCoordinates()
+      let end = this.getNewCoordinate(+robot.coordinateY * 100, +robot.coordinateX * 100)
+      return end.sub(start)
+    },
+    //地图初始化数据
+    async getLocationData() {
+      this.locationData = this.$setting
+
+      if (this.locationData) {
+        this.buildNo = this.locationData.DefaultBuild // 默认建筑(在BuildList数组的位置)
+        this.buildData = this.locationData.BuildList[this.buildNo] //默认建筑数据
+        this.mapBaseLayer = this.locationData.MapBaseLayer //地图底图
+
+        this.floorNo = this.buildData.DefaultFloor //默认楼层(在FloorList数组的位置)
+
+        if (this.buildData.FloorList[this.floorNo].No instanceof Array) {
+          // 楼层数据,数组格式
+          this.floorNoArray = this.buildData.FloorList[this.floorNo].No
+        } else {
+          this.floorNoArray = [this.buildData.FloorList[this.floorNo].No]
+        }
+
+        this.baseRelativeCoordinate0 = new maptalks.Coordinate(this.buildData.RelativeCoordinate0) //左上角相对坐标,单位:毫米
+        this.baseRelativeCoordinate1 = new maptalks.Coordinate(this.buildData.RelativeCoordinate1) //右下角相对坐标,单位:毫米
+        //Extent 表示地图上的边界框,一个具有最小和最大坐标的矩形经纬度
+        // baseRelativeExtent 生成了一个相对坐标的边界矩形
+        this.baseRelativeExtent = new maptalks.Extent(
+          this.baseRelativeCoordinate0,
+          this.baseRelativeCoordinate1
+        )
+
+        if (this.buildData.MultiMap) {
+          //同一个服务器上是否有同一个BuildId的多个地图
+          this.postExtent = [
+            this.baseRelativeCoordinate0.x,
+            this.baseRelativeCoordinate0.y,
+            this.baseRelativeCoordinate1.x,
+            this.baseRelativeCoordinate1.y,
+          ]
+        } else {
+          this.postExtent = null
+        }
+
+        if (this.buildData.Projection == 'identity') {
+          // Projection 地图投影  值为EPSG:3857
+          // baseExtent  生成一个GPS坐标的矩形
+          this.baseExtent = new maptalks.Extent(
+            new maptalks.Coordinate(0, 0),
+            new maptalks.Coordinate(
+              this.baseRelativeCoordinate1.x - this.baseRelativeCoordinate0.x,
+              this.baseRelativeCoordinate0.y - this.baseRelativeCoordinate1.y
+            )
+          )
+        } else {
+          // GPSCoordinate0  左上角GPS坐标(WGS84) x:经度 y:纬度
+          // GPSCoordinate1  右下角GPS坐标(WGS84) x:经度 y:纬度
+          this.baseGPSCoordinate0 = new maptalks.Coordinate(this.buildData.GPSCoordinate0)
+          this.baseGPSCoordinate1 = new maptalks.Coordinate(this.buildData.GPSCoordinate1)
+          this.baseGPSExtent = new maptalks.Extent(this.baseGPSCoordinate0, this.baseGPSCoordinate1)
+          this.baseExtent = this.baseGPSExtent
+        }
+        await this.createMap()
+      } else {
+        console.log('获取定位配置文件失败')
+      }
+    },
+    async createMap() {
+      let zoom, maxZoom, minZoom, baseLayer, resolution0, resolutionMax
+
+      if (this.buildData.Projection == 'identity') {
+        zoom = this.buildData.RelativeMapZoom // 相对坐标地图缩放
+        maxZoom = this.buildData.RelativeMapMaxZoom //相对坐标地图最大缩放
+        minZoom = this.buildData.RelativeMapMinZoom //相对坐标地图最小缩放
+        resolution0 = this.buildData.RelativeResolution0 //相对坐标地图最大分辨率
+        resolutionMax = this.buildData.RelativeResolutionMax //相对坐标地图最大分辨率倍数
+        baseLayer = null
+      } else {
+        zoom = this.buildData.GPSMapZoom //GPS地图缩放
+        maxZoom = this.buildData.GPSMapMaxZoom //GPS地图最大缩放
+        minZoom = this.buildData.GPSMapMinZoom //GPS地图最小缩放
+        resolution0 = this.buildData.GPSResolution0 //GPS地图最大分辨率
+        resolutionMax = this.buildData.GPSResolutionMax //GPS地图最大分辨率倍数
+        baseLayer = new maptalks.TileLayer('base', this.mapBaseLayer) //地图来源
+      }
+
+      if (this.map) this.map.remove()
+      this.map = new maptalks.Map('map', {
+        center: this.baseExtent.getCenter(), //地图中点
+        //centerCross: true,
+        zoom: zoom,
+        maxZoom: maxZoom,
+        minZoom: minZoom,
+        bearing: this.buildData.MapBearing, //地图旋转角度
+        pitch: this.buildData.MapPitch, //地图倾斜角度
+        maxExtent: this.baseExtent, //地图最大范围,平移超出范围会反弹回来
+        zoomControl: {
+          // 缩放控件
+          position: 'top-left',
+          slider: false,
+          zoomLevel: false,
+        },
+        scaleControl: true, //比例尺控件
+        spatialReference: {
+          // Map 的空间引用,默认使用的是google的地图投影 EPSG: 3857
+          projection: this.buildData.Projection,
+          resolutions: (function () {
+            const resolutions = []
+            for (let i = 0; i <= resolutionMax; i++) {
+              resolutions[i] = resolution0 / Math.pow(2, i)
+            }
+            return resolutions
+          })(),
+        },
+        baseLayer: baseLayer, //基础图层
+      })
+      //将地图设置为适合给定范围的最大缩放级别
+      this.map.fitExtent(this.baseExtent, 0)
+      // 图片图层
+      this.mapLayer = new maptalks.ImageLayer(
+        'map',
+        [
+          {
+            url: this.buildData.FloorList[this.floorNo].MapPath,
+            extent: this.baseExtent,
+            opacity: 1,
+          },
+        ],
+        {
+          forceRenderOnMoving: true,
+          forceRenderOnZooming: true,
+          forceRenderOnRotating: true,
+        }
+      ).addTo(this.map)
+      // 矢量图层
+      this.robotNavLayer = new maptalks.VectorLayer('robotNav', {
+        zIndex: 2,
+        forceRenderOnMoving: true,
+        forceRenderOnZooming: true,
+        forceRenderOnRotating: true,
+      }).addTo(this.map)
+
+      this.robotLayer = new maptalks.VectorLayer('robot', {
+        zIndex: 1,
+        forceRenderOnMoving: true,
+        forceRenderOnZooming: true,
+        forceRenderOnRotating: true,
+      }).addTo(this.map)
+
+      this.personLayer = new maptalks.VectorLayer('person', {
+        zIndex: 100,
+        forceRenderOnMoving: true,
+        forceRenderOnZooming: true,
+        forceRenderOnRotating: true,
+      }).addTo(this.map)
+
+      this.cameraLayer = new maptalks.VectorLayer('camera', {
+        zIndex: 10,
+        visible: this.buildData.CameraLayerDisplay,
+        forceRenderOnMoving: true,
+        forceRenderOnZooming: true,
+        forceRenderOnRotating: true,
+      }).addTo(this.map)
+
+      this.railLayer = new maptalks.VectorLayer('rail', {
+        zIndex: 1,
+        visible: false,
+        forceRenderOnMoving: true,
+        forceRenderOnZooming: true,
+        forceRenderOnRotating: true,
+      }).addTo(this.map)
+
+      this.railAlarmLayer = new maptalks.VectorLayer('railAlarm', {
+        zIndex: 2,
+        visible: true,
+        forceRenderOnMoving: true,
+        forceRenderOnZooming: true,
+        forceRenderOnRotating: true,
+      }).addTo(this.map)
+
+      this.perimeterLayer = new maptalks.VectorLayer('perimeter', {
+        zIndex: 3,
+        visible: true,
+        forceRenderOnMoving: true,
+        forceRenderOnZooming: true,
+        forceRenderOnRotating: true,
+      }).addTo(this.map)
+
+      this.perimeterAlarmLayer = new maptalks.VectorLayer('perimeterAlarm', {
+        zIndex: 40,
+        visible: true,
+        forceRenderOnMoving: true,
+        forceRenderOnZooming: true,
+        forceRenderOnRotating: true,
+      }).addTo(this.map)
+
+      this.historyLayer = new maptalks.VectorLayer('history', {
+        zIndex: 20,
+        forceRenderOnMoving: true,
+        forceRenderOnZooming: true,
+        forceRenderOnRotating: true,
+      }).addTo(this.map)
+      // 右上角工具栏
+      let _this = this
+      new maptalks.control.Toolbar({
+        items: [
+          {
+            item: '复位地图',
+            click: function () {
+              _this.map.animateTo(
+                {
+                  //center: baseExtent.getCenter(),
+                  //zoom: 13,
+                  bearing: _this.buildData.MapBearing,
+                  pitch: _this.buildData.MapPitch,
+                },
+                {
+                  duration: 1000,
+                },
+                (frame) => {
+                  if (frame.state.playState === 'finished') {
+                    _this.map.fitExtent(_this.baseExtent, 0, {
+                      duration: 1000,
+                    })
+                  }
+                }
+              )
+            },
+          },
+          // {
+          //   item: '围栏',
+          //   children: [
+          //     {
+          //       item: '显示',
+          //       click: function () {
+          //         _this.railLayer.show()
+          //       },
+          //     },
+          //     {
+          //       item: '隐藏',
+          //       click: function () {
+          //         _this.railLayer.hide()
+          //       },
+          //     },
+          //   ],
+          // },
+          // {
+          //   item: '摄像头',
+          //   children: [
+          //     {
+          //       item: '显示',
+          //       click: function () {
+          //         _this.cameraLayer.show()
+          //       },
+          //     },
+          //     {
+          //       item: '隐藏',
+          //       click: function () {
+          //         _this.cameraLayer.hide()
+          //       },
+          //     },
+          //   ],
+          // },
+        ],
+      }).addTo(this.map)
+      // 右下角信息栏
+      if (this.buildData.DebugPanelDisplay) {
+        this.debugPanel = new maptalks.control.Panel({
+          position: 'bottom-right',
+          draggable: false,
+          custom: true,
+          content: '<div class="map-debugpanel">hello </div>',
+          closeButton: false,
+        }).addTo(this.map)
+
+        this.map.on('click', (e) => this.update(e))
+      }
+      // 楼层控制器
+      if (this.buildData.FloorPanelDisplay) {
+        this.createFloorPanel()
+      }
+      // 地图选择器
+      // if (this.locationData.BuildPanelDisplay) {
+      //   this.createBuildPanel()
+      // }
+
+      // await this.getRail()
+      // await this.getArea()
+      // await this.getCamera()
+      // await this.getPerimeter()
+      // this.getLocation()
+
+      this.startMQTT()
+
+      // if (!this.interval1)
+      //   this.interval1 = setInterval(() => {
+      //     //this.getLocation()
+      //     this.getRailAlarm()
+      //   }, 1000)
+      // 点选重叠图形
+      this.map.on('contextmenu', (e) => this.identifyAndSelect(e))
+    },
+    //开始MQTT接收
+    startMQTT() {
+      this.personAlarm = {}
+      this.railAlarm = {}
+      this.areaAlarm = {}
+      this.arearailAlarm = {}
+      this.alarmingPerson = []
+      this.alarmingRail = []
+
+      this.topicArray.splice(0)
+      this.floorNoArray.forEach((f) => {
+        this.topicArray.push('Positioning/Positioning/' + this.buildData.BuildId + '/' + f + '/#')
+        this.topicArray.push('Positioning/Alarm/Person/' + this.buildData.BuildId + '/' + f + '/#')
+        this.topicArray.push('Positioning/Alarm/Rail/' + this.buildData.BuildId + '/' + f + '/#')
+      })
+      this.topicArray.push('Positioning/Alarm/Rail/' + this.buildData.BuildId + '/0/#')
+      this.topicArray.push('Positioning/Alarm/Area/' + this.buildData.BuildId + '/#')
+      this.topicArray.push('Perimeter/' + this.buildData.BuildId + '/0/#')
+      this.topicArray.push('Perimeter/#')
+      this.topicCount = 'CountArea/CountDic/' + this.buildData.BuildId
+
+      if (this.mqttClient && this.mqttClient.connected) {
+        this.mqttClient.subscribe(this.topicArray)
+        this.mqttClient.subscribe(this.topicCount)
+        return
+      }
+
+      // 连接选项
+      const options = {
+        clean: true, // true: 清除会话, false: 保留会话
+        keepalive: 60,
+        connectTimeout: 4000, // 超时时间
+        // 认证信息
+        clientId: getMQTTCilentId('map'),
+        username: 'client',
+        password: '19c9547ad2029be96774fce5f1b9f099',
+      }
+      const connectUrl = this.VUE_APP_BASE_WS + '/MQTTOverWebSocket'
+      //console.log(connectUrl)
+      this.mqttClient = mqtt.connect(connectUrl, options)
+
+      let _this = this
+      this.mqttClient.on('connect', function () {
+        //订阅主题
+        console.log('定位MQTT正在连接')
+        _this.mqttClient.subscribe(_this.topicArray)
+        _this.mqttClient.subscribe(_this.topicCount)
+      })
+      this.mqttClient.on('message', (topic, message) => {
+        if (topic == 'Online') {
+          console.log('定位MQTT收到消息:', topic, message.toString())
+        } else if (topic.startsWith('Positioning/Positioning/')) {
+          this.chengePerson(JSON.parse(message.toString()))
+          //console.log(JSON.parse(message.toString()))
+        } else if (topic.startsWith('Positioning/Alarm/')) {
+          let alarm = JSON.parse(message.toString())
+          switch (alarm.AlarmSource) {
+            case 1:
+              this.personAlarm[alarm.Id] = alarm.AlarmList
+              this.personAlarming(alarm.Id)
+              break
+            case 2:
+              this.railAlarm[alarm.Id] = alarm.AlarmList
+              this.railAlarming(alarm.Id)
+              break
+            case 3:
+              this.areaAlarm[alarm.Id] = alarm.AlarmList
+              let area = this.areaList.find((v) => v.id == alarm.Id)
+              if (area && area.railIds && area.railIds.length > 0) {
+                area.railIds.forEach((a) => {
+                  if (this.arearailAlarm[a]) {
+                    if (alarm.AlarmList.length > 0) {
+                      if (this.arearailAlarm[a].indexOf(area.id) == -1)
+                        this.arearailAlarm[a].push(area.id)
+                    } else {
+                      let i = this.arearailAlarm[a].indexOf(area.id)
+                      if (i >= 0) this.arearailAlarm[a].splice(i, 1)
+                    }
+                  } else {
+                    this.arearailAlarm[a] = []
+                    if (alarm.AlarmList.length > 0) this.arearailAlarm[a].push(area.id)
+                  }
+                  this.railAlarming(a)
+                })
+              }
+              break
+            default:
+              break
+          }
+        } else if (topic.startsWith('CountArea/CountDic/')) {
+          let count = JSON.parse(message.toString())
+          this.countDic = count
+        } else if (topic.startsWith('Perimeter/')) {
+          let perimeter = JSON.parse(message.toString())
+          if (
+            perimeter.buildId == this.buildData.BuildId &&
+            (this.floorNoArray.indexOf(perimeter.floorNo) > -1 || perimeter.FloorNo == 0)
+          ) {
+            //console.log(perimeter)
+            this.chengePerimeter(perimeter)
+          }
+        }
+      })
+    },
+    chengePerson(person) {
+      if (person.Display == 1) {
+        let p = this.personLayer.getGeometryById(person.Id)
+        if (p) {
+          this.personMove(p, person)
+        } else {
+          this.addPerson(person)
+        }
+      } else {
+        let p = this.personLayer.getGeometryById(person.Id)
+        if (p) {
+          p.remove()
+        }
+      }
+    },
+    chengePerimeter(perimeter) {
+      let s = this.perimeterLayer.getGeometryById(perimeter.segmentId)
+      if (!s) s = this.addPerimeter(perimeter.segmentId)
+      if (s) {
+        switch (perimeter.alarmType) {
+          case 0: //无报警
+            s.setSymbol({
+              lineColor: '#00ff00',
+              lineWidth: 4,
+              lineOpacity: 1,
+            })
+            break
+          case 1: //离线
+            s.setSymbol({
+              lineColor: '#ababab',
+              lineWidth: 4,
+              lineOpacity: 1,
+            })
+            break
+          case 2: //警告
+            s.setSymbol({
+              lineColor: '#00ff00',
+              lineWidth: 4,
+              lineOpacity: 1,
+            })
+            s.openInfoWindow()
+            break
+          case 3: //报警
+            s.setSymbol({
+              lineColor: '#00ff00',
+              lineWidth: 4,
+              lineOpacity: 1,
+            })
+            s.openInfoWindow()
+            break
+          default:
+            break
+        }
+        this.changPerimeterAlarm(perimeter.segmentId, perimeter.alarmType, perimeter.camera)
+      }
+    },
+    addPerimeter(id) {
+      let perimeter
+      let segment
+      for (let p in this.perimeterList) {
+        perimeter = this.perimeterList[p]
+        segment = perimeter.segments.find((b) => b.id == id)
+        if (segment) break
+      }
+      let s
+      if (perimeter && segment) {
+        s = new maptalks.LineString(
+          segment.points.map((p) => this.getNewCoordinate(p.x, p.y)),
+          {
+            id: segment.id,
+            symbol: {
+              lineColor: '#00ff00',
+              lineWidth: 4,
+              lineOpacity: 1,
+            },
+            properties: {
+              id: segment.id,
+              name: perimeter.name + '分段' + segment.code,
+            },
+          }
+        )
+          .addTo(this.perimeterLayer)
+          .setInfoWindow({
+            width: 150,
+            content: perimeter.name + '分段' + segment.code,
+          })
+      }
+      return s
+    },
+    changPerimeterAlarm(id, alarmType, camera) {
+      let color
+      switch (alarmType) {
+        case 0: //无报警
+          return
+        case 1: //离线
+          return
+        case 2: //警告
+          color = '#ffff00'
+          break
+        case 3: //报警
+          color = '#ff0000'
+          break
+        default:
+          break
+      }
+      let g = this.perimeterAlarmLayer.getGeometryById(id)
+      if (g) {
+        if (g.getSymbol().lineColor == '#ff0000') color = '#ff0000'
+        g.setSymbol({
+          lineColor: color,
+          lineWidth: 6,
+          lineOpacity: 1,
+        })
+        return
+      }
+      let perimeter
+      let segment
+      for (let p in this.perimeterList) {
+        perimeter = this.perimeterList[p]
+        segment = perimeter.segments.find((b) => b.id == id)
+        if (segment) break
+      }
+      if (perimeter && segment) {
+        let s = new maptalks.LineString(
+          segment.points.map((p) => this.getNewCoordinate(p.x, p.y)),
+          {
+            id: segment.id,
+            symbol: {
+              lineColor: color,
+              lineWidth: 6,
+              lineOpacity: 1,
+            },
+          }
+        ).addTo(this.perimeterAlarmLayer)
+        s.on('click', (param) => this.perimeterAlarmLayer.removeGeometry(param.target))
+        setTimeout(() => this.flashPerimeterAlarm(id), 500)
+
+        if (alarmType == 2 || alarmType == 3) {
+          this.cameraVisible = true
+          this.cameraData = camera
+        }
+      }
+    },
+    flashPerimeterAlarm(id) {
+      let g = this.perimeterAlarmLayer.getGeometryById(id)
+      if (g) {
+        let s = g.getSymbol()
+        s.lineOpacity = s.lineOpacity == 1 ? 0 : 1
+        if (g) {
+          g.setSymbol(s)
+          setTimeout(() => this.flashPerimeterAlarm(id), 500)
+        }
+      }
+    },
+    // 获取围栏
+    async getRail() {
+      this.railLayer.clear()
+      this.railAlarmLayer.clear()
+      let params = {
+        BuildId: this.buildData.BuildId,
+        FloorNoArray: this.floorNoArray,
+        Extent: this.postExtent,
+        // riskLevelArray: [1, 2, 3, 4] //四色图参数
+      }
+      try {
+        let res = await getRailListJson(params)
+        let data = res.data.content
+        if (data.length > 0) {
+          data.forEach((r) => {
+            let inExtent = true
+            let points = []
+            r.points.forEach((p) => {
+              if (!this.baseRelativeExtent.contains(new maptalks.Coordinate(p.x, p.y)))
+                inExtent = false
+              points.push(this.getNewCoordinate(p.x, p.y))
+            })
+            if (inExtent) {
+              this.railLayer.addGeometry(
+                new maptalks.Polygon(points, {
+                  symbol: {
+                    lineColor: 'rgb(0,196,240)',
+                    lineWidth: 2,
+                    lineOpacity: 1,
+                    polygonFill: 'rgb(135,196,240)',
+                    polygonOpacity: 0.6,
+                  },
+                })
+              )
+              this.railAlarmLayer.addGeometry(
+                new maptalks.Polygon(points, {
+                  id: r.id,
+                  visible: false,
+                  symbol: {
+                    lineColor: '#C06173',
+                    lineWidth: 2,
+                    lineOpacity: 1,
+                    polygonFill: '#E08193',
+                    polygonOpacity: 0.6,
+                  },
+                })
+              )
+              this.railAlarming(r.id)
+            }
+          })
+        }
+      } catch (error) {
+        console.log(error)
+        this.$message.error(error)
+      }
+    },
+    // 获取摄像头
+    async getCamera() {
+      this.cameraLayer.clear()
+      let params = {
+        buildId: this.buildData.BuildId,
+        floorNoArray: this.floorNoArray,
+        extent: this.postExtent,
+      }
+      try {
+        let res = await getCameraListJson(params)
+        let data = res.data.content
+        if (data.length > 0) {
+          data.forEach((c) => {
+            var m = new maptalks.Marker(this.getNewCoordinate(c.location.x, c.location.y), {
+              id: c.id,
+              visible: true,
+              symbol: {
+                markerFile: this.VUE_APP_BASE_API + c.iconPath,
+                markerWidth: 40,
+                markerHeight: 40,
+                markerDx: 0,
+                markerDy: 20,
+              },
+              properties: {
+                id: c.id,
+                name: c.name,
+                data: c,
+              },
+            }).addTo(this.cameraLayer)
+            m.on('click', this.cameraClickHandler)
+          })
+        }
+      } catch (error) {
+        console.log(error)
+        this.$message.error(error)
+      }
+    },
+    cameraClickHandler(param) {
+      let c = param.target.getProperties()
+      this.cameraVisible = true
+      this.cameraData = c.data
+    },
+    // 获取区域
+    async getArea() {
+      let params = {
+        BuildId: this.buildData.BuildId,
+        // riskLevelArray: [1, 2, 3, 4] //四色图参数
+      }
+      try {
+        let res = await getAreaListJson(params)
+        let data = res.data.content
+        this.areaList = data
+      } catch (error) {
+        console.log(error)
+        this.$message.error(error)
+      }
+    },
+    // 获取周界
+    async getPerimeter() {
+      this.perimeterLayer.clear()
+      this.perimeterAlarmLayer.clear()
+      this.perimeterList = []
+      let params = {
+        BuildId: this.buildData.BuildId,
+        FloorNoArray: this.floorNoArray,
+        Extent: this.postExtent,
+      }
+      try {
+        let res = await getPerimeterListJson(params)
+        let data = res.data.content
+        if (data.length > 0) {
+          this.perimeterList = data
+        }
+      } catch (error) {
+        console.log(error)
+        this.$message.error(error)
+      }
+    },
+    // 创建地图选择按钮模块
+    createBuildPanel() {
+      if (this.buildNo <= 1) {
+        this.buildPanelPos = 0
+      } else if (this.buildNo >= this.locationData.BuildList.length - 3) {
+        this.buildPanelPos = this.locationData.BuildList.length - 3
+      } else {
+        this.buildPanelPos = this.buildNo - 1
+      }
+
+      let mapdiv = document.getElementById('map')
+      let mapdivh = mapdiv.clientHeight || mapdiv.offsetHeight
+
+      this.buildPanel = new maptalks.control.Panel({
+        position: { top: mapdivh / 2 - 60, left: '20' },
+        draggable: false,
+        custom: true,
+        content: this.makeBuildPanelContent(),
+        closeButton: false,
+      }).addTo(this.map)
+    },
+    // 左下按钮页面内容生成
+    makeBuildPanelContent() {
+      let content
+      content = '<table class="map-buildpanel" cellpadding="0" frame=void rules=none>'
+      content +=
+        '<tr><td><button onclick="moveBuildPanel(0)"><div class="up-arrows"></div></button></td></tr>'
+      for (let i = this.buildPanelPos; i <= this.buildPanelPos + 2; i++) {
+        if (i == this.buildNo) {
+          content +=
+            '<tr><td><button style="background: rgb(28,188,156);">' +
+            this.locationData.BuildList[i].BuildAbbName +
+            '</button></td></tr>'
+        } else {
+          if (this.locationData.BuildList[i]) {
+            content +=
+              '<tr><td><button onclick="changeBuild(' +
+              i +
+              ')">' +
+              this.locationData.BuildList[i].BuildAbbName +
+              '</button></td></tr>'
+          } else {
+            content += '<tr><td><button></button></td></tr>'
+          }
+        }
+      }
+
+      content +=
+        '<tr><td><button onclick="moveBuildPanel(1)"><div class="down-arrows"></div></button></td></tr>'
+      content += '</table>'
+      return content
+    },
+    // 点击地图按钮上下箭头
+    moveBuildPanel(s) {
+      let b = this.buildPanelPos
+      if (s == 0) {
+        if (b > 0) b--
+      } else if (s == 1) {
+        if (b < this.buildData.FloorList.length - 3) b++
+      }
+      if (b != this.buildPanelPos) {
+        this.buildPanelPos = b
+        this.buildPanel.setContent(this.makeBuildPanelContent())
+      }
+    },
+    // 切换地图按钮操作
+    changeBuild(b) {
+      this.buildNo = b
+      this.buildPanel.setContent(this.makeBuildPanelContent())
+
+      this.buildData = this.locationData.BuildList[this.buildNo]
+
+      this.floorNo = this.buildData.DefaultFloor
+      if (this.buildData.FloorList[this.floorNo].No instanceof Array) {
+        this.floorNoArray = this.buildData.FloorList[this.floorNo].No
+      } else {
+        this.floorNoArray = [this.buildData.FloorList[this.floorNo].No]
+      }
+
+      this.baseRelativeCoordinate0 = new maptalks.Coordinate(this.buildData.RelativeCoordinate0)
+      this.baseRelativeCoordinate1 = new maptalks.Coordinate(this.buildData.RelativeCoordinate1)
+      this.baseRelativeExtent = new maptalks.Extent(
+        this.baseRelativeCoordinate0,
+        this.baseRelativeCoordinate1
+      )
+
+      if (this.buildData.MultiMap) {
+        this.postExtent = [
+          this.baseRelativeCoordinate0.x,
+          this.baseRelativeCoordinate0.y,
+          this.baseRelativeCoordinate1.x,
+          this.baseRelativeCoordinate1.y,
+        ]
+      } else {
+        this.postExtent = null
+      }
+
+      if (this.buildData.Projection == 'identity') {
+        this.baseExtent = new maptalks.Extent(
+          new maptalks.Coordinate(0, 0),
+          new maptalks.Coordinate(
+            this.baseRelativeCoordinate1.x - this.baseRelativeCoordinate0.x,
+            this.baseRelativeCoordinate0.y - this.baseRelativeCoordinate1.y
+          )
+        )
+      } else {
+        this.baseGPSCoordinate0 = new maptalks.Coordinate(this.buildData.GPSCoordinate0)
+        this.baseGPSCoordinate1 = new maptalks.Coordinate(this.buildData.GPSCoordinate1)
+        this.baseGPSExtent = new maptalks.Extent(this.baseGPSCoordinate0, this.baseGPSCoordinate1)
+        this.baseExtent = this.baseGPSExtent
+      }
+
+      if (this.mqttClient && this.mqttClient.connected) {
+        if (this.topicArray && this.topicArray.length > 0) {
+          this.topicArray.push(this.topicCount)
+          this.mqttClient.unsubscribe(this.topicArray, () => {
+            if (this.personLayer) this.personLayer.clear()
+            this.createMap()
+          })
+          return
+        }
+      }
+
+      this.createMap()
+    },
+    // 创建右下楼层切换按钮模块
+    createFloorPanel() {
+      if (this.floorNo <= 1) {
+        this.floorPanelPos = 0
+      } else if (this.floorNo >= this.buildData.FloorList.length - 3) {
+        this.floorPanelPos = this.buildData.FloorList.length - 3
+      } else {
+        this.floorPanelPos = this.floorNo - 1
+      }
+
+      let mapdiv = document.getElementById('map')
+      let mapdivh = mapdiv.clientHeight || mapdiv.offsetHeight
+
+      if (this.floorPanel) this.floorPanel.remove()
+
+      this.floorPanel = new maptalks.control.Panel({
+        position: { top: mapdivh / 2 - 60, right: '20' },
+        draggable: false,
+        custom: true,
+        content: this.makeFloorPanelContent(),
+        closeButton: false,
+      }).addTo(this.map)
+    },
+    // 楼层选择按钮模块页面内容生成
+    makeFloorPanelContent() {
+      let content
+      content = '<table class="map-floorpanel" cellpadding="0" frame=void rules=none>'
+      content +=
+        '<tr><td><button onclick="moveFloorPanel(0)"><div class="up-arrows"></div></button></td></tr>'
+      for (let i = this.floorPanelPos; i <= this.floorPanelPos + 2; i++) {
+        if (i == this.floorNo) {
+          content +=
+            '<tr><td><button style="background: rgb(28,188,156)">' +
+            this.buildData.FloorList[i].Name +
+            '</button></td></tr>'
+        } else {
+          if (this.buildData.FloorList[i]) {
+            content +=
+              '<tr><td><button onclick="changeFloor(' +
+              i +
+              ')">' +
+              this.buildData.FloorList[i].Name +
+              '</button></td></tr>'
+          } else {
+            content += '<tr><td><button></button></td></tr>'
+          }
+        }
+      }
+
+      content +=
+        '<tr><td><button onclick="moveFloorPanel(1)"><div class="down-arrows"></div></button></td></tr>'
+      content += '</table>'
+      return content
+    },
+    // 点击切换楼层按钮上下箭头
+    moveFloorPanel(s) {
+      let f = this.floorPanelPos
+      if (s == 0) {
+        if (f > 0) f--
+      } else if (s == 1) {
+        if (f < this.buildData.FloorList.length - 3) f++
+      }
+      if (f != this.floorPanelPos) {
+        this.floorPanelPos = f
+        this.floorPanel.setContent(this.makeFloorPanelContent())
+      }
+    },
+    // 点击切换楼层
+    changeFloor(f) {
+      this.floorNo = f
+      this.floorPanel.setContent(this.makeFloorPanelContent())
+
+      if (this.buildData.FloorList[this.floorNo].No instanceof Array) {
+        this.floorNoArray = this.buildData.FloorList[this.floorNo].No
+      } else {
+        this.floorNoArray = [this.buildData.FloorList[this.floorNo].No]
+      }
+
+      if (this.mqttClient && this.mqttClient.connected) {
+        if (this.topicArray && this.topicArray.length > 0)
+          this.mqttClient.unsubscribe(this.topicArray, () => {
+            if (this.personLayer) this.personLayer.clear()
+            this.startMQTT()
+          })
+      }
+
+      this.mapLayer.setImages([
+        {
+          url: this.buildData.FloorList[this.floorNo].MapPath,
+          extent: this.baseExtent,
+          opacity: 1,
+        },
+      ])
+      this.getRail()
+      this.getCamera()
+    },
+    // 右下角信息栏显示内容生成
+    update(e) {
+      let projection = this.map.getProjection()
+      let coordinate = e.coordinate,
+        prj = projection.project(coordinate)
+
+      this.debugPanel.setContent(
+        '<div class="map-debugpanel">' +
+          [
+            'Coordinate : [' + coordinate.x.toFixed(5) + ', ' + coordinate.y.toFixed(5) + ']',
+            'Projected Coordinate : [' + prj.x.toFixed(5) + ', ' + prj.y.toFixed(5) + ']',
+            'Zoom : ' + this.map.getZoom(),
+          ].join('<br>') +
+          '</div>'
+      )
+    },
+
+    addPerson(person) {
+      let marker = new maptalks.Marker(
+        this.getNewCoordinate(person.Positioning.X, person.Positioning.Y),
+        {
+          id: person.Id,
+          visible: true,
+          symbol: [
+            {
+              markerFile: this.VUE_APP_BASE_API + person.IconPath,
+              markerWidth: 40,
+              markerHeight: 40,
+              markerDx: 0,
+              markerDy: 20,
+              textName: person.Name,
+              textDx: 0,
+              textDy: 20,
+            },
+            {
+              textName: '',
+              textWeight: 'bold',
+              textStyle: 'normal',
+              textSize: 0,
+              textFill: '#FF0000',
+              textOpacity: 1,
+              textDx: 0,
+              textDy: -20,
+            },
+          ],
+          properties: {
+            id: person.Id,
+            name: person.Name,
+          },
+        }
+      ).addTo(this.personLayer)
+      marker.setInfoWindow({
+        title: person.Name,
+        width: 300,
+        autoCloseOn: 'click contextmenu',
+        content:
+          '<table width = "100%" style="border-bottom: 0px solid rgb(231, 234, 236) !important">\
+                        <tr>\
+                          <td width = "40%" rowspan="5" align="center">\
+                            <img src="' +
+          (person.PhotoPath
+            ? this.VUE_APP_BASE_API + person.PhotoPath
+            : 'static/images/default.png') +
+          '" style="width: 85px; height: 140px; object-fit: contain"/>\
+                          </td>\
+                          <td class="tdname">类型:</td>\
+                          <td class="tddata">' +
+          person.TypeName +
+          '</td>\
+                        <tr>\
+                          <td class="tdname">部门:</td>\
+                          <td class="tddata">' +
+          person.DepartmentName +
+          '</td>\
+                        </tr>\
+                        <tr>\
+                          <td class="tdname">职位:</td>\
+                          <td class="tddata">' +
+          person.PositionName +
+          '</td>\
+                        </tr>\
+                        <tr>\
+                          <td class="tdname">电话:</td>\
+                          <td class="tddata">' +
+          person.Telephone +
+          '</td>\
+                        </tr>\
+                        <tr>\
+                          <td class="tdname">SN:</td>\
+                          <td class="tddata">' +
+          person.LabelMAC +
+          '</td>\
+                        </tr>\
+                        <tr style="height:10px"/>\
+                     </table>',
+      })
+
+      this.personAlarming(person.Id)
+
+      return marker
+    },
+    personMove(geometry, person) {
+      geometry.animate(
+        {
+          translate: this.getOffset(geometry, person),
+        },
+        {
+          duration: 1000,
+        }
+      )
+    },
+    personAlarming(personId, repeat = false) {
+      let p = this.personLayer.getGeometryById(personId)
+      let pa = this.personAlarm[personId]
+
+      if (p) {
+        if (pa && pa.length > 0) {
+          if (!repeat) {
+            if (this.alarmingPerson.indexOf(personId) >= 0) return
+            else this.alarmingPerson.push(personId)
+          }
+
+          let str = ''
+          pa.forEach((v) => {
+            switch (v.AlarmType) {
+              case 11:
+                str += '越界(进入),'
+                break
+              case 12:
+                str += '越界(离开),'
+                break
+              case 20:
+                str += '滞留,'
+                break
+              case 50:
+                str += '静止,'
+                break
+              case 60:
+                str += 'SOS,'
+                break
+              default:
+                break
+            }
+          })
+          str = str.substr(0, str.length - 1)
+          if (p.getSymbol()[1].textName != str) {
+            p.updateSymbol([{}, { textName: str }])
+          }
+
+          if (p.getSymbol()[1].textSize == 0) {
+            p.updateSymbol([{}, { textSize: 16 }])
+          } else {
+            p.updateSymbol([{}, { textSize: 0 }])
+          }
+
+          setTimeout(() => {
+            this.personAlarming(personId, true)
+          }, 500)
+        } else {
+          let index = this.alarmingPerson.indexOf(personId)
+          if (index >= 0) this.alarmingPerson.splice(index, 1)
+          p.updateSymbol([{}, { textSize: 0 }])
+        }
+      }
+    },
+    railAlarming(railId, repeat = false) {
+      let r = this.railAlarmLayer.getGeometryById(railId)
+      let ra = this.railAlarm[railId]
+      let aa = this.arearailAlarm[railId]
+
+      if (r) {
+        if ((ra && ra.length > 0) || (aa && aa.length > 0)) {
+          if (!repeat) {
+            if (this.alarmingRail.indexOf(railId) >= 0) return
+            else this.alarmingRail.push(railId)
+          }
+
+          if (r.isVisible()) r.hide()
+          else r.show()
+          setTimeout(() => {
+            this.railAlarming(railId, true)
+          }, 500)
+        } else {
+          let index = this.alarmingRail.indexOf(railId)
+          if (index >= 0) this.alarmingRail.splice(index, 1)
+          r.hide()
+        }
+      }
+    },
+    getOffset(geometry, person) {
+      let start = geometry.getCoordinates()
+      let end = this.getNewCoordinate(person.Positioning.X, person.Positioning.Y)
+      return end.sub(start)
+    },
+    getNewCoordinate(x, y) {
+      if (this.buildData.Projection == 'identity') {
+        return new maptalks.Coordinate(
+          x - this.baseRelativeCoordinate0.x,
+          this.baseRelativeCoordinate0.y - y
+        )
+      } else {
+        return this.map.locate(
+          this.baseGPSCoordinate0,
+          (x - this.baseRelativeCoordinate0.x) / 1000,
+          -(y - this.baseRelativeCoordinate0.y) / 1000
+        )
+      }
+    },
+    identifyAndSelect(e) {
+      let _this = this
+      //identify
+      this.map.identify(
+        {
+          coordinate: e.coordinate,
+          layers: [this.personLayer, this.cameraLayer, this.perimeterLayer],
+        },
+        function (geos) {
+          if (geos.length === 0) {
+            _this.map.removeMenu()
+            return
+          }
+          var options = { items: [] }
+          geos.forEach(function (g) {
+            var personN = g.getProperties().name
+            options.items.push({
+              item: personN,
+              click: function () {
+                // console.log(g.toJSON());
+                //g.openInfoWindow()
+                g.fire('click')
+              },
+            })
+          })
+          _this.map.setMenu(options).openMenu(e.coordinate)
+        }
+      )
+    },
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+.map-container {
+  width: 100%;
+  height: calc(64vh - 98px);
+}
+::v-deep #title {
+  width: 100%;
+  height: 50px;
+  display: table;
+  text-align: center;
+  background-color: #3c8dbc;
+  p {
+    margin: auto;
+    display: table-cell;
+    vertical-align: middle;
+    text-align: center;
+    color: white;
+    font-family: SimHei, STHeiti;
+    font-size: 25px;
+    font-weight: bold;
+    letter-spacing: 5px;
+  }
+}
+
+::v-deep .page-main {
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  overflow-y: auto;
+}
+
+::v-deep .left {
+  width: 20%;
+  height: 100%;
+  float: left;
+  background-color: #101c45;
+}
+
+::v-deep .right {
+  width: 20%;
+  height: 100%;
+  float: left;
+  background-color: #101c45;
+}
+
+::v-deep .map {
+  width: 100%;
+  height: 100%;
+  height: calc(100vh - 84px);
+  float: left;
+}
+
+::v-deep .map-debugpanel {
+  background: rgba(135, 196, 240, 0.8);
+  width: 450px;
+  height: 120px;
+  border: 2px #fff solid;
+  padding: 10px;
+  color: #fff;
+}
+
+::v-deep .map-debugpanel input {
+  color: #bbb;
+}
+
+::v-deep .map-debugpanel a {
+  color: #fff;
+  float: right;
+  margin-right: 15px;
+}
+
+::v-deep .map-floorpanel {
+  background: rgb(52, 73, 94);
+  width: 40px;
+  height: 120px;
+  padding: 0px;
+  color: #fff;
+  border: 0px solid rgb(231, 234, 236) !important;
+}
+
+::v-deep .map-floorpanel tr {
+  text-align: center;
+  height: 30px;
+}
+
+::v-deep .map-floorpanel td {
+  text-align: center;
+  height: 30px;
+}
+
+::v-deep .map-floorpanel button {
+  width: 40px;
+  height: 30px;
+  border: none;
+  background: rgb(52, 73, 94);
+  color: #fff;
+}
+
+::v-deep .map-buildpanel {
+  background: rgb(52, 73, 94);
+  width: 40px;
+  height: 120px;
+  padding: 0px;
+  color: #fff;
+  border: 0px solid rgb(231, 234, 236) !important;
+}
+
+::v-deep .map-buildpanel tr {
+  text-align: center;
+  height: 30px;
+}
+
+::v-deep .map-buildpanel td {
+  text-align: center;
+  height: 30px;
+}
+
+::v-deep .map-buildpanel button {
+  width: 40px;
+  height: 30px;
+  border: none;
+  background: rgb(52, 73, 94);
+  color: #fff;
+  font-size: 14px;
+  cursor: pointer;
+}
+
+::v-deep .up-arrows {
+  width: 0;
+  height: 0;
+  border-bottom: 20px solid white;
+  border-left: 10px solid transparent;
+  border-right: 10px solid transparent;
+  position: absolute;
+  left: 50%;
+  transform: translate(-50%, -50%);
+}
+
+::v-deep .down-arrows {
+  width: 0;
+  height: 0;
+  border-top: 20px solid white;
+  border-left: 10px solid transparent;
+  border-right: 10px solid transparent;
+  position: absolute;
+  left: 50%;
+  transform: translate(-50%, -50%);
+}
+</style>

+ 776 - 652
src/views/robotSLG/robot/index.vue

@@ -1,368 +1,283 @@
 <template>
-  <div class="app-container">
-    <!--工具栏-->
-    <div class="head-container">
-      <div v-if="crud.props.searchToggle">
-        <el-input
-          v-model="query.code"
-          clearable
-          size="small"
-          placeholder="输入可视对讲编号"
-          style="width: 160px"
-          class="filter-item"
-          @keyup.enter.native="crud.toQuery"
-        />
-        <el-input
-          v-model="query.name"
-          clearable
-          size="small"
-          placeholder="输入可视对讲名称"
-          style="width: 160px"
-          class="filter-item"
-          @keyup.enter.native="crud.toQuery"
-        />
-        <el-select
-          v-model="query.type"
-          filterable
-          clearable
-          size="small"
-          placeholder="请选择类型"
-          class="filter-item"
-          style="width: 160px"
-          @change="crud.toQuery"
-        >
-          <el-option
-            v-for="item in optionsObj.VisualIntercomType"
-            :key="item.value"
-            :label="item.label"
-            :value="+item.value"
-          />
-        </el-select>
-        <el-select
-          v-model="query.buildId"
-          filterable
-          clearable
-          size="small"
-          placeholder="请选择建筑名称"
-          class="filter-item"
-          style="width: 160px"
-          @change="handleChangeBuildId"
-        >
-          <el-option
-            v-for="item in optionsObj.Build"
-            :key="item.value"
-            :label="item.label"
-            :value="item.value"
-          />
-        </el-select>
-        <el-select
-          v-model="query.floorNo"
-          filterable
-          clearable
-          size="small"
-          placeholder="请选择楼层"
-          class="filter-item"
-          style="width: 160px"
-          @change="crud.toQuery"
-        >
-          <el-option
-            v-for="item in optionsObj.FloorNo"
-            :key="item.value"
-            :label="item.label"
-            :value="item.value"
-          />
-        </el-select>
-        <el-select
-          v-model="query.faceRecognition"
-          clearable
-          size="small"
-          placeholder="人脸识别"
-          class="filter-item"
-          style="width: 160px"
-          @change="crud.toQuery"
-        >
-          <el-option
-            v-for="item in 2"
-            :key="item"
-            :label="item == '1' ? '是' : '否'"
-            :value="item == '1' ? true : false"
-          />
-        </el-select>
-        <el-select
-          v-model="query.enable"
-          clearable
-          size="small"
-          placeholder="启用状态"
-          class="filter-item"
-          style="width: 160px"
-          @change="crud.toQuery"
-        >
-          <el-option
-            v-for="item in 2"
-            :key="item"
-            :label="item == '1' ? '启用' : '禁用'"
-            :value="item == '1' ? true : false"
-          />
-        </el-select>
-        <rrOperation />
+  <div class="monitor-container">
+    <div class="top">
+      <div class="top-left">
+        <div class="top-left-top">
+          <Container2 :setting="setting.top_left_top">
+            <div class="video-kjg" v-show="cameraVisible1">
+              <!-- <image-video
+                :cameraData.sync="cameraKJG"
+                :visible.sync="cameraVisible1"
+              ></image-video> -->
+            </div>
+          </Container2>
+        </div>
+        <div class="top-left-bottom">
+          <Container2 :setting="setting.top_left_bottom">
+            <div class="video-hw" v-show="cameraVisible1">
+              <!-- <image-video :cameraData.sync="cameraHW" :visible.sync="cameraVisible1"></image-video> -->
+            </div>
+          </Container2>
+        </div>
+      </div>
+      <div class="top-center">
+        <div class="map">
+          <Map name="robot-map"></Map>
+        </div>
+      </div>
+      <div class="top-right">
+        <Container2 :setting="setting.top_right">
+          <div class="alarm-container">
+            <ul class="mete-top">
+              <li>
+                <div title="849.70 Hpa "><label>气压:</label><span>849.70 Hpa</span></div>
+              </li>
+              <li>
+                <div title="2.56 m/s "><label>风速:</label><span>2.56 m/s</span></div>
+              </li>
+              <li>
+                <div title="东北 "><label>风向:</label><span>东北</span></div>
+              </li>
+              <li>
+                <div title="58.07 mm "><label>累计雨量:</label><span>58.07 mm</span></div>
+              </li>
+            </ul>
+            <ul class="mete-middle">
+              <li>
+                <div class="plate"></div>
+                <p>27.92 ℃</p>
+                <p>当前温度</p>
+              </li>
+              <li>
+                <div class="plate"></div>
+                <p>18.62 %RH</p>
+                <p>当前湿度</p>
+              </li>
+            </ul>
+            <ul class="mete-bottom">
+              <li>
+                <div>
+                  <div class="plate2">
+                    <p class="val">0</p>
+                    <p class="unit">%LEL</p>
+                  </div>
+                  <p class="type">CH4</p>
+                </div>
+              </li>
+              <li>
+                <div>
+                  <div class="plate3">
+                    <p class="val">0</p>
+                    <p class="unit">ppm</p>
+                  </div>
+                  <p class="type">CO</p>
+                </div>
+              </li>
+              <li>
+                <div>
+                  <div class="plate2">
+                    <p class="val">0</p>
+                    <p class="unit">ppm</p>
+                  </div>
+                  <p class="type">H2S</p>
+                </div>
+              </li>
+              <li>
+                <div>
+                  <div class="plate3">
+                    <p class="val">0</p>
+                    <p class="unit">ppm</p>
+                  </div>
+                  <p class="type">SO2</p>
+                </div>
+              </li>
+              <li>
+                <div>
+                  <div class="plate2">
+                    <p class="val">0</p>
+                    <p class="unit">%VOL</p>
+                  </div>
+                  <p class="type">O2</p>
+                </div>
+              </li>
+              <li>
+                <div>
+                  <div class="plate3">
+                    <p class="val">--</p>
+                    <p class="unit">%LEL</p>
+                  </div>
+                  <p class="type">激光CH4</p>
+                </div>
+              </li>
+            </ul>
+          </div>
+        </Container2>
       </div>
-      <crudOperation :permission="permission" />
     </div>
-    <!-- 表单组件 -->
-    <el-dialog
-      append-to-body
-      :close-on-click-modal="false"
-      :before-close="crud.cancelCU"
-      :visible.sync="crudCU"
-      :title="crud.status.title"
-      width="1200px"
-    >
-      <el-row :gutter="40">
-        <el-col :span="8">
-          <el-form ref="form" :model="form" :rules="rules" size="small" label-width="100px">
-            <el-form-item label="编号" prop="code">
-              <el-input v-model="form.code" size="small" class="filter-item" style="width: 280px" />
-            </el-form-item>
-            <el-form-item label="名称" prop="name">
-              <el-input v-model="form.name" size="small" class="filter-item" style="width: 280px" />
-            </el-form-item>
-            <el-form-item label="类型" prop="type">
-              <el-select v-model="form.type" size="small" class="filter-item" style="width: 280px">
-                <el-option
-                  v-for="item in optionsObj.VisualIntercomType"
-                  :key="item.value"
-                  :label="item.label"
-                  :value="+item.value"
-                />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="建筑名称" prop="buildId">
-              <el-select
-                v-model="form.buildId"
-                size="small"
-                class="filter-item"
-                style="width: 280px"
-                disabled
-              >
-                <el-option
-                  v-for="item in optionsObj.Build"
-                  :key="item.value"
-                  :label="item.label"
-                  :value="item.value"
-                />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="楼层" prop="floorNo">
-              <el-input
-                v-model="form.floorNo"
-                size="small"
-                class="filter-item"
-                style="width: 280px"
-                disabled
-              />
-            </el-form-item>
-            <el-form-item label="高度" prop="height">
-              <el-input
-                v-model="form.height"
-                size="small"
-                class="filter-item"
-                style="width: 280px"
-              />
-            </el-form-item>
-            <el-form-item label="序列号" prop="sn">
-              <el-input v-model="form.sn" size="small" class="filter-item" style="width: 280px" />
-            </el-form-item>
-            <el-form-item label="MAC地址" prop="mac">
-              <el-input v-model="form.mac" size="small" class="filter-item" style="width: 280px" />
-            </el-form-item>
-            <el-form-item label="ip地址" prop="ip">
-              <el-input v-model="form.ip" size="small" class="filter-item" style="width: 280px" />
-            </el-form-item>
-            <el-form-item label="端口号" prop="port">
-              <el-input v-model="form.port" size="small" class="filter-item" style="width: 280px" />
-            </el-form-item>
-            <el-form-item label="用户名" prop="userName">
-              <el-input
-                v-model="form.userName"
-                size="small"
-                class="filter-item"
-                style="width: 280px"
-              />
-            </el-form-item>
-            <el-form-item label="密码" prop="password">
-              <el-input
-                v-model="form.password"
-                show-password
-                size="small"
-                class="filter-item"
-                style="width: 280px"
-              />
-            </el-form-item>
-            <el-form-item label="关联摄像头" prop="cameraID">
-              <el-select
-                v-model="form.cameraID"
-                size="small"
-                class="filter-item"
-                style="width: 280px"
-                filterable
-                clearable
-              >
-                <el-option
-                  v-for="item in optionsObj.Camera"
-                  :key="item.value"
-                  :label="item.label"
-                  :value="item.value"
-                />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="人脸识别" prop="faceRecognition">
-              <el-switch
-                v-model="form.faceRecognition"
-                active-color="#13ce66"
-                inactive-color="#ff4949"
-                :active-value="true"
-                :inactive-value="false"
-              >
-              </el-switch>
-            </el-form-item>
-            <el-form-item label="备注" prop="remark">
-              <el-input
-                v-model="form.remark"
-                size="small"
-                class="filter-item"
-                style="width: 280px"
-              />
-            </el-form-item>
-            <el-form-item label="启用" prop="enable">
-              <el-switch
-                v-model="form.enable"
-                active-color="#13ce66"
-                inactive-color="#ff4949"
-                :active-value="true"
-                :inactive-value="false"
-              >
-              </el-switch>
-            </el-form-item>
-          </el-form>
-        </el-col>
-        <el-col :span="16">
-          <relative-map
-            v-if="crudCU"
-            ref="relativeMap"
-            v-model="mapData"
-            drawShow
-            :buildFloor="buildFloor"
-            drawMode="Point"
-          />
-        </el-col>
-      </el-row>
-
-      <div slot="footer" class="dialog-footer">
-        <el-button type="text" @click="crud.cancelCU"> 取消 </el-button>
-        <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">
-          确认
-        </el-button>
+    <div class="bottom">
+      <div class="bottom-left">
+        <Container2 :setting="setting.bottom_left">
+          <div class="robot-info">
+            <div>
+              <el-row>
+                <el-col :span="13" class="robot-info-left">
+                  <img style="width: 160px; height: 220px" />
+                </el-col>
+                <el-col :span="11" class="robot-info-right">
+                  <el-select
+                    v-model="activeRobot.id"
+                    filterable
+                    clearable
+                    size="small"
+                    placeholder="机器人"
+                    class="filter-item"
+                    style="width: 160px"
+                    @change="selectActiveRobot"
+                  >
+                    <el-option
+                      v-for="item in robotList"
+                      :key="item.id"
+                      :label="item.title"
+                      :value="item.id"
+                    />
+                  </el-select>
+                  <div>机器人名称:</div>
+                  <div>{{ activeRobot.title }}</div>
+                  <div>职能:</div>
+                  <div>{{ activeRobot.func }}</div>
+                  <div>充电状态:{{ activeRobot.deviceStatus === 1 ? '在线' : '离线' }}</div>
+                  <div>电量:{{ activeRobot.battery }}%</div>
+                  <div>速度:{{ activeRobot.speed ? activeRobot.speed : '0m/s' }}</div>
+                </el-col>
+              </el-row>
+            </div>
+          </div>
+        </Container2>
+      </div>
+      <div class="bottom-center">
+        <el-tabs class="record-list" type="border-card">
+          <el-tab-pane label="巡检记录">
+            <el-table
+              ref="table"
+              :data="patrolRecordList"
+              :key="itemKey"
+              row-key="id"
+              max-height="222"
+              :header-cell-style="{
+                background: '#2892F0',
+                color: '#fff',
+                'text-align': 'center',
+              }"
+            >
+              <el-table-column label="导航点编号" prop="naviSequence" width="100" align="center" />
+              <el-table-column label="指标名称" prop="indicatorName" align="center" />
+              <el-table-column label="巡检结果" prop="value" width="90" align="center" />
+              <el-table-column label="巡检时间" prop="patrolTime" width="180" align="center" />
+              <el-table-column label="告警等级" prop="defectGrade" width="100" align="center">
+                <template slot-scope="scope">
+                  {{ scope.row.defectGrade == 0 ? '正常' : '' }}
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-tab-pane>
+          <el-tab-pane label="最近任务">
+            <el-table
+              :data="taskList"
+              ref="table"
+              row-key="id"
+              max-height="222"
+              :header-cell-style="{
+                background: '#2892F0',
+                color: '#fff',
+                'text-align': 'center',
+              }"
+            >
+              <el-table-column label="编号" prop="id" align="center" />
+              <!-- <el-table-column label="类型" prop="type" align="center" /> -->
+              <el-table-column label="开始时间" prop="beginTime" align="center" />
+              <el-table-column label="检测总数" prop="totalNumber" align="center" />
+              <el-table-column label="正常数量" prop="finishedNumber" align="center" />
+              <el-table-column label="缺陷数量" prop="defectNumber" align="center" />
+              <el-table-column label="未识别" prop="unrecognizeNumber" align="center" />
+            </el-table>
+          </el-tab-pane>
+        </el-tabs>
       </div>
-    </el-dialog>
-    <!--表格渲染-->
-    <el-table
-      ref="table"
-      v-loading="crud.loading"
-      :data="crud.data"
-      style="width: 100%"
-      @selection-change="crud.selectionChangeHandler"
-    >
-      <el-table-column type="selection" width="55" />
-      <el-table-column
-        v-for="item in visualIntercomConfigTableOptions"
-        :key="item.prop"
-        :label="item.label"
-        :prop="item.prop"
-        :width="item.width"
-        :align="item.align"
-        :fixed="item.fixed"
-        :sortable="item.sortable"
-      >
-      </el-table-column>
-      <!--   编辑与删除   -->
-      <el-table-column
-        v-if="checkPer(['admin', 'visualintercom:config:edit', 'visualintercom:config:del'])"
-        label="操作"
-        width="130px"
-        align="center"
-        fixed="right"
-      >
-        <template slot-scope="scope">
-          <udOperation :data="scope.row" :permission="permission" />
-        </template>
-      </el-table-column>
-    </el-table>
-    <!--分页组件-->
-    <pagination />
+      <div class="bottom-right">
+        <Container2 :setting="setting.bottom_right">
+          <div class="alarm">
+            <div
+              class="alarm-item-container"
+              v-for="(item, index) in alarmList"
+              :key="index"
+              :style="{ backgroundColor: getBgColor(index) }"
+            >
+              <div>
+                {{ setAlarmInfo(item) }}
+              </div>
+            </div>
+          </div>
+        </Container2>
+      </div>
+    </div>
   </div>
 </template>
 
 <script>
-import permission from '@/directive/permission'
-import crudVisualIntercom from '@/api/visualIntercom/config'
-import { getOptions } from '@/api/visualIntercom/public'
-import CRUD, { presenter, header, form, crud } from '@crud/crud'
-// import { crudOperation, rrOperation, udOperation, pagination } from '@crud'
-import crudComps from '@crud'
-import DateRangePicker from '@/components/DateRangePicker'
-import { visualIntercomConfigTableOptions } from '../tableConfig'
+import Container2 from '@/views/robotSLG/robot/components/Container2/index.vue'
+import Device from '@/views/robotSLG/robot/components/Device/index.vue'
+import ImageVideo from '@/views/robotSLG/robot/components/ImageVideo/index.vue'
+import Map from '@/views/robotSLG/robot/components/map/index.vue'
+
 import { initData } from '@/api/data'
-//import CameraMap from './cameraMap'
-import {
-  isPosNumber,
-  isNegNumber,
-  isNumber,
-  isPosInteger,
-  isNegInteger,
-  isInteger,
-} from '@/utils/validate'
-import RelativeMap from '@/components/RelativeMap'
+import * as mqtt from 'mqtt'
+import { getMQTTCilentId } from '@/utils/mqtt'
 
-const defaultForm = {
-  id: '0',
-  code: '', //编号
-  name: '', //名称
-  type: '',
-  buildId: '', //建筑ID
-  floorNo: null, //楼层号
-  location: null, //坐标
-  height: 0, //高度
-  faceRecognition: false,
-  enable: true, //是否显示在GIS
-  sn: '', //序列号
-  mac: '', //mac地址
-  ip: '', //ip地址
-  port: '', //端口号
-  userName: '', //用户名
-  password: '', // 密码
-  cameraID: '', // 绑定摄像头
-  remark: '', //备注
-}
+import {
+  getRobotList,
+  getRecognizeList,
+  getAreaTree,
+  getNaviList,
+  getPositionList,
+  getSenceList,
+  getTaskList,
+  getRobotToken,
+  getPatrolRecordList,
+  getAlarmList,
+} from '@/api/robotSLG/public'
 
 export default {
-  name: 'Robot',
-  directives: { permission },
-  mixins: [presenter(), header(), form(defaultForm), crud()],
-  components: { ...crudComps, DateRangePicker, RelativeMap },
-  cruds() {
-    return CRUD({
-      title: '可视对讲配置',
-      url: 'visualIntercom/config/getPageListJson',
-      listOrder: [],
-      crudMethod: { ...crudVisualIntercom },
-      optShow: {
-        add: true,
-        edit: true,
-        del: true,
-        reset: true,
-        import: true,
-        export: true,
+  components: { Container2, Device, ImageVideo, Map },
+  data() {
+    return {
+      setting: {
+        top_left_top: {
+          title: '可见光',
+          // subtitle: 'DEVICE LIST',
+        },
+        top_left_bottom: {
+          title: '红外',
+          // subtitle: 'TASK INFORMATION',
+        },
+        top_right: {
+          title: '环境信息',
+          // subtitle: 'ALARM LIST',
+        },
+        bottom_left: {
+          title: '机器人',
+          // subtitle: 'GAS MONITORING',
+        },
+        bottom_center: {
+          title: '任务与巡检记录',
+          // subtitle: 'SYSTEM PARAMETER',
+        },
+        bottom_right: {
+          title: '报警信息',
+          // subtitle: 'SYSTEM STATE',
+        },
       },
+      robotUrl: '@/assets/images/dashboard/robot.png',
+      robotToken: null,
       robotList: [
         {
           id: '', //主键ID
@@ -381,105 +296,23 @@ export default {
           createTime: '', //创建时间
         },
       ],
-      recognizeTypeList: [
-        {
-          id: '', //主键ID
-          name: '', //识别类型名称
-          code: '', //编号
-          desc: '', //描述信息
-          createTime: '', //创建时间
-        },
-      ],
-      areaTree: {
+      pictureUrl: '',
+      activeRobot: {
         id: '', //主键ID
-        parentId: '', //父节点ID
-        parent: '', //父节点名称
-        path: '', //区域树路径
-        level: '', //层级
-        sort: '', //排序比重值
-        name: '', //区域名称
-        memo: '', //备注
-        editor: '', //编辑人
+        modelId: '', //模型ID
+        number: '', //设备编号
+        category: '', //设备类型
+        issueDate: '', //发售时间
+        sequence: '', //出厂号
+        title: '', //名称
+        profile: '', //头像
+        desc: '', //描述
+        func: '', //功能说明
+        battery: '', //剩余电量
+        deviceStatus: '', //设备状态
+        taskMode: '', //机器人任务执行模式
         createTime: '', //创建时间
-        subList: '', //下级区域节点
-        naviList: '', //下辖导航点
       },
-      navPointList: [
-        {
-          id: '', //主键ID
-          robotId: '', //机器人ID
-          robot: '', //机器人名称
-          mapId: '', //地图ID
-          map: '', //地图名称
-          areaId: '', //区域ID
-          area: '', //区域名称
-          alias: '', //导航点别名
-          naviType: '', //导航点类型
-          sequence: '', //导航点编号
-          coordinateX: '', //横坐标
-          coordinateY: '', //纵坐标
-          yaw: '', //航向角
-          longitude: '', //经度
-          latitude: '', //维度
-          distance: '', //与原点距离
-          chargingDeviceId: '', //充电设备ID
-          positionCount: '', //巡检点个数
-          positionList: '', //巡检点列表
-          createTime: '', //创建时间
-        },
-      ],
-      patrolPostionList: [
-        {
-          id: '', //主键ID
-          robotId: '', //机器人ID
-          mapId: '', //地图ID
-          areaId: '', //区域ID
-          area: '', //区域名称
-          naviId: '', //导航点ID
-          naviSequence: '', //导航点别名
-          indicatorId: '', //指标ID
-          indicatorName: '', //指标名称
-          categoryId: '', //指标类目ID
-          categoryName: '', //指标类目名称
-          recognizeId: '', //识别类型ID
-          recognizeName: '', //识别类型名称
-          recognizeCode: '', //识别类型编码
-          regionSequence: '', //区域编号
-          panRotateAngleLocationH: '', //云台水平算法定位转动角度
-          panRotateAngleLocationV: '', //云台垂直算法定位转动角度
-          panRotateAngleRecognizeH: '', //云台水平算法识别转动角度
-          panRotateAngleRecognizeV: '', //云台垂直算法识别转动角度
-          visibleCameraLocationZoom: '', //可见光相机算法定位变焦
-          visibleCameraLocationFocus: '', //可见光相机算法定位聚焦
-          visibleCameraRecognizeZoom: '', //可见光相机算法识别变焦
-          visibleCameraRecognizeFocus: '', //可见光相机算法识别聚焦
-          infraredCameraRadiation: '', //红外相机辐射
-          infraredCameraZoom: '', //红外相机变焦
-          infraredCameraFocus: '', //红外相机聚焦
-          infraredDistance: '', //红外线距离
-          needFillLight: '', //是否开启补光灯
-          hasObstacle: '', //是否有障碍
-          recordVoiceSecond: '', //录音时间
-          cycleTaskPicturePtzStepDegree: '', //循环拍照的步长
-          cycleRangeDegree: '', //环测范围
-          cycleIsClockwise: '', //环测旋转方向
-          cyclePtzSpeed: '', //环测转动速度
-          sceneList: '', //已设置阈值场景列表
-          resourceList: [
-            {
-              id: '', //主键ID
-              mapId: '', //地图ID
-              naviId: '', //导航点ID
-              positionId: '', //巡检点ID
-              index: '', //序号
-              type: '', //资源类型
-              url: '', //资源路径
-              createTime: '', //创建时间
-            },
-          ], //算法资源列表
-          createTime: '', //创建时间
-        },
-      ],
       taskList: [
         {
           //任务
@@ -570,117 +403,37 @@ export default {
           createTime: '', //创建时间
         },
       ],
+      naviList: [],
 
-      RobotRealtimeInfoList: [
-        {
-          id: '', //主键ID
-          orgId: '', //组织ID
-          robotId: '', //机器人ID
-          robot: '', //机器人名称
-          taskId: '', //任务ID
-          task: '', //任务名称
-          sceneId: '', //场景ID
-          scene: '', //场景名称
-          mapId: '', //地图ID
-          map: '', //地图名称
-          areaId: '', //区域ID
-          area: '', //区域名称
-          naviId: '', //导航点ID
-          naviSequence: '', //导航点编号
-          positionId: '', //巡检点ID
-          indicatorId: '', //指标ID
-          indicatorName: '', //指标名称
-          categoryId: '', //指标类目ID
-          categoryName: '', //指标类目名称
-          recognizeId: '', //识别类型ID
-          recognizeCode: '', //识别类型编码
-          recognizeName: '', //识别类型名称
-          unit: '', //单位
-          index: '', //序号
-          patrolTime: '', //巡检时间
-          recognizeState: '', //识别状态
-          thresholdId: '', //识别阈值ID
-          defectGrade: '', //缺陷等级
-          value: '', //检测值
-          detail: '', //检测值明细
-          adjustTime: '', //矫正时间
-          recognizeTime: '', //识别时间
-          modifiedGrade: '', //修正后等级
-          defectReview: '', //缺陷追溯
-          reviewMemo: '', //缺陷审核备注
-          reviewState: '', //缺陷处理状态
-          confirmTime: '', //缺陷确认时间
-          reviewerId: '', //缺陷确认人ID
-          reviewer: '', //缺陷确认人名
-          solveTime: '', //缺陷解决时间
-          solverId: '', //缺陷解决人ID
-          solver: '', //缺陷解决人名
-          guardLine: '', //警戒线
-          resourceList: [
-            {
-              id: '', //主键ID
-              orgId: '', //组织ID
-              robotId: '', //机器人ID
-              robot: '', //机器人名称
-              mapId: '', //地图ID
-              health: '', //机器人本体是否正常
-              reportTime: '', //上报时间
-              leftWheelSpeed: '', //左轮速度
-              rightWheelSpeed: '', //右轮速度
-              speed: '', //实时速度
-              angularSpeed: '', //实时角速度
-              cpuUsed: '', //CPU使用率
-              memUsed: '', //内存使用率
-              diskUsed: '', //磁盘使用率
-              batteryRatio: '', //剩余电量比率
-              batteryVolt: '', //当前电池电压
-              batteryCurrent: '', //当前电池电流
-              temperature: '', //舱内温度
-              humidity: '', //舱内湿度
-              mileage: '', //当前行驶里程
-              rotation: '', //当前旋转角度
-              direction: '', //当前行驶方向
-              distance: '', //距原点距离
-              laserDistance: '', //激光距离
-              panRotateAngleH: '', //云台水平转动角度
-              panRotateAngleV: '', //云台垂直转动角度
-              visibleFocus: '', //可见光相机焦距
-              visibleZoom: '', //可见光相机变焦
-              infraredFocus: '', //红外相机焦距
-              coordinateX: '', //横坐标
-              coordinateY: '', //纵坐标
-              yaw: '', //航向角
-              longitude: '', //经度
-              latitude: '', //维度
-              controlSysState: '', //控制系统状态
-              chargeSysState: '', //充电系统状态
-              visibleCameraState: '', //可见光相机状态
-              infraredCameraState: '', //红外相机状态
-              panState: '', //云台状态
-              bridgeState: '', //网桥状态
-              laserObstacleState: '', //激光避障器状态
-              mmwObstacleState: '', //毫米波避障器状态
-              backObstacleState: '', //后置避障器状态
-              pitObstacleState: '', //测坑避障器状态
-              wiperState: '', //雨刷状态
-              lightState: '', //补光灯状态
-              recordState: '', //录音状态
-              intercomState: '', //对讲机状态
-              eStopState: '', //急停按钮状态
-              runState: '', //机器人运行状态
-              taskMode: '', //机器人任务执行模式
-              createTime: '', //创建时间
-            },
-          ], //算法资源列表
-          createTime: '', //创建时间
-        },
-      ],
-    })
+      runningTask: null,
+
+      mqttClient: null,
+      topicArray: [],
+      currData: {},
+
+      robotInfo: [], //机器人缓存列表
+      onlineRobort: {}, //当前选中机器人
+
+      //实时报警数据
+      alarmList: [],
+
+      ///存储视频列表
+      cameraList: [],
+      //小页面视频配置
+      cameraVisible1: true,
+      cameraHW: {},
+      cameraKJG: {},
+
+      itemKey: '',
+    }
+  },
+  created() {
+    this.init()
   },
   computed: {
-    crudCU() {
-      return this.crud.status.cu > 0
-    },
+    // crudCU() {
+    //   return this.crud.status.cu > 0
+    // },
     VUE_APP_BASE_API() {
       return process.env.VUE_APP_BASE_API
     },
@@ -688,116 +441,487 @@ export default {
       return 'ws://' + window.location.host + process.env.VUE_APP_BASE_API
     },
   },
-  data() {
-    var chackHeight = (rule, value, callback) => {
-      if (!isPosNumber(value)) return callback(new Error('请输入正确的高度'))
-      return callback()
-    }
-    return {
-      visualIntercomConfigTableOptions,
-      permission: {
-        add: ['admin', 'visualintercom:config:add'],
-        edit: ['admin', 'visualintercom:config:edit'],
-        del: ['admin', 'visualintercom:config:del'],
-      },
-      rules: {
-        code: [{ required: true, message: '请选输入编号', trigger: 'blur' }],
-        name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
-        type: [{ required: true, message: '选择类型', trigger: 'blur' }],
-        buildId: [{ required: true, message: '请在地图上画点', trigger: 'blur' }],
-        floorNo: [{ required: true, message: '请在地图上画点', trigger: 'blur' }],
-        height: [{ required: true, validator: chackHeight, trigger: 'blur' }],
-        ip: [{ required: true, message: '请输入IP地址', trigger: 'blur' }],
-        userName: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
-      },
-      optionsObj: {
-        Camera: [],
-        Build: [],
-        FloorNo: [],
-        VisualIntercomType: [],
-      },
-      mapData: [],
-      buildFloor: {},
-    }
-  },
-  created() {
-    this.getOptions()
+  beforeDestroy() {
+    this.mqttClient.end()
   },
   methods: {
-    [CRUD.HOOK.beforeToAdd]() {
-      this.mapData = []
-      this.buildFloor = {}
+    init() {
+      // this.getRobotList()
+      // this.getCameraList()
+      // this.getAlarmInfo()
+      // this.startMQTT()
+      this.initRobotInfo().then(() => {
+        this.getCameraConfigOption()
+
+        this.getRobotOption()
+        this.getTaskListOption()
+        this.getPatrolRecordListOption()
+        this.getAlarmListOption()
+        //获取在执行任务并进行在执行任务实时巡检表更新
+        this.getRunningTaskListOption()
+        // setInterval(() => {
+        //   if (this.runningTask == null || this.runningTask.id === '23') {
+        //     this.getRunningTaskListOption()
+        //     console.log('123')
+        //   }
+        //   if (this.runningTask.id !== '23') {
+        //     this.getRunningPatrolRecordListOption(this.runningTask)
+        //     console.log('456')
+        //   }
+        // }, 3000)
+      })
     },
-    // 打开
-    [CRUD.HOOK.beforeToEdit]() {
-      this.mapData = [
-        {
-          buildId: this.form.buildId,
-          floorNo: this.form.floorNo,
-          geometries: [
-            {
-              type: 'Point',
-              points: [{ x: this.form.location.x, y: this.form.location.y }],
-            },
-          ],
-        },
-      ]
-      this.buildFloor = {
-        buildId: this.form.buildId,
-        floorNo: this.form.floorNo,
-      }
+    // 机器人登录获取token
+    async initRobotInfo() {
+      try {
+        let res = await getRobotToken(ROBOT)
+        console.log(res)
+        if (res.code === 1) {
+          this.robotToken = res.data
+        }
+      } catch (error) {}
     },
-    //验证前处理
-    [CRUD.HOOK.beforeValidateCU]() {
-      if (
-        this.mapData &&
-        this.mapData.length > 0 &&
-        this.mapData[0].geometries &&
-        this.mapData[0].geometries.length > 0 &&
-        this.mapData[0].geometries[0].points &&
-        this.mapData[0].geometries[0].points.length > 0
-      ) {
-        this.form.buildId = this.mapData[0].buildId
-        this.form.floorNo = this.mapData[0].floorNo
-        this.form.location = {
-          buildId: this.mapData[0].buildId,
-          floorNo: this.mapData[0].floorNo,
-          x: this.mapData[0].geometries[0].points[0].x,
-          y: this.mapData[0].geometries[0].points[0].y,
+    // 机器人获取机器人列表
+    async getRobotOption() {
+      try {
+        let res = await getRobotList({ token: this.robotToken, pageIndex: 1, pageSize: 10 })
+        if (res.code === 1) {
+          // console.log(res)
+          this.robotList = res.data.list
+          this.activeRobot = this.robotList[0]
+        } else {
+          this.initRobotInfo()
         }
-      } else {
-        this.$message.error('请绘制正确的点')
-        return false
-      }
+      } catch (error) {}
     },
-    // 提交前的验证
-    [CRUD.HOOK.afterValidateCU]() {},
-    async handleChangeBuildId(val) {
-      await this.getFloorNoOption(val)
-      this.crud.toQuery()
+    selectActiveRobot(r) {
+      this.activeRobot = r
     },
-    getOptions() {
-      Object.keys(this.optionsObj).forEach(async (key) => {
-        if (key == 'FloorNo') return
-        try {
-          let res = await getOptions(key)
-          if (res.code === 20000) this.optionsObj[key] = res.data.content
-        } catch (error) {
-          console.log(error)
+    // 获取任务列表
+    async getTaskListOption() {
+      try {
+        let res = await getTaskList({ token: this.robotToken, pageIndex: 1, pageSize: 10 })
+        if (res.code === 1) {
+          this.taskList = res.data.list
+          // console.log(this.taskList)
+        } else {
+          this.getRobotToken()
         }
-      })
+      } catch (error) {}
+    },
+    // 获取执行中任务
+    async getRunningTaskListOption() {
+      try {
+        let res = await getTaskList({
+          token: this.robotToken,
+          pageIndex: 1,
+          pageSize: 10,
+          state: 'RUNNING',
+        })
+        if (res.code === 1) {
+          this.runningTask = res.data.list[0]
+          // console.log(this.runningTask)
+        } else {
+          this.getRobotToken()
+        }
+      } catch (error) {}
+    },
+    //获取执行中任务巡检记录表
+    async getRunningPatrolRecordListOption(c) {
+      try {
+        let res = await getPatrolRecordList({
+          token: this.robotToken,
+          pageIndex: 1,
+          pageSize: 10,
+          taskIdList: [c.id],
+        })
+        if (res.code === 1) {
+          this.patrolRecordList = res.data.list
+          console.log(this.patrolRecordList)
+          this.itemKey = Math.random()
+        } else {
+          this.getRobotToken()
+        }
+      } catch (error) {}
     },
-    async getFloorNoOption(buildId) {
+    //获取巡检记录表
+    async getPatrolRecordListOption() {
       try {
-        let res = await getOptions('FloorNo', { buildId: buildId })
-        if (res.code === 20000) {
-          this.optionsObj.FloorNo = res.data.content
-          this.query.floorNo = null
+        let res = await getPatrolRecordList({ token: this.robotToken, pageIndex: 1, pageSize: 10 })
+        if (res.code === 1) {
+          this.patrolRecordList = res.data.list
+        } else {
+          this.getRobotToken()
         }
       } catch (error) {}
     },
+    //获取报警列表
+    async getAlarmListOption() {
+      try {
+        let res = await getAlarmList({ token: this.robotToken, pageIndex: 1, pageSize: 10 })
+        if (res.code === 1) {
+          this.alarmList = res.data.list
+        } else {
+          this.getRobotToken()
+        }
+      } catch (error) {}
+    },
+    // //获取导航点列表
+    // async getNaviistOption() {
+    //   try {
+    //     let res = await getNaviList({ token: this.robotToken, pageIndex: 1, pageSize: 10 })
+    //     if (res.code === 1) {
+    //       this.naviList = res.data.list
+    //     } else {
+    //       this.getRobotToken()
+    //     }
+    //   } catch (error) {}
+    // },
+
+    //获取机器人摄像头
+    async getCameraConfigOption() {
+      try {
+        let res = await initData('camera/config/getPageListJson', { name: '机器人' })
+        // console.log(res.data.content)
+        if (res && res.data && res.data.content && res.data.content.length > 1) {
+          this.cameraHW = res.data.content[0]
+          this.cameraKJG = res.data.content[1]
+        }
+      } catch (error) {}
+    },
+    //切换机器人
+    changeRobot(deviceInfo) {
+      if (deviceInfo) {
+        for (let i = 0; i < this.robotInfo.length; i++) {
+          const element = this.robotInfo[i]
+          if (element.id == deviceInfo.id) {
+            this.onlineRobort = element
+          }
+        }
+        this.getOnlineRobotInfo()
+        this.getTaskInfo()
+      }
+      // console.log(this.onlineRobort)
+    },
+    //转换报警信息
+    setAlarmInfo(i) {
+      var json = JSON.parse(i.alarmInfo)
+      return i.robot + ' 在 ' + json.category + ' 区域,检测 ' + json.indicator + ' 指标异常 '
+    },
+    //报警列表信息背景颜色
+    getBgColor(index) {
+      return index % 2 == 0 ? 'transparent' : 'rgb(15, 116, 204)'
+    },
+
+    //开始MQTT接收
+    startMQTT() {
+      // 连接选项
+      const options = {
+        clean: true, // true: 清除会话, false: 保留会话
+        keepalive: 60,
+        connectTimeout: 4000, // 超时时间
+        // 认证信息
+        clientId: getMQTTCilentId('realtimedata'),
+        username: 'client',
+        password: '19c9547ad2029be96774fce5f1b9f099',
+      }
+      const connectUrl = this.VUE_APP_BASE_WS + '/MQTTOverWebSocket'
+      //console.log(connectUrl)
+      this.mqttClient = mqtt.connect(connectUrl, options)
+
+      let _this = this
+      this.mqttClient.on('connect', function () {
+        //订阅主题
+        console.log('实时数据MQTT正在连接')
+        //if (_this.topicArray.length > 0) {
+        //_this.mqttClient.subscribe(_this.topicArray)
+        //console.log('订阅1', this.topicArray)
+        //}
+      })
+      this.mqttClient.on('message', (topic, message) => {
+        if (topic == 'Online') {
+          console.log('实时数据MQTT收到消息:', topic, message.toString())
+        } else if (topic.startsWith('DataCommunication/TagData/')) {
+          let data = JSON.parse(message.toString())
+          //console.log(JSON.parse(message.toString()))
+          Vue.set(this.currData, data.Tag, data)
+        }
+      })
+    },
+    refreshSubscribe() {
+      //console.log('refreshSubscribe')
+      this.currData = {}
+      if (this.mqttClient && this.mqttClient.connected) {
+        //console.log(this.mqttClient)
+        let newTopicArray
+        if (this.robotInfo) {
+          this.robotInfo.forEach((a) => {
+            if (a.typeExtensionData)
+              this.newTopicArray.push.apply(
+                this.newTopicArray,
+                a.typeExtensionData
+                  .filter((e) => e.isTag)
+                  .map((e) => 'DataCommunication/TagData/' + e.value)
+              )
+            if (a.extraWindowData)
+              this.newTopicArray.push.apply(
+                this.newTopicArray,
+                a.extraWindowData
+                  .filter((e) => e.isTag)
+                  .map((e) => 'DataCommunication/TagData/' + e.value)
+              )
+          })
+        }
+        // console.log(this.newTopicArray);
+        let unsubscribeTopicArray = lodash.difference(this.topicArray, newTopicArray)
+        if (unsubscribeTopicArray.length > 0) {
+          //console.log('解除订阅', unsubscribeTopicArray)
+          this.mqttClient.unsubscribe(unsubscribeTopicArray)
+        }
+        let subscribeTopicArray = lodash.difference(newTopicArray, this.topicArray)
+        if (subscribeTopicArray.length > 0) {
+          //console.log('订阅', subscribeTopicArray)
+          this.mqttClient.subscribe(subscribeTopicArray)
+        }
+        this.topicArray = newTopicArray
+      } else {
+        setTimeout(() => {
+          //console.log('setTimeout refreshSubscribe')
+          this.refreshSubscribe()
+        }, 1000)
+      }
+    },
   },
 }
 </script>
+<style>
+.app-main {
+  min-height: calc(100vh - 85px);
+}
+</style>
 
-<style></style>
+<style lang="scss" scoped>
+.monitor-container {
+  min-height: calc(100vh - 125px);
+  height: calc(100vh - 125px);
+  padding: 10px 30px 30px 30px;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+  div {
+    border: solid 0px rgb(255, 255, 255);
+    border-radius: 2px;
+    //padding: 10px;
+    //background-color: aqua;
+  }
+  .top {
+    height: calc(54vh);
+    display: flex;
+    gap: 20px;
+    .top-left {
+      width: 250px;
+      min-width: 364px;
+      height: inherit;
+      min-height: calc(20vh);
+      display: flex;
+      flex-direction: column;
+      gap: 20px;
+      .top-left-top {
+        height: 360px;
+        background-color: rgb(24, 120, 204);
+        .device-container {
+          padding: 15px;
+          .device-container-slite {
+            height: 10px;
+          }
+        }
+        .video-kjg {
+          background-color: rgb(24, 120, 204);
+          position: absolute;
+          width: 250px;
+          height: 25%;
+          min-width: 363px;
+          min-height: calc(20vh);
+          top: 6;
+          left: 10;
+          text-align: right;
+          .close {
+            margin: 10px;
+          }
+        }
+      }
+      .top-left-bottom {
+        background-color: rgb(24, 120, 204);
+        min-height: calc(25.5vh);
+        .video-hw {
+          background-color: rgb(24, 120, 204);
+          position: absolute;
+          width: 250px;
+          height: 24.5%;
+          min-width: 363px;
+          min-height: calc(20vh);
+          top: 99;
+          left: 10;
+          text-align: right;
+          .close {
+            margin: 10px;
+          }
+        }
+      }
+    }
+    .top-center {
+      width: 100%;
+      min-width: 50%;
+      background-color: rgb(24, 120, 204);
+      position: relative;
+      .map {
+        border: solid 1px rgb(24, 120, 204);
+        width: 100%;
+        height: 100%;
+      }
+    }
+    .top-right {
+      width: 370px;
+      min-width: 360px;
+      background-color: rgb(24, 120, 204);
+      .alarm-container {
+        .mete-top {
+          display: flex;
+          flex-wrap: wrap;
+          li {
+            font-size: 13px;
+            width: 50%;
+            min-width: 150px;
+            height: calc(2vh);
+            display: flex;
+          }
+        }
+        .mete-middle {
+          display: flex;
+          flex-wrap: wrap;
+          li {
+            font-size: 13px;
+            width: 50%;
+            min-width: 150px;
+            list-style-type: none;
+            .plate {
+              background-image: url(~@/assets/images/dashboard/gas/plate1.png);
+              width: 102px;
+              height: 50px;
+              background-size: 100% 100%;
+            }
+            p {
+              text-align: left;
+              margin: 0 0 0 24px;
+            }
+          }
+        }
+        .mete-bottom {
+          display: flex;
+          flex-wrap: wrap;
+          li {
+            margin-left: 10px;
+            font-size: 12px;
+            width: 45%;
+            min-width: 150px;
+            list-style-type: none;
+            .plate2 {
+              background-image: url(~@/assets/images/dashboard/gas/plate2.png);
+              width: 80px;
+              height: 80px;
+              background-size: 100% 100%;
+            }
+            .plate3 {
+              background-image: url(~@/assets/images/dashboard/gas/plate3.png);
+              width: 80px;
+              height: 80px;
+              background-size: 100% 100%;
+            }
+            .val {
+              padding: 34px 10px 10px 10px;
+              align-content: left;
+            }
+            .unit {
+              align-content: center;
+            }
+            p {
+              text-align: left;
+              margin: 1px 0 0 26px;
+            }
+          }
+        }
+      }
+    }
+  }
+  .bottom {
+    height: calc(36vh);
+    display: flex;
+    gap: 20px;
+    .bottom-left {
+      width: calc(26vw);
+      min-width: 364px;
+      // min-width: 15%;
+      background-color: rgb(24, 120, 204);
+      .robot-info {
+        padding: 10px;
+        display: flex;
+        flex-wrap: wrap;
+        gap: 22px;
+        .robot-info-left {
+          img {
+            background-image: url(~@/assets/images/dashboard/robot.png);
+            background-size: 100% 100%;
+            border: 0px;
+          }
+        }
+        .robot-info-right div {
+          font-size: 14px;
+          margin: 5px;
+        }
+      }
+    }
+    .bottom-center {
+      // width: calc(48vw);
+      // min-width: 35%;
+      height: calc(30vh);
+      min-height: calc(30vh);
+      width: 100%;
+      min-width: 53%;
+      background-color: rgb(24, 120, 204);
+      // .parameter {
+      //   padding: 24px 31px;
+      //   display: flex;
+      //   flex-wrap: wrap;
+      //   gap: 23px;
+      //   .parameter-item {
+      //     height: 32px;
+      //   }
+      // }
+      .record-list {
+        margin-bottom: 10px;
+        min-height: calc(30vh);
+      }
+    }
+    .bottom-right {
+      width: 370px;
+      min-width: 370px;
+      // min-width: 25%;
+      background-color: rgb(24, 120, 204);
+      .alarm {
+        height: calc(30vh);
+        overflow-y: scroll;
+        .alarm-item-container {
+          margin: 6px;
+          text-align: justify;
+          height: 52px;
+          padding: 8px 10px;
+          background-color: transparent;
+          font-size: 16px;
+          line-height: 22px;
+          // height: calc(100% - 30px);
+        }
+      }
+    }
+  }
+}
+</style>

+ 803 - 0
src/views/robotSLG/robot2/index.vue

@@ -0,0 +1,803 @@
+<template>
+  <div class="app-container">
+    <!--工具栏-->
+    <div class="head-container">
+      <div v-if="crud.props.searchToggle">
+        <el-input
+          v-model="query.code"
+          clearable
+          size="small"
+          placeholder="输入可视对讲编号"
+          style="width: 160px"
+          class="filter-item"
+          @keyup.enter.native="crud.toQuery"
+        />
+        <el-input
+          v-model="query.name"
+          clearable
+          size="small"
+          placeholder="输入可视对讲名称"
+          style="width: 160px"
+          class="filter-item"
+          @keyup.enter.native="crud.toQuery"
+        />
+        <el-select
+          v-model="query.type"
+          filterable
+          clearable
+          size="small"
+          placeholder="请选择类型"
+          class="filter-item"
+          style="width: 160px"
+          @change="crud.toQuery"
+        >
+          <el-option
+            v-for="item in optionsObj.VisualIntercomType"
+            :key="item.value"
+            :label="item.label"
+            :value="+item.value"
+          />
+        </el-select>
+        <el-select
+          v-model="query.buildId"
+          filterable
+          clearable
+          size="small"
+          placeholder="请选择建筑名称"
+          class="filter-item"
+          style="width: 160px"
+          @change="handleChangeBuildId"
+        >
+          <el-option
+            v-for="item in optionsObj.Build"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+        <el-select
+          v-model="query.floorNo"
+          filterable
+          clearable
+          size="small"
+          placeholder="请选择楼层"
+          class="filter-item"
+          style="width: 160px"
+          @change="crud.toQuery"
+        >
+          <el-option
+            v-for="item in optionsObj.FloorNo"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+        <el-select
+          v-model="query.faceRecognition"
+          clearable
+          size="small"
+          placeholder="人脸识别"
+          class="filter-item"
+          style="width: 160px"
+          @change="crud.toQuery"
+        >
+          <el-option
+            v-for="item in 2"
+            :key="item"
+            :label="item == '1' ? '是' : '否'"
+            :value="item == '1' ? true : false"
+          />
+        </el-select>
+        <el-select
+          v-model="query.enable"
+          clearable
+          size="small"
+          placeholder="启用状态"
+          class="filter-item"
+          style="width: 160px"
+          @change="crud.toQuery"
+        >
+          <el-option
+            v-for="item in 2"
+            :key="item"
+            :label="item == '1' ? '启用' : '禁用'"
+            :value="item == '1' ? true : false"
+          />
+        </el-select>
+        <rrOperation />
+      </div>
+      <crudOperation :permission="permission" />
+    </div>
+    <!-- 表单组件 -->
+    <el-dialog
+      append-to-body
+      :close-on-click-modal="false"
+      :before-close="crud.cancelCU"
+      :visible.sync="crudCU"
+      :title="crud.status.title"
+      width="1200px"
+    >
+      <el-row :gutter="40">
+        <el-col :span="8">
+          <el-form ref="form" :model="form" :rules="rules" size="small" label-width="100px">
+            <el-form-item label="编号" prop="code">
+              <el-input v-model="form.code" size="small" class="filter-item" style="width: 280px" />
+            </el-form-item>
+            <el-form-item label="名称" prop="name">
+              <el-input v-model="form.name" size="small" class="filter-item" style="width: 280px" />
+            </el-form-item>
+            <el-form-item label="类型" prop="type">
+              <el-select v-model="form.type" size="small" class="filter-item" style="width: 280px">
+                <el-option
+                  v-for="item in optionsObj.VisualIntercomType"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="+item.value"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="建筑名称" prop="buildId">
+              <el-select
+                v-model="form.buildId"
+                size="small"
+                class="filter-item"
+                style="width: 280px"
+                disabled
+              >
+                <el-option
+                  v-for="item in optionsObj.Build"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="楼层" prop="floorNo">
+              <el-input
+                v-model="form.floorNo"
+                size="small"
+                class="filter-item"
+                style="width: 280px"
+                disabled
+              />
+            </el-form-item>
+            <el-form-item label="高度" prop="height">
+              <el-input
+                v-model="form.height"
+                size="small"
+                class="filter-item"
+                style="width: 280px"
+              />
+            </el-form-item>
+            <el-form-item label="序列号" prop="sn">
+              <el-input v-model="form.sn" size="small" class="filter-item" style="width: 280px" />
+            </el-form-item>
+            <el-form-item label="MAC地址" prop="mac">
+              <el-input v-model="form.mac" size="small" class="filter-item" style="width: 280px" />
+            </el-form-item>
+            <el-form-item label="ip地址" prop="ip">
+              <el-input v-model="form.ip" size="small" class="filter-item" style="width: 280px" />
+            </el-form-item>
+            <el-form-item label="端口号" prop="port">
+              <el-input v-model="form.port" size="small" class="filter-item" style="width: 280px" />
+            </el-form-item>
+            <el-form-item label="用户名" prop="userName">
+              <el-input
+                v-model="form.userName"
+                size="small"
+                class="filter-item"
+                style="width: 280px"
+              />
+            </el-form-item>
+            <el-form-item label="密码" prop="password">
+              <el-input
+                v-model="form.password"
+                show-password
+                size="small"
+                class="filter-item"
+                style="width: 280px"
+              />
+            </el-form-item>
+            <el-form-item label="关联摄像头" prop="cameraID">
+              <el-select
+                v-model="form.cameraID"
+                size="small"
+                class="filter-item"
+                style="width: 280px"
+                filterable
+                clearable
+              >
+                <el-option
+                  v-for="item in optionsObj.Camera"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="人脸识别" prop="faceRecognition">
+              <el-switch
+                v-model="form.faceRecognition"
+                active-color="#13ce66"
+                inactive-color="#ff4949"
+                :active-value="true"
+                :inactive-value="false"
+              >
+              </el-switch>
+            </el-form-item>
+            <el-form-item label="备注" prop="remark">
+              <el-input
+                v-model="form.remark"
+                size="small"
+                class="filter-item"
+                style="width: 280px"
+              />
+            </el-form-item>
+            <el-form-item label="启用" prop="enable">
+              <el-switch
+                v-model="form.enable"
+                active-color="#13ce66"
+                inactive-color="#ff4949"
+                :active-value="true"
+                :inactive-value="false"
+              >
+              </el-switch>
+            </el-form-item>
+          </el-form>
+        </el-col>
+        <el-col :span="16">
+          <relative-map
+            v-if="crudCU"
+            ref="relativeMap"
+            v-model="mapData"
+            drawShow
+            :buildFloor="buildFloor"
+            drawMode="Point"
+          />
+        </el-col>
+      </el-row>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button type="text" @click="crud.cancelCU"> 取消 </el-button>
+        <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">
+          确认
+        </el-button>
+      </div>
+    </el-dialog>
+    <!--表格渲染-->
+    <el-table
+      ref="table"
+      v-loading="crud.loading"
+      :data="crud.data"
+      style="width: 100%"
+      @selection-change="crud.selectionChangeHandler"
+    >
+      <el-table-column type="selection" width="55" />
+      <el-table-column
+        v-for="item in visualIntercomConfigTableOptions"
+        :key="item.prop"
+        :label="item.label"
+        :prop="item.prop"
+        :width="item.width"
+        :align="item.align"
+        :fixed="item.fixed"
+        :sortable="item.sortable"
+      >
+      </el-table-column>
+      <!--   编辑与删除   -->
+      <el-table-column
+        v-if="checkPer(['admin', 'visualintercom:config:edit', 'visualintercom:config:del'])"
+        label="操作"
+        width="130px"
+        align="center"
+        fixed="right"
+      >
+        <template slot-scope="scope">
+          <udOperation :data="scope.row" :permission="permission" />
+        </template>
+      </el-table-column>
+    </el-table>
+    <!--分页组件-->
+    <pagination />
+  </div>
+</template>
+
+<script>
+import permission from '@/directive/permission'
+import crudVisualIntercom from '@/api/visualIntercom/config'
+import { getOptions } from '@/api/visualIntercom/public'
+import CRUD, { presenter, header, form, crud } from '@crud/crud'
+// import { crudOperation, rrOperation, udOperation, pagination } from '@crud'
+import crudComps from '@crud'
+import DateRangePicker from '@/components/DateRangePicker'
+import { visualIntercomConfigTableOptions } from '../tableConfig'
+import { initData } from '@/api/data'
+//import CameraMap from './cameraMap'
+import {
+  isPosNumber,
+  isNegNumber,
+  isNumber,
+  isPosInteger,
+  isNegInteger,
+  isInteger,
+} from '@/utils/validate'
+import RelativeMap from '@/components/RelativeMap'
+
+const defaultForm = {
+  id: '0',
+  code: '', //编号
+  name: '', //名称
+  type: '',
+  buildId: '', //建筑ID
+  floorNo: null, //楼层号
+  location: null, //坐标
+  height: 0, //高度
+  faceRecognition: false,
+  enable: true, //是否显示在GIS
+  sn: '', //序列号
+  mac: '', //mac地址
+  ip: '', //ip地址
+  port: '', //端口号
+  userName: '', //用户名
+  password: '', // 密码
+  cameraID: '', // 绑定摄像头
+  remark: '', //备注
+}
+
+export default {
+  name: 'Robot',
+  directives: { permission },
+  mixins: [presenter(), header(), form(defaultForm), crud()],
+  components: { ...crudComps, DateRangePicker, RelativeMap },
+  cruds() {
+    return CRUD({
+      title: '可视对讲配置',
+      url: 'visualIntercom/config/getPageListJson',
+      listOrder: [],
+      crudMethod: { ...crudVisualIntercom },
+      optShow: {
+        add: true,
+        edit: true,
+        del: true,
+        reset: true,
+        import: true,
+        export: true,
+      },
+      robotList: [
+        {
+          id: '', //主键ID
+          modelId: '', //模型ID
+          number: '', //设备编号
+          category: '', //设备类型
+          issueDate: '', //发售时间
+          sequence: '', //出厂号
+          title: '', //名称
+          profile: '', //头像
+          desc: '', //描述
+          func: '', //功能说明
+          battery: '', //剩余电量
+          deviceStatus: '', //设备状态
+          taskMode: '', //机器人任务执行模式
+          createTime: '', //创建时间
+        },
+      ],
+      recognizeTypeList: [
+        {
+          id: '', //主键ID
+          name: '', //识别类型名称
+          code: '', //编号
+          desc: '', //描述信息
+          createTime: '', //创建时间
+        },
+      ],
+      areaTree: {
+        id: '', //主键ID
+        parentId: '', //父节点ID
+        parent: '', //父节点名称
+        path: '', //区域树路径
+        level: '', //层级
+        sort: '', //排序比重值
+        name: '', //区域名称
+        memo: '', //备注
+        editor: '', //编辑人
+        createTime: '', //创建时间
+        subList: '', //下级区域节点
+        naviList: '', //下辖导航点
+      },
+      navPointList: [
+        {
+          id: '', //主键ID
+          robotId: '', //机器人ID
+          robot: '', //机器人名称
+          mapId: '', //地图ID
+          map: '', //地图名称
+          areaId: '', //区域ID
+          area: '', //区域名称
+          alias: '', //导航点别名
+          naviType: '', //导航点类型
+          sequence: '', //导航点编号
+          coordinateX: '', //横坐标
+          coordinateY: '', //纵坐标
+          yaw: '', //航向角
+          longitude: '', //经度
+          latitude: '', //维度
+          distance: '', //与原点距离
+          chargingDeviceId: '', //充电设备ID
+          positionCount: '', //巡检点个数
+          positionList: '', //巡检点列表
+          createTime: '', //创建时间
+        },
+      ],
+      patrolPostionList: [
+        {
+          id: '', //主键ID
+          robotId: '', //机器人ID
+          mapId: '', //地图ID
+          areaId: '', //区域ID
+          area: '', //区域名称
+          naviId: '', //导航点ID
+          naviSequence: '', //导航点别名
+          indicatorId: '', //指标ID
+          indicatorName: '', //指标名称
+          categoryId: '', //指标类目ID
+          categoryName: '', //指标类目名称
+          recognizeId: '', //识别类型ID
+          recognizeName: '', //识别类型名称
+          recognizeCode: '', //识别类型编码
+          regionSequence: '', //区域编号
+          panRotateAngleLocationH: '', //云台水平算法定位转动角度
+          panRotateAngleLocationV: '', //云台垂直算法定位转动角度
+          panRotateAngleRecognizeH: '', //云台水平算法识别转动角度
+          panRotateAngleRecognizeV: '', //云台垂直算法识别转动角度
+          visibleCameraLocationZoom: '', //可见光相机算法定位变焦
+          visibleCameraLocationFocus: '', //可见光相机算法定位聚焦
+          visibleCameraRecognizeZoom: '', //可见光相机算法识别变焦
+          visibleCameraRecognizeFocus: '', //可见光相机算法识别聚焦
+          infraredCameraRadiation: '', //红外相机辐射
+          infraredCameraZoom: '', //红外相机变焦
+          infraredCameraFocus: '', //红外相机聚焦
+          infraredDistance: '', //红外线距离
+          needFillLight: '', //是否开启补光灯
+          hasObstacle: '', //是否有障碍
+          recordVoiceSecond: '', //录音时间
+          cycleTaskPicturePtzStepDegree: '', //循环拍照的步长
+          cycleRangeDegree: '', //环测范围
+          cycleIsClockwise: '', //环测旋转方向
+          cyclePtzSpeed: '', //环测转动速度
+          sceneList: '', //已设置阈值场景列表
+          resourceList: [
+            {
+              id: '', //主键ID
+              mapId: '', //地图ID
+              naviId: '', //导航点ID
+              positionId: '', //巡检点ID
+              index: '', //序号
+              type: '', //资源类型
+              url: '', //资源路径
+              createTime: '', //创建时间
+            },
+          ], //算法资源列表
+          createTime: '', //创建时间
+        },
+      ],
+      taskList: [
+        {
+          //任务
+          id: '', //主键ID
+          periodicTaskId: '', //任务模板ID
+          orgId: '', //组织ID
+          robotId: '', //机器人Id
+          robot: '', //机器人名称
+          mapId: '', //地图ID
+          map: '', //地图名称
+          sceneId: '', //巡检场景ID
+          scene: '', //场景名称
+          title: '', //任务名称
+          type: '', //任务类型
+          taskFrom: '', //任务下发来源
+          priority: '', //任务优先级
+          exitOnPrior: '', //遇更高优先级任务提前终止
+          finalJob: '', //任务完成后指令
+          scheduleTime: '', //计划开始时间
+          beginTime: '', //任务开始时间
+          endTime: '', //任务结束时间
+          state: '', //任务状态
+          progress: '', //运行进度
+          totalNumber: '', //须检测总数
+          finishedNumber: '', //已检测总数
+          defectNumber: '', //缺陷总数
+          unrecognizeNumber: '', //未识别总数
+          areaList: '', //关联区域列表
+          positionList: '', //检测点列表
+          nextPosition: '', //当前任务下一个检测点位
+          editor: '', //编辑人
+          createTime: '', //创建时间
+        },
+      ],
+      patrolRecordList: [
+        {
+          id: '', //主键ID
+          orgId: '', //组织ID
+          robotId: '', //机器人ID
+          robot: '', //机器人名称
+          taskId: '', //任务ID
+          task: '', //任务名称
+          sceneId: '', //场景ID
+          scene: '', //场景名称
+          mapId: '', //地图ID
+          map: '', //地图名称
+          areaId: '', //区域ID
+          area: '', //区域名称
+          naviId: '', //导航点ID
+          naviSequence: '', //导航点编号
+          positionId: '', //巡检点ID
+          indicatorId: '', //指标ID
+          indicatorName: '', //指标名称
+          categoryId: '', //指标类目ID
+          categoryName: '', //指标类目名称
+          recognizeId: '', //识别类型ID
+          recognizeCode: '', //识别类型编码
+          recognizeName: '', //识别类型名称
+          unit: '', //单位
+          index: '', //序号
+          patrolTime: '', //巡检时间
+          recognizeState: '', //识别状态
+          thresholdId: '', //识别阈值ID
+          defectGrade: '', //缺陷等级
+          value: '', //检测值
+          detail: '', //检测值明细
+          adjustTime: '', //矫正时间
+          recognizeTime: '', //识别时间
+          modifiedGrade: '', //修正后等级
+          defectReview: '', //缺陷追溯
+          reviewMemo: '', //缺陷审核备注
+          reviewState: '', //缺陷处理状态
+          confirmTime: '', //缺陷确认时间
+          reviewerId: '', //缺陷确认人ID
+          reviewer: '', //缺陷确认人名
+          solveTime: '', //缺陷解决时间
+          solverId: '', //缺陷解决人ID
+          solver: '', //缺陷解决人名
+          guardLine: '', //警戒线
+          resourceList: [
+            {
+              index: '', //序号
+              type: '', //资源类型
+              originUrl: '', //原始资源路径
+              processedUrl: '', //已处理资源路径
+            },
+          ], //算法资源列表
+          createTime: '', //创建时间
+        },
+      ],
+
+      RobotRealtimeInfoList: [
+        {
+          id: '', //主键ID
+          orgId: '', //组织ID
+          robotId: '', //机器人ID
+          robot: '', //机器人名称
+          taskId: '', //任务ID
+          task: '', //任务名称
+          sceneId: '', //场景ID
+          scene: '', //场景名称
+          mapId: '', //地图ID
+          map: '', //地图名称
+          areaId: '', //区域ID
+          area: '', //区域名称
+          naviId: '', //导航点ID
+          naviSequence: '', //导航点编号
+          positionId: '', //巡检点ID
+          indicatorId: '', //指标ID
+          indicatorName: '', //指标名称
+          categoryId: '', //指标类目ID
+          categoryName: '', //指标类目名称
+          recognizeId: '', //识别类型ID
+          recognizeCode: '', //识别类型编码
+          recognizeName: '', //识别类型名称
+          unit: '', //单位
+          index: '', //序号
+          patrolTime: '', //巡检时间
+          recognizeState: '', //识别状态
+          thresholdId: '', //识别阈值ID
+          defectGrade: '', //缺陷等级
+          value: '', //检测值
+          detail: '', //检测值明细
+          adjustTime: '', //矫正时间
+          recognizeTime: '', //识别时间
+          modifiedGrade: '', //修正后等级
+          defectReview: '', //缺陷追溯
+          reviewMemo: '', //缺陷审核备注
+          reviewState: '', //缺陷处理状态
+          confirmTime: '', //缺陷确认时间
+          reviewerId: '', //缺陷确认人ID
+          reviewer: '', //缺陷确认人名
+          solveTime: '', //缺陷解决时间
+          solverId: '', //缺陷解决人ID
+          solver: '', //缺陷解决人名
+          guardLine: '', //警戒线
+          resourceList: [
+            {
+              id: '', //主键ID
+              orgId: '', //组织ID
+              robotId: '', //机器人ID
+              robot: '', //机器人名称
+              mapId: '', //地图ID
+              health: '', //机器人本体是否正常
+              reportTime: '', //上报时间
+              leftWheelSpeed: '', //左轮速度
+              rightWheelSpeed: '', //右轮速度
+              speed: '', //实时速度
+              angularSpeed: '', //实时角速度
+              cpuUsed: '', //CPU使用率
+              memUsed: '', //内存使用率
+              diskUsed: '', //磁盘使用率
+              batteryRatio: '', //剩余电量比率
+              batteryVolt: '', //当前电池电压
+              batteryCurrent: '', //当前电池电流
+              temperature: '', //舱内温度
+              humidity: '', //舱内湿度
+              mileage: '', //当前行驶里程
+              rotation: '', //当前旋转角度
+              direction: '', //当前行驶方向
+              distance: '', //距原点距离
+              laserDistance: '', //激光距离
+              panRotateAngleH: '', //云台水平转动角度
+              panRotateAngleV: '', //云台垂直转动角度
+              visibleFocus: '', //可见光相机焦距
+              visibleZoom: '', //可见光相机变焦
+              infraredFocus: '', //红外相机焦距
+              coordinateX: '', //横坐标
+              coordinateY: '', //纵坐标
+              yaw: '', //航向角
+              longitude: '', //经度
+              latitude: '', //维度
+              controlSysState: '', //控制系统状态
+              chargeSysState: '', //充电系统状态
+              visibleCameraState: '', //可见光相机状态
+              infraredCameraState: '', //红外相机状态
+              panState: '', //云台状态
+              bridgeState: '', //网桥状态
+              laserObstacleState: '', //激光避障器状态
+              mmwObstacleState: '', //毫米波避障器状态
+              backObstacleState: '', //后置避障器状态
+              pitObstacleState: '', //测坑避障器状态
+              wiperState: '', //雨刷状态
+              lightState: '', //补光灯状态
+              recordState: '', //录音状态
+              intercomState: '', //对讲机状态
+              eStopState: '', //急停按钮状态
+              runState: '', //机器人运行状态
+              taskMode: '', //机器人任务执行模式
+              createTime: '', //创建时间
+            },
+          ], //算法资源列表
+          createTime: '', //创建时间
+        },
+      ],
+    })
+  },
+  computed: {
+    crudCU() {
+      return this.crud.status.cu > 0
+    },
+    VUE_APP_BASE_API() {
+      return process.env.VUE_APP_BASE_API
+    },
+    VUE_APP_BASE_WS() {
+      return 'ws://' + window.location.host + process.env.VUE_APP_BASE_API
+    },
+  },
+  data() {
+    var chackHeight = (rule, value, callback) => {
+      if (!isPosNumber(value)) return callback(new Error('请输入正确的高度'))
+      return callback()
+    }
+    return {
+      visualIntercomConfigTableOptions,
+      permission: {
+        add: ['admin', 'visualintercom:config:add'],
+        edit: ['admin', 'visualintercom:config:edit'],
+        del: ['admin', 'visualintercom:config:del'],
+      },
+      rules: {
+        code: [{ required: true, message: '请选输入编号', trigger: 'blur' }],
+        name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
+        type: [{ required: true, message: '选择类型', trigger: 'blur' }],
+        buildId: [{ required: true, message: '请在地图上画点', trigger: 'blur' }],
+        floorNo: [{ required: true, message: '请在地图上画点', trigger: 'blur' }],
+        height: [{ required: true, validator: chackHeight, trigger: 'blur' }],
+        ip: [{ required: true, message: '请输入IP地址', trigger: 'blur' }],
+        userName: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
+      },
+      optionsObj: {
+        Camera: [],
+        Build: [],
+        FloorNo: [],
+        VisualIntercomType: [],
+      },
+      mapData: [],
+      buildFloor: {},
+    }
+  },
+  created() {
+    this.getOptions()
+  },
+  methods: {
+    [CRUD.HOOK.beforeToAdd]() {
+      this.mapData = []
+      this.buildFloor = {}
+    },
+    // 打开
+    [CRUD.HOOK.beforeToEdit]() {
+      this.mapData = [
+        {
+          buildId: this.form.buildId,
+          floorNo: this.form.floorNo,
+          geometries: [
+            {
+              type: 'Point',
+              points: [{ x: this.form.location.x, y: this.form.location.y }],
+            },
+          ],
+        },
+      ]
+      this.buildFloor = {
+        buildId: this.form.buildId,
+        floorNo: this.form.floorNo,
+      }
+    },
+    //验证前处理
+    [CRUD.HOOK.beforeValidateCU]() {
+      if (
+        this.mapData &&
+        this.mapData.length > 0 &&
+        this.mapData[0].geometries &&
+        this.mapData[0].geometries.length > 0 &&
+        this.mapData[0].geometries[0].points &&
+        this.mapData[0].geometries[0].points.length > 0
+      ) {
+        this.form.buildId = this.mapData[0].buildId
+        this.form.floorNo = this.mapData[0].floorNo
+        this.form.location = {
+          buildId: this.mapData[0].buildId,
+          floorNo: this.mapData[0].floorNo,
+          x: this.mapData[0].geometries[0].points[0].x,
+          y: this.mapData[0].geometries[0].points[0].y,
+        }
+      } else {
+        this.$message.error('请绘制正确的点')
+        return false
+      }
+    },
+    // 提交前的验证
+    [CRUD.HOOK.afterValidateCU]() {},
+    async handleChangeBuildId(val) {
+      await this.getFloorNoOption(val)
+      this.crud.toQuery()
+    },
+    getOptions() {
+      Object.keys(this.optionsObj).forEach(async (key) => {
+        if (key == 'FloorNo') return
+        try {
+          let res = await getOptions(key)
+          if (res.code === 20000) this.optionsObj[key] = res.data.content
+        } catch (error) {
+          console.log(error)
+        }
+      })
+    },
+    async getFloorNoOption(buildId) {
+      try {
+        let res = await getOptions('FloorNo', { buildId: buildId })
+        if (res.code === 20000) {
+          this.optionsObj.FloorNo = res.data.content
+          this.query.floorNo = null
+        }
+      } catch (error) {}
+    },
+  },
+}
+</script>
+
+<style></style>

+ 33 - 24
src/views/robotSLG/tableConfig.js

@@ -227,8 +227,8 @@ export const patrolTaskTableOptions = [
 export const patrolRecordTableOptions = [
   {
     index: '',
-    prop: 'robot',
-    label: '机器人',
+    prop: 'taskId',
+    label: '任务编号',
     width: '160',
     align: 'center',
     fixed: false,
@@ -238,6 +238,15 @@ export const patrolRecordTableOptions = [
     index: '',
     prop: 'task',
     label: '任务名称',
+    width: '',
+    align: 'center',
+    fixed: false,
+    sortable: false
+  },
+  {
+    index: '',
+    prop: 'robot',
+    label: '机器人',
     width: '160',
     align: 'center',
     fixed: false,
@@ -247,7 +256,7 @@ export const patrolRecordTableOptions = [
     index: '',
     prop: 'scene',
     label: '场景名称',
-    width: '160',
+    width: '100',
     align: 'center',
     fixed: false,
     sortable: false
@@ -256,7 +265,7 @@ export const patrolRecordTableOptions = [
     index: '',
     prop: 'area',
     label: '区域名称',
-    width: '160',
+    width: '100',
     align: 'center',
     fixed: false,
     sortable: false
@@ -274,7 +283,7 @@ export const patrolRecordTableOptions = [
     index: '',
     prop: 'indicatorName',
     label: '指标名称',
-    width: '100',
+    width: '',
     align: 'center',
     fixed: false,
     sortable: false
@@ -288,20 +297,20 @@ export const patrolRecordTableOptions = [
     fixed: false,
     sortable: false
   },
-  {
-    index: '',
-    prop: 'recognizeTime',
-    label: '识别时间',
-    width: '',
-    align: 'center',
-    fixed: false,
-    sortable: false
-  },
+  // {
+  //   index: '',
+  //   prop: 'recognizeTime',
+  //   label: '识别时间',
+  //   width: '',
+  //   align: 'center',
+  //   fixed: false,
+  //   sortable: false
+  // },
   {
     index: '',
     prop: 'recognizeState',
     label: '识别状态',
-    width: '',
+    width: '100',
     align: 'center',
     fixed: false,
     sortable: false
@@ -315,14 +324,14 @@ export const patrolRecordTableOptions = [
     fixed: false,
     sortable: false
   },
-  {
-    index: '',
-    prop: 'detail',
-    label: '监测值明细',
-    width: '120',
-    align: 'center',
-    fixed: false,
-    sortable: false
-  },
+  // {
+  //   index: '',
+  //   prop: 'detail',
+  //   label: '监测值明细',
+  //   width: '120',
+  //   align: 'center',
+  //   fixed: false,
+  //   sortable: false
+  // },
 
 ]