@@ -1074,9 +1074,10 @@ inject:
|
|||||||
- <script src="/js/shuoshuoshouye.js"></script>
|
- <script src="/js/shuoshuoshouye.js"></script>
|
||||||
- <script src="/js/ai-summary.js"></script>
|
- <script src="/js/ai-summary.js"></script>
|
||||||
- <script src="/js/search/typesense-search.js"></script>
|
- <script src="/js/search/typesense-search.js"></script>
|
||||||
- <script src="/js/footer.js"
|
- <script src="/js/footer.js"></script>
|
||||||
- <script src="https://cdn.jsdmirror.com/npm/echarts@4.9.0/dist/echarts.min.js"></script>
|
- <script src="https://cdn.jsdmirror.com/npm/echarts@4.9.0/dist/echarts.min.js"></script>
|
||||||
- <script src="https://cdn.jsdmirror.com/gh/bishshi/welcomemessage/txmap.js"></script>
|
- <script src="https://cdn.jsdmirror.com/gh/bishshi/welcomemessage/txmap.js"></script>
|
||||||
|
- <script src="/js/weather.js"></script>
|
||||||
- <script src="https://cdn.jsdmirror.com/gh/bishshi/rightmenu@1.2/rightmenu.js"></script>
|
- <script src="https://cdn.jsdmirror.com/gh/bishshi/rightmenu@1.2/rightmenu.js"></script>
|
||||||
- <script src="https://cdn.jsdmirror.com/gh/bishshi/sidecalendar@latest/calendar.js"></script>
|
- <script src="https://cdn.jsdmirror.com/gh/bishshi/sidecalendar@latest/calendar.js"></script>
|
||||||
- <script src="https://cdn.jsdmirror.com/npm/chinese-lunar@0.1.4/lib/chinese-lunar.js"></script>
|
- <script src="https://cdn.jsdmirror.com/npm/chinese-lunar@0.1.4/lib/chinese-lunar.js"></script>
|
||||||
@@ -1166,4 +1167,4 @@ ai_summary:
|
|||||||
enable: true
|
enable: true
|
||||||
title: BiのAI摘要
|
title: BiのAI摘要
|
||||||
loadingText: AI正在绞尽脑汁想思路ING···
|
loadingText: AI正在绞尽脑汁想思路ING···
|
||||||
modelName: HunYuan-Lite
|
modelName: HunYuan-Lite
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ if theme.aside.card_announcement.enable
|
|||||||
i.fas.fa-bullhorn.fa-shake
|
i.fas.fa-bullhorn.fa-shake
|
||||||
span= _p('aside.card_announcement')
|
span= _p('aside.card_announcement')
|
||||||
.announcement_content!= theme.aside.card_announcement.content
|
.announcement_content!= theme.aside.card_announcement.content
|
||||||
#welcome-ip-location-info
|
#welcome-ip-location-info
|
||||||
|
#aside-weather
|
||||||
@@ -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 = `
|
||||||
|
<div class="aside-weather-card">
|
||||||
|
<div class="weather-top">
|
||||||
|
</div>
|
||||||
|
<div class="weather-info">
|
||||||
|
${weatherSentence}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function initWeather() {
|
||||||
|
const el = document.getElementById(WEATHER_ID);
|
||||||
|
if (!el) return;
|
||||||
|
|
||||||
|
el.innerHTML = "🌥️ 获取天气中...";
|
||||||
|
|
||||||
|
getLocation()
|
||||||
|
.then(loc => getWeather(loc.lng, loc.lat))
|
||||||
|
.then(renderWeather)
|
||||||
|
.catch(err => {
|
||||||
|
console.error("[weather.js] 天气加载失败", err);
|
||||||
|
el.innerHTML = `🌧️ 天气加载失败:${err.message || "未知错误"}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 🚀 初次加载
|
||||||
|
window.addEventListener("load", initWeather);
|
||||||
|
|
||||||
|
// 🔄 pjax
|
||||||
|
document.addEventListener("pjax:complete", initWeather);
|
||||||
|
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user