weatherForecast.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. <template>
  2. <div class="wf-box" :style="{ height: boxHeight + 'px' }">
  3. <a-tabs v-model:activeKey="activeKey">
  4. <a-tab-pane v-for="(item, index) in weatherData.weatherData.predict.detail" :key="index">
  5. <template #tab>
  6. <div class="tab-box">
  7. <div>{{ item.date }}</div>
  8. <div>{{ setWeek(item.date) }}</div>
  9. <div> <img v-if="item.day.weather.temperature < 999" :src="showImg(item.day.weather.info)" /> </div>
  10. <div>{{ item.day.weather.temperature < 999 ? item.day.weather.info : '' }}</div>
  11. <div>{{ item.day.weather.temperature < 999 ? item.day.wind.direct : '' }}</div>
  12. <div>{{ item.day.weather.temperature < 999 ? item.day.wind.power : '' }}</div>
  13. <div :style="setColor(item.day.weather.temperature)" class="temperature"
  14. >{{ item.day.weather.temperature < 999 ? item.day.weather.temperature : '' }}℃</div
  15. >
  16. <div :style="setColor(item.night.weather.temperature)" class="temperature">{{ item.night.weather.temperature }}℃</div>
  17. <div class="inner-t"> <img :src="showImg(item.night.weather.info)" /> </div>
  18. <div>{{ item.night.weather.info }}</div>
  19. <div>{{ item.night.wind.direct }}</div>
  20. <div>{{ item.night.wind.power }}</div>
  21. </div>
  22. </template>
  23. <div class="wf-content">
  24. <div>
  25. <div>{{ item.date }}</div>
  26. <div>{{ setWeek(item.date) }}</div>
  27. <div> <img src="../../../assets/images/weatherIcon/js-icon.png" />降水</div>
  28. <div> <img src="../../../assets/images/weatherIcon/qw-icon.png" />气温</div>
  29. <div> <img src="../../../assets/images/weatherIcon/fs-icon.png" />风速</div>
  30. <div> <img src="../../../assets/images/weatherIcon/fx-icon.png" />风向</div>
  31. <div> <img src="../../../assets/images/weatherIcon/sd-icon.png" />湿度</div>
  32. </div>
  33. <template v-for="(items, indexs) in item.hour_predict" :key="indexs">
  34. <div v-if="indexs != 0">
  35. <div>{{ items[0] }}</div>
  36. <div><img class="tab-img-d" :src="items[1]" /></div>
  37. <div>{{ items[2] == '-' ? '0mm' : items[2]}}</div>
  38. <!-- strM -->
  39. <div :style="setColor(items[3])" class="temperature">{{ items[3] }}</div>
  40. <div>{{ items[4] }}</div>
  41. <div>{{ items[5] }}</div>
  42. <div>{{ items[6] }}</div>
  43. </div>
  44. </template>
  45. </div>
  46. </a-tab-pane>
  47. </a-tabs>
  48. <div class="wf-echarts-box" id="myElement">
  49. <div class="wf-echarts-title"> 预报曲线 </div>
  50. <div id="wf-echarts" :style="{ width: '100%', height: '280px' }"> </div>
  51. </div>
  52. </div>
  53. </template>
  54. <script lang="ts" setup>
  55. import { ref, getCurrentInstance, watch, onMounted, reactive } from 'vue';
  56. import eventBus from '/@/utils/eventBus';
  57. import elementResizeDetectorMaker from 'element-resize-detector';
  58. let erd = elementResizeDetectorMaker(); //创建实例
  59. let activeKey = ref<Number>(0);
  60. eventBus.on('weatherReset', () => {
  61. // setEcharts();
  62. chart.resize();
  63. });
  64. let boxHeight = ref(900);
  65. eventBus.on('progressHeight', (height) => {
  66. boxHeight.value = height > 900 ? height - 70 : height;
  67. });
  68. // echarts模块
  69. const { proxy } = getCurrentInstance();
  70. const echarts = proxy.$echarts;
  71. // 获取传参
  72. const props = defineProps({
  73. weatherData: {
  74. type: Object,
  75. default: () => {
  76. return {};
  77. },
  78. },
  79. });
  80. watch([() => props.weatherData], (value) => {
  81. // console.log(props.weatherData.weatherData.tempchart);
  82. // console.log('监听图表数据');
  83. // reset();
  84. // setEcharts();
  85. // echarts1();
  86. });
  87. // 写入颜色
  88. function setColor(value) {
  89. let str = value.replace('℃', '') * 1;
  90. let color = {};
  91. if (str <= 15) {
  92. color.background = '#c5f576';
  93. color.color = '#333';
  94. }
  95. if (str > 15 && str <= 20) {
  96. color.background = '#dff3bb';
  97. color.color = '#333';
  98. color.color = '#333';
  99. }
  100. if (str > 20 && str <= 25) {
  101. color.background = '#efdb64';
  102. color.color = '#333';
  103. }
  104. if (str > 25 && str <= 30) {
  105. color.background = '#e4ad54';
  106. color.color = '#333';
  107. }
  108. if (str > 30) {
  109. color.background = '#db9148';
  110. color.color = '#333';
  111. }
  112. return color;
  113. }
  114. function showImg(value) {
  115. // return require(`../../assets/images/weatherIcon/${value}.png`);
  116. return new URL(`../../../assets/images/weatherIcon/${value}.png`, import.meta.url).href;
  117. }
  118. // 通过年月日获取星期几
  119. function setWeek(date) {
  120. let weeks = ['日', '一', '二', '三', '四', '五', '六'];
  121. let day = new Date(date || new Date()).getDay();
  122. return '星期' + weeks[day];
  123. }
  124. let chart = null;
  125. function echarts1() {
  126. chart = echarts.init(document.getElementById('wf-echarts'));
  127. var option;
  128. option = {
  129. tooltip: {
  130. trigger: 'axis',
  131. axisPointer: {
  132. type: 'shadow',
  133. },
  134. formatter: function (params) {
  135. return `<div>
  136. <div>
  137. 高温(℃):${params[0].value == '-' ? params[1].value : params[0].value}
  138. </div>
  139. <div>
  140. 低温(℃):${params[2].value == '-' ? params[3].value : params[2].value}
  141. </div>
  142. </div>`;
  143. },
  144. },
  145. grid: {
  146. left: '3%', //默认10%
  147. right: '4%', //默认10%
  148. bottom: '4%', //默认60
  149. containLabel: true,
  150. //grid区域是否包含坐标轴的刻度标签
  151. },
  152. legend: {
  153. data: ['高温', '低温'],
  154. textStyle: {
  155. fontSize: 14, //字体大小
  156. color: '#ffffff', //字体颜色
  157. },
  158. left: 'right',
  159. },
  160. xAxis: {
  161. type: 'category',
  162. data: dataIns.name,
  163. axisLabel: {
  164. //x轴文字的配置
  165. show: true,
  166. textStyle: {
  167. color: '#fff',
  168. },
  169. formatter: function (val) {
  170. var strs = val.split(''); //字符串数组
  171. var str = '';
  172. for (var i = 0, s; (s = strs[i++]); ) {
  173. //遍历字符串数组
  174. if (i > 5 && i < 17) {
  175. str += s;
  176. }
  177. if (!(i % 10)) str += '\n'; //按需要求余
  178. }
  179. if (val === getNowDate()) {
  180. return str + '\n' + '今天';
  181. } else {
  182. return str + '\n' + setWeek(val);
  183. }
  184. },
  185. },
  186. },
  187. yAxis: [
  188. {
  189. name: '温度:℃',
  190. type: 'value',
  191. splitNumber: 5,
  192. axisLabel: {
  193. //y轴文字的配置
  194. textStyle: {
  195. color: '#fff',
  196. margin: 15,
  197. },
  198. // formatter: '{value} %'//y轴的每一个刻度值后面加上‘%’号
  199. },
  200. splitLine: {
  201. //网格线
  202. lineStyle: {
  203. type: 'dotted', //设置网格线类型 dotted:虚线 solid:实线
  204. width: 1, //y轴线的宽度
  205. color: '#484849',
  206. },
  207. show: true, //隐藏或显示
  208. },
  209. nameTextStyle: {
  210. color: 'rgba(255, 255, 255, 0.8)', //颜色
  211. },
  212. },
  213. {
  214. type: 'value',
  215. splitNumber: 5,
  216. axisLabel: {
  217. //y轴文字的配置
  218. textStyle: {
  219. color: '#fff',
  220. margin: 15,
  221. },
  222. // formatter: '{value} %'//y轴的每一个刻度值后面加上‘%’号
  223. },
  224. splitLine: {
  225. //网格线
  226. lineStyle: {
  227. type: 'dotted', //设置网格线类型 dotted:虚线 solid:实线
  228. width: 1, //y轴线的宽度
  229. color: '#484849',
  230. },
  231. show: true, //隐藏或显示
  232. },
  233. nameTextStyle: {
  234. color: 'rgba(255, 255, 255, 0.8)', //颜色
  235. padding: [0, 0, 0, 30],
  236. },
  237. },
  238. ],
  239. series: [
  240. {
  241. name: '高温',
  242. type: 'line',
  243. data: dataIns.beforeMax,
  244. smooth: true,
  245. itemStyle: {
  246. normal: {
  247. color: '#FF541B', //改变折线点的颜色
  248. lineStyle: {
  249. color: '#FF541B', //改变折线颜色
  250. },
  251. },
  252. },
  253. },
  254. {
  255. name: '高温',
  256. type: 'line',
  257. smooth: true, //关键点,为true是不支持虚线,实线就用true
  258. itemStyle: {
  259. normal: {
  260. color: '#FF541B', //改变折线点的颜色
  261. lineStyle: {
  262. width: 2,
  263. type: 'dotted', //'dotted'虚线 'solid'实线
  264. color: '#FF541B', //改变折线颜色
  265. },
  266. },
  267. },
  268. data: dataIns.afterMax,
  269. },
  270. {
  271. name: '低温',
  272. type: 'line',
  273. data: dataIns.beforeMin,
  274. smooth: true,
  275. itemStyle: {
  276. normal: {
  277. color: '#00D8F0', //改变折线点的颜色
  278. lineStyle: {
  279. color: '#00D8F0', //改变折线颜色
  280. },
  281. },
  282. },
  283. },
  284. {
  285. name: '低温',
  286. type: 'line',
  287. smooth: true, //关键点,为true是不支持虚线,实线就用true
  288. itemStyle: {
  289. normal: {
  290. color: '#00D8F0', //改变折线点的颜色
  291. lineStyle: {
  292. width: 2,
  293. type: 'dotted', //'dotted'虚线 'solid'实线
  294. color: '#00D8F0', //改变折线颜色
  295. },
  296. },
  297. },
  298. data: dataIns.afterMin,
  299. },
  300. ],
  301. };
  302. option && chart.setOption(option);
  303. // window.addEventListener('resize', function () {
  304. // chart.resize();
  305. // });
  306. }
  307. let dataIns = reactive({
  308. name: [],
  309. beforeMin: [],
  310. beforeMax: [],
  311. afterMin: [],
  312. afterMax: [],
  313. });
  314. function reset() {
  315. // 重置数据:
  316. dataIns.name = [];
  317. dataIns.beforeMin = [];
  318. dataIns.beforeMax = [];
  319. dataIns.afterMin = [];
  320. dataIns.afterMax = [];
  321. }
  322. function setEcharts() {
  323. dataIns.name = [];
  324. let tempchart = props.weatherData.weatherData.tempchart;
  325. // js 获取今天的年月日
  326. let day = getNowDate();
  327. // 记录今天的索引//默认100
  328. let dayIndex = 100;
  329. // props.weatherData.weatherData.tempchart
  330. tempchart.forEach((element, index) => {
  331. dataIns.name.push(element.time);
  332. if (element.time === day) {
  333. dayIndex = index;
  334. dataIns.beforeMin.push(element.min_temp);
  335. dataIns.beforeMax.push(element.max_temp);
  336. dataIns.afterMin.push(element.min_temp);
  337. dataIns.afterMax.push(element.max_temp);
  338. }
  339. if (index < dayIndex) {
  340. dataIns.beforeMin.push(element.min_temp);
  341. dataIns.beforeMax.push(element.max_temp);
  342. dataIns.afterMin.push('-');
  343. dataIns.afterMax.push('-');
  344. }
  345. if (index > dayIndex) {
  346. dataIns.beforeMin.push('-');
  347. dataIns.beforeMax.push('-');
  348. dataIns.afterMin.push(element.min_temp);
  349. dataIns.afterMax.push(element.max_temp);
  350. }
  351. });
  352. }
  353. //js 获取今天,明天,后天的年月日
  354. function getNowDate(obj) {
  355. var d = new Date(); //创建 Date 对象的语法
  356. var vYear = d.getFullYear(); //获得当前年(4位数)
  357. var vMon = d.getMonth() + 1; //获得当前月(月份默认计算是从0开始,0-11代表1-12月,加1比较直观些)
  358. var vDay = d.getDate(); //获得当前日(1-31)
  359. //拼接成完整日期,格式如:2019-06-17
  360. var nowDate = vYear + '/' + (vMon < 10 ? '0' + vMon : vMon) + '/' + (vDay < 10 ? '0' + vDay : vDay);
  361. //返回完整日期
  362. return nowDate;
  363. }
  364. const myElement = ref(null);
  365. // 图表方法结束
  366. onMounted(() => {
  367. setEcharts();
  368. echarts1();
  369. erd.listenTo(document.getElementById('myElement'), (element) => {
  370. chart.resize();
  371. });
  372. });
  373. </script>
  374. <style lang="less" scoped>
  375. .wf-box {
  376. width: 100%;
  377. overflow: auto;
  378. }
  379. .wf-box .tab-box {
  380. color: #fff !important;
  381. background-color: #06305e;
  382. text-align: center;
  383. // width: 13%;
  384. padding-bottom: 10px;
  385. & > div {
  386. height: 40px;
  387. font-size: 16px;
  388. line-height: 40px;
  389. }
  390. img {
  391. display: inline-block;
  392. }
  393. }
  394. .wf-box {
  395. padding: 10px;
  396. }
  397. ::v-deep(.ant-tabs-nav .ant-tabs-tab) {
  398. margin: 0;
  399. padding: 0;
  400. width: 13%;
  401. margin-left: 1.28%;
  402. }
  403. ::v-deep(.ant-tabs-nav .ant-tabs-tab:nth-child(1)) {
  404. margin-left: 0%;
  405. }
  406. .temperature {
  407. background-color: #dcb640;
  408. }
  409. ::v-deep(.ant-tabs-tab-active .tab-box) {
  410. background-color: rgba(0, 234, 255, 0.3) !important;
  411. }
  412. ::v-deep(.ant-tabs-ink-bar) {
  413. width: 0;
  414. height: 0;
  415. border-left: 5px solid transparent;
  416. border-right: 5px solid transparent;
  417. border-top: 15px solid rgba(0, 234, 255, 0.3);
  418. width: 10px;
  419. background-color: transparent !important;
  420. position: relative;
  421. top: 0px;
  422. left: 5%;
  423. }
  424. ::v-deep(.ant-tabs-ink-bar) {
  425. width: 0 !important;
  426. height: 0 !important;
  427. border-left: 10px solid transparent;
  428. border-right: 10px solid transparent;
  429. border-top: 15px solid rgba(0, 234, 255, 0.3);
  430. background-color: transparent !important;
  431. }
  432. ::v-deep(.ant-tabs-bar) {
  433. border-bottom: 0px solid #303030 !important;
  434. }
  435. .wf-content {
  436. width: 100%;
  437. border-radius: 4px;
  438. overflow: hidden;
  439. display: flex;
  440. background-color: #06305e;
  441. & > div:hover {
  442. background-color: rgba(23, 134, 255, 0.1);
  443. }
  444. & > div {
  445. width: 11%;
  446. text-align: center;
  447. font-size: 16px;
  448. & > div {
  449. line-height: 50px;
  450. color: #fff;
  451. // img {
  452. // width: 50px;
  453. // }
  454. }
  455. }
  456. & > div:nth-child(1) {
  457. width: 12%;
  458. background-color: rgba(8, 97, 122, 0.63);
  459. border-bottom: 1px solid #ddd;
  460. }
  461. img {
  462. display: inline-block;
  463. vertical-align: middle;
  464. margin-right: 10px;
  465. }
  466. }
  467. .wf-echarts-title {
  468. color: #00d8f0;
  469. font-size: 14px;
  470. border-bottom: 1px solid rgba(19, 94, 176, 0.52);
  471. padding: 10px 0;
  472. }
  473. // #wf-echarts {
  474. // background-color: red;
  475. // }
  476. .tab-img-d {
  477. width: 50px;
  478. margin-right: 0px;
  479. }
  480. .inner-t {
  481. line-height: 60px;
  482. height: 60px !important;
  483. padding-top: 10px;
  484. }
  485. </style>
  486. <style>
  487. /* .wrap-power-big .wf-box {
  488. height: 1000px;
  489. }
  490. .wrap-power-min .wf-box {
  491. height: 900px;
  492. } */
  493. .wrap-power-big .wf-box .tab-box > div {
  494. height: 33px;
  495. line-height: 33px;
  496. }
  497. .wrap-power-big .wf-content > div > div {
  498. height: 35px;
  499. line-height: 35px;
  500. }
  501. .wrap-power-big .wf-box .tab-box .inner-t {
  502. height: 33px !important;
  503. line-height: 33px !important;
  504. }
  505. .wrap-power-big .wf-box .tab-box img {
  506. width: 40px;
  507. }
  508. .wrap-power-big .wf-box .tab-box .inner-t img {
  509. position: relative;
  510. top: -10px;
  511. }
  512. </style>