gasPumpHomeBet.vue 17 KB

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