黄陂项目
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

747 lines
22 KiB

4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
  1. <template>
  2. <div class="dashboard-container">
  3. <div class="dashboard-editor-container">
  4. <panel-group />
  5. <el-row :gutter="20" style="margin-bottom:20px;height: 152px;">
  6. <el-col :xs="24" :sm="24" :lg="8">
  7. <!-- search-area -->
  8. <div class="container-left" style="height: 100%;margin: 0; position: relative;">
  9. <span class="right-top-line" />
  10. <span class="left-bottom-line" />
  11. <h3 class=" table-title" style="margin-bottom: 26px;">
  12. <p class="title-arrow">
  13. 档案检索
  14. </p>
  15. </h3>
  16. <SearchAcrives :is-home-search="isHomeSearch" />
  17. </div>
  18. </el-col>
  19. <el-col :xs="24" :sm="24" :lg="8">
  20. <div class="container-left" style="height: 100%;margin: 0; position: relative;">
  21. <span class="right-top-line" />
  22. <span class="left-bottom-line" />
  23. <h3 class=" table-title">
  24. <p class="title-arrow">
  25. <i class="iconfont icon-kongqizhiliangshuju" />环境数据
  26. </p>
  27. </h3>
  28. <div class="home-floor-tab">
  29. <p :class="{ 'active-floor': floorEnvIndex == 0 }" @click="changeFloorEnvTab(0)">3楼</p>
  30. </div>
  31. <el-carousel ref="carouselEnvRef" trigger="click" :interval="10000" indicator-position="none" height="110px" arrow="never" @change="handleEnvChange">
  32. <el-carousel-item>
  33. <div class="warehouse-tab" style="display: flex; justify-content: center; align-items: center; height: calc(100%); ">
  34. <div class="five-bottom">
  35. <!-- <p class="env-title">档案库</p> -->
  36. <!-- <ul class="leakage-list">
  37. <li :class="{ 'leakage-warn': topDisplayData.DAK_DIV_TOP_001.curstatus > 0 }">
  38. <p>温度</p>
  39. <span>{{ topDisplayData.DAK_DIV_TOP_001.curValue }}</span>
  40. </li>
  41. <li :class="{ 'leakage-warn': topDisplayData.DAK_DIV_TOP_002.curstatus > 0 }">
  42. <p>湿度</p>
  43. <span>{{ topDisplayData.DAK_DIV_TOP_002.curValue }}</span>
  44. </li>
  45. <li :class="{ 'leakage-warn': topDisplayData.DAK_DIV_TOP_003.curstatus > 0 }">
  46. <p>CO2</p>
  47. <span>{{ topDisplayData.DAK_DIV_TOP_003.curValue }}</span>
  48. </li>
  49. <li :class="{ 'leakage-warn': topDisplayData.DAK_DIV_TOP_005.curstatus > 0 }">
  50. <p>PM2.5</p>
  51. <span>{{ topDisplayData.DAK_DIV_TOP_005.curValue }}</span>
  52. </li>
  53. <li :class="{ 'leakage-warn': topDisplayData.DAK_DIV_TOP_006.curstatus > 0 }">
  54. <p>PM10</p>
  55. <span>{{ topDisplayData.DAK_DIV_TOP_006.curValue }}</span>
  56. </li>
  57. <li :class="{ 'leakage-warn': topDisplayData.DAK_DIV_TOP_004.curstatus > 0 }">
  58. <p>TVOC</p>
  59. <span>{{ topDisplayData.DAK_DIV_TOP_004.curValue }}</span>
  60. </li>
  61. </ul> -->
  62. <ul v-if="newAlarm && newAlarm.length !== 0" class="leakage-list">
  63. <li v-for="item in newAlarm" :key="item.SUBID">
  64. <div class="msg-txt">
  65. <p>{{ item.subName }}</p>
  66. <span>{{ item.value }}</span>
  67. </div>
  68. </li>
  69. </ul>
  70. </div>
  71. </div>
  72. </el-carousel-item>
  73. </el-carousel>
  74. </div>
  75. </el-col>
  76. <el-col :xs="24" :sm="24" :lg="8">
  77. <div class="container-left" style="height: 100%;margin: 0; position: relative;">
  78. <span class="right-top-line" />
  79. <span class="left-bottom-line" />
  80. <h3 class=" table-title">
  81. <p class="title-arrow">
  82. <svg-icon icon-class="a-3Dkufang" class-name="warehouse-svg" />3D库房
  83. </p>
  84. </h3>
  85. <div class="home-floor-tab">
  86. <p :class="{ 'active-floor': floorIndex == 0 }" @click="changeFloorTab(0)">3楼</p>
  87. <!-- <p :class="{ 'active-floor': floorIndex == 1 }" @click="changeFloorTab(1)">7楼</p> -->
  88. </div>
  89. <el-carousel ref="carouselRef" trigger="click" :interval="4000" indicator-position="none" height="110px" arrow="never" @change="handleChange">
  90. <el-carousel-item>
  91. <div class="warehouse-tab">
  92. <ul class="warehouse-nav">
  93. <li @click="changeActiveTab(1,0)">
  94. <span />
  95. <p>全景图</p>
  96. </li>
  97. </ul>
  98. </div>
  99. </el-carousel-item>
  100. </el-carousel>
  101. </div>
  102. </el-col>
  103. </el-row>
  104. <el-row :gutter="20" style="margin-bottom:20px;height: calc(50vh - 251px);">
  105. <el-col :xs="24" :sm="24" :lg="8">
  106. <!-- 待办事项 -->
  107. <div class="container-wrap">
  108. <span class="right-top-line" />
  109. <span class="left-bottom-line" />
  110. <h3 class="table-title">
  111. <p class="title-arrow">
  112. <svg-icon icon-class="tongzhigonggao" class-name="warehouse-svg" />待办事项
  113. </p>
  114. </h3>
  115. <div style="height: calc(100% - 40px);overflow-y: auto;overflow-x: hidden;">
  116. <ul v-if="waitBorrowerData.length !== 0" class="todo-list">
  117. <li v-for="(item,index) in waitBorrowerData" :key="index" :class="item.title.includes('警告') || item.title.includes('逾期') ? 'warn-info' :''" @click="handleToWaiting(item)">
  118. <el-tooltip class="item" effect="dark" :content="item.title" :enterable="false" placement="top">
  119. <p>{{ item.title }}</p>
  120. </el-tooltip>
  121. <span>{{ item.update_time | parseTime }}</span>
  122. </li>
  123. </ul>
  124. <div v-else class="empty-main" style="height: 100%;">
  125. <svg-icon icon-class="empty" class-name="empty-img" />
  126. <p>暂无数据</p>
  127. </div>
  128. </div>
  129. </div>
  130. </el-col>
  131. <el-col :xs="24" :sm="24" :lg="8">
  132. <!-- 门禁记录 -->
  133. <!-- <security-door :height="'calc(100% - 40px)'" /> -->
  134. <AccessDoor :height="'calc(100% - 40px)'" />
  135. </el-col>
  136. <el-col :xs="24" :sm="24" :lg="8">
  137. <!-- 报警记录 -->
  138. <warehouse-warning :height="'calc(100% - 40px)'" />
  139. </el-col>
  140. </el-row>
  141. <el-row :gutter="20" style="height: calc(50vh - 251px);">
  142. <el-col :xs="24" :sm="24" :lg="8">
  143. <!-- 档案借阅 -->
  144. <div class="container-wrap">
  145. <span class="right-top-line" />
  146. <span class="left-bottom-line" />
  147. <h3 class="table-title">
  148. <p class="title-arrow">档案借阅</p>
  149. </h3>
  150. <div class="chart-wrapper">
  151. <lend-across :lend-data="lendData" />
  152. </div>
  153. </div>
  154. </el-col>
  155. <el-col :xs="24" :sm="24" :lg="8">
  156. <!-- 档案类别 -->
  157. <div class="container-wrap">
  158. <span class="right-top-line" />
  159. <span class="left-bottom-line" />
  160. <h3 class="table-title">
  161. <p class="title-arrow">档案类别</p>
  162. </h3>
  163. <div class="chart-wrapper">
  164. <cate-pie :cate-data="cateData" />
  165. </div>
  166. </div>
  167. </el-col>
  168. <el-col :xs="24" :sm="24" :lg="8">
  169. <!-- 档案类型 -->
  170. <div class="container-wrap">
  171. <span class="right-top-line" />
  172. <span class="left-bottom-line" />
  173. <h3 class="table-title">
  174. <p class="title-arrow">档案类型</p>
  175. </h3>
  176. <div v-if="typeData.length !== 0" class="chart-wrapper">
  177. <type-pie :type-data="typeData" />
  178. </div>
  179. <div v-else class="empty-main">
  180. <svg-icon icon-class="empty" class-name="empty-img" />
  181. <p>暂无数据</p>
  182. </div>
  183. </div>
  184. </el-col>
  185. </el-row>
  186. </div>
  187. </div>
  188. </template>
  189. <script>
  190. import PanelGroup from './dashboard/PanelGroup'
  191. import lendAcross from '@/views/components/echarts/lendAcross.vue'
  192. import catePie from '@/views/components/echarts/catePie.vue'
  193. import typePie from '@/views/components/echarts/typePie.vue'
  194. import WarehouseWarning from '@/views/components/WarehouseWarning'
  195. // import SecurityDoor from '@/views/components/SecurityDoor'
  196. import AccessDoor from '@/views/components/AccessDoor'
  197. import SearchAcrives from '@/views/archivesManage/archivesSearch/index'
  198. import { statisticsCrud } from '@/views/system/archiveStatistics/mixins/statistics'
  199. import { FetchWaitBorrower } from '@/api/archivesManage/lendManage'
  200. // import displayConfigApi from '@/api/storeManage/displayConfig'
  201. // import thirdApi from '@/api/thirdApi'
  202. import alarmApi from '@/api/home/alarm'
  203. // import { allDeviceData, mockIpData } from '@/views/environmentalScreen/index.js'
  204. // // 同步mock方法
  205. // const mockFetchDataForIP = (params) => {
  206. // return new Promise((resolve) => {
  207. // setTimeout(() => {
  208. // const ip = params.ip
  209. // const result = mockIpData[ip] || { code: 200, message: '操作成功', data: [], timestamp: Date.now() }
  210. // resolve(result.data)
  211. // }, 500)
  212. // })
  213. // }
  214. import { mapGetters } from 'vuex'
  215. export default {
  216. name: 'Dashboard',
  217. components: {
  218. WarehouseWarning,
  219. // SecurityDoor,
  220. AccessDoor,
  221. PanelGroup,
  222. lendAcross,
  223. catePie,
  224. typePie,
  225. SearchAcrives
  226. },
  227. mixins: [statisticsCrud],
  228. data() {
  229. return {
  230. waitBorrowerData: [],
  231. floorIndex: 0,
  232. floorEnvIndex: 0,
  233. isHomeSearch: false,
  234. roomId: null,
  235. allDisplayConfigData: [],
  236. displayConfigData: [],
  237. url: '',
  238. allDeviceIds: [],
  239. oaoMessage: {
  240. ZLS_MO_OAO_001: {
  241. show: false,
  242. wendu: '',
  243. sidu: '',
  244. alarmState: 0
  245. },
  246. YLS_MO_OAO_001: {
  247. show: false,
  248. wendu: '',
  249. sidu: '',
  250. alarmState: 0
  251. }
  252. },
  253. topDisplayData: {
  254. DAK_DIV_TOP_001: {
  255. show: false,
  256. curValue: '',
  257. unit: '',
  258. curstatus: 0
  259. },
  260. DAK_DIV_TOP_002: {
  261. show: false,
  262. curValue: '',
  263. unit: '',
  264. curstatus: 0
  265. },
  266. DAK_DIV_TOP_003: {
  267. show: false,
  268. curValue: '',
  269. unit: '',
  270. curstatus: 0
  271. },
  272. DAK_DIV_TOP_004: {
  273. show: false,
  274. curValue: '',
  275. unit: '',
  276. curstatus: 0
  277. },
  278. DAK_DIV_TOP_005: {
  279. show: false,
  280. curValue: '',
  281. unit: '',
  282. curstatus: 0
  283. },
  284. DAK_DIV_TOP_006: {
  285. show: false,
  286. curValue: '',
  287. unit: '',
  288. curstatus: 0
  289. }
  290. },
  291. // 同步FullView的核心数据
  292. newAlarm: [],
  293. aqiValue: 45,
  294. aqiStatus: '健康',
  295. keepIndicators: [
  296. '二氧化碳',
  297. '甲醛',
  298. '综合气体',
  299. 'PM2.5浓度',
  300. 'PM10浓度',
  301. '温度',
  302. '湿度',
  303. '空气质量'
  304. ],
  305. ipToNameMap: {}, // IP到设备名称映射
  306. currentDeviceName: '', // 当前显示设备名称
  307. currentIpIndex: 0, // IP轮询索引
  308. excludeIpList: ['192.168.99.101:6003'] // 排除IP列表
  309. }
  310. },
  311. computed: {
  312. ...mapGetters([
  313. 'roles'
  314. ])
  315. },
  316. async created() {
  317. this.getWaitBorrower()
  318. // console.log('allDeviceData:', allDeviceData)
  319. // this.allDisplayConfigData = allDeviceData
  320. // this.handleDeviceIpList()
  321. // 真实请求请替换:
  322. await alarmApi.FetchYpGetSite().then((data) => {
  323. if (data && data.length > 0) {
  324. this.allDisplayConfigData = data
  325. // 处理设备IP列表
  326. this.handleDeviceIpList()
  327. } else {
  328. this.allDisplayConfigData = []
  329. }
  330. })
  331. // 初始加载数据
  332. if (this.allDeviceIds.length > 0) {
  333. this.currentDeviceName = this.ipToNameMap[this.allDeviceIds[0]] || ''
  334. await this.getRealTimeData(this.allDeviceIds[0])
  335. console.log('初始加载IP数据:', this.allDeviceIds[0])
  336. } else {
  337. console.warn('无有效设备IP,停止轮询')
  338. this.newAlarm = []
  339. }
  340. },
  341. mounted() {
  342. if (this.allDeviceIds.length > 0) {
  343. this.dataTimer = setInterval(async() => {
  344. const currentIp = this.getNextIp()
  345. this.currentDeviceName = this.ipToNameMap[currentIp] || ''
  346. await this.getRealTimeData(currentIp)
  347. }, 10000)
  348. console.log(`启动IP轮询,共${this.allDeviceIds.length}个有效IP:`, this.allDeviceIds)
  349. }
  350. },
  351. methods: {
  352. /**
  353. * 处理设备IP列表去重+排除+名称映射
  354. */
  355. handleDeviceIpList() {
  356. const ipSet = new Set()
  357. this.ipToNameMap = {}
  358. this.allDisplayConfigData.forEach(element => {
  359. const ip = (element.IP || '').trim()
  360. if (ip && !this.excludeIpList.includes(ip)) {
  361. ipSet.add(ip)
  362. this.ipToNameMap[ip] = element.Name || `未知设备(${ip})`
  363. console.log('有效设备IP:', ip, '设备名称:', element.Name)
  364. } else if (this.excludeIpList.includes(ip)) {
  365. console.log('排除指定IP:', ip, '设备名称:', element.Name)
  366. } else if (!ip) {
  367. console.log('过滤空IP:', element.Name)
  368. }
  369. })
  370. this.allDeviceIds = Array.from(ipSet)
  371. },
  372. /**
  373. * 获取下一个轮询IP循环切换
  374. */
  375. getNextIp() {
  376. if (this.allDeviceIds.length === 0) return ''
  377. const ip = this.allDeviceIds[this.currentIpIndex]
  378. this.currentIpIndex = (this.currentIpIndex + 1) % this.allDeviceIds.length
  379. console.log(`轮询切换 - 当前IP:${ip},下一个索引:${this.currentIpIndex}`)
  380. return ip
  381. },
  382. /**
  383. * 请求指定IP的实时数据过滤+AQI计算
  384. */
  385. async getRealTimeData(targetIp) {
  386. if (!targetIp) {
  387. this.newAlarm = []
  388. this.currentDeviceName = ''
  389. return
  390. }
  391. try {
  392. console.log(`开始请求IP【${targetIp}】的实时数据(模拟)`)
  393. // 模拟
  394. // const data = await mockFetchDataForIP({ ip: targetIp })
  395. // 真实请求
  396. const data = await alarmApi.FetchDataForIP({ ip: targetIp })
  397. // 过滤需要的指标
  398. const filteredData = data.filter(item =>
  399. this.keepIndicators.includes(item.subName)
  400. )
  401. if (filteredData.length > 0) {
  402. this.newAlarm = filteredData
  403. console.log(`IP【${targetIp}】(${this.currentDeviceName}) 过滤后的数据:`, filteredData)
  404. } else {
  405. this.newAlarm = []
  406. this.aqiValue = 45
  407. this.aqiStatus = '健康'
  408. console.log(`IP【${targetIp}】(${this.currentDeviceName}) 无需要的指标数据`)
  409. }
  410. } catch (error) {
  411. this.newAlarm = []
  412. this.aqiValue = 45
  413. this.aqiStatus = '健康'
  414. this.currentDeviceName = ''
  415. console.error(`IP【${targetIp}】数据请求失败:`, error)
  416. }
  417. },
  418. handleChange(index) {
  419. this.floorIndex = index
  420. },
  421. handleEnvChange(index) {
  422. this.floorEnvIndex = index
  423. },
  424. changeFloorTab(index) {
  425. this.floorIndex = index
  426. const carousel = this.$refs.carouselRef
  427. carousel.setActiveItem(index)
  428. },
  429. changeFloorEnvTab(index) {
  430. this.floorEnvIndex = index
  431. const carousel = this.$refs.carouselEnvRef
  432. carousel.setActiveItem(index)
  433. },
  434. // handleSetLineChartData(type) {
  435. // this.lineChartData = lineChartData[type]
  436. // },
  437. getWaitBorrower() {
  438. FetchWaitBorrower().then(data => {
  439. if (data) {
  440. this.waitBorrowerData = data
  441. }
  442. })
  443. },
  444. changeActiveTab(floorId, roomId) {
  445. if (this.roles.includes('admin') || this.roles.includes('warehouse3D')) {
  446. this.$router.push({
  447. name: 'warehouse3D',
  448. params: {
  449. floorId: floorId,
  450. roomId: roomId
  451. }
  452. })
  453. } else {
  454. this.$message({
  455. message: '当前账号没有权限',
  456. type: 'warning'
  457. })
  458. }
  459. },
  460. handleToWaiting(item) {
  461. if (this.roles.includes('admin') || this.roles.includes('lendManage:list')) {
  462. // 待借档案:到“待借档案” 0
  463. // 借出确认:到“借出确认” 1
  464. // 逾期警告:到“归还确认” 2
  465. // 即将到期:到“归还确认” 3
  466. let locationIndex = 0
  467. if (item.title.includes('待借档案')) {
  468. locationIndex = 0
  469. } else if (item.title.includes('借出确认')) {
  470. locationIndex = 1
  471. } else if (item.title.includes('逾期警告')) {
  472. locationIndex = 2
  473. } else if (item.title.includes('即将到期')) {
  474. locationIndex = 2
  475. }
  476. this.$router.push({
  477. name: 'lendManage',
  478. params: {
  479. locationIndex: locationIndex
  480. }
  481. })
  482. } else {
  483. this.$message({
  484. message: '当前账号没有权限',
  485. type: 'warning'
  486. })
  487. }
  488. }
  489. }
  490. }
  491. </script>
  492. <style rel="stylesheet/scss" lang="scss" scoped>
  493. @import "~@/assets/styles/lend-manage.scss";
  494. .dashboard-editor-container {
  495. padding: 20px;
  496. background-color: #031435;
  497. position: relative;
  498. .chart-wrapper {
  499. height: calc(100% - 40px);
  500. }
  501. }
  502. @media (max-width: 1024px) {
  503. .chart-wrapper {
  504. padding: 8px;
  505. }
  506. }
  507. .warehouse-tab {
  508. color: #fff;
  509. .warehouse-nav {
  510. display: flex;
  511. justify-content: space-around;
  512. position: absolute;
  513. bottom: 15px;
  514. z-index: 11;
  515. width: 100%;
  516. padding: 0;
  517. li {
  518. display: flex;
  519. flex-direction: column;
  520. align-items: center;
  521. flex-wrap: nowrap;
  522. align-content: center;
  523. justify-content: center;
  524. height: 90px;
  525. text-align: right;
  526. font-size: 14px;
  527. position: relative;
  528. &:hover {
  529. cursor: pointer;
  530. }
  531. span {
  532. width: 72px;
  533. height: 52px;
  534. margin-bottom: 7px;
  535. }
  536. p {
  537. text-align: left;
  538. }
  539. &:first-child span {
  540. background: url("~@/assets/images/tab_fullview_logo.png") no-repeat;
  541. }
  542. &:nth-child(2) span {
  543. background: url("~@/assets/images/tab_archives_logo.png") no-repeat;
  544. }
  545. &:nth-child(3) span {
  546. background: url("~@/assets/images/tab_collate_logo.png") no-repeat;
  547. }
  548. &:nth-child(4) span {
  549. background: url("~@/assets/images/tab_read_logo.png") no-repeat;
  550. }
  551. }
  552. }
  553. }
  554. .el-col {
  555. height: 100%;
  556. }
  557. .container-left,
  558. .container-right,
  559. .container-wrap,
  560. .el-card,
  561. .header-container-wrap {
  562. min-height: 100%;
  563. }
  564. .warehose-el-table ::v-deep .el-table__header-wrapper {
  565. box-shadow: inset 0px 0px 6px 1px #339cff;
  566. background: none !important;
  567. }
  568. .container-wrap {
  569. min-height: auto;
  570. height: 100%;
  571. // overflow: hidden;
  572. }
  573. .todo-list {
  574. padding: 0 20px;
  575. & li {
  576. height: 42px;
  577. line-height: 42px;
  578. margin-bottom: 10px;
  579. font-size: 13px;
  580. color: #ffffff;
  581. background: #02255f;
  582. box-shadow: inset 0px 0px 6px 1px #339cff;
  583. border-radius: 26px;
  584. opacity: 1;
  585. cursor: pointer;
  586. &.warn-info{
  587. color: #F65163;
  588. box-shadow: inset 0px 0px 15px 1px #f65164;
  589. }
  590. & p {
  591. display: inline-block;
  592. width: calc(100% - 140px);
  593. padding-left: 10px;
  594. text-overflow: ellipsis;
  595. overflow: hidden;
  596. white-space: nowrap;
  597. word-break: break-all;
  598. }
  599. & span {
  600. float: right;
  601. padding-right: 10px;
  602. }
  603. }
  604. }
  605. ::v-deep
  606. .el-table--striped
  607. .el-table__body
  608. tr.el-table__row--striped
  609. td.el-table__cell {
  610. background: #02255f;
  611. }
  612. .search-area {
  613. width: 100%;
  614. height: 100%;
  615. margin: 0;
  616. display: flex;
  617. align-items: center;
  618. justify-content: center;
  619. }
  620. ::v-deep .search-main{
  621. padding: 0 0 0 20px;
  622. .head-container{
  623. padding: 0;
  624. width: 100% !important;
  625. .search-input {
  626. width: 100% !important;
  627. }
  628. .input-with-select{
  629. width: 100% !important;
  630. }
  631. }
  632. }
  633. .home-floor-tab{
  634. position: absolute;
  635. right: 14px;
  636. top: 10px;
  637. color: #fff;
  638. display: flex;
  639. justify-self: flex-start;
  640. p{
  641. font-size: 14px;
  642. padding:2px 6px;
  643. margin-right: 6px;
  644. color: #339cff;
  645. border: 1px solid #339cff;
  646. border-radius: 4px;
  647. cursor: pointer;
  648. &.active-floor,
  649. &:hover{
  650. color: #fff;
  651. background-color: #113d72;
  652. }
  653. }
  654. }
  655. .icon-kongqizhiliangshuju{
  656. font-size: 14px;
  657. color: #F65163;
  658. margin-right: 6px
  659. }
  660. .env-title{
  661. width: 50px;
  662. height: 40px;
  663. line-height: 20px;
  664. text-align: center;
  665. font-size: 12px;
  666. margin: 10px 10px 0 0;
  667. }
  668. .leakage-list {
  669. display: flex;
  670. justify-content:flex-start;
  671. flex-wrap: wrap;
  672. flex: 1;
  673. text-align: left;
  674. font-size: 10px;
  675. padding-left: 10px;
  676. li {
  677. position: relative;
  678. display: flex;
  679. justify-content: flex-start;
  680. flex-wrap: wrap;
  681. align-items: center;
  682. width: 72px;
  683. height: 40px;
  684. border: 1px solid #3581cc;
  685. background-color: #02255f;
  686. border-radius: 2px;
  687. padding: 4px;
  688. margin: 6px 10px 0 0;
  689. font-size: 12px;
  690. &::before {
  691. content: "";
  692. position: absolute;
  693. top: 2px;
  694. right: 2px;
  695. width: 0;
  696. height: 0;
  697. border-color: transparent #339cff;
  698. border-width: 0 4px 4px 0;
  699. border-style: solid;
  700. }
  701. p {
  702. width: 100%;
  703. }
  704. span{
  705. width: 100%;
  706. color: #18B08F;
  707. text-align: right;
  708. }
  709. &.leakage-warn {
  710. border-color: #f65164;
  711. box-shadow: inset 0px 0px 15px 1px #f65164;
  712. color: #f65164;
  713. &::before {
  714. border-color: transparent #f65164;
  715. }
  716. span {
  717. color: #f65164;
  718. }
  719. }
  720. }
  721. }
  722. .five-bottom{
  723. display: flex;
  724. justify-content: flex-start;
  725. align-items: center;
  726. .env-title{
  727. line-height: 40px;
  728. }
  729. }
  730. </style>