vent-detail.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. <template>
  2. <view class="vent-detail">
  3. <u-tabs
  4. class="devic-box-tab"
  5. :current="PageCur"
  6. :list="tabList"
  7. @click="NavChange"
  8. ></u-tabs>
  9. <view class="vent-content">
  10. <view class="top-area">
  11. <view class="top-title">
  12. <view style="font-weight: bold">{{ mainTitle || "--" }}</view>
  13. <view class="title-icon">
  14. <image
  15. src="/static/model/alarmTrue.svg"
  16. alt=""
  17. class="icon-style"
  18. />
  19. <text class="icon-text">低风险</text>
  20. </view>
  21. </view>
  22. <view class="top-card">
  23. <view class="card-box" v-for="(item, index) in cardList" :key="index">
  24. <view class="box-item">
  25. <view class="box-val">{{ item.value }}</view>
  26. <view class="box-name">{{ item.name }}</view>
  27. </view>
  28. </view>
  29. </view>
  30. <view class="top-card1">
  31. <view
  32. class="card-box"
  33. v-for="(item, index) in cardList1"
  34. :key="index"
  35. >
  36. <view class="box-item">
  37. <view class="box-val">{{ item.value }}</view>
  38. <view class="box-name">{{ item.name }}</view>
  39. </view>
  40. </view>
  41. </view>
  42. </view>
  43. <view class="center-area">
  44. <view class="top-title">
  45. <view style="font-weight: bold">通风信息状态监测</view>
  46. </view>
  47. <view class="echartBox">
  48. <canvas
  49. id="myChart"
  50. :style="{ width: '100%', height: '180px' }"
  51. ></canvas>
  52. </view>
  53. </view>
  54. <view class="bot-area">
  55. <view class="top-title">
  56. <view style="font-weight: bold">通风监控测点信息</view>
  57. </view>
  58. <view class="bot-content">
  59. <view class="card-b" v-for="(item, index) in cardListTf" :key="index">
  60. <div class="item-l">
  61. <div class="label-l">{{ item.label }}</div>
  62. <div class="value-l">{{ item.value }}</div>
  63. </div>
  64. <div class="item-r">
  65. <div
  66. class="content-r"
  67. v-for="(items, ind) in item.listR"
  68. :key="ind"
  69. >
  70. <span>{{ `${items.label} : ` }}</span>
  71. <span
  72. :class="{
  73. 'status-f': items.value == 1,
  74. 'status-l': items.value == 0,
  75. }"
  76. >{{ `${items.value}${items.dw}` }}</span
  77. >
  78. </div>
  79. </div>
  80. </view>
  81. </view>
  82. </view>
  83. </view>
  84. </view>
  85. </template>
  86. <script>
  87. import api from "@/api/api";
  88. export default {
  89. name: "ventDetail",
  90. props: {},
  91. watch: {},
  92. data() {
  93. return {
  94. mainTitle: "",
  95. myChart: null,
  96. timer: "",
  97. PageCur: "0",
  98. tabList: [],
  99. cardList: [
  100. { name: "进风量(m³/min)", value: 0 },
  101. { name: "回风量(m³/min)", value: 0 },
  102. { name: "需风量(m³/min)", value: 0 },
  103. ],
  104. cardList1: [
  105. { name: "O₂(%)", value: 0 },
  106. { name: "CO(%)", value: 0 },
  107. ],
  108. //echarts图表数据
  109. maxY: 0,
  110. xData: [],
  111. yDataJ: [],
  112. yDataH: [],
  113. yDataX: [],
  114. cardListTf: [],
  115. };
  116. },
  117. mounted() {
  118. this.getTabList();
  119. // than.initChart();
  120. this.getWindDeviceList();
  121. },
  122. beforeDestroy() {
  123. this.myChart.clear();
  124. this.myChart.dispose();
  125. this.timer = null;
  126. clearTimeout(this.timer);
  127. },
  128. methods: {
  129. NavChange: function (item) {
  130. clearTimeout(this.timer);
  131. this.PageCur = item.index;
  132. this.mainTitle = this.tabList[this.PageCur].name;
  133. this.getMonitor(this.tabList[this.PageCur].deviceID, true);
  134. },
  135. getMonitor(deviceID, flag) {
  136. let than = this;
  137. than.timer = setTimeout(
  138. async () => {
  139. await than.getSysWarnList(deviceID, "vent");
  140. if (than.timer) {
  141. than.timer = null;
  142. }
  143. than.getMonitor(deviceID);
  144. },
  145. flag ? 0 : 3000
  146. );
  147. },
  148. //获取顶部tab选项数据
  149. getTabList() {
  150. new Promise((resolve, reject) => {
  151. api
  152. .sysTypeWarn({ type: "vent" })
  153. .then((response) => {
  154. if (response.data.code == 200 && response.data.result.length != 0) {
  155. let result = response.data.result;
  156. this.tabList = result.map((el) => {
  157. //lxh
  158. return {
  159. name: el.deviceName,
  160. warn: "低风险",
  161. deviceID: el.deviceID,
  162. strtype: el.deviceType,
  163. };
  164. });
  165. this.mainTitle = this.tabList[0].name;
  166. this.getMonitor(this.tabList[0].deviceID, true);
  167. } else {
  168. reject(response);
  169. }
  170. })
  171. .catch((error) => {
  172. console.log("catch===>response", response);
  173. reject(error);
  174. });
  175. });
  176. },
  177. formatRoundNum(num) {
  178. let interger = Math.ceil(num);
  179. let leng = String(interger).length;
  180. return (
  181. Math.ceil(interger / Math.pow(10, leng - 1)) * Math.pow(10, leng - 1)
  182. );
  183. },
  184. //初始化echarts实例
  185. initChart() {
  186. let canvas = document.getElementById("myChart");
  187. this.myChart = this.$echarts.init(canvas);
  188. let option = {
  189. grid: {
  190. top: "24%",
  191. left: "0%",
  192. bottom: "6%",
  193. right: "2%",
  194. containLabel: true,
  195. },
  196. tooltip: {
  197. trigger: "item",
  198. backgroundColor: "rgba(0, 0, 0, .6)",
  199. textStyle: {
  200. color: "#fff",
  201. fontSize: 12,
  202. },
  203. },
  204. legend: {
  205. // align: 'center',
  206. right: "0%",
  207. top: "0%",
  208. type: "plain",
  209. textStyle: {
  210. color: "#0eb4fc",
  211. fontSize: 12,
  212. },
  213. // icon:'rect',
  214. itemGap: 25,
  215. itemWidth: 20,
  216. icon: "path://M0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v0a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z",
  217. data: [
  218. {
  219. name: "进风量",
  220. },
  221. {
  222. name: "回风量",
  223. },
  224. {
  225. name: "需风量",
  226. },
  227. ],
  228. },
  229. xAxis: [
  230. {
  231. type: "category",
  232. boundaryGap: false,
  233. axisLabel: {
  234. // formatter: '{value}',
  235. fontSize: 12,
  236. margin: 10,
  237. textStyle: {
  238. color: "#b3b8cc",
  239. },
  240. // formatter: function (params) {
  241. // let newParamsName = ref('') // 最终拼接成的字符串
  242. // let paramsNameNumber = ref(params.length) // 实际标签的个数
  243. // let provideNumber = ref(10) // 每行能显示的字的个数
  244. // let rowNumber = Math.ceil(paramsNameNumber.value / provideNumber.value) // 换行的话,需要显示几行,向上取整
  245. // /**
  246. // * 判断标签的个数是否大于规定的个数, 如果大于,则进行换行处理 如果不大于,即等于或小于,就返回原标签
  247. // */
  248. // // 条件等同于rowNumber>1
  249. // if (paramsNameNumber.value > provideNumber.value) {
  250. // /** 循环每一行,p表示行 */
  251. // for (var p = 0; p < rowNumber; p++) {
  252. // var tempStr = '' // 表示每一次截取的字符串
  253. // var start = p * provideNumber.value // 开始截取的位置
  254. // var end = start + provideNumber.value // 结束截取的位置
  255. // // 此处特殊处理最后一行的索引值
  256. // if (p == rowNumber - 1) {
  257. // // 最后一次不换行
  258. // tempStr = params.substring(start, paramsNameNumber.value)
  259. // } else {
  260. // // 每一次拼接字符串并换行
  261. // tempStr = params.substring(start, end) + '\n'
  262. // }
  263. // newParamsName.value += tempStr // 最终拼成的字符串
  264. // }
  265. // } else {
  266. // // 将旧标签的值赋给新标签
  267. // newParamsName.value = params
  268. // }
  269. // //将最终的字符串返回
  270. // return newParamsName.value
  271. // }
  272. },
  273. axisLine: {
  274. lineStyle: {
  275. color: "#f1f5f6",
  276. },
  277. },
  278. axisTick: {
  279. show: false,
  280. },
  281. data: this.xData || [],
  282. },
  283. ],
  284. yAxis: [
  285. {
  286. boundaryGap: false,
  287. type: "value",
  288. max: this.maxY,
  289. axisLabel: {
  290. textStyle: {
  291. color: "#b3b8cc",
  292. },
  293. formatter: "{value}",
  294. },
  295. name: "(m³/min)",
  296. nameTextStyle: {
  297. color: "#b3b8cc",
  298. fontSize: 12,
  299. lineHeight: 0,
  300. },
  301. splitLine: {
  302. lineStyle: {
  303. color: "#f1f5f6",
  304. },
  305. },
  306. axisLine: {
  307. show: true,
  308. lineStyle: {
  309. color: "#f1f5f6",
  310. },
  311. },
  312. axisTick: {
  313. show: false,
  314. },
  315. },
  316. {
  317. boundaryGap: false,
  318. type: "value",
  319. max: this.maxY,
  320. axisLabel: {
  321. textStyle: {
  322. color: "#b3b8cc",
  323. },
  324. formatter: "{value}",
  325. },
  326. name: "(m³/min)",
  327. nameTextStyle: {
  328. color: "#fff",
  329. fontSize: 12,
  330. lineHeight: 10,
  331. },
  332. splitLine: {
  333. lineStyle: {
  334. color: "#f1f5f6",
  335. },
  336. },
  337. axisLine: {
  338. show: true,
  339. lineStyle: {
  340. color: "#f1f5f6",
  341. },
  342. },
  343. axisTick: {
  344. show: false,
  345. },
  346. },
  347. ],
  348. series: [
  349. {
  350. name: "进风量",
  351. type: "line",
  352. smooth: true,
  353. showSymbol: true,
  354. symbolSize: 8,
  355. zlevel: 3,
  356. itemStyle: {
  357. color: "#19a3df",
  358. borderColor: "#a3c8d8",
  359. },
  360. lineStyle: {
  361. normal: {
  362. width: 2,
  363. color: "#19a3df",
  364. },
  365. },
  366. data: this.yDataJ || [],
  367. },
  368. {
  369. name: "回风量",
  370. type: "line",
  371. smooth: true,
  372. showSymbol: true,
  373. symbolSize: 8,
  374. zlevel: 3,
  375. itemStyle: {
  376. color: "#4fffad",
  377. borderColor: "#a3c8d8",
  378. },
  379. lineStyle: {
  380. normal: {
  381. width: 2,
  382. color: "#4fffad",
  383. },
  384. },
  385. data: this.yDataH || [],
  386. },
  387. {
  388. name: "需风量",
  389. type: "line",
  390. smooth: true,
  391. showSymbol: true,
  392. symbolSize: 8,
  393. zlevel: 3,
  394. itemStyle: {
  395. color: "#fc8452",
  396. borderColor: "#a3c8d8",
  397. },
  398. lineStyle: {
  399. normal: {
  400. width: 2,
  401. color: "#fc8452",
  402. },
  403. },
  404. data: this.yDataX || [],
  405. },
  406. ],
  407. };
  408. this.myChart.setOption(option);
  409. window.addEventListener("resize", () => {
  410. this.myChart.resize();
  411. });
  412. },
  413. //获取选项详情数据
  414. getSysWarnList(id, type) {
  415. new Promise((resolve, reject) => {
  416. api
  417. .sysWarn({ sysid: id, type: type })
  418. .then((response) => {
  419. if (response.data.code == 200) {
  420. this.xData = [];
  421. this.yDataH = [];
  422. this.yDataJ = [];
  423. this.yDataX = [];
  424. let data = response.data.result;
  425. this.cardList[0].value = data.jin || "--";
  426. this.cardList[1].value = data.hui || "--";
  427. this.cardList[2].value = data.xufengliang || "--";
  428. if (data.history.length != 0) {
  429. data.history.forEach((v) => {
  430. //lxh
  431. this.yDataJ.push(parseFloat(v.jin));
  432. this.yDataH.push(parseFloat(v.hui));
  433. if (
  434. this.cardList[2].value &&
  435. this.cardList[2].value != "--"
  436. ) {
  437. this.yDataX.push(this.cardList[2].value);
  438. } else {
  439. this.yDataX.push(0);
  440. }
  441. this.xData.push(v.time);
  442. });
  443. }
  444. let max1 = this.yDataJ.reduce((acr, cur) => {
  445. return acr > cur ? acr : cur;
  446. });
  447. let max2 = this.yDataH.reduce((acr1, cur1) => {
  448. return acr1 > cur1 ? acr1 : cur1;
  449. });
  450. this.maxY =
  451. max1 >= max2
  452. ? this.formatRoundNum(max1 * 1.5)
  453. : this.formatRoundNum(max2 * 1.5);
  454. this.initChart();
  455. } else {
  456. reject(response);
  457. }
  458. })
  459. .catch((error) => {
  460. console.log("catch===>response", response);
  461. reject(error);
  462. });
  463. });
  464. },
  465. //获取通风监控测点信息
  466. getWindDeviceList() {
  467. new Promise((resolve, reject) => {
  468. api
  469. .getDeviceVent({ devicetype: "windrect", pagetype: "normal" })
  470. .then((response) => {
  471. if (response.data.code == 200) {
  472. let data = response.data.result;
  473. if (data.msgTxt[0].datalist.length != 0) {
  474. let list = data.msgTxt[0].datalist;
  475. if (list.length > 0) {
  476. this.cardListTf = list.map((el) => {
  477. //lxh
  478. const readData = el.readData;
  479. el = Object.assign(el, readData);
  480. return {
  481. label: "通信状态",
  482. value: el.netStatus == "0" ? "断开" : "连接",
  483. listR: [
  484. {
  485. id: 0,
  486. label: "安装位置",
  487. dw: "",
  488. value: el.strinstallpos,
  489. },
  490. { id: 1, label: "风量", dw: "(m³/min)", value: el.m3 },
  491. { id: 2, label: "风速", dw: "(m/s)", value: el.va },
  492. { id: 4, label: "时间", dw: "", value: el.readTime },
  493. {
  494. id: 3,
  495. label: "是否报警",
  496. dw: "",
  497. value:
  498. el.warnFlag == "0"
  499. ? "正常"
  500. : el.warnFlag == 1
  501. ? "报警"
  502. : el.warnFlag == 2
  503. ? "断开"
  504. : "未监测",
  505. },
  506. ],
  507. };
  508. });
  509. }
  510. }
  511. } else {
  512. reject(response);
  513. }
  514. })
  515. .catch((error) => {
  516. console.log("catch===>response", response);
  517. reject(error);
  518. });
  519. });
  520. },
  521. },
  522. computed: {},
  523. };
  524. </script>
  525. <style lang="scss" scoped>
  526. .vent-detail {
  527. position: relative;
  528. box-sizing: border-box;
  529. .devic-box-tab {
  530. padding: 0px 10px !important;
  531. }
  532. .vent-content {
  533. height: 704px;
  534. box-sizing: border-box;
  535. overflow-y: auto;
  536. .top-area {
  537. width: 100%;
  538. padding: 10px;
  539. box-sizing: border-box;
  540. background-color: #fff;
  541. margin-bottom: 2px;
  542. .top-card {
  543. width: 100%;
  544. height: 60px;
  545. margin-bottom: 10px;
  546. display: flex;
  547. justify-content: space-between;
  548. align-items: center;
  549. .card-box {
  550. width: 32%;
  551. height: 100%;
  552. border-radius: 5px;
  553. background: linear-gradient(
  554. to right,
  555. rgba(55, 135, 254, 0.08),
  556. rgba(4, 184, 255, 0.08),
  557. rgba(60, 161, 237, 0.08)
  558. );
  559. }
  560. .card-box:nth-child(1) .box-item {
  561. display: flex;
  562. flex-direction: column;
  563. justify-content: center;
  564. align-items: flex-start;
  565. width: 100%;
  566. height: 100%;
  567. padding: 0px 15px;
  568. background: url("/static/jinfeng.png") no-repeat center;
  569. background-size: 75% 70%;
  570. }
  571. .card-box:nth-child(2) .box-item {
  572. display: flex;
  573. flex-direction: column;
  574. justify-content: center;
  575. align-items: flex-start;
  576. width: 100%;
  577. height: 100%;
  578. padding: 0px 15px;
  579. background: url("/static/huifeng.png") no-repeat center;
  580. background-size: 75% 70%;
  581. }
  582. .card-box:nth-child(3) .box-item {
  583. display: flex;
  584. flex-direction: column;
  585. justify-content: center;
  586. align-items: flex-start;
  587. width: 100%;
  588. height: 100%;
  589. padding: 0px 15px;
  590. background: url("/static/xufeng.png") no-repeat center;
  591. background-size: 75% 70%;
  592. }
  593. }
  594. .top-card1 {
  595. width: 100%;
  596. height: 60px;
  597. display: flex;
  598. justify-content: space-between;
  599. align-items: center;
  600. .card-box {
  601. width: 49%;
  602. height: 100%;
  603. border-radius: 5px;
  604. background: linear-gradient(
  605. to right,
  606. rgba(55, 135, 254, 0.08),
  607. rgba(4, 184, 255, 0.08),
  608. rgba(60, 161, 237, 0.08)
  609. );
  610. }
  611. .card-box:nth-child(1) .box-item {
  612. display: flex;
  613. flex-direction: column;
  614. justify-content: center;
  615. align-items: flex-start;
  616. width: 100%;
  617. height: 100%;
  618. padding: 0px 15px;
  619. background: url("/static/O₂.png") no-repeat right;
  620. background-size: 40% 80%;
  621. }
  622. .card-box:nth-child(2) .box-item {
  623. display: flex;
  624. flex-direction: column;
  625. justify-content: center;
  626. align-items: flex-start;
  627. width: 100%;
  628. height: 100%;
  629. padding: 0px 15px;
  630. background: url("/static/CO.png") no-repeat right;
  631. background-size: 40% 80%;
  632. }
  633. }
  634. }
  635. .center-area {
  636. width: 100%;
  637. height: 220px;
  638. padding: 0px 10px;
  639. box-sizing: border-box;
  640. background-color: #fff;
  641. margin-bottom: 2px;
  642. }
  643. .bot-area {
  644. width: 100%;
  645. padding: 0px 10px;
  646. box-sizing: border-box;
  647. background-color: #fff;
  648. margin-bottom: 2px;
  649. .bot-content {
  650. overflow-y: auto;
  651. .card-b {
  652. width: 100%;
  653. height: 100px;
  654. display: flex;
  655. justify-content: space-between;
  656. padding: 5px;
  657. margin-bottom: 5px;
  658. background: linear-gradient(
  659. to right,
  660. rgba(55, 135, 254, 0.08),
  661. rgba(4, 184, 255, 0.08),
  662. rgba(60, 161, 237, 0.08)
  663. );
  664. .item-l {
  665. position: relative;
  666. width: 80px;
  667. height: 100%;
  668. background: url("/static/bot-area.png") no-repeat center;
  669. background-size: 100% 100%;
  670. .label-l {
  671. width: 100%;
  672. position: absolute;
  673. top: 7px;
  674. font-size: 12px;
  675. text-align: center;
  676. }
  677. .value-l {
  678. width: 100%;
  679. position: absolute;
  680. top: 50px;
  681. color: #0eb4fc;
  682. text-align: center;
  683. }
  684. }
  685. .item-r {
  686. width: calc(100% - 100px);
  687. height: 100%;
  688. display: flex;
  689. flex-direction: column;
  690. justify-content: space-around;
  691. .content-r {
  692. display: flex;
  693. span {
  694. font-size: 12px;
  695. &:first-child {
  696. display: inline-block;
  697. width: 68px;
  698. }
  699. &:last-child {
  700. display: inline-block;
  701. width: calc(100% - 68px);
  702. overflow: hidden;
  703. white-space: nowrap;
  704. /* 不换行 */
  705. /* 超出部分隐藏 */
  706. text-overflow: ellipsis;
  707. /* 使用省略符号 */
  708. }
  709. }
  710. .status-f {
  711. color: #ff0000;
  712. }
  713. .status-l {
  714. color: #3df6ff;
  715. }
  716. }
  717. }
  718. }
  719. }
  720. }
  721. .top-title {
  722. height: 28px;
  723. margin-bottom: 10px;
  724. display: flex;
  725. justify-content: space-between;
  726. align-items: center;
  727. .title-icon {
  728. display: flex;
  729. justify-content: space-between;
  730. align-items: center;
  731. width: 90px;
  732. height: 28px;
  733. padding: 0px 10px;
  734. border-radius: 5px;
  735. background: #d4ecff;
  736. .icon-text {
  737. font-size: 12px;
  738. font-weight: bold;
  739. color: #0eb4fc;
  740. }
  741. }
  742. }
  743. .box-item .box-val {
  744. height: 28px;
  745. line-height: 28px;
  746. color: #0eb4fc;
  747. font-weight: bold;
  748. }
  749. .box-item .box-name {
  750. font-size: 12px;
  751. }
  752. .icon-style {
  753. width: 14px;
  754. height: 14px;
  755. }
  756. }
  757. }
  758. </style>