fix: 天气预测接口更替为开源的 Open-Meteo
- 默认情况下,将结合最适合的天气模型(auto) - 预报 3天长度
This commit is contained in:
parent
d8456d165b
commit
7555c4c72b
@ -1,7 +1,6 @@
|
|||||||
var WeatherForecast = (function() {
|
var WeatherForecast = (function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var weatherApiKey = 'Uxh4IdMuAvhSiBnsf4UUDVGF4e3YAp2B';
|
|
||||||
var weatherEnabled = false;
|
var weatherEnabled = false;
|
||||||
var weatherData = null;
|
var weatherData = null;
|
||||||
var currentForecastIndex = 0;
|
var currentForecastIndex = 0;
|
||||||
@ -81,7 +80,6 @@ var WeatherForecast = (function() {
|
|||||||
contentElement.innerHTML =
|
contentElement.innerHTML =
|
||||||
'<div class="weather-loading">' +
|
'<div class="weather-loading">' +
|
||||||
'<i class="layui-icon layui-icon-loading layui-icon-anim-rotate"></i>' +
|
'<i class="layui-icon layui-icon-loading layui-icon-anim-rotate"></i>' +
|
||||||
'<p>请确保网络可访问 Windy API 服务</p>' +
|
|
||||||
'<p>正在获取天气预测数据...</p>' +
|
'<p>正在获取天气预测数据...</p>' +
|
||||||
'</div>';
|
'</div>';
|
||||||
}
|
}
|
||||||
@ -140,23 +138,19 @@ var WeatherForecast = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fetchWeatherData(lat, lon) {
|
function fetchWeatherData(lat, lon) {
|
||||||
var requestBody = {
|
var url = 'https://api.open-meteo.com/v1/forecast?' +
|
||||||
"lat": parseFloat(lat.toFixed(2)),
|
'latitude=' + lat.toFixed(4) +
|
||||||
"lon": parseFloat(lon.toFixed(2)),
|
'&longitude=' + lon.toFixed(4) +
|
||||||
"model": "gfs",
|
'¤t=temperature_2m,wind_speed_10m,wind_direction_10m,relative_humidity_2m,surface_pressure' +
|
||||||
"parameters": ["temp", "wind", "precip", "pressure", "rh", "windGust"],
|
'&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m,wind_direction_10m,precipitation,surface_pressure,wind_gusts_10m' +
|
||||||
"levels": ["surface"],
|
'&forecast_days=3' +
|
||||||
"key": weatherApiKey,
|
'&timezone=auto';
|
||||||
"hours": 72
|
|
||||||
};
|
|
||||||
|
|
||||||
fetch('https://api.windy.com/api/point-forecast/v2', {
|
fetch(url, {
|
||||||
method: 'POST',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json'
|
||||||
},
|
}
|
||||||
body: JSON.stringify(requestBody)
|
|
||||||
})
|
})
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@ -165,7 +159,7 @@ var WeatherForecast = (function() {
|
|||||||
return response.json();
|
return response.json();
|
||||||
})
|
})
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
weatherData = data;
|
weatherData = transformOpenMeteoData(data);
|
||||||
|
|
||||||
var currentTime = new Date().getTime();
|
var currentTime = new Date().getTime();
|
||||||
var closestIndex = 0;
|
var closestIndex = 0;
|
||||||
@ -203,6 +197,40 @@ var WeatherForecast = (function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function transformOpenMeteoData(data) {
|
||||||
|
var transformed = {
|
||||||
|
ts: [],
|
||||||
|
'temp-surface': [],
|
||||||
|
'wind-speed': [],
|
||||||
|
'wind-direction': [],
|
||||||
|
'precipitation': [],
|
||||||
|
'rh-surface': [],
|
||||||
|
'pressure-surface': [],
|
||||||
|
'gust-surface': []
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!data.hourly || !data.hourly.time) {
|
||||||
|
return transformed;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < data.hourly.time.length; i++) {
|
||||||
|
transformed.ts.push(new Date(data.hourly.time[i]).getTime());
|
||||||
|
|
||||||
|
transformed['temp-surface'].push(data.hourly.temperature_2m[i]);
|
||||||
|
|
||||||
|
var windSpeedMs = data.hourly.wind_speed_10m[i] ? data.hourly.wind_speed_10m[i] / 3.6 : null;
|
||||||
|
transformed['wind-speed'].push(windSpeedMs);
|
||||||
|
transformed['wind-direction'].push(data.hourly.wind_direction_10m[i]);
|
||||||
|
transformed['precipitation'].push(data.hourly.precipitation[i]);
|
||||||
|
transformed['rh-surface'].push(data.hourly.relative_humidity_2m[i]);
|
||||||
|
transformed['pressure-surface'].push(data.hourly.surface_pressure[i]);
|
||||||
|
var gustMs = data.hourly.wind_gusts_10m[i] ? data.hourly.wind_gusts_10m[i] / 3.6 : null;
|
||||||
|
transformed['gust-surface'].push(gustMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return transformed;
|
||||||
|
}
|
||||||
|
|
||||||
function displayCurrentForecast() {
|
function displayCurrentForecast() {
|
||||||
if (!weatherData || !weatherData.ts || weatherData.ts.length === 0) {
|
if (!weatherData || !weatherData.ts || weatherData.ts.length === 0) {
|
||||||
displayWeatherError('无可用的天气预测数据');
|
displayWeatherError('无可用的天气预测数据');
|
||||||
@ -213,22 +241,22 @@ var WeatherForecast = (function() {
|
|||||||
var forecastHtml = '<div class="weather-forecast-item"><div class="weather-param-grid">';
|
var forecastHtml = '<div class="weather-forecast-item"><div class="weather-param-grid">';
|
||||||
|
|
||||||
if (weatherData['temp-surface'] && weatherData['temp-surface'][i] !== null) {
|
if (weatherData['temp-surface'] && weatherData['temp-surface'][i] !== null) {
|
||||||
var temp = (weatherData['temp-surface'][i] - 273.15).toFixed(1);
|
var temp = weatherData['temp-surface'][i].toFixed(1);
|
||||||
forecastHtml += createWeatherParam('温度', temp + '°C');
|
forecastHtml += createWeatherParam('温度', temp + '°C');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weatherData['wind_u-surface'] && weatherData['wind_v-surface'] &&
|
if (weatherData['wind-speed'] && weatherData['wind-speed'][i] !== null) {
|
||||||
weatherData['wind_u-surface'][i] !== null && weatherData['wind_v-surface'][i] !== null) {
|
var windSpeed = weatherData['wind-speed'][i].toFixed(1);
|
||||||
var windU = weatherData['wind_u-surface'][i];
|
|
||||||
var windV = weatherData['wind_v-surface'][i];
|
|
||||||
var windSpeed = Math.sqrt(windU * windU + windV * windV).toFixed(1);
|
|
||||||
var windDir = getWindDirection(windU, windV);
|
|
||||||
forecastHtml += createWeatherParam('风速', windSpeed + ' m/s');
|
forecastHtml += createWeatherParam('风速', windSpeed + ' m/s');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weatherData['wind-direction'] && weatherData['wind-direction'][i] !== null) {
|
||||||
|
var windDir = getWindDirectionFromDegrees(weatherData['wind-direction'][i]);
|
||||||
forecastHtml += createWeatherParam('风向', windDir);
|
forecastHtml += createWeatherParam('风向', windDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weatherData['past3hprecip-surface'] && weatherData['past3hprecip-surface'][i] !== null) {
|
if (weatherData['precipitation'] && weatherData['precipitation'][i] !== null) {
|
||||||
var precip = weatherData['past3hprecip-surface'][i].toFixed(1);
|
var precip = weatherData['precipitation'][i].toFixed(1);
|
||||||
forecastHtml += createWeatherParam('降水', precip + ' mm');
|
forecastHtml += createWeatherParam('降水', precip + ' mm');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +266,7 @@ var WeatherForecast = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (weatherData['pressure-surface'] && weatherData['pressure-surface'][i] !== null) {
|
if (weatherData['pressure-surface'] && weatherData['pressure-surface'][i] !== null) {
|
||||||
var pressure = (weatherData['pressure-surface'][i] / 100).toFixed(0);
|
var pressure = weatherData['pressure-surface'][i].toFixed(0);
|
||||||
forecastHtml += createWeatherParam('气压', pressure + ' hPa');
|
forecastHtml += createWeatherParam('气压', pressure + ' hPa');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +319,14 @@ var WeatherForecast = (function() {
|
|||||||
return directions[index];
|
return directions[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getWindDirectionFromDegrees(degrees) {
|
||||||
|
if (degrees === null || degrees === undefined) return '无风';
|
||||||
|
|
||||||
|
var directions = ['北', '东北', '东', '东南', '南', '西南', '西', '西北'];
|
||||||
|
var index = Math.round(degrees / 45) % 8;
|
||||||
|
return directions[index];
|
||||||
|
}
|
||||||
|
|
||||||
function isEnabled() {
|
function isEnabled() {
|
||||||
return weatherEnabled;
|
return weatherEnabled;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -851,7 +851,7 @@
|
|||||||
<div id="weatherForecastCard" class="weather-forecast-card" style="display: none;" th:if="${role=='SUPER_ADMIN'}">
|
<div id="weatherForecastCard" class="weather-forecast-card" style="display: none;" th:if="${role=='SUPER_ADMIN'}">
|
||||||
<div class="weather-card-header">
|
<div class="weather-card-header">
|
||||||
<h3 class="weather-card-title">
|
<h3 class="weather-card-title">
|
||||||
Windy 天气预测
|
Open-Meteo 天气预测
|
||||||
</h3>
|
</h3>
|
||||||
<button class="weather-close-btn" onclick="closeWeatherCard()">×</button>
|
<button class="weather-close-btn" onclick="closeWeatherCard()">×</button>
|
||||||
</div>
|
</div>
|
||||||
@ -948,10 +948,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<div class="dropdown-group" th:if="${role=='SUPER_ADMIN'}">
|
<div class="dropdown-group" th:if="${role=='SUPER_ADMIN'}">
|
||||||
<div class="dropdown-group-title">Windy 天气预测</div>
|
<div class="dropdown-group-title">Open-Meteo 天气预测</div>
|
||||||
<div class="dropdown-item">
|
<div class="dropdown-item">
|
||||||
<label class="switch-label">
|
<label class="switch-label">
|
||||||
<span>启用天气预测(需网络被代理)</span>
|
<span>启用天气预测</span>
|
||||||
<input type="checkbox" id="enableWeatherSwitch" onchange="toggleWeatherForecast()">
|
<input type="checkbox" id="enableWeatherSwitch" onchange="toggleWeatherForecast()">
|
||||||
<span class="switch-slider"></span>
|
<span class="switch-slider"></span>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user