Explorar o código

设备预览,云台控制等功能修改-提交

lxh hai 3 días
pai
achega
05fe9a956b
Modificáronse 42 ficheiros con 11031 adicións e 835 borrados
  1. 3 0
      src/assets/icons/1.svg
  2. 3 0
      src/assets/icons/2.svg
  3. 3 0
      src/assets/icons/3.svg
  4. 7 0
      src/assets/icons/4.svg
  5. 3 0
      src/assets/icons/5.svg
  6. 6 0
      src/assets/icons/6.svg
  7. 4 0
      src/assets/icons/dingwei.svg
  8. 3 0
      src/assets/icons/yuandi.svg
  9. BIN=BIN
      src/assets/images/home-container/configurable/hsq/table-head.png
  10. 1 1
      src/components/map/map-cad-viewer.es.js
  11. 1 1
      src/components/map/types/components/MapCadViewer.d.ts
  12. 4 2
      src/components/vent/camera/LivePlayerWrapper.vue
  13. 269 26
      src/components/vent/camera/createPlayer.vue
  14. 3 2
      src/hooks/component/createPlayer.ts
  15. 30 12
      src/hooks/system/useCameraPianation.ts
  16. 4 0
      src/views/vent/cad/dwgViewerTest.vue
  17. 60 0
      src/views/vent/monitorManager/hsqHome/components/AlarmDay.vue
  18. 23 1
      src/views/vent/monitorManager/hsqHome/components/AlarmMonitor.vue
  19. 60 0
      src/views/vent/monitorManager/hsqHome/components/AlarmMonth.vue
  20. 68 0
      src/views/vent/monitorManager/hsqHome/components/AlarmPoint.vue
  21. 57 1
      src/views/vent/monitorManager/hsqHome/components/CommonTable.vue
  22. 331 12
      src/views/vent/monitorManager/hsqHome/components/DeviceCenter.vue
  23. 1004 178
      src/views/vent/monitorManager/hsqHome/components/DeviceControl.vue
  24. 131 71
      src/views/vent/monitorManager/hsqHome/components/DeviceRight.vue
  25. 1108 68
      src/views/vent/monitorManager/hsqHome/components/DeviceTree.vue
  26. 496 17
      src/views/vent/monitorManager/hsqHome/components/DeviceView.vue
  27. 1 0
      src/views/vent/monitorManager/hsqHome/components/DeviceWarnList.vue
  28. 498 0
      src/views/vent/monitorManager/hsqHome/components/HistoryFilterTree.vue
  29. 104 140
      src/views/vent/monitorManager/hsqHome/components/WarnCenTop.vue
  30. 1 0
      src/views/vent/monitorManager/hsqHome/components/basicBorder.vue
  31. 253 0
      src/views/vent/monitorManager/hsqHome/components/common/commonEchart.vue
  32. 1 0
      src/views/vent/monitorManager/hsqHome/components/navMenu.vue
  33. 138 0
      src/views/vent/monitorManager/hsqHome/components/type.ts
  34. 41 4
      src/views/vent/monitorManager/hsqHome/fireMonitor.vue
  35. 93 0
      src/views/vent/monitorManager/hsqHome/historyReport.vue
  36. 70 6
      src/views/vent/monitorManager/hsqHome/hsqHome.api.ts
  37. 350 282
      src/views/vent/monitorManager/hsqHome/hsqHome.data.ts
  38. 5 1
      src/views/vent/monitorManager/hsqHome/index.vue
  39. 0 1
      src/views/vent/monitorManager/hsqHome/systemManger.vue
  40. 73 9
      src/views/vent/monitorManager/hsqHome/videoPlayer.vue
  41. 1 0
      vite.config.ts
  42. 5720 0
      红沙泉SDK接口文档-0917.md

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

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="17.524" height="18.872" viewBox="0 0 17.524 18.872">
+  <path id="路径_58072" data-name="路径 58072" d="M121.489,64a1.348,1.348,0,0,1,1.347,1.348v6h0a.758.758,0,0,1-1.515,0h0V65.517H108.183V81.356h4.464a.758.758,0,0,1,0,1.517h-4.632a1.348,1.348,0,0,1-1.347-1.348V65.348A1.348,1.348,0,0,1,108.014,64h13.475Zm-6.134,14.838.009,0,1.572.344a.506.506,0,0,1-.208.989l-.008,0-.127-.028a3.454,3.454,0,0,0,6.157-.843l.014-.043a.59.59,0,0,1,1.126.351,4.633,4.633,0,0,1-8.128,1.4v.015a.505.505,0,1,1-1.011.008v-1.7a.505.505,0,0,1,.6-.5Zm-2.478-2.032a.674.674,0,0,1,0,1.348H110.52a.674.674,0,0,1,0-1.348Zm6.6-3.37a4.628,4.628,0,0,1,3.706,1.853v-.015a.505.505,0,1,1,1.011-.008v1.7a.505.505,0,0,1-.6.5l-.009,0-1.572-.344a.505.505,0,1,1,.208-.989l.008,0,.127.028a3.454,3.454,0,0,0-6.157.843l-.014.043a.59.59,0,0,1-1.126-.351A4.634,4.634,0,0,1,119.475,73.436Zm-5.376-.674a.674.674,0,0,1,0,1.348H110.52a.674.674,0,0,1,0-1.348Zm4.842-4.044a.674.674,0,0,1,0,1.348H110.52a.674.674,0,0,1,0-1.348Z" transform="translate(-106.667 -64)" fill="#36c7ff"/>
+</svg>

+ 3 - 0
src/assets/icons/2.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="21.387" height="19.986" viewBox="0 0 21.387 19.986">
+  <path id="路径_58073" data-name="路径 58073" d="M102.641,123.557a2.47,2.47,0,0,0-.782.127l-2.712-3.63a2.445,2.445,0,1,0-3.379.611L92.726,131.3a2.554,2.554,0,0,0-.462.06L88,124.345a2.445,2.445,0,1,0-1.857.857,2.474,2.474,0,0,0,.593-.072l4.244,6.99a2.445,2.445,0,1,0,3.176-.422l3.032-10.605a2.453,2.453,0,0,0,.767-.137l2.7,3.615a2.445,2.445,0,1,0,1.982-1.013Z" transform="translate(-83.7 -116.2)" fill="#36c7ff"/>
+</svg>

+ 3 - 0
src/assets/icons/3.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="18.747" height="15.3" viewBox="0 0 18.747 15.3">
+  <path id="路径_58074" data-name="路径 58074" d="M104.08,173.366h-6.3v-1.8h6.3Zm0,6.3h-8.1v-1.8h8.1Zm0,6.3h-18v-1.8h18v1.8Zm-16.806-8.122-1.04.352-.9-1.559.824-.724a3.615,3.615,0,0,1,0-1.492l-.824-.724.9-1.559,1.04.352a3.587,3.587,0,0,1,1.291-.747l.215-1.076h1.8l.216,1.076a3.6,3.6,0,0,1,1.291.747l1.04-.353.9,1.559-.824.724a3.616,3.616,0,0,1,0,1.492l.824.724-.9,1.559-1.04-.352a3.588,3.588,0,0,1-1.291.747l-.215,1.076h-1.8l-.216-1.076a3.578,3.578,0,0,1-1.291-.747Zm2.407-3.577a.9.9,0,1,0,.9.9A.9.9,0,0,0,89.68,174.266Z" transform="translate(-85.333 -170.666)" fill="#36c7ff"/>
+</svg>

+ 7 - 0
src/assets/icons/4.svg

@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="17.697" height="18.344" viewBox="0 0 17.697 18.344">
+  <g id="组_16942" data-name="组 16942" transform="translate(-102.4 -66.048)">
+    <path id="路径_58065" data-name="路径 58065" d="M541.446,527.114l-2.617-2.606a.567.567,0,0,1,.083-.841c.26-.26.623-.353.841-.135l4.039,4.039a.648.648,0,0,1,.021.851l-3.935,3.935a.625.625,0,0,1-.841-.1c-.3-.3-.332-.665-.125-.872l2.679-2.668-5.731-.208a.811.811,0,0,1-.82-.685.829.829,0,0,1,.841-.8Z" transform="translate(-423.866 -448.088)" fill="#36c7ff"/>
+    <path id="路径_58067" data-name="路径 58067" d="M110.156,84.125H104.84a2.4,2.4,0,0,1-1.724-.716,2.427,2.427,0,0,1-.716-1.724v-13.2a2.385,2.385,0,0,1,.716-1.724,2.427,2.427,0,0,1,1.724-.716h7.829l5.233,5.233V74.79a.831.831,0,0,1-1.661,0V71.977l-4.257-4.257H104.84a.78.78,0,0,0-.779.779V81.7a.78.78,0,0,0,.779.779h5.316a.833.833,0,0,1,.831.831A.824.824,0,0,1,110.156,84.125Z" transform="translate(0)" fill="#36c7ff"/>
+    <path id="路径_58068" data-name="路径 58068" d="M540.937,80.373H537.48a2.385,2.385,0,0,1-1.724-.716,2.427,2.427,0,0,1-.716-1.724V74.559a.831.831,0,0,1,1.661,0v3.385a.78.78,0,0,0,.779.779h3.457a.833.833,0,0,1,.831.831A.824.824,0,0,1,540.937,80.373Z" transform="translate(-423.866 -7.524)" fill="#36c7ff"/>
+  </g>
+</svg>

+ 3 - 0
src/assets/icons/5.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="19.111" height="20.748" viewBox="0 0 19.111 20.748">
+  <path id="路径_58075" data-name="路径 58075" d="M119.615,75.622a1.163,1.163,0,0,1,1.163,1.163v2.97h4.65a1.163,1.163,0,0,1,1.163,1.163v3.856a1.163,1.163,0,0,1-1.163,1.163h-.587l1.93,8a1.163,1.163,0,0,1-1.13,1.435H110.151a1.163,1.163,0,0,1-1.135-1.417l1.8-8.016h-.958a1.163,1.163,0,0,1-1.163-1.163V80.918a1.163,1.163,0,0,1,1.163-1.163h5.1v-2.97a1.163,1.163,0,0,1,1.163-1.163Zm3.432,10.316h-10.44l-1.73,7.688h3.07l.662-3.79a.233.233,0,0,1,.229-.193h1.382a.233.233,0,0,1,.233.233l0,.044-.719,3.705h4.664l-.717-3.705,0-.044a.233.233,0,0,1,.233-.233h1.383a.233.233,0,0,1,.228.193l.659,3.79H124.9l-1.854-7.688Zm-4.014-8.572h-2.325V81.5h-6.266v2.694h14.4V81.5h-5.813V77.366Z" transform="translate(-108.198 -75.122)" fill="#36c7ff" stroke="rgba(0,0,0,0)" stroke-miterlimit="10" stroke-width="1"/>
+</svg>

+ 6 - 0
src/assets/icons/6.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="18.893" height="19.436" viewBox="0 0 18.893 19.436">
+  <g id="组_16945" data-name="组 16945" transform="translate(-112 -100.5)">
+    <path id="路径_58070" data-name="路径 58070" d="M350.327,410.285a.827.827,0,0,0,.827-.827v-7.132a.827.827,0,1,0-1.653,0v7.132A.827.827,0,0,0,350.327,410.285Zm6.022,0a.827.827,0,0,0,.827-.827v-7.132a.827.827,0,1,0-1.653,0v7.132A.827.827,0,0,0,356.349,410.285Zm-3.011,0a.827.827,0,0,0,.827-.827v-7.132a.827.827,0,1,0-1.653,0v7.132A.827.827,0,0,0,353.338,410.285Z" transform="translate(-231.891 -293.892)" fill="#36c7ff"/>
+    <path id="路径_58071" data-name="路径 58071" d="M130.066,103.4h-4.375v-1.07a1.837,1.837,0,0,0-1.835-1.835h-4.82a1.837,1.837,0,0,0-1.835,1.835v1.07h-4.375a.827.827,0,1,0,0,1.653h2.019v12.278a2.6,2.6,0,0,0,2.6,2.6h8a2.6,2.6,0,0,0,2.6-2.6V105.058h2.019a.827.827,0,1,0,0-1.653Zm-11.212-1.07a.182.182,0,0,1,.182-.182h4.82a.182.182,0,0,1,.182.182v1.07h-5.184Zm7.539,15a.948.948,0,0,1-.947.947h-8a.948.948,0,0,1-.947-.947V105.058h9.9Z" transform="translate(0 0)" fill="#36c7ff"/>
+  </g>
+</svg>

+ 4 - 0
src/assets/icons/dingwei.svg

@@ -0,0 +1,4 @@
+<svg id="组_16991" data-name="组 16991" xmlns="http://www.w3.org/2000/svg" width="47.138" height="47.142" viewBox="0 0 47.138 47.142">
+  <path id="路径_58078" data-name="路径 58078" d="M393.986,387.41a6.606,6.606,0,1,0,6.606,6.606A6.614,6.614,0,0,0,393.986,387.41Zm0,10a3.392,3.392,0,1,1,3.392-3.392A3.4,3.4,0,0,1,393.986,397.408Z" transform="translate(-370.417 -370.445)" fill="#fff"/>
+  <path id="路径_58079" data-name="路径 58079" d="M112.661,89.091H110.49A19.888,19.888,0,0,0,92.539,70.926V68.737a1.607,1.607,0,0,0-1.607-1.607H90.65a1.607,1.607,0,0,0-1.607,1.607v2.18A19.879,19.879,0,0,0,70.912,89.091H68.737A1.607,1.607,0,0,0,67.13,90.7v.282a1.607,1.607,0,0,0,1.607,1.607h2.189a19.888,19.888,0,0,0,18.117,17.9v2.179a1.607,1.607,0,0,0,1.607,1.607h.282a1.607,1.607,0,0,0,1.607-1.607v-2.189a19.9,19.9,0,0,0,17.937-17.888h2.184a1.607,1.607,0,0,0,1.607-1.607V90.7A1.607,1.607,0,0,0,112.661,89.091ZM92.539,107.247v-1.709a1.607,1.607,0,0,0-1.607-1.607H90.65a1.607,1.607,0,0,0-1.607,1.607v1.733A16.678,16.678,0,0,1,74.159,92.587h1.7A1.607,1.607,0,0,0,77.47,90.98V90.7a1.607,1.607,0,0,0-1.607-1.607H74.127a16.679,16.679,0,0,1,14.917-14.96v1.732A1.607,1.607,0,0,0,90.65,77.47h.282a1.607,1.607,0,0,0,1.607-1.607V74.155a16.68,16.68,0,0,1,14.735,14.937h-1.739a1.607,1.607,0,0,0-1.607,1.607v.282a1.607,1.607,0,0,0,1.607,1.607h1.7A16.676,16.676,0,0,1,92.539,107.247Z" transform="translate(-67.13 -67.13)" fill="#fff"/>
+</svg>

+ 3 - 0
src/assets/icons/yuandi.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="68" height="68" viewBox="0 0 68 68">
+  <circle id="椭圆_2679" data-name="椭圆 2679" cx="34" cy="34" r="34" fill="#15517b"/>
+</svg>

BIN=BIN
src/assets/images/home-container/configurable/hsq/table-head.png


+ 1 - 1
src/components/map/map-cad-viewer.es.js

@@ -1,5 +1,5 @@
 import { defineComponent as _e, openBlock as de, createElementBlock as ge, normalizeStyle as Lt, createElementVNode as _, toDisplayString as ye, Fragment as Ge, renderList as qe, createCommentVNode as Ue, computed as St, createTextVNode as gn, ref as N, shallowRef as Et, onMounted as fn, onBeforeUnmount as An, normalizeClass as Ke, createVNode as hn, createBlock as yn, triggerRef as Ct } from "vue";
-import Re from "maplibre-gl";
+  import * as Re from "maplibre-gl";
 import { MapboxOverlay as mn } from "@deck.gl/mapbox";
 import { OrthographicView as bt, Deck as vn, LinearInterpolator as In } from "@deck.gl/core";
 import { ScatterplotLayer as xn, TextLayer as Qt, PathLayer as Pe, PolygonLayer as kt, IconLayer as En } from "@deck.gl/layers";

+ 1 - 1
src/components/map/types/components/MapCadViewer.d.ts

@@ -1,4 +1,4 @@
-import { default as maplibregl } from 'maplibre-gl';
+import * as maplibregl from 'maplibre-gl';
 import { MapboxOverlay } from '@deck.gl/mapbox';
 import { LayerItem } from './LayerPanel';
 import { CadFeature, CadData, ViewerMode, MapMarker, BoundaryConfig, MapConfig } from '../types/cad';

+ 4 - 2
src/components/vent/camera/LivePlayerWrapper.vue

@@ -4,7 +4,7 @@
       ref="player"
       :video-url="src"
       live
-      stretch
+      :stretch="stretch"
       :autoplay="autoplay"
       muted
       controls
@@ -24,8 +24,10 @@
       src: string
       /** 是否自动播放,默认 true,保持原有行为 */
       autoplay?: boolean
+      /** 是否拉伸铺满;预览弹窗传 false 以避免画面变形 */
+      stretch?: boolean
     }>(),
-    { autoplay: true }
+    { autoplay: true, stretch: true }
   );
 
   const videoEl = ref<HTMLElement | null>(null);

+ 269 - 26
src/components/vent/camera/createPlayer.vue

@@ -1,52 +1,295 @@
 <template>
   <div id="LivePlayerBox">
-    <component
+    <div
       v-for="(item, index) in streamList"
       :key="index"
-      :is="item.zj"
-      :src="item.src"
-      :autoplay="item.autoplay"
-      class="liveVideo"
-    />
+      :class="['live-video-item', { 'is-selected': selectedIndex === index }]"
+      @click.stop="handleSelect(item, index)"
+      @dblclick.capture.stop.prevent="handleDblclick($event, item, index)"
+    >
+      <component :is="item.zj" :src="item.src" :autoplay="item.autoplay" class="liveVideo" />
+    </div>
   </div>
+
+  <!-- 双击放大:弹窗预览(青蓝监控风格,等比展示不失真) -->
+  <Teleport to="body">
+    <div v-if="previewVisible" class="camera-preview-mask" @click.self="closePreview">
+      <div
+        class="camera-preview-panel"
+        :style="{ transform: `translate(${previewOffset.x}px, ${previewOffset.y}px)` }"
+      >
+        <div class="camera-preview-header" @mousedown="onPreviewDragStart">
+          <span class="camera-preview-title">{{ previewTitle }}</span>
+          <div class="camera-preview-close" title="关闭" @click="closePreview" @mousedown.stop>×</div>
+        </div>
+        <div class="camera-preview-body">
+          <div class="camera-preview-stage">
+            <component
+              v-if="previewItem"
+              :is="previewItem.zj"
+              :src="previewItem.src"
+              :autoplay="true"
+              :stretch="false"
+              class="camera-preview-player"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+  </Teleport>
 </template>
 
 <script setup lang="ts">
-  import { ref, onMounted, onBeforeUnmount } from 'vue';
-  import HlsPlayer from '@/components/vent/camera/HlsPlayer.vue';
-  import LivePlayerWrapper from '@/components/vent/camera/LivePlayerWrapper.vue';
+  import { reactive, ref, onMounted, onBeforeUnmount } from 'vue'
+  import HlsPlayer from '@/components/vent/camera/HlsPlayer.vue'
+  import LivePlayerWrapper from '@/components/vent/camera/LivePlayerWrapper.vue'
+
+  interface PreviewStreamItem {
+    zj: any
+    src: string
+    autoplay: boolean
+    name?: string
+    meta?: any
+  }
 
   const props = defineProps<{
-    srcList: any[];
+    srcList: any[]
     /** 自动播放起始下标,配合 autoPlayCount 使用,默认 0 */
-    autoPlayStart?: number;
+    autoPlayStart?: number
     /** 自动播放数量:未传则全部自动播放 */
-    autoPlayCount?: number;
-  }>();
+    autoPlayCount?: number
+    /** 摄像头选中回调 */
+    onSelect?: (camera: any, index: number) => void
+  }>()
+
+  const streamList = ref<PreviewStreamItem[]>([])
+  /** 当前选中的摄像头下标 */
+  const selectedIndex = ref(-1)
+  /** 弹窗预览 */
+  const previewVisible = ref(false)
+  const previewTitle = ref('摄像头预览')
+  const previewItem = ref<PreviewStreamItem | null>(null)
+  /** 弹窗拖动偏移 */
+  const previewOffset = reactive({ x: 0, y: 0 })
+  let dragging = false
+  let dragStartX = 0
+  let dragStartY = 0
+  let dragOriginX = 0
+  let dragOriginY = 0
+
+  function handleSelect(item: PreviewStreamItem, index: number) {
+    selectedIndex.value = index
+    props.onSelect?.(item.meta || { addr: item.src, name: item.name }, index)
+  }
+
+  function exitBrowserFullscreen() {
+    if (document.fullscreenElement && document.exitFullscreen) {
+      document.exitFullscreen().catch(() => {})
+    }
+  }
+
+  function onPreviewDragMove(e: MouseEvent) {
+    if (!dragging) return
+    previewOffset.x = dragOriginX + (e.clientX - dragStartX)
+    previewOffset.y = dragOriginY + (e.clientY - dragStartY)
+  }
+
+  function onPreviewDragEnd() {
+    if (!dragging) return
+    dragging = false
+    window.removeEventListener('mousemove', onPreviewDragMove)
+    window.removeEventListener('mouseup', onPreviewDragEnd)
+  }
+
+  /** 按住标题栏拖动弹窗 */
+  function onPreviewDragStart(e: MouseEvent) {
+    if (e.button !== 0) return
+    dragging = true
+    dragStartX = e.clientX
+    dragStartY = e.clientY
+    dragOriginX = previewOffset.x
+    dragOriginY = previewOffset.y
+    window.addEventListener('mousemove', onPreviewDragMove)
+    window.addEventListener('mouseup', onPreviewDragEnd)
+  }
+
+  function closePreview() {
+    onPreviewDragEnd()
+    previewVisible.value = false
+    previewItem.value = null
+    previewOffset.x = 0
+    previewOffset.y = 0
+  }
+
+  /** 双击:弹窗内等比放大预览,不进入浏览器全屏、不撑破网格 */
+  function handleDblclick(_e: MouseEvent, item: PreviewStreamItem, index: number) {
+    handleSelect(item, index)
+    exitBrowserFullscreen()
+
+    if (previewVisible.value && selectedIndex.value === index && previewItem.value?.src === item.src) {
+      closePreview()
+      return
+    }
 
-  const streamList = ref<any[]>([]);
+    previewTitle.value = item.name || item.meta?.name || '摄像头预览'
+    previewItem.value = {
+      zj: item.zj,
+      src: item.src,
+      autoplay: true,
+      name: item.name,
+      meta: item.meta,
+    }
+    previewOffset.x = 0
+    previewOffset.y = 0
+    previewVisible.value = true
+  }
 
   onMounted(() => {
-    const componentList: any[] = [];
-    const start = props.autoPlayStart ?? 0;
+    const componentList: PreviewStreamItem[] = []
+    const start = props.autoPlayStart ?? 0
     for (let i = 0; i < props.srcList.length; i++) {
-      const stream = props.srcList[i];
+      const stream = props.srcList[i]
       if (stream.addr.includes('0.0.0.0')) {
-        stream.addr = stream.addr.replace('0.0.0.0', window.location.hostname);
+        stream.addr = stream.addr.replace('0.0.0.0', window.location.hostname)
       }
       const autoplay =
-        props.autoPlayCount == null ? true : i >= start && i < start + props.autoPlayCount;
+        props.autoPlayCount == null ? true : i >= start && i < start + props.autoPlayCount
+      const meta = {
+        name: stream.name,
+        addr: stream.addr,
+        cameraRate: stream.cameraRate,
+        devicekind: stream.devicekind,
+        id: stream.id,
+        deviceid: stream.deviceid || stream.devId || stream.deviceId || stream.deviceID || '',
+        ip: stream.ip || '',
+      }
       if (stream.addr.toLowerCase().includes('.m3u8') || stream.addr.toLowerCase().startsWith('rtsp://')) {
-        componentList.push({ zj: HlsPlayer, src: stream.addr, autoplay });
+        componentList.push({ zj: HlsPlayer, src: stream.addr, autoplay, name: stream.name, meta })
       } else if (stream.addr.startsWith('rtmp://')) {
-        componentList.push({ zj: LivePlayerWrapper, src: stream.addr, autoplay });
+        componentList.push({ zj: LivePlayerWrapper, src: stream.addr, autoplay, name: stream.name, meta })
       } else {
-        componentList.push({ zj: LivePlayerWrapper, src: stream.addr, autoplay });
+        componentList.push({ zj: LivePlayerWrapper, src: stream.addr, autoplay, name: stream.name, meta })
       }
     }
-    streamList.value = componentList;
-  });
+    streamList.value = componentList
+  })
+
   onBeforeUnmount(() => {
-    streamList.value = [];
-  });
+    closePreview()
+    streamList.value = []
+    selectedIndex.value = -1
+  })
 </script>
+
+<style lang="less" scoped>
+.camera-preview-mask {
+  position: fixed;
+  inset: 0;
+  z-index: 3000;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: rgba(9, 23, 44, 0.82);
+  backdrop-filter: blur(4px);
+}
+
+.camera-preview-panel {
+  /* 略缩小弹窗,仍按 16:9 等比约束,避免画面被强行拉伸 */
+  width: min(72vw, calc(68vh * 16 / 9), 960px);
+  max-height: 78vh;
+  display: flex;
+  flex-direction: column;
+  border: 1px solid rgba(0, 210, 255, 0.75);
+  box-shadow:
+    0 0 0 2px rgba(8, 40, 70, 0.95),
+    0 0 22px rgba(0, 200, 255, 0.3),
+    inset 0 0 0 1px rgba(0, 180, 255, 0.28);
+  background: linear-gradient(180deg, rgba(6, 28, 48, 0.98) 0%, rgba(4, 16, 32, 0.98) 100%);
+  overflow: hidden;
+  will-change: transform;
+}
+
+.camera-preview-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  height: 36px;
+  padding: 0 14px;
+  flex-shrink: 0;
+  color: #fff;
+  background: linear-gradient(to right, #134c77, transparent);
+  border-bottom: 1px solid rgba(41, 171, 241, 0.45);
+  cursor: move;
+  user-select: none;
+}
+
+.camera-preview-title {
+  color: #e8f4ff;
+  font-size: 14px;
+  font-weight: 600;
+  letter-spacing: 0.5px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.camera-preview-close {
+  width: 28px;
+  height: 24px;
+  line-height: 20px;
+  text-align: center;
+  cursor: pointer;
+  color: #01fefc;
+  border: 1px solid #01fefc;
+  border-radius: 2px;
+  flex-shrink: 0;
+  transition: background-color 0.2s, box-shadow 0.2s;
+  user-select: none;
+
+  &:hover {
+    background-color: rgba(36, 132, 188, 0.55);
+    box-shadow: 0 0 6px rgba(1, 254, 252, 0.45);
+  }
+}
+
+.camera-preview-body {
+  flex: 1;
+  min-height: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 14px;
+  box-sizing: border-box;
+  background: #0a1a2e;
+}
+
+.camera-preview-stage {
+  width: 100%;
+  aspect-ratio: 16 / 9;
+  max-height: calc(78vh - 64px);
+  background: #000;
+  border: 1px solid rgba(0, 183, 255, 0.4);
+  overflow: hidden;
+  position: relative;
+}
+
+.camera-preview-player {
+  width: 100% !important;
+  height: 100% !important;
+  display: block;
+}
+
+:deep(.camera-preview-stage video),
+:deep(.camera-preview-stage canvas),
+:deep(.camera-preview-stage .liveVideo),
+:deep(.camera-preview-stage .video-js),
+:deep(.camera-preview-stage .video-wrapper),
+:deep(.camera-preview-stage .player-wrapper) {
+  width: 100% !important;
+  height: 100% !important;
+  max-width: 100%;
+  max-height: 100%;
+  object-fit: contain !important;
+  background: #000;
+}
+</style>

+ 3 - 2
src/hooks/component/createPlayer.ts

@@ -4,7 +4,8 @@ import createPlayer from '@/components/vent/camera/createPlayer.vue';
 export function createPlayerVNode(
   streamList: [],
   autoPlayCount?: number,
-  autoPlayStart?: number
+  autoPlayStart?: number,
+  onSelect?: (camera: any, index: number) => void
 ): VNode {
-  return h(createPlayer, { srcList: streamList, autoPlayCount, autoPlayStart });
+  return h(createPlayer, { srcList: streamList, autoPlayCount, autoPlayStart, onSelect });
 }

+ 30 - 12
src/hooks/system/useCameraPianation.ts

@@ -11,7 +11,7 @@ import { createPlayerVNode } from '../component/createPlayer';
 I18N.use(ZH);
 
 export function useCamera() {
-  const cameraList = (params) => defHttp.get({ url: '/safety/ventanalyCamera/list', params });
+  const cameraList = (params) => defHttp.get({ url: '/safety/ventanalyCamera/list', params}, { joinParamsToUrl: true });
   const cameraAddrList = (params) => defHttp.post({ url: '/monitor/camera/info', params });
   const cameraAddr = (params) => defHttp.get({ url: '/monitor/camera/queryByCameraCode', params });
 
@@ -44,7 +44,7 @@ export function useCamera() {
     await removeCameraRef(parentPlayerDom, renderPlayer);
     let res;
     if (!devKind && !cameraData) {
-      res = await cameraList({ deviceid, pageNo: pagination.current, pageSize: pagination.pageSize });
+      res = await cameraList({ devIdList:deviceid, pageNo: pagination.current, pageSize: pagination.pageSize });
     } else if (devKind && !cameraData) {
       res = await cameraList({ sysId: deviceid, devKind, pageNo: pagination.current, pageSize: pagination.pageSize });
     }
@@ -67,18 +67,29 @@ export function useCamera() {
           try {
             const data = await cameraAddr({ devicekind: item['devicekind'], cameraCode: item['addr'], videoType });
             if (data && data['url']) {
-              cameraAddrs.push({ name: item['name'], addr: data['url'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
+              cameraAddrs.push({
+                name: item['name'],
+                addr: data['url'],
+                cameraRate: item['cameraRate'],
+                devicekind: item['devicekind'],
+                id: item['id'],
+                deviceid: item['devId'] || item['deviceId'] || item['deviceID'] || item['deviceid'] || '',
+                ip: item['ip'] || item['strip'] || '',
+              });
             }
-            // // 从海康平台接口获取视频流测试
-            // cameraAddrs.push({
-            //   name: item['name'],
-            //   addr: 'https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.mp4/.m3u8',
-            // });
           } catch (error) {}
         } else if (item['devicekind'] == 'toHKR') {
           cameraNames.push({ name: item['name'], cameraRate: item['cameraRate'] });
         } else {
-          cameraAddrs.push({ name: item['name'], addr: item['addr'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
+          cameraAddrs.push({
+            name: item['name'],
+            addr: item['addr'],
+            cameraRate: item['cameraRate'],
+            devicekind: item['devicekind'],
+            id: item['id'],
+            deviceid: item['devId'] || item['deviceId'] || item['deviceID'] || item['deviceid'] || '',
+            ip: item['ip'] || item['strip'] || '',
+          });
         }
       }
     }
@@ -100,7 +111,8 @@ export function useCamera() {
         sortedCameraAddrs,
         parentPlayerDom,
         pagination?.autoPlayCount,
-        pagination?.autoPlayStart
+        pagination?.autoPlayStart,
+        pagination?.onCameraSelect
       );
     }
   }
@@ -388,8 +400,14 @@ export function useCamera() {
     });
   }
 
-  function deviceCameraInit1(cameraAddrs, player, autoPlayCount?: number, autoPlayStart?: number) {
-    const vnode = createPlayerVNode(cameraAddrs, autoPlayCount, autoPlayStart);
+  function deviceCameraInit1(
+    cameraAddrs,
+    player,
+    autoPlayCount?: number,
+    autoPlayStart?: number,
+    onSelect?: (camera: any, index: number) => void
+  ) {
+    const vnode = createPlayerVNode(cameraAddrs, autoPlayCount, autoPlayStart, onSelect);
     render(vnode, player.value);
   }
 

+ 4 - 0
src/views/vent/cad/dwgViewerTest.vue

@@ -442,6 +442,10 @@ function locateIcon(id: number | string) {
   console.log(`定位设备 ${id}:`, ok ? "成功" : "未找到");
   return ok;
 }
+
+defineExpose({
+  locateIcon,
+});
   function loadCAD(data){
      cadData.value = data;
       console.log(`Loaded ${data.features.length} CAD features`);

+ 60 - 0
src/views/vent/monitorManager/hsqHome/components/AlarmDay.vue

@@ -0,0 +1,60 @@
+<template>
+  <div class="alarm-day">
+    <div class="list-title">
+      <span>报警数量日统计</span>
+    </div>
+    <div class="list-content">
+      <commonEchart
+        :x-axis-data="xAxisData"
+        :series="series"
+        y-axis-name="次数"
+        :show-label="true"
+        :bar-width="16"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+import commonEchart, { type CommonBarSeriesItem } from './common/commonEchart.vue'
+
+/** 近 7 日日期(模拟) */
+const xAxisData = ref<string[]>(['09-11', '09-12', '09-13', '09-14', '09-15', '09-16', '09-17'])
+
+/** 日报警数量(模拟) */
+const series = ref<CommonBarSeriesItem[]>([
+  {
+    name: '报警数量',
+    data: [6, 9, 4, 12, 8, 15, 11],
+  },
+])
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+.alarm-day {
+  --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 15px;
+  box-sizing: border-box;
+}
+.list-title {
+  width: 177px;
+  height: 30px;
+  line-height: 22px;
+  padding-left: 16px;
+  color: #01fefc;
+  font-weight: bolder;
+  background: var(--image-box-bg) no-repeat;
+  background-size: 100% 100%;
+  margin-bottom: 10px;
+  flex-shrink: 0;
+}
+.list-content{
+  width: 100%;
+  height: calc(100% - 40px);
+}
+</style>

+ 23 - 1
src/views/vent/monitorManager/hsqHome/components/AlarmMonitor.vue

@@ -15,7 +15,14 @@
       </div>
     </div>
     <div class="alarm-bot">
-      <CommonTable :columns="alarmColumns" :table-data="tableData"></CommonTable>
+      <CommonTable
+        :columns="alarmColumns"
+        :table-data="tableData"
+        selectable
+        row-key="id"
+        :selected-key="selectedAlarmId"
+        @row-click="onSelectAlarm"
+      ></CommonTable>
     </div>
   </div>
 </template>
@@ -50,10 +57,25 @@ const timeRange = ref<[string, string]>([
 
 // 表格数据源:从后端获取报警日志列表数据
 let tableData = ref<any[]>([])
+/** 当前选中的报警记录 id */
+const selectedAlarmId = ref<string | number | null>(null)
 
 /** 定时获取监测数据定时器 */
 let timer: null | NodeJS.Timeout = null;
 
+const emit = defineEmits<{
+  (e: 'locate', deviceId: string | number): void
+}>()
+
+/** 报警监控行点击选中,并通知父组件按 deviceId 定位 */
+function onSelectAlarm(row: any) {
+  selectedAlarmId.value = row?.id ?? null
+  const deviceId = row?.deviceId ?? row?.deviceID ?? row?.devId
+  if (deviceId != null && deviceId !== '') {
+    emit('locate', deviceId)
+  }
+}
+
 /**
  * 定时获取监测数据
  * 通过定时器循环调用数据获取方法,更新表格数据

+ 60 - 0
src/views/vent/monitorManager/hsqHome/components/AlarmMonth.vue

@@ -0,0 +1,60 @@
+<template>
+  <div class="alarm-month">
+    <div class="list-title">
+      <span>报警数量月统计</span>
+    </div>
+    <div class="list-content">
+      <commonEchart
+        :x-axis-data="xAxisData"
+        :series="series"
+        y-axis-name="次数"
+        :show-label="true"
+        :bar-width="20"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+import commonEchart, { type CommonBarSeriesItem } from './common/commonEchart.vue'
+
+/** 近 6 个月份(模拟) */
+const xAxisData = ref<string[]>(['4月', '5月', '6月', '7月', '8月', '9月'])
+
+/** 月报警数量(模拟) */
+const series = ref<CommonBarSeriesItem[]>([
+  {
+    name: '报警数量',
+    data: [86, 102, 74, 128, 95, 113],
+  },
+])
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+.alarm-month {
+  --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 15px;
+  box-sizing: border-box;
+}
+.list-title {
+  width: 177px;
+  height: 30px;
+  line-height: 22px;
+  padding-left: 16px;
+  color: #01fefc;
+  font-weight: bolder;
+  background: var(--image-box-bg) no-repeat;
+  background-size: 100% 100%;
+  margin-bottom: 10px;
+  flex-shrink: 0;
+}
+.list-content{
+  width: 100%;
+  height: calc(100% - 40px);
+}
+</style>

+ 68 - 0
src/views/vent/monitorManager/hsqHome/components/AlarmPoint.vue

@@ -0,0 +1,68 @@
+<template>
+  <div class="alarm-point">
+    <div class="list-title">
+      <span>报警数量点位统计</span>
+    </div>
+    <div class="list-content">
+      <commonEchart
+        :x-axis-data="xAxisData"
+        :series="series"
+        y-axis-name="次数"
+        :show-label="true"
+        :bar-width="22"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+import commonEchart, { type CommonBarSeriesItem } from './common/commonEchart.vue'
+
+/** 点位类目(模拟) */
+const xAxisData = ref<string[]>([
+  '煤厂北侧',
+  '煤厂西侧',
+  '煤场东侧',
+  '煤场西侧',
+  '采场北侧',
+  '采场西侧1',
+  '采场西侧2',
+])
+
+/** 点位报警数量(模拟) */
+const series = ref<CommonBarSeriesItem[]>([
+  {
+    name: '报警数量',
+    data: [18, 12, 26, 9, 15, 21, 7],
+  },
+])
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+.alarm-point {
+  --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 15px;
+  box-sizing: border-box;
+}
+.list-title {
+  width: 177px;
+  height: 30px;
+  line-height: 22px;
+  padding-left: 16px;
+  color: #01fefc;
+  font-weight: bolder;
+  background: var(--image-box-bg) no-repeat;
+  background-size: 100% 100%;
+  margin-bottom: 10px;
+  flex-shrink: 0;
+}
+.list-content{
+  width: 100%;
+  height: calc(100% - 40px);
+}
+</style>

+ 57 - 1
src/views/vent/monitorManager/hsqHome/components/CommonTable.vue

@@ -5,7 +5,13 @@
         item.name }}</div>
     </div>
     <div ref="scrollRef" class="table__content_list">
-      <div class="table__content_list_row" v-for="(item, index) in tableData" :key="`svvhbct-${index}`">
+      <div
+        class="table__content_list_row"
+        :class="{ 'is-clickable': selectable, 'is-active': isRowActive(item) }"
+        v-for="(item, index) in tableData"
+        :key="getRowKey(item, index)"
+        @click="onRowClick(item, index)"
+      >
         <div v-for="(t, i) in columns" :key="`svvhbctr-${i}`" :style="{ flexBasis }" class="table__content__list_item">
           <slot :name="t.prop" :scope="item">
             <span v-if="t.prop == 'syswarnLevel'" style="display: flex; align-items: center;justify-content: center;">
@@ -51,9 +57,28 @@ let props = defineProps({
   defaultValue: {
     type: String,
     default: ''
+  },
+  /** 是否启用行点击选中 */
+  selectable: {
+    type: Boolean,
+    default: false
+  },
+  /** 行唯一键字段名 */
+  rowKey: {
+    type: String,
+    default: 'deviceID'
+  },
+  /** 当前选中行的 key */
+  selectedKey: {
+    type: [String, Number],
+    default: null
   }
 })
 
+const emit = defineEmits<{
+  (e: 'row-click', row: any, index: number): void
+}>()
+
 const scrollRef = ref(null);
 if (props.autoScroll) {
   useAutoScroll(scrollRef);
@@ -63,6 +88,23 @@ const flexBasis = computed(() => {
   return Math.fround(100 / props.columns.length) + '%';
 });
 
+/** 获取行唯一标识 */
+function getRowKey(item: any, index: number) {
+  return item?.[props.rowKey] ?? index
+}
+
+/** 判断行是否选中 */
+function isRowActive(item: any) {
+  if (props.selectedKey == null || props.selectedKey === '') return false
+  return String(item?.[props.rowKey]) === String(props.selectedKey)
+}
+
+/** 行点击 */
+function onRowClick(item: any, index: number) {
+  if (!props.selectable) return
+  emit('row-click', item, index)
+}
+
 /**
  * 安全获取对象属性值,当值为 null/undefined/空字符串时返回默认值
  *
@@ -188,11 +230,25 @@ function get(o, p) {
       background-repeat: no-repeat;
       background-position: center bottom;
       background-image: var(--image-content-text);
+      transition: box-shadow 0.2s, background-color 0.2s;
 
       span {
         display: inline-block;
         text-align: center;
       }
+
+      &.is-clickable {
+        cursor: pointer;
+
+        &:hover {
+          background-color: rgba(22, 90, 150, 0.28);
+        }
+      }
+
+      /* 选中高亮:半透明蓝底,与火区监测界面风格一致(无边框) */
+      &.is-active {
+        background-color: rgba(22, 90, 150, 0.55);
+      }
     }
   }
 

+ 331 - 12
src/views/vent/monitorManager/hsqHome/components/DeviceCenter.vue

@@ -2,17 +2,17 @@
   <div class="long-list1">
     <div class="list-title">
       <div class="title-l">
-        <span>设备详情-</span>
-        <span style="margin-left: 5px;">{{ detailDatas.strserno }}</span>
+        <span>前端配置</span>
+        <!-- <span style="margin-left: 5px;">{{ detailDatas.strserno }}</span> -->
       </div>
-      <div class="title-r">
+      <!-- <div class="title-r">
         <span :class="detailDatas.netStatus ? 'icon-pie' : 'icon-pie1'">
           <span :class="detailDatas.netStatus ? 'pie-item' : 'pie-item-warn'"></span>
         </span>
         <span>{{ detailDatas.netStatus ? '在线' : '离线' }}</span>
-      </div>
+      </div> -->
     </div>
-    <div class="basic-box">
+    <!-- <div class="basic-box">
       <basicBorder title="基本信息">
         <div class="basic-card">
           <div class="card-t">
@@ -53,10 +53,10 @@
           </div>
         </div>
       </basicBorder>
-    </div>
+    </div> -->
     <div class="basic-box">
-      <basicBorder title="实时状态">
-        <div class="basic-card">
+      <basicBorder title="告警参数">
+        <!-- <div class="basic-card">
           <div class="card-status-t">
             <div class="card-item">
               <SvgIcon class="icon-style" size="20" name="yxzt" />
@@ -103,12 +103,202 @@
               <div class="value-status-text">{{ detailDatas.csb || '-' }}</div>
             </div>
           </div>
+        </div> -->
+        <div class="temp-warn">
+          <div class="warn-item">
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div style="margin-right: 10px;">热源功能 </div>
+            </div>
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div style="margin-right: 10px;">闯入功能 </div>
+            </div>
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div style="margin-right: 10px;">热源跟踪 </div>
+            </div>
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div style="margin-right: 10px;">低小慢 </div>
+            </div>
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div style="margin-right: 10px;">高清推倍抓拍 </div>
+            </div>
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div style="margin-right: 10px;">热源测温 </div>
+            </div>
+          </div>
+          <div class="warn-item">
+            <div class="item-basic">
+              <div class="item-label1">告警阈值 : </div>
+              <a-input style="width: 150px;" v-model:value="formData.ld" placeholder="请输入" size="small" />
+              <span style="margin: 0 12px;">~</span>
+              <a-input style="width: 150px;" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">告警面积矢量 : </div>
+              <a-input style="width: 150px;" v-model:value="formData.ld" placeholder="请输入" size="small" />
+              <span style="margin: 0 11px;">~</span>
+              <a-input style="width: 150px;" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+          </div>
+          <div class="warn-item">
+            <div class="item-basic">
+              <div class="item-label1">辐射量平衡系数 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">材质发射率 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">环境温度 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+          </div>
+
+          <div class="warn-item">
+            <div class="item-basic">
+              <div class="item-label1">灰度值偏值 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">多热源区分阈值 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">动态屏蔽灵敏度 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+          </div>
+          <div class="warn-item">
+            <div class="item-basic">
+              <div class="item-label1">报警最小静止时长 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">半圈时长 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">停留时长 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+          </div>
+          <div class="warn-item">
+            <div class="item-basic">
+              <div class="item-label1">低小慢尾长 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">低小慢范围 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">设备号 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+          </div>
+          <div class="warn-item">
+            <div class="item-basic">
+              <div class="item-label1">设备名称 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">红外IP : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">子网掩码 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+          </div>
+          <div class="warn-item">
+            <div class="item-basic">
+              <div class="item-label1">网关 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">通讯端口号 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">告警端口号 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+          </div>
+          <div class="warn-item">
+            <div class="item-basic">
+              <div class="item-label1">横向视场角 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">纵向视场角: </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">主码分辨率: </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+          </div>
+          <div class="warn-item">
+            <div class="item-basic">
+              <div class="item-label1">子码分辨率 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">服务器IP: </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+            <div class="item-basic">
+              <div class="item-label1">服务器端口: </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+          </div>
+          <div class="warn-item">
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div style="margin-right: 10px;">显示最高温 </div>
+            </div>
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div style="margin-right: 10px;">显示最低温 </div>
+            </div>
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div style="margin-right: 10px;">显示平均温 </div>
+            </div>
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div style="margin-right: 10px;">显示运行模式 </div>
+            </div>
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div style="margin-right: 10px;">显示运行状态 </div>
+            </div>
+          </div>
+          <div class="warn-item">
+            <div class="item-basic">
+              <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+              <div>开启中心服务</div>
+            </div>
+          </div>
+          <div class="btn-box">
+            <div class="baisc-btn">获取</div>
+            <div class="baisc-btn">
+              <div class="btn-item">设置</div>
+            </div>
+          </div>
         </div>
       </basicBorder>
+
     </div>
     <div class="basic-box1">
-      <basicBorder title="历史报警记录">
-        <div class="basic-history">
+      <basicBorder title="【版本】">
+        <!-- <div class="basic-history">
           <div class="time-range">
             <a-range-picker v-model:value="timeRange" class="alarm-range-picker" show-time
               value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" :placeholder="['开始时间', '结束时间']"
@@ -124,8 +314,34 @@
               </div>
             </div>
           </div>
+        </div> -->
+        <div class="temp-warn">
+          <div class="warn-item">
+            <div class="item-basic">
+              <div class="item-label1">设备版本信息 : </div>
+              <a-input class="item-input" v-model:value="formData.ld" placeholder="请输入" size="small" />
+            </div>
+          </div>
+          <div class="btn-box version-btn">
+            <div class="baisc-btn">
+              <div class="btn-item">获取</div>
+            </div>
+          </div>
         </div>
       </basicBorder>
+
+    </div>
+    <div class="basic-box2">
+      <basicBorder title="【操作】">
+        <div class="btn-box">
+          <div class="baisc-btn-save">重启前端</div>
+          <div class="baisc-btn-save">
+            <div class="btn-item">恢复前端默认配置</div>
+          </div>
+          <div class="baisc-btn-save">保存前端配置</div>
+        </div>
+      </basicBorder>
+
     </div>
   </div>
 </template>
@@ -154,6 +370,7 @@ const timeRange = ref<[string, string]>([
   dayjs().startOf('day').format(DATE_FORMAT),
   dayjs().format(DATE_FORMAT),
 ])
+let formData = ref<any>({})
 
 // https获取监测数据
 let timer: null | NodeJS.Timeout = null;
@@ -292,12 +509,114 @@ onUnmounted(() => {
   }
 
   .basic-box {
-    height: 180px;
+    position: relative;
+    height: 480px;
     margin-bottom: 10px;
   }
 
   .basic-box1 {
-    height: calc(100% - 420px);
+    // height: calc(100% - 230px);
+    height: 125px;
+    margin-bottom: 10px;
+  }
+
+  .basic-box2 {
+    height: 85px;
+  }
+
+  .temp-warn {
+    position: relative;
+  }
+
+  .item-input {
+    width: 180px !important;
+  }
+
+  .warn-item {
+    display: flex;
+    align-items: center;
+    height: 32px;
+    background: linear-gradient(to right, #134c77, transparent);
+    margin-bottom: 10px;
+    padding: 0px 10px;
+    box-sizing: border-box;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+
+  .item-label {
+    width: 130px;
+    text-align: right;
+    margin-right: 5px;
+  }
+
+  .item-label1 {
+    width: 120px;
+    text-align: right;
+    margin-right: 5px;
+  }
+
+  .item-basic {
+    display: flex;
+    // flex: 1;
+    // justify-content: space-between;
+    align-items: center;
+  }
+
+  .zxm-input {
+    background-color: transparent;
+    border: 1px solid #2792c2;
+    color: #fff;
+  }
+
+  .zxm-checkbox-wrapper {
+    margin: 0px 10px 0px 55px;
+  }
+
+  .btn-box {
+    width: 100%;
+    display: flex;
+    justify-content: center;
+    gap: 10px;
+    align-items: center;
+    // position: absolute;
+    // right: 50%;
+    // bottom: 0px;
+    // transform: translate(-50%,0);
+  }
+
+  .baisc-btn {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 85px;
+    height: 30px;
+    border: 1px solid #01fefc;
+    border-radius: 4px;
+    padding: 3px;
+    cursor: pointer;
+  }
+
+  .baisc-btn-save {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    height: 30px;
+    border: 1px solid #01fefc;
+    border-radius: 4px;
+    padding: 4px;
+    cursor: pointer;
+  }
+
+  .btn-item {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(32, 166, 169);
   }
 
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1004 - 178
src/views/vent/monitorManager/hsqHome/components/DeviceControl.vue


+ 131 - 71
src/views/vent/monitorManager/hsqHome/components/DeviceRight.vue

@@ -9,32 +9,132 @@
           :key="index" @click="changeNav(item, index)">{{ item.label }}</div>
       </div>
       <div class="basic-box">
-        <basicBorder title="【设备基本信息】">
+        <basicBorder title="【设备管理】">
           <div class="temp-warn">
             <div class="warn-item">
-              <div class="item-label">安装位置 : </div>
+              <div class="item-label">设备号 : </div>
               <a-input class="item-input" v-model:value="formData.strinstallpos" placeholder="请输入" size="small" />
             </div>
             <div class="warn-item">
-              <div class="item-label">设备编码 : </div>
+              <div class="item-label">设备名称 : </div>
               <a-input class="item-input" v-model:value="formData.strserno" placeholder="请输入" size="small" />
             </div>
             <div class="warn-item">
-              <div class="item-label">生产厂家 : </div>
+              <div class="item-label">分组 : </div>
               <a-input class="item-input" v-model:value="formData.manufacturer" placeholder="请输入" size="small" />
             </div>
             <div class="warn-item">
-              <div class="item-label">坐标x : </div>
+              <div class="item-label">设备IP : </div>
               <a-input class="item-input" v-model:value="formData.alarm_east" placeholder="请输入" size="small" />
             </div>
             <div class="warn-item">
-              <div class="item-label">坐标y : </div>
+              <div class="item-label">通讯端口 : </div>
               <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
             </div>
+            <div class="warn-item">
+              <div class="item-basic">
+                <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+                <div style="margin-right: 8px;">是否带红外 </div>
+              </div>
+              <div class="item-basic">
+                <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+                <div style="margin-right: 8px;">是否高清 </div>
+              </div>
+              <div class="item-basic">
+                <a-checkbox v-model:checked="formData.yjgb"></a-checkbox>
+                <div >是否带云台 </div>
+              </div>
+            </div>
+            <div class="warn-item">
+              <div class="item-label">红外IP : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">红外端口 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">红外类型 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">红外用户名 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">红外密码 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">红外流地址 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">红外子码流地址 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">水平视场角 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">垂直视场角 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">高清IP : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">高清端口 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">高清类型 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">高清用户名 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">高清密码 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">高清流地址 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">高清子码流地址 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">安装高度 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">正北偏角 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">经度 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="warn-item">
+              <div class="item-label">纬度 : </div>
+              <a-input class="item-input" v-model:value="formData.alarm_north" placeholder="请输入" size="small" />
+            </div>
+            <div class="btn-box">
+              <div class="baisc-btn">恢复默认</div>
+              <div class="baisc-btn">
+                <div class="btn-item">保存设置</div>
+              </div>
+            </div>
           </div>
         </basicBorder>
       </div>
-      <div class="basic-box1">
+      <!-- <div class="basic-box1">
         <basicBorder title="【图像参数配置】">
           <div class="temp-warn">
             <div class="warn-item">
@@ -79,59 +179,12 @@
             </div>
           </div>
         </basicBorder>
-      </div>
-      <div class="basic-box1">
-        <basicBorder title="【联动配置】">
-          <div class="temp-warn">
-            <div class="warn-item">
-              <div class="item-basic">
-                <div class="item-label1">声光报警器联动 : </div>
-                <a-switch v-model:checked="formData.sgbjq" />
-              </div>
-              <div class="item-basic">
-                <div class="item-label1">短信通知联动 : </div>
-                <a-switch v-model:checked="formData.dxtz" />
-              </div>
-            </div>
-            <div class="warn-item">
-              <div class="item-basic">
-                <div class="item-label1">视频录制联动 : </div>
-                <a-switch v-model:checked="formData.splz" />
-              </div>
-              <div class="item-basic">
-                <div class="item-label1">消防系统联动 : </div>
-                <a-switch v-model:checked="formData.xfxt" />
-              </div>
-            </div>
-            <div class="warn-item">
-              <div class="item-basic">
-                <div class="item-label1">应急广播联动 : </div>
-                <a-switch v-model:checked="formData.yjgb" />
-              </div>
-              <div class="item-basic">
-                <div class="item-label1">大屏显示联动 : </div>
-                <a-switch v-model:checked="formData.dpxs" />
-              </div>
-            </div>
-            <div class="warn-item">
-              <div class="item-basic">
-                <div class="item-label1">GIS定位联动 : </div>
-                <a-switch v-model:checked="formData.gis" />
-              </div>
-              <div class="item-basic">
-                <div class="item-label1">数据记录联动 : </div>
-                <a-switch v-model:checked="formData.sjjl" />
-              </div>
-            </div>
-          </div>
+      </div> -->
+      <!-- <div class="basic-box1">
+        <basicBorder title="【摄像头配置】">
         </basicBorder>
-      </div>
-      <div class="btn-box">
-        <div class="baisc-btn">恢复默认</div>
-        <div class="baisc-btn">
-          <div class="btn-item">保存设置</div>
-        </div>
-      </div>
+      </div> -->
+
     </div>
   </div>
 </template>
@@ -161,8 +214,8 @@ function changeNav(item, index) {
 }
 
 watch(() => props.detailData, (newVal, oldVal) => {
-  console.log(newVal,'9900')
-  formData.value =Object.assign({},newVal.readData,newVal,)
+  console.log(newVal, '9900')
+  formData.value = Object.assign({}, newVal.readData, newVal,)
 }, { immediate: true })
 </script>
 
@@ -227,17 +280,19 @@ watch(() => props.detailData, (newVal, oldVal) => {
   }
 
   .basic-box {
-    height: 260px;
+    height: calc(100% - 47px);
     margin-bottom: 10px;
   }
 
   .basic-box1 {
-    height: 210px;
+    // height: 210px;
+    height: 430px;
     margin-bottom: 10px;
+
   }
 
   .temp-warn {
-    height: 100%;
+    position: relative;
   }
 
   .warn-item {
@@ -268,8 +323,8 @@ watch(() => props.detailData, (newVal, oldVal) => {
 
   .item-basic {
     display: flex;
-    flex: 1;
-    justify-content: space-between;
+    // flex: 1;
+    // justify-content: space-between;
     align-items: center;
   }
 
@@ -280,13 +335,14 @@ watch(() => props.detailData, (newVal, oldVal) => {
   }
 
   .btn-box {
-    width: 190px;
+    width: 100%;
     display: flex;
-    justify-content: space-between;
+    justify-content: center;
     align-items: center;
-    position: absolute;
-    right: 16px;
-    bottom: 18px;
+    gap: 10px;
+    // position: absolute;
+    // right: 16px;
+    // bottom: 18px;
   }
 
   .baisc-btn {
@@ -310,6 +366,10 @@ watch(() => props.detailData, (newVal, oldVal) => {
     background-color: rgba(32, 166, 169);
   }
 
+  .zxm-checkbox-wrapper {
+    margin: 0px 10px 0px 15px;
+  }
+
   ::-webkit-scrollbar {
     display: none;
   }

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1108 - 68
src/views/vent/monitorManager/hsqHome/components/DeviceTree.vue


+ 496 - 17
src/views/vent/monitorManager/hsqHome/components/DeviceView.vue

@@ -1,8 +1,9 @@
 <template>
   <!-- 设备画面组件:右侧面板上方,包含操作按钮和 2×4 监控画面网格 -->
   <div class="device-view">
-    <!-- 顶部操作按钮:最新热源 / 最新闯入 / 最新烟雾 / 关闭声光报警 -->
-    <div class="view-actions">
+   <div class="device-view-content">
+     <!-- 顶部操作按钮:最新热源 / 最新闯入 / 最新烟雾 / 关闭声光报警 -->
+     <div class="view-actions">
       <button v-for="btn in actions" :key="btn.key" type="button"
         :class="['action-btn', { active: activeAction === btn.key }]" @click="onAction(btn.key)">
         {{ btn.label }}
@@ -11,7 +12,7 @@
 
     <!-- 2×4 监控画面网格 -->
     <div class="view-grid">
-      <div class="view-cell" @click="selectChannel">
+      <div class="view-cell">
         <div class="media-wrap">
           <div
             v-if="renderPlayer"
@@ -40,13 +41,63 @@
         @change="onPageChange"
       />
     </div>
+   </div>
+
+    <!-- 最新热源 / 最新闯入 报警图片弹窗 -->
+    <Teleport to="body">
+      <div v-if="latestAlarmVisible" class="latest-alarm-mask" @click.self="closeLatestAlarmPopup">
+        <div :class="['latest-alarm-panel', { expanded: latestAlarmExpanded }]">
+          <div class="latest-alarm-frame">
+            <div class="latest-alarm-title-tab">{{ latestAlarmTitle }}</div>
+            <div class="latest-alarm-toolbar">
+              <button type="button" class="latest-alarm-icon-btn" title="放大" @click="toggleLatestAlarmExpand">
+                <svg viewBox="0 0 16 16" width="14" height="14">
+                  <rect x="3" y="3" width="7" height="7" fill="none" stroke="currentColor" stroke-width="1.3" />
+                  <path d="M9 3 H13 V7 M13 3 L9.5 6.5 M7 9 L3 13 M3 9 V13 H7" fill="none" stroke="currentColor"
+                    stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" />
+                </svg>
+              </button>
+              <button type="button" class="latest-alarm-icon-btn" title="关闭" @click="closeLatestAlarmPopup">
+                <svg viewBox="0 0 16 16" width="14" height="14">
+                  <rect x="2.5" y="2.5" width="8" height="8" fill="none" stroke="currentColor" stroke-width="1.3" />
+                  <path d="M8 8 L13.5 13.5 M10.5 13.5 H13.5 V10.5" fill="none" stroke="currentColor" stroke-width="1.3"
+                    stroke-linecap="round" stroke-linejoin="round" />
+                </svg>
+              </button>
+            </div>
+
+            <div class="latest-alarm-image-wrap">
+              <img
+                v-if="latestAlarmData.imageUrl"
+                class="latest-alarm-image"
+                :src="latestAlarmData.imageUrl"
+                :alt="latestAlarmTitle"
+              />
+              <div v-else class="latest-alarm-image-empty">暂无告警图像</div>
+              <div class="latest-alarm-overlay bottom-right">{{ latestAlarmData.deviceName || '--' }}</div>
+            </div>
+
+            <div class="latest-alarm-footer">
+              <span>告警时间:{{ latestAlarmData.alarmTime || '--' }}</span>
+              <span class="latest-alarm-sep">|</span>
+              <span>告警设备:{{ latestAlarmData.deviceName || '--' }}</span>
+              <span class="latest-alarm-sep">|</span>
+              <span>告警类型:{{ latestAlarmData.alarmType || '--' }}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </Teleport>
   </div>
 </template>
 
 <script setup lang="ts">
 import { nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
+import dayjs from 'dayjs'
 import { useCamera } from '/@/hooks/system/useCameraPianation'
-
+import { useMessage } from '/@/hooks/web/useMessage'
+import { getFileAccessHttpUrl } from '/@/utils/common/compUtils'
+import { dscAlarmLogList } from '../hsqHome.api'
 
 /** 操作按钮数据结构 */
 interface ActionItem {
@@ -54,6 +105,20 @@ interface ActionItem {
   label: string
 }
 
+/** 最新报警弹窗展示数据 */
+interface LatestAlarmPopupData {
+  imageUrl: string
+  alarmTime: string
+  deviceName: string
+  alarmType: string
+}
+
+/** 事件类型编码:热源 / 闯入 */
+const EVENT_TYPE_MAP: Record<string, { code: string; title: string; typeLabel: string }> = {
+  heat: { code: '10001', title: '最新热源告警图', typeLabel: '热源报警' },
+  intrusion: { code: '10002', title: '最新闯入告警图', typeLabel: '闯入报警' },
+}
+
 let props = defineProps({
   deviceId: {
     type: String,
@@ -70,15 +135,17 @@ const emit = defineEmits<{
 const { getCamera, removeCamera, Total: total } = useCamera()
 const playerRef = ref()
 const renderPlayer = ref(true)
-/** 网格分页:2×4,每页 8 路画面;autoPlayStart/Count 控制自动播放区间 */
+/** 网格分页:2×4,每页 8 路画面;autoPlayStart/Count 控制自动播放区间;onCameraSelect 选中回调 */
 const pagination = reactive<{
   current: number
   pageSize: number
   autoPlayStart?: number
   autoPlayCount?: number
+  onCameraSelect?: (camera: any, index: number) => void
 }>({
   current: 1,
   pageSize: 8,
+  onCameraSelect: handleCameraSelect,
 })
 /** 顶部操作按钮列表 */
 const actions: ActionItem[] = [
@@ -90,21 +157,214 @@ const actions: ActionItem[] = [
 
 /** 当前激活的操作按钮 */
 const activeAction = ref('')
-/** 当前选中的通道 ID */
+/** 当前选中的通道 ID / 名称 */
 const selectedId = ref('')
+/** 当前选中的画面下标 */
+const selectedIndex = ref(-1)
 /** 取流播放模式:visible 前4播后4停;infrared 前4停后4播 */
 const streamPlayMode = ref<'visible' | 'infrared' | null>(null)
+/** 各画面本地焦距缩放比例(不调接口) */
+const viewZoomMap = reactive<Record<number, number>>({})
+/** 各画面本地焦点模糊程度(px,不调接口) */
+const viewFocusBlurMap = reactive<Record<number, number>>({})
+/** 各画面本地光圈亮度系数(1 为正常,不调接口) */
+const viewIrisBrightMap = reactive<Record<number, number>>({})
+const ZOOM_STEP = 0.15
+const ZOOM_MIN = 1
+const ZOOM_MAX = 3
+const FOCUS_BLUR_STEP = 0.4
+const FOCUS_BLUR_MIN = 0
+const FOCUS_BLUR_MAX = 4
+const IRIS_BRIGHT_STEP = 0.12
+const IRIS_BRIGHT_MIN = 0.4
+const IRIS_BRIGHT_MAX = 2
+
+const { createMessage } = useMessage()
+
+/** 最新报警弹窗 */
+const latestAlarmVisible = ref(false)
+const latestAlarmExpanded = ref(false)
+const latestAlarmTitle = ref('最新热源告警图')
+const latestAlarmLoading = ref(false)
+const latestAlarmData = reactive<LatestAlarmPopupData>({
+  imageUrl: '',
+  alarmTime: '',
+  deviceName: '',
+  alarmType: '',
+})
+
+/** 解析报警记录中的图片地址 */
+function resolveAlarmImageUrl(record: Record<string, any>) {
+  const raw =
+    record.picName ||
+    record.picName2 ||
+    ''
+  if (!raw) return ''
+  const text = String(raw)
+  if (/^https?:\/\//i.test(text) || text.startsWith('data:')) return text
+  // 兼容路径中带盘符前缀的情况(与报警详情一致)
+  const path = text.includes('h') ? text.substring(text.indexOf('h')) : text
+  return getFileAccessHttpUrl(path.replace(/\\/g, '/'))
+}
+
+/** 从列表中过滤出指定类型的最新一条记录 */
+function pickLatestAlarmRecord(records: any[], eventCode: string) {
+  const matched = (records || []).filter((item) => String(item?.eventType) === eventCode)
+  if (!matched.length) return null
+  return matched
+    .slice()
+    .sort(
+      (a, b) =>
+        dayjs(b.createTime || b.alarmTime || 0).valueOf() -
+        dayjs(a.createTime || a.alarmTime || 0).valueOf(),
+    )[0]
+}
+
+/** 点击最新热源 / 最新闯入:请求列表后展示对应最新报警图 */
+async function openLatestAlarmByType(key: 'heat' | 'intrusion') {
+  if (latestAlarmLoading.value) return
+  const meta = EVENT_TYPE_MAP[key]
+  if (!meta) return
+
+  latestAlarmLoading.value = true
+  try {
+    const res = await dscAlarmLogList({ pageNo: 1, pageSize: 1000 })
+    const records = res?.records || []
+    console.log('报警图片列表', records)
+    const latest = pickLatestAlarmRecord(records, meta.code)
+    if (!latest) {
+      createMessage.warning(`暂无${meta.typeLabel}数据`)
+      return
+    }
+
+    latestAlarmTitle.value = meta.title
+    latestAlarmData.imageUrl = resolveAlarmImageUrl(latest)
+    latestAlarmData.alarmTime = String(latest.createTime || latest.alarmTime || '')
+    latestAlarmData.deviceName = String(latest.deviceName || latest.devId || latest.strname || '')
+    latestAlarmData.alarmType = meta.typeLabel
+    latestAlarmExpanded.value = false
+    latestAlarmVisible.value = true
+  } catch (e) {
+    console.error('获取最新报警记录失败', e)
+    createMessage.error('获取最新报警记录失败')
+  } finally {
+    latestAlarmLoading.value = false
+  }
+}
+
+function toggleLatestAlarmExpand() {
+  latestAlarmExpanded.value = !latestAlarmExpanded.value
+}
+
+function closeLatestAlarmPopup() {
+  latestAlarmVisible.value = false
+  latestAlarmExpanded.value = false
+}
 
 /** 点击操作按钮,触发 action 事件 */
 function onAction(key: string) {
   activeAction.value = key
+  if (key === 'heat' || key === 'intrusion') {
+    openLatestAlarmByType(key)
+  }
   emit('action', key)
 }
 
 /** 选中监控通道,触发 select 事件 */
-function selectChannel(item) {
-  selectedId.value = item.id
-  emit('select', item)
+function handleCameraSelect(camera: any, index: number) {
+  selectedIndex.value = index
+  selectedId.value = camera?.id || camera?.name || String(index)
+  const deviceid =
+    camera?.deviceid ||
+    camera?.deviceId ||
+    camera?.deviceID ||
+    camera?.devId ||
+    ''
+  emit('select', {
+    ...camera,
+    index,
+    deviceid: deviceid != null && deviceid !== '' ? String(deviceid) : '',
+    ip: camera?.ip || camera?.strip || '',
+  })
+  applyViewLensStyles()
+}
+
+/** 对当前选中画面做本地焦距缩放(不调接口) */
+function zoomSelectedView(direction: 1 | -1) {
+  if (selectedIndex.value < 0) return
+  const index = selectedIndex.value
+  const current = viewZoomMap[index] ?? 1
+  const next = Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, Number((current + direction * ZOOM_STEP).toFixed(2))))
+  viewZoomMap[index] = next
+  applyViewLensStyles()
+}
+
+/**
+ * 对当前选中画面做本地焦点调节(不调接口)
+ * direction > 0 焦点后调(更模糊);direction < 0 焦点前调(更清晰)
+ */
+function focusSelectedView(direction: 1 | -1) {
+  if (selectedIndex.value < 0) return
+  const index = selectedIndex.value
+  const current = viewFocusBlurMap[index] ?? 0
+  const next = Math.min(
+    FOCUS_BLUR_MAX,
+    Math.max(FOCUS_BLUR_MIN, Number((current + direction * FOCUS_BLUR_STEP).toFixed(2))),
+  )
+  viewFocusBlurMap[index] = next
+  applyViewLensStyles()
+}
+
+/**
+ * 对当前选中画面做本地光圈调节(不调接口)
+ * direction > 0 光圈扩大(更亮);direction < 0 光圈缩小(更暗)
+ */
+function irisSelectedView(direction: 1 | -1) {
+  if (selectedIndex.value < 0) return
+  const index = selectedIndex.value
+  const current = viewIrisBrightMap[index] ?? 1
+  const next = Math.min(
+    IRIS_BRIGHT_MAX,
+    Math.max(IRIS_BRIGHT_MIN, Number((current + direction * IRIS_BRIGHT_STEP).toFixed(2))),
+  )
+  viewIrisBrightMap[index] = next
+  applyViewLensStyles()
+}
+
+/** 获取画面实际绘制节点(video/canvas),避免操作外层容器 */
+function getPaintNode(item: HTMLElement) {
+  const media = item.querySelector('video, canvas') as HTMLElement | null
+    || (item.querySelector('.liveVideo') as HTMLElement | null)
+  if (!media || media === item) return null
+  return (media.matches('video, canvas')
+    ? media
+    : (media.querySelector('video, canvas') as HTMLElement | null) || media)
+}
+
+/** 把焦距缩放 + 焦点模糊 + 光圈亮度应用到对应画面内容(不改变外层容器尺寸) */
+function applyViewLensStyles() {
+  const root = playerRef.value as HTMLElement | undefined
+  if (!root) return
+  const items = Array.from(root.querySelectorAll('.live-video-item')) as HTMLElement[]
+  items.forEach((item, index) => {
+    item.style.overflow = 'hidden'
+    item.style.transform = ''
+
+    const paintNode = getPaintNode(item)
+    if (!paintNode) return
+
+    const scale = viewZoomMap[index] ?? 1
+    const blur = viewFocusBlurMap[index] ?? 0
+    const bright = viewIrisBrightMap[index] ?? 1
+    const filters: string[] = []
+    if (bright !== 1) filters.push(`brightness(${bright})`)
+    if (blur > 0) filters.push(`blur(${blur}px)`)
+
+    paintNode.style.transformOrigin = 'center center'
+    paintNode.style.transition = 'transform 0.15s ease, filter 0.15s ease'
+    paintNode.style.transform = scale === 1 ? 'none' : `scale(${scale})`
+    paintNode.style.filter = filters.length ? filters.join(' ') : 'none'
+  })
 }
 
 /** 同步分页上的自动播放区间 */
@@ -160,13 +420,24 @@ async function loadCameraList() {
   if (streamPlayMode.value) {
     await nextTick()
     // 等待播放器挂载完成后再校正播放状态
-    setTimeout(() => applyStreamPlayState(), 300)
+    setTimeout(() => {
+      applyStreamPlayState()
+      applyViewLensStyles()
+    }, 300)
+  } else {
+    await nextTick()
+    setTimeout(() => applyViewLensStyles(), 300)
   }
 }
 
 /** 分页切换 */
 async function onPageChange(page: number) {
   pagination.current = page
+  selectedIndex.value = -1
+  selectedId.value = ''
+  Object.keys(viewZoomMap).forEach((key) => delete viewZoomMap[Number(key)])
+  Object.keys(viewFocusBlurMap).forEach((key) => delete viewFocusBlurMap[Number(key)])
+  Object.keys(viewIrisBrightMap).forEach((key) => delete viewIrisBrightMap[Number(key)])
   await loadCameraList()
 }
 
@@ -178,6 +449,11 @@ watch(
   () => props.deviceId,
   async () => {
     pagination.current = 1
+    selectedIndex.value = -1
+    selectedId.value = ''
+    Object.keys(viewZoomMap).forEach((key) => delete viewZoomMap[Number(key)])
+    Object.keys(viewFocusBlurMap).forEach((key) => delete viewFocusBlurMap[Number(key)])
+    Object.keys(viewIrisBrightMap).forEach((key) => delete viewIrisBrightMap[Number(key)])
     await loadCameraList()
   }
 )
@@ -190,6 +466,9 @@ defineExpose({
   enableVisibleLightPlayMode,
   enableInfraredPlayMode,
   applyStreamPlayState,
+  zoomSelectedView,
+  focusSelectedView,
+  irisSelectedView,
 })
 </script>
 
@@ -203,15 +482,21 @@ defineExpose({
   --dv-accent-soft: rgba(0, 212, 255, 0.45);
   --dv-text: #d8f4ff;
 
+  position: relative;
   width: 100%;
   height: 100%;
+  padding: 15px;
+  box-sizing: border-box;
+}
+.device-view-content{
+  width:100%;
+  height: 100%; 
   display: flex;
   flex-direction: column;
   overflow: hidden;
   color: var(--dv-text);
   user-select: none;
-  padding: 15px;
-  box-sizing: border-box;
+  // margin: 15px;
 }
 
 // 顶部操作按钮栏
@@ -251,6 +536,7 @@ defineExpose({
 
 // 2×4 监控画面网格
 .view-grid {
+  position: relative;
   flex: 1;
   min-height: 0;
   display: flex;
@@ -329,23 +615,216 @@ defineExpose({
   justify-content: flex-start;
   flex-wrap: wrap;
   pointer-events: none;
-  gap:  10px;
+  gap: 10px;
+
+  .live-video-item {
+    width: 349px;
+    height: 220px;
+    padding: 12px 8px;
+    box-sizing: border-box;
+    pointer-events: auto;
+    cursor: pointer;
+    background-size: 100% 100%;
+    border: 1px solid transparent;
+    border-radius: 2px;
+    transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s;
+    /* 变焦时容器尺寸不变,仅裁剪放大后的画面 */
+    overflow: hidden;
+    position: relative;
+    flex: 0 0 349px;
+
+    &:hover {
+      border-color: rgba(1, 254, 252, 0.45);
+      box-shadow: 0 0 8px rgba(0, 183, 255, 0.25);
+    }
+
+    /* 选中态:青色描边高亮,与监控界面风格一致 */
+    &.is-selected {
+      border-color: #01fefc;
+      box-shadow:
+        0 0 10px rgba(1, 254, 252, 0.45),
+        inset 0 0 12px rgba(0, 183, 255, 0.12);
+      background-color: rgba(0, 90, 140, 0.18);
+    }
+
+    /* 内层媒体区:占满内容区,作为裁剪视口 */
+    .liveVideo,
+    video,
+    canvas {
+      display: block;
+      width: 100% !important;
+      height: 100% !important;
+      max-width: 100%;
+      max-height: 100%;
+      object-fit: cover;
+      transform-origin: center center;
+    }
+  }
 
   .liveVideo {
-    width: 349px !important;
-    height: 220px !important;
-    padding: 12px 8px !important;
+    width: 100% !important;
+    height: 100% !important;
+    padding: 0 !important;
     align-self: auto !important;
-    // margin: 8px !important;
     background-size: 100% 100% !important;
+    pointer-events: none;
+    overflow: hidden;
   }
 
   .video-parent {
     pointer-events: auto !important;
     align-self: auto !important;
+    overflow: hidden;
+    width: 100%;
+    height: 100%;
   }
 }
 ::-webkit-scrollbar {
     display: none;
   }
+
+/* 最新热源 / 最新闯入 弹窗(风格对齐报警自动弹窗) */
+.latest-alarm-mask {
+  position: fixed;
+  inset: 0;
+  z-index: 2200;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: rgba(0, 8, 20, 0.55);
+}
+
+.latest-alarm-panel {
+  width: min(720px, 92vw);
+  max-height: 90vh;
+
+  &.expanded {
+    width: min(1080px, 96vw);
+  }
+}
+
+.latest-alarm-frame {
+  position: relative;
+  padding: 18px 12px 0;
+  background: linear-gradient(180deg, rgba(6, 28, 48, 0.98) 0%, rgba(4, 16, 32, 0.98) 100%);
+  border: 1px solid rgba(0, 210, 255, 0.85);
+  box-shadow:
+    0 0 0 2px rgba(8, 40, 70, 0.95),
+    0 0 22px rgba(0, 200, 255, 0.35),
+    inset 0 0 0 1px rgba(0, 180, 255, 0.35);
+  clip-path: polygon(
+    10px 0,
+    calc(100% - 10px) 0,
+    100% 10px,
+    100% calc(100% - 10px),
+    calc(100% - 10px) 100%,
+    10px 100%,
+    0 calc(100% - 10px),
+    0 10px
+  );
+}
+
+.latest-alarm-title-tab {
+  position: absolute;
+  top: -1px;
+  left: 50%;
+  transform: translateX(-50%);
+  min-width: 168px;
+  height: 28px;
+  padding: 0 28px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #fff;
+  font-size: 14px;
+  font-weight: 600;
+  letter-spacing: 1px;
+  background: linear-gradient(180deg, #2ad4e8 0%, #1498b8 55%, #0c6f8a 100%);
+  clip-path: polygon(12px 0, calc(100% - 12px) 0, 100% 100%, 0 100%);
+  box-shadow: 0 0 10px rgba(0, 200, 255, 0.45);
+  z-index: 2;
+}
+
+.latest-alarm-toolbar {
+  position: absolute;
+  top: 8px;
+  right: 12px;
+  display: flex;
+  gap: 8px;
+  z-index: 3;
+}
+
+.latest-alarm-icon-btn {
+  width: 22px;
+  height: 22px;
+  padding: 0;
+  border: none;
+  background: transparent;
+  color: #e8f4ff;
+  cursor: pointer;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+
+  &:hover {
+    color: #01fefc;
+  }
+}
+
+.latest-alarm-image-wrap {
+  position: relative;
+  margin-top: 14px;
+  height: 380px;
+  border: 1px solid rgba(0, 183, 255, 0.45);
+  background: #000;
+  overflow: hidden;
+
+  .latest-alarm-panel.expanded & {
+    height: 560px;
+  }
+}
+
+.latest-alarm-image {
+  width: 100%;
+  height: 100%;
+  object-fit: contain;
+  display: block;
+}
+
+.latest-alarm-image-empty {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: rgba(200, 220, 235, 0.55);
+  font-size: 14px;
+}
+
+.latest-alarm-overlay {
+  position: absolute;
+  color: #fff;
+  font-size: 13px;
+  text-shadow: 0 0 4px rgba(0, 0, 0, 0.85);
+  pointer-events: none;
+
+  &.bottom-right {
+    right: 10px;
+    bottom: 10px;
+  }
+}
+
+.latest-alarm-footer {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  gap: 8px;
+  padding: 10px 8px 12px;
+  color: #cfe9ff;
+  font-size: 13px;
+}
+
+.latest-alarm-sep {
+  color: rgba(1, 254, 252, 0.55);
+}
 </style>

+ 1 - 0
src/views/vent/monitorManager/hsqHome/components/DeviceWarnList.vue

@@ -21,6 +21,7 @@
 </template>
 
 <script setup lang="ts">
+import type { PropType } from 'vue'
 import basicBorder from './basicBorder.vue'
 // 表格列配置(从数据文件导入)
 import {videoColumns} from '../hsqHome.data.js'

+ 498 - 0
src/views/vent/monitorManager/hsqHome/components/HistoryFilterTree.vue

@@ -0,0 +1,498 @@
+<template>
+  <div class="history-filter-tree">
+    <div class="list-title">
+      <span>数据筛选</span>
+    </div>
+
+    <div class="list-content">
+      <!-- 时间范围(与报警监控时间组件一致) -->
+      <div class="filter-form">
+        <div class="time-range">
+          <a-range-picker
+            v-model:value="timeRange"
+            class="alarm-range-picker"
+            show-time
+            value-format="YYYY-MM-DD HH:mm:ss"
+            format="YYYY-MM-DD HH:mm:ss"
+            :placeholder="['开始时间', '结束时间']"
+            :allow-clear="false"
+            :get-popup-container="popupContainer"
+          />
+        </div>
+      </div>
+
+      <!-- 设备树勾选 -->
+      <div class="filter-tree">
+        <div v-for="group in filterTree" :key="group.id" class="tree-group">
+          <div class="group-row" @click="toggleGroup(group.id)">
+            <span :class="['expand-icon', { collapsed: !group.expanded }]">
+              <svg viewBox="0 0 10 10" width="10" height="10">
+                <path
+                  d="M1 3.2 L5 7.2 L9 3.2"
+                  fill="none"
+                  stroke="currentColor"
+                  stroke-width="1.4"
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                />
+              </svg>
+            </span>
+            <a-checkbox
+              class="tree-check"
+              :checked="isGroupChecked(group)"
+              :indeterminate="isGroupPartial(group)"
+              @click.stop
+              @update:checked="(val) => toggleGroupCheck(group, !!val)"
+            />
+            <span class="group-title" :title="group.title">{{ group.title }}</span>
+          </div>
+
+          <div v-show="group.expanded" class="group-children">
+            <div
+              v-for="(device, index) in group.children"
+              :key="device.id"
+              :class="['device-row', { 'is-last': index === group.children.length - 1 }]"
+            >
+              <span class="tree-line"></span>
+              <a-checkbox
+                class="tree-check"
+                :checked="device.checked"
+                @update:checked="(val) => toggleDeviceCheck(group, device, !!val)"
+              />
+              <span class="device-name" :title="device.name">{{ device.name }}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- 底部操作(检索对齐填充按钮,导出对齐「重启前端」描边按钮) -->
+      <div class="filter-actions">
+        <div class="baisc-btn" @click="onSearch">
+          <div class="btn-item">检索</div>
+        </div>
+        <div class="baisc-btn-save" @click="onExport">导出</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, reactive, ref, watch, type PropType } from 'vue'
+import dayjs from 'dayjs'
+import type {
+  HistoryFilterDeviceNode,
+  HistoryFilterGroupNode,
+  HistoryFilterPayload,
+} from './type'
+import { managesysList, monitorSystem } from '../hsqHome.api'
+
+const DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss'
+
+const props = defineProps({
+  /** 外部传入设备树;未传时按视频预览同接口自行拉取 */
+  treeData: {
+    type: Array as PropType<HistoryFilterGroupNode[]>,
+    default: () => [],
+  },
+})
+
+const emit = defineEmits<{
+  (e: 'search', payload: HistoryFilterPayload): void
+  (e: 'export', payload: HistoryFilterPayload): void
+}>()
+
+/** 时间范围:[开始时间, 结束时间],默认近 7 天至当前 */
+const timeRange = ref<[string, string]>([
+  dayjs().subtract(7, 'day').startOf('day').format(DATE_FORMAT),
+  dayjs().format(DATE_FORMAT),
+])
+
+const filterTree = reactive<HistoryFilterGroupNode[]>([])
+const treeLoading = ref(false)
+
+const popupContainer = (trigger: HTMLElement) => trigger.parentNode as HTMLElement
+
+watch(
+  () => props.treeData,
+  (list) => {
+    if (list?.length) {
+      filterTree.splice(0, filterTree.length, ...cloneTree(list))
+    }
+  },
+  { deep: true },
+)
+
+function cloneTree(list: HistoryFilterGroupNode[]): HistoryFilterGroupNode[] {
+  return list.map((group) => ({
+    ...group,
+    children: (group.children || []).map((child) => ({ ...child })),
+  }))
+}
+
+/**
+ * 将 monitorSystem 返回的双光谱设备列表转为筛选树结构
+ * 字段映射与视频预览设备树保持一致:deviceID → id,strname → name
+ */
+function mapMonitorToFilterTree(res: any): HistoryFilterGroupNode[] {
+  const rawList = res?.deviceInfo?.duaSpeCamera?.datalist || []
+  const data = rawList.map((el: any) => Object.assign({}, el, el.readData))
+  return [
+    {
+      id: 'g1',
+      title: '双光谱摄像机',
+      checked: true,
+      expanded: true,
+      children: data.map((d: any) => ({
+        id: String(d.deviceID ?? d.id ?? ''),
+        name: String(d.strname || d.name || ''),
+        checked: true,
+      })),
+    },
+  ]
+}
+
+/** 刷新时保留已有勾选状态,避免重置 */
+function mergeCheckedState(next: HistoryFilterGroupNode[]): HistoryFilterGroupNode[] {
+  const checkedMap = new Map<string, boolean>()
+  filterTree.forEach((group) => {
+    group.children?.forEach((device) => {
+      checkedMap.set(device.id, !!device.checked)
+    })
+  })
+  return next.map((group) => {
+    const children = (group.children || []).map((child) => ({
+      ...child,
+      checked: checkedMap.has(child.id) ? !!checkedMap.get(child.id) : child.checked,
+    }))
+    return {
+      ...group,
+      children,
+      checked: children.length > 0 && children.every((c) => c.checked),
+    }
+  })
+}
+
+/**
+ * 与视频预览设备树一致:
+ * 1) managesysList 取系统 ID
+ * 2) monitorSystem 拉取设备并组装树
+ */
+async function loadDeviceTree() {
+  if (props.treeData?.length) {
+    filterTree.splice(0, filterTree.length, ...cloneTree(props.treeData))
+    return
+  }
+  if (treeLoading.value) return
+  treeLoading.value = true
+  try {
+    const sysRes = await managesysList({ strtype: 'sys_openair_fire', pagetype: 'normal' })
+    const systemID = sysRes?.records?.[0]?.id
+    if (!systemID) {
+      filterTree.splice(0, filterTree.length)
+      return
+    }
+    const res = await monitorSystem({ type: 'all', systemID, devicetype: '' })
+    const next = mergeCheckedState(mapMonitorToFilterTree(res))
+    filterTree.splice(0, filterTree.length, ...cloneTree(next))
+  } catch (e) {
+    console.error('历史报表设备树加载失败', e)
+  } finally {
+    treeLoading.value = false
+  }
+}
+
+function isGroupChecked(group: HistoryFilterGroupNode) {
+  const children = group.children || []
+  return children.length > 0 && children.every((item) => item.checked)
+}
+
+function isGroupPartial(group: HistoryFilterGroupNode) {
+  const children = group.children || []
+  const checkedCount = children.filter((item) => item.checked).length
+  return checkedCount > 0 && checkedCount < children.length
+}
+
+function toggleGroup(id: string) {
+  const group = filterTree.find((item) => item.id === id)
+  if (!group) return
+  group.expanded = !group.expanded
+}
+
+function toggleGroupCheck(group: HistoryFilterGroupNode, checked: boolean) {
+  group.checked = checked
+  group.children.forEach((child) => {
+    child.checked = checked
+  })
+}
+
+function toggleDeviceCheck(
+  group: HistoryFilterGroupNode,
+  device: HistoryFilterDeviceNode,
+  checked: boolean,
+) {
+  device.checked = checked
+  group.checked = isGroupChecked(group)
+}
+
+function buildPayload(): HistoryFilterPayload {
+  const deviceIds = filterTree.flatMap((group) =>
+    group.children.filter((item) => item.checked).map((item) => item.id),
+  )
+  return {
+    startTime: timeRange.value?.[0] || '',
+    endTime: timeRange.value?.[1] || '',
+    deviceIds,
+  }
+}
+
+function onSearch() {
+  emit('search', buildPayload())
+}
+
+function onExport() {
+  emit('export', buildPayload())
+}
+
+onMounted(() => {
+  loadDeviceTree()
+})
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.history-filter-tree {
+  --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-5.png');
+  --hf-text: #e8f4ff;
+
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 15px;
+  box-sizing: border-box;
+  color: var(--hf-text);
+  display: flex;
+  flex-direction: column;
+}
+
+.list-title {
+  width: 177px;
+  height: 30px;
+  line-height: 22px;
+  padding-left: 16px;
+  color: #01fefc;
+  font-weight: bolder;
+  background: var(--image-box-bg) no-repeat;
+  background-size: 100% 100%;
+  margin-bottom: 10px;
+  flex-shrink: 0;
+}
+
+.list-content {
+  width: 100%;
+  flex: 1;
+  min-height: 0;
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.filter-form {
+  flex-shrink: 0;
+  padding: 4px 0 0;
+}
+
+.time-range {
+  width: 100%;
+}
+
+.alarm-range-picker {
+  width: 100%;
+}
+
+:deep(.zxm-picker) {
+  width: 100%;
+  height: 28px;
+  border: 1px solid #3ae1ff !important;
+  background-color: rgba(16, 64, 100, 0.85) !important;
+  box-shadow: 0 0 6px rgba(58, 225, 255, 0.25);
+}
+
+:deep(.zxm-picker-input > input) {
+  color: #fff !important;
+  font-size: 14px;
+  text-align: center;
+}
+
+:deep(.zxm-picker-input > input::placeholder) {
+  color: rgba(200, 236, 255, 0.45) !important;
+}
+
+:deep(.zxm-picker-separator),
+:deep(.zxm-picker-suffix),
+:deep(.zxm-picker-clear) {
+  color: #3ae1ff !important;
+}
+
+.filter-tree {
+  flex: 1;
+  min-height: 0;
+  overflow: auto;
+  padding: 4px 2px 8px;
+}
+
+.tree-group {
+  margin-bottom: 4px;
+}
+
+.group-row,
+.device-row {
+  display: flex;
+  align-items: center;
+  min-height: 30px;
+  gap: 8px;
+  user-select: none;
+}
+
+.group-row {
+  padding: 0 6px;
+  cursor: pointer;
+
+  &:hover {
+    background: rgba(255, 255, 255, 0.03);
+  }
+}
+
+.expand-icon {
+  width: 14px;
+  height: 14px;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  color: #d8e6f5;
+  transition: transform 0.2s;
+  flex-shrink: 0;
+
+  &.collapsed {
+    transform: rotate(-90deg);
+  }
+}
+
+.group-title,
+.device-name {
+  flex: 1;
+  min-width: 0;
+  color: #fff;
+  font-size: 13px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.group-children {
+  position: relative;
+}
+
+.device-row {
+  position: relative;
+  padding: 0 6px 0 28px;
+
+  .tree-line {
+    position: absolute;
+    left: 14px;
+    top: 0;
+    bottom: 0;
+    width: 0;
+    border-left: 1px solid rgba(180, 210, 235, 0.35);
+  }
+
+  &.is-last .tree-line {
+    bottom: 50%;
+  }
+}
+
+.tree-check {
+  margin: 0 !important;
+  flex-shrink: 0;
+
+  :deep(.ant-checkbox-inner),
+  :deep(.zxm-checkbox-inner) {
+    width: 14px;
+    height: 14px;
+    background: transparent !important;
+    border-color: rgba(230, 240, 255, 0.95) !important;
+    border-radius: 2px;
+  }
+
+  :deep(.ant-checkbox-checked .ant-checkbox-inner),
+  :deep(.zxm-checkbox-checked .zxm-checkbox-inner) {
+    background: #fff !important;
+    border-color: #fff !important;
+  }
+
+  :deep(.ant-checkbox-checked .ant-checkbox-inner::after),
+  :deep(.zxm-checkbox-checked .zxm-checkbox-inner::after) {
+    border-color: #111 !important;
+  }
+
+  :deep(.ant-checkbox-indeterminate .ant-checkbox-inner::after),
+  :deep(.zxm-checkbox-indeterminate .zxm-checkbox-inner::after) {
+    background: #111 !important;
+  }
+
+  :deep(.ant-checkbox + span),
+  :deep(.zxm-checkbox + span) {
+    display: none;
+  }
+}
+
+.filter-actions {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 10px;
+  flex-shrink: 0;
+  padding: 4px 8px 2px;
+}
+
+.baisc-btn {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 85px;
+  height: 30px;
+  border: 1px solid #01fefc;
+  border-radius: 4px;
+  padding: 3px;
+  cursor: pointer;
+  box-sizing: border-box;
+}
+
+.baisc-btn-save {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 85px;
+  height: 30px;
+  border: 1px solid #01fefc;
+  border-radius: 4px;
+  padding: 4px;
+  cursor: pointer;
+  box-sizing: border-box;
+  color: #fff;
+  font-size: 14px;
+  letter-spacing: 1px;
+}
+
+.btn-item {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(32, 166, 169);
+  color: #fff;
+  font-size: 14px;
+  letter-spacing: 1px;
+}
+</style>

+ 104 - 140
src/views/vent/monitorManager/hsqHome/components/WarnCenTop.vue

@@ -2,31 +2,26 @@
   <div class="mixed-warn">
     <div class="list-title">
       <span>报警详情</span>
-      <!-- <span style="margin-left: 5px;">{{ warnData.devId || '-' }}</span> -->
     </div>
     <div class="list-t">
       <div class="basic-box">
         <div class="box-btn">
-          <div v-for="(btn, index) in actionBtns" :key="btn.key"
-            :class="['baisc-btn', { 'baisc-btn-active': activeBtn == btn.key }]" @click="changeStep(btn)">
+          <div
+            v-for="btn in actionBtns"
+            :key="btn.key"
+            :class="['baisc-btn', { 'baisc-btn-active': activeBtn == btn.key }]"
+            @click="changeStep(btn)"
+          >
             <div class="btn-item">{{ btn.label }}</div>
           </div>
         </div>
         <div class="echart-box">
-          <div class="box-img">
+          <div v-for="(src, index) in warnPicUrls" :key="index" class="box-img">
             <img
-              v-if="picUrl1"
-              :src="picUrl1"
+              v-if="src"
+              :src="src"
               title="双击放大预览"
-              @dblclick="openPreview(picUrl1)"
-            />
-          </div>
-          <div class="box-img">
-            <img
-              v-if="picUrl2"
-              :src="picUrl2"
-              title="双击放大预览"
-              @dblclick="openPreview(picUrl2)"
+              @dblclick="openPreview(src)"
             />
           </div>
         </div>
@@ -34,60 +29,14 @@
       <div class="basic-box">
         <basicBorder title="报警详情">
           <div class="warn-detail">
-             <div class="warn-item">
-              <div class="item-label">设备编号 : </div>
-              <div class="item-val text-val1">{{ warnData.devId || '-' }}</div>
-            </div>
-            <div class="warn-item">
-              <div class="item-label">报警设备 : </div>
-              <div class="item-val text-val1">{{ warnData.deviceName || '-' }}</div>
-            </div>
-            <div class="warn-item">
-              <div class="item-label">报警类型 : </div>
-              <div class="item-val text-val"> {{ warnData.eventType == '10001' ? '热源报警' : warnData.eventType == '10002'
-                ?
-                '闯入报警' : '-' }}</div>
-            </div>
-            <div class="warn-item">
-              <div class="item-label">报警时间 : </div>
-              <div class="item-val text-val1"> {{ warnData.createTime || '-' }}</div>
-            </div>
-            <!-- <div class="warn-item">
-              <div class="item-label">红外类型 : </div>
-              <div class="item-val text-val"> {{ warnData.irModel || '-' }}</div>
-            </div> -->
-            <div class="warn-item">
-              <div class="item-label ">模式 : </div>
-              <div class="item-val text-val"> {{ warnData.mode=='1' ? '预置位' : warnData.mode=='2' ? '角度位下标号' : '-'  }}</div>
-            </div>
-            <div class="warn-item">
-              <div class="item-label">红外水平像素数量 : </div>
-              <div class="item-val text-val1"> {{ warnData.numOfIrHorPixs || '-' }}</div>
-            </div>
-            <div class="warn-item">
-              <div class="item-label">红外垂直像素数量 : </div>
-              <div class="item-val text-val1"> {{ warnData.numOfIrVerPixs || '-' }}</div>
+            <div v-for="item in detailItems" :key="item.label" class="warn-item">
+              <div class="item-label">{{ item.label }} : </div>
+              <div class="item-val" :class="item.valueClass">{{ item.value }}</div>
             </div>
-            <div class="warn-item">
-              <div class="item-label">云台水平角 : </div>
-              <div class="item-val text-val1"> {{ warnData.ptzHorAngle || '-' }}</div>
-            </div>
-            <div class="warn-item">
-              <div class="item-label">云台垂直角 : </div>
-              <div class="item-val text-val1"> {{ warnData.ptzVerAngle || '-' }}</div>
-            </div>
-            <!-- <div class="warn-item">
-              <div class="item-label">测温标记 : </div>
-              <div class="item-val text-val1"> {{ warnData.tempFlag || '-' }}</div>
-            </div> -->
-
           </div>
         </basicBorder>
       </div>
     </div>
-    <!-- <div class="list-c">
-      <basicBorder title="报警地图位置"></basicBorder>
-    </div> -->
     <div class="list-b">
       <basicBorder title="处理流程">
         <div class="process-flow-box">
@@ -96,14 +45,14 @@
             <span>当前状态:等待值班人员确认处理</span>
           </div>
           <div class="flow-process">
-            <div class="pic-process" v-for="(item, index) in picList" :key="index">
+            <div v-for="(item, index) in picList" :key="index" class="pic-process">
               <img :src="item.src" alt="">
               <div class="pic-text">{{ item.label }}</div>
             </div>
           </div>
           <div class="flow-step">
             <a-steps progress-dot :current="currentStep">
-              <a-step title="" description="" v-for="(item, index) in picList" :key="index" />
+              <a-step v-for="(item, index) in picList" :key="index" title="" description="" />
             </a-steps>
           </div>
         </div>
@@ -135,56 +84,95 @@ import { useGlobSetting } from '/@/hooks/setting';
 import { updateProcessState } from '../hsqHome.api'
 import { useMessage } from '/@/hooks/web/useMessage';
 
+interface DetailItem {
+  label: string
+  value: string | number
+  valueClass: 'text-val' | 'text-val1'
+}
+
+interface ActionBtn {
+  key: number
+  label: string
+}
+
 const props = defineProps({
   warnData: {
     type: Object,
-    required: true
-  }
+    required: true,
+  },
 })
 
-/** 当前步骤 */
+/** 当前步骤(与 a-steps / processState 对应) */
 const currentStep = ref(0)
-/** 当前激活的处置按钮 */
-const activeBtn = ref('')
-const globSetting = useGlobSetting();
-const baseUploadUrl = globSetting.uploadUrl;
-const { createMessage } = useMessage();
-let urlStr = '';
-if (import.meta.env.PROD) {
-  urlStr = VUE_APP_URL.baseUrl;
-} else {
-  urlStr = baseUploadUrl || '';
-}
-
-/** 预览弹窗显隐与图片地址 */
+/** 当前激活的处置按钮 key */
+const activeBtn = ref<number | ''>('')
+/** 预览弹窗 */
 const previewVisible = ref(false)
 const previewSrc = ref('')
 
-/** 重置处理流程 UI 状态(不调用接口) */
-function resetProcessFlow() {
-  currentStep.value = 0
-  activeBtn.value = ''
+const globSetting = useGlobSetting()
+const { createMessage } = useMessage()
+const urlStr = import.meta.env.PROD ? VUE_APP_URL.baseUrl : globSetting.uploadUrl || ''
+
+/**
+ * 根据 processState 同步处理流程步骤与上方处置按钮激活态
+ * 对应关系:currentStep = btn.key - 1;步骤为 0 时无按钮激活
+ */
+function syncProcessFlow(processState: unknown) {
+  const step = Number(processState)
+  currentStep.value = Number.isFinite(step) ? step : 0
+  const matched = actionBtns.find((btn) => btn.key - 1 === currentStep.value)
+  activeBtn.value = matched ? matched.key : ''
 }
 
-/** 报警信息列表切换详情时,重置处理流程状态 */
+/** 同时监听报警 id / 处理状态,保持步骤与按钮一致 */
 watch(
-  () => props.warnData?.id,
-  (id, prevId) => {
-    if (id !== prevId) {
-      resetProcessFlow()
-    }
-  }
+  () => [props.warnData?.id, props.warnData?.processState] as const,
+  () => syncProcessFlow(props.warnData?.processState),
+  { immediate: true }
 )
 
 /** 拼接报警图片完整地址 */
 function buildPicUrl(picName?: string) {
   if (!picName) return ''
-  const path = picName.indexOf('h') >= 0 ? picName.substring(picName.indexOf('h')) : picName
+  const path = picName.includes('h') ? picName.substring(picName.indexOf('h')) : picName
   return `${urlStr}/sys/common/static/${path}`
 }
 
-const picUrl1 = computed(() => buildPicUrl(props.warnData?.picName))
-const picUrl2 = computed(() => buildPicUrl(props.warnData?.picName2))
+const warnPicUrls = computed(() => [
+  buildPicUrl(props.warnData?.picName),
+  buildPicUrl(props.warnData?.picName2),
+])
+
+const eventTypeText = computed(() => {
+  const type = props.warnData?.eventType
+  if (type == '10001') return '热源报警'
+  if (type == '10002') return '闯入报警'
+  return '-'
+})
+
+const modeText = computed(() => {
+  const mode = props.warnData?.mode
+  if (mode == '1') return '预置位'
+  if (mode == '2') return '角度位下标号'
+  return '-'
+})
+
+/** 报警详情字段列表 */
+const detailItems = computed<DetailItem[]>(() => {
+  const data = props.warnData || {}
+  return [
+    { label: '设备编号', value: data.devId || '-', valueClass: 'text-val1' },
+    { label: '报警设备', value: data.deviceName || '-', valueClass: 'text-val1' },
+    { label: '报警类型', value: eventTypeText.value, valueClass: 'text-val' },
+    { label: '报警时间', value: data.createTime || '-', valueClass: 'text-val1' },
+    { label: '模式', value: modeText.value, valueClass: 'text-val' },
+    { label: '红外水平像素数量', value: data.numOfIrHorPixs || '-', valueClass: 'text-val1' },
+    { label: '红外垂直像素数量', value: data.numOfIrVerPixs || '-', valueClass: 'text-val1' },
+    { label: '云台水平角', value: data.ptzHorAngle || '-', valueClass: 'text-val1' },
+    { label: '云台垂直角', value: data.ptzVerAngle || '-', valueClass: 'text-val1' },
+  ]
+})
 
 /** 打开图片预览 */
 function openPreview(src: string) {
@@ -199,22 +187,20 @@ function closePreview() {
   previewSrc.value = ''
 }
 
-/** 切换步骤 */
-function changeStep(btn: any) {
-  currentStep.value = btn.key - 1
-  activeBtn.value = btn.key
+/** 切换步骤并更新服务端状态 */
+function changeStep(btn: ActionBtn) {
+  syncProcessFlow(btn.key - 1)
   getUpdateWarnStatus()
 }
 
-/** 更新报警状态 */
+/** 更新报警处理状态 */
 async function getUpdateWarnStatus() {
-  let res = await updateProcessState({
+  const res = await updateProcessState({
     id: props.warnData.id,
     processState: currentStep.value,
   })
   createMessage.success(res.msg || '更新成功')
 }
-
 </script>
 
 <style lang="less" scoped>
@@ -227,13 +213,6 @@ async function getUpdateWarnStatus() {
 .mixed-warn {
   --image-box-bg: url('@/assets/images/home-container/configurable/hsq/2-11.png');
   --image-box-bg1: url('@/assets/images/home-container/configurable/hsq/3-4.png');
-  --image-box-bg2: url('@/assets/images/home-container/configurable/hsq/4-1.png');
-  --image-box-bg3: url('@/assets/images/home-container/configurable/hsq/4-2.png');
-  --image-box-bg4: url('@/assets/images/home-container/configurable/hsq/4-3.png');
-  --image-box-bg5: url('@/assets/images/home-container/configurable/hsq/4-4.png');
-  --image-box-bg6: url('@/assets/images/home-container/configurable/hsq/4-5.png');
-
-  --image-box-bg7: url('@/assets/images/home-container/configurable/hsq/ceshi1.png');
   position: relative;
   width: 100%;
   height: 100%;
@@ -254,7 +233,6 @@ async function getUpdateWarnStatus() {
   .list-t {
     display: flex;
     justify-content: space-between;
-    // height: 235px;
     height: 380px;
     margin-bottom: 10px;
   }
@@ -339,7 +317,7 @@ async function getUpdateWarnStatus() {
     height: 28px;
     background: linear-gradient(to right, #134c77, transparent);
     margin-bottom: 8px;
-    padding: 0px 15px;
+    padding: 0 15px;
     box-sizing: border-box;
 
     &:last-child {
@@ -349,10 +327,8 @@ async function getUpdateWarnStatus() {
 
   .item-label {
     margin-right: 5px;
-    // font-size: 13px;
   }
 
-
   .text-val {
     color: #fc002a;
   }
@@ -361,11 +337,6 @@ async function getUpdateWarnStatus() {
     color: rgb(247, 169, 24);
   }
 
-  .list-c {
-    height: 150px;
-    margin-bottom: 10px;
-  }
-
   .list-b {
     position: relative;
     height: 120px;
@@ -381,15 +352,13 @@ async function getUpdateWarnStatus() {
     top: 6px;
     color: orange;
 
-    span {
-      &:nth-child(1) {
-        display: inline-block;
-        width: 8px;
-        height: 8px;
-        border-radius: 50%;
-        background-color: orange;
-        margin-right: 5px;
-      }
+    span:nth-child(1) {
+      display: inline-block;
+      width: 8px;
+      height: 8px;
+      border-radius: 50%;
+      background-color: orange;
+      margin-right: 5px;
     }
   }
 
@@ -413,10 +382,9 @@ async function getUpdateWarnStatus() {
     .pic-text {
       width: 100%;
       text-align: center;
-      border-top: 1px solid rgba(18, 73, 113);
-      border-bottom: 1px solid rgba(18, 73, 113);
-      border-left: 1px solid #29abf1;
-      border-right: 1px solid #29abf1;
+      border: 1px solid rgba(18, 73, 113);
+      border-left-color: #29abf1;
+      border-right-color: #29abf1;
       border-radius: 5px;
     }
   }
@@ -424,23 +392,19 @@ async function getUpdateWarnStatus() {
   .flow-step {
     width: 100%;
     position: absolute;
-    bottom: 0px;
+    bottom: 0;
     left: 0;
-    padding: 0px 30px;
+    padding: 0 30px;
   }
-
 }
 
 :deep(.zxm-steps-icon .zxm-steps-icon-dot) {
   border: 1px solid #2cb6ff !important;
 }
 
-:deep(.zxm-steps-item-process > .zxm-steps-item-container > .zxm-steps-item-tail::after) {
-  background-color: rgba(28, 118, 172, .6) !important;
-}
-
+:deep(.zxm-steps-item-process > .zxm-steps-item-container > .zxm-steps-item-tail::after),
 :deep(.zxm-steps-item-wait > .zxm-steps-item-container > .zxm-steps-item-tail::after) {
-  background-color: rgba(28, 118, 172, .6) !important;
+  background-color: rgba(28, 118, 172, 0.6) !important;
 }
 
 /* Teleport 到 body,需写在 .mixed-warn 外以保证样式生效 */

+ 1 - 0
src/views/vent/monitorManager/hsqHome/components/basicBorder.vue

@@ -53,6 +53,7 @@ let props = defineProps({
     height: calc(100% - 30px);
     padding: 10px 15px;
     box-sizing: border-box;
+    overflow-y: auto;
   }
 }
 </style>

+ 253 - 0
src/views/vent/monitorManager/hsqHome/components/common/commonEchart.vue

@@ -0,0 +1,253 @@
+<template>
+  <div class="common-echart" :style="{ width, height }">
+    <div ref="chartRef" class="chart-canvas"></div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, watch, onMounted, type PropType, type Ref } from 'vue'
+import { merge } from 'lodash-es'
+import type { EChartsOption } from 'echarts'
+import { useECharts } from '/@/hooks/web/useECharts'
+
+/** 柱状图单系列数据 */
+export interface CommonBarSeriesItem {
+  name: string
+  data: number[]
+  /** 柱条颜色;不传则使用主题渐变色板 */
+  color?: string
+  barWidth?: number | string
+}
+
+/** 主题色板(青蓝监控风格) */
+const THEME_COLORS = ['#01fefc', '#3ae1ff', '#20a6a9', '#2f6fb8', '#7ec7ff']
+
+const props = defineProps({
+  /** 类目轴数据 */
+  xAxisData: {
+    type: Array as PropType<string[]>,
+    default: () => [],
+  },
+  /** 柱状图系列 */
+  series: {
+    type: Array as PropType<CommonBarSeriesItem[]>,
+    default: () => [],
+  },
+  /** Y 轴名称 */
+  yAxisName: {
+    type: String,
+    default: '',
+  },
+  /** 图表标题 */
+  title: {
+    type: String,
+    default: '',
+  },
+  /** 是否显示图例 */
+  showLegend: {
+    type: Boolean,
+    default: true,
+  },
+  /** 默认柱宽 */
+  barWidth: {
+    type: [Number, String] as PropType<number | string>,
+    default: 18,
+  },
+  /** 是否显示柱顶数值 */
+  showLabel: {
+    type: Boolean,
+    default: false,
+  },
+  /** 额外 option,会与默认配置深度合并 */
+  option: {
+    type: Object as PropType<EChartsOption>,
+    default: () => ({}),
+  },
+  width: {
+    type: String,
+    default: '100%',
+  },
+  height: {
+    type: String,
+    default: '100%',
+  },
+})
+
+const chartRef = ref<HTMLDivElement | null>(null)
+const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>)
+
+function buildBarColor(index: number, custom?: string) {
+  const base = custom || THEME_COLORS[index % THEME_COLORS.length]
+  return new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+    { offset: 0, color: base },
+    { offset: 1, color: 'rgba(1, 254, 252, 0.08)' },
+  ])
+}
+
+function buildOption(): EChartsOption {
+  const multi = props.series.length > 1
+  const base: EChartsOption = {
+    backgroundColor: 'transparent',
+    title: props.title
+      ? {
+          text: props.title,
+          left: 8,
+          top: 4,
+          textStyle: {
+            color: '#01fefc',
+            fontSize: 14,
+            fontWeight: 'bold',
+          },
+        }
+      : undefined,
+    tooltip: {
+      trigger: 'axis',
+      backgroundColor: 'rgba(0, 0, 0, 0.6)',
+      borderColor: 'rgba(58, 225, 255, 0.45)',
+      borderWidth: 1,
+      textStyle: {
+        color: '#fff',
+        fontSize: 12,
+      },
+      axisPointer: {
+        type: 'shadow',
+        shadowStyle: {
+          color: 'rgba(1, 254, 252, 0.08)',
+        },
+      },
+    },
+    legend: {
+      show: props.showLegend && multi,
+      top: props.title ? 28 : 4,
+      right: 12,
+      itemWidth: 14,
+      itemHeight: 8,
+      itemGap: 16,
+      textStyle: {
+        color: '#7ec7ff',
+        fontSize: 12,
+      },
+      icon: 'roundRect',
+    },
+    grid: {
+      top: props.title || (props.showLegend && multi) ? 52 : 28,
+      left: 12,
+      right: 16,
+      bottom: 12,
+      containLabel: true,
+    },
+    xAxis: {
+      type: 'category',
+      data: props.xAxisData,
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '#244a94',
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+      axisLabel: {
+        color: '#b3b8cc',
+        fontSize: 12,
+        margin: 10,
+      },
+      splitLine: {
+        show: false,
+      },
+    },
+    yAxis: {
+      type: 'value',
+      name: props.yAxisName,
+      nameTextStyle: {
+        color: '#fff',
+        fontSize: 12,
+        padding: [0, 0, 0, 8],
+      },
+      min: 0,
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '#244a94',
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+      axisLabel: {
+        color: '#b3b8cc',
+        fontSize: 12,
+      },
+      splitLine: {
+        show: true,
+        lineStyle: {
+          color: '#0d2973',
+          type: 'dashed',
+        },
+      },
+    },
+    series: props.series.map((item, index) => ({
+      name: item.name,
+      type: 'bar' as const,
+      barWidth: item.barWidth ?? props.barWidth,
+      barGap: '30%',
+      data: item.data,
+      itemStyle: {
+        color: buildBarColor(index, item.color),
+        borderRadius: [2, 2, 0, 0],
+      },
+      label: {
+        show: props.showLabel,
+        position: 'top' as const,
+        color: '#e8f4ff',
+        fontSize: 12,
+      },
+      emphasis: {
+        itemStyle: {
+          shadowBlur: 8,
+          shadowColor: 'rgba(1, 254, 252, 0.45)',
+        },
+      },
+    })),
+  }
+
+  return merge({}, base, props.option || {})
+}
+
+function renderChart() {
+  setOptions(buildOption())
+}
+
+onMounted(() => {
+  renderChart()
+})
+
+watch(
+  () => [props.xAxisData, props.series, props.yAxisName, props.title, props.option, props.showLabel, props.barWidth],
+  () => {
+    renderChart()
+  },
+  { deep: true },
+)
+
+defineExpose({
+  /** 手动刷新图表 */
+  refresh: renderChart,
+  /** 获取 echarts 实例相关能力 */
+  echarts,
+})
+</script>
+
+<style lang="less" scoped>
+.common-echart {
+  width: 100%;
+  height: 100%;
+  min-height: 160px;
+}
+
+.chart-canvas {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 1 - 0
src/views/vent/monitorManager/hsqHome/components/navMenu.vue

@@ -17,6 +17,7 @@ let menuList = ref<any[]>([
   { label: '设备管理', value: 'sbgl' },
   // { label: '联动配置', value: 'ldpz' },
   { label: '系统管理', value: 'xtgl' },
+  { label: '历史报表', value: 'lspb' },
 ]);
 let $emit = defineEmits(['changeMenu']);
 

+ 138 - 0
src/views/vent/monitorManager/hsqHome/components/type.ts

@@ -0,0 +1,138 @@
+/** 设备节点 */
+export interface DeviceNode {
+  id: string
+  name: string
+  /** 勾选:可见光取流 / 红外取流 */
+  checks: [boolean, boolean]
+  /** 在线状态:1/true 在线,0/false 离线 */
+  netStatus?: number | boolean
+  /** 设备 IP(SDK 抓拍等接口用) */
+  ip?: string
+  /** 经度 / 纬度(可选) */
+  longitude?: string | number
+  latitude?: string | number
+}
+
+/** 告警上报表单字段 */
+export interface AlarmFormState {
+  deviceId: string
+  deviceName: string
+  longitude: string
+  latitude: string
+  operator: string
+  remark: string
+}
+
+/** 告警上报字段配置 */
+export interface AlarmReportFieldItem {
+  key: keyof AlarmFormState
+  label: string
+  placeholder?: string
+}
+
+/** 设备分组 */
+export interface DeviceGroup {
+  id: string
+  title: string
+  children?: DeviceNode[]
+}
+
+/** 扫描角度配置 */
+export interface AngleState {
+  hMin: number
+  hMax: number
+  vMin: number
+  vMax: number
+}
+
+/** 角度字段配置 */
+export interface AngleField {
+  label: string
+  minKey: keyof AngleState
+  maxKey: keyof AngleState
+}
+
+/** 在线/离线统计 */
+export interface StatsCount {
+  online: number
+  offline: number
+}
+
+/** 预置位工具栏项 */
+export interface PresetToolbarItem {
+  key: string
+  /** SvgIcon name,对应 assets/icons 下文件名 */
+  icon: string
+  title: string
+}
+
+/** 预置位列表项 */
+export interface PresetItem {
+  id: string
+  name: string
+}
+
+/** 红外控制单项 */
+export interface IrControlItem {
+  key: string
+  icon: string
+  /** + 按钮提示 */
+  plusTip?: string
+  /** − 按钮提示 */
+  minusTip?: string
+}
+
+/** 激光操作按钮 */
+export interface LaserActionItem {
+  key: string
+  label: string
+}
+
+/** 录像文件(来自 recordMP4File 返回) */
+export interface RecordFileItem {
+  fileName: string
+  /** 存储路径(不含文件名) */
+  filePath: string
+  /** 完整路径 = filePath + fileName */
+  fullPath: string
+  /** 可播放地址(HTTP 映射后) */
+  playUrl: string
+  recordTime: string
+}
+
+/** 报警自动弹窗展示数据 */
+export interface AutoAlarmPopupData {
+  imageUrl: string
+  maxTemp: string
+  overlayTime: string
+  deviceLabel: string
+  alarmTime: string
+  alarmDevice: string
+  alarmType: string
+  hotspotValue: string
+}
+
+/** 历史筛选树子节点 */
+export interface HistoryFilterDeviceNode {
+  id: string
+  name: string
+  checked: boolean
+}
+
+/** 历史筛选树分组节点 */
+export interface HistoryFilterGroupNode {
+  id: string
+  title: string
+  checked: boolean
+  expanded: boolean
+  children: HistoryFilterDeviceNode[]
+}
+
+/** 历史数据筛选条件 */
+export interface HistoryFilterPayload {
+  /** 开始时间 YYYY-MM-DD HH:mm:ss */
+  startTime: string
+  /** 结束时间 YYYY-MM-DD HH:mm:ss */
+  endTime: string
+  deviceIds: string[]
+}

+ 41 - 4
src/views/vent/monitorManager/hsqHome/fireMonitor.vue

@@ -8,19 +8,31 @@
       </div>
       <div class="box-cen">
         <CommonBd title="光谱摄像机">
-          <CommonTable :columns="deviceColumns" :table-data="tableDataGp"></CommonTable>
+          <CommonTable
+            :columns="deviceColumns"
+            :table-data="tableDataGp"
+            selectable
+            :selected-key="selectedGpId"
+            @row-click="onSelectGp"
+          ></CommonTable>
         </CommonBd>
       </div>
       <div class="box-bot">
         <CommonBd title="火灾探测器">
-          <CommonTable :columns="deviceColumns" :table-data="tableDataHz"></CommonTable>
+          <CommonTable
+            :columns="deviceColumns"
+            :table-data="tableDataHz"
+            selectable
+            :selected-key="selectedHzId"
+            @row-click="onSelectHz"
+          ></CommonTable>
         </CommonBd>
       </div>
     </div>
     <div class="basic-fire-box1">
       <!-- 模型区域 -->
       <div class="model-box">
-        <dwgViewer :devices="tableData" />
+        <dwgViewer ref="dwgViewerRef" :devices="tableData" />
       </div>
       <!-- <div class="box1-bot">
         <CommonBd title="快捷操作">
@@ -32,7 +44,7 @@
       <div class="box-top1">
         <CommonBd title="报警监控">
           <!-- <AlarmMonitor :option="alarmOption" :cardData="alarmData"></AlarmMonitor> -->
-          <AlarmMonitor></AlarmMonitor>
+          <AlarmMonitor @locate="locateDeviceOnMap"></AlarmMonitor>
         </CommonBd>
       </div>
       <div class="box-cen1">
@@ -74,6 +86,12 @@ let tableData = ref<any[]>([])
 let tableDataGp = ref<any[]>([])
 /** 火灾探测器表格数据 */
 let tableDataHz = ref<any[]>([])
+/** 光谱摄像机当前选中行 */
+const selectedGpId = ref<string | number | null>(null)
+/** 火灾探测器当前选中行 */
+const selectedHzId = ref<string | number | null>(null)
+/** CAD 图纸组件引用 */
+const dwgViewerRef = ref<InstanceType<typeof dwgViewer> | null>(null)
 /** 历史温度曲线设备选项配置 */
 let deviceOptions = ref<any[]>([])
 /** 环境监测设备选项配置 */
@@ -83,6 +101,24 @@ let envData = reactive({})
 /** 定时获取监测数据定时器 */
 let timer: null | NodeJS.Timeout = null;
 
+/** 点击列表行后定位 CAD 图标 */
+function locateDeviceOnMap(deviceID: string | number | null | undefined) {
+  if (deviceID == null || deviceID === '') return
+  dwgViewerRef.value?.locateIcon?.(deviceID)
+}
+
+/** 光谱摄像机行点击选中并定位 */
+function onSelectGp(row: any) {
+  selectedGpId.value = row?.deviceID ?? null
+  locateDeviceOnMap(selectedGpId.value)
+}
+
+/** 火灾探测器行点击选中并定位 */
+function onSelectHz(row: any) {
+  selectedHzId.value = row?.deviceID ?? null
+  locateDeviceOnMap(selectedHzId.value)
+}
+
 /**
  * 定时获取监测数据
  * 通过定时器循环调用数据获取方法,更新表格数据
@@ -118,6 +154,7 @@ async function getManagesysDeviceNumTj() {
 async function getTableData() {
   const res = await monitorSystem({ type: 'all', systemID: systemId.value, devicetype: '' });
   tableDataGp.value = res.deviceInfo.duaSpeCamera.datalist.map(el => Object.assign({}, el, el.readData)) || [];
+  tableDataHz.value = (res.deviceInfo.imgFireDet?.datalist || []).map(el => Object.assign({}, el, el.readData));
   tableData.value = tableDataGp.value
   deviceOptions.value = tableDataGp.value.map(v => ({
     label: v.strname,

+ 93 - 0
src/views/vent/monitorManager/hsqHome/historyReport.vue

@@ -0,0 +1,93 @@
+<template>
+  <div class="history-report">
+    <div class="left-box">
+      <HistoryFilterTree></HistoryFilterTree>
+    </div>
+    <div class="right-box">
+      <div class="right-box-top">
+        <AlarmPoint></AlarmPoint>
+      </div>
+      <div class="right-box-bottom">
+        <div class="right-box-bottom-left">
+          <AlarmDay></AlarmDay>
+        </div>
+        <div class="right-box-bottom-right">
+          <AlarmMonth></AlarmMonth>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+import HistoryFilterTree from './components/HistoryFilterTree.vue'
+import AlarmPoint from './components/AlarmPoint.vue'
+import AlarmDay from './components/AlarmDay.vue'
+import AlarmMonth from './components/AlarmMonth.vue'
+
+ </script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.history-report {
+  --image-box1-bg: url('@/assets/images/home-container/configurable/hsq/5-3.png');
+  --image-box1-bg1: url('@/assets/images/home-container/configurable/hsq/7-1.png');
+  --image-box1-bg2: url('@/assets/images/home-container/configurable/hsq/5-2.png');
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+  height: calc(100% - 10px);
+  color: @white;
+  margin-bottom: 10px;
+
+  /* 上部:用户列表 + 角色统计,高度自适应剩余空间 */
+  .left-box {
+    position: relative;
+    width: 420px;
+    height: calc(100% - 70px);
+    margin-top: 70px;
+    margin-right: 10px;
+    background: var(--image-box1-bg) no-repeat center;
+    background-size: 100% 100%;
+  }
+
+  .right-box {
+    position: relative;
+    width: calc(100% - 430px);
+    height: calc(100% - 70px);
+    margin-top: 70px;
+  }
+
+  .right-box-top {
+    width: 100%;
+    height: calc(50% - 10px);
+    margin-bottom: 10px;
+    background: var(--image-box1-bg1) no-repeat center;
+    background-size: 100% 100%;
+  }
+
+  .right-box-bottom {
+    display: flex;
+    justify-content: space-between;
+    width: 100%;
+    height: 50%;
+  }
+
+  .right-box-bottom-left {
+    width: calc(50% - 5px);
+    height: 100%;
+    margin-right: 10px;
+    background: var(--image-box1-bg2) no-repeat center;
+    background-size: 100% 100%;
+  }
+
+  .right-box-bottom-right {
+    width: calc(50% - 5px);
+    height: 100%;
+    background: var(--image-box1-bg2) no-repeat center;
+    background-size: 100% 100%;
+  }
+}
+</style>

+ 70 - 6
src/views/vent/monitorManager/hsqHome/hsqHome.api.ts

@@ -17,9 +17,17 @@ enum Api {
   warningList = '/safety/managesysAlarmInfo/list',//预警条目list
   dscAlarmLogList = '/safety/dscAlarmLog/list',//设备预警历史查询
   listdays = '/safety/ventanalyMonitorData/listdays',//详情历史曲线
-  duaSpeCameraControl = '/safety/ventanalyMonitorData/duaSpeCameraControl',//设备控制
   updateProcessState = '/safety/dscAlarmLog/updateProcessState',//更新处理状态
-  
+  captureToFile = '/api/zc/device/captureToFile',//一键抓拍图片接口
+  recordMP4File='/api/zc/device/recordMP4File',//录制MP4文件接口
+  stopRecordMP4File='/api/zc/device/stopRecordMP4File',//停止录制MP4文件接口
+  getSysCfg = '/api/zc/device/getSysCfg',//获取系统配置参数
+  setSysCfg = '/api/zc/device/setSysCfg',//设置系统配置参数
+  alarmAutoCapture = '/api/zc/device/alarmAutoCapture',//报警自动抓拍接口
+  hsqComControl = '/safety/hsqSdk/hsqComControl',//双光谱摄像机控制接口
+  setRunModeCfg = '/api/zc/device/setRunModeCfg',//设置云台运行模式配置
+  setPesudoColor = '/api/zc/device/setPesudoColor',//设置伪彩色
+  getAlarmStat = '/safety/dscAlarmLog/getAlarmStat',//获取报警统计信息-数据曲线
 }
 /**
 * 日志列表接口
@@ -100,13 +108,69 @@ export const dscAlarmLogList = (params) => defHttp.get({ url: Api.dscAlarmLogLis
 export const listdays = (params) => defHttp.get({ url: Api.listdays, params }, { joinParamsToUrl: true });
 
 /**
-* 设备控制接口
+* 更新处理状态接口
 * @param params
 */
-export const duaSpeCameraControl = (params) => defHttp.post({ url: Api.duaSpeCameraControl, params });
+export const updateProcessState = (params) => defHttp.post({ url: Api.updateProcessState, params });
 
 /**
-* 更新处理状态接口
+* 一键抓拍图片接口
 * @param params
 */
-export const updateProcessState = (params) => defHttp.post({ url: Api.updateProcessState, params });
+export const captureToFile = (params) => defHttp.post({ url: Api.captureToFile, params });
+
+/**
+* 录制MP4文件接口
+* @param params
+*/
+export const recordMP4File = (params) => defHttp.post({ url: Api.recordMP4File, params });
+
+/**
+* 停止录制MP4文件接口
+* @param params
+*/
+export const stopRecordMP4File = (params) => defHttp.post({ url: Api.stopRecordMP4File, params });
+
+/**
+* 获取系统配置参数接口
+* @param params
+*/
+export const getSysCfg = (params) => defHttp.post({ url: Api.getSysCfg, params });
+
+/**
+* 设置系统配置参数接口
+* @param params
+*/
+export const setSysCfg = (params) => defHttp.post({ url: Api.setSysCfg, params });
+
+
+/**
+* 报警自动抓拍接口
+* @param params
+*/
+export const alarmAutoCapture = (params) => defHttp.post({ url: Api.alarmAutoCapture, params });
+
+
+/**
+* 双光谱摄像机控制接口
+* @param params
+*/
+export const hsqComControl = (params) => defHttp.post({ url: Api.hsqComControl, params });
+
+/**
+* 设置云台运行模式配置接口
+* @param params
+*/
+export const setRunModeCfg = (params) => defHttp.post({ url: Api.setRunModeCfg, params });
+
+/**
+* 设置伪彩色接口
+* @param params
+*/
+export const setPesudoColor = (params) => defHttp.post({ url: Api.setPesudoColor, params });
+
+/**
+* 获取报警统计信息-数据曲线接口
+* @param params
+*/
+export const getAlarmStat = (params) => defHttp.post({ url: Api.getAlarmStat, params });

+ 350 - 282
src/views/vent/monitorManager/hsqHome/hsqHome.data.ts

@@ -1,118 +1,125 @@
 import { getAssetURL } from '/@/utils/ui';
+import type {LaserActionItem, DeviceNode, DeviceGroup, AlarmFormState, AlarmReportFieldItem, AngleState, StatsCount,
+AngleField, PresetToolbarItem } from
+'./components/type'
 /** Tab 标签项数据结构 */
 interface TabItem {
-  key: string
-  label: string
+key: string
+label: string
 }
 /** 镜头控制项(变焦/聚焦/光圈)数据结构 */
 interface LensControl {
-  key: string
-  icon: string
+key: string
+icon: string
+/** + 按钮提示 */
+plusTip: string
+/** − 按钮提示 */
+minusTip: string
 }
 
 
 //设备状态总览
 export let option = [
-  {
-    label: '在线设备',
-    value: 'onlineNum',
-  },
-  {
-    label: '离线设备',
-    value: 'offlineNum',
-  },
-  {
-    label: '故障设备',
-    value: 'faultNum',
-  },
-  {
-    label: '报警设备',
-    value: 'alarmNum',
-  },
+{
+label: '在线设备',
+value: 'onlineNum',
+},
+{
+label: '离线设备',
+value: 'offlineNum',
+},
+{
+label: '故障设备',
+value: 'faultNum',
+},
+{
+label: '报警设备',
+value: 'alarmNum',
+},
 ]
 
 //实时温度曲线
 export const chartConfig: any = {
-  type: 'line_area',
-  grid: {
-    top: 25,
-    left: 25,
-    bottom: 10,
-    right: 25,
-  },
-  legend: { show: true },
-  xAxis: [{ show: true }],
-  yAxis: [{ show: true, name: '(℃)', position: 'left', nameTextStyle: { color: '#fff', fontSize: 12, lineHeight: 2, } }],
-  series: [
-    {
-      label: '平均温度',
-      readFrom: '',
-      xprop: 'pos',
-      yprop: 'value',
-      color: ['rgba(52, 193, 248,.8)', 'rgba(52, 193, 248,.2)'],
-    },
-  ],
+type: 'line_area',
+grid: {
+top: 25,
+left: 25,
+bottom: 10,
+right: 25,
+},
+legend: { show: true },
+xAxis: [{ show: true }],
+yAxis: [{ show: true, name: '(℃)', position: 'left', nameTextStyle: { color: '#fff', fontSize: 12, lineHeight: 2, } }],
+series: [
+{
+label: '平均温度',
+readFrom: '',
+xprop: 'pos',
+yprop: 'value',
+color: ['rgba(52, 193, 248,.8)', 'rgba(52, 193, 248,.2)'],
+},
+],
 };
 
 //设备状态表格
 export let deviceColumns: any[] = [
-  {
-    name: '设备名称',
-    prop: 'strname',
-  },
-  {
-    name: '在线状态',
-    prop: 'netStatus',
-  },
-  {
-    name: '温度(‌℃‌)',
-    //prop: 'syswarnLevel',
-    prop: 'avg'
-  },
+{
+name: '设备名称',
+prop: 'strname',
+},
+{
+name: '在线状态',
+prop: 'netStatus',
+},
+{
+name: '温度(‌℃‌)',
+//prop: 'syswarnLevel',
+prop: 'avg'
+},
 ]
 
 //快捷操作
 export let quickOption = [
-  { label: '系统运行时间', value: 'time', iconName: 'time-run' },
-  { label: '数据刷新', value: 'sjsx', iconName: 'data-reset' },
-  { label: '网络延迟', value: 'wlyc', iconName: 'internet-on' },
+{ label: '系统运行时间', value: 'time', iconName: 'time-run' },
+{ label: '数据刷新', value: 'sjsx', iconName: 'data-reset' },
+{ label: '网络延迟', value: 'wlyc', iconName: 'internet-on' },
 ]
 export let btnOption = [
-  { firstLabel: '报警确认', secondLabel: '视屏调取', thirdLabel: '联动控制' },
-  { firstLabel: '数据导出', secondLabel: '生成报表', thirdLabel: '定位追踪' },
-  { firstLabel: '声光关闭', secondLabel: '应急广播', thirdLabel: '系统设置' },
+{ firstLabel: '报警确认', secondLabel: '视屏调取', thirdLabel: '联动控制' },
+{ firstLabel: '数据导出', secondLabel: '生成报表', thirdLabel: '定位追踪' },
+{ firstLabel: '声光关闭', secondLabel: '应急广播', thirdLabel: '系统设置' },
 ]
 
 //报警监控
 export let alarmOption = [
-  {
-    label: '今日报警',
-    value: 'dayWarn',
-  },
-  {
-    label: '已处理',
-    value: 'warnOk',
-  },
-  {
-    label: '未处理',
-    value: 'warnUnOk',
-  },
+{
+label: '今日报警',
+value: 'dayWarn',
+},
+{
+label: '已处理',
+value: 'warnOk',
+},
+{
+label: '未处理',
+value: 'warnUnOk',
+},
 ]
 
 //区域温度统计
 export let chartTempConfig: any = {
-  type: 'bar_cylinder_wide',
-  readFrom: '',
-  grid: {
-    top: 40,
-    left: 50,
-    bottom: 14,
-    right: 50,
-  },
-  legend: { show: false },
-  xAxis: [{ show: true }],
-  yAxis: [{ show: true, name: '', position: 'left' }],
-  series: [{ readFrom: '', xprop: 'x', yprop: 'y', label: '温度' }],
+type: 'bar_cylinder_wide',
+readFrom: '',
+grid: {
+top: 40,
+left: 50,
+bottom: 14,
+right: 50,
+},
+legend: { show: false },
+xAxis: [{ show: true }],
+yAxis: [{ show: true, name: '', position: 'left' }],
+series: [{ readFrom: '', xprop: 'x', yprop: 'y', label: '温度' }],
 }
 
 
@@ -131,260 +138,321 @@ export let chartTempConfig: any = {
 
 //用户列表
 export let optionUser = [
-  { label: '用户账号', value: 'username' },
-  { label: '用户姓名', value: 'realname' },
-  { label: '所属角色', value: 'userRolesStr' },
-  { label: '部门', value: 'orgCodeTxt' },
-  { label: '手机号', value: 'phone' },
-  { label: '状态', value: 'status_dictText' },
+{ label: '用户账号', value: 'username' },
+{ label: '用户姓名', value: 'realname' },
+{ label: '所属角色', value: 'userRolesStr' },
+{ label: '部门', value: 'orgCodeTxt' },
+{ label: '手机号', value: 'phone' },
+{ label: '状态', value: 'status_dictText' },
 ]
 
 //日志审计
 export let logbtnOption = [
-  { label: '登录日志', value: 'login' },
-  { label: '操作日志', value: 'operate' },
-  { label: '浏览日志', value: 'look' },
+{ label: '登录日志', value: 'login' },
+{ label: '操作日志', value: 'operate' },
+{ label: '浏览日志', value: 'look' },
 ]
 export let titleOption = [
-  { label: '操作人ID', value: 'userid' },
-  { label: '操作人', value: 'username' },
-  { label: '日志内容', value: 'logContent' },
-  { label: 'IP', value: 'ip' },
-  { label: '创建时间', value: 'createTime' },
-  { label: '日志类型', value: 'logType_dictText' },
+{ label: '操作人ID', value: 'userid' },
+{ label: '操作人', value: 'username' },
+{ label: '日志内容', value: 'logContent' },
+{ label: 'IP', value: 'ip' },
+{ label: '创建时间', value: 'createTime' },
+{ label: '日志类型', value: 'logType_dictText' },
 ]
 export let titleLookOption = [
-  { label: '操作人ID', value: 'userid' },
-  { label: '操作人', value: 'username' },
-  { label: '日志内容', value: 'logContent' },
-  { label: 'IP', value: 'ip' },
-  { label: '创建时间', value: 'createTime' },
+{ label: '操作人ID', value: 'userid' },
+{ label: '操作人', value: 'username' },
+{ label: '日志内容', value: 'logContent' },
+{ label: 'IP', value: 'ip' },
+{ label: '创建时间', value: 'createTime' },
 ]
 
 //今日登录统计
 export let dayLoginConfig: any = {
-  type: 'bar_cylinder_wide',
-  readFrom: '',
-  grid: {
-    top: 55,
-    left: 20,
-    bottom: 25,
-    right: 20,
-  },
-  legend: { show: false },
-  xAxis: [{ show: true }],
-  yAxis: [{ show: true, name: '', position: 'left' }],
-  series: [{ readFrom: '', xprop: 'x', yprop: 'y', label: '次数' }],
+type: 'bar_cylinder_wide',
+readFrom: '',
+grid: {
+top: 55,
+left: 20,
+bottom: 25,
+right: 20,
+},
+legend: { show: false },
+xAxis: [{ show: true }],
+yAxis: [{ show: true, name: '', position: 'left' }],
+series: [{ readFrom: '', xprop: 'x', yprop: 'y', label: '次数' }],
 }
 
 //报警列表表头
 export let warnTitle = [
-  { label: '设备名称', value: 'deviceName' },
-  { label: '报警类型', value: 'eventTypeC' },
-  { label: '模式', value: 'mode_dictText' },
-  { label: '时间', value: 'createTime' },
-  { label: '操作', value: 'operation' },
+{ label: '设备名称', value: 'deviceName' },
+{ label: '报警类型', value: 'eventTypeC' },
+{ label: '模式', value: 'mode_dictText' },
+{ label: '时间', value: 'createTime' },
+{ label: '操作', value: 'operation' },
 ]
 
 export let alarmColumns: any[] = [
-  {
-    name: '设备名称',
-    prop: 'deviceName',
-  },
-  {
-    name: '报警类型',
-    prop: 'eventTypeC',
-  },
-  {
-    name: '模式',
-    prop: 'mode_dictText',
-  },
-  {
-    name: '时间',
-    prop: 'createTime',
-  },
+{
+name: '设备名称',
+prop: 'deviceName',
+},
+{
+name: '报警类型',
+prop: 'eventTypeC',
+},
+{
+name: '模式',
+prop: 'mode_dictText',
+},
+{
+name: '时间',
+prop: 'createTime',
+},
 ]
 export let dscAlarmLogColumns: any[] = [
-  {
-    name: '设备名称',
-    prop: 'deviceName',
-  },
-  {
-    name: '安装位置',
-    prop: 'devicePos',
-  },
-  {
-    name: '报警类型',
-    prop: 'eventTypeC',
-  },
-  {
-    name: '红外类型',
-    prop: 'irModel',
-  },
-  {
-    name: '模式',
-    prop: 'mode',
-  },
-  {
-    name: '红外水平像素',
-    prop: 'numOfIrHorPixs',
-  },
-  {
-    name: '红外垂直像素',
-    prop: 'numOfIrVerPixs',
-  },
-  {
-    name: '云台水平角',
-    prop: 'ptzHorAngle',
-  },
-  {
-    name: '云台垂直角',
-    prop: 'ptzVerAngle',
-  },
+{
+name: '设备名称',
+prop: 'deviceName',
+},
+{
+name: '安装位置',
+prop: 'devicePos',
+},
+{
+name: '报警类型',
+prop: 'eventTypeC',
+},
+{
+name: '红外类型',
+prop: 'irModel',
+},
+{
+name: '模式',
+prop: 'mode',
+},
+{
+name: '红外水平像素',
+prop: 'numOfIrHorPixs',
+},
+{
+name: '红外垂直像素',
+prop: 'numOfIrVerPixs',
+},
+{
+name: '云台水平角',
+prop: 'ptzHorAngle',
+},
+{
+name: '云台垂直角',
+prop: 'ptzVerAngle',
+},
 ]
 
 //联动规则配置
 export let warnTableConfig: any = {
-  readFrom: '',
-  type: 'C',
-  tableReadFrom: 'warnInfo',
-  columns: [
-    {
-      name: '报警条目',
-      prop: 'alarmName',
-    },
-    {
-      name: '预警等级',
-      prop: 'alarmLevel',
-    },
-    {
-      name: '所属系统',
-      prop: 'systemType_dictText',
-    },
-    {
-      name: '预警类型',
-      prop: 'alarmType_dictText',
-    },
-    {
-      name: '创建人',
-      prop: 'createBy',
-    },
-    {
-      name: '操作',
-      prop: 'operation',
-    },
-  ],
+readFrom: '',
+type: 'C',
+tableReadFrom: 'warnInfo',
+columns: [
+{
+name: '报警条目',
+prop: 'alarmName',
+},
+{
+name: '预警等级',
+prop: 'alarmLevel',
+},
+{
+name: '所属系统',
+prop: 'systemType_dictText',
+},
+{
+name: '预警类型',
+prop: 'alarmType_dictText',
+},
+{
+name: '创建人',
+prop: 'createBy',
+},
+{
+name: '操作',
+prop: 'operation',
+},
+],
 }
 export let warnTableConfigD: any = {
-  readFrom: '',
-  type: 'D',
+readFrom: '',
+type: 'D',
 }
 
 //视频预览-报警列表表头
 export let videoColumns: any[] = [
-  {
-    name: '设备号',
-    prop: 'preset',
-  },
-  {
-    name: '设备名称',
-    prop: 'deviceName',
-  },
-  {
-    name: '设备安装位置',
-    prop: 'devicePos',
-  },
-  {
-    name: '报警类型',
-    prop: 'eventTypeC',
-  },
-  {
-    name: '红外类型',
-    prop: 'irModel',
-  },
-  {
-    name: '模式',
-    prop: 'mode',
-  },
-  {
-    name: '红外水平像素数量',
-    prop: 'numOfIrHorPixs',
-  },
-  {
-    name: '红外垂直像素数量',
-    prop: 'numOfIrVerPixs',
-  },
-  {
-    name: '云台水平角',
-    prop: 'ptzHorAngle',
-  },
-  {
-    name: '云台垂直角',
-    prop: 'ptzVerAngle',
-  },
-  {
-    name: '测温标记',
-    prop: 'tempFlag',
-  },
+{
+name: '设备号',
+prop: 'preset',
+},
+{
+name: '设备名称',
+prop: 'deviceName',
+},
+{
+name: '设备安装位置',
+prop: 'devicePos',
+},
+{
+name: '报警类型',
+prop: 'eventTypeC',
+},
+//{
+//name: '红外类型',
+//prop: 'irModel',
+//},
+{
+name: '模式',
+prop: 'modeC',
+},
+{
+name: '红外水平像素数量',
+prop: 'numOfIrHorPixs',
+},
+{
+name: '红外垂直像素数量',
+prop: 'numOfIrVerPixs',
+},
+{
+name: '云台水平角',
+prop: 'ptzHorAngle',
+},
+{
+name: '云台垂直角',
+prop: 'ptzVerAngle',
+},
+{
+name: '测温标记',
+prop: 'tempFlag',
+},
 ]
 
 /**视频预览-Tab 标签列表 */
 export const tabs: TabItem[] = [
-  { key: 'device', label: '设备' },
-  { key: 'stats', label: '统计' },
-  { key: 'advanced', label: '高级' },
-  { key: 'preset', label: '预置位' },
+{ key: 'device', label: '设备' },
+{ key: 'stats', label: '统计' },
+{ key: 'advanced', label: '高级' },
+{ key: 'angle', label: '角度' },
+{ key: 'preset', label: '预置位' },
 ]
 
 /**云台控制-功能 Tab 列表:云台控制 / 红外控制 / 激光 / 透雾 */
 export const tabsPtz: TabItem[] = [
-  { key: 'ptz', label: '云台控制' },
-  { key: 'ir', label: '红外控制' },
-  { key: 'laser', label: '激光' },
-  { key: 'defog', label: '透雾' },
+{ key: 'ptz', label: '云台控制' },
+{ key: 'ir', label: '红外控制' },
+{ key: 'laser', label: '激光' },
+{ key: 'defog', label: '透雾' },
 ]
 /**云台控制 - 镜头控制项:变焦、聚焦、光圈 */
 export const lensControls: LensControl[] = [
-  {
-    key: 'zoom',
-    icon: `<svg viewBox="0 0 24 24" width="18"
+{
+key: 'zoom',
+plusTip: '焦距变大',
+minusTip: '焦距变小',
+icon: `<svg viewBox="0 0 24 24" width="18"
   height="18"><circle cx="10" cy="10" r="6" fill="none" stroke="#fff" stroke-width="1.6"/><path d="M14.5 14.5 L20 20" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/><path d="M10 7.5 V12.5 M7.5 10 H12.5" stroke="#fff" stroke-width="1.5" stroke-linecap="round"/></svg>`,
-  },
-  {
-    key: 'focus',
-    icon: `<svg viewBox="0 0 24 24" width="18"
+},
+{
+key: 'focus',
+plusTip: '焦点前调',
+minusTip: '焦点后调',
+icon: `<svg viewBox="0 0 24 24" width="18"
   height="18"><rect x="3" y="7" width="12" height="10" rx="1.5" fill="none" stroke="#fff" stroke-width="1.5"/><circle cx="9" cy="12" r="2.5" fill="none" stroke="#fff" stroke-width="1.4"/><path d="M15 9.5 L21 7 V17 L15 14.5 Z" fill="none" stroke="#fff" stroke-width="1.4" stroke-linejoin="round"/></svg>`,
-  },
-  {
-    key: 'iris',
-    icon: `<svg viewBox="0 0 24 24" width="18"
+},
+{
+key: 'iris',
+plusTip: '光圈扩大',
+minusTip: '光圈缩小',
+icon: `<svg viewBox="0 0 24 24" width="18"
   height="18"><circle cx="12" cy="12" r="8" fill="none" stroke="#fff" stroke-width="1.4"/><path d="M12 4 L14.5 10.5 L21 12 L14.5 13.5 L12 20 L9.5 13.5 L3 12 L9.5 10.5 Z" fill="none" stroke="#fff" stroke-width="1.2" stroke-linejoin="round"/></svg>`,
-  },
+},
 ]
 
 export let picList = [
-  { src: getAssetURL('home-container/configurable/hsq/4-1.png'), label: '1.报警触发' },
-  { src: getAssetURL('home-container/configurable/hsq/6-1.png'), label: '2.系统确认' },
-  { src: getAssetURL('home-container/configurable/hsq/6-2.png'), label: '3.通知值班' },
-  { src: getAssetURL('home-container/configurable/hsq/4-4.png'), label: '4.现场处置' },
-  { src: getAssetURL('home-container/configurable/hsq/4-5.png'), label: '5.确认解除' },
+{ src: getAssetURL('home-container/configurable/hsq/4-1.png'), label: '1.报警触发' },
+{ src: getAssetURL('home-container/configurable/hsq/6-1.png'), label: '2.系统确认' },
+{ src: getAssetURL('home-container/configurable/hsq/6-2.png'), label: '3.通知值班' },
+{ src: getAssetURL('home-container/configurable/hsq/4-4.png'), label: '4.现场处置' },
+{ src: getAssetURL('home-container/configurable/hsq/4-5.png'), label: '5.确认解除' },
 ]
 /** 处置流程按钮 */
 export const actionBtns = [
-  { key: 2, label: '系统确认' },
-  { key: 3, label: '通知值班' },
-  { key: 4, label: '现场处置' },
-  { key: 5, label: '确认解除' },
+{ key: 2, label: '系统确认' },
+{ key: 3, label: '通知值班' },
+{ key: 4, label: '现场处置' },
+{ key: 5, label: '确认解除' },
 ]
 
 export let navList =[
-  { label: '光谱摄像机', value: 'duaSpeCamera' },
-  { label: '火灾探测器', value: 'imgFireDet' }
+{ label: '光谱摄像机', value: 'duaSpeCamera' },
+{ label: '火灾探测器', value: 'imgFireDet' }
 ]
 export let titleList =[
-  { label: '用户', value: 'username' },
-  { label: '操作设备', value: 'devicename' },
-  { label: '操作记录', value: 'strremark' },
-  { label: '登录IP', value: 'ip' },
-  { label: '时间', value: 'updateTime' },
+{ label: '用户', value: 'username' },
+{ label: '操作设备', value: 'devicename' },
+{ label: '操作记录', value: 'strremark' },
+{ label: '登录IP', value: 'ip' },
+{ label: '时间', value: 'updateTime' },
 ]
+
+/** 角度默认值(刷新时恢复) */
+export const ANGLE_DEFAULT: AngleState = {
+hMin: 0,
+hMax: 360,
+vMin: 90,
+vMax: 180,
+}
+
+export const angleFields: AngleField[] = [
+{ label: '水平扫描角度:', minKey: 'hMin', maxKey: 'hMax' },
+{ label: '垂直扫描角度:', minKey: 'vMin', maxKey: 'vMax' },
+]
+
+/** 多选框提示:第一个可见光取流,第二个红外取流 */
+export const checkTips = ['可见光取流', '红外取流'] as const
+
+/** 告警上报字段(全部可手动输入修改) */
+export const alarmReportFieldList: AlarmReportFieldItem[] = [
+{ key: 'deviceId', label: '设备号', placeholder: '请输入设备号' },
+{ key: 'deviceName', label: '设备名', placeholder: '请输入设备名' },
+{ key: 'longitude', label: '设备经度', placeholder: '请输入设备经度' },
+{ key: 'latitude', label: '设备纬度', placeholder: '请输入设备纬度' },
+{ key: 'operator', label: '操作员', placeholder: '请输入操作员' },
+{ key: 'remark', label: '备注', placeholder: '请输入备注' },
+]
+
+/** 预置位工具栏:图标对应 assets/icons 下 1.svg ~ 6.svg */
+export const presetToolbarItems: PresetToolbarItem[] = [
+{ key: 'refresh', icon: '1', title: '刷新' },
+{ key: 'link', icon: '2', title: '关联' },
+{ key: 'config', icon: '3', title: '配置' },
+{ key: 'export', icon: '4', title: '导出' },
+{ key: 'clear', icon: '5', title: '清空' },
+{ key: 'delete', icon: '6', title: '删除' },
+]
+
+/** 预置位表格列 */
+export const presetColumns = [
+{ key: 'id', label: '编号' },
+{ key: 'name', label: '名称' },
+{ key: 'action', label: '操作' },
+] as const
+
+/** 预置位空表占位行数(对齐设计稿斑马纹区域) */
+export const PRESET_EMPTY_ROW_COUNT = 8
+
+/** 激光操作:开/关激光、补光、爆闪 */
+export const laserActions: LaserActionItem[] = [
+{ key: 'laserOn', label: '开激光' },
+{ key: 'laserOff', label: '关激光' },
+{ key: 'laserFillLight', label: '补光' },
+{ key: 'laserStrobe', label: '开爆闪' },
+]

+ 5 - 1
src/views/vent/monitorManager/hsqHome/index.vue

@@ -22,6 +22,7 @@ import systemManger from './systemManger.vue'
 import largeScreen from './largeScreen.vue'
 import linkConfiguration from './linkConfiguration.vue'
 import videoPlayer from './videoPlayer.vue'
+import historyReport from './historyReport.vue'
 
 
 /** 菜单键值映射接口,定义各导航菜单项对应的 key 标识 */
@@ -32,7 +33,8 @@ interface IMenuKeyMap {
   ldpz: 'ldpz'
   xtgl: 'xtgl'
   dpzs: 'dpzs'
-  spyl: 'spyl'
+  spyl: 'spyl',
+  lspb: 'lspb',
 }
 /** 菜单 key 类型,从 IMenuKeyMap 中提取所有键的联合类型 */
 type MenuKey = IMenuKeyMap[keyof IMenuKeyMap]
@@ -54,6 +56,8 @@ const menuComponentMap: Record<MenuKey, Component> = {
   xtgl: systemManger,
   dpzs: largeScreen,
   spyl: videoPlayer,
+  lspb: historyReport,
+
 }
 
 /**

+ 0 - 1
src/views/vent/monitorManager/hsqHome/systemManger.vue

@@ -194,7 +194,6 @@ onMounted(() => {
   color: @white;
   position: relative;
   margin-bottom: 10px;
-  background-color: #09172c;
 
   /* 上部:用户列表 + 角色统计,高度自适应剩余空间 */
   .basic-top-box {

+ 73 - 9
src/views/vent/monitorManager/hsqHome/videoPlayer.vue

@@ -5,18 +5,27 @@
     <div class="left-box">
       <!-- 左上:设备树组件 -->
       <div class="basic-top-left">
-        <DeviceTree :treeData="treeData" @checkChange="onCheckChange" />
+        <DeviceTree
+          :treeData="treeData"
+          :selectedCamera="selectedCamera"
+          @checkChange="onCheckChange"
+          @checkedDeviceIdsChange="onCheckedDeviceIdsChange"
+        />
       </div>
       <!-- 左下:设备控制组件 -->
       <div class="basic-bottom-left">
-        <DeviceControl :deviceOptions="deviceOptions" />
+        <DeviceControl
+          :deviceOptions="deviceOptions"
+          :selectedCamera="selectedCamera"
+          @action="onPtzAction"
+        />
       </div>
     </div>
     <!-- 右侧面板:设备画面 + 告警列表 -->
     <div class="right-box">
       <!-- 右上:设备画面组件 -->
       <div class="basic-top-right">
-        <DeviceView ref="deviceViewRef" :deviceId="deviceId" />
+        <DeviceView ref="deviceViewRef" :deviceId="checkedDeviceIds" @select="onCameraSelect" />
       </div>
       <!-- 右下:设备告警列表组件 -->
       <div class="basic-bottom-right">
@@ -46,8 +55,10 @@ interface GroupNode {
 interface DeviceNode {
   id: string
   name: string
-  /** 三个勾选状态:如显示/联动/告警等 */
-  checks: [boolean, boolean, boolean]
+  /** 勾选:可见光取流 / 红外取流 */
+  checks: [boolean, boolean]
+  /** 设备 IP */
+  ip?: string
 }
 
 //系统id
@@ -58,10 +69,14 @@ const treeData = ref<GroupNode[]>([])
 const deviceOptions = ref<any[]>([])
 // 双光谱摄像机报警记录-分页列表查询
 const warnList = ref<any[]>([])
-// 当前选中的设备ID
-const deviceId = ref('')
+// // 当前选中的设备ID
+// const deviceId = ref('')
+/** 设备树勾选中的设备 ID 列表(随勾选动态更新) */
+const checkedDeviceIds = ref<string>('')
 /** 设备画面组件引用 */
 const deviceViewRef = ref<InstanceType<typeof DeviceView> | null>(null)
+/** 当前画面区选中的摄像头 */
+const selectedCamera = ref<any>(null)
 /** 定时获取监测数据定时器 */
 let timer: null | NodeJS.Timeout = null;
 
@@ -72,7 +87,8 @@ let timer: null | NodeJS.Timeout = null;
  */
 function onCheckChange(payload: { device: DeviceNode; index: number; checked: boolean }) {
   console.log('设备树勾选变更', payload)
-  deviceId.value = payload.device.id || ''
+  // deviceId.value = payload.device.id || ''
+  selectedCamera.value = null
   if (!payload.checked) return
   if (payload.index === 0) {
     deviceViewRef.value?.enableVisibleLightPlayMode?.()
@@ -81,6 +97,52 @@ function onCheckChange(payload: { device: DeviceNode; index: number; checked: bo
   }
 }
 
+/** 接收子组件勾选设备 ID 数组(默认全选后即为全部设备 ID) */
+function onCheckedDeviceIdsChange(ids: string[]) {
+  checkedDeviceIds.value = ids.join(',') || ''
+  console.log('勾选设备ID列表', checkedDeviceIds.value)
+}
+
+/** 画面区摄像头选中(附带当前设备 IP / deviceid,供抓拍、录像等 SDK 接口使用) */
+function onCameraSelect(camera: any) {
+  if (!camera) {
+    selectedCamera.value = null
+    return
+  }
+  const deviceid =
+    camera.deviceid ||
+    camera.deviceId ||
+    camera.deviceID ||
+    camera.devId ||
+    ''
+  selectedCamera.value = {
+    ...camera,
+    deviceid: deviceid != null && String(deviceid).trim() !== '' ? String(deviceid).trim() : '',
+    ip: camera.ip || camera.strip || '',
+  }
+}
+
+/** 云台焦距 / 焦点 / 光圈:不调接口,直接作用于当前选中画面 */
+function onPtzAction(payload: { type: string; value: string }) {
+  if (!payload?.type || payload.value === 'stop') return
+  if (payload.type === 'zoom') {
+    if (payload.value === 'plus') deviceViewRef.value?.zoomSelectedView?.(1)
+    else if (payload.value === 'minus') deviceViewRef.value?.zoomSelectedView?.(-1)
+    return
+  }
+  if (payload.type === 'focus') {
+    // plus=焦点前调(更清晰),minus=焦点后调(更模糊)
+    if (payload.value === 'plus') deviceViewRef.value?.focusSelectedView?.(-1)
+    else if (payload.value === 'minus') deviceViewRef.value?.focusSelectedView?.(1)
+    return
+  }
+  if (payload.type === 'iris') {
+    // plus=光圈扩大(更亮),minus=光圈缩小(更暗)
+    if (payload.value === 'plus') deviceViewRef.value?.irisSelectedView?.(1)
+    else if (payload.value === 'minus') deviceViewRef.value?.irisSelectedView?.(-1)
+  }
+}
+
 /**
  * 定时获取监测数据
  * 通过定时器循环调用数据获取方法,更新表格数据
@@ -207,7 +269,8 @@ async function getTableData() {
         return {
           id: d.deviceID,
           name: d.strname,
-          checks: prevChecks ? [...prevChecks] : [false, false],
+          ip: d.ip || d.strip || '',
+          checks: prevChecks ? [...prevChecks] : [true, true],
         }
       })
     },
@@ -230,6 +293,7 @@ async function getDscAlarmLogList() {
     warnList.value = res.records.map(el => ({
       ...el,
       eventTypeC: el.eventType == '10001' ? '热源报警' : el.eventType == '10002' ? '闯入报警' : '-',
+      modeC: el.mode == '1' || el.mode == 1 ? '预置位' : el.mode == '2' || el.mode == 2 ? '角度位下标号' : '-',
     }))
   }
 }

+ 1 - 0
vite.config.ts

@@ -152,6 +152,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
         'china-area-data',
         'clipboard',
         'codemirror',
+        'maplibre-gl',
         'codemirror/addon/fold/brace-fold.js',
         'codemirror/addon/fold/comment-fold.js',
         'codemirror/addon/fold/foldcode.js',

+ 5720 - 0
红沙泉SDK接口文档-0917.md

@@ -0,0 +1,5720 @@
+# ZC SDK 设备接口文档
+
+> 基础路径:`/api/zc/device` 请求方式:POST Content-Type:application/json
+> 请求/返回数据格式:结构体字段 JSON(byte[] 字符数组字段传字符串)
+
+## 目录
+
+1. [login — 设备登录。](#1) 
+2. [logout — 设备登出。](#2) 
+3. [reboot — 设备重启。](#3) 
+4. [resetConfig — 恢复设备出厂配置(不保存)。](#4) 
+5. [saveConfig — 保存设备当前全部配置。](#5) 
+6. [getDeviceInfo — 获取设备基础信息。](#6) 
+7. [setDeviceInfo — 设置设备基础信息。](#7) 
+8. [getNetworkConfig — 获取设备网络配置(裸指针接口)。](#8) 
+9. [setNetworkConfig — 设置设备网络配置。](#9) 
+10. [ptzControl — 云台持续运动控制。](#10) 
+11. [ptzPresetControl — 预置位操作:调用/保存/删除预置位。](#11) 
+12. [rockerSpeedControl — 摇杆无级速度控制。](#12) 
+13. [setPTZAngle — 指定云台绝对角度定位。](#13) 
+14. [getPtzAngle — 获取云台当前角度。](#14) 
+15. [motorControl — 电机单独控制。](#15) 
+16. [captureJPEGToFile — 抓拍可见光 JPG 保存到本地文件。](#16) 
+17. [captureJPEG — 抓拍可见光 JPG,返回 Base64 图片数据。](#17) 
+18. [captureThermalToFile — 抓拍红外热图保存到文件。](#18) 
+19. [captureVisibleHDToFile — 高清可见光抓拍保存文件。](#19) 
+20. [captureTemperatureFrame — 获取红外测温原始帧数据(温度矩阵),返回 Base64。](#20) 
+21. [streamDisconnect — 关闭实时流。](#21) 
+22. [parsePixelTemp — 根据像素坐标读取单点温度。](#22) 
+23. [getTempMaxMinAvg — 计算整张画面最高/最低/平均温度。](#23) 
+24. [parsePoseData — 解析原始姿态数据(陀螺仪/加速度/欧拉角/测温)。](#24) 
+25. [getPresetPotTempRect — 获取预置位测温矩形区域。](#25) 
+26. [setPresetPotTempRect — 设置预置位测温矩形区域。](#26) 
+27. [clearPresetPotTempRect — 清空预置位测温矩形区域。](#27) 
+28. [getPresetPotTempPoly — 获取预置位测温多边形区域。](#28) 
+29. [setPresetPotTempPoly — 设置预置位测温多边形区域。](#29) 
+30. [clearPresetPotTempPoly — 清空预置位测温多边形区域。](#30) 
+31. [getPresetStaticShieldRect — 获取预置位静屏矩形屏蔽区。](#31) 
+32. [setPresetStaticShieldRect — 设置预置位静屏矩形屏蔽区。](#32) 
+33. [clearPresetStaticShieldRect — 清空预置位静屏矩形屏蔽区。](#33) 
+34. [getPresetStaticShieldPoly — 获取预置位静屏多边形屏蔽区。](#34) 
+35. [setPresetStaticShieldPoly — 设置预置位静屏多边形屏蔽区。](#35) 
+36. [clearPresetStaticShieldPoly — 清空预置位静屏多边形屏蔽区。](#36) 
+37. [deviceUpgrade — 设备固件升级。](#37) 
+38. [streamGetSingleFrame — 实时流取单帧(ZC_StreamGetSingleFrame)。](#38) 
+39. [streamFreeSingleFrame — 释放实时流单帧(ZC_StreamFreeSingleFrame)。](#39) 
+40. [captureFrameV20 — V20 抓取一帧图像(ZC_CaptureFrame_V20)。](#40) 
+41. [captureFrame — 通用抓取一帧(ZC_CaptureFrame,常用于测温帧)。](#41) 
+42. [tempFrmGetPixTemp — 帧内单点温度(ZC_TempFrm_GetPixTemp)。](#42) 
+43. [ptzControlLegacy — 旧版 PTZ 控制(ZC_PTZControl,区别于 {@code /ptzControl} 的 ZC_PTZControl_V20)。](#43) 
+44. [gotoPtzAngle — 云台按角度定位(ZC_GotoPtzAngle)。](#44) 
+45. [setAlarmPictureSavePath — ](#45) 
+46. [stopSrvCenter — ](#46) 
+47. [startSrvCenter — ](#47) 
+48. [deviceSearch — ](#48) 
+49. [mapLog — ](#49) 
+50. [realPlay — 设备实时预览(设备绑定回调,RealDataCallback 在 ZcDeviceManager 注册并上报)。](#50) 
+51. [registerRgbDataCallback — ](#51) 
+52. [stopRealPlay — ](#52) 
+53. [getSDKVersion — 获取 SDK 版本号](#53) 
+54. [init — SDK 全局初始化,程序启动调用一次即可](#54) 
+55. [clear — 释放 SDK 全局资源,程序退出前调用一次即可](#55) 
+56. [getLastError — 获取 SDK 最后一次错误码](#56) 
+57. [freeFrameV20 — 释放一帧 V20 帧数据](#57) 
+58. [freeFrm — 释放一帧普通帧数据](#58) 
+59. [getLaserDistance — 获取激光测距距离](#59) 
+60. [realPlay_CopyRGBData — 从实时预览拷贝一帧 RGB 数据(BGR24)](#60) 
+61. [getLastAlarmInfo_FromDevice — 从设备读取最近一次报警信息](#61) 
+62. [mapFireLocation — 地图火点位置映射(d 定位/ir 红外/f 火点/loc 位置 4 个结构体)](#62) 
+63. [displayRGBData — 渲染一帧 BGR24 数据到窗口](#63) 
+64. [compressIRDataTo8Bits — 将红外温度数据帧压缩为 8 位数据](#64) 
+65. [tempFrm_WriteToTxt — 将温度数据帧写入 txt 文档](#65) 
+66. [tempFrm_Rect_WriteToTxt — 将温度数据帧指定矩形区域写入 txt 文档](#66) 
+67. [parseInquiryInfo — 解析设备搜索返回的 JSON 信息](#67) 
+68. [getDeviceSoftVersion — 获取设备软件版本](#68) 
+69. [getConnectStatus — 获取设备连接状态](#69) 
+70. [realPlay_SetImageStretch — 预览图像拉伸](#70) 
+71. [captureJPEGPicture — 抓拍JPEG图片](#71) 
+72. [recordMP4File — 开始录制MP4视频](#72) 
+73. [stopRecordMP4File — 停止录制MP4视频](#73) 
+74. [getImageCfg — 查询图像参数](#74) 
+75. [setImageCfg — 设置图像参数](#75) 
+76. [getMediaCompress — 查询音视频压缩参数](#76) 
+77. [setMediaCompress — 设置音视频压缩参数](#77) 
+78. [getTPDCfg — 查询测温参数](#78) 
+79. [setTPDCfg — 设置测温参数](#79) 
+80. [restoreTPDCfg — 恢复默认测温参数](#80) 
+81. [getAutoShutterCfg — 查询 自动快门](#81) 
+82. [setAutoShutterCfg — 设置 自动快门](#82) 
+83. [systemTimeSync_V20 — 系统时间同步](#83) 
+84. [getSupplyLightCfg_V20 — 查询补光灯参数](#84) 
+85. [setSupplyLightCfg_V20 — 设置补光灯参数](#85) 
+86. [getRS485Cfg_V20 — 查询RS485参数](#86) 
+87. [setRS485Cfg_V20 — 设置RS485参数](#87) 
+88. [getNTPCfg_V20 — 查询NTP参数](#88) 
+89. [setNTPCfg_V20 — 设置NTP参数](#89) 
+90. [getPTZCfg_V20 — 查询PTZ参数](#90) 
+91. [setPTZCfg_V20 — 设置PTZ参数](#91) 
+92. [getSmartCaps — 查询智能分析能力集](#92) 
+93. [getTempDetectPoint_V20 — 对应 C 接口 {@code ZC_GetTempDetectPoint_V20}(SDK 头文件无独立注释,功能见函数名)](#93) 
+94. [setTempDetectPoint_V20 — 对应 C 接口 {@code ZC_SetTempDetectPoint_V20}(SDK 头文件无独立注释,功能见函数名)](#94) 
+95. [getTempDetectLine_V20 — 对应 C 接口 {@code ZC_GetTempDetectLine_V20}(SDK 头文件无独立注释,功能见函数名)](#95) 
+96. [setTempDetectLine_V20 — 对应 C 接口 {@code ZC_SetTempDetectLine_V20}(SDK 头文件无独立注释,功能见函数名)](#96) 
+97. [getTempDetectEllipse — 对应 C 接口 {@code ZC_GetTempDetectEllipse}(SDK 头文件无独立注释,功能见函数名)](#97) 
+98. [setTempDetectEllipse — 对应 C 接口 {@code ZC_SetTempDetectEllipse}(SDK 头文件无独立注释,功能见函数名)](#98) 
+99. [getTempDetectRect_V20 — 查询区域测温矩形参数](#99) 
+100. [setTempDetectRect_V20 — 设置区域测温矩形参数](#100) 
+101. [getTempDetectPoly_V20 — 查询区域测温多边形参数](#101) 
+102. [setTempDetectPoly_V20 — 设置区域测温多边形参数](#102) 
+103. [getStaticShieldRect_V20 — 查询静态屏蔽矩形参数](#103) 
+104. [setStaticShieldRect_V20 — 设置静态屏蔽矩形参数](#104) 
+105. [getStaticShieldPoly_V20 — 查询静态屏蔽多边形参数](#105) 
+106. [setStaticShieldPoly_V20 — 设置静态屏蔽多边形参数](#106) 
+107. [getStaticAnalRect_V20 — 查询定区分析矩形参数](#107) 
+108. [setStaticAnalRect_V20 — 设置定区分析矩形参数](#108) 
+109. [getStaticAnalPoly_V20 — 查询定区分析多边形参数](#109) 
+110. [setStaticAnalPoly_V20 — 设置定区分析多边形参数](#110) 
+111. [getDynaShieldRect_V20 — 查询动态屏蔽矩形参数](#111) 
+112. [setDynaShieldRect_V20 — 设置动态屏蔽矩形参数](#112) 
+113. [getDynaShieldPoly_V20 — 查询动态屏蔽多边形参数](#113) 
+114. [setDynaShieldPoly_V20 — 设置动态屏蔽多边形参数](#114) 
+115. [getBreakinLine_V20 — 查询周界入侵线参数](#115) 
+116. [setBreakinLine_V20 — 设置周界入侵线参数](#116) 
+117. [getBreakinRect_V20 — 查询周界入侵矩形参数](#117) 
+118. [setBreakinRect_V20 — 设置周界入侵矩形参数](#118) 
+119. [getBreakinPolygon_V20 — 查询周界入侵多边形参数](#119) 
+120. [setBreakinPolygon_V20 — 设置周界入侵多边形参数](#120) 
+121. [getBreakinPolyline_V20 — 查询周界入侵折线参数](#121) 
+122. [setBreakinPolyline_V20 — 设置周界入侵折线参数](#122) 
+123. [setPesudoColor — 设置伪彩(仅热成像有效)](#123) 
+124. [getConfig — 获取参数](#124) 
+125. [setConfig — 设置参数](#125) 
+126. [getSysCfg — 获取系统参数](#126) 
+127. [setSysCfg — 设置系统参数](#127) 
+128. [setRunModeCfg — 切换模式](#128) 
+129. [setEnvironmentTemperature — 设置环境温度值](#129) 
+130. [pTZControlEx — 对应 C 接口 {@code ZC_PTZControlEx}(SDK 头文件无独立注释,功能见函数名)](#130) 
+131. [getAllPreset — 查询所有预置位的状态](#131) 
+132. [setPtzPreset — 设置云台预置位](#132) 
+133. [gotoPtzPreset — 调用云台预置位](#133) 
+134. [delPtzPreset — 删除云台预置位](#134) 
+135. [getPresetInfo — 获取预置位信息](#135) 
+136. [setPresetInfo — 设置预置位信息](#136) 
+137. [getPtzCruiseCfg — 查询巡航线](#137) 
+138. [setPtzCruise — 设置巡航线](#138) 
+139. [gotoPtzCruise — 调用巡航线](#139) 
+140. [clrPtzCruise — 清除巡航线](#140) 
+141. [showClickTemp — 显示point位置的温度](#141) 
+142. [hideClickTemp — 隐藏point位置的温度](#142) 
+143. [captureLastAlarm — 获取最后一张报警图](#143) 
+144. [captureHDFrameNoOsd — 获取一帧无叠加的高清图像数据](#144) 
+145. [uploadVoiceFile — 上传语音文件](#145) 
+146. [getHttpDestInfo — 获取HTTP报警接收目的地址信息](#146) 
+147. [setHttpDestInfo — 设置HTTP报警接收目的地址信息](#147) 
+148. [getIRData — 获取红外数据](#148) 
+149. [getIRBadPixFrm — 获取红外坏点数据帧](#149) 
+150. [setIRBadPixFrm — 修复红外坏点数据帧](#150) 
+151. [getMappingTemInfo — 对应 C 接口 {@code ZC_GetMappingTemInfo}(SDK 头文件无独立注释,功能见函数名)](#151) 
+152. [setMappingTemInfo — 对应 C 接口 {@code ZC_SetMappingTemInfo}(SDK 头文件无独立注释,功能见函数名)](#152) 
+153. [setInvalidRect — 设置灼伤区](#153) 
+154. [clrInvalidRect — 清除灼伤区](#154) 
+155. [getPresetStaticAnalysisRect — 定区-矩形](#155) 
+156. [setPresetStaticAnalysisRect — 对应 C 接口 {@code ZC_SetPresetStaticAnalysisRect}(SDK 头文件无独立注释,功能见函数名)](#156) 
+157. [clrPresetStaticAnalysisRect — 对应 C 接口 {@code ZC_ClrPresetStaticAnalysisRect}(SDK 头文件无独立注释,功能见函数名)](#157) 
+158. [getPresetStaticAnalysisPoly — 定区-多边形](#158) 
+159. [setPresetStaticAnalysisPoly — 对应 C 接口 {@code ZC_SetPresetStaticAnalysisPoly}(SDK 头文件无独立注释,功能见函数名)](#159) 
+160. [clrPresetStaticAnalysisPoly — 对应 C 接口 {@code ZC_ClrPresetStaticAnalysisPoly}(SDK 头文件无独立注释,功能见函数名)](#160) 
+161. [getPresetDynamicShieldRect — 动屏-矩形](#161) 
+162. [setPresetDynamicShieldRect — 对应 C 接口 {@code ZC_SetPresetDynamicShieldRect}(SDK 头文件无独立注释,功能见函数名)](#162) 
+163. [clrPresetDynamicShieldRect — 对应 C 接口 {@code ZC_ClrPresetDynamicShieldRect}(SDK 头文件无独立注释,功能见函数名)](#163) 
+164. [getPresetDynamicShieldPoly — 动屏-多边形](#164) 
+165. [setPresetDynamicShieldPoly — 对应 C 接口 {@code ZC_SetPresetDynamicShieldPoly}(SDK 头文件无独立注释,功能见函数名)](#165) 
+166. [clrPresetDynamicShieldPoly — 对应 C 接口 {@code ZC_ClrPresetDynamicShieldPoly}(SDK 头文件无独立注释,功能见函数名)](#166) 
+167. [getPresetMoveLine — 闯入-线](#167) 
+168. [setPresetMoveLine — 对应 C 接口 {@code ZC_SetPresetMoveLine}(SDK 头文件无独立注释,功能见函数名)](#168) 
+169. [clrPresetMoveLine — 对应 C 接口 {@code ZC_ClrPresetMoveLine}(SDK 头文件无独立注释,功能见函数名)](#169) 
+170. [getPresetMoveRect — 闯入-矩形](#170) 
+171. [setPresetMoveRect — 对应 C 接口 {@code ZC_SetPresetMoveRect}(SDK 头文件无独立注释,功能见函数名)](#171) 
+172. [clrPresetMoveRect — 对应 C 接口 {@code ZC_ClrPresetMoveRect}(SDK 头文件无独立注释,功能见函数名)](#172) 
+173. [getPresetMovePoly — 闯入-多边形](#173) 
+174. [setPresetMovePoly — 对应 C 接口 {@code ZC_SetPresetMovePoly}(SDK 头文件无独立注释,功能见函数名)](#174) 
+175. [clrPresetMovePoly — 对应 C 接口 {@code ZC_ClrPresetMovePoly}(SDK 头文件无独立注释,功能见函数名)](#175) 
+176. [getPresetMoveBorder — 闯入-多边形边界](#176) 
+177. [setPresetMoveBorder — 对应 C 接口 {@code ZC_SetPresetMoveBorder}(SDK 头文件无独立注释,功能见函数名)](#177) 
+178. [clrPresetMoveBorder — 对应 C 接口 {@code ZC_ClrPresetMoveBorder}(SDK 头文件无独立注释,功能见函数名)](#178) 
+179. [getPresetTempPoint — 测温点](#179) 
+180. [setPresetTempPoint — 对应 C 接口 {@code ZC_SetPresetTempPoint}(SDK 头文件无独立注释,功能见函数名)](#180) 
+181. [clrPresetTempPoint — 对应 C 接口 {@code ZC_ClrPresetTempPoint}(SDK 头文件无独立注释,功能见函数名)](#181) 
+182. [getPresetPotTempLine — 测温线](#182) 
+183. [setPresetPotTempLine — 对应 C 接口 {@code ZC_SetPresetPotTempLine}(SDK 头文件无独立注释,功能见函数名)](#183) 
+184. [clrPresetPotTempLine — 对应 C 接口 {@code ZC_ClrPresetPotTempLine}(SDK 头文件无独立注释,功能见函数名)](#184) 
+185. [getPresetOilLevelRect — 油位监测](#185) 
+186. [setPresetOilLevelRect — 对应 C 接口 {@code ZC_SetPresetOilLevelRect}(SDK 头文件无独立注释,功能见函数名)](#186) 
+187. [clrPresetOilLevelRect — 对应 C 接口 {@code ZC_ClrPresetOilLevelRect}(SDK 头文件无独立注释,功能见函数名)](#187) 
+188. [getPresetOilLevelPoly — 对应 C 接口 {@code ZC_GetPresetOilLevelPoly}(SDK 头文件无独立注释,功能见函数名)](#188) 
+189. [setPresetOilLevelPoly — 对应 C 接口 {@code ZC_SetPresetOilLevelPoly}(SDK 头文件无独立注释,功能见函数名)](#189) 
+190. [clrPresetOilLevelPoly — 对应 C 接口 {@code ZC_ClrPresetOilLevelPoly}(SDK 头文件无独立注释,功能见函数名)](#190) 
+191. [getPresetBlackBodyRect — 黑体区域接口](#191) 
+192. [setPresetBlackBodyRect — 对应 C 接口 {@code ZC_SetPresetBlackBodyRect}(SDK 头文件无独立注释,功能见函数名)](#192) 
+193. [getPresetTargetStayRect — 目标逗留,此功能只在1号预置位下有效](#193) 
+194. [setPresetTargetStayRect — 对应 C 接口 {@code ZC_SetPresetTargetStayRect}(SDK 头文件无独立注释,功能见函数名)](#194) 
+195. [clrPresetTargetStayRect — 对应 C 接口 {@code ZC_ClrPresetTargetStayRect}(SDK 头文件无独立注释,功能见函数名)](#195) 
+196. [getAngleStaticAnalysisRect — 定区-矩形](#196) 
+197. [setAngleStaticAnalysisRect — 对应 C 接口 {@code ZC_SetAngleStaticAnalysisRect}(SDK 头文件无独立注释,功能见函数名)](#197) 
+198. [clrAngleStaticAnalysisRect — 对应 C 接口 {@code ZC_ClrAngleStaticAnalysisRect}(SDK 头文件无独立注释,功能见函数名)](#198) 
+199. [getAngleStaticAnalysisPoly — 定区-多边形](#199) 
+200. [setAngleStaticAnalysisPoly — 对应 C 接口 {@code ZC_SetAngleStaticAnalysisPoly}(SDK 头文件无独立注释,功能见函数名)](#200) 
+201. [clrAngleStaticAnalysisPoly — 对应 C 接口 {@code ZC_ClrAngleStaticAnalysisPoly}(SDK 头文件无独立注释,功能见函数名)](#201) 
+202. [getAngleStaticShieldRect — 静屏-矩形](#202) 
+203. [setAngleStaticShieldRect — 对应 C 接口 {@code ZC_SetAngleStaticShieldRect}(SDK 头文件无独立注释,功能见函数名)](#203) 
+204. [clrAngleStaticShieldRect — 对应 C 接口 {@code ZC_ClrAngleStaticShieldRect}(SDK 头文件无独立注释,功能见函数名)](#204) 
+205. [getAngleStaticShieldPoly — 静屏-多边形](#205) 
+206. [setAngleStaticShieldPoly — 对应 C 接口 {@code ZC_SetAngleStaticShieldPoly}(SDK 头文件无独立注释,功能见函数名)](#206) 
+207. [clrAngleStaticShieldPoly — 对应 C 接口 {@code ZC_ClrAngleStaticShieldPoly}(SDK 头文件无独立注释,功能见函数名)](#207) 
+208. [getAngleDynamicShieldRect — 动屏-矩形](#208) 
+209. [setAngleDynamicShieldRect — 对应 C 接口 {@code ZC_SetAngleDynamicShieldRect}(SDK 头文件无独立注释,功能见函数名)](#209) 
+210. [clrAngleDynamicShieldRect — 对应 C 接口 {@code ZC_ClrAngleDynamicShieldRect}(SDK 头文件无独立注释,功能见函数名)](#210) 
+211. [getAngleDynamicShieldPoly — 动屏-多边形](#211) 
+212. [setAngleDynamicShieldPoly — 对应 C 接口 {@code ZC_SetAngleDynamicShieldPoly}(SDK 头文件无独立注释,功能见函数名)](#212) 
+213. [clrAngleDynamicShieldPoly — 对应 C 接口 {@code ZC_ClrAngleDynamicShieldPoly}(SDK 头文件无独立注释,功能见函数名)](#213) 
+214. [getAngleMoveLine — 闯入-线](#214) 
+215. [setAngleMoveLine — 对应 C 接口 {@code ZC_SetAngleMoveLine}(SDK 头文件无独立注释,功能见函数名)](#215) 
+216. [clrAngleMoveLine — 对应 C 接口 {@code ZC_ClrAngleMoveLine}(SDK 头文件无独立注释,功能见函数名)](#216) 
+217. [getAngleMoveRect — 闯入-矩形](#217) 
+218. [setAngleMoveRect — 对应 C 接口 {@code ZC_SetAngleMoveRect}(SDK 头文件无独立注释,功能见函数名)](#218) 
+219. [clrAngleMoveRect — 对应 C 接口 {@code ZC_ClrAngleMoveRect}(SDK 头文件无独立注释,功能见函数名)](#219) 
+220. [getAngleMovePoly — 闯入-多边形`](#220) 
+221. [setAngleMovePoly — 对应 C 接口 {@code ZC_SetAngleMovePoly}(SDK 头文件无独立注释,功能见函数名)](#221) 
+222. [clrAngleMovePoly — 对应 C 接口 {@code ZC_ClrAngleMovePoly}(SDK 头文件无独立注释,功能见函数名)](#222) 
+223. [getAngleMoveBorder — 闯入-多边形边界](#223) 
+224. [setAngleMoveBorder — 对应 C 接口 {@code ZC_SetAngleMoveBorder}(SDK 头文件无独立注释,功能见函数名)](#224) 
+225. [clrAngleMoveBorder — 对应 C 接口 {@code ZC_ClrAngleMoveBorder}(SDK 头文件无独立注释,功能见函数名)](#225) 
+226. [ruiTing_GetZone — R-T-D-Z](#226) 
+227. [ruiTing_SetZone — 对应 C 接口 {@code ZC_RuiTing_SetZone}(SDK 头文件无独立注释,功能见函数名)](#227) 
+228. [ruiTing_DelZone — 对应 C 接口 {@code ZC_RuiTing_DelZone}(SDK 头文件无独立注释,功能见函数名)](#228) 
+229. [ruiTing_GetGroup — 对应 C 接口 {@code ZC_RuiTing_GetGroup}(SDK 头文件无独立注释,功能见函数名)](#229) 
+230. [ruiTing_SetGroup — 对应 C 接口 {@code ZC_RuiTing_SetGroup}(SDK 头文件无独立注释,功能见函数名)](#230) 
+231. [ruiTing_DelGroup — 对应 C 接口 {@code ZC_RuiTing_DelGroup}(SDK 头文件无独立注释,功能见函数名)](#231) 
+232. [enableRecvAlarm — 是否接收报警 bEnable = 1,接收;bEnable = 0,不接收](#232) 
+233. [alarmAutoCapture — 报警自动抓拍图像](#233) 
+234. [captureToFile — 抓拍图像](#234) 
+
+<a id='1-login'></a>
+
+## 1. login — 设备登录(红外 + 可见光)。
+
+- **URL**:`POST /api/zc/device/login`
+
+### 请求体(LoginReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 红外(ZC)设备 IP |
+| port | int | 否 | 红外设备端口 |
+| username | String | 否 | 红外设备登录用户名 |
+| password | String | 否 | 红外设备登录密码 |
+| hdCamera | CameraInfo | 否 | 可见光(海康)设备连接参数(ip/port/username/password) |
+| irCamera | CameraInfo | 否 | 红外设备信息(预留) |
+
+### 返回
+
+始终 HTTP 200 + code=0(登录结果在 data 中,失败不回错误码):
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| ip | String | 设备 IP |
+| handle | long | 红外(ZC)登录句柄 |
+| loginTime | long | 登录时间戳(毫秒) |
+| result | int | 红外登录结果(0-成功 1-失败) |
+| msg1 | String | 红外结果消息 |
+| handle2 | long | 可见光(海康)登录句柄 |
+| hdresult | int | 可见光登录结果(0-成功 1-失败) |
+| msg2 | String | 可见光结果消息 |
+| msg | String | 总体结果消息(任一台失败时为"设备登录失败") |
+
+**说明**:先登录可见光设备(连接参数取 hdCamera),再登录红外设备(ip/port/username/password),两台设备相互独立;
+红外登录成功后按 IP 缓存句柄,并自动注册该设备的报警/事件/测温回调(回调数据经 ZcCallbackNotifier 上报)。
+
+---
+
+<a id='2-logout'></a>
+
+## 2. logout — 设备登出(红外 + 可见光)。
+
+- **URL**:`POST /api/zc/device/logout`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+
+### 返回
+
+始终 HTTP 200 + code=0(登出结果在 data 中):
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| result | int | 红外(ZC SDK)登出返回码 |
+| msg1 | String | 红外结果消息 |
+| hdresult | int | 可见光登出结果(0-成功 1-失败) |
+| msg2 | String | 可见光结果消息 |
+| msg | String | 总体结果消息(任一台失败时为"设备退出登录失败") |
+
+**说明**:先按 IP 取可见光设备信息并登出海康会话,再登出红外(ZC)会话(移除句柄缓存并注销设备绑定回调)。
+
+---
+
+<a id='3-reboot'></a>
+
+## 3. reboot — 设备重启。
+
+- **URL**:`POST /api/zc/device/reboot`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+
+### 返回
+
+code=0 成功,data 为 SDK 返回码(0 成功)
+
+---
+
+<a id='4-resetConfig'></a>
+
+## 4. resetConfig — 恢复设备出厂配置(不保存)。
+
+- **URL**:`POST /api/zc/device/resetConfig`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='5-saveConfig'></a>
+
+## 5. saveConfig — 保存设备当前全部配置。
+
+- **URL**:`POST /api/zc/device/saveConfig`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='6-getDeviceInfo'></a>
+
+## 6. getDeviceInfo — 获取设备基础信息。
+
+- **URL**:`POST /api/zc/device/getDeviceInfo`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+
+### 返回
+
+code=0 成功,data 为设备信息对象 {deviceID, deviceName, serialNumber, macAddress, appVersion, deviceType, deviceModel, runningTime}
+
+---
+
+<a id='7-setDeviceInfo'></a>
+
+## 7. setDeviceInfo — 设置设备基础信息。
+
+- **URL**:`POST /api/zc/device/setDeviceInfo`
+
+### 请求体(SetDeviceInfoReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| deviceInfo | DeviceInfoDto | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='8-getNetworkConfig'></a>
+
+## 8. getNetworkConfig — 获取设备网络配置(裸指针接口)。
+
+- **URL**:`POST /api/zc/device/getNetworkConfig`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='9-setNetworkConfig'></a>
+
+## 9. setNetworkConfig — 设置设备网络配置。
+
+- **URL**:`POST /api/zc/device/setNetworkConfig`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+
+### 返回
+
+code=100 提示不支持
+
+---
+
+<a id='10-ptzControl'></a>
+
+## 10. ptzControl — 云台持续运动控制。
+
+- **URL**:`POST /api/zc/device/ptzControl`
+
+### 请求体(PtzControlReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| cmd | int | 是 |  云台命令码:1-云台上 2-云台下 3-云台左 4-云台右 5-左上 6-右上 7-左下 8-右下;9-倍率变大 10-倍率变小 11-光圈放大 12-光圈缩小 13-焦点前调 14-焦点后调  |
+| stop | int | 是 | 停止标志:0-开始(持续运动,需再发一次 1 停止) 1-停止 |
+| speed | int | 是 | 速度:1~100 |
+| type | int | 是 | 1-红外 2-可见光 |
+
+### 返回
+
+始终 HTTP 200 + code=0(云台控制结果在 data 中):
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| result | int | 云台控制返回码(0-成功) |
+| msg | String | 总体消息 |
+---
+
+<a id='11-ptzPresetControl'></a>
+
+## 11. ptzPresetControl — 预置位操作:调用/保存/删除预置位。
+
+- **URL**:`POST /api/zc/device/ptzPresetControl`
+
+### 请求体(PresetReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| cmd | int | 否 |  |
+| idx | int | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='12-rockerSpeedControl'></a>
+
+## 12. rockerSpeedControl — 摇杆无级速度控制。
+
+- **URL**:`POST /api/zc/device/rockerSpeedControl`
+
+### 请求体(RockerReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| x | int | 否 |  |
+| y | int | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='13-setPTZAngle'></a>
+
+## 13. setPTZAngle — 指定云台绝对角度定位。
+
+- **URL**:`POST /api/zc/device/setPTZAngle`
+
+### 请求体(AngleReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| hAngle | float | 否 |  |
+| vAngle | float | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='14-getPtzAngle'></a>
+
+## 14. getPtzAngle — 获取云台当前角度。
+
+- **URL**:`POST /api/zc/device/getPtzAngle`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+
+### 返回
+
+code=0 成功,data 为 {horAngle, verAngle}
+
+---
+
+<a id='15-motorControl'></a>
+
+## 15. motorControl — 电机单独控制。
+
+- **URL**:`POST /api/zc/device/motorControl`
+
+### 请求体(MotorReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| id | int | 否 |  |
+| ctrl | int | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='16-captureJPEGToFile'></a>
+
+## 16. captureJPEGToFile — 抓拍可见光 JPG 保存到本地文件。
+
+- **URL**:`POST /api/zc/device/captureJPEGToFile`
+
+### 请求体(CaptureFileReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| channel | int | 否 |  |
+| path | String | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='17-captureJPEG'></a>
+
+## 17. captureJPEG — 抓拍可见光 JPG,返回 Base64 图片数据。
+
+- **URL**:`POST /api/zc/device/captureJPEG`
+
+### 请求体(CaptureReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| channel | int | 否 |  |
+
+### 返回
+
+code=0 成功,data 为 {length, imageBase64};失败时 imageBase64 为 null
+
+---
+
+<a id='18-captureThermalToFile'></a>
+
+## 18. captureThermalToFile — 抓拍红外热图保存到文件。
+
+- **URL**:`POST /api/zc/device/captureThermalToFile`
+
+### 请求体(PathReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| path | String | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='19-captureVisibleHDToFile'></a>
+
+## 19. captureVisibleHDToFile — 高清可见光抓拍保存文件。
+
+- **URL**:`POST /api/zc/device/captureVisibleHDToFile`
+
+### 请求体(PathReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| path | String | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='20-captureTemperatureFrame'></a>
+
+## 20. captureTemperatureFrame — 获取红外测温原始帧数据(温度矩阵),返回 Base64。
+
+- **URL**:`POST /api/zc/device/captureTemperatureFrame`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+
+### 返回
+
+code=0 成功,data 为 {length, frameBase64}
+
+---
+
+<a id='21-streamDisconnect'></a>
+
+## 21. streamDisconnect — 关闭实时流。
+
+- **URL**:`POST /api/zc/device/streamDisconnect`
+
+### 请求体(StreamDisconnectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| streamHandle | long | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='22-parsePixelTemp'></a>
+
+## 22. parsePixelTemp — 根据像素坐标读取单点温度。
+
+- **URL**:`POST /api/zc/device/parsePixelTemp`
+
+### 请求体(ParsePixelTempReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| x | int | 否 |  |
+| y | int | 否 |  |
+| frameBase64 | String | 否 |  |
+| width | int | 否 |  |
+| height | int | 否 |  |
+
+### 返回
+
+code=0 成功,data 为该点温度值(℃)
+
+---
+
+<a id='23-getTempMaxMinAvg'></a>
+
+## 23. getTempMaxMinAvg — 计算整张画面最高/最低/平均温度。
+
+- **URL**:`POST /api/zc/device/getTempMaxMinAvg`
+
+### 请求体(TempFrameReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| frameBase64 | String | 否 |  |
+| width | int | 否 |  |
+| height | int | 否 |  |
+
+### 返回
+
+code=0 成功,data 为 {maxX, maxY, maxT, minX, minY, minT, avgT}
+
+---
+
+<a id='24-parsePoseData'></a>
+
+## 24. parsePoseData — 解析原始姿态数据(陀螺仪/加速度/欧拉角/测温)。
+
+- **URL**:`POST /api/zc/device/parsePoseData`
+
+### 请求体(PoseReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| dataBase64 | String | 否 |  |
+
+### 返回
+
+code=0 成功,data 为姿态对象 {gyroX, gyroY, gyroZ, accX, accY, accZ, pitch, roll, yaw, m1Te, m2Te, m3Te, m1Tm, m2Tm, m3Tm}
+
+---
+
+<a id='25-getPresetPotTempRect'></a>
+
+## 25. getPresetPotTempRect — 获取预置位测温矩形区域。
+
+- **URL**:`POST /api/zc/device/getPresetPotTempRect`
+
+### 请求体(RegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+
+### 返回
+
+code=0 成功,data 为矩形结构体(SDK 以姿态结构体承载,字段名见 PoseDto)
+
+---
+
+<a id='26-setPresetPotTempRect'></a>
+
+## 26. setPresetPotTempRect — 设置预置位测温矩形区域。
+
+- **URL**:`POST /api/zc/device/setPresetPotTempRect`
+
+### 请求体(TempRectRegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+| rect | PotTempRectDto | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='27-clearPresetPotTempRect'></a>
+
+## 27. clearPresetPotTempRect — 清空预置位测温矩形区域。
+
+- **URL**:`POST /api/zc/device/clearPresetPotTempRect`
+
+### 请求体(RegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='28-getPresetPotTempPoly'></a>
+
+## 28. getPresetPotTempPoly — 获取预置位测温多边形区域。
+
+- **URL**:`POST /api/zc/device/getPresetPotTempPoly`
+
+### 请求体(RegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+
+### 返回
+
+code=0 成功,data 为 {radiation, alarmTemp, poly:{points:[{x,y}×6]}}
+
+---
+
+<a id='29-setPresetPotTempPoly'></a>
+
+## 29. setPresetPotTempPoly — 设置预置位测温多边形区域。
+
+- **URL**:`POST /api/zc/device/setPresetPotTempPoly`
+
+### 请求体(TempPolyRegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+| poly | PotTempPolyDto | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='30-clearPresetPotTempPoly'></a>
+
+## 30. clearPresetPotTempPoly — 清空预置位测温多边形区域。
+
+- **URL**:`POST /api/zc/device/clearPresetPotTempPoly`
+
+### 请求体(RegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='31-getPresetStaticShieldRect'></a>
+
+## 31. getPresetStaticShieldRect — 获取预置位静屏矩形屏蔽区。
+
+- **URL**:`POST /api/zc/device/getPresetStaticShieldRect`
+
+### 请求体(RegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+
+### 返回
+
+code=0 成功,data 为 {leftUp:{x,y}, rightDown:{x,y}}
+
+---
+
+<a id='32-setPresetStaticShieldRect'></a>
+
+## 32. setPresetStaticShieldRect — 设置预置位静屏矩形屏蔽区。
+
+- **URL**:`POST /api/zc/device/setPresetStaticShieldRect`
+
+### 请求体(RectRegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+| rect | RectDto | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='33-clearPresetStaticShieldRect'></a>
+
+## 33. clearPresetStaticShieldRect — 清空预置位静屏矩形屏蔽区。
+
+- **URL**:`POST /api/zc/device/clearPresetStaticShieldRect`
+
+### 请求体(RegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='34-getPresetStaticShieldPoly'></a>
+
+## 34. getPresetStaticShieldPoly — 获取预置位静屏多边形屏蔽区。
+
+- **URL**:`POST /api/zc/device/getPresetStaticShieldPoly`
+
+### 请求体(RegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+
+### 返回
+
+code=0 成功,data 为 {points:[{x,y}×6]}
+
+---
+
+<a id='35-setPresetStaticShieldPoly'></a>
+
+## 35. setPresetStaticShieldPoly — 设置预置位静屏多边形屏蔽区。
+
+- **URL**:`POST /api/zc/device/setPresetStaticShieldPoly`
+
+### 请求体(PolyRegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+| poly | PolyDto | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='36-clearPresetStaticShieldPoly'></a>
+
+## 36. clearPresetStaticShieldPoly — 清空预置位静屏多边形屏蔽区。
+
+- **URL**:`POST /api/zc/device/clearPresetStaticShieldPoly`
+
+### 请求体(RegionReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| preset | int | 否 |  |
+| idx | int | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='37-deviceUpgrade'></a>
+
+## 37. deviceUpgrade — 设备固件升级。
+
+- **URL**:`POST /api/zc/device/deviceUpgrade`
+
+### 请求体(UpgradeReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| filename | String | 否 |  |
+| filepath | String | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='38-streamGetSingleFrame'></a>
+
+## 38. streamGetSingleFrame — 实时流取单帧(ZC_StreamGetSingleFrame)。
+
+- **URL**:`POST /api/zc/device/streamGetSingleFrame`
+
+### 请求体(StreamFrameReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| streamHandle | long | 否 |  |
+
+### 返回
+
+code=0 成功,data 为 {width, height, length, timestamp, dataBase64};帧内存接口内部已释放
+
+---
+
+<a id='39-streamFreeSingleFrame'></a>
+
+## 39. streamFreeSingleFrame — 释放实时流单帧(ZC_StreamFreeSingleFrame)。
+
+- **URL**:`POST /api/zc/device/streamFreeSingleFrame`
+
+### 请求体(StreamFrameReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| streamHandle | long | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='40-captureFrameV20'></a>
+
+## 40. captureFrameV20 — V20 抓取一帧图像(ZC_CaptureFrame_V20)。
+
+- **URL**:`POST /api/zc/device/captureFrameV20`
+
+### 请求体(FrameV20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| type | int | 否 |  |
+
+### 返回
+
+code=0 成功,data 为 {width, height, length, timestamp, dataBase64};帧内存接口内部已释放
+
+---
+
+<a id='41-captureFrame'></a>
+
+## 41. captureFrame — 通用抓取一帧(ZC_CaptureFrame,常用于测温帧)。
+
+- **URL**:`POST /api/zc/device/captureFrame`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+
+### 返回
+
+code=0 成功,data 为 {width, height, length, dataBase64};帧内存接口内部已释放
+
+---
+
+<a id='42-tempFrmGetPixTemp'></a>
+
+## 42. tempFrmGetPixTemp — 帧内单点温度(ZC_TempFrm_GetPixTemp)。
+
+- **URL**:`POST /api/zc/device/tempFrmGetPixTemp`
+
+### 请求体(PixTempReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| width | int | 否 |  |
+| height | int | 否 |  |
+| x | int | 否 |  |
+| y | int | 否 |  |
+| frameBase64 | String | 否 |  |
+
+### 返回
+
+code=0 成功,data 为该点温度值(失败返回 NaN)
+
+---
+
+<a id='43-ptzControlLegacy'></a>
+
+## 43. ptzControlLegacy — 旧版 PTZ 控制(ZC_PTZControl,区别于 {@code /ptzControl} 的 ZC_PTZControl_V20)。
+
+- **URL**:`POST /api/zc/device/ptzControlLegacy`
+
+### 请求体(PtzLegacyReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| command | int | 否 |  |
+| control | int | 否 |  |
+| speed | int | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='44-gotoPtzAngle'></a>
+
+## 44. gotoPtzAngle — 云台按角度定位(ZC_GotoPtzAngle)。
+
+- **URL**:`POST /api/zc/device/gotoPtzAngle`
+
+### 请求体(GotoAngleReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+| horAngle | float | 否 |  |
+| verAngle | float | 否 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='45-setAlarmPictureSavePath'></a>
+
+## 45. setAlarmPictureSavePath — 
+
+- **URL**:`POST /api/zc/device/setAlarmPictureSavePath`
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='46-stopSrvCenter'></a>
+
+## 46. stopSrvCenter — 
+
+- **URL**:`POST /api/zc/device/stopSrvCenter`
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='47-startSrvCenter'></a>
+
+## 47. startSrvCenter — 
+
+- **URL**:`POST /api/zc/device/startSrvCenter`
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='48-deviceSearch'></a>
+
+## 48. deviceSearch — 
+
+- **URL**:`POST /api/zc/device/deviceSearch`
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='49-mapLog'></a>
+
+## 49. mapLog — 
+
+- **URL**:`POST /api/zc/device/mapLog`
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='50-realPlay'></a>
+
+## 50. realPlay — 设备实时预览(设备绑定回调,RealDataCallback 在 ZcDeviceManager 注册并上报)。
+
+- **URL**:`POST /api/zc/device/realPlay`
+
+### 返回
+
+预览句柄 hRealPlay
+
+---
+
+<a id='51-registerRgbDataCallback'></a>
+
+## 51. registerRgbDataCallback — 
+
+- **URL**:`POST /api/zc/device/registerRgbDataCallback`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='52-stopRealPlay'></a>
+
+## 52. stopRealPlay — 
+
+- **URL**:`POST /api/zc/device/stopRealPlay`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 |  |
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='53-getSDKVersion'></a>
+
+## 53. getSDKVersion — 获取 SDK 版本号
+
+- **URL**:`POST /api/zc/device/getSDKVersion`
+- **C 接口**:`ZC_GetSDKVersion`
+
+### 返回
+
+code=0 成功,data 含 version 字符串与 major/minor/revise/build 分量
+
+---
+
+<a id='54-init'></a>
+
+## 54. init — SDK 全局初始化,程序启动调用一次即可
+
+- **URL**:`POST /api/zc/device/init`
+- **C 接口**:`ZC_Init`
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='55-clear'></a>
+
+## 55. clear — 释放 SDK 全局资源,程序退出前调用一次即可
+
+- **URL**:`POST /api/zc/device/clear`
+- **C 接口**:`ZC_Clear`
+
+### 返回
+
+`Result<Integer>`
+
+---
+
+<a id='56-getLastError'></a>
+
+## 56. getLastError — 获取 SDK 最后一次错误码
+
+- **URL**:`POST /api/zc/device/getLastError`
+- **C 接口**:`ZC_GetLastErr`
+
+### 返回
+
+code=0 成功,data 为最近一次 SDK 调用的错误码
+
+---
+
+<a id='57-freeFrameV20'></a>
+
+## 57. freeFrameV20 — 释放一帧 V20 帧数据
+
+- **URL**:`POST /api/zc/device/freeFrameV20`
+- **C 接口**:`ZC_FreeFrame_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 是 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='58-freeFrm'></a>
+
+## 58. freeFrm — 释放一帧普通帧数据
+
+- **URL**:`POST /api/zc/device/freeFrm`
+- **C 接口**:`ZC_FreeFrm`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 是 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='59-getLaserDistance'></a>
+
+## 59. getLaserDistance — 获取激光测距距离
+
+- **URL**:`POST /api/zc/device/getLaserDistance`
+- **C 接口**:`ZC_GetLaserDistance`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+
+### 返回
+
+code=0 成功;返回值为数值结果
+
+---
+
+<a id='60-realPlay_CopyRGBData'></a>
+
+## 60. realPlay_CopyRGBData — 从实时预览拷贝一帧 RGB 数据(BGR24)
+
+- **URL**:`POST /api/zc/device/realPlay_CopyRGBData`
+- **C 接口**:`ZC_RealPlay_CopyRGBData`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | timeout(超时毫秒) |
+
+### 返回
+
+code=0 成功;data 为返回数据
+
+---
+
+<a id='61-getLastAlarmInfo_FromDevice'></a>
+
+## 61. getLastAlarmInfo_FromDevice — 从设备读取最近一次报警信息
+
+- **URL**:`POST /api/zc/device/getLastAlarmInfo_FromDevice`
+- **C 接口**:`ZC_GetLastAlarmInfo_FromDevice`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为返回数据
+
+---
+
+<a id='62-mapFireLocation'></a>
+
+## 62. mapFireLocation — 地图火点位置映射(d 定位/ir 红外/f 火点/loc 位置 4 个结构体)
+
+- **URL**:`POST /api/zc/device/mapFireLocation`
+- **C 接口**:`ZC_MapFireLocation`
+
+### 请求体(MapFireReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| d | String | 否 |  |
+| ir | String | 否 |  |
+| f | String | 否 |  |
+| loc | String | 否 |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='63-displayRGBData'></a>
+
+## 63. displayRGBData — 渲染一帧 BGR24 数据到窗口
+
+- **URL**:`POST /api/zc/device/displayRGBData`
+- **C 接口**:`ZC_DisplayRGBData`
+
+### 请求体(DisplayReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| w | Integer | 否 |  |
+| h | Integer | 否 |  |
+| pRGB | String | 否 |  |
+| bpp | Integer | 否 |  |
+| stretch | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='64-compressIRDataTo8Bits'></a>
+
+## 64. compressIRDataTo8Bits — 将红外温度数据帧压缩为 8 位数据
+
+- **URL**:`POST /api/zc/device/compressIRDataTo8Bits`
+- **C 接口**:`ZC_CompressIRDataTo8Bits`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_FRAME_S 结构体字段 JSON
+
+---
+
+<a id='65-tempFrm_WriteToTxt'></a>
+
+## 65. tempFrm_WriteToTxt — 将温度数据帧写入 txt 文档
+
+- **URL**:`POST /api/zc/device/tempFrm_WriteToTxt`
+- **C 接口**:`ZC_TempFrm_WriteToTxt`
+
+### 请求体(TxtReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 是 |  |
+| size | Integer | 否 |  |
+| s1 | String | 否 |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='66-tempFrm_Rect_WriteToTxt'></a>
+
+## 66. tempFrm_Rect_WriteToTxt — 将温度数据帧指定矩形区域写入 txt 文档
+
+- **URL**:`POST /api/zc/device/tempFrm_Rect_WriteToTxt`
+- **C 接口**:`ZC_TempFrm_Rect_WriteToTxt`
+
+### 请求体(TxtRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 是 |  |
+| size | Integer | 否 |  |
+| i4 | Integer | 否 |  |
+| i1 | Integer | 否 | x1 |
+| i2 | Integer | 否 | y1 |
+| i3 | Integer | 否 |  |
+| s1 | String | 否 |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='67-parseInquiryInfo'></a>
+
+## 67. parseInquiryInfo — 解析设备搜索返回的 JSON 信息
+
+- **URL**:`POST /api/zc/device/parseInquiryInfo`
+- **C 接口**:`ZC_ParseInquiryInfo`
+
+### 请求体(ParseInquiryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| s1 | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_INQUIRY_INFO_S 结构体字段 JSON
+
+---
+
+<a id='68-getDeviceSoftVersion'></a>
+
+## 68. getDeviceSoftVersion — 获取设备软件版本
+
+- **URL**:`POST /api/zc/device/getDeviceSoftVersion`
+- **C 接口**:`ZC_GetDeviceSoftVersion`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_VERSION_S 结构体字段 JSON
+
+---
+
+<a id='69-getConnectStatus'></a>
+
+## 69. getConnectStatus — 获取设备连接状态
+
+- **URL**:`POST /api/zc/device/getConnectStatus`
+- **C 接口**:`ZC_GetConnectStatus`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='70-realPlay_SetImageStretch'></a>
+
+## 70. realPlay_SetImageStretch — 预览图像拉伸
+
+- **URL**:`POST /api/zc/device/realPlay_SetImageStretch`
+- **C 接口**:`ZC_RealPlay_SetImageStretch`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | stretch |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='71-captureJPEGPicture'></a>
+
+## 71. captureJPEGPicture — 抓拍JPEG图片
+
+- **URL**:`POST /api/zc/device/captureJPEGPicture`
+- **C 接口**:`ZC_CaptureJPEGPicture`
+
+### 请求体(StrReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| s1 | String | 否 |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='72-recordMP4File'></a>
+
+## 72. recordMP4File — 开始录制 MP4 视频(红外 + 可见光)
+
+- **URL**:`POST /api/zc/device/recordMP4File`
+- **C 接口**:`ZC_RecordMP4File`(红外);可见光走海康 HCNetSDK 实时录制(通道 1,recordType=0)
+
+### 请求体(StrReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| s1 | String | 是 | 可见光录像文件名(如 visible.mp4,为空返回错误) |
+| s2 | String | 否 | 红外录像文件名(如 ir.mp4) |
+
+### 返回
+
+始终 HTTP 200 + code=0(结果在 data 中):
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| fileName | String | 可见光文件名(s1 回显) |
+| fileName2 | String | 红外文件名(s2 回显) |
+| filePath | String | 存储目录(mp4-path,不含文件名) |
+| result | int | 红外录制返回码(0-成功) |
+| msg1 | String | 红外结果消息 |
+| hdresult | int | 可见光录制结果(0-成功) |
+| msg2 | String | 可见光结果消息 |
+| msg | String | 总体消息(设备未登录时为"录制失败,请检查设备连接情况") |
+
+**说明**:红外录制到 `mp4-path` + s2,可见光录制到 `mp4-path` + s1,两路相互独立。
+
+---
+
+<a id='73-stopRecordMP4File'></a>
+
+## 73. stopRecordMP4File — 停止录制 MP4 视频(红外 + 可见光)
+
+- **URL**:`POST /api/zc/device/stopRecordMP4File`
+- **C 接口**:`ZC_StopRecordMP4File`(红外);可见光走海康停止实时录制
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+
+### 返回
+
+始终 HTTP 200 + code=0(结果在 data 中):
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| result | int | 红外停止录制返回码(0-成功) |
+| msg1 | String | 红外结果消息 |
+| filePath | String | 文件所属目录 |
+| fileName | String | 可见光文件名称 |
+| hdresult | int | 可见光停止结果(0-成功) |
+| msg2 | String | 可见光结果消息 |
+| fileName2 | String | 红外文件名称 |
+| msg | String | 总体消息(设备未登录时为"停止录制失败,请检查设备连接情况") |
+
+**说明**:红外取实时流句柄后调用 `ZC_StopRecordMP4File`;可见光调用海康停止实时录制(文件落盘),两路相互独立。
+
+---
+
+<a id='74-getImageCfg'></a>
+
+## 74. getImageCfg — 查询图像参数
+
+- **URL**:`POST /api/zc/device/getImageCfg`
+- **C 接口**:`ZC_GetImageCfg`
+
+### 请求体(BinaryIntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | channel |
+
+### 返回
+
+code=0 成功;data 为 ZC_IMAGE_CFG_S 结构体字段 JSON
+
+---
+
+<a id='75-setImageCfg'></a>
+
+## 75. setImageCfg — 设置图像参数
+
+- **URL**:`POST /api/zc/device/setImageCfg`
+- **C 接口**:`ZC_SetImageCfg`
+
+### 请求体(ImageCfgReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| data | ZC_IMAGE_CFG_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_IMAGE_CFG_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| brightnessLevel | int |  |
+| contrastLevel | int |  |
+| TNRLevel | int |  |
+| SNRLevel | int |  |
+| DDELevel | int |  |
+| AGCMode | int |  |
+| GAINLevel | int |  |
+| BosLevel | int |  |
+| AGCOnOff | int |  |
+| mirrorFlip | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='76-getMediaCompress'></a>
+
+## 76. getMediaCompress — 查询音视频压缩参数
+
+- **URL**:`POST /api/zc/device/getMediaCompress`
+- **C 接口**:`ZC_GetMediaCompress`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | channel |
+| i2 | Integer | 否 | source |
+
+### 返回
+
+code=0 成功;data 为 ZC_MEDIA_COMPRESS_V20_S 结构体字段 JSON
+
+---
+
+<a id='77-setMediaCompress'></a>
+
+## 77. setMediaCompress — 设置音视频压缩参数
+
+- **URL**:`POST /api/zc/device/setMediaCompress`
+- **C 接口**:`ZC_SetMediaCompress`
+
+### 请求体(MediaCompressReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_MEDIA_COMPRESS_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_MEDIA_COMPRESS_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| resolution | int |  |
+| videoEncType | int | 视频编码类型:0-H.264,1-H.265,2-MJPEG |
+| videoBitrate | int |  |
+| videoFrameRate | int | 视频帧率:[1,30] |
+| intervalFrameI | int | I帧间隔:[1,100] |
+| audioInputEnabled | int | 音频输入:0~禁用,1~启用 |
+| audioInputVolume | int | 音频输入音量:[0,100] |
+| audioOutputEnabled | int | 音频输出:0~禁用,1~启用 |
+| audioOutputVolume | int | 音频输出音量:[0,100] |
+| audioEncType | int | 音频编码类型:0-PCM,1-AAC,2-G711A,3-G711U,4-MP3 |
+| audioBirate | int | 音频码率:32000,64000 |
+| audioSamplingRate | int | 音频采样率:8000,16000,32000,44100 |
+| videoBitRateMode | int | 码率控制:0-定码率(cbr),1-变码率(vbr) |
+| videoProfile | int | 编码等级:0-Baseline,1-Main,2-High |
+| videoQuality | int | 编码质量:[0,6] |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='78-getTPDCfg'></a>
+
+## 78. getTPDCfg — 查询测温参数
+
+- **URL**:`POST /api/zc/device/getTPDCfg`
+- **C 接口**:`ZC_GetTPDCfg`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_TPD_CFG_S 结构体字段 JSON
+
+---
+
+<a id='79-setTPDCfg'></a>
+
+## 79. setTPDCfg — 设置测温参数
+
+- **URL**:`POST /api/zc/device/setTPDCfg`
+- **C 接口**:`ZC_SetTPDCfg`
+
+### 请求体(TPDCfgReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_TPD_CFG_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_TPD_CFG_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| ta | int | 环境反射温度 |
+| tu | int | 大气温度 |
+| gain | int | 增益 |
+| ems | double | 目标发射率 |
+| tau | double | 大气透过率 |
+| distance | double | 距离 |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='80-restoreTPDCfg'></a>
+
+## 80. restoreTPDCfg — 恢复默认测温参数
+
+- **URL**:`POST /api/zc/device/restoreTPDCfg`
+- **C 接口**:`ZC_RestoreTPDCfg`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='81-getAutoShutterCfg'></a>
+
+## 81. getAutoShutterCfg — 查询 自动快门
+
+- **URL**:`POST /api/zc/device/getAutoShutterCfg`
+- **C 接口**:`ZC_GetAutoShutterCfg`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_AUTO_SHUTTER_S 结构体字段 JSON
+
+---
+
+<a id='82-setAutoShutterCfg'></a>
+
+## 82. setAutoShutterCfg — 设置 自动快门
+
+- **URL**:`POST /api/zc/device/setAutoShutterCfg`
+- **C 接口**:`ZC_SetAutoShutterCfg`
+
+### 请求体(AutoShutterCfgReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_AUTO_SHUTTER_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_AUTO_SHUTTER_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int | 1-启用;0-禁用 |
+| interval | int | 快门间隔,单位:秒 |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='83-systemTimeSync_V20'></a>
+
+## 83. systemTimeSync_V20 — 系统时间同步
+
+- **URL**:`POST /api/zc/device/systemTimeSync_V20`
+- **C 接口**:`ZC_SystemTimeSync_V20`
+
+### 请求体(temTimeSync_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_DATETIME_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_DATETIME_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| year | int |  |
+| month | int |  |
+| day | int |  |
+| hour | int |  |
+| minute | int |  |
+| second | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='84-getSupplyLightCfg_V20'></a>
+
+## 84. getSupplyLightCfg_V20 — 查询补光灯参数
+
+- **URL**:`POST /api/zc/device/getSupplyLightCfg_V20`
+- **C 接口**:`ZC_GetSupplyLightCfg_V20`
+
+### 请求体(BinaryIntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | channel |
+
+### 返回
+
+code=0 成功;data 为 ZC_SUPPLYLIGHT_V20_S 结构体字段 JSON
+
+---
+
+<a id='85-setSupplyLightCfg_V20'></a>
+
+## 85. setSupplyLightCfg_V20 — 设置补光灯参数
+
+- **URL**:`POST /api/zc/device/setSupplyLightCfg_V20`
+- **C 接口**:`ZC_SetSupplyLightCfg_V20`
+
+### 请求体(SupplyLightCfg_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| data | ZC_SUPPLYLIGHT_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_SUPPLYLIGHT_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| mode | int |  |
+| brightness | int |  |
+| startHour | int |  |
+| startMinute | int |  |
+| startSecond | int |  |
+| stopHour | int |  |
+| stopMinute | int |  |
+| stopSecond | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='86-getRS485Cfg_V20'></a>
+
+## 86. getRS485Cfg_V20 — 查询RS485参数
+
+- **URL**:`POST /api/zc/device/getRS485Cfg_V20`
+- **C 接口**:`ZC_GetRS485Cfg_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_RS485_V20_S 结构体字段 JSON
+
+---
+
+<a id='87-setRS485Cfg_V20'></a>
+
+## 87. setRS485Cfg_V20 — 设置RS485参数
+
+- **URL**:`POST /api/zc/device/setRS485Cfg_V20`
+- **C 接口**:`ZC_SetRS485Cfg_V20`
+
+### 请求体(RS485Cfg_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_RS485_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_RS485_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| baudrate | int |  |
+| databits | int |  |
+| stopbits | int |  |
+| parity | int |  |
+| addrbits | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='88-getNTPCfg_V20'></a>
+
+## 88. getNTPCfg_V20 — 查询NTP参数
+
+- **URL**:`POST /api/zc/device/getNTPCfg_V20`
+- **C 接口**:`ZC_GetNTPCfg_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_NTP_V20_S 结构体字段 JSON
+
+---
+
+<a id='89-setNTPCfg_V20'></a>
+
+## 89. setNTPCfg_V20 — 设置NTP参数
+
+- **URL**:`POST /api/zc/device/setNTPCfg_V20`
+- **C 接口**:`ZC_SetNTPCfg_V20`
+
+### 请求体(NTPCfg_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_NTP_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_NTP_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| server | byte[] |  |
+| port | int |  |
+| period | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='90-getPTZCfg_V20'></a>
+
+## 90. getPTZCfg_V20 — 查询PTZ参数
+
+- **URL**:`POST /api/zc/device/getPTZCfg_V20`
+- **C 接口**:`ZC_GetPTZCfg_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_PTZ_V20_S 结构体字段 JSON
+
+---
+
+<a id='91-setPTZCfg_V20'></a>
+
+## 91. setPTZCfg_V20 — 设置PTZ参数
+
+- **URL**:`POST /api/zc/device/setPTZCfg_V20`
+- **C 接口**:`ZC_SetPTZCfg_V20`
+
+### 请求体(PTZCfg_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_PTZ_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_PTZ_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| type | int |  |
+| p2pMaxTimeInterval | int |  |
+| watchDuration | int |  |
+| runMode | int |  |
+| cruiseLine | int |  |
+| horFov | double |  |
+| verFov | double |  |
+| northDeclination | double |  |
+| horStartAngle | double |  |
+| horEndAngle | double |  |
+| verStartAngle | double |  |
+| verEndAngle | double |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='92-getSmartCaps'></a>
+
+## 92. getSmartCaps — 查询智能分析能力集
+
+- **URL**:`POST /api/zc/device/getSmartCaps`
+- **C 接口**:`ZC_GetSmartCaps`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_SMART_CAPS_S 结构体字段 JSON
+
+---
+
+<a id='93-getTempDetectPoint_V20'></a>
+
+## 93. getTempDetectPoint_V20 — 对应 C 接口 {@code ZC_GetTempDetectPoint_V20}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/getTempDetectPoint_V20`
+- **C 接口**:`ZC_GetTempDetectPoint_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_TEMP_DETECT_POINT_V20_S 结构体字段 JSON
+
+---
+
+<a id='94-setTempDetectPoint_V20'></a>
+
+## 94. setTempDetectPoint_V20 — 对应 C 接口 {@code ZC_SetTempDetectPoint_V20}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setTempDetectPoint_V20`
+- **C 接口**:`ZC_SetTempDetectPoint_V20`
+
+### 请求体(TempDetectPoint_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_TEMP_DETECT_POINT_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_TEMP_DETECT_POINT_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| name | byte[] |  |
+| displayName | int |  |
+| alarmHighTemp | double |  |
+| radiation | double |  |
+| x | int |  |
+| y | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='95-getTempDetectLine_V20'></a>
+
+## 95. getTempDetectLine_V20 — 对应 C 接口 {@code ZC_GetTempDetectLine_V20}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/getTempDetectLine_V20`
+- **C 接口**:`ZC_GetTempDetectLine_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_TEMP_DETECT_LINE_V20_S 结构体字段 JSON
+
+---
+
+<a id='96-setTempDetectLine_V20'></a>
+
+## 96. setTempDetectLine_V20 — 对应 C 接口 {@code ZC_SetTempDetectLine_V20}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setTempDetectLine_V20`
+- **C 接口**:`ZC_SetTempDetectLine_V20`
+
+### 请求体(TempDetectLine_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_TEMP_DETECT_LINE_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_TEMP_DETECT_LINE_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| name | byte[] |  |
+| displayName | int |  |
+| alarmHighTemp | double |  |
+| radiation | double |  |
+| x1 | int |  |
+| y1 | int |  |
+| x2 | int |  |
+| y2 | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='97-getTempDetectEllipse'></a>
+
+## 97. getTempDetectEllipse — 对应 C 接口 {@code ZC_GetTempDetectEllipse}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/getTempDetectEllipse`
+- **C 接口**:`ZC_GetTempDetectEllipse`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_TEMP_DETECT_ELLIPSE_S 结构体字段 JSON
+
+---
+
+<a id='98-setTempDetectEllipse'></a>
+
+## 98. setTempDetectEllipse — 对应 C 接口 {@code ZC_SetTempDetectEllipse}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setTempDetectEllipse`
+- **C 接口**:`ZC_SetTempDetectEllipse`
+
+### 请求体(TempDetectEllipseReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_TEMP_DETECT_ELLIPSE_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_TEMP_DETECT_ELLIPSE_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| name | byte[] |  |
+| displayName | int |  |
+| alarmHighTemp | double |  |
+| radiation | double |  |
+| x | int |  |
+| y | int |  |
+| a | int |  |
+| b | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='99-getTempDetectRect_V20'></a>
+
+## 99. getTempDetectRect_V20 — 查询区域测温矩形参数
+
+- **URL**:`POST /api/zc/device/getTempDetectRect_V20`
+- **C 接口**:`ZC_GetTempDetectRect_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_TEMP_DETECT_RECT_V20_S 结构体字段 JSON
+
+---
+
+<a id='100-setTempDetectRect_V20'></a>
+
+## 100. setTempDetectRect_V20 — 设置区域测温矩形参数
+
+- **URL**:`POST /api/zc/device/setTempDetectRect_V20`
+- **C 接口**:`ZC_SetTempDetectRect_V20`
+
+### 请求体(TempDetectRect_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_TEMP_DETECT_RECT_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_TEMP_DETECT_RECT_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| name | byte[] |  |
+| displayName | int |  |
+| alarmHighTemp | double |  |
+| radiation | double |  |
+| x1 | int |  |
+| y1 | int |  |
+| x2 | int |  |
+| y2 | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='101-getTempDetectPoly_V20'></a>
+
+## 101. getTempDetectPoly_V20 — 查询区域测温多边形参数
+
+- **URL**:`POST /api/zc/device/getTempDetectPoly_V20`
+- **C 接口**:`ZC_GetTempDetectPoly_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_TEMP_DETECT_POLY_V20_S 结构体字段 JSON
+
+---
+
+<a id='102-setTempDetectPoly_V20'></a>
+
+## 102. setTempDetectPoly_V20 — 设置区域测温多边形参数
+
+- **URL**:`POST /api/zc/device/setTempDetectPoly_V20`
+- **C 接口**:`ZC_SetTempDetectPoly_V20`
+
+### 请求体(TempDetectPoly_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_TEMP_DETECT_POLY_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_TEMP_DETECT_POLY_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| name | byte[] |  |
+| displayName | int |  |
+| alarmHighTemp | double |  |
+| radiation | double |  |
+| points | ZC_POINT_V20_S[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='103-getStaticShieldRect_V20'></a>
+
+## 103. getStaticShieldRect_V20 — 查询静态屏蔽矩形参数
+
+- **URL**:`POST /api/zc/device/getStaticShieldRect_V20`
+- **C 接口**:`ZC_GetStaticShieldRect_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_STATIC_SHIELD_RECT_V20_S 结构体字段 JSON
+
+---
+
+<a id='104-setStaticShieldRect_V20'></a>
+
+## 104. setStaticShieldRect_V20 — 设置静态屏蔽矩形参数
+
+- **URL**:`POST /api/zc/device/setStaticShieldRect_V20`
+- **C 接口**:`ZC_SetStaticShieldRect_V20`
+
+### 请求体(StaticShieldRect_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_STATIC_SHIELD_RECT_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_STATIC_SHIELD_RECT_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| x1 | int |  |
+| y1 | int |  |
+| x2 | int |  |
+| y2 | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='105-getStaticShieldPoly_V20'></a>
+
+## 105. getStaticShieldPoly_V20 — 查询静态屏蔽多边形参数
+
+- **URL**:`POST /api/zc/device/getStaticShieldPoly_V20`
+- **C 接口**:`ZC_GetStaticShieldPoly_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_STATIC_SHIELD_POLY_V20_S 结构体字段 JSON
+
+---
+
+<a id='106-setStaticShieldPoly_V20'></a>
+
+## 106. setStaticShieldPoly_V20 — 设置静态屏蔽多边形参数
+
+- **URL**:`POST /api/zc/device/setStaticShieldPoly_V20`
+- **C 接口**:`ZC_SetStaticShieldPoly_V20`
+
+### 请求体(StaticShieldPoly_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_STATIC_SHIELD_POLY_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_STATIC_SHIELD_POLY_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| points | ZC_POINT_V20_S[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='107-getStaticAnalRect_V20'></a>
+
+## 107. getStaticAnalRect_V20 — 查询定区分析矩形参数
+
+- **URL**:`POST /api/zc/device/getStaticAnalRect_V20`
+- **C 接口**:`ZC_GetStaticAnalRect_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_STATIC_ANAL_RECT_V20_S 结构体字段 JSON
+
+---
+
+<a id='108-setStaticAnalRect_V20'></a>
+
+## 108. setStaticAnalRect_V20 — 设置定区分析矩形参数
+
+- **URL**:`POST /api/zc/device/setStaticAnalRect_V20`
+- **C 接口**:`ZC_SetStaticAnalRect_V20`
+
+### 请求体(StaticAnalRect_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_STATIC_ANAL_RECT_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_STATIC_ANAL_RECT_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| x1 | int |  |
+| y1 | int |  |
+| x2 | int |  |
+| y2 | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='109-getStaticAnalPoly_V20'></a>
+
+## 109. getStaticAnalPoly_V20 — 查询定区分析多边形参数
+
+- **URL**:`POST /api/zc/device/getStaticAnalPoly_V20`
+- **C 接口**:`ZC_GetStaticAnalPoly_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_STATIC_ANAL_POLY_V20_S 结构体字段 JSON
+
+---
+
+<a id='110-setStaticAnalPoly_V20'></a>
+
+## 110. setStaticAnalPoly_V20 — 设置定区分析多边形参数
+
+- **URL**:`POST /api/zc/device/setStaticAnalPoly_V20`
+- **C 接口**:`ZC_SetStaticAnalPoly_V20`
+
+### 请求体(StaticAnalPoly_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_STATIC_ANAL_POLY_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_STATIC_ANAL_POLY_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| points | ZC_POINT_V20_S[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='111-getDynaShieldRect_V20'></a>
+
+## 111. getDynaShieldRect_V20 — 查询动态屏蔽矩形参数
+
+- **URL**:`POST /api/zc/device/getDynaShieldRect_V20`
+- **C 接口**:`ZC_GetDynaShieldRect_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_DYNA_SHIELD_RECT_V20_S 结构体字段 JSON
+
+---
+
+<a id='112-setDynaShieldRect_V20'></a>
+
+## 112. setDynaShieldRect_V20 — 设置动态屏蔽矩形参数
+
+- **URL**:`POST /api/zc/device/setDynaShieldRect_V20`
+- **C 接口**:`ZC_SetDynaShieldRect_V20`
+
+### 请求体(DynaShieldRect_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_DYNA_SHIELD_RECT_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_DYNA_SHIELD_RECT_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| x1 | int |  |
+| y1 | int |  |
+| x2 | int |  |
+| y2 | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='113-getDynaShieldPoly_V20'></a>
+
+## 113. getDynaShieldPoly_V20 — 查询动态屏蔽多边形参数
+
+- **URL**:`POST /api/zc/device/getDynaShieldPoly_V20`
+- **C 接口**:`ZC_GetDynaShieldPoly_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_DYNA_SHIELD_POLY_V20_S 结构体字段 JSON
+
+---
+
+<a id='114-setDynaShieldPoly_V20'></a>
+
+## 114. setDynaShieldPoly_V20 — 设置动态屏蔽多边形参数
+
+- **URL**:`POST /api/zc/device/setDynaShieldPoly_V20`
+- **C 接口**:`ZC_SetDynaShieldPoly_V20`
+
+### 请求体(DynaShieldPoly_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_DYNA_SHIELD_POLY_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_DYNA_SHIELD_POLY_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| points | ZC_POINT_V20_S[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='115-getBreakinLine_V20'></a>
+
+## 115. getBreakinLine_V20 — 查询周界入侵线参数
+
+- **URL**:`POST /api/zc/device/getBreakinLine_V20`
+- **C 接口**:`ZC_GetBreakinLine_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_BREAKIN_LINE_V20_S 结构体字段 JSON
+
+---
+
+<a id='116-setBreakinLine_V20'></a>
+
+## 116. setBreakinLine_V20 — 设置周界入侵线参数
+
+- **URL**:`POST /api/zc/device/setBreakinLine_V20`
+- **C 接口**:`ZC_SetBreakinLine_V20`
+
+### 请求体(BreakinLine_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_BREAKIN_LINE_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_BREAKIN_LINE_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| x1 | int |  |
+| y1 | int |  |
+| x2 | int |  |
+| y2 | int |  |
+| ioLow | int |  |
+| ioHigh | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='117-getBreakinRect_V20'></a>
+
+## 117. getBreakinRect_V20 — 查询周界入侵矩形参数
+
+- **URL**:`POST /api/zc/device/getBreakinRect_V20`
+- **C 接口**:`ZC_GetBreakinRect_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_BREAKIN_RECT_V20_S 结构体字段 JSON
+
+---
+
+<a id='118-setBreakinRect_V20'></a>
+
+## 118. setBreakinRect_V20 — 设置周界入侵矩形参数
+
+- **URL**:`POST /api/zc/device/setBreakinRect_V20`
+- **C 接口**:`ZC_SetBreakinRect_V20`
+
+### 请求体(BreakinRect_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_BREAKIN_RECT_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_BREAKIN_RECT_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| x1 | int |  |
+| y1 | int |  |
+| x2 | int |  |
+| y2 | int |  |
+| ioLow | int |  |
+| ioHigh | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='119-getBreakinPolygon_V20'></a>
+
+## 119. getBreakinPolygon_V20 — 查询周界入侵多边形参数
+
+- **URL**:`POST /api/zc/device/getBreakinPolygon_V20`
+- **C 接口**:`ZC_GetBreakinPolygon_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_BREAKIN_POLYGON_V20_S 结构体字段 JSON
+
+---
+
+<a id='120-setBreakinPolygon_V20'></a>
+
+## 120. setBreakinPolygon_V20 — 设置周界入侵多边形参数
+
+- **URL**:`POST /api/zc/device/setBreakinPolygon_V20`
+- **C 接口**:`ZC_SetBreakinPolygon_V20`
+
+### 请求体(BreakinPolygon_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_BREAKIN_POLYGON_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_BREAKIN_POLYGON_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| ioLow | int |  |
+| ioHigh | int |  |
+| points | ZC_POINT_V20_S[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='121-getBreakinPolyline_V20'></a>
+
+## 121. getBreakinPolyline_V20 — 查询周界入侵折线参数
+
+- **URL**:`POST /api/zc/device/getBreakinPolyline_V20`
+- **C 接口**:`ZC_GetBreakinPolyline_V20`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_BREAKIN_POLYLINE_V20_S 结构体字段 JSON
+
+---
+
+<a id='122-setBreakinPolyline_V20'></a>
+
+## 122. setBreakinPolyline_V20 — 设置周界入侵折线参数
+
+- **URL**:`POST /api/zc/device/setBreakinPolyline_V20`
+- **C 接口**:`ZC_SetBreakinPolyline_V20`
+
+### 请求体(BreakinPolyline_V20Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_BREAKIN_POLYLINE_V20_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_BREAKIN_POLYLINE_V20_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| enable | int |  |
+| preset | int |  |
+| index | int |  |
+| ioLow | int |  |
+| ioHigh | int |  |
+| points | ZC_POINT_V20_S[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='123-setPesudoColor'></a>
+
+## 123. setPesudoColor — 设置伪彩(仅热成像有效)
+
+- **URL**:`POST /api/zc/device/setPesudoColor`
+- **C 接口**:`ZC_SetPesudoColor`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | color |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='124-getConfig'></a>
+
+## 124. getConfig — 获取参数
+
+- **URL**:`POST /api/zc/device/getConfig`
+- **C 接口**:`ZC_GetConfig`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_CMD_GET_CONFIG_S 结构体字段 JSON
+
+---
+
+<a id='125-setConfig'></a>
+
+## 125. setConfig — 设置参数
+
+- **URL**:`POST /api/zc/device/setConfig`
+- **C 接口**:`ZC_SetConfig`
+
+### 请求体(ConfigReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_CMD_SET_CONFIG_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_CMD_SET_CONFIG_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| dwCommand | int |  |
+| dwChannel | int |  |
+| dwInBufferSize | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='126-getSysCfg'></a>
+
+## 126. getSysCfg — 获取系统参数
+
+- **URL**:`POST /api/zc/device/getSysCfg`
+- **C 接口**:`ZC_GetSysCfg`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_SYSTEM_CFG_S 结构体字段 JSON
+
+---
+
+<a id='127-setSysCfg'></a>
+
+## 127. setSysCfg — 设置系统参数
+
+- **URL**:`POST /api/zc/device/setSysCfg`
+- **C 接口**:`ZC_SetSysCfg`
+
+### 请求体(SysCfgReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_SYSTEM_CFG_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_SYSTEM_CFG_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| ip | byte[] | ip地址 |
+| subnetMask | byte[] | 子网掩码 |
+| gateway | byte[] | 网关 |
+| srvCenterIp | byte[] | 中心服务器IP |
+| srvCenterPort | int | 中心服务器IP |
+| cmdPort | int | 中心服务器端口 |
+| alarmPort | int | 默认8000 |
+| deviceId | int | 设备编号 |
+| deviceName | byte[] | 设备名称 |
+| longitude | float | 经度 |
+| latitude | float | 纬度 |
+| runMode | int | 运行模式 1/0 |
+| cruiseLine | int | 巡航线 |
+| stayDuration | int | 巡航点停留的分析时长 |
+| ptzSemiCircleDuration | int | 云台半圈耗时 |
+| findFire | int | 热源开关 1/0 |
+| fireMeasureTemp | int | 热源测温 1/0 |
+| fireRadius | int | 热源半径 |
+| fireMinThreshold | int | 热源最小阀值 |
+| fireMaxThreshold | int | 热源最大阀值 |
+| fireMinArea | int | 热源最小面积 |
+| fireMaxArea | int | 热源最大面积 |
+| fireTrace | int | 热源跟踪开关 1/0 |
+| camZoomCapture | int | 联动摄像机推倍抓拍 |
+| shakeRadius | int | 抖动半径(判断动态屏蔽区域内报警源抖动的半径范围) |
+| stillDuration | int | 静止时长(判断动态屏蔽区域内报警源静止的时间长度) |
+| findMove | int | 闯入开关 1/0 |
+| findDxm | int | 低小慢开关 1/0 |
+| dxmLength | int | 低小慢尾长 |
+| dxmRadius | int | 低小慢半径 |
+| radiation | float | 辐射值 |
+| emissivity | float | 发射率 |
+| environmentTemp | float | 环温 |
+| showMaxTemp | int | 显示最高温 |
+| showMinTemp | int | 显示最低温 |
+| showAvgTemp | int | 显示平均温 |
+| showRunMode | int | 显示运行模式 |
+| showRunStatus | int | 显示运行状态 |
+| xStartPix | int | x起始位置 |
+| xEndPix | int | x结束位置 |
+| yStartPix | int | y起始位置 |
+| yEndPix | int | y结束位置 |
+| horStartAngle | float | 水平起始角度 |
+| horEndAngle | float | 水平结束角度 |
+| verStartAngle | float | 垂直起始角度 |
+| verEndAngle | float | 垂直结束角度 |
+| horFov | float | 水平视场角 | 
+| verFov | float | 垂直视场角 |
+| horPixs | int | 水平像素 |
+| verPixs | int | 垂直像素 |
+| grayOffset | int | 原始数据偏移量 |
+| majorStreamReso | int | 主码分辨率 0-640x480;1-1280x720;2-1920x1080;3-2592x1944; |
+| minorStreamReso | int | 子码分辨率 |
+| streamColor | int | streamColor |
+| globalMaxTempThreshold | float |  |
+| globalMinTempThreshold | float |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='128-setRunModeCfg'></a>
+
+## 128. setRunModeCfg — 切换模式
+
+- **URL**:`POST /api/zc/device/setRunModeCfg`
+- **C 接口**:`ZC_SetRunModeCfg`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | RunMode |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='129-setEnvironmentTemperature'></a>
+
+## 129. setEnvironmentTemperature — 设置环境温度值
+
+- **URL**:`POST /api/zc/device/setEnvironmentTemperature`
+- **C 接口**:`ZC_SetEnvironmentTemperature`
+
+### 请求体(FloatReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| f1 | Float | 否 |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='130-pTZControlEx'></a>
+
+## 130. pTZControlEx — 对应 C 接口 {@code ZC_PTZControlEx}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/pTZControlEx`
+- **C 接口**:`ZC_PTZControlEx`
+
+### 请求体(Int3Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | ptzCtrl |
+| i2 | Integer | 否 | control |
+| i3 | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='131-getAllPreset'></a>
+
+## 131. getAllPreset — 查询所有预置位的状态
+
+- **URL**:`POST /api/zc/device/getAllPreset`
+- **C 接口**:`ZC_GetAllPreset`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_ALL_PRESET_S 结构体字段 JSON
+
+---
+
+<a id='132-setPtzPreset'></a>
+
+## 132. setPtzPreset — 设置云台预置位
+
+- **URL**:`POST /api/zc/device/setPtzPreset`
+- **C 接口**:`ZC_SetPtzPreset`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='133-gotoPtzPreset'></a>
+
+## 133. gotoPtzPreset — 调用云台预置位
+
+- **URL**:`POST /api/zc/device/gotoPtzPreset`
+- **C 接口**:`ZC_GotoPtzPreset`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='134-delPtzPreset'></a>
+
+## 134. delPtzPreset — 删除云台预置位
+
+- **URL**:`POST /api/zc/device/delPtzPreset`
+- **C 接口**:`ZC_DelPtzPreset`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='135-getPresetInfo'></a>
+
+## 135. getPresetInfo — 获取预置位信息
+
+- **URL**:`POST /api/zc/device/getPresetInfo`
+- **C 接口**:`ZC_GetPresetInfo`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_PRESET_INFO_S 结构体字段 JSON
+
+---
+
+<a id='136-setPresetInfo'></a>
+
+## 136. setPresetInfo — 设置预置位信息
+
+- **URL**:`POST /api/zc/device/setPresetInfo`
+- **C 接口**:`ZC_SetPresetInfo`
+
+### 请求体(PresetInfoReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_PRESET_INFO_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_PRESET_INFO_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| no | int |  |
+| name | byte[] |  |
+| time | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='137-getPtzCruiseCfg'></a>
+
+## 137. getPtzCruiseCfg — 查询巡航线
+
+- **URL**:`POST /api/zc/device/getPtzCruiseCfg`
+- **C 接口**:`ZC_GetPtzCruiseCfg`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_CRUISE_CFG_S 结构体字段 JSON
+
+---
+
+<a id='138-setPtzCruise'></a>
+
+## 138. setPtzCruise — 设置巡航线
+
+- **URL**:`POST /api/zc/device/setPtzCruise`
+- **C 接口**:`ZC_SetPtzCruise`
+
+### 请求体(PtzCruiseReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_CRUISE_CFG_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_CRUISE_CFG_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| cruiseNo | int |  |
+| preset | byte[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='139-gotoPtzCruise'></a>
+
+## 139. gotoPtzCruise — 调用巡航线
+
+- **URL**:`POST /api/zc/device/gotoPtzCruise`
+- **C 接口**:`ZC_GotoPtzCruise`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | CruiseLineNo |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='140-clrPtzCruise'></a>
+
+## 140. clrPtzCruise — 清除巡航线
+
+- **URL**:`POST /api/zc/device/clrPtzCruise`
+- **C 接口**:`ZC_ClrPtzCruise`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | CruiseLineNo |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='141-showClickTemp'></a>
+
+## 141. showClickTemp — 显示point位置的温度
+
+- **URL**:`POST /api/zc/device/showClickTemp`
+- **C 接口**:`ZC_ShowClickTemp`
+
+### 请求体(wClickTempReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_POINT_S | 是 | 结构体对象(字段见下表) |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='142-hideClickTemp'></a>
+
+## 142. hideClickTemp — 隐藏point位置的温度
+
+- **URL**:`POST /api/zc/device/hideClickTemp`
+- **C 接口**:`ZC_HideClickTemp`
+
+### 请求体(IpReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='143-captureLastAlarm'></a>
+
+## 143. captureLastAlarm — 获取最后一张报警图
+
+- **URL**:`POST /api/zc/device/captureLastAlarm`
+- **C 接口**:`ZC_CaptureLastAlarm`
+
+### 请求体(StrReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| s1 | String | 否 |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='144-captureHDFrameNoOsd'></a>
+
+## 144. captureHDFrameNoOsd — 获取一帧无叠加的高清图像数据
+
+- **URL**:`POST /api/zc/device/captureHDFrameNoOsd`
+- **C 接口**:`ZC_CaptureHDFrameNoOsd`
+
+### 请求体(tureHDFrameNoOsdReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_FRAME_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_FRAME_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| width | int |  |
+| height | int |  |
+| length | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='145-uploadVoiceFile'></a>
+
+## 145. uploadVoiceFile — 上传语音文件
+
+- **URL**:`POST /api/zc/device/uploadVoiceFile`
+- **C 接口**:`ZC_UploadVoiceFile`
+
+### 请求体(oadVoiceFileReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_VOICE_INFO_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_VOICE_INFO_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| byType | byte |  |
+| bySampleRate | byte |  |
+| byChannels | byte |  |
+| byBitsPerSample | byte |  |
+| byTime | float |  |
+| byLen | int |  |
+| filepath | byte[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='146-getHttpDestInfo'></a>
+
+## 146. getHttpDestInfo — 获取HTTP报警接收目的地址信息
+
+- **URL**:`POST /api/zc/device/getHttpDestInfo`
+- **C 接口**:`ZC_GetHttpDestInfo`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_HTTP_DEST_INFO_S 结构体字段 JSON
+
+---
+
+<a id='147-setHttpDestInfo'></a>
+
+## 147. setHttpDestInfo — 设置HTTP报警接收目的地址信息
+
+- **URL**:`POST /api/zc/device/setHttpDestInfo`
+- **C 接口**:`ZC_SetHttpDestInfo`
+
+### 请求体(HttpDestInfoReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_HTTP_DEST_INFO_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_HTTP_DEST_INFO_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| openHttpPushAlarm | int |  |
+| foreverToken | int |  |
+| appid | byte[] |  |
+| appkey | byte[] |  |
+| httpDestPath | byte[] |  |
+| httpUserData | byte[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='148-getIRData'></a>
+
+## 148. getIRData — 获取红外数据
+
+- **URL**:`POST /api/zc/device/getIRData`
+- **C 接口**:`ZC_GetIRData`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_FRAME_S 结构体字段 JSON
+
+---
+
+<a id='149-getIRBadPixFrm'></a>
+
+## 149. getIRBadPixFrm — 获取红外坏点数据帧
+
+- **URL**:`POST /api/zc/device/getIRBadPixFrm`
+- **C 接口**:`ZC_GetIRBadPixFrm`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_FRAME_S 结构体字段 JSON
+
+---
+
+<a id='150-setIRBadPixFrm'></a>
+
+## 150. setIRBadPixFrm — 修复红外坏点数据帧
+
+- **URL**:`POST /api/zc/device/setIRBadPixFrm`
+- **C 接口**:`ZC_SetIRBadPixFrm`
+
+### 请求体(IRBadPixFrmReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_FRAME_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_FRAME_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| width | int |  |
+| height | int |  |
+| length | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='151-getMappingTemInfo'></a>
+
+## 151. getMappingTemInfo — 对应 C 接口 {@code ZC_GetMappingTemInfo}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/getMappingTemInfo`
+- **C 接口**:`ZC_GetMappingTemInfo`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_MAPPING_TEM_INFO_S 结构体字段 JSON
+
+---
+
+<a id='152-setMappingTemInfo'></a>
+
+## 152. setMappingTemInfo — 对应 C 接口 {@code ZC_SetMappingTemInfo}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setMappingTemInfo`
+- **C 接口**:`ZC_SetMappingTemInfo`
+
+### 请求体(MappingTemInfoReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_MAPPING_TEM_INFO_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_MAPPING_TEM_INFO_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| mappingLevel | ZC_MAPPING_TEM_LEVEL_S[] |  |
+| sampleStudyTem | float |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='153-setInvalidRect'></a>
+
+## 153. setInvalidRect — 设置灼伤区
+
+- **URL**:`POST /api/zc/device/setInvalidRect`
+- **C 接口**:`ZC_SetInvalidRect`
+
+### 请求体(InvalidRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| data | ZC_RECT_S | 是 | 结构体对象(字段见下表) |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='154-clrInvalidRect'></a>
+
+## 154. clrInvalidRect — 清除灼伤区
+
+- **URL**:`POST /api/zc/device/clrInvalidRect`
+- **C 接口**:`ZC_ClrInvalidRect`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='155-getPresetStaticAnalysisRect'></a>
+
+## 155. getPresetStaticAnalysisRect — 定区-矩形
+
+- **URL**:`POST /api/zc/device/getPresetStaticAnalysisRect`
+- **C 接口**:`ZC_GetPresetStaticAnalysisRect`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_RECT_S 结构体字段 JSON
+
+---
+
+<a id='156-setPresetStaticAnalysisRect'></a>
+
+## 156. setPresetStaticAnalysisRect — 对应 C 接口 {@code ZC_SetPresetStaticAnalysisRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetStaticAnalysisRect`
+- **C 接口**:`ZC_SetPresetStaticAnalysisRect`
+
+### 请求体(PresetStaticAnalysisRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_RECT_S | 是 | 结构体对象(字段见下表) |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='157-clrPresetStaticAnalysisRect'></a>
+
+## 157. clrPresetStaticAnalysisRect — 对应 C 接口 {@code ZC_ClrPresetStaticAnalysisRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetStaticAnalysisRect`
+- **C 接口**:`ZC_ClrPresetStaticAnalysisRect`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='158-getPresetStaticAnalysisPoly'></a>
+
+## 158. getPresetStaticAnalysisPoly — 定区-多边形
+
+- **URL**:`POST /api/zc/device/getPresetStaticAnalysisPoly`
+- **C 接口**:`ZC_GetPresetStaticAnalysisPoly`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_POLY_S 结构体字段 JSON
+
+---
+
+<a id='159-setPresetStaticAnalysisPoly'></a>
+
+## 159. setPresetStaticAnalysisPoly — 对应 C 接口 {@code ZC_SetPresetStaticAnalysisPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetStaticAnalysisPoly`
+- **C 接口**:`ZC_SetPresetStaticAnalysisPoly`
+
+### 请求体(PresetStaticAnalysisPolyReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_POLY_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_POLY_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| p | ZC_POINT_S[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='160-clrPresetStaticAnalysisPoly'></a>
+
+## 160. clrPresetStaticAnalysisPoly — 对应 C 接口 {@code ZC_ClrPresetStaticAnalysisPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetStaticAnalysisPoly`
+- **C 接口**:`ZC_ClrPresetStaticAnalysisPoly`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='161-getPresetDynamicShieldRect'></a>
+
+## 161. getPresetDynamicShieldRect — 动屏-矩形
+
+- **URL**:`POST /api/zc/device/getPresetDynamicShieldRect`
+- **C 接口**:`ZC_GetPresetDynamicShieldRect`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_RECT_S 结构体字段 JSON
+
+---
+
+<a id='162-setPresetDynamicShieldRect'></a>
+
+## 162. setPresetDynamicShieldRect — 对应 C 接口 {@code ZC_SetPresetDynamicShieldRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetDynamicShieldRect`
+- **C 接口**:`ZC_SetPresetDynamicShieldRect`
+
+### 请求体(PresetDynamicShieldRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_RECT_S | 是 | 结构体对象(字段见下表) |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='163-clrPresetDynamicShieldRect'></a>
+
+## 163. clrPresetDynamicShieldRect — 对应 C 接口 {@code ZC_ClrPresetDynamicShieldRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetDynamicShieldRect`
+- **C 接口**:`ZC_ClrPresetDynamicShieldRect`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='164-getPresetDynamicShieldPoly'></a>
+
+## 164. getPresetDynamicShieldPoly — 动屏-多边形
+
+- **URL**:`POST /api/zc/device/getPresetDynamicShieldPoly`
+- **C 接口**:`ZC_GetPresetDynamicShieldPoly`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_POLY_S 结构体字段 JSON
+
+---
+
+<a id='165-setPresetDynamicShieldPoly'></a>
+
+## 165. setPresetDynamicShieldPoly — 对应 C 接口 {@code ZC_SetPresetDynamicShieldPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetDynamicShieldPoly`
+- **C 接口**:`ZC_SetPresetDynamicShieldPoly`
+
+### 请求体(PresetDynamicShieldPolyReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_POLY_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_POLY_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| p | ZC_POINT_S[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='166-clrPresetDynamicShieldPoly'></a>
+
+## 166. clrPresetDynamicShieldPoly — 对应 C 接口 {@code ZC_ClrPresetDynamicShieldPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetDynamicShieldPoly`
+- **C 接口**:`ZC_ClrPresetDynamicShieldPoly`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='167-getPresetMoveLine'></a>
+
+## 167. getPresetMoveLine — 闯入-线
+
+- **URL**:`POST /api/zc/device/getPresetMoveLine`
+- **C 接口**:`ZC_GetPresetMoveLine`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_MOVE_LINE_S 结构体字段 JSON
+
+---
+
+<a id='168-setPresetMoveLine'></a>
+
+## 168. setPresetMoveLine — 对应 C 接口 {@code ZC_SetPresetMoveLine}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetMoveLine`
+- **C 接口**:`ZC_SetPresetMoveLine`
+
+### 请求体(PresetMoveLineReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_MOVE_LINE_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_MOVE_LINE_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| lowIO | int |  |
+| highIO | int |  |
+| line | ZC_LINE_S |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='169-clrPresetMoveLine'></a>
+
+## 169. clrPresetMoveLine — 对应 C 接口 {@code ZC_ClrPresetMoveLine}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetMoveLine`
+- **C 接口**:`ZC_ClrPresetMoveLine`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='170-getPresetMoveRect'></a>
+
+## 170. getPresetMoveRect — 闯入-矩形
+
+- **URL**:`POST /api/zc/device/getPresetMoveRect`
+- **C 接口**:`ZC_GetPresetMoveRect`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_MOVE_RECT_S 结构体字段 JSON
+
+---
+
+<a id='171-setPresetMoveRect'></a>
+
+## 171. setPresetMoveRect — 对应 C 接口 {@code ZC_SetPresetMoveRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetMoveRect`
+- **C 接口**:`ZC_SetPresetMoveRect`
+
+### 请求体(PresetMoveRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_MOVE_RECT_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_MOVE_RECT_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| lowIO | int |  |
+| highIO | int |  |
+| rect | ZC_RECT_S |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='172-clrPresetMoveRect'></a>
+
+## 172. clrPresetMoveRect — 对应 C 接口 {@code ZC_ClrPresetMoveRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetMoveRect`
+- **C 接口**:`ZC_ClrPresetMoveRect`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='173-getPresetMovePoly'></a>
+
+## 173. getPresetMovePoly — 闯入-多边形
+
+- **URL**:`POST /api/zc/device/getPresetMovePoly`
+- **C 接口**:`ZC_GetPresetMovePoly`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_MOVE_POLY_S 结构体字段 JSON
+
+---
+
+<a id='174-setPresetMovePoly'></a>
+
+## 174. setPresetMovePoly — 对应 C 接口 {@code ZC_SetPresetMovePoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetMovePoly`
+- **C 接口**:`ZC_SetPresetMovePoly`
+
+### 请求体(PresetMovePolyReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_MOVE_POLY_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_MOVE_POLY_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| lowIO | int |  |
+| highIO | int |  |
+| poly | ZC_POLY_S |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='175-clrPresetMovePoly'></a>
+
+## 175. clrPresetMovePoly — 对应 C 接口 {@code ZC_ClrPresetMovePoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetMovePoly`
+- **C 接口**:`ZC_ClrPresetMovePoly`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='176-getPresetMoveBorder'></a>
+
+## 176. getPresetMoveBorder — 闯入-多边形边界
+
+- **URL**:`POST /api/zc/device/getPresetMoveBorder`
+- **C 接口**:`ZC_GetPresetMoveBorder`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_MOVE_POLY_S 结构体字段 JSON
+
+---
+
+<a id='177-setPresetMoveBorder'></a>
+
+## 177. setPresetMoveBorder — 对应 C 接口 {@code ZC_SetPresetMoveBorder}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetMoveBorder`
+- **C 接口**:`ZC_SetPresetMoveBorder`
+
+### 请求体(PresetMoveBorderReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_MOVE_POLY_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_MOVE_POLY_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| lowIO | int |  |
+| highIO | int |  |
+| poly | ZC_POLY_S |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='178-clrPresetMoveBorder'></a>
+
+## 178. clrPresetMoveBorder — 对应 C 接口 {@code ZC_ClrPresetMoveBorder}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetMoveBorder`
+- **C 接口**:`ZC_ClrPresetMoveBorder`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='179-getPresetTempPoint'></a>
+
+## 179. getPresetTempPoint — 测温点
+
+- **URL**:`POST /api/zc/device/getPresetTempPoint`
+- **C 接口**:`ZC_GetPresetTempPoint`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_TEMP_POINT_S 结构体字段 JSON
+
+---
+
+<a id='180-setPresetTempPoint'></a>
+
+## 180. setPresetTempPoint — 对应 C 接口 {@code ZC_SetPresetTempPoint}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetTempPoint`
+- **C 接口**:`ZC_SetPresetTempPoint`
+
+### 请求体(PresetTempPointReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_TEMP_POINT_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_TEMP_POINT_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| radiation | float |  |
+| alarm_temp | float |  |
+| point | ZC_POINT_S |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='181-clrPresetTempPoint'></a>
+
+## 181. clrPresetTempPoint — 对应 C 接口 {@code ZC_ClrPresetTempPoint}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetTempPoint`
+- **C 接口**:`ZC_ClrPresetTempPoint`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='182-getPresetPotTempLine'></a>
+
+## 182. getPresetPotTempLine — 测温线
+
+- **URL**:`POST /api/zc/device/getPresetPotTempLine`
+- **C 接口**:`ZC_GetPresetPotTempLine`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_POT_TEMP_LINE_S 结构体字段 JSON
+
+---
+
+<a id='183-setPresetPotTempLine'></a>
+
+## 183. setPresetPotTempLine — 对应 C 接口 {@code ZC_SetPresetPotTempLine}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetPotTempLine`
+- **C 接口**:`ZC_SetPresetPotTempLine`
+
+### 请求体(PresetPotTempLineReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_POT_TEMP_LINE_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_POT_TEMP_LINE_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| radiation | float |  |
+| alarm_temp | float |  |
+| line | ZC_LINE_S |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='184-clrPresetPotTempLine'></a>
+
+## 184. clrPresetPotTempLine — 对应 C 接口 {@code ZC_ClrPresetPotTempLine}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetPotTempLine`
+- **C 接口**:`ZC_ClrPresetPotTempLine`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='185-getPresetOilLevelRect'></a>
+
+## 185. getPresetOilLevelRect — 油位监测
+
+- **URL**:`POST /api/zc/device/getPresetOilLevelRect`
+- **C 接口**:`ZC_GetPresetOilLevelRect`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_OIL_LEVEL_RECT_S 结构体字段 JSON
+
+---
+
+<a id='186-setPresetOilLevelRect'></a>
+
+## 186. setPresetOilLevelRect — 对应 C 接口 {@code ZC_SetPresetOilLevelRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetOilLevelRect`
+- **C 接口**:`ZC_SetPresetOilLevelRect`
+
+### 请求体(PresetOilLevelRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_OIL_LEVEL_RECT_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_OIL_LEVEL_RECT_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| rect | ZC_RECT_S |  |
+| safe_percent | float |  |
+| name | byte[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='187-clrPresetOilLevelRect'></a>
+
+## 187. clrPresetOilLevelRect — 对应 C 接口 {@code ZC_ClrPresetOilLevelRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetOilLevelRect`
+- **C 接口**:`ZC_ClrPresetOilLevelRect`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='188-getPresetOilLevelPoly'></a>
+
+## 188. getPresetOilLevelPoly — 对应 C 接口 {@code ZC_GetPresetOilLevelPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/getPresetOilLevelPoly`
+- **C 接口**:`ZC_GetPresetOilLevelPoly`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_OIL_LEVEL_POLY_S 结构体字段 JSON
+
+---
+
+<a id='189-setPresetOilLevelPoly'></a>
+
+## 189. setPresetOilLevelPoly — 对应 C 接口 {@code ZC_SetPresetOilLevelPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetOilLevelPoly`
+- **C 接口**:`ZC_SetPresetOilLevelPoly`
+
+### 请求体(PresetOilLevelPolyReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_OIL_LEVEL_POLY_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_OIL_LEVEL_POLY_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| poly | ZC_POLY_S |  |
+| safe_percent | float |  |
+| name | byte[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='190-clrPresetOilLevelPoly'></a>
+
+## 190. clrPresetOilLevelPoly — 对应 C 接口 {@code ZC_ClrPresetOilLevelPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetOilLevelPoly`
+- **C 接口**:`ZC_ClrPresetOilLevelPoly`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='191-getPresetBlackBodyRect'></a>
+
+## 191. getPresetBlackBodyRect — 黑体区域接口
+
+- **URL**:`POST /api/zc/device/getPresetBlackBodyRect`
+- **C 接口**:`ZC_GetPresetBlackBodyRect`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | preset |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_RECT_S 结构体字段 JSON
+
+---
+
+<a id='192-setPresetBlackBodyRect'></a>
+
+## 192. setPresetBlackBodyRect — 对应 C 接口 {@code ZC_SetPresetBlackBodyRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetBlackBodyRect`
+- **C 接口**:`ZC_SetPresetBlackBodyRect`
+
+### 请求体(PresetBlackBodyRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_RECT_S | 是 | 结构体对象(字段见下表) |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='193-getPresetTargetStayRect'></a>
+
+## 193. getPresetTargetStayRect — 目标逗留,此功能只在1号预置位下有效
+
+- **URL**:`POST /api/zc/device/getPresetTargetStayRect`
+- **C 接口**:`ZC_GetPresetTargetStayRect`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_TARGET_STAY_RECT_S 结构体字段 JSON
+
+---
+
+<a id='194-setPresetTargetStayRect'></a>
+
+## 194. setPresetTargetStayRect — 对应 C 接口 {@code ZC_SetPresetTargetStayRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setPresetTargetStayRect`
+- **C 接口**:`ZC_SetPresetTargetStayRect`
+
+### 请求体(PresetTargetStayRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_TARGET_STAY_RECT_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_TARGET_STAY_RECT_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | int |  |
+| stay_time | int |  |
+| min_io | int |  |
+| max_io | int |  |
+| rect | ZC_RECT_S |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='195-clrPresetTargetStayRect'></a>
+
+## 195. clrPresetTargetStayRect — 对应 C 接口 {@code ZC_ClrPresetTargetStayRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrPresetTargetStayRect`
+- **C 接口**:`ZC_ClrPresetTargetStayRect`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='196-getAngleStaticAnalysisRect'></a>
+
+## 196. getAngleStaticAnalysisRect — 定区-矩形
+
+- **URL**:`POST /api/zc/device/getAngleStaticAnalysisRect`
+- **C 接口**:`ZC_GetAngleStaticAnalysisRect`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_RECT_S 结构体字段 JSON
+
+---
+
+<a id='197-setAngleStaticAnalysisRect'></a>
+
+## 197. setAngleStaticAnalysisRect — 对应 C 接口 {@code ZC_SetAngleStaticAnalysisRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setAngleStaticAnalysisRect`
+- **C 接口**:`ZC_SetAngleStaticAnalysisRect`
+
+### 请求体(AngleStaticAnalysisRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_RECT_S | 是 | 结构体对象(字段见下表) |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='198-clrAngleStaticAnalysisRect'></a>
+
+## 198. clrAngleStaticAnalysisRect — 对应 C 接口 {@code ZC_ClrAngleStaticAnalysisRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrAngleStaticAnalysisRect`
+- **C 接口**:`ZC_ClrAngleStaticAnalysisRect`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='199-getAngleStaticAnalysisPoly'></a>
+
+## 199. getAngleStaticAnalysisPoly — 定区-多边形
+
+- **URL**:`POST /api/zc/device/getAngleStaticAnalysisPoly`
+- **C 接口**:`ZC_GetAngleStaticAnalysisPoly`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_POLY_S 结构体字段 JSON
+
+---
+
+<a id='200-setAngleStaticAnalysisPoly'></a>
+
+## 200. setAngleStaticAnalysisPoly — 对应 C 接口 {@code ZC_SetAngleStaticAnalysisPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setAngleStaticAnalysisPoly`
+- **C 接口**:`ZC_SetAngleStaticAnalysisPoly`
+
+### 请求体(AngleStaticAnalysisPolyReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_POLY_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_POLY_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| p | ZC_POINT_S[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='201-clrAngleStaticAnalysisPoly'></a>
+
+## 201. clrAngleStaticAnalysisPoly — 对应 C 接口 {@code ZC_ClrAngleStaticAnalysisPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrAngleStaticAnalysisPoly`
+- **C 接口**:`ZC_ClrAngleStaticAnalysisPoly`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='202-getAngleStaticShieldRect'></a>
+
+## 202. getAngleStaticShieldRect — 静屏-矩形
+
+- **URL**:`POST /api/zc/device/getAngleStaticShieldRect`
+- **C 接口**:`ZC_GetAngleStaticShieldRect`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_RECT_S 结构体字段 JSON
+
+---
+
+<a id='203-setAngleStaticShieldRect'></a>
+
+## 203. setAngleStaticShieldRect — 对应 C 接口 {@code ZC_SetAngleStaticShieldRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setAngleStaticShieldRect`
+- **C 接口**:`ZC_SetAngleStaticShieldRect`
+
+### 请求体(AngleStaticShieldRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_RECT_S | 是 | 结构体对象(字段见下表) |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='204-clrAngleStaticShieldRect'></a>
+
+## 204. clrAngleStaticShieldRect — 对应 C 接口 {@code ZC_ClrAngleStaticShieldRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrAngleStaticShieldRect`
+- **C 接口**:`ZC_ClrAngleStaticShieldRect`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='205-getAngleStaticShieldPoly'></a>
+
+## 205. getAngleStaticShieldPoly — 静屏-多边形
+
+- **URL**:`POST /api/zc/device/getAngleStaticShieldPoly`
+- **C 接口**:`ZC_GetAngleStaticShieldPoly`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_POLY_S 结构体字段 JSON
+
+---
+
+<a id='206-setAngleStaticShieldPoly'></a>
+
+## 206. setAngleStaticShieldPoly — 对应 C 接口 {@code ZC_SetAngleStaticShieldPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setAngleStaticShieldPoly`
+- **C 接口**:`ZC_SetAngleStaticShieldPoly`
+
+### 请求体(AngleStaticShieldPolyReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_POLY_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_POLY_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| p | ZC_POINT_S[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='207-clrAngleStaticShieldPoly'></a>
+
+## 207. clrAngleStaticShieldPoly — 对应 C 接口 {@code ZC_ClrAngleStaticShieldPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrAngleStaticShieldPoly`
+- **C 接口**:`ZC_ClrAngleStaticShieldPoly`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='208-getAngleDynamicShieldRect'></a>
+
+## 208. getAngleDynamicShieldRect — 动屏-矩形
+
+- **URL**:`POST /api/zc/device/getAngleDynamicShieldRect`
+- **C 接口**:`ZC_GetAngleDynamicShieldRect`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_RECT_S 结构体字段 JSON
+
+---
+
+<a id='209-setAngleDynamicShieldRect'></a>
+
+## 209. setAngleDynamicShieldRect — 对应 C 接口 {@code ZC_SetAngleDynamicShieldRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setAngleDynamicShieldRect`
+- **C 接口**:`ZC_SetAngleDynamicShieldRect`
+
+### 请求体(AngleDynamicShieldRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_RECT_S | 是 | 结构体对象(字段见下表) |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='210-clrAngleDynamicShieldRect'></a>
+
+## 210. clrAngleDynamicShieldRect — 对应 C 接口 {@code ZC_ClrAngleDynamicShieldRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrAngleDynamicShieldRect`
+- **C 接口**:`ZC_ClrAngleDynamicShieldRect`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='211-getAngleDynamicShieldPoly'></a>
+
+## 211. getAngleDynamicShieldPoly — 动屏-多边形
+
+- **URL**:`POST /api/zc/device/getAngleDynamicShieldPoly`
+- **C 接口**:`ZC_GetAngleDynamicShieldPoly`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_POLY_S 结构体字段 JSON
+
+---
+
+<a id='212-setAngleDynamicShieldPoly'></a>
+
+## 212. setAngleDynamicShieldPoly — 对应 C 接口 {@code ZC_SetAngleDynamicShieldPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setAngleDynamicShieldPoly`
+- **C 接口**:`ZC_SetAngleDynamicShieldPoly`
+
+### 请求体(AngleDynamicShieldPolyReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_POLY_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_POLY_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| p | ZC_POINT_S[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='213-clrAngleDynamicShieldPoly'></a>
+
+## 213. clrAngleDynamicShieldPoly — 对应 C 接口 {@code ZC_ClrAngleDynamicShieldPoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrAngleDynamicShieldPoly`
+- **C 接口**:`ZC_ClrAngleDynamicShieldPoly`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='214-getAngleMoveLine'></a>
+
+## 214. getAngleMoveLine — 闯入-线
+
+- **URL**:`POST /api/zc/device/getAngleMoveLine`
+- **C 接口**:`ZC_GetAngleMoveLine`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_MOVE_LINE_S 结构体字段 JSON
+
+---
+
+<a id='215-setAngleMoveLine'></a>
+
+## 215. setAngleMoveLine — 对应 C 接口 {@code ZC_SetAngleMoveLine}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setAngleMoveLine`
+- **C 接口**:`ZC_SetAngleMoveLine`
+
+### 请求体(AngleMoveLineReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_MOVE_LINE_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_MOVE_LINE_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| lowIO | int |  |
+| highIO | int |  |
+| line | ZC_LINE_S |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='216-clrAngleMoveLine'></a>
+
+## 216. clrAngleMoveLine — 对应 C 接口 {@code ZC_ClrAngleMoveLine}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrAngleMoveLine`
+- **C 接口**:`ZC_ClrAngleMoveLine`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='217-getAngleMoveRect'></a>
+
+## 217. getAngleMoveRect — 闯入-矩形
+
+- **URL**:`POST /api/zc/device/getAngleMoveRect`
+- **C 接口**:`ZC_GetAngleMoveRect`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_MOVE_RECT_S 结构体字段 JSON
+
+---
+
+<a id='218-setAngleMoveRect'></a>
+
+## 218. setAngleMoveRect — 对应 C 接口 {@code ZC_SetAngleMoveRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setAngleMoveRect`
+- **C 接口**:`ZC_SetAngleMoveRect`
+
+### 请求体(AngleMoveRectReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_MOVE_RECT_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_MOVE_RECT_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| lowIO | int |  |
+| highIO | int |  |
+| rect | ZC_RECT_S |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='219-clrAngleMoveRect'></a>
+
+## 219. clrAngleMoveRect — 对应 C 接口 {@code ZC_ClrAngleMoveRect}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrAngleMoveRect`
+- **C 接口**:`ZC_ClrAngleMoveRect`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='220-getAngleMovePoly'></a>
+
+## 220. getAngleMovePoly — 闯入-多边形`
+
+- **URL**:`POST /api/zc/device/getAngleMovePoly`
+- **C 接口**:`ZC_GetAngleMovePoly`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_MOVE_POLY_S 结构体字段 JSON
+
+---
+
+<a id='221-setAngleMovePoly'></a>
+
+## 221. setAngleMovePoly — 对应 C 接口 {@code ZC_SetAngleMovePoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setAngleMovePoly`
+- **C 接口**:`ZC_SetAngleMovePoly`
+
+### 请求体(AngleMovePolyReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_MOVE_POLY_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_MOVE_POLY_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| lowIO | int |  |
+| highIO | int |  |
+| poly | ZC_POLY_S |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='222-clrAngleMovePoly'></a>
+
+## 222. clrAngleMovePoly — 对应 C 接口 {@code ZC_ClrAngleMovePoly}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrAngleMovePoly`
+- **C 接口**:`ZC_ClrAngleMovePoly`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='223-getAngleMoveBorder'></a>
+
+## 223. getAngleMoveBorder — 闯入-多边形边界
+
+- **URL**:`POST /api/zc/device/getAngleMoveBorder`
+- **C 接口**:`ZC_GetAngleMoveBorder`
+
+### 请求体(BinaryInt2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;data 为 ZC_MOVE_POLY_S 结构体字段 JSON
+
+---
+
+<a id='224-setAngleMoveBorder'></a>
+
+## 224. setAngleMoveBorder — 对应 C 接口 {@code ZC_SetAngleMoveBorder}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/setAngleMoveBorder`
+- **C 接口**:`ZC_SetAngleMoveBorder`
+
+### 请求体(AngleMoveBorderReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 |  |
+| i2 | Integer | 否 |  |
+| data | ZC_MOVE_POLY_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_MOVE_POLY_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| lowIO | int |  |
+| highIO | int |  |
+| poly | ZC_POLY_S |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='225-clrAngleMoveBorder'></a>
+
+## 225. clrAngleMoveBorder — 对应 C 接口 {@code ZC_ClrAngleMoveBorder}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/clrAngleMoveBorder`
+- **C 接口**:`ZC_ClrAngleMoveBorder`
+
+### 请求体(Int2Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | angle |
+| i2 | Integer | 否 | index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='226-ruiTing_GetZone'></a>
+
+## 226. ruiTing_GetZone — R-T-D-Z
+
+- **URL**:`POST /api/zc/device/ruiTing_GetZone`
+- **C 接口**:`ZC_RuiTing_GetZone`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_RuiTing_ZONE_S 结构体字段 JSON
+
+---
+
+<a id='227-ruiTing_SetZone'></a>
+
+## 227. ruiTing_SetZone — 对应 C 接口 {@code ZC_RuiTing_SetZone}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/ruiTing_SetZone`
+- **C 接口**:`ZC_RuiTing_SetZone`
+
+### 请求体(Ting_SetZoneReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_RuiTing_ZONE_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_RuiTing_ZONE_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| index | int |  |
+| name | byte[] |  |
+| radiation | float |  |
+| alarm_temp | float |  |
+| rect | ZC_RECT_S |  |
+| poly | ZC_POLY_S |  |
+| pot_tem_switch | int |  |
+| trend_tem_switch | int |  |
+| absolute_tem_switch | int |  |
+| relative_tem_switch | int |  |
+| trend_tem_rate_degree | float |  |
+| trend_tem_rate_minute | int |  |
+| absolute_tem_reference_x | int |  |
+| absolute_tem_reference_y | int |  |
+| absolute_tem_reference_tem | float |  |
+| pot_tem_timeout | int |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='228-ruiTing_DelZone'></a>
+
+## 228. ruiTing_DelZone — 对应 C 接口 {@code ZC_RuiTing_DelZone}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/ruiTing_DelZone`
+- **C 接口**:`ZC_RuiTing_DelZone`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | zone_index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='229-ruiTing_GetGroup'></a>
+
+## 229. ruiTing_GetGroup — 对应 C 接口 {@code ZC_RuiTing_GetGroup}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/ruiTing_GetGroup`
+- **C 接口**:`ZC_RuiTing_GetGroup`
+
+### 请求体(BinaryReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | String | 否 |  |
+| size | Integer | 否 |  |
+
+### 返回
+
+code=0 成功;data 为 ZC_RuiTing_RELATIVE_TEMP_GROUP_S 结构体字段 JSON
+
+---
+
+<a id='230-ruiTing_SetGroup'></a>
+
+## 230. ruiTing_SetGroup — 对应 C 接口 {@code ZC_RuiTing_SetGroup}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/ruiTing_SetGroup`
+- **C 接口**:`ZC_RuiTing_SetGroup`
+
+### 请求体(Ting_SetGroupReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| data | ZC_RuiTing_RELATIVE_TEMP_GROUP_S | 是 | 结构体对象(字段见下表) |
+
+**`data` 结构体字段(ZC_RuiTing_RELATIVE_TEMP_GROUP_S):**
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| group_index | int |  |
+| relative_tem_rate | float |  |
+| relative_tem_ary | int[] |  |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='231-ruiTing_DelGroup'></a>
+
+## 231. ruiTing_DelGroup — 对应 C 接口 {@code ZC_RuiTing_DelGroup}(SDK 头文件无独立注释,功能见函数名)
+
+- **URL**:`POST /api/zc/device/ruiTing_DelGroup`
+- **C 接口**:`ZC_RuiTing_DelGroup`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | group_index |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='232-enableRecvAlarm'></a>
+
+## 232. enableRecvAlarm — 是否接收报警 bEnable = 1,接收;bEnable = 0,不接收
+
+- **URL**:`POST /api/zc/device/enableRecvAlarm`
+- **C 接口**:`ZC_EnableRecvAlarm`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | bEnable |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+<a id='233-alarmAutoCapture'></a>
+
+## 233. alarmAutoCapture — 报警自动抓拍图像
+
+- **URL**:`POST /api/zc/device/alarmAutoCapture`
+- **C 接口**:`ZC_AlarmAutoCapture`
+
+### 请求体(IntReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 否 | bEnable |
+
+### 返回
+
+code=0 成功;返回值为操作结果(0 表示成功)
+
+---
+
+
+<a id='234-captureToFile'></a>
+
+## 234. captureToFile — 红外 + 可见光抓拍保存 JPG 文件。
+
+- **URL**:`POST /api/zc/device/captureToFile`
+- **C 接口**:`ZC_CaptureThermalToFile`(红外);可见光走海康 HCNetSDK 抓图(通道 1)
+
+### 请求体(PathPicReq)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| normalPic | String | 是 | 可见光图片文件名(如 visible.jpg) |
+| IRPic | String | 是 | 红外图片文件名(如 IRPic.jpg) |
+
+### 返回
+
+始终 HTTP 200 + code=0(抓拍结果在 data 中):
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| normalPic | String | 可见光图片文件名(回显) |
+| IRPic | String | 红外图片文件名(回显) |
+| filePath | String | 存储目录(capture-path,不含文件名) |
+| result | int | 红外抓拍返回码(0-成功) |
+| msg1 | String | 红外结果消息 |
+| hdresult | String | 可见光图片保存的完整路径 |
+| msg2 | String | 可见光结果消息 |
+| msg | String | 总体消息(设备未登录时为"抓拍失败,请检查设备连接情况") |
+
+**说明**:红外抓拍保存到 `capture-path` + IRPic,可见光抓拍保存到 `capture-path` + normalPic,两张相互独立。
+
+---
+
+<a id='235-pTZControlHK'></a>
+
+## 235. pTZControlHK — 云台控制(可见光 / 海康)
+
+- **URL**:`POST /api/zc/device/pTZControlHK`
+- **海康接口**:`NET_DVR_PTZControlWithSpeed_Other`(登录句柄直控,无需先开预览/录制;失败回退 `NET_DVR_PTZControlWithSpeed`)
+
+### 请求体(Int3Req)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| ip | String | 是 | 设备 IP |
+| i1 | Integer | 是 | 云台命令码:1-云台上 2-云台下 3-云台左 4-云台右 5-左上 6-右上 7-左下 8-右下;9-倍率变大 10-倍率变小 11-光圈放大 12-光圈缩小 13-焦点前调 14-焦点后调 |
+| i2 | Integer | 是 | 停止标志:0-开始(持续运动,需再发一次 1 停止) 1-停止 |
+| i3 | Integer | 是 | 速度:1~7 |
+
+### 返回
+
+code=0 成功(data 为 null);设备未登录或云台指令下发失败时仅记录日志消息,仍返回 code=0
+
+**说明**:通道固定为 1,按 IP 取可见光设备信息后下发指令;设备需具备云台/变倍等能力,否则指令不会产生实际动作(SDK 可能返回成功)。
+
+---
+

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio