import type { WithAbortSignal } from "#Source/abort/index.ts" import { generalFetch } from "#Source/request/index.ts" import type { Lang, Unit } from "../base.ts" export type WeatherDailyForecastDays = "3d" | "7d" | "10d" | "15d" | "30d" const internalWeatherDailyForecastUnitSet = new Set(["m", "i"]) const internalWeatherDailyForecastDaysSet = new Set([ "3d", "7d", "10d", "15d", "30d", ]) /** * @description 调用和风天气每日天气预报接口时使用的参数。 * * @example * ;``` * const options: WeatherDailyForecastOptions = { * baseUrl: "https://abcxyz.qweatherapi.com", * jwt: "eyJhbGciOiJFZERTQSJ9.payload.signature", * days: "3d", * location: "101010100", * lang: "zh-hans", * unit: "m", * } * ``` */ export interface WeatherDailyForecastOptions extends WithAbortSignal { /** * @description 和风天气 API Base URL,例如 `https://abcxyz.qweatherapi.com`。 */ baseUrl: string /** * @description 用于 `Authorization: Bearer` 请求头的 JWT。 */ jwt: string /** * @description 预报天数。 */ days: WeatherDailyForecastDays /** * @description 需要查询地区的 LocationID,或以英文逗号分隔的经度、纬度坐标。 */ location: string /** * @description 返回结果的多语言代码。 */ lang?: Lang | undefined /** * @description 数据单位设置,`m` 为公制,`i` 为英制。 */ unit?: Unit | undefined /** * @description 请求超时时间,单位为毫秒。 */ timeout?: number | undefined } /** * @description 每日天气预报响应中的单日数据。 */ export interface WeatherDailyForecastResultDaily { /** * @description 预报日期。 */ fxDate: string /** * @description 日出时间,在高纬度地区可能为空。 */ sunrise: string /** * @description 日落时间,在高纬度地区可能为空。 */ sunset: string /** * @description 当天月升时间,可能为空。 */ moonrise: string /** * @description 当天月落时间,可能为空。 */ moonset: string /** * @description 月相名称。 */ moonPhase: string /** * @description 月相图标代码。 */ moonPhaseIcon: string /** * @description 预报当天最高温度。 */ tempMax: string /** * @description 预报当天最低温度。 */ tempMin: string /** * @description 白天天气状况的图标代码。 */ iconDay: string /** * @description 白天天气状况文字描述。 */ textDay: string /** * @description 夜间天气状况的图标代码。 */ iconNight: string /** * @description 夜间天气状况文字描述。 */ textNight: string /** * @description 白天风向 360 角度。 */ wind360Day: string /** * @description 白天风向。 */ windDirDay: string /** * @description 白天风力等级。 */ windScaleDay: string /** * @description 白天风速,单位为公里/小时。 */ windSpeedDay: string /** * @description 夜间风向 360 角度。 */ wind360Night: string /** * @description 夜间风向。 */ windDirNight: string /** * @description 夜间风力等级。 */ windScaleNight: string /** * @description 夜间风速,单位为公里/小时。 */ windSpeedNight: string /** * @description 相对湿度,百分比数值。 */ humidity: string /** * @description 预报当天总降水量。 */ precip: string /** * @description 大气压强。 */ pressure: string /** * @description 能见度。 */ vis: string /** * @description 云量,可能为空。 */ cloud: string /** * @description 紫外线强度指数。 */ uvIndex: string } /** * @description 和风天气每日天气预报接口的响应结果。 * * @example * ;``` * const result: WeatherDailyForecastResult = { * code: "200", * updateTime: "2021-11-15T16:35+08:00", * fxLink: "http://hfx.link/2ax1", * daily: [ * { * fxDate: "2021-11-15", * sunrise: "06:58", * sunset: "16:59", * moonrise: "15:16", * moonset: "03:40", * moonPhase: "盈凸月", * moonPhaseIcon: "803", * tempMax: "12", * tempMin: "-1", * iconDay: "101", * textDay: "多云", * iconNight: "150", * textNight: "晴", * wind360Day: "45", * windDirDay: "东北风", * windScaleDay: "1-2", * windSpeedDay: "3", * wind360Night: "0", * windDirNight: "北风", * windScaleNight: "1-2", * windSpeedNight: "3", * humidity: "65", * precip: "0.0", * pressure: "1020", * vis: "25", * cloud: "4", * uvIndex: "3", * }, * ], * refer: { * sources: ["QWeather"], * license: ["QWeather Developers License"], * }, * } * ``` */ export interface WeatherDailyForecastResultRefer { /** * @description 原始数据来源或数据源说明。 */ sources?: string[] | undefined /** * @description 数据许可或版权声明。 */ license?: string[] | undefined } export interface WeatherDailyForecastResult { /** * @description 接口状态码。 */ code: string /** * @description 当前 API 的最近更新时间。 */ updateTime: string /** * @description 当前数据对应的响应式天气页面链接。 */ fxLink: string /** * @description 每日天气预报数据列表。 */ daily: WeatherDailyForecastResultDaily[] /** * @description 响应中的来源与许可信息。 */ refer?: WeatherDailyForecastResultRefer | undefined } const internalValidateWeatherDailyForecastOptions = ( options: WeatherDailyForecastOptions, ): { baseUrl: string jwt: string location: string days: WeatherDailyForecastDays } => { const baseUrl = options.baseUrl.trim() const jwt = options.jwt.trim() const location = options.location.trim() if (baseUrl === "") { throw new TypeError("WeatherDailyForecast baseUrl must not be empty.") } if (jwt === "") { throw new TypeError("WeatherDailyForecast jwt must not be empty.") } if (location === "") { throw new TypeError("WeatherDailyForecast location must not be empty.") } if (internalWeatherDailyForecastDaysSet.has(options.days) === false) { throw new RangeError("WeatherDailyForecast days must be one of: 3d, 7d, 10d, 15d, 30d.") } if ( options.unit !== undefined && internalWeatherDailyForecastUnitSet.has(options.unit) === false ) { throw new RangeError("WeatherDailyForecast unit must be one of: m, i.") } return { baseUrl, jwt, location, days: options.days, } } /** * @description 获取指定地区的每日天气预报。 * * @see {@link https://dev.qweather.com/docs/api/weather/weather-daily-forecast/} */ export const weatherDailyForecast = async ( options: WeatherDailyForecastOptions, ): Promise => { const { baseUrl, jwt, location, days } = internalValidateWeatherDailyForecastOptions(options) const { lang, unit, timeout, abortSignal } = options return await generalFetch< { query: { location: string lang?: Lang | undefined unit?: Unit | undefined } }, { type: "json" data: WeatherDailyForecastResult } >({ baseUrl, path: `/v7/weather/${days}`, method: "get", headers: { Authorization: `Bearer ${jwt}`, }, query: { location, lang, unit, }, responseType: "json", timeout, abortSignal, }).getJson() }