fireMonitor.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. <template>
  2. <div class="fire-monitor">
  3. <div class="basic-fire-box">
  4. <div class="box-top">
  5. <CommonBd title="设备状态总览">
  6. <CustomGalleryNew :option="option" :galleryData="galleryData"></CustomGalleryNew>
  7. </CommonBd>
  8. </div>
  9. <div class="box-cen">
  10. <CommonBd title="光谱摄像机">
  11. <CommonTable
  12. :columns="deviceColumns"
  13. :table-data="tableDataGp"
  14. selectable
  15. :selected-key="selectedGpId"
  16. @row-click="onSelectGp"
  17. ></CommonTable>
  18. </CommonBd>
  19. </div>
  20. <div class="box-bot">
  21. <CommonBd title="火灾探测器">
  22. <CommonTable
  23. :columns="deviceColumns"
  24. :table-data="tableDataHz"
  25. selectable
  26. :selected-key="selectedHzId"
  27. @row-click="onSelectHz"
  28. ></CommonTable>
  29. </CommonBd>
  30. </div>
  31. </div>
  32. <div class="basic-fire-box1">
  33. <!-- 模型区域 -->
  34. <div class="model-box">
  35. <dwgViewer ref="dwgViewerRef" :devices="tableData" />
  36. </div>
  37. <!-- <div class="box1-bot">
  38. <CommonBd title="快捷操作">
  39. <QuickAction :quick-option="quickOption" :btn-option="btnOption" :quick-data="quickData"></QuickAction>
  40. </CommonBd>
  41. </div> -->
  42. </div>
  43. <div class="basic-fire-box">
  44. <div class="box-top1">
  45. <CommonBd title="报警监控">
  46. <!-- <AlarmMonitor :option="alarmOption" :cardData="alarmData"></AlarmMonitor> -->
  47. <AlarmMonitor @locate="locateDeviceOnMap"></AlarmMonitor>
  48. </CommonBd>
  49. </div>
  50. <div class="box-cen1">
  51. <!-- <CommonBd title="区域温度统计">
  52. <CustomChart :chart-config="chartTempConfig" :chart-data="chartTempData"></CustomChart>
  53. </CommonBd> -->
  54. <CommonBd title="历史温度曲线">
  55. <HistoryLine :deviceOptions="deviceOptions"></HistoryLine>
  56. </CommonBd>
  57. </div>
  58. <div class="box-bot1">
  59. <CommonBd title="环境监测数据">
  60. <EnvironmentMonitor :option="envOption" :environData="envData"></EnvironmentMonitor>
  61. </CommonBd>
  62. </div>
  63. </div>
  64. </div>
  65. </template>
  66. <script lang="ts" setup>
  67. import { onMounted, onUnmounted, ref, computed, nextTick, onBeforeMount, watch, reactive, inject, Ref } from 'vue';
  68. import CommonBd from './components/CommonBd.vue';
  69. import CustomGalleryNew from './components/CustomGalleryNew.vue';
  70. import CommonTable from './components/CommonTable.vue';
  71. import AlarmMonitor from './components/AlarmMonitor.vue';
  72. import HistoryLine from './components/HistoryLine.vue';
  73. import EnvironmentMonitor from './components/EnvironmentMonitor.vue';
  74. // import QuickAction from './components/QuickAction.vue';
  75. import dwgViewer from '../../cad/dwgViewerTest.vue';
  76. import { option, chartConfig, deviceColumns, quickOption, btnOption, alarmOption, chartTempConfig, } from './hsqHome.data';
  77. import { managesysList, monitorSystem, deviceList, monitorDevice, getManagesysDeviceNum } from './hsqHome.api';
  78. /** 当前系统ID */
  79. let systemId = ref('')
  80. /** 设备状态总览卡片数据 */
  81. let galleryData = ref({})
  82. /** 设备列表表格数据(包含双光谱相机和火灾探测器) */
  83. let tableData = ref<any[]>([])
  84. /** 光谱摄像机表格数据 */
  85. let tableDataGp = ref<any[]>([])
  86. /** 火灾探测器表格数据 */
  87. let tableDataHz = ref<any[]>([])
  88. /** 光谱摄像机当前选中行 */
  89. const selectedGpId = ref<string | number | null>(null)
  90. /** 火灾探测器当前选中行 */
  91. const selectedHzId = ref<string | number | null>(null)
  92. /** CAD 图纸组件引用 */
  93. const dwgViewerRef = ref<InstanceType<typeof dwgViewer> | null>(null)
  94. /** 历史温度曲线设备选项配置 */
  95. let deviceOptions = ref<any[]>([])
  96. /** 环境监测设备选项配置 */
  97. let envOption = ref<any[]>([])
  98. /** 环境监测数据 */
  99. let envData = reactive({})
  100. /** 定时获取监测数据定时器 */
  101. let timer: null | NodeJS.Timeout = null;
  102. /** 点击列表行后定位 CAD 图标 */
  103. function locateDeviceOnMap(deviceID: string | number | null | undefined) {
  104. if (deviceID == null || deviceID === '') return
  105. dwgViewerRef.value?.locateIcon?.(deviceID)
  106. }
  107. /** 光谱摄像机行点击选中并定位 */
  108. function onSelectGp(row: any) {
  109. selectedGpId.value = row?.deviceID ?? null
  110. locateDeviceOnMap(selectedGpId.value)
  111. }
  112. /** 火灾探测器行点击选中并定位 */
  113. function onSelectHz(row: any) {
  114. selectedHzId.value = row?.deviceID ?? null
  115. locateDeviceOnMap(selectedHzId.value)
  116. }
  117. /**
  118. * 定时获取监测数据
  119. * 通过定时器循环调用数据获取方法,更新表格数据
  120. *
  121. * @param flag - 是否立即执行(首次调用时传true跳过延时)
  122. */
  123. function getMonitor(flag?: boolean) {
  124. timer = setTimeout(async () => {
  125. await getManagesysDeviceNumTj();
  126. await getTableData();
  127. await getDeviceMonitor();
  128. if (timer) {
  129. timer = null;
  130. }
  131. getMonitor();
  132. }, flag ? 0 : 10000);
  133. }
  134. /**
  135. * 获取管理系统设备数量统计
  136. * 调用 getManagesysDeviceNum 接口,根据当前系统ID获取设备数量统计信息
  137. */
  138. async function getManagesysDeviceNumTj() {
  139. const res = await getManagesysDeviceNum({ sysId: systemId.value, deviceKinds: "duaSpeCamera" });
  140. galleryData.value = res || {};
  141. }
  142. /**
  143. * 获取设备列表数据
  144. *
  145. * 调用 deviceList 接口获取双光谱相机设备列表,
  146. * 并将返回数据赋值给 tableData
  147. */
  148. async function getTableData() {
  149. const res = await monitorSystem({ type: 'all', systemID: systemId.value, devicetype: '' });
  150. tableDataGp.value = (res?.deviceInfo?.duaSpeCamera?.datalist || []).map(el => Object.assign({}, el, el.readData || {}));
  151. tableDataHz.value = (res?.deviceInfo?.imgFireDet?.datalist || []).map(el => Object.assign({}, el, el.readData || {}));
  152. tableData.value = tableDataGp.value
  153. deviceOptions.value = tableDataGp.value.map(v => ({
  154. label: v.strname,
  155. value: v.deviceID,
  156. devicetype: v.deviceType
  157. }))
  158. }
  159. /**
  160. * 获取环境监测设备数据
  161. * 调用 monitorDevice 接口,查询指定系统的户外火灾相关监测设备状态
  162. */
  163. async function getDeviceMonitor() {
  164. const res = await monitorDevice({ devicetype: 'sys', systemID: systemId.value, types: 'sys_openair_fire' });
  165. const sensors = (res?.msgTxt || []).filter((v: any) => String(v?.type || '').indexOf('modelsensor') != -1)
  166. envOption.value = sensors.map((el: any) => {
  167. const first = el?.datalist?.[0] || {}
  168. const readData = first.readData || {}
  169. return {
  170. label: first.typeName || '-',
  171. value: Object.keys(readData).filter((v) => v.endsWith('val') || v.endsWith('ture'))[0] || '',
  172. unit: first.typeName == '温度传感器' ? '℃' : first.typeName == '氧气传感器' ? '%' : first.typeName == 'CO传感器' ? 'ppm' : first.typeName == '瓦斯传感器' ? '%' : first.typeName == '烟雾传感器' ? '' : ''
  173. }
  174. })
  175. // 保持 reactive 引用,避免整体替换导致子组件不更新
  176. Object.keys(envData).forEach((key) => delete (envData as any)[key])
  177. const merged = Object.assign({}, ...sensors.map((el: any) => el?.datalist?.[0]?.readData || {}))
  178. Object.assign(envData, merged)
  179. }
  180. /**
  181. * 获取管理系统列表
  182. * 调用 managesysList 接口获取户外火灾相关系统列表,并取第一个系统ID作为当前系统
  183. */
  184. async function getManagesysList() {
  185. const res = await managesysList({ strtype: 'sys_openair_fire', pagetype: 'normal' });
  186. if (res && res.records) {
  187. systemId.value = res.records[0].id
  188. }
  189. }
  190. /**
  191. * 组件挂载完成
  192. * 先获取管理系统列表初始化系统ID,然后立即启动定时获取监测数据
  193. */
  194. onMounted(async () => {
  195. await getManagesysList();
  196. getMonitor(true);
  197. });
  198. /**
  199. * 组件卸载前
  200. * 清理定时器,停止轮询获取监测数据
  201. */
  202. onUnmounted(() => {
  203. if (timer) clearTimeout(timer);
  204. timer = null;
  205. });
  206. </script>
  207. <style lang="less" scoped>
  208. @import '/@/design/theme.less';
  209. .fire-monitor {
  210. position: relative;
  211. width: 100%;
  212. height: calc(100% - 10px);
  213. color: @white;
  214. margin-bottom: 10px;
  215. display: flex;
  216. justify-content: space-between;
  217. .basic-fire-box {
  218. width: 430px;
  219. height: 100%;
  220. &:nth-child(1) {
  221. margin-right: 10px;
  222. }
  223. &:nth-child(3) {
  224. margin-left: 10px;
  225. }
  226. }
  227. .basic-fire-box1 {
  228. position: relative;
  229. width: calc(100% - 880px);
  230. height: 100%;
  231. }
  232. .model-box {
  233. position: absolute;
  234. top: 63px;
  235. left: 0;
  236. width: 100%;
  237. // height: 615px;
  238. height: calc(100% - 63px);
  239. border: 1px solid rgba(40, 165, 232, 0.8);
  240. // margin-bottom: 10px;
  241. }
  242. .box1-bot {
  243. position: absolute;
  244. bottom: 0px;
  245. left: 0;
  246. width: 100%;
  247. height: 155px;
  248. }
  249. .box-top {
  250. height: 185px;
  251. margin-bottom: 10px;
  252. }
  253. .box-top1 {
  254. height: 360px;
  255. margin-bottom: 10px;
  256. }
  257. .box-cen {
  258. height: 310px;
  259. margin-bottom: 10px;
  260. }
  261. .box-cen1 {
  262. height: 220px;
  263. margin-bottom: 10px;
  264. }
  265. .box-bot {
  266. height: 335px;
  267. }
  268. .box-bot1 {
  269. height: 250px;
  270. }
  271. }
  272. :deep(.loading-box) {
  273. position: unset;
  274. }
  275. </style>