import type { WithAbortSignal } from "#Source/abort/index.ts" import { generalFetch } from "#Source/request/index.ts" import type { Lang } from "../base.ts" import type { AirQualityIndex, AirQualityMetadata, AirQualityPollutant, AirQualityStation, } from "./shared.ts" /** * @description 调用和风天气实时空气质量接口时使用的参数。 * * @example * ;``` * const options: AirCurrentOptions = { * baseUrl: "https://abcxyz.qweatherapi.com", * jwt: "eyJhbGciOiJFZERTQSJ9.payload.signature", * latitude: 39.9, * longitude: 116.4, * lang: "zh-hans", * timeout: 5_000, * } * ``` */ export interface AirCurrentOptions extends WithAbortSignal { /** * @description 和风天气 API Base URL,例如 `https://abcxyz.qweatherapi.com`。 */ baseUrl: string /** * @description 用于 `Authorization: Bearer` 请求头的 JWT。 */ jwt: string /** * @description 查询位置的纬度,十进制格式,最多支持小数点后两位。 */ latitude: number | string /** * @description 查询位置的经度,十进制格式,最多支持小数点后两位。 */ longitude: number | string /** * @description 返回结果的多语言代码。 */ lang?: Lang | undefined /** * @description 请求超时时间,单位为毫秒。 */ timeout?: number | undefined } /** * @description 和风天气实时空气质量接口的响应结果。 * * @example * ;``` * const result: AirCurrentResult = { * metadata: { * tag: "d75a323239766b831889e8020cba5aca9b90fca5080a1175c3487fd8acb06e84", * }, * indexes: [ * { * code: "us-epa", * name: "AQI (US)", * aqi: 46, * aqiDisplay: "46", * level: "1", * category: "Good", * color: { * red: 0, * green: 228, * blue: 0, * alpha: 1, * }, * primaryPollutant: { * code: "pm2p5", * name: "PM 2.5", * fullName: "Fine particulate matter (<2.5µm)", * }, * health: { * effect: "No health effects.", * advice: { * generalPopulation: "Everyone can continue their outdoor activities normally.", * sensitivePopulation: "Everyone can continue their outdoor activities normally.", * }, * }, * }, * ], * pollutants: [ * { * code: "pm2p5", * name: "PM 2.5", * fullName: "Fine particulate matter (<2.5µm)", * concentration: { * value: 11, * unit: "μg/m3", * }, * subIndexes: [ * { * code: "us-epa", * aqi: 46, * aqiDisplay: "46", * }, * ], * }, * ], * stations: [ * { * id: "P51762", * name: "North Holywood", * }, * ], * } * ``` */ export interface AirCurrentResult { /** * @description 响应元数据。 */ metadata: AirQualityMetadata /** * @description 当前地点对应的空气质量指数列表。 */ indexes: AirQualityIndex[] /** * @description 当前地点对应的污染物浓度数据列表。 */ pollutants: AirQualityPollutant[] /** * @description 当前 AQI 关联的监测站列表。 */ stations: AirQualityStation[] } const internalNormalizeAirCurrentCoordinate = ( value: number | string, name: "latitude" | "longitude", ): string => { if (typeof value === "number") { if (Number.isFinite(value) === false) { throw new TypeError(`AirCurrent ${name} must be a finite number.`) } return String(value) } const normalized = value.trim() if (normalized === "") { throw new TypeError(`AirCurrent ${name} must not be empty.`) } return normalized } const internalValidateAirCurrentOptions = ( options: AirCurrentOptions, ): { baseUrl: string jwt: string latitude: string longitude: string } => { const baseUrl = options.baseUrl.trim() const jwt = options.jwt.trim() const latitude = internalNormalizeAirCurrentCoordinate(options.latitude, "latitude") const longitude = internalNormalizeAirCurrentCoordinate(options.longitude, "longitude") if (baseUrl === "") { throw new TypeError("AirCurrent baseUrl must not be empty.") } if (jwt === "") { throw new TypeError("AirCurrent jwt must not be empty.") } return { baseUrl, jwt, latitude, longitude, } } /** * @description 获取指定经纬度坐标的实时空气质量数据。 * * @see {@link https://dev.qweather.com/docs/api/air-quality/air-current/} */ export const airCurrent = async (options: AirCurrentOptions): Promise => { const { baseUrl, jwt, latitude, longitude } = internalValidateAirCurrentOptions(options) const { lang, timeout, abortSignal } = options return await generalFetch< { query: { lang?: Lang | undefined } }, { type: "json" data: AirCurrentResult } >({ baseUrl, path: `/airquality/v1/current/${latitude}/${longitude}`, method: "get", headers: { Authorization: `Bearer ${jwt}`, }, query: { lang, }, responseType: "json", timeout, abortSignal, }).getJson() }