index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. <template>
  2. <div class="device-box" id="monitorBox">
  3. <a-tabs class="tabs-box" type="card" v-model:activeKey="activeKey" @change="tabChange" id="tabsBox" v-if="isRefresh">
  4. <a-tab-pane key="1" tab="实时监测">
  5. <template v-if="deviceType == 'fan' && activeKey == '1'">
  6. <GroupMonitorTable :dataSource="dataSource" :columnsType="`${deviceType}_monitor`" />
  7. </template>
  8. <template v-else-if="activeKey == '1' && deviceType">
  9. <MonitorTable ref="monitorTable" :columnsType="`${deviceType}_monitor`" :dataSource="dataSource"
  10. design-scope="device_monitor" :isShowPagination="false" :isShowActionColumn="isHaveAction.includes(deviceType.split('_')[0]) ? false : true" :is-show-select="false" title="设备监测"
  11. :form-config="deviceType == 'safetymonitor' ? formConfig : undefined" :scroll="{y: 650}">
  12. <template #filterCell="{ column, record }">
  13. <template v-if="deviceType.startsWith('gate')">
  14. <template v-if="record.frontGateOpenCtrl == 1 || record.frontGateOpenCtrl === true">
  15. <a-tag
  16. v-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 0 && record.frontGateClose == 0"
  17. color="red">正在打开</a-tag>
  18. <a-tag v-else-if="column.dataIndex === 'frontGateOpen'" color="processing">打开</a-tag>
  19. </template>
  20. <template v-else-if="record.frontGateOpenCtrl == 0 || record.frontGateOpenCtrl === false">
  21. <a-tag
  22. v-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 0 && record.frontGateClose == 0"
  23. color="red">正在关闭</a-tag>
  24. <a-tag
  25. v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 0 && record.frontGateClose == 1"
  26. color="default">关闭</a-tag>
  27. <a-tag
  28. v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 1 && record.frontGateClose == 0"
  29. color="default">打开</a-tag>
  30. </template>
  31. <template v-if="record.rearGateOpenCtrl == 1 || record.rearGateOpenCtrl === true">
  32. <a-tag
  33. v-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 0 && record.rearGateClose == 0"
  34. color="red">正在打开</a-tag>
  35. <a-tag v-else-if="column.dataIndex === 'rearGateOpen'" color="processing">打开</a-tag>
  36. </template>
  37. <template v-else-if="record.rearGateOpenCtrl == 0 || record.rearGateOpenCtrl === false">
  38. <a-tag
  39. v-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 0 && record.rearGateClose == 0"
  40. color="red">正在关闭</a-tag>
  41. <a-tag
  42. v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 0 && record.rearGateClose == 1"
  43. color="default">关闭</a-tag>
  44. <a-tag
  45. v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 1 && record.rearGateClose == 0"
  46. color="default">打开</a-tag>
  47. </template>
  48. </template>
  49. <template v-if="deviceType.startsWith('windrect')">
  50. <a-tag v-if="column.dataIndex === 'sign'"
  51. :color="record.sign == 0 ? '#95CF65' : record.sign == 1 ? '#4590EA' : '#9876AA'"> {{
  52. record.sign == 0 ? '高位' : record.sign == 1 ? '中位' : '低位'
  53. }}</a-tag>
  54. <template v-if="record && column && column.dataIndex === 'isRun' && record.isRun">
  55. <a-tag v-if="record.isRun == -2 || record.isRun == -1"
  56. :color="record.isRun == -2 ? '#95CF65' : '#ED5700'">{{
  57. record.isRun == -2 ? '空闲' : '等待'
  58. }}</a-tag>
  59. <a-tag v-else-if="record.isRun == 100" color="#4693FF">完成</a-tag>
  60. <Progress v-else :percent="Number(record.isRun)" size="small" status="active" />
  61. </template>
  62. </template>
  63. <template v-if="deviceType.startsWith('safetymonitor')">
  64. <div v-if="!record.devicename && column.dataIndex === 'devicename'">-</div>
  65. <div v-if="!record.V && column.dataIndex === 'V'">-</div>
  66. <div v-if="!record.PointUnit && column.dataIndex === 'PointUnit'">-</div>
  67. <div v-if="!record.highRange && column.dataIndex === 'highRange'">-</div>
  68. <div v-if="!record.lowRange && column.dataIndex === 'lowRange'">-</div>
  69. <div v-if="!record.dataTypeName && column.dataIndex === 'dataTypeName'">-</div>
  70. </template>
  71. <a-tag v-if="column.dataIndex === 'warnFlag'"
  72. :color="record.warnFlag == 0 ? 'green' : record.warnFlag == 1 ? '#FF5812' : 'gray'"> {{
  73. record.warnFlag == 0 ? '正常' : record.warnFlag == 1 ? '报警' : record.warnFlag == 2 ? '断开' : '未监测'
  74. }}</a-tag>
  75. <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == 0 ? 'default' : 'green'">{{
  76. record.netStatus == 0 ? '断开' : '连接'
  77. }}</a-tag>
  78. </template>
  79. </MonitorTable>
  80. </template>
  81. <!-- 图表 -->
  82. <!-- <div style="width:100%;height:280px;margin: 20px 0px;">
  83. <BarAndLine v-if="deviceType == 'windrect'" xAxisPropType="strname" :dataSource="dataSource" height="100%"
  84. :chartsColumns="chartsColumnsRect" chartsType="" :option="echartsOption" />
  85. <BarAndLine v-else-if="deviceType == 'fanlocal'" xAxisPropType="strname" :dataSource="dataSource" height="100%"
  86. :chartsColumns="chartsColumnsFan" chartsType="" :option="echartsOption" />
  87. <BarAndLine v-else-if="deviceType == 'fanmain'" xAxisPropType="strname" :dataSource="dataSource" height="100%"
  88. :chartsColumns="chartsColumnsMain" chartsType="" :option="echartsOption" />
  89. <BarAndLine v-else-if="deviceType == 'fiber'" xAxisPropType="strname" :dataSource="dataSource" height="100%"
  90. :chartsColumns="chartsColumnsFiber" chartsType="" :option="echartsOption" />
  91. <BarAndLine v-else-if="deviceType == 'obfurage'" xAxisPropType="strname" :dataSource="dataSource" height="100%"
  92. :chartsColumns="chartsColumnsObf" chartsType="" :option="echartsOption" />
  93. <BarAndLine v-else-if="deviceType == 'bundletube'" xAxisPropType="strname" :dataSource="dataSource"
  94. height="100%" :chartsColumns="chartsColumnsBun" chartsType="" :option="echartsOption" />
  95. <BarAndLine v-else xAxisPropType="strname" :dataSource="dataSource" height="100%"
  96. :chartsColumns="chartsColumnsreal" chartsType="" :option="echartsOption" />
  97. </div> -->
  98. </a-tab-pane>
  99. <a-tab-pane key="2" tab="历史数据">
  100. <div class="tab-item">
  101. <HistoryTable ref="historyTable" v-if="activeKey == '2'" :columns-type="`${deviceType}`"
  102. :device-type="deviceType" :device-list-api="getDeviceList.bind(null, { devicekind: deviceType })"
  103. designScope="device-history" @change="changeHis" />
  104. </div>
  105. <!-- 图表 -->
  106. <!-- <div v-if="alive" style="width:100%;height:280px;margin: 20px 0px;">
  107. <BarAndLine v-if="deviceType == 'windrect'" xAxisPropType="gdevicename" :dataSource="dataSourceHis"
  108. height="100%" :chartsColumns="chartsColumnsRect" chartsType="" :option="echartsOption" />
  109. <BarAndLine v-else-if="deviceType == 'fanlocal'" xAxisPropType="gdevicename" :dataSource="dataSourceHis"
  110. height="100%" :chartsColumns="chartsColumnsFan" chartsType="" :option="echartsOption" />
  111. <BarAndLine v-else-if="deviceType == 'fanmain'" xAxisPropType="gdevicename" :dataSource="dataSourceHis"
  112. height="100%" :chartsColumns="chartsColumnsMain" chartsType="" :option="echartsOption" />
  113. <BarAndLine v-else-if="deviceType == 'fiber'" xAxisPropType="gdevicename" :dataSource="dataSourceHis"
  114. height="100%" :chartsColumns="chartsColumnsFiber" chartsType="" :option="echartsOption" />
  115. <BarAndLine v-else-if="deviceType == 'obfurage'" xAxisPropType="gdevicename" :dataSource="dataSourceHis"
  116. height="100%" :chartsColumns="chartsColumnsObf" chartsType="" :option="echartsOption" />
  117. <BarAndLine v-else-if="deviceType == 'bundletube'" xAxisPropType="gdevicename" :dataSource="dataSourceHis"
  118. height="100%" :chartsColumns="chartsColumnsBun" chartsType="" :option="echartsOption" />
  119. <BarAndLine v-else xAxisPropType="gdevicename" :dataSource="dataSourceHis" height="100%"
  120. :chartsColumns="chartsColumnsreal" chartsType="" :option="echartsOption" />
  121. </div> -->
  122. </a-tab-pane>
  123. <a-tab-pane key="3" tab="报警历史">
  124. <div class="tab-item">
  125. <AlarmHistoryTable ref="alarmHistoryTable" v-if="activeKey == '3'" columns-type="alarm"
  126. :device-type="deviceType" :device-list-api="getDeviceList.bind(null, { devicekind: deviceType })"
  127. designScope="alarm-history" />
  128. </div>
  129. </a-tab-pane>
  130. <a-tab-pane key="4" tab="操作历史" v-if="deviceType !== 'safetymonitor'">
  131. <div class="tab-item">
  132. <HandlerHistoryTable ref="handlerHistoryTable" v-if="activeKey == '4'" columns-type="operator_history"
  133. :device-type="deviceType" :device-list-api="getDeviceList.bind(null, { devicekind: deviceType })"
  134. designScope="operator-history" />
  135. </div>
  136. </a-tab-pane>
  137. </a-tabs>
  138. </div>
  139. </template>
  140. <script setup lang="ts">
  141. import { ref, onMounted, onUnmounted, shallowRef, defineProps, watch, nextTick, unref } from 'vue'
  142. import BarAndLine from '/@/components/chart/BarAndLine.vue';
  143. import { list, getDeviceList } from './safety.api'
  144. import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
  145. import HistoryTable from '../comment/HistoryTable.vue';
  146. import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
  147. import MonitorTable from '../comment/MonitorTable.vue';
  148. import GroupMonitorTable from '../comment/GroupMonitorTable.vue';
  149. import { Progress } from 'ant-design-vue';
  150. import { useRouter } from 'vue-router';
  151. import { formConfig, isHaveAction } from './safety.data'
  152. import { getDictItemsByCode } from '/@/utils/dict';
  153. // import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
  154. // const echartsOption = {
  155. // grid: {
  156. // top: '60px',
  157. // left: '10px',
  158. // right: '25px',
  159. // bottom: '5%',
  160. // containLabel: true,
  161. // },
  162. // toolbox: {
  163. // feature: {},
  164. // },
  165. // };
  166. // let alive = ref(true)
  167. type DeviceType = { deviceType: string, deviceName: string, datalist: any[] };
  168. const props = defineProps({
  169. pageData: {
  170. type: Object,
  171. default: () => { }
  172. }
  173. })
  174. const scroll = {
  175. y: 360
  176. }
  177. const monitorTable = ref()
  178. const historyTable = ref()
  179. const alarmHistoryTable = ref()
  180. const handlerHistoryTable = ref()
  181. const isRefresh = ref(true)
  182. const activeKey = ref('1'); // tab key
  183. const dataSource = shallowRef([]) // 实时监测数据
  184. const deviceType = ref('') // 监测设备类型
  185. // let dataSourceHis = shallowRef([])//历史数据
  186. //历史数据
  187. async function changeHis(data) {
  188. // alive.value = false
  189. // nextTick(() => {
  190. // dataSourceHis = data
  191. // alive.value = true
  192. // })
  193. }
  194. async function tabChange(activeKeyVal) {
  195. activeKey.value = activeKeyVal;
  196. if (activeKey.value != '1') {
  197. if (timer != undefined) {
  198. clearTimeout(timer);
  199. timer = undefined;
  200. }
  201. } else {
  202. timer = null
  203. await getMonitor(true)
  204. }
  205. };
  206. // https获取监测数据
  207. let timer: null | NodeJS.Timeout = null;
  208. function getMonitor(flag?) {
  209. if (deviceType.value) {
  210. if (timer) timer = null
  211. if (Object.prototype.toString.call(timer) === '[object Null]') {
  212. timer = setTimeout(async () => {
  213. await getDataSource()
  214. if (timer) {
  215. getMonitor();
  216. }
  217. }, flag ? 0 : 1000);
  218. }
  219. }
  220. };
  221. async function getDataSource() {
  222. const formData = monitorTable.value.getForm()
  223. const res = await list({ devicetype: deviceType.value, filterParams: { ...formData.getFieldsValue() } })
  224. if (res.msgTxt.length > 0) {
  225. dataSource.value = []
  226. const dataArr = res.msgTxt[0].datalist || [];
  227. dataArr.filter((data: any) => {
  228. const readData = data.readData;
  229. return Object.assign(data, readData);
  230. });
  231. if(deviceType.value == 'safetymonitor'){
  232. // 如果是安全监控的数据时需要过滤常见设备数据,根据设定的常用安全监控字典去匹配
  233. const dictCodes = getDictItemsByCode('safetynormal')
  234. const searchForm = formData.getFieldsValue()
  235. if(!searchForm['dataTypeName'] && dictCodes && dictCodes.length){
  236. for(let i=0; i< dictCodes.length; i++){
  237. const dict = dictCodes[i]
  238. dataArr.forEach((item) => {
  239. if(dict['value'] == item['dataTypeName']){
  240. dataSource.value.push(item)
  241. }
  242. })
  243. }
  244. }else{
  245. dataSource.value = dataArr
  246. }
  247. }else{
  248. dataSource.value = dataArr
  249. }
  250. } else {
  251. dataSource.value = []
  252. }
  253. }
  254. onMounted(async () => {
  255. const { currentRoute } = useRouter();
  256. if(unref(currentRoute)){
  257. const path = unref(currentRoute).path
  258. if (path) {
  259. deviceType.value = path.substring(path.lastIndexOf('/') + 1)
  260. }
  261. await getMonitor(true)
  262. }
  263. })
  264. onUnmounted(() => {
  265. if (timer) {
  266. clearTimeout(timer);
  267. }
  268. timer = undefined;
  269. })
  270. </script>
  271. <style lang="less" scoped >
  272. @import '/@/design/vent/color.less';
  273. @import '/@/design/vent/modal.less';
  274. @ventSpace: zxm;
  275. .device-box {
  276. width: 100%;
  277. height: calc(100% - 100px);
  278. padding-bottom: 10px;
  279. margin-top: 20px;
  280. display: flex;
  281. justify-content: center;
  282. .tabs-box {
  283. width: calc(100% - 12px) !important;
  284. height: 100% !important;
  285. bottom: 3px !important;
  286. }
  287. .device-button-group {
  288. position: absolute;
  289. top: -30px;
  290. display: flex;
  291. width: 100%;
  292. .device-button {
  293. height: 26px;
  294. padding: 0 20px;
  295. background: linear-gradient(45deg, #04e6fb55, #0c5cab55);
  296. clip-path: polygon(10px 0,
  297. 0 50%,
  298. 10px 100%,
  299. 100% 100%,
  300. calc(100% - 10px) 50%,
  301. 100% 0);
  302. display: flex;
  303. justify-content: center;
  304. align-items: center;
  305. color: #FFF;
  306. position: relative;
  307. cursor: pointer;
  308. &:nth-child(1) {
  309. left: calc(-6px * 1);
  310. }
  311. &:nth-child(2) {
  312. left: calc(-6px * 2);
  313. }
  314. &:nth-child(3) {
  315. left: calc(-6px * 3);
  316. }
  317. &:nth-child(4) {
  318. left: calc(-6px * 4);
  319. }
  320. &:nth-child(5) {
  321. left: calc(-6px * 5);
  322. }
  323. &:nth-child(6) {
  324. left: calc(-6px * 6);
  325. }
  326. &:nth-child(7) {
  327. left: calc(-6px * 7);
  328. }
  329. &:nth-child(8) {
  330. left: calc(-6px * 8);
  331. }
  332. &:nth-child(9) {
  333. left: calc(-6px * 9);
  334. }
  335. &:nth-child(10) {
  336. left: calc(-6px * 10);
  337. }
  338. &:nth-child(11) {
  339. left: calc(-6px * 11);
  340. }
  341. &:nth-child(12) {
  342. left: calc(-6px * 12);
  343. }
  344. &:nth-child(13) {
  345. left: calc(-6px * 13);
  346. }
  347. &:nth-child(14) {
  348. left: calc(-6px * 14);
  349. }
  350. &:nth-child(15) {
  351. left: calc(-6px * 15);
  352. }
  353. &:first-child {
  354. clip-path: polygon(0 0,
  355. 10px 50%,
  356. 0 100%,
  357. 100% 100%,
  358. calc(100% - 10px) 50%,
  359. 100% 0);
  360. }
  361. }
  362. .device-active {
  363. background: linear-gradient(45deg, #04e6fb, #0c5cab);
  364. &::before {
  365. border-color: #0efcff;
  366. box-shadow: 1px 1px 3px 1px #0efcff inset;
  367. }
  368. }
  369. }
  370. .enter-detail {
  371. color: #fff;
  372. cursor: pointer;
  373. position: absolute;
  374. right: 120px;
  375. top: -6px;
  376. padding: 5px;
  377. border-radius: 5px;
  378. margin-left: 8px;
  379. margin-right: 8px;
  380. width: auto;
  381. height: 33px !important;
  382. display: flex;
  383. align-items: center;
  384. justify-content: center;
  385. color: #fff;
  386. padding: 5px 15px 5px 15px;
  387. cursor: pointer;
  388. &:hover {
  389. background: linear-gradient(#2cd1ff55, #1eb0ff55);
  390. }
  391. &::before {
  392. width: calc(100% - 6px);
  393. height: 27px;
  394. content: '';
  395. position: absolute;
  396. top: 3px;
  397. right: 0;
  398. left: 3px;
  399. bottom: 0;
  400. z-index: -1;
  401. border-radius: inherit;
  402. /*important*/
  403. background: linear-gradient(#1fa6cb, #127cb5);
  404. }
  405. }
  406. }
  407. :deep(.@{ventSpace}-tabs-tabpane-active) {
  408. height: 100%;
  409. border: 1px solid #44d3ff70;
  410. border-radius: 2px;
  411. -webkit-backdrop-filter: blur(8px);
  412. box-shadow: 0 0 20px #44b4ff33 inset;
  413. background-color: #ffffff11;
  414. overflow-y: auto;
  415. }
  416. :deep(.@{ventSpace}-tabs-card) {
  417. .@{ventSpace}-tabs-tab {
  418. background: linear-gradient(#2cd1ff55, #1eb0ff55);
  419. border-color: #74e9fe;
  420. border-radius: 0%;
  421. &:hover {
  422. color: #64d5ff;
  423. }
  424. }
  425. .@{ventSpace}-tabs-content{
  426. height: 100% !important;
  427. }
  428. .@{ventSpace}-tabs-tab.@{ventSpace}-tabs-tab-active .@{ventSpace}-tabs-tab-btn {
  429. color: aqua;
  430. }
  431. .@{ventSpace}-tabs-nav::before {
  432. border-color: #74e9fe;
  433. }
  434. .@{ventSpace}-picker,
  435. .@{ventSpace}-select-selector {
  436. width: 100% !important;
  437. background: #00000017 !important;
  438. border: 1px solid @vent-form-item-boder !important;
  439. input,
  440. .@{ventSpace}-select-selection-item,
  441. .@{ventSpace}-picker-suffix {
  442. color: #fff !important;
  443. }
  444. .@{ventSpace}-select-selection-placeholder {
  445. color: #b7b7b7 !important;
  446. }
  447. }
  448. .@{ventSpace}-pagination-next,
  449. .action,
  450. .@{ventSpace}-select-arrow,
  451. .@{ventSpace}-picker-separator {
  452. color: #fff !important;
  453. }
  454. .@{ventSpace}-table-cell-row-hover {
  455. background: #264d8833 !important;
  456. }
  457. .@{ventSpace}-table-row-selected {
  458. background: #00c0a311 !important;
  459. td {
  460. background-color: #00000000 !important;
  461. }
  462. }
  463. .@{ventSpace}-table-thead {
  464. // background: linear-gradient(#004a8655 0%, #004a86aa 10%) !important;
  465. background: #3d9dd45d !important;
  466. &>tr>th,
  467. .@{ventSpace}-table-column-title {
  468. // color: #70f9fc !important;
  469. border-color: #84f2ff !important;
  470. border-left: none !important;
  471. border-right: none !important;
  472. padding: 7px;
  473. }
  474. }
  475. .@{ventSpace}-table-tbody {
  476. tr>td {
  477. padding: 12px;
  478. }
  479. }
  480. .@{ventSpace}-table-tbody>tr:hover.@{ventSpace}-table-row>td {
  481. background-color: #26648855 !important;
  482. }
  483. .jeecg-basic-table-row__striped {
  484. // background: #97efff11 !important;
  485. td {
  486. background-color: #97efff11 !important;
  487. }
  488. }
  489. }
  490. </style>