Compare commits

..

No commits in common. "c6c9015cd3dead4aa4a7aac727ce1efba5f202a9" and "2599b00626386da64a92955530b60f0234dc8da5" have entirely different histories.

3 changed files with 30 additions and 110 deletions

View File

@ -3,11 +3,11 @@ package db
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
_ "github.com/go-sql-driver/mysql"
"log" "log"
"math"
"rain_monitor/models" "rain_monitor/models"
"time" "time"
_ "github.com/go-sql-driver/mysql"
) )
var db *sql.DB var db *sql.DB
@ -84,44 +84,6 @@ func SaveWeatherData(data *models.WeatherData) (int64, error) {
} }
func SaveRainGaugeData(data *models.RainGaugeData) (int64, error) { func SaveRainGaugeData(data *models.RainGaugeData) (int64, error) {
// 检查是否在短时间内已经插入过类似数据
// 获取最近5分钟内的数据
fiveMinutesAgo := data.Timestamp.Add(-5 * time.Minute)
rows, err := db.Query(`
SELECT id, timestamp, total_rainfall
FROM rain_gauge_data
WHERE timestamp BETWEEN ? AND ?
ORDER BY timestamp DESC
`, fiveMinutesAgo, data.Timestamp)
if err != nil {
log.Printf("查询最近雨量计数据失败: %v", err)
// 即使查询失败,我们仍然尝试插入新数据
} else {
defer rows.Close()
// 检查是否有相似数据
for rows.Next() {
var id int64
var ts time.Time
var rainfall float64
if err := rows.Scan(&id, &ts, &rainfall); err != nil {
log.Printf("扫描雨量计数据失败: %v", err)
continue
}
// 如果时间非常接近小于1分钟且雨量数据相同或非常接近则认为是重复数据
timeDiff := data.Timestamp.Sub(ts)
rainfallDiff := math.Abs(data.TotalRainfall - rainfall)
if timeDiff < time.Minute && rainfallDiff < 0.1 {
log.Printf("检测到重复的雨量计数据跳过插入。ID=%d, 时间=%v", id, ts)
return id, nil // 返回已存在的记录ID
}
}
}
result, err := db.Exec(models.InsertRainGaugeDataSQL, result, err := db.Exec(models.InsertRainGaugeDataSQL,
data.Timestamp, data.DailyRainfall, data.InstantRainfall, data.YesterdayRainfall, data.Timestamp, data.DailyRainfall, data.InstantRainfall, data.YesterdayRainfall,
data.TotalRainfall, data.HourlyRainfall, data.LastHourRainfall, data.Max24hRainfall, data.TotalRainfall, data.HourlyRainfall, data.LastHourRainfall, data.Max24hRainfall,
@ -134,7 +96,6 @@ func SaveRainGaugeData(data *models.RainGaugeData) (int64, error) {
if err != nil { if err != nil {
return 0, fmt.Errorf("获取插入ID失败: %v", err) return 0, fmt.Errorf("获取插入ID失败: %v", err)
} }
log.Printf("雨量计数据已保存ID=%d, 时间=%v", id, data.Timestamp)
return id, nil return id, nil
} }
@ -255,19 +216,7 @@ func GetAggregatedData(start, end time.Time) ([]models.AggregatedData, error) {
log.Printf("扫描行数据失败: %v", err) log.Printf("扫描行数据失败: %v", err)
return nil, fmt.Errorf("扫描聚合数据失败: %v", err) return nil, fmt.Errorf("扫描聚合数据失败: %v", err)
} }
// 设置格式化时间字符串
data.FormattedTime = timestampStr data.FormattedTime = timestampStr
// 尝试解析时间字符串为time.Time类型
timestamp, err := time.Parse("2006-01-02 15:04:05", timestampStr)
if err != nil {
log.Printf("解析时间字符串失败: %v, 原始字符串: %s", err, timestampStr)
// 即使解析失败也继续处理前端会使用FormattedTime
} else {
data.Timestamp = timestamp
}
result = append(result, data) result = append(result, data)
} }

View File

@ -160,7 +160,7 @@ LIMIT 1
const QueryAggregatedDataSQL = ` const QueryAggregatedDataSQL = `
SELECT SELECT
w.time_hour as timestamp, w.time_hour as timestamp,
MAX(r.hourly_rainfall) as rainfall, MAX(r.daily_rainfall) as rainfall,
AVG(w.temperature) as avg_temperature, AVG(w.temperature) as avg_temperature,
AVG(w.humidity) as avg_humidity, AVG(w.humidity) as avg_humidity,
AVG(w.wind_speed) as avg_wind_speed, AVG(w.wind_speed) as avg_wind_speed,
@ -176,7 +176,7 @@ FROM
LEFT JOIN LEFT JOIN
(SELECT (SELECT
DATE_FORMAT(timestamp, '%Y-%m-%d %H:00:00') as time_hour, DATE_FORMAT(timestamp, '%Y-%m-%d %H:00:00') as time_hour,
hourly_rainfall daily_rainfall
FROM rain_gauge_data FROM rain_gauge_data
WHERE timestamp BETWEEN ? AND ? WHERE timestamp BETWEEN ? AND ?
) r ON w.time_hour = r.time_hour ) r ON w.time_hour = r.time_hour

View File

@ -247,7 +247,7 @@
<thead> <thead>
<tr> <tr>
<th>时间</th> <th>时间</th>
<th>小时降雨量(mm)</th> <th>降雨量(mm)</th>
<th>温度(℃)</th> <th>温度(℃)</th>
<th>湿度(%)</th> <th>湿度(%)</th>
<th>风速(m/s)</th> <th>风速(m/s)</th>
@ -544,34 +544,22 @@
try { try {
// 按时间正序排列数据(从早到晚) // 按时间正序排列数据(从早到晚)
data.sort((a, b) => { data.sort((a, b) => {
const timeA = a.formatted_time ? new Date(a.formatted_time) : new Date(a.timestamp); const timeA = a.timestamp ? new Date(a.timestamp) : new Date(a.formatted_time);
const timeB = b.formatted_time ? new Date(b.formatted_time) : new Date(b.timestamp); const timeB = b.timestamp ? new Date(b.timestamp) : new Date(b.formatted_time);
return timeA - timeB; return timeA - timeB;
}); });
const labels = data.map(item => { const labels = data.map(item => {
// 优先使用formatted_time如果不存在则尝试使用timestamp
let timeStr = item.formatted_time || item.timestamp;
try {
// 解析时间字符串为本地时间 // 解析时间字符串为本地时间
const timeStr = item.formatted_time || item.timestamp;
const date = new Date(timeStr); const date = new Date(timeStr);
// 检查日期是否有效
if (isNaN(date.getTime())) {
return timeStr; // 如果无法解析,直接返回原始字符串
}
// 格式化为中文日期时间格式 // 格式化为中文日期时间格式
return date.getFullYear() + '/' + return date.getFullYear() + '/' +
(date.getMonth() + 1).toString().padStart(2, '0') + '/' + (date.getMonth() + 1).toString().padStart(2, '0') + '/' +
date.getDate().toString().padStart(2, '0') + ' ' + date.getDate().toString().padStart(2, '0') + ' ' +
date.getHours().toString().padStart(2, '0') + ':' + date.getHours().toString().padStart(2, '0') + ':' +
date.getMinutes().toString().padStart(2, '0'); date.getMinutes().toString().padStart(2, '0');
} catch (e) {
console.error('图表时间解析错误:', e);
return timeStr; // 出错时返回原始字符串
}
}); });
// 是否使用自适应范围 // 是否使用自适应范围
@ -600,7 +588,7 @@
datasets: [ datasets: [
{ {
type: 'bar', type: 'bar',
label: '小时降雨量(mm)', label: '降雨量(mm)',
data: data.map(item => item.rainfall !== null && !isNaN(item.rainfall) ? item.rainfall : 0), data: data.map(item => item.rainfall !== null && !isNaN(item.rainfall) ? item.rainfall : 0),
backgroundColor: 'rgba(54, 162, 235, 0.5)', backgroundColor: 'rgba(54, 162, 235, 0.5)',
borderColor: 'rgba(54, 162, 235, 1)', borderColor: 'rgba(54, 162, 235, 1)',
@ -630,7 +618,7 @@
position: 'left', position: 'left',
title: { title: {
display: true, display: true,
text: '小时降雨量(mm)' text: '降雨量(mm)'
}, },
grid: { grid: {
drawOnChartArea: false drawOnChartArea: false
@ -666,37 +654,20 @@
tbody.innerHTML = ''; tbody.innerHTML = '';
// 按时间倒序排列数据(从晚到早),这样最新的数据在表格顶部 // 按时间倒序排列数据(从晚到早),这样最新的数据在表格顶部
const sortedData = [...data].sort((a, b) => { const sortedData = [...data].sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
// 使用formatted_time进行排序如果不存在则尝试使用timestamp
const timeA = a.formatted_time ? new Date(a.formatted_time) : new Date(a.timestamp);
const timeB = b.formatted_time ? new Date(b.formatted_time) : new Date(b.timestamp);
return timeB - timeA;
});
sortedData.forEach(item => { sortedData.forEach(item => {
const row = document.createElement('tr'); const row = document.createElement('tr');
// 解析时间字符串为本地时间
// 优先使用formatted_time如果不存在则尝试使用timestamp
let formattedDate;
if (item.formatted_time) {
// 如果已经有格式化好的时间,直接使用
formattedDate = item.formatted_time;
} else {
// 否则尝试解析timestamp并格式化
try {
const date = new Date(item.timestamp); const date = new Date(item.timestamp);
formattedDate =
const formattedDate =
date.getFullYear() + '/' + date.getFullYear() + '/' +
(date.getMonth() + 1).toString().padStart(2, '0') + '/' + (date.getMonth() + 1).toString().padStart(2, '0') + '/' +
date.getDate().toString().padStart(2, '0') + ' ' + date.getDate().toString().padStart(2, '0') + ' ' +
date.getHours().toString().padStart(2, '0') + ':' + date.getHours().toString().padStart(2, '0') + ':' +
date.getMinutes().toString().padStart(2, '0') + ':' + date.getMinutes().toString().padStart(2, '0') + ':' +
date.getSeconds().toString().padStart(2, '0'); date.getSeconds().toString().padStart(2, '0');
} catch (e) {
console.error('时间解析错误:', e);
formattedDate = '时间格式错误';
}
}
row.innerHTML = ` row.innerHTML = `
<td>${formattedDate}</td> <td>${formattedDate}</td>
@ -715,13 +686,13 @@
function exportData() { function exportData() {
// 从表格中获取完整数据 // 从表格中获取完整数据
const tableRows = document.querySelectorAll('#tableBody tr'); const tableRows = document.querySelectorAll('#tableBody tr');
let csv = '时间,小时降雨量(mm),温度(℃),湿度(%),风速(m/s),大气压(kPa),太阳辐射(W/m²)\n'; let csv = '时间,降雨量(mm),温度(℃),湿度(%),风速(m/s),大气压(kPa),太阳辐射(W/m²)\n';
tableRows.forEach(row => { tableRows.forEach(row => {
const cells = row.querySelectorAll('td'); const cells = row.querySelectorAll('td');
const rowData = [ const rowData = [
cells[0].textContent, // 时间 cells[0].textContent, // 时间
cells[1].textContent, // 小时降雨量 cells[1].textContent, // 降雨量
cells[2].textContent, // 温度 cells[2].textContent, // 温度
cells[3].textContent, // 湿度 cells[3].textContent, // 湿度
cells[4].textContent, // 风速 cells[4].textContent, // 风速