feat: 新增总降雨的数值查看

This commit is contained in:
yarnom 2025-08-26 20:02:42 +08:00
parent f969c2fe0f
commit 3e50260c51
5 changed files with 81 additions and 6 deletions

View File

@ -131,7 +131,8 @@ func GetSeriesFrom10Min(db *sql.DB, stationID string, startTime, endTime time.Ti
ROUND(wind_dir_deg::numeric, 2) AS wind_direction, ROUND(wind_dir_deg::numeric, 2) AS wind_direction,
ROUND(rain_10m_mm_x1000/1000.0, 3) AS rainfall, ROUND(rain_10m_mm_x1000/1000.0, 3) AS rainfall,
ROUND(solar_wm2_x100/100.0, 2) AS light, ROUND(solar_wm2_x100/100.0, 2) AS light,
ROUND(uv_index::numeric, 2) AS uv ROUND(uv_index::numeric, 2) AS uv,
ROUND(rain_total_mm_x1000/1000.0, 3) AS rain_total
FROM rs485_weather_10min FROM rs485_weather_10min
WHERE station_id = $1 AND bucket_start >= $2 AND bucket_start <= $3 WHERE station_id = $1 AND bucket_start >= $2 AND bucket_start <= $3
ORDER BY bucket_start` ORDER BY bucket_start`
@ -156,7 +157,7 @@ func GetSeriesFrom10Min(db *sql.DB, stationID string, startTime, endTime time.Ti
var points []types.WeatherPoint var points []types.WeatherPoint
for rows.Next() { for rows.Next() {
var p types.WeatherPoint var p types.WeatherPoint
if err := rows.Scan(&p.DateTime, &p.Temperature, &p.Humidity, &p.Pressure, &p.WindSpeed, &p.WindDir, &p.Rainfall, &p.Light, &p.UV); err != nil { if err := rows.Scan(&p.DateTime, &p.Temperature, &p.Humidity, &p.Pressure, &p.WindSpeed, &p.WindDir, &p.Rainfall, &p.Light, &p.UV, &p.RainTotal); err != nil {
continue continue
} }
points = append(points, p) points = append(points, p)
@ -191,7 +192,8 @@ func buildAggFrom10MinQuery(interval string) string {
SUM(sin(radians(wind_dir_deg)) * sample_count)::double precision AS sin_sum, SUM(sin(radians(wind_dir_deg)) * sample_count)::double precision AS sin_sum,
SUM(cos(radians(wind_dir_deg)) * sample_count)::double precision AS cos_sum, SUM(cos(radians(wind_dir_deg)) * sample_count)::double precision AS cos_sum,
SUM(rain_10m_mm_x1000) AS rain_sum, SUM(rain_10m_mm_x1000) AS rain_sum,
SUM(sample_count) AS n_sum SUM(sample_count) AS n_sum,
MAX(rain_total_mm_x1000) AS rain_total_max
FROM base FROM base
GROUP BY 1 GROUP BY 1
) )
@ -206,7 +208,8 @@ func buildAggFrom10MinQuery(interval string) string {
ELSE degrees(atan2(sin_sum, cos_sum)) END)::numeric, 2) AS wind_direction, ELSE degrees(atan2(sin_sum, cos_sum)) END)::numeric, 2) AS wind_direction,
ROUND((rain_sum/1000.0)::numeric, 3) AS rainfall, ROUND((rain_sum/1000.0)::numeric, 3) AS rainfall,
ROUND((w_solar/NULLIF(n_sum,0))/100.0, 2) AS light, ROUND((w_solar/NULLIF(n_sum,0))/100.0, 2) AS light,
ROUND((w_uv/NULLIF(n_sum,0))::numeric, 2) AS uv ROUND((w_uv/NULLIF(n_sum,0))::numeric, 2) AS uv,
ROUND((rain_total_max/1000.0)::numeric, 3) AS rain_total
FROM g FROM g
ORDER BY grp` ORDER BY grp`
} }
@ -415,3 +418,37 @@ func GetForecastData(db *sql.DB, stationID string, startTime, endTime time.Time,
return points, nil return points, nil
} }
func GetSeriesRaw(db *sql.DB, stationID string, startTime, endTime time.Time) ([]types.WeatherPoint, error) {
query := `
SELECT
to_char(timestamp, 'YYYY-MM-DD HH24:MI:SS') AS date_time,
COALESCE(temperature, 0) AS temperature,
COALESCE(humidity, 0) AS humidity,
COALESCE(pressure, 0) AS pressure,
COALESCE(wind_speed, 0) AS wind_speed,
COALESCE(wind_direction, 0) AS wind_direction,
COALESCE(rainfall, 0) AS rainfall,
COALESCE(light, 0) AS light,
COALESCE(uv, 0) AS uv,
COALESCE(rainfall, 0) AS rain_total
FROM rs485_weather_data
WHERE station_id = $1 AND timestamp >= $2 AND timestamp <= $3
ORDER BY timestamp`
rows, err := db.Query(query, stationID, startTime, endTime)
if err != nil {
return nil, err
}
defer rows.Close()
var points []types.WeatherPoint
for rows.Next() {
var p types.WeatherPoint
if err := rows.Scan(&p.DateTime, &p.Temperature, &p.Humidity, &p.Pressure, &p.WindSpeed, &p.WindDir, &p.Rainfall, &p.Light, &p.UV, &p.RainTotal); err != nil {
continue
}
points = append(points, p)
}
return points, nil
}

View File

@ -126,7 +126,12 @@ func getDataHandler(c *gin.Context) {
} }
// 获取数据改为基于10分钟聚合表的再聚合 // 获取数据改为基于10分钟聚合表的再聚合
points, err := database.GetSeriesFrom10Min(database.GetDB(), stationID, start, end, interval) var points []types.WeatherPoint
if interval == "raw" {
points, err = database.GetSeriesRaw(database.GetDB(), stationID, start, end)
} else {
points, err = database.GetSeriesFrom10Min(database.GetDB(), stationID, start, end, interval)
}
if err != nil { if err != nil {
log.Printf("查询数据失败: %v", err) // 记录具体错误到服务端日志 log.Printf("查询数据失败: %v", err) // 记录具体错误到服务端日志
c.JSON(http.StatusInternalServerError, gin.H{ c.JSON(http.StatusInternalServerError, gin.H{

View File

@ -24,6 +24,7 @@ type WeatherPoint struct {
Rainfall float64 `json:"rainfall"` Rainfall float64 `json:"rainfall"`
Light float64 `json:"light"` Light float64 `json:"light"`
UV float64 `json:"uv"` UV float64 `json:"uv"`
RainTotal float64 `json:"rain_total"`
} }
// PageData 页面数据结构 // PageData 页面数据结构

View File

@ -32,12 +32,20 @@ const WeatherChart = {
const item = historyData.find(d => d.date_time === label); const item = historyData.find(d => d.date_time === label);
return item ? item.rainfall : null; return item ? item.rainfall : null;
}); });
const historyRainTotals = allLabels.map(label => {
const item = historyData.find(d => d.date_time === label);
return item && item.rain_total !== undefined ? item.rain_total : null;
});
// 准备预报数据 // 准备预报数据
const forecastTemperatures = allLabels.map(label => { const forecastTemperatures = allLabels.map(label => {
const item = forecastData.find(d => d.date_time === label); const item = forecastData.find(d => d.date_time === label);
return item && item.temperature !== null ? item.temperature : null; return item && item.temperature !== null ? item.temperature : null;
}); });
const forecastHumidities = allLabels.map(label => {
const item = forecastData.find(d => d.date_time === label);
return item && item.humidity !== null ? item.humidity : null;
});
const forecastRainfalls = allLabels.map(label => { const forecastRainfalls = allLabels.map(label => {
const item = forecastData.find(d => d.date_time === label); const item = forecastData.find(d => d.date_time === label);
return item && item.rainfall !== null ? item.rainfall : null; return item && item.rainfall !== null ? item.rainfall : null;
@ -74,6 +82,17 @@ const WeatherChart = {
backgroundColor: 'rgba(54, 162, 235, 0.6)', backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgb(54, 162, 235)', borderColor: 'rgb(54, 162, 235)',
yAxisID: 'y-rainfall' yAxisID: 'y-rainfall'
},
{
label: '累计雨量 (mm) - 实测(10m total)',
data: historyRainTotals,
borderColor: 'rgb(75, 192, 192)',
backgroundColor: 'rgba(75, 192, 192, 0.1)',
yAxisID: 'y-rainfall',
tension: 0.2,
spanGaps: false,
pointRadius: 0,
hidden: true
} }
]; ];
@ -88,7 +107,19 @@ const WeatherChart = {
borderDash: [5, 5], borderDash: [5, 5],
yAxisID: 'y-temperature', yAxisID: 'y-temperature',
tension: 0.4, tension: 0.4,
spanGaps: false spanGaps: false,
hidden: true
},
{
label: '湿度 (%) - 预报',
data: forecastHumidities,
borderColor: 'rgba(255, 165, 0, 0.8)',
backgroundColor: 'rgba(255, 165, 0, 0.05)',
borderDash: [5, 5],
yAxisID: 'y-humidity',
tension: 0.4,
spanGaps: false,
hidden: false
}, },
{ {
label: '雨量 (mm) - 预报', label: '雨量 (mm) - 预报',

View File

@ -489,6 +489,7 @@
<option value="10min">10分钟</option> <option value="10min">10分钟</option>
<option value="30min">30分钟</option> <option value="30min">30分钟</option>
<option value="1hour" selected>1小时</option> <option value="1hour" selected>1小时</option>
<option value="raw">原始(16s)</option>
</select> </select>
</div> </div>