feat: 新增总降雨的数值查看
This commit is contained in:
parent
f969c2fe0f
commit
3e50260c51
@ -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
|
||||||
|
}
|
||||||
|
|||||||
@ -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{
|
||||||
|
|||||||
@ -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 页面数据结构
|
||||||
|
|||||||
@ -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) - 预报',
|
||||||
|
|||||||
@ -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>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user