windAndFloodPrevention.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. <template>
  2. <div class="container">
  3. <div class="card">
  4. <div class="card-header">
  5. <i class="icon-line" />
  6. <div class="text">气温降水实况</div>
  7. </div>
  8. <div class="card-content">
  9. <div class="flex-end">
  10. <el-select v-model="tabActive" :teleported="false" cl>
  11. <el-option
  12. v-for="item in tabs"
  13. :key="item.value"
  14. :label="item.name"
  15. :value="item.value"
  16. />
  17. </el-select>
  18. </div>
  19. <img
  20. class="img-box"
  21. :src="liveMapState.data[0] ? liveMapState.data[0].pic_url : ''"
  22. />
  23. </div>
  24. </div>
  25. <div class="card">
  26. <div class="card-header">
  27. <i class="icon-line" />
  28. <div class="text">气象卫星图</div>
  29. </div>
  30. <div class="card-content">
  31. <img class="img-box" :src="temp1" />
  32. </div>
  33. </div>
  34. <div class="card">
  35. <div class="card-header">
  36. <i class="icon-line" />
  37. <div class="text">一周预报</div>
  38. </div>
  39. <div class="card-content3">
  40. <div
  41. v-for="(item, index) in weekForecast"
  42. :key="index"
  43. class="card-item"
  44. >
  45. <div class="text1">{{ item.name }}</div>
  46. <div class="text1">
  47. <i :class="getClass(item.type1)" />{{ item.type1 }}
  48. </div>
  49. <div class="text1">{{ item.data1 }}℃</div>
  50. <div class="text1">{{ item.data2 }}</div>
  51. <div class="text1">|</div>
  52. <div class="text1">
  53. <i :class="getClass(item.type2)" />{{ item.type2 }}
  54. </div>
  55. <div class="text1">{{ item.data3 }}℃</div>
  56. <div class="text1">{{ item.data4 }}</div>
  57. </div>
  58. </div>
  59. </div>
  60. <div class="card">
  61. <div class="card-header">
  62. <i class="icon-line" />
  63. <div class="text">逐小时预报</div>
  64. </div>
  65. <div class="card-content">
  66. <Chart :option="option1" style="height: 240px" />
  67. </div>
  68. </div>
  69. <div class="card">
  70. <div class="card-header">
  71. <i class="icon-line" />
  72. <div class="text">水库监测</div>
  73. </div>
  74. <div class="card-content2">
  75. <div class="card-item">
  76. <i class="icon1" />
  77. <div class="flex">
  78. <div class="text1">漫坝</div>
  79. <div class="text2 text-red">
  80. 11
  81. <div class="text3">个</div>
  82. </div>
  83. </div>
  84. </div>
  85. <div class="card-item2">
  86. <i class="icon2" />
  87. <div class="flex">
  88. <div class="text1">超保证</div>
  89. <div class="text2 text-orange">
  90. 40
  91. <div class="text3">个</div>
  92. </div>
  93. </div>
  94. </div>
  95. <div class="card-item3">
  96. <i class="icon3" />
  97. <div class="flex">
  98. <div class="text1">超警戒</div>
  99. <div class="text2 text-blue">
  100. 37
  101. <div class="text3">个</div>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. </div>
  107. <div class="card">
  108. <div class="card-header">
  109. <i class="icon-line" />
  110. <div class="text">河道监测</div>
  111. </div>
  112. <div class="card-content2">
  113. <div class="card-item">
  114. <i class="icon1" />
  115. <div class="flex">
  116. <div class="text1">{{ riverStatus[0].type }}</div>
  117. <div class="text2 text-red">
  118. {{ riverStatus[0].value }}
  119. <div class="text3">个</div>
  120. </div>
  121. </div>
  122. </div>
  123. <div class="card-item2">
  124. <i class="icon2" />
  125. <div class="flex">
  126. <div class="text1">{{ riverStatus[1].type }}</div>
  127. <div class="text2 text-orange">
  128. {{ riverStatus[1].value }}
  129. <div class="text3">个</div>
  130. </div>
  131. </div>
  132. </div>
  133. <div class="card-item3">
  134. <i class="icon3" />
  135. <div class="flex">
  136. <div class="text1">{{ riverStatus[2].type }}</div>
  137. <div class="text2 text-blue">
  138. {{ riverStatus[2].value }}
  139. <div class="text3">个</div>
  140. </div>
  141. </div>
  142. </div>
  143. </div>
  144. </div>
  145. <div class="card">
  146. <div class="card-header">
  147. <i class="icon-line" />
  148. <div class="text">易涝点</div>
  149. </div>
  150. <div class="card-content2">
  151. <el-table
  152. :data="detailsData.dataList"
  153. header-cell-class-name="common-table-header"
  154. :row-class-name="getTableRowClass"
  155. table-layout="auto"
  156. class="common-table"
  157. >
  158. <el-table-column prop="area" align="center">
  159. <template #header>
  160. <div class="table-line" @click="showPicker = true">
  161. <div>{{ !!labelData ? labelData : "所有区县" }}</div>
  162. <i class="icon-down" />
  163. </div>
  164. </template>
  165. </el-table-column>
  166. <el-table-column
  167. label="易涝点名称"
  168. prop="flood_name"
  169. align="center"
  170. />
  171. <el-table-column label="提供单位" prop="unit" align="center" />
  172. <el-table-column label="视频" prop="publicTime" align="center">
  173. <template #default="scope">
  174. <div class="btn" @click="handlePlay(scope.row)">播放</div>
  175. </template>
  176. </el-table-column>
  177. </el-table>
  178. </div>
  179. <pagination
  180. v-show="total > 0"
  181. v-model:page="queryParams2.current"
  182. v-model:limit="queryParams2.size"
  183. :total="total"
  184. :pager-count="3"
  185. size="small"
  186. layout="prev, pager, next"
  187. @pagination="getTableDetail"
  188. />
  189. </div>
  190. <van-popup v-model:show="showPicker" round position="bottom">
  191. <van-picker
  192. :columns="columns"
  193. @cancel="showPicker = false"
  194. @confirm="onSelectTypeConfirm"
  195. />
  196. </van-popup>
  197. </div>
  198. </template>
  199. <script lang="ts" setup>
  200. import { ElSelect, ElOption, ElTable, ElTableColumn } from "element-plus";
  201. import { onMounted, reactive, ref, watch } from "vue";
  202. import { getTemperature } from "@/api/disasterRiskMonitor/windAndFloodPrevention";
  203. import temp1 from "@/assets/temp1.jfif";
  204. import { chartOption2 } from "./chartOptions";
  205. import { getEasyFlood } from "@/api/disasterRiskMonitor/easyFlood";
  206. import router from "@/router";
  207. import { getRiverStatus } from "@/api/disasterRiskMonitor/riverInform";
  208. let tabs = reactive([
  209. { name: "6h降水", value: "6h_precipitation" },
  210. { name: "24h降水", value: "24h_precipitation" },
  211. { name: "整点气温", value: "hourly_temperature" },
  212. { name: "24h最高温", value: "24h_max_temperature" },
  213. { name: "24h最低温", value: "24h_min_temperature" },
  214. { name: "24小时变温", value: "24h_variable_temperature" }
  215. ]);
  216. let tabActive = ref("hourly_temperature");
  217. const riverStatus = ref();
  218. const liveMapState = reactive({
  219. show: false,
  220. activeIndex: 0,
  221. speed: 1,
  222. playing: false,
  223. data: []
  224. });
  225. let weekForecast = ref([
  226. {
  227. name: "今天",
  228. type1: "晴",
  229. data1: "32.6",
  230. data2: "小于3级",
  231. type2: "阴",
  232. data3: "32.6",
  233. data4: "小于3级"
  234. },
  235. {
  236. name: "今天",
  237. type1: "晴",
  238. data1: "32.6",
  239. data2: "小于3级",
  240. type2: "阴",
  241. data3: "32.6",
  242. data4: "小于3级"
  243. },
  244. {
  245. name: "今天",
  246. type1: "雷雨",
  247. data1: "32.6",
  248. data2: "小于3级",
  249. type2: "阴",
  250. data3: "32.6",
  251. data4: "小于3级"
  252. },
  253. {
  254. name: "今天",
  255. type1: "晴",
  256. data1: "32.6",
  257. data2: "小于3级",
  258. type2: "阴",
  259. data3: "32.6",
  260. data4: "小于3级"
  261. },
  262. {
  263. name: "今天",
  264. type1: "雷雨",
  265. data1: "32.6",
  266. data2: "小于3级",
  267. type2: "阴",
  268. data3: "32.6",
  269. data4: "小于3级"
  270. },
  271. {
  272. name: "今天",
  273. type1: "晴",
  274. data1: "32.6",
  275. data2: "小于3级",
  276. type2: "阴",
  277. data3: "32.6",
  278. data4: "小于3级"
  279. },
  280. {
  281. name: "今天",
  282. type1: "晴",
  283. data1: "32.6",
  284. data2: "小于3级",
  285. type2: "阴",
  286. data3: "32.6",
  287. data4: "小于3级"
  288. }
  289. ]);
  290. let detailsData = ref({
  291. dataList: []
  292. });
  293. let showPicker = ref(false);
  294. let labelData = ref("");
  295. let total = ref(0);
  296. const columns = ref([
  297. { text: "所有区县", value: "" },
  298. { text: "茂南区", value: "1" },
  299. { text: "信宜市", value: "2" }
  300. ]);
  301. let queryParams = reactive({
  302. area: ""
  303. });
  304. const queryParams2 = ref({
  305. query: {
  306. area: "",
  307. keyword: ""
  308. },
  309. current: 1,
  310. size: 10
  311. });
  312. const option1 = ref(chartOption2);
  313. const getRiverDetail = () => {
  314. getRiverStatus().then(res => {
  315. riverStatus.value = res.rows;
  316. });
  317. };
  318. getRiverDetail();
  319. watch(
  320. () => liveMapState.show,
  321. () => {
  322. if (!liveMapState.show) {
  323. liveMapState.playing = false;
  324. liveMapState.activeIndex = 0;
  325. }
  326. },
  327. {
  328. immediate: true
  329. }
  330. );
  331. const onSelectTypeConfirm = ({ selectedOptions }) => {
  332. showPicker.value = false;
  333. labelData.value = selectedOptions[0].text;
  334. queryParams.area = selectedOptions[0].value;
  335. initData();
  336. };
  337. const getClass = name => {
  338. let res = "";
  339. if (name === "晴") {
  340. res = "icon1";
  341. } else if (name === "阴") {
  342. res = "icon2";
  343. } else if (name === "雷雨") {
  344. res = "icon3";
  345. }
  346. return res;
  347. };
  348. const initData = () => {
  349. getTemperature({ args: tabActive.value }).then(res => {
  350. liveMapState.data = res.data.max_level;
  351. });
  352. // detailsData.value.dataList = [
  353. // { area: "茂南区", name: "高山铁路桥底", data1: "城市管理和综合执法局" },
  354. // { area: "茂南区", name: "油城二路桥底", data1: "城市管理和综合执法局" },
  355. // { area: "茂南区", name: "榕园东北侧", data1: "城市管理和综合执法局" },
  356. // { area: "茂南区", name: "人民中路", data1: "城市管理和综合执法局" },
  357. // { area: "化州市", name: "橘城南路", data1: "城市管理和综合执法局" },
  358. // { area: "化州市", name: "下郭大道", data1: "城市管理和综合执法局" },
  359. // { area: "化州市", name: "河西沙埚村", data1: "城市管理和综合执法局" }
  360. // ];
  361. getTableDetail();
  362. option1.value.xAxis.data = [
  363. "19时",
  364. "20时",
  365. "21时",
  366. "22时",
  367. "23时",
  368. "24时",
  369. "1时",
  370. "2时",
  371. "3时",
  372. "40时",
  373. "5时",
  374. "6时",
  375. "7时",
  376. "8时",
  377. "9时",
  378. "10时",
  379. "11时",
  380. "12时",
  381. "13时",
  382. "14时",
  383. "15时",
  384. "16时",
  385. "17时",
  386. "18时"
  387. ];
  388. option1.value.series[0].data = [
  389. "22",
  390. "22",
  391. "21",
  392. "21",
  393. "20",
  394. "20",
  395. "19",
  396. "19",
  397. "19",
  398. "20",
  399. "21",
  400. "22",
  401. "22",
  402. "23",
  403. "24",
  404. "25",
  405. "25",
  406. "25",
  407. "24",
  408. "23",
  409. "24",
  410. "23",
  411. "22",
  412. "22"
  413. ];
  414. option1.value.series[1].data = [
  415. "0.0",
  416. "0.0",
  417. "0.0",
  418. "0.0",
  419. "0.0",
  420. "0.0",
  421. "0.0",
  422. "0.0",
  423. "0.0",
  424. "0.0",
  425. "0.0",
  426. "0.0",
  427. "0.0",
  428. "0.0",
  429. "11.0",
  430. "13.0",
  431. "10.0",
  432. "9.0",
  433. "0.0",
  434. "0.0",
  435. "0.0",
  436. "0.0",
  437. "0.0",
  438. "0.0"
  439. ];
  440. };
  441. const getTableDetail = () => {
  442. getEasyFlood(queryParams2.value).then(res => {
  443. detailsData.value.dataList = res.rows;
  444. total.value = res.total;
  445. });
  446. };
  447. // table样式
  448. const getTableRowClass = ({ rowIndex }) => {
  449. return rowIndex % 2 === 0 ? "" : "common-table-tr";
  450. };
  451. const handlePlay = row => {
  452. router.push({
  453. name: "WindAndFloodPreventionView",
  454. query: {
  455. latitude: row.lat,
  456. longitude: row.lng,
  457. name: encodeURIComponent(row.flood_name)
  458. }
  459. });
  460. };
  461. onMounted(() => {
  462. initData();
  463. });
  464. </script>
  465. <style lang="scss" scoped>
  466. .container {
  467. height: calc(100vh);
  468. padding: 16px;
  469. .card {
  470. background-color: #ffffff;
  471. border: 1px solid #eaedf7;
  472. box-shadow: 0 0 4px 0 #4554661a;
  473. border-radius: 4px;
  474. padding: 2px;
  475. margin-top: 16px;
  476. &:first-child {
  477. margin-top: 0;
  478. }
  479. .card-header {
  480. font-size: 16px;
  481. color: #414f64;
  482. font-weight: bold;
  483. line-height: 26px;
  484. padding: 11px 10px;
  485. display: flex;
  486. align-items: center;
  487. border-top-left-radius: 4px;
  488. border-top-right-radius: 4px;
  489. background-image: linear-gradient(180deg, #f3f7fd 0%, #ffffff 100%);
  490. .icon-line {
  491. display: inline-block;
  492. width: 6px;
  493. height: 16px;
  494. background: url("@/assets/images/line.jpg") no-repeat;
  495. background-size: 100% 100%;
  496. margin-right: 3px;
  497. }
  498. }
  499. .card-content {
  500. padding-bottom: 13px;
  501. .flex-end {
  502. display: flex;
  503. justify-content: flex-end;
  504. padding: 0 5px;
  505. .el-select {
  506. width: 120px;
  507. }
  508. }
  509. .img-box {
  510. cursor: pointer;
  511. margin-top: 13px;
  512. }
  513. }
  514. .card-content2 {
  515. display: flex;
  516. justify-content: space-between;
  517. align-items: center;
  518. .card-item {
  519. background: url("@/assets/images/disasterRiskMonitor/windAndFloodPrevention/box1.png")
  520. no-repeat;
  521. }
  522. .card-item2 {
  523. background: url("@/assets/images/disasterRiskMonitor/windAndFloodPrevention/box2.png")
  524. no-repeat;
  525. }
  526. .card-item3 {
  527. background: url("@/assets/images/disasterRiskMonitor/windAndFloodPrevention/box3.png")
  528. no-repeat;
  529. }
  530. .card-item,
  531. .card-item2,
  532. .card-item3 {
  533. width: 106px;
  534. height: 71px;
  535. background-size: 100% 100%;
  536. display: flex;
  537. align-items: center;
  538. padding: 10px 13px;
  539. .icon1 {
  540. display: inline-block;
  541. width: 25px;
  542. height: 27px;
  543. background: url("@/assets/images/disasterRiskMonitor/windAndFloodPrevention/icon1.png")
  544. no-repeat;
  545. background-size: 100% 100%;
  546. }
  547. .icon2 {
  548. display: inline-block;
  549. width: 25px;
  550. height: 27px;
  551. background: url("@/assets/images/disasterRiskMonitor/windAndFloodPrevention/icon2.png")
  552. no-repeat;
  553. background-size: 100% 100%;
  554. }
  555. .icon3 {
  556. display: inline-block;
  557. width: 25px;
  558. height: 26px;
  559. background: url("@/assets/images/disasterRiskMonitor/windAndFloodPrevention/icon3.png")
  560. no-repeat;
  561. background-size: 100% 100%;
  562. }
  563. .flex {
  564. display: flex;
  565. flex-direction: column;
  566. margin-left: 16px;
  567. .text1 {
  568. font-size: 12px;
  569. }
  570. .text2 {
  571. display: flex;
  572. align-items: baseline;
  573. font-size: 24px;
  574. font-weight: bold;
  575. }
  576. .text3 {
  577. font-size: 12px;
  578. font-weight: normal;
  579. color: #414f64;
  580. }
  581. .text-red {
  582. color: #ff2f3c;
  583. }
  584. .text-orange {
  585. color: #ffaf00;
  586. }
  587. .text-blue {
  588. color: #2c81ff;
  589. }
  590. }
  591. }
  592. }
  593. .card-content3 {
  594. display: flex;
  595. padding-bottom: 16px;
  596. overflow-x: auto;
  597. .card-item {
  598. display: flex;
  599. flex-direction: column;
  600. align-items: center;
  601. min-width: 60px;
  602. height: 194px;
  603. background-image: linear-gradient(
  604. 180deg,
  605. #ffffff 0%,
  606. #f6f9ff 79%,
  607. #f8faff 100%
  608. );
  609. border: 2px solid #ffffff;
  610. box-shadow:
  611. 0 2px 1px -1px #bcd7ffb5,
  612. inset 0 1px 3px 6px #ace2ff08;
  613. border-radius: 4px;
  614. margin-left: 5px;
  615. padding: 20px 5px;
  616. &:first-child {
  617. margin-left: 0;
  618. }
  619. .text1 {
  620. display: flex;
  621. justify-content: center;
  622. align-items: center;
  623. font-size: 12px;
  624. color: #414f64;
  625. line-height: 21px;
  626. }
  627. }
  628. }
  629. }
  630. .btn {
  631. font-size: 14px;
  632. color: #2c81ff;
  633. }
  634. }
  635. </style>