黄陂项目
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.

630 lines
22 KiB

2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. <template>
  2. <div class="warehouse">
  3. <div class="warehouse-left">
  4. <div class="left-3d">
  5. <iframe id="myIframe" ref="myIframe" name="iframeMap" class="iframe_box" src="/web3D/index.html" frameborder="0" scrolling="no" />
  6. <div style="position: absolute; top: 0; left: 0;">
  7. <p style="font-size: 12px; margin-bottom: 10px;">{{ currentDeviceName }}</p>
  8. <ul v-if="newAlarm && newAlarm.length !== 0" class="msg-list">
  9. <li v-for="item in newAlarm" :key="item.SUBID">
  10. <svg-icon v-if="item.subName === '温度'" icon-class="temperature" class-name="msg-list-svg" />
  11. <svg-icon v-if="item.subName === '湿度'" icon-class="shidu" class-name="msg-list-svg" />
  12. <svg-icon v-if="item.subName === 'PM2.5浓度'" icon-class="pm25" class-name="msg-list-svg" />
  13. <svg-icon v-if="item.subName === 'PM10浓度'" icon-class="pm10" class-name="msg-list-svg" />
  14. <svg-icon v-if="item.subName === 'TVOC'" icon-class="voc" class-name="msg-list-svg" />
  15. <svg-icon v-if="item.subName === '二氧化碳'" icon-class="co2" class-name="msg-list-svg" />
  16. <svg-icon v-if="item.subName === '甲醛'" icon-class="jiaquan" class-name="msg-list-svg" style="width: 2em; margin-left: 20px;" />
  17. <svg-icon v-if="item.subName === '综合气体'" icon-class="comprehensive-gas" class-name="msg-list-svg" />
  18. <svg-icon v-if="item.subName === '空气质量'" icon-class="kongqi" class-name="msg-list-svg" />
  19. <div class="msg-txt">
  20. <span class="msg-list-num">{{ item.value }}</span>
  21. <p class="msg-list-unit">{{ item.subName }} {{ item.dw }}</p>
  22. </div>
  23. </li>
  24. </ul>
  25. </div>
  26. <div
  27. v-if="hasValidData"
  28. class="air-quality"
  29. :class="[
  30. aqiStatus === '优' ? 'air-excellent' : '',
  31. aqiStatus === '良' ? 'air-good' : '',
  32. aqiStatus === '轻度污染' ? 'air-lightPollution' : '',
  33. aqiStatus === '中度污染' ? 'air-mediumPollution' : '',
  34. aqiStatus === '重度污染' ? 'air-heavyPollution' : '',
  35. aqiStatus === '严重污染' ? 'air-severePollution' : ''
  36. ]"
  37. >
  38. <h3>实时空气质量指数AQI</h3>
  39. <div class="air-params">
  40. <div class="air-left">
  41. <span class="air-title">实时AQI</span>
  42. <div class="air-result"><p>{{ aqiValue }}</p><span>(AQI-中国标准)</span></div>
  43. </div>
  44. <div class="air-right">
  45. <span>空气质量为</span>
  46. <p>{{ aqiStatus }}</p>
  47. </div>
  48. </div>
  49. </div>
  50. </div>
  51. </div>
  52. <div class="warehouse-right">
  53. <warehouse-warning :height="'calc(100% - 40px)'" :storeroom-id="roomId" />
  54. <AccessDoor :height="'calc(100% - 40px)'" />
  55. </div>
  56. <hkVideo ref="camera" :dialog-open.sync="open" />
  57. </div>
  58. </template>
  59. <script>
  60. import WarehouseWarning from '@/views/components/WarehouseWarning'
  61. import AccessDoor from '@/views/components/AccessDoor'
  62. import hkVideo from '../module/hkVideo.vue'
  63. import alarmApi from '@/api/home/alarm'
  64. // import { allDeviceData, mockIpData } from './index.js'
  65. // const mockFetchDataForIP = (params) => {
  66. // return new Promise((resolve) => {
  67. // setTimeout(() => {
  68. // const ip = params.ip
  69. // const result = mockIpData[ip] || { code: 200, message: '操作成功', data: [], timestamp: Date.now() }
  70. // resolve(result.data)
  71. // }, 500)
  72. // })
  73. // }
  74. export default {
  75. name: 'FullView',
  76. components: { WarehouseWarning, AccessDoor, hkVideo },
  77. data() {
  78. return {
  79. roomId: '01A1DC2123C2B75E1A579D',
  80. allDisplayConfigData: [],
  81. displayConfigData: [],
  82. originalAllDeviceIds: [],
  83. allDeviceIds: [],
  84. currentIpIndex: 0,
  85. excludeIpList: [
  86. '192.168.99.101:6003'
  87. ],
  88. timer: '',
  89. open: false,
  90. newAlarm: [],
  91. aqiValue: 45,
  92. aqiStatus: '优',
  93. keepIndicators: [
  94. '二氧化碳',
  95. '甲醛',
  96. '综合气体',
  97. 'PM2.5浓度',
  98. 'PM10浓度',
  99. '温度',
  100. '湿度',
  101. '空气质量'
  102. ],
  103. aqiGradeStandard: [
  104. { aqiMin: 0, aqiMax: 50, level: '优', colorKey: 'excellent' },
  105. { aqiMin: 51, aqiMax: 100, level: '良', colorKey: 'good' },
  106. { aqiMin: 101, aqiMax: 150, level: '轻度污染', colorKey: 'lightPollution' },
  107. { aqiMin: 151, aqiMax: 200, level: '中度污染', colorKey: 'mediumPollution' },
  108. { aqiMin: 201, aqiMax: 300, level: '重度污染', colorKey: 'heavyPollution' },
  109. { aqiMin: 301, aqiMax: 500, level: '严重污染', colorKey: 'severePollution' }
  110. ],
  111. aqiBpTable: {
  112. pm25: [
  113. { iaqiLo: 0, iaqiHi: 50, bpLo: 0, bpHi: 35 }, // 优
  114. { iaqiLo: 50, iaqiHi: 100, bpLo: 35, bpHi: 75 }, // 良
  115. { iaqiLo: 100, iaqiHi: 150, bpLo: 75, bpHi: 115 }, // 轻度污染
  116. { iaqiLo: 150, iaqiHi: 200, bpLo: 115, bpHi: 150 }, // 中度污染
  117. { iaqiLo: 200, iaqiHi: 300, bpLo: 150, bpHi: 250 }, // 重度污染
  118. { iaqiLo: 300, iaqiHi: 500, bpLo: 250, bpHi: 500 } // 严重污染
  119. ],
  120. pm10: [
  121. { iaqiLo: 0, iaqiHi: 50, bpLo: 0, bpHi: 50 }, // 优
  122. { iaqiLo: 50, iaqiHi: 100, bpLo: 50, bpHi: 150 }, // 良
  123. { iaqiLo: 100, iaqiHi: 150, bpLo: 150, bpHi: 250 }, // 轻度污染
  124. { iaqiLo: 150, iaqiHi: 200, bpLo: 250, bpHi: 350 }, // 中度污染
  125. { iaqiLo: 200, iaqiHi: 300, bpLo: 350, bpHi: 420 }, // 重度污染
  126. { iaqiLo: 300, iaqiHi: 500, bpLo: 420, bpHi: 500 } // 严重污染
  127. ]
  128. },
  129. // 新增:存储IP到设备名称的映射
  130. ipToNameMap: {},
  131. // 新增:当前显示的设备名称
  132. currentDeviceName: '',
  133. aqiTimer: null,
  134. // 新增:存储所有设备的PM2.5/PM10数据
  135. allDevicesPollutantData: [],
  136. hasValidData: false
  137. }
  138. },
  139. async created() {
  140. window.getIframeLoading = this.getIframeLoading
  141. // this.allDisplayConfigData = allDeviceData
  142. // this.handleDeviceIpList()
  143. await alarmApi.FetchYpGetSite().then((data) => {
  144. if (data && data.length > 0) {
  145. this.allDisplayConfigData = data
  146. this.handleDeviceIpList()
  147. } else {
  148. this.allDisplayConfigData = []
  149. }
  150. })
  151. await this.getAllDevicesPollutantData()
  152. this.calcGlobalAQI()
  153. if (this.allDeviceIds.length > 0) {
  154. this.currentDeviceName = this.ipToNameMap[this.allDeviceIds[0]] || ''
  155. await this.getRealTimeData(this.allDeviceIds[0])
  156. // 轮询定时器(仅更新msg-list,完全不碰AQI)
  157. this.timer = setInterval(async() => {
  158. const currentIp = this.getNextIp()
  159. this.currentDeviceName = this.ipToNameMap[currentIp] || ''
  160. await this.getRealTimeData(currentIp)
  161. }, 10000)
  162. console.log(`启动IP轮询,共${this.allDeviceIds.length}个有效IP:`, this.allDeviceIds)
  163. } else {
  164. console.warn('无有效设备IP,停止轮询')
  165. this.newAlarm = []
  166. }
  167. // 可选:开启AQI定时更新(如需实时刷新全量AQI)
  168. // if (this.allDeviceIds.length > 0) {
  169. // this.aqiTimer = setInterval(async() => {
  170. // await this.getAllDevicesPollutantData()
  171. // this.calcGlobalAQI()
  172. // }, 30000)
  173. // console.log('启动全量AQI计算定时器(30秒/次)')
  174. // }
  175. },
  176. mounted() {
  177. const _this = this
  178. _this.iframeWin = this.$refs.myIframe.contentWindow
  179. window.addEventListener('message', this.handleMessageEvent)
  180. },
  181. beforeDestroy() {
  182. // 清理轮询定时器
  183. if (this.timer) {
  184. clearInterval(this.timer)
  185. console.log('停止IP轮询')
  186. }
  187. // 清理AQI定时器
  188. if (this.aqiTimer) {
  189. clearInterval(this.aqiTimer)
  190. console.log('停止全量AQI计算定时器')
  191. }
  192. window.removeEventListener('message', this.handleMessageEvent)
  193. },
  194. methods: {
  195. handleDeviceIpList() {
  196. const filteredIpSet = new Set() // 过滤后的IP(轮询用)
  197. const originalIpSet = new Set() // 原始IP(AQI计算用)
  198. this.ipToNameMap = {}
  199. this.allDisplayConfigData.forEach(element => {
  200. const ip = (element.IP || '').trim()
  201. if (ip) {
  202. // 1. 原始IP列表:所有非空IP都加入(用于AQI计算)
  203. originalIpSet.add(ip)
  204. // 2. 过滤后的IP列表:排除指定IP(用于轮询)
  205. if (!this.excludeIpList.includes(ip)) {
  206. filteredIpSet.add(ip)
  207. } else {
  208. console.log('轮询排除IP:', ip, '设备名称:', element.Name)
  209. }
  210. // 存储IP到名称的映射(所有IP都存)
  211. this.ipToNameMap[ip] = element.Name || `未知设备(${ip})`
  212. console.log('有效设备IP(AQI计算包含):', ip, '设备名称:', element.Name)
  213. } else {
  214. console.log('过滤空IP:', element.Name)
  215. }
  216. })
  217. // 赋值:过滤后的IP(轮询)、原始IP(AQI)
  218. this.allDeviceIds = Array.from(filteredIpSet) // 轮询用
  219. this.originalAllDeviceIds = Array.from(originalIpSet) // AQI计算用
  220. console.log(`轮询IP列表(过滤后):`, this.allDeviceIds)
  221. console.log(`AQI计算IP列表(原始):`, this.originalAllDeviceIds)
  222. },
  223. /**
  224. * 获取下一个轮询IP循环切换
  225. */
  226. getNextIp() {
  227. if (this.allDeviceIds.length === 0) return ''
  228. // 先重置索引(防止数组长度变化导致越界)
  229. this.currentIpIndex = this.currentIpIndex % this.allDeviceIds.length
  230. const ip = this.allDeviceIds[this.currentIpIndex]
  231. this.currentIpIndex = (this.currentIpIndex + 1) % this.allDeviceIds.length
  232. console.log(`轮询切换 - 当前IP:${ip},下一个索引:${this.currentIpIndex}`)
  233. return ip
  234. },
  235. /**
  236. * 处理iframe消息事件
  237. */
  238. handleMessageEvent(event) {
  239. if (event.data) {
  240. switch (event.data.type) {
  241. case 'autoRotationStatus':
  242. {
  243. const newValue = event.data.value
  244. this.$emit('update:isGetRotate', newValue)
  245. console.log('Received auto rotation status:', newValue)
  246. }
  247. break
  248. case 'cameraClick':
  249. {
  250. const deviceData = event.data.data
  251. console.log('cameraClick', deviceData)
  252. if (deviceData.toLowerCase().includes('cam')) {
  253. this.open = true
  254. this.$nextTick(() => {
  255. this.$refs.camera.getVideoUrl(this.roomId, deviceData)
  256. })
  257. }
  258. }
  259. break
  260. case 'archCabinetsClick':
  261. {
  262. const data = event.data.data
  263. console.log('archCabinetsClick', data)
  264. console.log(data.split('-')[1])
  265. if (data.includes('cabinet')) {
  266. this.deviceId = data.split('-')[1]
  267. this.$router.push('/storeManage/deseCabinet')
  268. localStorage.setItem('cabinetNum', this.deviceId)
  269. }
  270. }
  271. break
  272. default:
  273. console.log('未知消息类型:', event.data)
  274. }
  275. }
  276. },
  277. /**
  278. * 请求指定IP的实时数据过滤+设备名称关联
  279. */
  280. async getRealTimeData(targetIp) {
  281. if (!targetIp) {
  282. this.newAlarm = []
  283. this.currentDeviceName = ''
  284. return
  285. }
  286. try {
  287. console.log(`开始请求IP【${targetIp}】的实时数据(模拟)`)
  288. // const data = await mockFetchDataForIP({ ip: targetIp })
  289. // 真实请求
  290. const data = await alarmApi.FetchDataForIP({ ip: targetIp })
  291. const filteredData = data.filter(item =>
  292. this.keepIndicators.includes(item.subName)
  293. )
  294. if (filteredData.length > 0) {
  295. this.newAlarm = filteredData
  296. console.log(`IP【${targetIp}】(${this.currentDeviceName}) 过滤后的数据:`, filteredData)
  297. } else {
  298. this.newAlarm = []
  299. console.log(`IP【${targetIp}】(${this.currentDeviceName}) 无需要的指标数据`)
  300. }
  301. } catch (error) {
  302. this.newAlarm = []
  303. // 移除AQI重置逻辑
  304. this.currentDeviceName = ''
  305. console.error(`IP【${targetIp}】模拟数据请求失败:`, error)
  306. }
  307. },
  308. calcAQI() {},
  309. /**
  310. * 获取所有设备的PM2.5/PM10数据用于计算全局AQI
  311. */
  312. async getAllDevicesPollutantData() {
  313. if (this.originalAllDeviceIds.length === 0) {
  314. this.allDevicesPollutantData = []
  315. return
  316. }
  317. const allPollutantData = []
  318. // 遍历原始IP列表(和EnvironmentalScreen的allDeviceIds一致)
  319. for (const ip of this.originalAllDeviceIds) {
  320. try {
  321. // const data = await mockFetchDataForIP({ ip })
  322. // 真实请求
  323. const data = await alarmApi.FetchDataForIP({ ip })
  324. // 仅过滤PM2.5/PM10
  325. const pm25Item = data.find(item => item.subName === 'PM2.5浓度')
  326. const pm10Item = data.find(item => item.subName === 'PM10浓度')
  327. if (pm25Item) {
  328. allPollutantData.push({
  329. ...pm25Item,
  330. value: parseFloat(pm25Item.value) || 0, // 确保数值类型
  331. dw: pm25Item.dw || 'ug/立方米' // 对齐单位
  332. })
  333. }
  334. if (pm10Item) {
  335. allPollutantData.push({
  336. ...pm10Item,
  337. value: parseFloat(pm10Item.value) || 0,
  338. dw: pm10Item.dw || 'ug/立方米'
  339. })
  340. }
  341. } catch (error) {
  342. console.error(`获取IP【${ip}】污染物数据失败:`, error)
  343. }
  344. }
  345. this.allDevicesPollutantData = allPollutantData
  346. },
  347. /**
  348. * 计算全局AQI所有设备PM2.5/PM10平均值
  349. */
  350. calcGlobalAQI() {
  351. this.hasValidData = this.allDevicesPollutantData.length > 0
  352. // 无数据时兜底(和EnvironmentalScreen一致:默认AQI=45,状态=优)
  353. if (!this.hasValidData) {
  354. this.aqiValue = 45
  355. this.aqiStatus = '优'
  356. return
  357. }
  358. // 2. 提取所有设备的PM2.5/PM10数值(转数字,兜底0)
  359. const pm25List = this.allDevicesPollutantData
  360. .filter(item => item.subName === 'PM2.5浓度')
  361. .map(item => parseFloat(item.value) || 0)
  362. const pm10List = this.allDevicesPollutantData
  363. .filter(item => item.subName === 'PM10浓度')
  364. .map(item => parseFloat(item.value) || 0)
  365. // 3. 计算平均值(和EnvironmentalScreen一致:所有设备平均值)
  366. const avgPm25 = pm25List.length > 0
  367. ? (pm25List.reduce((sum, val) => sum + val, 0) / pm25List.length)
  368. : 0
  369. const avgPm10 = pm10List.length > 0
  370. ? (pm10List.reduce((sum, val) => sum + val, 0) / pm10List.length)
  371. : 0
  372. // 4. 完全复用EnvironmentalScreen的国标AQI计算公式
  373. const aqiBpTable = {
  374. pm25: [
  375. { iaqiLo: 0, iaqiHi: 50, bpLo: 0, bpHi: 35 }, // 优
  376. { iaqiLo: 50, iaqiHi: 100, bpLo: 35, bpHi: 75 }, // 良
  377. { iaqiLo: 100, iaqiHi: 150, bpLo: 75, bpHi: 115 }, // 轻度污染
  378. { iaqiLo: 150, iaqiHi: 200, bpLo: 115, bpHi: 150 }, // 中度污染
  379. { iaqiLo: 200, iaqiHi: 300, bpLo: 150, bpHi: 250 }, // 重度污染
  380. { iaqiLo: 300, iaqiHi: 500, bpLo: 250, bpHi: 500 } // 严重污染
  381. ],
  382. pm10: [
  383. { iaqiLo: 0, iaqiHi: 50, bpLo: 0, bpHi: 50 }, // 优
  384. { iaqiLo: 50, iaqiHi: 100, bpLo: 50, bpHi: 150 }, // 良
  385. { iaqiLo: 100, iaqiHi: 150, bpLo: 150, bpHi: 250 }, // 轻度污染
  386. { iaqiLo: 150, iaqiHi: 200, bpLo: 250, bpHi: 350 }, // 中度污染
  387. { iaqiLo: 200, iaqiHi: 300, bpLo: 350, bpHi: 420 }, // 重度污染
  388. { iaqiLo: 300, iaqiHi: 500, bpLo: 420, bpHi: 500 } // 严重污染
  389. ]
  390. }
  391. // 计算单污染物分指数(IAQI)
  392. const calculateIAQI = (conc, pollutantType) => {
  393. const bpTable = aqiBpTable[pollutantType]
  394. if (conc > bpTable[bpTable.length - 1].bpHi) return 500
  395. const matchedBp = bpTable.find(item => conc >= item.bpLo && conc <= item.bpHi) || bpTable[0]
  396. const iaqi = ((matchedBp.iaqiHi - matchedBp.iaqiLo) / (matchedBp.bpHi - matchedBp.bpLo)) * (conc - matchedBp.bpLo) + matchedBp.iaqiLo
  397. return Math.min(Math.round(iaqi), 500)
  398. }
  399. // 计算PM2.5、PM10分指数,取最大值为最终AQI
  400. const iaqiPm25 = calculateIAQI(avgPm25, 'pm25')
  401. const iaqiPm10 = calculateIAQI(avgPm10, 'pm10')
  402. const finalAQI = Math.max(iaqiPm25, iaqiPm10)
  403. // 5. 匹配AQI等级
  404. this.aqiValue = finalAQI
  405. const matchedGrade = this.aqiGradeStandard.find(grade =>
  406. finalAQI >= grade.aqiMin && finalAQI <= grade.aqiMax
  407. )
  408. this.aqiStatus = matchedGrade ? matchedGrade.level : '严重污染'
  409. // 可选:打印日志,便于和EnvironmentalScreen对比
  410. console.log('FullView AQI计算(对齐EnvironmentalScreen):', {
  411. avgPm25: avgPm25.toFixed(2),
  412. avgPm10: avgPm10.toFixed(2),
  413. iaqiPm25,
  414. iaqiPm10,
  415. finalAQI,
  416. aqiStatus: this.aqiStatus
  417. })
  418. },
  419. getIframeLoading(value) {},
  420. deviceState(e) {
  421. this.iframeWin.postMessage({ data: this.oaoMessage }, '*')
  422. },
  423. handleAQI() {
  424. this.oaoMessage.forEach(element => {
  425. window.frames['iframeMap'].setAlertValue(element.id, element.wendu, element.sidu)
  426. })
  427. },
  428. handleAlarm(deviceId) {
  429. window.frames['iframeMap'].Myalert(deviceId, true)
  430. },
  431. handleHide(deviceId) {
  432. window.frames['iframeMap'].setYangGanCanshow(deviceId, true)
  433. }
  434. }
  435. }
  436. </script>
  437. <style lang="scss" scoped>
  438. @import "~@/assets/styles/lend-manage.scss";
  439. .warehouse-left {
  440. position: relative;
  441. }
  442. .container-wrap {
  443. min-height: auto;
  444. height: calc(100% / 2 - 10px);
  445. overflow: hidden;
  446. margin-bottom: 20px;
  447. }
  448. // 新增:设备名称标题样式
  449. .device-name-title {
  450. position: absolute;
  451. top: 0;
  452. left: 0;
  453. color: #fff;
  454. font-size: 18px;
  455. font-weight: 600;
  456. background: rgba(0, 0, 0, 0.3);
  457. padding: 8px 16px;
  458. border-radius: 4px;
  459. z-index: 10;
  460. }
  461. .air-quality{
  462. position: absolute;
  463. bottom: 10px;
  464. right: 20px;
  465. color: #fff;
  466. padding: 20px 20px 10px 20px;
  467. border-radius: 5px;
  468. z-index: 999;
  469. h3{
  470. padding: 30px 0;
  471. }
  472. .air-params{
  473. display: flex;
  474. justify-content: space-between;
  475. align-items: last baseline;
  476. .air-left{
  477. .air-title{
  478. position: relative;
  479. padding-left: 12px;
  480. font-size: 14px;
  481. &::before{
  482. content: "";
  483. position: absolute;
  484. left: 0;
  485. top: 50%;
  486. width: 6px;
  487. height: 6px;
  488. background-color: #18B08F;
  489. border-radius: 50%;
  490. }
  491. }
  492. .air-result{
  493. display: flex;
  494. justify-content: space-between;
  495. align-items: last baseline;
  496. padding-top: 10px;
  497. p{
  498. font-size: 30px;
  499. font-weight: 600;
  500. padding: 0 6px 0 10px;
  501. }
  502. span{
  503. display: block;
  504. font-size: 12px;
  505. opacity: .6;
  506. }
  507. }
  508. }
  509. .air-right{
  510. text-align: center;
  511. span{
  512. display: block;
  513. font-size: 12px;
  514. }
  515. p{
  516. font-size: 18px;
  517. font-weight: 600;
  518. padding: 10px 30px;
  519. margin-top: 10px;
  520. border-radius: 5px;
  521. }
  522. }
  523. }
  524. &.air-excellent { // 优 - 绿色
  525. background-image: linear-gradient(to top, rgba(40, 180, 40, .5), rgba(40, 180, 40, 0));
  526. .air-params .air-right p {
  527. background-color: rgba(40, 180, 40, .2);
  528. }
  529. .air-title::before {
  530. background-color: #28B428;
  531. }
  532. }
  533. &.air-good { // 良 - 黄色
  534. background-image: linear-gradient(to top, rgba(255, 200, 0, .5), rgba(255, 200, 0, 0));
  535. .air-params .air-right p {
  536. background-color: rgba(255, 200, 0, .2);
  537. }
  538. .air-title::before {
  539. background-color: #FFC800;
  540. }
  541. }
  542. &.air-lightPollution { // 轻度污染 - 橙色
  543. background-image: linear-gradient(to top, rgba(255, 140, 0, .5), rgba(255, 140, 0, 0));
  544. .air-params .air-right p {
  545. background-color: rgba(255, 140, 0, .2);
  546. }
  547. .air-title::before {
  548. background-color: #FF8C00;
  549. }
  550. }
  551. &.air-mediumPollution { // 中度污染 - 红色
  552. background-image: linear-gradient(to top, rgba(255, 0, 0, .5), rgba(255, 0, 0, 0));
  553. .air-params .air-right p {
  554. background-color: rgba(255, 0, 0, .2);
  555. }
  556. .air-title::before {
  557. background-color: #FF0000;
  558. }
  559. }
  560. &.air-heavyPollution { // 重度污染 - 紫色
  561. background-image: linear-gradient(to top, rgba(150, 0, 200, .5), rgba(150, 0, 200, 0));
  562. .air-params .air-right p {
  563. background-color: rgba(150, 0, 200, .2);
  564. }
  565. .air-title::before {
  566. background-color: #9600C8;
  567. }
  568. }
  569. &.air-severePollution { // 严重污染 - 褐红色
  570. background-image: linear-gradient(to top, rgba(120, 0, 0, .5), rgba(120, 0, 0, 0));
  571. .air-params .air-right p {
  572. background-color: rgba(120, 0, 0, .2);
  573. }
  574. .air-title::before {
  575. background-color: #780000;
  576. }
  577. }
  578. }
  579. // 兼容原有air-warn类(可选,可删除)
  580. .air-warn{
  581. background-image: linear-gradient(to top, rgba(246, 81, 99, .5), rgba(24, 176, 143, 0));
  582. .air-params{
  583. .air-right{
  584. p{
  585. background-color: rgba(246, 81, 99, .2);
  586. }
  587. }
  588. }
  589. }
  590. .msg-list{
  591. position: static;
  592. flex-wrap: wrap !important;
  593. li{
  594. margin-bottom: 20px;
  595. }
  596. }
  597. </style>