diff --git a/_config.butterfly.yml b/_config.butterfly.yml index 918abb0..6e8858d 100644 --- a/_config.butterfly.yml +++ b/_config.butterfly.yml @@ -1074,9 +1074,10 @@ inject: - - - - - - - + - - - - @@ -1166,4 +1167,4 @@ ai_summary: enable: true title: BiのAI摘要 loadingText: AI正在绞尽脑汁想思路ING··· - modelName: HunYuan-Lite \ No newline at end of file + modelName: HunYuan-Lite diff --git a/themes/butterfly/layout/includes/widget/card_announcement.pug b/themes/butterfly/layout/includes/widget/card_announcement.pug index 7ddbd9c..79095fd 100644 --- a/themes/butterfly/layout/includes/widget/card_announcement.pug +++ b/themes/butterfly/layout/includes/widget/card_announcement.pug @@ -4,4 +4,5 @@ if theme.aside.card_announcement.enable i.fas.fa-bullhorn.fa-shake span= _p('aside.card_announcement') .announcement_content!= theme.aside.card_announcement.content - #welcome-ip-location-info \ No newline at end of file + #welcome-ip-location-info + #aside-weather \ No newline at end of file diff --git a/themes/butterfly/source/js/weather.js b/themes/butterfly/source/js/weather.js new file mode 100644 index 0000000..c2876c6 --- /dev/null +++ b/themes/butterfly/source/js/weather.js @@ -0,0 +1,204 @@ +// weather.js + +(function () { + + const WEATHER_ID = "aside-weather"; + const LOCATION_WAIT_MS = 3000; + const LOCATION_POLL_INTERVAL_MS = 100; + const WEATHER_KEY = "70201debab4245379e376d116b05f8a2"; + const WEATHER_HOST = "https://ny5vxmbbkd.re.qweatherapi.com"; + const WEATHER_LANG = "zh"; + + function debugLog(label, payload) { + console.log(`[weather.js] ${label}`, payload); + } + + function maskSecret(secret) { + if (!secret || secret.length < 10) return secret; + return `${secret.slice(0, 4)}***${secret.slice(-4)}`; + } + + function readExistingLocation() { + return window.ipLocation?.result?.location || null; + } + + function waitForExistingLocation(timeout = LOCATION_WAIT_MS) { + return new Promise((resolve, reject) => { + const existingLocation = readExistingLocation(); + if (existingLocation) { + resolve(existingLocation); + return; + } + + const startTime = Date.now(); + const timer = window.setInterval(() => { + const location = readExistingLocation(); + if (location) { + window.clearInterval(timer); + resolve(location); + return; + } + + if (Date.now() - startTime >= timeout) { + window.clearInterval(timer); + reject(new Error("等待 ipLocation 超时")); + } + }, LOCATION_POLL_INTERVAL_MS); + }); + } + + function requestLocationFallback() { + return new Promise((resolve, reject) => { + if (!window.$?.ajax) { + reject(new Error("jQuery 未加载,无法执行定位兜底请求")); + return; + } + + $.ajax({ + type: 'get', + url: 'https://apis.map.qq.com/ws/location/v1/ip', + data: { + key: '你的key', + output: 'jsonp', + callback: '?', + }, + dataType: 'jsonp', + success: function (res) { + debugLog("定位兜底返回", res); + if (res && res.status === 0 && res.result?.location) { + window.ipLocation = res; + resolve(res.result.location); + } else { + reject(new Error("定位失败")); + } + }, + error: function () { + reject(new Error("定位请求失败")); + } + }); + }); + } + + function getLocation() { + return waitForExistingLocation() + .then(location => { + debugLog("使用 txmap.js 定位", location); + return location; + }) + .catch(error => { + debugLog("等待 txmap.js 定位失败,转兜底请求", error); + return requestLocationFallback(); + }); + } + + + function getWeather(lng, lat) { + const location = `${lng.toFixed(2)},${lat.toFixed(2)}`; + const params = new URLSearchParams({ + location, + lang: WEATHER_LANG, + key: WEATHER_KEY + }); + const requestUrl = `${WEATHER_HOST}/v7/weather/now?${params.toString()}`; + + debugLog("天气请求参数", { + host: WEATHER_HOST, + location, + lang: WEATHER_LANG, + key: maskSecret(WEATHER_KEY) + }); + + return fetch(requestUrl, { + headers: { + Accept: "application/json" + } + }).then(async res => { + const responseText = await res.text(); + let data; + + try { + data = JSON.parse(responseText); + } catch (parseError) { + debugLog("天气接口返回非 JSON", { + status: res.status, + statusText: res.statusText, + body: responseText + }); + throw new Error(`天气接口返回非 JSON,HTTP ${res.status}`); + } + + debugLog("天气接口响应", { + status: res.status, + statusText: res.statusText, + body: data + }); + + if (!res.ok) { + const detail = data?.error?.detail || data?.msg || `HTTP ${res.status}`; + throw new Error(`天气接口请求失败:${detail}`); + } + + return data; + }); + } + + + function renderWeather(data) { + const el = document.getElementById(WEATHER_ID); + if (!el) return; + + if (data.code !== "200") { + debugLog("天气接口业务错误", data); + el.innerHTML = `天气获取失败:${data.code || "未知错误"}`; + return; + } + + const now = data.now; + + const emojiMap = { + "晴": "☀️", + "多云": "⛅", + "阴": "☁️", + "雨": "🌧️", + "雪": "❄️", + "雷": "⛈️" + }; + + const emoji = emojiMap[now.text] || "🌡️"; + const weatherSentence = `当前天气${now.text},气温${now.temp}℃,体感${now.feelsLike}℃,${now.windDir}${now.windScale}级,湿度${now.humidity}%,能见度${now.vis}km。`; + + el.innerHTML = ` +