qweather_sdk/api/
indices.rs

1use chrono::{DateTime, FixedOffset, NaiveDate};
2use serde::{Deserialize, Serialize};
3use serde_aux::prelude::deserialize_number_from_string;
4use std::collections::BTreeMap;
5
6use crate::{
7    api::{decode_datetime, Refer},
8    client::QWeatherClient,
9    APIResult,
10};
11
12impl QWeatherClient {
13    /// 天气指数预报
14    ///
15    /// 获取中国和全球城市天气生活指数预报数据。
16    ///
17    /// * 中国天气生活指数 :舒适度指数、洗车指数、穿衣指数、感冒指数、运动指数、旅游指数、
18    ///   紫外线指数、空气污染扩散条件指数、空调开启指数、过敏指数、太阳镜指数、化妆指数、晾晒指数、
19    ///   交通指数、钓鱼指数、防晒指数
20    /// * 海外天气生活指数 :运动指数、洗车指数、紫外线指数、钓鱼指数
21    ///
22    /// # 参数
23    /// * location : 地区/城市ID
24    /// * type_ : 指数类型
25    /// * day : 预报天数,1天或者3天
26    pub async fn indices_forecast(
27        &self,
28        location: &str,
29        type_: &str,
30        day: i32,
31    ) -> APIResult<IndicesForecastResponse> {
32        let url = format!("{}/v7/indices/{}d", self.get_api_host(), day);
33
34        let mut params = BTreeMap::new();
35        params.insert("location".to_string(), location.to_string());
36        params.insert("type".to_string(), type_.to_string());
37
38        self.request_api(url, params).await
39    }
40}
41
42/// 天气指数预报
43#[derive(Deserialize, Serialize, Debug, Clone)]
44#[serde(rename_all = "camelCase")]
45pub struct DailyIndices {
46    /// 预报日期
47    pub date: NaiveDate,
48    /// 生活指数类型ID
49    #[serde(deserialize_with = "deserialize_number_from_string")]
50    #[serde(rename = "type")]
51    pub type_: i32,
52    /// 生活指数类型的名称
53    pub name: String,
54    /// 生活指数预报等级
55    #[serde(deserialize_with = "deserialize_number_from_string")]
56    pub level: i32,
57    /// 生活指数预报级别名称
58    pub category: String,
59    /// 生活指数预报的详细描述,可能为空
60    pub text: String,
61}
62
63/// 天气指数预报返回数据
64#[derive(Deserialize, Serialize, Debug, Clone)]
65#[serde(rename_all = "camelCase")]
66pub struct IndicesForecastResponse {
67    /// 请参考[状态码](https://dev.qweather.com/docs/resource/status-code/)
68    pub code: String,
69    /// 当前[API的最近更新时间](https://dev.qweather.com/docs/resource/glossary/#update-time)
70    #[serde(deserialize_with = "decode_datetime")]
71    pub update_time: DateTime<FixedOffset>,
72    /// 当前数据的响应式页面,便于嵌入网站或应用
73    pub fx_link: String,
74    /// 当前国家预警的LocationID
75    pub daily: Vec<DailyIndices>,
76    /// 数据来源
77    pub refer: Refer,
78}
79
80#[test]
81fn test_indices_forecast() {
82    let json_dat = r#"{
83  "code": "200",
84  "updateTime": "2021-12-16T18:35+08:00",
85  "fxLink": "http://hfx.link/2ax2",
86  "daily": [
87    {
88      "date": "2021-12-16",
89      "type": "1",
90      "name": "运动指数",
91      "level": "3",
92      "category": "较不宜",
93      "text": "天气较好,但考虑天气寒冷,风力较强,推荐您进行室内运动,若户外运动请注意保暖并做好准备活动。"
94    },
95    {
96      "date": "2021-12-16",
97      "type": "2",
98      "name": "洗车指数",
99      "level": "3",
100      "category": "较不宜",
101      "text": "较不宜洗车,未来一天无雨,风力较大,如果执意擦洗汽车,要做好蒙上污垢的心理准备。"
102    }
103  ],
104  "refer": {
105    "sources": [
106      "QWeather"
107    ],
108    "license": [
109      "QWeather Developers License"
110    ]
111  }
112}"#;
113
114    let resp: IndicesForecastResponse = serde_json::from_str(json_dat).unwrap();
115    assert_eq!(resp.code, "200");
116    assert_eq!(resp.daily.len(), 2);
117    assert_eq!(resp.daily[0].name, "运动指数");
118    assert_eq!(resp.daily[0].level, 3);
119    assert_eq!(resp.daily[0].category, "较不宜");
120    assert_eq!(resp.daily[0].text, "天气较好,但考虑天气寒冷,风力较强,推荐您进行室内运动,若户外运动请注意保暖并做好准备活动。");
121    assert_eq!(resp.refer.sources[0], "QWeather");
122    assert_eq!(resp.refer.license[0], "QWeather Developers License");
123    assert_eq!(resp.update_time.to_rfc3339(), "2021-12-16T18:35:00+08:00");
124    assert_eq!(resp.fx_link, "http://hfx.link/2ax2");
125}