import type { WithAbortSignal } from "#Source/abort/index.ts" import { generalFetch } from "#Source/request/index.ts" import type { Lang } from "../base.ts" const internalTimeMachineAirDatePattern = /^\d{8}$/ /** * @description 调用和风天气空气质量时光机接口时使用的参数。 * * @example * ;``` * const options: TimeMachineAirOptions = { * baseUrl: "https://abcxyz.qweatherapi.com", * jwt: "eyJhbGciOiJFZERTQSJ9.payload.signature", * location: "101010100", * date: "20200725", * lang: "zh-hans", * timeout: 5_000, * } * ``` */ export interface TimeMachineAirOptions extends WithAbortSignal { /** * @description 和风天气 API Base URL,例如 `https://abcxyz.qweatherapi.com`。 */ baseUrl: string /** * @description 用于 `Authorization: Bearer` 请求头的 JWT。 */ jwt: string /** * @description 需要查询地区的 LocationID。 */ location: string /** * @description 需要查询的历史日期,格式为 `yyyyMMdd`。 */ date: string /** * @description 返回结果的多语言代码。 */ lang?: Lang | undefined /** * @description 请求超时时间,单位为毫秒。 */ timeout?: number | undefined } /** * @description 空气质量时光机响应中的逐小时空气质量数据。 * * @example * ;``` * const airHourly: TimeMachineAirResultAirHourly = { * pubTime: "2020-07-25 00:00", * aqi: "52", * level: "2", * category: "良", * primary: "PM10", * pm10: "54", * pm2p5: "22", * no2: "31", * so2: "2", * co: "0.5", * o3: "85", * } * ``` */ export interface TimeMachineAirResultAirHourly { /** * @description 空气质量数据发布时间。 */ pubTime: string /** * @description 空气质量指数。 */ aqi: string /** * @description 空气质量指数等级。 */ level: string /** * @description 空气质量级别名称。 */ category: string /** * @description 空气质量的主要污染物,空气质量为优时返回 `NA`。 */ primary: string /** * @description PM10 数值。 */ pm10: string /** * @description PM2.5 数值。 */ pm2p5: string /** * @description 二氧化氮数值。 */ no2: string /** * @description 二氧化硫数值。 */ so2: string /** * @description 一氧化碳数值。 */ co: string /** * @description 臭氧数值。 */ o3: string } /** * @description 空气质量时光机响应中的来源与许可信息。 * * @example * ;``` * const refer: TimeMachineAirResultRefer = { * sources: ["QWeather"], * license: ["QWeather Developers License"], * } * ``` */ export interface TimeMachineAirResultRefer { /** * @description 原始数据来源或数据源说明。 */ sources?: string[] | undefined /** * @description 数据许可或版权声明。 */ license?: string[] | undefined } /** * @description 和风天气空气质量时光机接口的响应结果。 * * @example * ;``` * const result: TimeMachineAirResult = { * code: "200", * fxLink: "http://hfx.link/2ax6", * airHourly: [ * { * pubTime: "2020-07-25 00:00", * aqi: "52", * level: "2", * category: "良", * primary: "PM10", * pm10: "54", * pm2p5: "22", * no2: "31", * so2: "2", * co: "0.5", * o3: "85", * }, * ], * refer: { * sources: ["QWeather"], * license: ["QWeather Developers License"], * }, * } * ``` */ export interface TimeMachineAirResult { /** * @description 接口状态码。 */ code: string /** * @description 当前数据对应的响应式天气页面链接。 */ fxLink: string /** * @description 当日逐小时历史空气质量数据。 */ airHourly: TimeMachineAirResultAirHourly[] /** * @description 响应中的来源与许可信息。 */ refer?: TimeMachineAirResultRefer | undefined } const internalValidateTimeMachineAirOptions = ( options: TimeMachineAirOptions, ): { baseUrl: string jwt: string location: string date: string } => { const baseUrl = options.baseUrl.trim() const jwt = options.jwt.trim() const location = options.location.trim() const date = options.date.trim() if (baseUrl === "") { throw new TypeError("TimeMachineAir baseUrl must not be empty.") } if (jwt === "") { throw new TypeError("TimeMachineAir jwt must not be empty.") } if (location === "") { throw new TypeError("TimeMachineAir location must not be empty.") } if (date === "") { throw new TypeError("TimeMachineAir date must not be empty.") } if (internalTimeMachineAirDatePattern.test(date) === false) { throw new RangeError("TimeMachineAir date must use yyyyMMdd format.") } return { baseUrl, jwt, location, date, } } /** * @description 获取指定地区指定日期的历史空气质量再分析数据。 * * @see {@link https://dev.qweather.com/docs/api/time-machine/time-machine-air/} */ export const timeMachineAir = async ( options: TimeMachineAirOptions, ): Promise => { const { baseUrl, jwt, location, date } = internalValidateTimeMachineAirOptions(options) const { lang, timeout, abortSignal } = options return await generalFetch< { query: { location: string date: string lang?: Lang | undefined } }, { type: "json" data: TimeMachineAirResult } >({ baseUrl, path: "/v7/historical/air", method: "get", headers: { Authorization: `Bearer ${jwt}`, }, query: { location, date, lang, }, responseType: "json", timeout, abortSignal, }).getJson() }