go_rain_dtu/web.go
2025-05-14 16:56:03 +08:00

207 lines
5.3 KiB
Go

package main
import (
"html/template"
"net/http"
"os"
"path/filepath"
"strconv"
"time"
)
func startWebServer() {
if err := os.MkdirAll("templates", 0755); err != nil {
logger.Fatalf("创建模板目录失败: %v", err)
}
indexPath := filepath.Join("templates", "index.html")
if _, err := os.Stat(indexPath); os.IsNotExist(err) {
logger.Printf("警告: %s 不存在", indexPath)
}
http.HandleFunc("/", handleIndex)
http.HandleFunc("/refresh-data", handleRefresh)
logger.Printf("启动Web服务器: http://0.0.0.0:10003")
if err := http.ListenAndServe(":10003", nil); err != nil {
logger.Fatalf("启动Web服务器失败: %v", err)
}
}
func handleRefresh(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "只支持POST请求", http.StatusMethodNotAllowed)
return
}
activeConnMutex.Lock()
sensor := activeSensor
activeConnMutex.Unlock()
if sensor == nil {
http.Error(w, "无活动的传感器连接", http.StatusServiceUnavailable)
return
}
if time.Since(sensor.lastQueryTime) < 3*time.Second {
w.WriteHeader(http.StatusOK)
return
}
if sensor.sendQuery() {
logger.Printf("用户触发查询命令")
w.WriteHeader(http.StatusOK)
} else {
http.Error(w, "发送查询命令失败", http.StatusInternalServerError)
}
}
func handleIndex(w http.ResponseWriter, r *http.Request) {
page := 1
pageSize := 20
if pageParam := r.URL.Query().Get("page"); pageParam != "" {
if p, err := strconv.Atoi(pageParam); err == nil && p > 0 {
page = p
}
}
offset := (page - 1) * pageSize
var total int
err := db.QueryRow("SELECT COUNT(*) FROM sensor_data").Scan(&total)
if err != nil {
http.Error(w, "数据库错误", http.StatusInternalServerError)
logger.Printf("统计记录错误: %v", err)
return
}
totalPages := (total + pageSize - 1) / pageSize
pages := []int{}
startPage := page - 2
if startPage < 1 {
startPage = 1
}
endPage := startPage + 4
if endPage > totalPages {
endPage = totalPages
startPage = endPage - 4
if startPage < 1 {
startPage = 1
}
}
for i := startPage; i <= endPage; i++ {
pages = append(pages, i)
}
rows, err := db.Query(`
SELECT id, timestamp, wind_speed, wind_force, wind_direction8, wind_direction360,
humidity, temperature, noise, pm25, pm10, atm_pressure,
lux20wh, lux20wl, light20w, optical_rain, compass_angle, solar_radiation
FROM sensor_data
ORDER BY timestamp DESC
LIMIT ? OFFSET ?
`, pageSize, offset)
if err != nil {
http.Error(w, "数据库错误", http.StatusInternalServerError)
logger.Printf("查询记录错误: %v", err)
return
}
defer rows.Close()
var records []SensorData
for rows.Next() {
var id int
var data SensorData
err := rows.Scan(
&id, &data.Timestamp, &data.WindSpeed, &data.WindForce, &data.WindDirection8, &data.WindDirection360,
&data.Humidity, &data.Temperature, &data.Noise, &data.PM25, &data.PM10, &data.AtmPressure,
&data.Lux20WH, &data.Lux20WL, &data.Light20W, &data.OpticalRain, &data.CompassAngle, &data.SolarRadiation,
)
if err != nil {
http.Error(w, "数据库错误", http.StatusInternalServerError)
logger.Printf("扫描记录错误: %v", err)
return
}
records = append(records, data)
}
var latest SensorData
var id int
err = db.QueryRow(`
SELECT id, timestamp, wind_speed, wind_force, wind_direction8, wind_direction360,
humidity, temperature, noise, pm25, pm10, atm_pressure,
lux20wh, lux20wl, light20w, optical_rain, compass_angle, solar_radiation
FROM sensor_data
ORDER BY timestamp DESC
LIMIT 1
`).Scan(
&id, &latest.Timestamp, &latest.WindSpeed, &latest.WindForce, &latest.WindDirection8, &latest.WindDirection360,
&latest.Humidity, &latest.Temperature, &latest.Noise, &latest.PM25, &latest.PM10, &latest.AtmPressure,
&latest.Lux20WH, &latest.Lux20WL, &latest.Light20W, &latest.OpticalRain, &latest.CompassAngle, &latest.SolarRadiation,
)
var latestPtr *SensorData
if err == nil {
latestPtr = &latest
}
activeConnMutex.Lock()
connStatus := "未连接"
clientAddr := clientAddress
var lastReset time.Time
if activeSensor != nil {
connStatus = "已连接"
lastReset = activeSensor.lastResetTime
}
activeConnMutex.Unlock()
lastResetStr := "无记录"
if !lastReset.IsZero() {
lastResetStr = lastReset.Format("2006-01-02 15:04:05")
}
data := struct {
Records []SensorData
Latest *SensorData
Page int
PrevPage int
NextPage int
TotalPages int
Pages []int
ConnStatus string
ClientAddr string
LastReset string
}{
Records: records,
Latest: latestPtr,
Page: page,
PrevPage: page - 1,
NextPage: page + 1,
TotalPages: totalPages,
Pages: pages,
ConnStatus: connStatus,
ClientAddr: clientAddr,
LastReset: lastResetStr,
}
funcMap := template.FuncMap{
"div": func(a, b int) float64 {
return float64(a) / float64(b)
},
}
tmpl, err := template.New("index.html").Funcs(funcMap).ParseFiles("templates/index.html")
if err != nil {
http.Error(w, "模板错误", http.StatusInternalServerError)
logger.Printf("解析模板错误: %v", err)
return
}
if err := tmpl.Execute(w, data); err != nil {
http.Error(w, "模板错误", http.StatusInternalServerError)
logger.Printf("执行模板错误: %v", err)
return
}
}