gasPumpHome.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. <template>
  2. <div class="monitor-container">
  3. <div id="FlowSensor" class="FlowSensor-box" style="position: absolute; display: none">
  4. <!-- <div class="elementContent" v-if="selectData['deviceType'].startsWith('pump_under') || selectData['deviceType'] == 'pump_n12m2pq'">
  5. <fourBorderBg>
  6. <template v-for="(item, index) in modelMonitor" :key="index">
  7. <div class="gas-monitor-row">
  8. <div class="title">{{ item.title }}</div>
  9. <div class="value">{{ selectData[item.code] ? selectData[item.code] : '-' }}</div>
  10. </div>
  11. </template>
  12. </fourBorderBg>
  13. </div> -->
  14. </div>
  15. <!-- 布尔台新瓦斯泵模型上的数据 -->
  16. <div class="elementContent" style="position: absolute; display: none">
  17. <div v-for="(tag, index) in modelMonitorTags" :key="index" :id="tag.domId" class="modal-monitor-box">
  18. <div class="title">{{ tag.title }}</div
  19. ><div class="signal-round" :class="{ 'signal-round-gry': selectData[tag.code] != 1, 'signal-round-run': selectData[tag.code] == 1 }"></div>
  20. </div>
  21. </div>
  22. <div v-if="selectData['netStatus'] == 0" class="device-state">网络断开</div>
  23. <div class="lr left-box">
  24. <div class="left-container">
  25. <div class="monitor-box">
  26. <ventBox1>
  27. <template #title>
  28. <div>瓦斯泵</div>
  29. </template>
  30. <template #container>
  31. <div v-for="key in 2" :key="key">
  32. <div class="parameter-title group-parameter-title">
  33. <SvgIcon class="icon" size="14" name="pulp-title" /><span>{{ key }}#瓦斯泵磁力启动器</span>
  34. </div>
  35. <div class="input-box">
  36. <div v-for="(item, index) in pumpMonitorData" class="input-item" :key="index">
  37. <div class="title">{{ item.title }}:</div>
  38. <template v-if="item.type !== 'sign' && item.type !== 'warning'">
  39. <div class="value">{{
  40. selectData && selectData[item.code.replace('Starter', `Starter${key + 4}`)]
  41. ? formatNum(selectData[item.code.replace('Starter', `Starter${key + 4}`)], 1)
  42. : '-'
  43. }}</div>
  44. </template>
  45. <template v-else>
  46. <div class="value">
  47. <span
  48. :class="{
  49. 'signal-round': true,
  50. 'signal-round-run': item.type === 'sign' && selectData[item.code.replace('Starter', `Starter${key + 4}`)] == '1',
  51. 'signal-round-gry': selectData[item.code.replace('Starter', `Starter${key + 4}`)] == '0',
  52. 'signal-round-warning': item.type === 'warning' && selectData[item.code.replace('Starter', `Starter${key + 4}`)] == '1',
  53. }"
  54. ></span>
  55. </div>
  56. </template>
  57. </div>
  58. </div>
  59. </div>
  60. </template>
  61. </ventBox1>
  62. <ventBox1 class="vent-margin-t-10">
  63. <template #title>
  64. <div>注水泵</div>
  65. </template>
  66. <template #container>
  67. <div v-for="key in 2" :key="key">
  68. <div class="parameter-title group-parameter-title">
  69. <SvgIcon class="icon" size="14" name="pulp-title" /><span>{{ key }}#注水泵</span>
  70. </div>
  71. <div class="input-box">
  72. <div v-for="(item, index) in waterPumpData" class="input-item" :key="index">
  73. <div class="title">{{ item.title }}:</div>
  74. <template v-if="item.type !== 'sign'">
  75. <div class="value">{{
  76. selectData && selectData[item.code.replace('WaterfloodPump', `WaterfloodPump${key}`)]
  77. ? formatNum(selectData[item.code.replace('WaterfloodPump', `WaterfloodPump${key}`)], 1)
  78. : '-'
  79. }}</div>
  80. </template>
  81. <template v-else>
  82. <div class="value">
  83. <span
  84. :class="{
  85. 'signal-round': true,
  86. 'signal-round-run': selectData[item.code.replace('WaterfloodPump', `WaterfloodPump${key}`)],
  87. 'signal-round-gry': selectData[item.code.replace('WaterfloodPump', `WaterfloodPump${key}`)] == '0',
  88. }"
  89. ></span>
  90. </div>
  91. </template>
  92. </div>
  93. </div>
  94. </div>
  95. </template>
  96. </ventBox1>
  97. <ventBox1 class="vent-margin-t-10">
  98. <template #title>
  99. <div>排水泵</div>
  100. </template>
  101. <template #container>
  102. <div v-for="key in 2" :key="key">
  103. <div class="parameter-title group-parameter-title">
  104. <SvgIcon class="icon" size="14" name="pulp-title" /><span>{{ key }}#排水泵</span>
  105. </div>
  106. <div class="input-box">
  107. <div v-for="(item, index) in dewateringPumpData" class="input-item" :key="index">
  108. <div class="title">{{ item.title }}:</div>
  109. <template v-if="item.type !== 'sign'">
  110. <div class="value">{{
  111. selectData && selectData[item.code.replace('DewateringPump', `DewateringPump${key}`)]
  112. ? formatNum(selectData[item.code.replace('DewateringPump', `DewateringPump${key}`)], 1)
  113. : '-'
  114. }}</div>
  115. </template>
  116. <template v-else>
  117. <div class="value">
  118. <span
  119. :class="{
  120. 'signal-round': true,
  121. 'signal-round-run': selectData[item.code.replace('DewateringPump', `DewateringPump${key}`)],
  122. 'signal-round-gry': selectData[item.code.replace('DewateringPump', `DewateringPump${key}`)] == '0',
  123. }"
  124. ></span>
  125. </div>
  126. </template>
  127. </div>
  128. </div>
  129. </div>
  130. </template>
  131. </ventBox1>
  132. </div>
  133. </div>
  134. </div>
  135. <div class="lr right-box">
  136. <div class="item-box sensor-container">
  137. <ventBox1 class="vent-margin-t-10">
  138. <template #title>
  139. <div>泵站远程集中控制</div>
  140. </template>
  141. <template #container>
  142. <div class="top-btn">
  143. <div class="btn-group">
  144. <a-button class="btn-item" type="primary" @click="handlerFn('zfw')">总复位</a-button>
  145. <a-button class="btn-item" type="default" disabled @click="handlerFn('change')">一键切换</a-button>
  146. </div>
  147. <div class="btn-group">
  148. <a-button style="width: calc(100% - 16px); padding: 0 8px" type="primary" @click="openModal">瓦斯泵控制</a-button>
  149. </div>
  150. <div>
  151. <div class="control-item">
  152. <div class="control-title">控制模式:</div>
  153. <a-radio-group v-model:value="selectData['ykjdqh']" @change="changeCtr">
  154. <a-radio :value="'0'">就地</a-radio>
  155. <a-radio :value="'1'">远程</a-radio>
  156. </a-radio-group>
  157. </div>
  158. <div class="control-item">
  159. <div class="control-title">检修模式:</div>
  160. <a-radio-group v-model:value="selectData['jxmsqh']" @change="changeMode">
  161. <a-radio :value="'0'">关闭</a-radio>
  162. <a-radio :value="'1'">开启</a-radio>
  163. </a-radio-group>
  164. </div>
  165. </div>
  166. </div>
  167. </template>
  168. </ventBox1>
  169. <ventBox1 class="vent-margin-t-10">
  170. <template #title>
  171. <div>泵站监测详情</div>
  172. </template>
  173. <template #container>
  174. <ListItem
  175. v-for="(item, index) in modelMonitor"
  176. :key="index"
  177. class="w-100% mb-5px"
  178. :value="selectData[item.code]"
  179. :label="item.title"
  180. label-width="250px"
  181. />
  182. </template>
  183. </ventBox1>
  184. </div>
  185. <!-- <div class="item-box" >
  186. <LivePlayer id="fm-player1" style="height: 250px;" ref="player1" :videoUrl="flvURL1()" muted live loading controls />
  187. </div> -->
  188. </div>
  189. <div ref="playerRef" class="player-box"></div>
  190. </div>
  191. <DetailModal @register="register" :device-type="deviceType" :device-id="deviceId" />
  192. <PasswordModal
  193. :modal-is-show="passwordModalIsShow"
  194. modal-title="密码检验"
  195. :modal-type="handlerType"
  196. @handle-ok="handleOK"
  197. @handle-cancel="handleCancel"
  198. />
  199. </template>
  200. <script setup lang="ts">
  201. import { ref, onMounted, onUnmounted, reactive, defineProps, watch, inject, nextTick, onBeforeUnmount } from 'vue';
  202. import ventBox1 from '/@/components/vent/ventBox1.vue';
  203. import { setModelType, playAnimate } from '../gasPump.threejs';
  204. import ListItem from '@/views/vent/gas/components/list/listItem.vue';
  205. import {
  206. stateWarningHeader,
  207. valveWarningState,
  208. pumpMonitorData,
  209. waterPumpData,
  210. dewateringPumpData,
  211. modelMonitor,
  212. modelMonitorTags,
  213. valveCtrlType,
  214. } from '../gasPump.data';
  215. import { list } from '../gasPump.api';
  216. import { SvgIcon } from '/@/components/Icon';
  217. import { formatNum } from '/@/utils/ventutil';
  218. import DetailModal from './DetailModal.vue';
  219. import { useModal } from '/@/components/Modal';
  220. import { deviceControlApi } from '/@/api/vent/index';
  221. import PasswordModal from '../../comment/components/PasswordModal.vue';
  222. import { message } from 'ant-design-vue';
  223. import fourBorderBg from '/@/components/vent/fourBorderBg.vue';
  224. import { useCamera } from '/@/hooks/system/useCamera';
  225. const globalConfig = inject('globalConfig');
  226. const props = defineProps({
  227. deviceId: {
  228. type: String,
  229. require: true,
  230. },
  231. deviceType: {
  232. type: String,
  233. require: true,
  234. },
  235. });
  236. const [register, { openModal }] = useModal();
  237. const loading = ref(false);
  238. const tabActiveKey = ref(1);
  239. const passwordModalIsShow = ref(false);
  240. const handlerType = ref('');
  241. const playerRef = ref();
  242. // 监测数据
  243. const selectData = ref({
  244. pump1: false,
  245. pump2: false,
  246. pump3: false,
  247. pump4: false,
  248. waterPump1: false,
  249. waterPump2: false,
  250. waterPump3: false,
  251. waterPump4: false,
  252. inValve1: false,
  253. outValve1: false,
  254. inValve2: false,
  255. outValve2: false,
  256. inValve3: false,
  257. outValve3: false,
  258. inValve4: false,
  259. outValve4: false,
  260. jxmsqh: '1',
  261. ykjdqh: '1',
  262. FlowSensor_InputFlux: '-',
  263. deviceType: '',
  264. });
  265. const { getCamera, removeCamera } = useCamera();
  266. // https获取监测数据
  267. let timer: null | NodeJS.Timeout = null;
  268. function getMonitor(flag?) {
  269. if (Object.prototype.toString.call(timer) === '[object Null]') {
  270. return new Promise((resolve) => {
  271. timer = setTimeout(
  272. async () => {
  273. if (props.deviceId) {
  274. const data = await getDataSource(props.deviceId);
  275. selectData.value = data;
  276. playAnimate(data);
  277. // Object.assign(selectData, data);
  278. }
  279. if (timer) {
  280. timer = null;
  281. }
  282. resolve(null);
  283. await getMonitor();
  284. loading.value = false;
  285. },
  286. flag ? 0 : 1000
  287. );
  288. });
  289. }
  290. }
  291. async function getDataSource(systemID) {
  292. const res = await list({ devicetype: props.deviceType, ids: systemID });
  293. const result = res.msgTxt[0]['datalist'][0];
  294. Object.assign(result, result['readData']);
  295. return result;
  296. }
  297. function handler(passWord, paramcode) {
  298. let value = '';
  299. if (paramcode == 'ykjdqh') {
  300. value = selectData.value['ykjdqh'] == '1' ? '2' : '1';
  301. }
  302. if (paramcode == 'jxmsqh') {
  303. value = selectData.value['jxmsqh'] == '1' ? '2' : '1';
  304. }
  305. const data = {
  306. deviceid: selectData.value['deviceID'],
  307. devicetype: selectData.value['deviceType'],
  308. paramcode: paramcode,
  309. password: passWord,
  310. value: value,
  311. };
  312. deviceControlApi(data)
  313. .then((res) => {
  314. if (globalConfig.History_Type == 'remote') {
  315. message.success('指令已下发至生产管控平台成功!');
  316. } else {
  317. message.success('指令已下发成功!');
  318. }
  319. })
  320. .catch((err) => {
  321. message.success('控制异常');
  322. });
  323. }
  324. function changeCtr(e) {
  325. if (e.target.value == 1) {
  326. // 就地
  327. handlerType.value = 'jxmsqh';
  328. } else if (e.target.value == 2) {
  329. // 远程
  330. handlerType.value = 'jxmsqh';
  331. }
  332. passwordModalIsShow.value = true;
  333. }
  334. function changeMode(e) {
  335. if (e.target.value == 1) {
  336. // 检修开
  337. handlerType.value = 'ykjdqh';
  338. } else if (e.target.value == 2) {
  339. // 检修关
  340. handlerType.value = 'ykjdqh';
  341. }
  342. passwordModalIsShow.value = true;
  343. }
  344. function handlerFn(paramcode) {
  345. handlerType.value = paramcode;
  346. passwordModalIsShow.value = true;
  347. }
  348. function handleOK(passWord, handlerState) {
  349. handler(passWord, handlerState);
  350. passwordModalIsShow.value = false;
  351. handlerType.value = '';
  352. }
  353. function handleCancel() {
  354. passwordModalIsShow.value = false;
  355. handlerType.value = '';
  356. }
  357. // 喷粉操作
  358. function handlerDevice(code, data) {}
  359. watch(
  360. () => props.deviceType,
  361. () => {
  362. removeCamera();
  363. nextTick(async () => {
  364. if (props.deviceType == 'pump_over') {
  365. setModelType('gasPump');
  366. } else if (props.deviceType?.startsWith('pump_under') || props.deviceType == 'pump_n12m2pq') {
  367. setModelType('gasPumpUnder');
  368. }
  369. });
  370. }
  371. );
  372. watch(
  373. () => props.deviceId,
  374. async (deviceID) => {
  375. removeCamera();
  376. if (deviceID) await getCamera(deviceID, playerRef.value);
  377. }
  378. );
  379. onMounted(async () => {
  380. timer = null;
  381. await getMonitor(true);
  382. // if (selectData && selectData['deviceID']) await getCamera(selectData['deviceID'], playerRef.value);
  383. });
  384. onBeforeUnmount(() => {
  385. removeCamera();
  386. });
  387. onUnmounted(() => {
  388. removeCamera();
  389. if (timer) {
  390. clearTimeout(timer);
  391. timer = undefined;
  392. }
  393. });
  394. </script>
  395. <style lang="less" scoped>
  396. @import '/@/design/theme.less';
  397. @import '/@/design/vent/modal.less';
  398. @import '../../comment/less/workFace.less';
  399. @ventSpace: zxm;
  400. .elementContent {
  401. :deep(.main-container) {
  402. display: flex;
  403. flex-wrap: wrap;
  404. width: 690px;
  405. padding: 10px 12px 10px 15px;
  406. border: 1px solid #d3e1ff33;
  407. background-color: #061c2a55;
  408. box-shadow: 0 0 15px #3b567f55;
  409. background-color: #38383833;
  410. .gas-monitor-row {
  411. display: flex;
  412. flex-direction: row;
  413. flex-wrap: wrap;
  414. color: #fff;
  415. line-height: 32px;
  416. .title {
  417. width: 250px;
  418. color: #baeaff;
  419. }
  420. .value {
  421. width: 80px;
  422. color: #efae05;
  423. }
  424. }
  425. }
  426. }
  427. .modal-monitor-box {
  428. background-color: #000;
  429. color: #fff;
  430. padding: 0 5px;
  431. display: flex;
  432. align-items: center;
  433. justify-content: center;
  434. .signal-round {
  435. margin-left: 5px;
  436. }
  437. }
  438. .device-state {
  439. width: 100%;
  440. position: absolute;
  441. top: 20px;
  442. color: #e90000;
  443. display: flex;
  444. justify-content: center;
  445. font-size: 20px;
  446. }
  447. .lr {
  448. margin-top: 0 !important;
  449. }
  450. .left-box {
  451. width: 360px !important;
  452. direction: rtl;
  453. overflow-y: auto;
  454. overflow-x: hidden;
  455. height: calc(100% - 60px);
  456. margin-top: 30px !important;
  457. .left-container {
  458. direction: ltr;
  459. }
  460. }
  461. .right-box {
  462. width: 350px !important;
  463. overflow-y: auto;
  464. overflow-x: hidden;
  465. .environment-monitor {
  466. .item {
  467. flex: 1;
  468. margin: 0 5px;
  469. .title {
  470. color: #7ae5ff;
  471. text-align: center;
  472. margin-bottom: 2px;
  473. }
  474. .num {
  475. width: 100%;
  476. height: 30px;
  477. text-align: center;
  478. border-top: 2px solid #50c8fc;
  479. border-radius: 4px;
  480. background-image: linear-gradient(#2e4d5955, #3780b499, #2e465955);
  481. }
  482. }
  483. }
  484. .pool-box {
  485. width: 327px;
  486. height: 65px;
  487. padding: 0 5px;
  488. background: url('/@/assets/images/vent/pump1.png') no-repeat;
  489. background-size: cover;
  490. background-origin: content-box;
  491. margin-top: 2px;
  492. .num {
  493. color: aqua;
  494. }
  495. .center {
  496. padding-right: 5px;
  497. }
  498. }
  499. }
  500. .player-box {
  501. position: absolute;
  502. height: 100%;
  503. width: 100%;
  504. padding: 0 20px 0 20px;
  505. z-index: 9999;
  506. display: flex;
  507. align-items: end;
  508. bottom: 80px;
  509. :deep(#LivePlayerBox) {
  510. display: flex;
  511. justify-content: end;
  512. }
  513. }
  514. .control-group {
  515. display: flex;
  516. // justify-content: space-around;
  517. flex-wrap: wrap;
  518. margin: 4px 0;
  519. .control-item {
  520. display: flex;
  521. flex-direction: column;
  522. justify-content: center;
  523. align-items: center;
  524. padding: 1px 10px;
  525. .control-item-title {
  526. color: #a6dce9;
  527. position: relative;
  528. }
  529. .control-item-state {
  530. width: 86px;
  531. height: 31px;
  532. background: url('/@/assets/images/vent/control-switch-bg1.png');
  533. display: flex;
  534. justify-content: center;
  535. align-items: center;
  536. color: #fff;
  537. }
  538. .button-box {
  539. position: relative;
  540. padding: 5px;
  541. border: 1px transparent solid;
  542. background-clip: border-box;
  543. border-radius: 5px;
  544. margin-left: 8px;
  545. }
  546. .a-button {
  547. pointer-events: auto;
  548. }
  549. &::v-deep .a-button--mini {
  550. padding: 6px 10px;
  551. }
  552. &::v-deep .a-button--mini.is-round {
  553. padding: 6px 10px;
  554. }
  555. }
  556. }
  557. .input-box {
  558. width: calc(100%);
  559. display: flex;
  560. flex-direction: row !important;
  561. flex-wrap: wrap !important;
  562. .input-item {
  563. width: calc(50% - 8px);
  564. padding: 0 2px;
  565. &:nth-child(2n) {
  566. margin-left: 4px;
  567. }
  568. }
  569. }
  570. .btn-group {
  571. display: flex;
  572. justify-content: space-around;
  573. .btn-item {
  574. width: 82px;
  575. text-align: center;
  576. }
  577. }
  578. .top-btn {
  579. .btn-group {
  580. margin-bottom: 8px;
  581. .btn-item {
  582. width: calc(50% - 16px);
  583. margin: 0 4px;
  584. }
  585. }
  586. .control-item {
  587. margin-left: 10px;
  588. margin-bottom: 8px;
  589. display: flex;
  590. .control-title {
  591. width: 150px;
  592. color: var(--vent-font-action-link);
  593. }
  594. }
  595. }
  596. .state-header {
  597. display: flex;
  598. color: var(--vent-font-action-link);
  599. .header-item {
  600. width: 25%;
  601. text-align: center;
  602. }
  603. }
  604. .device-row {
  605. display: flex;
  606. margin-top: 10px;
  607. .state {
  608. width: 25%;
  609. text-align: center;
  610. font-size: 13px;
  611. }
  612. }
  613. :deep(.@{ventSpace}-tabs-tabpane-active) {
  614. overflow: auto;
  615. }
  616. :deep(.list-item__background) {
  617. background-image: linear-gradient(to right, #39deff15, #3977e500) !important;
  618. line-height: 30px !important;
  619. height: 30px !important;
  620. }
  621. </style>