diff --git a/src/components/WeatherWidget.vue b/src/components/WeatherWidget.vue index 377b259..542724c 100644 --- a/src/components/WeatherWidget.vue +++ b/src/components/WeatherWidget.vue @@ -12,9 +12,10 @@ const temp = ref(""); const desc = ref(""); const kind = ref<"sun" | "cloud" | "overcast" | "rain" | "snow" | "fog" | "storm">("sun"); -/** WWO weatherCode → 中文天气名(wttr.in j1 格式不随 lang 翻译,本地映射) */ +/** WWO weatherCode → 中文天气名。wttr.in 的 lang_zh 对新代码不再翻译(英文透传), + * 且上游已出现旧表之外的扩展码(如 149 烟霾),故本地映射 + 英文描述关键词兜底(DESC_ZH)。 */ const CODE_ZH: Record = { - 113: "晴", 116: "多云", 119: "阴", 122: "阴", 143: "薄雾", 248: "雾", 260: "冻雾", + 113: "晴", 116: "多云", 119: "阴", 122: "阴", 143: "薄雾", 149: "烟霾", 248: "雾", 260: "冻雾", 176: "零星小雨", 263: "零星毛毛雨", 266: "毛毛雨", 281: "冻毛毛雨", 284: "冻毛毛雨", 293: "零星小雨", 296: "小雨", 299: "零星阵雨", 302: "阵雨", 305: "零星大雨", 308: "大雨", 311: "冻雨", 314: "冻雨", 350: "冰雹", 353: "零星阵雨", 356: "阵雨", 359: "暴雨", 362: "零星阵雨", 365: "阵雨", @@ -24,13 +25,62 @@ const CODE_ZH: Record = { 227: "吹雪", 230: "暴风雪", }; -function kindOf(code: number): typeof kind.value { +/** 英文描述 → 中文(顺序敏感:特称在前,兜底泛称在后;覆盖上表未收录的新代码) */ +const DESC_ZH: Array<[RegExp, string]> = [ + [/thundery|thunder|storm/i, "雷阵雨"], + [/torrential/i, "暴雨"], + [/heavy rain/i, "大雨"], + [/moderate rain|rain at times/i, "中雨"], + [/(light|patchy) rain/i, "小雨"], + [/rain shower/i, "阵雨"], + [/sleet/i, "雨夹雪"], + [/freezing drizzle/i, "冻毛毛雨"], + [/drizzle/i, "毛毛雨"], + [/freezing rain/i, "冻雨"], + [/ice pellet/i, "冰雹"], + [/blizzard/i, "暴风雪"], + [/blowing snow/i, "吹雪"], + [/heavy snow/i, "大雪"], + [/moderate snow/i, "中雪"], + [/(light|patchy) snow/i, "小雪"], + [/snow shower/i, "阵雪"], + [/rain/i, "雨"], + [/snow/i, "雪"], + [/smoke|haze/i, "烟霾"], + [/freezing fog/i, "冻雾"], + [/mist|fog/i, "雾"], + [/overcast/i, "阴"], + [/cloud/i, "多云"], + [/clear|sunny/i, "晴"], +]; + +function zhFromDesc(en: string): string { + if (!en) return ""; + for (const [re, zh] of DESC_ZH) { + if (re.test(en)) return zh; + } + return ""; +} + +/** 未知码返回 undefined,由描述关键词接棒定图标 */ +function kindOf(code: number): typeof kind.value | undefined { if ([200, 386, 389].includes(code)) return "storm"; if ([179, 182, 185, 227, 320, 323, 326, 350, 368, 371, 374, 377].includes(code)) return "snow"; if ([176, 263, 266, 281, 284, 293, 296, 299, 302, 305, 308, 311, 314, 353, 356, 359, 362, 365].includes(code)) return "rain"; - if ([143, 248, 260].includes(code)) return "fog"; + if ([143, 149, 248, 260].includes(code)) return "fog"; if ([119, 122].includes(code)) return "overcast"; if ([116].includes(code)) return "cloud"; + if ([113].includes(code)) return "sun"; + return undefined; +} + +function kindFromDesc(en: string): typeof kind.value { + if (/thunder|storm/i.test(en)) return "storm"; + if (/snow|sleet|blizzard/i.test(en)) return "snow"; + if (/rain|drizzle|shower/i.test(en)) return "rain"; + if (/smoke|haze|mist|fog/i.test(en)) return "fog"; + if (/overcast/i.test(en)) return "overcast"; + if (/cloud/i.test(en)) return "cloud"; return "sun"; } @@ -39,8 +89,9 @@ function apply(j: any) { if (!cur) return; temp.value = cur.temp_C; const code = Number(cur.weatherCode) || 0; - desc.value = CODE_ZH[code] || cur.lang_zh?.[0]?.value || cur.weatherDesc?.[0]?.value || ""; - kind.value = kindOf(code); + const en = cur.weatherDesc?.[0]?.value || ""; + desc.value = CODE_ZH[code] || zhFromDesc(en); + kind.value = kindOf(code) ?? kindFromDesc(en); visible.value = true; }