import type { WithAbortSignal } from "#Source/abort/index.ts" import { generalFetch } from "#Source/request/index.ts" import type { Lang } from "../base.ts" /** * @description 调用和风天气 GeoAPI 城市搜索接口时使用的参数。 * * @example * ;``` * const options: GeoCityLookupOptions = { * baseUrl: "https://abcxyz.qweatherapi.com", * jwt: "eyJhbGciOiJFZERTQSJ9.payload.signature", * location: "beij", * adm: "beijing", * range: "cn", * number: 10, * lang: "zh-hans", * timeout: 5_000, * } * ``` */ export interface GeoCityLookupOptions extends WithAbortSignal { /** * @description 和风天气 API Base URL,例如 `https://your_api_base_url`。 */ baseUrl: string /** * @description 用于 `Authorization: Bearer` 请求头的 JWT。 */ jwt: string /** * @description 需要查询的地区名称、经纬度、LocationID 或 Adcode。 */ location: string /** * @description 上级行政区划,用于缩小搜索范围并排除重名地区。 */ adm?: string | undefined /** * @description 搜索范围,使用 ISO 3166 国家或地区代码,例如 `cn`。 */ range?: string | undefined /** * @description 返回结果数量,取值范围为 1-20。 */ number?: number | undefined /** * @description 返回结果的多语言代码。 */ lang?: Lang | undefined /** * @description 请求超时时间,单位为毫秒。 */ timeout?: number | undefined } /** * @description 城市搜索结果中的单个地区信息。 * * @example * ;``` * const location: GeoCityLookupResultLocation = { * name: "北京", * id: "101010100", * lat: "39.90499", * lon: "116.40529", * adm2: "北京", * adm1: "北京市", * country: "中国", * tz: "Asia/Shanghai", * utcOffset: "+08:00", * isDst: "0", * type: "city", * rank: "10", * fxLink: "https://www.qweather.com/weather/beijing-101010100.html", * } * ``` */ export interface GeoCityLookupResultLocation { /** * @description 地区或城市名称。 */ name: string /** * @description 地区或城市的 Location ID。 */ id: string /** * @description 地区或城市纬度。 */ lat: string /** * @description 地区或城市经度。 */ lon: string /** * @description 地区或城市的上级行政区划名称。 */ adm2: string /** * @description 地区或城市所属一级行政区域。 */ adm1: string /** * @description 地区或城市所属国家名称。 */ country: string /** * @description 地区或城市所在时区。 */ tz: string /** * @description 地区或城市当前与 UTC 的偏移。 */ utcOffset: string /** * @description 是否当前处于夏令时,`1` 表示是,`0` 表示否。 */ isDst: string /** * @description 地区或城市的属性类型。 */ type: string /** * @description 地区评分 Rank 值。 */ rank: string /** * @description 对应地区的和风天气页面链接。 */ fxLink: string } /** * @description 城市搜索结果中的来源与许可信息。 * * @example * ;``` * const refer: GeoCityLookupResultRefer = { * sources: ["QWeather"], * license: ["QWeather Developers License"], * } * ``` */ export interface GeoCityLookupResultRefer { /** * @description 原始数据来源或数据源说明。 */ sources?: string[] | undefined /** * @description 数据许可或版权声明。 */ license?: string[] | undefined } /** * @description 和风天气 GeoAPI 城市搜索接口的响应结果。 * * @example * ;``` * const result: GeoCityLookupResult = { * code: "200", * location: [ * { * name: "北京", * id: "101010100", * lat: "39.90499", * lon: "116.40529", * adm2: "北京", * adm1: "北京市", * country: "中国", * tz: "Asia/Shanghai", * utcOffset: "+08:00", * isDst: "0", * type: "city", * rank: "10", * fxLink: "https://www.qweather.com/weather/beijing-101010100.html", * }, * ], * refer: { * sources: ["QWeather"], * license: ["QWeather Developers License"], * }, * } * ``` */ export interface GeoCityLookupResult { /** * @description 接口状态码。 */ code: string /** * @description 搜索命中的地区列表。 */ location?: GeoCityLookupResultLocation[] | undefined /** * @description 响应中的来源与许可信息。 */ refer?: GeoCityLookupResultRefer | undefined } const internalValidateGeoCityLookupOptions = (options: GeoCityLookupOptions): void => { const { baseUrl, jwt: token, location, number } = options if (baseUrl.trim() === "") { throw new TypeError("GeoCityLookup baseUrl must not be empty.") } if (token.trim() === "") { throw new TypeError("GeoCityLookup token must not be empty.") } if (location.trim() === "") { throw new TypeError("GeoCityLookup location must not be empty.") } if (number !== undefined && (Number.isInteger(number) === false || number < 1 || number > 20)) { throw new RangeError("GeoCityLookup number must be an integer between 1 and 20.") } } /** * @see {@link https://dev.qweather.com/docs/api/geoapi/city-lookup/} */ export const geoCityLookup = async ( options: GeoCityLookupOptions, ): Promise => { internalValidateGeoCityLookupOptions(options) const { baseUrl, jwt, location, adm, range, number, lang, timeout, abortSignal } = options return await generalFetch< { query: { location: string adm?: string | undefined range?: string | undefined number?: number | undefined lang?: Lang | undefined } }, { type: "json" data: GeoCityLookupResult } >({ baseUrl, path: "/geo/v2/city/lookup", method: "get", headers: { Authorization: `Bearer ${jwt.trim()}`, }, query: { location: location.trim(), adm, range, number, lang, }, responseType: "json", timeout, abortSignal, }).getJson() }