balancePressHomeSP.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <template>
  2. <a-spin tip="Loading..." :spinning="loading">
  3. <div class="monitor-container">
  4. <div class="lr left-box">
  5. <Transition enter-active-class="animate__animated animate__fadeInLeft" leave-active-class="animate__animated animate__fadeOutLeft">
  6. <ventBox1 v-if="showModules">
  7. <template #title>
  8. <div>均压与低氧参数监测与设置</div>
  9. </template>
  10. <template #container>
  11. <div class="vent-flex-row-between auto-control mt-10px mb-10px">
  12. <div class="title">自动调节:</div>
  13. <a-radio-group :value="avePressSetting.isAuto" name="radioGroup" @change="changeAvePressState($event, 'isAuto')">
  14. <a-radio :value="false">关闭</a-radio>
  15. <a-radio :value="true">开启</a-radio>
  16. </a-radio-group>
  17. </div>
  18. <div class="vent-flex-row-between auto-control mt-10px mb-10px">
  19. <div class="title">调节类型:</div>
  20. <a-radio-group :value="avePressSetting.controlType" name="radioGroup" @change="changeAvePressState($event, 'controlType')">
  21. <a-radio value="co">CO</a-radio>
  22. <a-radio value="pressure">压差</a-radio>
  23. </a-radio-group>
  24. </div>
  25. <div>
  26. <!-- <div class="divider-line">开始条件</div>
  27. <div v-for="(item, index) in settingParam1" class="input-item" :key="index">
  28. <div class="title">{{ item.title }}:</div>
  29. <a-input-number class="input-value" v-model:value="formData[item.code]" placeholder="" />
  30. <div class="unit">{{ item.unit }}</div>
  31. </div> -->
  32. <div class="divider-line"></div>
  33. <div v-for="(item, index) in settingParam5" class="input-item" :key="index">
  34. <div class="title">{{ item.title }}:</div>
  35. <a-input-number class="input-value" v-model:value="avePressSetting[item.code]" placeholder="" :disabled="settingFormDisabled" />
  36. <div class="unit">&nbsp;{{ item.unit }}</div>
  37. </div>
  38. <!-- <div class="divider-line">结束时间</div>
  39. <div v-for="(item, index) in settingParam3" class="input-item" :key="index">
  40. <div class="title">{{ item.title }}:</div>
  41. <a-input-number class="input-value" v-model:value="formData[item.code]" placeholder="" />
  42. <div class="unit">{{ item.unit }}</div>
  43. </div> -->
  44. </div>
  45. <div class="btn-box flex" style="text-align: center">
  46. <div class="btn btn1 flex-1" @click="editSettingForm">{{ settingFormDisabled ? '编辑' : '取消' }}</div>
  47. <div class="btn btn1 flex-1" @click="submitSettingForm">提交</div>
  48. </div>
  49. </template>
  50. </ventBox1>
  51. </Transition>
  52. </div>
  53. <ModuleCommon
  54. v-for="(cfg, index) in configs"
  55. :key="`svvmbcb${index}`"
  56. :show-style="cfg.showStyle"
  57. :module-data="cfg.moduleData"
  58. :module-name="cfg.moduleName"
  59. :device-type="cfg.deviceType"
  60. :data="selectData"
  61. :visible="showModules"
  62. />
  63. </div>
  64. <PasswordModal z-index="2000" :modal-is-show="modalVisible" modal-title="提交" @handle-ok="handleResolve" @handle-cancel="handleReject" />
  65. <UpdatePassword @register="updatePwdRegister" @submit="handleChangePassword" />
  66. <!-- <BasicModal title="风门状态监测" :mask="false" :bodyStyle="{ height: '50px' }" style="top: 20px" :show-ok-btn="false" @register="warnRegister2">
  67. {{ warnModalText2 }}
  68. </BasicModal>
  69. <BasicModal
  70. title="压差状态监测"
  71. :mask="false"
  72. :bodyStyle="{ height: '50px' }"
  73. centered
  74. ok-text="下发联动控制指令"
  75. @ok="autoControl"
  76. @register="warnRegister1"
  77. >
  78. {{ warnModalText1 }}
  79. </BasicModal>
  80. <BasicModal title="局扇状态监测" :mask="false" :bodyStyle="{ height: '50px' }" style="top: 420px" :show-ok-btn="false" @register="warnRegister3">
  81. {{ warnModalText3 }}
  82. </BasicModal> -->
  83. <div class="switch-button icon-goto right-10px top-70px" :class="{ 'right-390px': showModules }" @click="showModules = !showModules"></div>
  84. <!-- <div v-else class="switch-button icon-goto right-10px top-70px" @click="showModules = true"></div> -->
  85. </a-spin>
  86. </template>
  87. <script setup lang="ts">
  88. import { ref, onMounted, onUnmounted, defineProps, h } from 'vue';
  89. import { mountedThree, destroy, setModelType, updateText, play } from '../balancePress.threejs';
  90. import { list } from '../balancePress.api';
  91. import ModuleCommon from '../../../home/configurable/components/ModuleCommon.vue';
  92. import { useInitConfigs } from '../../../home/configurable/hooks/useInit';
  93. import { useGlobSetting } from '/@/hooks/setting';
  94. import { settingParam5 } from '../balancePress.data';
  95. // import { Modal } from 'ant-design-vue';
  96. import ventBox1 from '/@/components/vent/ventBox1.vue';
  97. import PasswordModal from '../../comment/components/PasswordModal.vue';
  98. import UpdatePassword from '../../comment/components/UpdatePassword.vue';
  99. import { useModal } from '/@/components/Modal';
  100. // import { connectWebSocket, onWebSocket } from '/@/hooks/web/useWebSocket';
  101. // import { getToken } from '/@/utils/auth';
  102. // import { useUserStore } from '/@/store/modules/user';
  103. import { usePressControlSP } from '../hooks/useControl';
  104. import { Modal } from 'ant-design-vue';
  105. import dayjs from 'dayjs';
  106. import { connectWebSocket, onWebSocket } from '/@/hooks/web/useWebSocket';
  107. import { useUserStore } from '/@/store/modules/user';
  108. import { getToken } from '/@/utils/auth';
  109. // import dayjs from 'dayjs';
  110. // import { Config } from '../../../deviceManager/configurationTable/types';
  111. const props = defineProps({
  112. deviceId: {
  113. type: String,
  114. require: true,
  115. },
  116. });
  117. const { sysOrgCode } = useGlobSetting();
  118. const loading = ref(false);
  119. const showModules = ref(true);
  120. // 监测数据
  121. const selectData = ref();
  122. // https获取监测数据
  123. let timer: any = null;
  124. function getMonitor(flag?) {
  125. if (Object.prototype.toString.call(timer) === '[object Null]') {
  126. timer = setTimeout(
  127. async () => {
  128. if (props.deviceId) {
  129. const data = await getDataSource(props.deviceId);
  130. // Object.assign(selectData, data);
  131. updateText(selectData);
  132. selectData.value = data;
  133. }
  134. if (timer) {
  135. timer = null;
  136. }
  137. await getMonitor();
  138. },
  139. flag ? 0 : 1000
  140. );
  141. }
  142. }
  143. async function getDataSource(systemID) {
  144. const res = await list({ devicetype: 'sys', systemID });
  145. const result = Array.from(res.msgTxt).reduce(
  146. (obj: any, e: any) => {
  147. obj[e.type] = e;
  148. return obj;
  149. },
  150. {
  151. /** 用于归类fanlocal */
  152. fanlocal: { datalist: [] },
  153. /** 用于归类gate */
  154. gate: { datalist: [] },
  155. /** 用于归类window */
  156. window: { datalist: [] },
  157. /** 用于归类work_surface */
  158. work_surface: { datalist: [] },
  159. others: { datalist: [] },
  160. }
  161. );
  162. return result;
  163. }
  164. const {
  165. avePressSetting,
  166. // avePressLinkage,
  167. // gateLinkage,
  168. formData,
  169. getAvePress,
  170. changePassword,
  171. // linkageControl,
  172. settingControl,
  173. autoControl,
  174. cancelControl,
  175. } = usePressControlSP();
  176. const modalVisible = ref(false);
  177. const { configs, fetchConfigs } = useInitConfigs();
  178. const [updatePwdRegister, { closeModal, setModalProps }] = useModal();
  179. function handleChangePassword(values) {
  180. setModalProps({ confirmLoading: true });
  181. changePassword(values).finally(() => {
  182. setModalProps({ confirmLoading: false });
  183. closeModal();
  184. });
  185. }
  186. // function changeIsAuto({ target }, id) {
  187. // formData.value.isAuto = target.value;
  188. // modalVisible.value = true;
  189. // resolver = (password) => {
  190. // linkageControl(
  191. // { password, id },
  192. // {
  193. // isAuto: formData.value.isAuto,
  194. // }
  195. // ).finally(() => {
  196. // modalVisible.value = false;
  197. // });
  198. // };
  199. // }
  200. function changeAvePressState({ target }, key) {
  201. formData.value.temp = target.value;
  202. modalVisible.value = true;
  203. resolver = (password) => {
  204. settingControl(
  205. { password, id: avePressSetting.value.id },
  206. {
  207. [key]: formData.value.temp,
  208. }
  209. ).finally(() => {
  210. modalVisible.value = false;
  211. });
  212. };
  213. }
  214. // function submitLinkageForm(password) {}
  215. function submitSettingForm() {
  216. modalVisible.value = true;
  217. resolver = (password) => {
  218. settingControl({ password, id: avePressSetting.value.id }, avePressSetting.value).finally(() => {
  219. modalVisible.value = false;
  220. settingFormDisabled.value = true;
  221. });
  222. };
  223. }
  224. let resolver: any = null;
  225. let rejecter: any = null;
  226. function handleResolve(password) {
  227. if (resolver) {
  228. resolver(password);
  229. } else {
  230. modalVisible.value = false;
  231. }
  232. resolver = null;
  233. rejecter = null;
  234. }
  235. function handleReject() {
  236. if (rejecter) {
  237. rejecter();
  238. } else {
  239. modalVisible.value = false;
  240. }
  241. resolver = null;
  242. rejecter = null;
  243. }
  244. const settingFormDisabled = ref(true);
  245. function editSettingForm() {
  246. settingFormDisabled.value = !settingFormDisabled.value;
  247. /** 如果取消了编辑模式,那么需要重置表单 */
  248. if (settingFormDisabled.value) {
  249. getAvePress();
  250. }
  251. }
  252. // const [warnRegister1, warnModal1] = useModal();
  253. // const [warnRegister2, warnModal2] = useModal();
  254. // const [warnRegister3, warnModal3] = useModal();
  255. let warnModal1: { destroy: () => void } | null = null;
  256. let warnModal2: { destroy: () => void } | null = null;
  257. let warnModal3: { destroy: () => void } | null = null;
  258. // const warnModalText1 = ref('');
  259. // const warnModalText2 = ref('');
  260. // const warnModalText3 = ref('');
  261. // 初始化 WebSocket
  262. function initWebSocket() {
  263. const token = getToken();
  264. const userStore = useUserStore();
  265. const glob = useGlobSetting();
  266. // WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
  267. const url = `${glob.wsUrl?.replace('https://', 'wss://').replace('http://', 'ws://')}/websocket/${userStore.getUserInfo.id}?token=${token}`;
  268. connectWebSocket(url);
  269. onWebSocket((data: any) => {
  270. if (data.cmd !== 'topic' || data.topic !== 'warn') return;
  271. if (!data.msgTxt) return;
  272. const { info = '', type = '', avgPressureLogId, date } = JSON.parse(data.msgTxt);
  273. const datestr = dayjs(date).format('YYYY-MM-DD HH:mm:ss');
  274. switch (type) {
  275. case 'o2':
  276. // 如果已经存在报警模态框,则不需要处理
  277. if (warnModal1) break;
  278. warnModal1 = Modal.confirm({
  279. title: data.msgTitle,
  280. content: h('div', { style: { color: '#fff' } }, [h('p', datestr), h('p', info)]),
  281. centered: true,
  282. okText: '下发调节指令',
  283. mask: true,
  284. class: 'balancePress',
  285. onOk() {
  286. // 点击确定按钮后,执行调节指令。调节指令需要确认密码,所以需要先弹出密码框
  287. return new Promise((resolve, reject) => {
  288. modalVisible.value = true;
  289. // 弹出密码框后,输入密码并验证成功则关闭密码弹窗和报警弹窗,失败则关闭密码弹窗但不关闭报警弹窗
  290. resolver = (password) => {
  291. autoControl({ password, id: avePressSetting.value.id }, { avgPressLogId: avgPressureLogId })
  292. .then(() => {
  293. modalVisible.value = false;
  294. resolve(true);
  295. warnModal1?.destroy();
  296. warnModal1 = null;
  297. })
  298. .catch(() => {
  299. modalVisible.value = false;
  300. reject();
  301. });
  302. };
  303. // 弹出密码框取消操作则关闭密码弹窗但不关闭报警弹窗
  304. rejecter = () => {
  305. modalVisible.value = false;
  306. reject();
  307. };
  308. });
  309. },
  310. onCancel() {
  311. return cancelControl({}, { avgPressLogId: avgPressureLogId }).finally(() => {
  312. warnModal1?.destroy();
  313. warnModal1 = null;
  314. });
  315. },
  316. });
  317. // warnModalText1.value = info;
  318. // warnModal1.openModal();
  319. break;
  320. case 'pressure':
  321. // warnModalText1.value = info;
  322. // warnModal1.openModal();
  323. if (warnModal1) break;
  324. warnModal1 = Modal.confirm({
  325. title: data.msgTitle,
  326. content: h('div', { style: { color: '#fff' } }, [h('p', datestr), h('p', info)]),
  327. centered: true,
  328. okText: '下发调节指令',
  329. mask: true,
  330. class: 'balancePress',
  331. onOk() {
  332. // 点击确定按钮后,执行调节指令。调节指令需要确认密码,所以需要先弹出密码框
  333. return new Promise((resolve, reject) => {
  334. modalVisible.value = true;
  335. // 弹出密码框后,输入密码并验证成功则关闭密码弹窗和报警弹窗,失败则关闭密码弹窗但不关闭报警弹窗
  336. resolver = (password) => {
  337. autoControl({ password, id: avePressSetting.value.id }, { avgPressLogId: avgPressureLogId })
  338. .then(() => {
  339. modalVisible.value = false;
  340. resolve(true);
  341. warnModal1?.destroy();
  342. warnModal1 = null;
  343. })
  344. .catch(() => {
  345. modalVisible.value = false;
  346. reject();
  347. });
  348. };
  349. // 弹出密码框取消操作则关闭密码弹窗但不关闭报警弹窗
  350. rejecter = () => {
  351. modalVisible.value = false;
  352. reject();
  353. };
  354. });
  355. },
  356. onCancel() {
  357. return cancelControl({}, { avgPressLogId: avgPressureLogId }).finally(() => {
  358. warnModal1?.destroy();
  359. warnModal1 = null;
  360. });
  361. },
  362. });
  363. break;
  364. case 'gate':
  365. if (warnModal2) break;
  366. warnModal2 = Modal.warning({
  367. title: data.msgTitle,
  368. content: info,
  369. mask: true,
  370. class: 'balancePress',
  371. onOk: () => {
  372. warnModal2?.destroy();
  373. warnModal2 = null;
  374. },
  375. });
  376. break;
  377. case 'fansys':
  378. if (warnModal3) break;
  379. warnModal3 = Modal.warning({
  380. title: data.msgTitle,
  381. content: info,
  382. mask: true,
  383. class: 'balancePress',
  384. style: 'top: 700px',
  385. onOk: () => {
  386. warnModal3?.destroy();
  387. warnModal3 = null;
  388. },
  389. });
  390. break;
  391. default:
  392. break;
  393. }
  394. });
  395. }
  396. onMounted(() => {
  397. fetchConfigs('balancePressHome');
  398. initWebSocket();
  399. getAvePress();
  400. loading.value = true;
  401. mountedThree().then(async () => {
  402. if (sysOrgCode === 'jsnyspmy') {
  403. await setModelType('balancePressSp'); //balancePressBase
  404. } else {
  405. await setModelType('balancePressTun'); //balancePressBase
  406. }
  407. loading.value = false;
  408. timer = null;
  409. await getMonitor(true);
  410. play('startSmoke', 'top', 30, 'open', 0);
  411. });
  412. // loading.value = false;
  413. // timer = null;
  414. // getMonitor(true);
  415. });
  416. onUnmounted(() => {
  417. destroy();
  418. if (timer) {
  419. clearTimeout(timer);
  420. }
  421. });
  422. </script>
  423. <style lang="less" scoped>
  424. @import '/@/design/vent/modal.less';
  425. @import '../../comment/less/workFace.less';
  426. @ventSpace: zxm;
  427. .monitor-container {
  428. margin-top: 60px;
  429. }
  430. .switch-button {
  431. width: 34px;
  432. height: 34px;
  433. position: fixed;
  434. // right: 5px;
  435. // bottom: 300px;
  436. z-index: 1000;
  437. background-repeat: no-repeat;
  438. background-size: 100% 100%;
  439. pointer-events: auto;
  440. transition: right 1s;
  441. }
  442. .icon-goto {
  443. --image-monitor-goto: url('/@/assets/images/company/monitor-goto.png');
  444. background-image: var(--image-monitor-goto);
  445. }
  446. .divider-line {
  447. border-bottom: 1px solid white;
  448. }
  449. </style>
  450. <style>
  451. /* .balancePress .zxm-modal-confirm-title {
  452. font-size: 20px;
  453. } */
  454. .balancePress .zxm-modal-confirm-content {
  455. font-size: 22px;
  456. }
  457. </style>