最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Electron+Vue3 MAC 版日历 开发记录(5)——天气预报

    正文概述 掘金(叶梅树)   2021-06-05   728

    这是我参与更文挑战的第5天,活动详情查看: 更文挑战

    Electron+Vue3 MAC 版日历 开发记录(5)——天气预报

    有了之前的框架整理和基本农历功能,接着就可以在 日历 View 里增加显示天气情况。

    天气预报

    实现天气预报的功能,还是比较简单得。

    1. 从天气预报服务商实时获取天气信息;
    2. 数据缓存;
    3. 显示在页面中;
    4. 设置是否显示天气预报的开关。

    和风天气

    在国内提供天气预报 API/SDK 的平台不少,其中「和风天气」是佼佼者。

    Electron+Vue3 MAC 版日历 开发记录(5)——天气预报

    开发具体看:和风天气开发平台

    服务端开发

    服务端主要使用到和风天气 API 的有:

    1. 城市信息查询接口:dev.qweather.com/docs/api/ge…
    2. 实时天气接口:dev.qweather.com/docs/api/we…
    3. 逐天(3 天)天气预报接口:dev.qweather.com/docs/api/we…
    4. 实时空气质量接口:dev.qweather.com/docs/api/ai…

    具体 Laravel 代码:

    <?php
    /**
     * User: yemeishu
     */
    
    namespace App\Http\Controllers;
    
    use Carbon\Carbon;
    use GuzzleHttp\Client;
    use GuzzleHttp\Pool;
    use Illuminate\Http\Request;
    use GuzzleHttp\Psr7\Request as GRequest;
    use Illuminate\Support\Arr;
    use function Matrix\add;
    
    class WeatherController extends Controller
    {
        private $counter = 1;
        private $result = [];
        private $public_id = "***";
        private $key = "***";
    
        // 和风天气开发平台
        // https://dev.qweather.com/docs/api/weather/
        // 实况接口
        private $now_finance_api = "https://api.qweather.com/v7/weather/now";
        private $now_dev_api = "https://devapi.qweather.com/v7/weather/now";
    
        // 3天预报接口
        private $td_finance_api = "https://api.qweather.com/v7/weather/3d";
        private $td_dev_api = "https://devapi.qweather.com/v7/weather/3d";
    
        // 空气质量接口
        private $air_finance_api = "https://api.qweather.com/v7/air/now";
        private $air_dev_api = "https://devapi.qweather.com/v7/air/now";
    
        // 城市信息搜索接口
        // 需要存于数据库,避免多次查询接口
        // 每天每个账号下所有应用前50000次免费
        private $city_lookup_api = "https://geoapi.qweather.com/v2/city/lookup";
    
        // 默认以石家庄经纬度为例
        private $coordinate_default = "114.48,38.03";
    
        private $location;
    
        private $finance_api = [
            "https://geoapi.qweather.com/v2/city/lookup",
            "https://api.qweather.com/v7/weather/now",
            "https://api.qweather.com/v7/weather/3d",
            "https://api.qweather.com/v7/air/now"
        ];
    
        private $dev_api = [
            "https://geoapi.qweather.com/v2/city/lookup",
            "https://devapi.qweather.com/v7/weather/now",
            "https://devapi.qweather.com/v7/weather/3d",
            "https://devapi.qweather.com/v7/air/now"
        ];
    
        public function weatherData(Request $request)
        {
            $this->location = $request->input('location', $this->coordinate_default);
    
            $client = new Client();
    
            $requests = function ($apis) {
                foreach ($apis as $api) {
                    yield new GRequest(
                        'GET',
                        "$api?location=$this->location&key=$this->key"
                    );
                }
            };
    
            $pool = new Pool(
                $client,
                $requests($this->dev_api),
                [
                'concurrency' => 3,
                'fulfilled' => function ($response, $index) {
                    $data = json_decode($response->getBody()->getContents(), true);
                    $this->change2result($data);
                    if ($this->countedAndCheckEnded($data)) {
                        return $this->result;
                    }
                },
                'rejected' => function ($reason, $index) {
                    info('weather rejected', [$reason]);
                    // this is delivered each failed request
                },
            ]);
    
            $promise = $pool->promise();
    
            $promise->wait();
    
            return $this->result;
        }
    
        private function countedAndCheckEnded($data)
        {
            if ($this->counter < count($this->dev_api)){
                $this->counter++;
                return false;
            }
            return true;
        }
    
        private function change2result($data)
        {
            if ($data['code'] == 200) {
                if (Arr::has($data, 'updateTime')) {
                    $this->result['updateTime'] = (new Carbon($data['updateTime']))->toDateTimeString();
                }
    
                if (Arr::has($data, 'now')) {
                    foreach ($data['now'] as $key => $value) {
                        $this->result['weatherNow'][$key] = $value;
                    }
                }
    
                if (Arr::has($data, 'daily')) {
                    $this->result['weatherDailies'] = $data['daily'];
                }
    
                if (Arr::has($data, 'location')) {
                    $this->result['locations'] = $data['location'];
                }
            }
        }
    }
    

    默认使用我自己所在地区的经纬度,接口返回数据如下:

    {
        locations: [
            {
                name: "桥西",
                id: "101090120",
                lat: "38.02838135",
                lon: "114.46292877",
                adm2: "石家庄",
                adm1: "河北省",
                country: "中国",
                tz: "Asia/Shanghai",
                utcOffset: "+08:00",
                isDst: "0",
                type: "city",
                rank: "35",
                fxLink: "http://hfx.link/1toj1"
            }
        ],
        updateTime: "2021-05-18 15:58:00",
        weatherNow: {
            obsTime: "2021-05-18T15:53+08:00",
            temp: "30",
            feelsLike: "26",
            icon: "100",
            text: "晴",
            wind360: "135",
            windDir: "东南风",
            windScale: "5",
            windSpeed: "32",
            humidity: "33",
            precip: "0.0",
            pressure: "994",
            vis: "20",
            cloud: "10",
            dew: "10",
            pubTime: "2021-05-18T15:00+08:00",
            aqi: "79",
            level: "2",
            category: "良",
            primary: "O3",
            pm10: "56",
            pm2p5: "31",
            no2: "17",
            so2: "16",
            co: "0.9",
            o3: "183"
        },
        weatherDailies: [
            {
                fxDate: "2021-05-18",
                sunrise: "05:10",
                sunset: "19:28",
                moonrise: "10:04",
                moonset: "01:00",
                moonPhase: "峨眉月",
                tempMax: "30",
                tempMin: "17",
                iconDay: "100",
                textDay: "晴",
                iconNight: "101",
                textNight: "多云",
                wind360Day: "180",
                windDirDay: "南风",
                windScaleDay: "3-4",
                windSpeedDay: "16",
                wind360Night: "0",
                windDirNight: "北风",
                windScaleNight: "1-2",
                windSpeedNight: "3",
                humidity: "34",
                precip: "0.0",
                pressure: "993",
                vis: "25",
                cloud: "0",
                uvIndex: "10"
            },
            {
                fxDate: "2021-05-19",
                sunrise: "05:09",
                sunset: "19:28",
                moonrise: "11:08",
                moonset: "01:35",
                moonPhase: "峨眉月",
                tempMax: "30",
                tempMin: "18",
                iconDay: "302",
                textDay: "雷阵雨",
                iconNight: "350",
                textNight: "阵雨",
                wind360Day: "180",
                windDirDay: "南风",
                windScaleDay: "3-4",
                windSpeedDay: "16",
                wind360Night: "0",
                windDirNight: "北风",
                windScaleNight: "1-2",
                windSpeedNight: "3",
                humidity: "55",
                precip: "2.5",
                pressure: "991",
                vis: "24",
                cloud: "60",
                uvIndex: "5"
            },
            {
                fxDate: "2021-05-20",
                sunrise: "05:08",
                sunset: "19:29",
                moonrise: "12:14",
                moonset: "02:06",
                moonPhase: "上弦月",
                tempMax: "28",
                tempMin: "18",
                iconDay: "101",
                textDay: "多云",
                iconNight: "150",
                textNight: "晴",
                wind360Day: "0",
                windDirDay: "北风",
                windScaleDay: "1-2",
                windSpeedDay: "3",
                wind360Night: "0",
                windDirNight: "北风",
                windScaleNight: "1-2",
                windSpeedNight: "3",
                humidity: "83",
                precip: "0.0",
                pressure: "994",
                vis: "24",
                cloud: "25",
                uvIndex: "11"
            }
        ]
    }
    

    以上这些天气数据够我们当下使用了。

    数据请求

    在本项目中,主要使用带有缓存功能的 axios-cache-plugin,同样的封装为 WeatherService

    'use strict';
    import axios from 'axios';
    import wrapper from 'axios-cache-plugin';
    export default class WeatherService {
      // 这里是使用 async/await
      async getWeathers(location: any) {
        const locationStr = location.longitude + ',' + location.latitude;
        const http = wrapper(axios, {
          maxCacheSize: 15,
          ttl: 7200000, //ms 数据缓存 2 小时
        });
        http.__addFilter(/weatherdata/);
    
        const res = await http({
          url: 'https://***.com/weatherdata',
          method: 'get',
          params: {
            param: JSON.stringify({
              location: locationStr,
            }),
          },
        });
    
        return res.data;
      }
    }
    

    显示到 View 中

    剩下的就比较简单了,就是怎么显示到 View 中了,还是在:

    const dateWeather = this.showWeather(date, weather);
    if (dateWeather == undefined) {
      return {
        html: `<div class="fc-daygrid-day-number">${dayNumberText}</div>
            <div class="fc-daygrid-day-chinese">${dayTextInChinese}</div>`,
      };
    } else {
      const imgSrc = weathericons + '/../' + dateWeather.iconDay +'.png';
      return {
        html: `<div class="fc-daygrid-day-number">${dayNumberText}</div>
          <div class="fc-daygrid-day-chinese">${dayTextInChinese}</div>
          <div class="fc-daygrid-dayweather">
            <img class="fc-daygrid-dayweather-iconday" src=${imgSrc}/>
            <span class="fc-daygrid-dayweather-temp">${dateWeather.textDay} ${dateWeather.tempMin}-${dateWeather.tempMax}°C</span>
          </div>`,
      };
    }
    

    因为只显示 3 天的天气预报,所以还需要判断可否显示天气:

    showWeather(date: Date, weather: any) {
    
    if (weather == null || weather.weatherDailies == null) {
      return undefined;
    }
    const dateString = Moment(date).format('YYYY-MM-DD');
    const result = weather.weatherDailies.find((dateWeather: { fxDate: string; }) => dateWeather.fxDate == dateString);
    return result;
    }
    

    来看看显示结果:

    Electron+Vue3 MAC 版日历 开发记录(5)——天气预报

    小结

    关于开关控制是否显示天气的设置功能,下一步继续整理。

    具体代码也放在 Github 上 fanly/fanlymenu,欢迎查看!

    最后感谢自己能坚持到第五天,也欢迎大家看看前四天的记录,对本项目有个初步的了解:


    起源地下载网 » Electron+Vue3 MAC 版日历 开发记录(5)——天气预报

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元