fix: 调整一些bug

This commit is contained in:
fengyarnom 2025-05-24 13:37:49 +08:00
parent 0ba3f638f4
commit ceb83afff2
3 changed files with 267 additions and 173 deletions

View File

@ -1,168 +1,194 @@
package main package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template" "html/template"
"log" "log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"time" "time"
) )
// 启动HTTP服务器 // 启动HTTP服务器
func StartHTTPServer(address string) error { func StartHTTPServer(address string) error {
http.HandleFunc("/", handleIndex) http.HandleFunc("/", handleIndex)
http.HandleFunc("/api/data", handleGetData) http.HandleFunc("/api/data", handleGetData)
http.HandleFunc("/api/sensors", handleGetSensors) http.HandleFunc("/api/sensors", handleGetSensors)
http.HandleFunc("/api/clients", handleGetClients) http.HandleFunc("/api/clients", handleGetClients)
fmt.Printf("HTTP服务器已启动正在监听 %s\n", address) http.HandleFunc("/api/trigger-query", handleTriggerQuery)
return http.ListenAndServe(address, nil) fmt.Printf("HTTP服务器已启动正在监听 %s\n", address)
} return http.ListenAndServe(address, nil)
}
// 处理主页
func handleIndex(w http.ResponseWriter, r *http.Request) { // 处理主页
log.Printf("接收到主页请求: %s", r.URL.Path) func handleIndex(w http.ResponseWriter, r *http.Request) {
log.Printf("接收到主页请求: %s", r.URL.Path)
templatePath := "templates/index.html"
absPath, _ := filepath.Abs(templatePath) templatePath := "templates/index.html"
absPath, _ := filepath.Abs(templatePath)
_, err := os.Stat(templatePath)
if os.IsNotExist(err) { _, err := os.Stat(templatePath)
log.Printf("错误: 模板文件不存在: %s", absPath) if os.IsNotExist(err) {
http.Error(w, "模板文件不存在", http.StatusInternalServerError) log.Printf("错误: 模板文件不存在: %s", absPath)
return http.Error(w, "模板文件不存在", http.StatusInternalServerError)
} return
}
tmpl, err := template.ParseFiles(templatePath)
if err != nil { tmpl, err := template.ParseFiles(templatePath)
log.Printf("错误: 无法解析模板: %v", err) if err != nil {
http.Error(w, "无法加载模板:"+err.Error(), http.StatusInternalServerError) log.Printf("错误: 无法解析模板: %v", err)
return http.Error(w, "无法加载模板:"+err.Error(), http.StatusInternalServerError)
} return
}
log.Printf("模板加载成功,开始渲染")
err = tmpl.Execute(w, nil) log.Printf("模板加载成功,开始渲染")
if err != nil { err = tmpl.Execute(w, nil)
log.Printf("错误: 渲染模板出错: %v", err) if err != nil {
http.Error(w, "渲染模板出错:"+err.Error(), http.StatusInternalServerError) log.Printf("错误: 渲染模板出错: %v", err)
} http.Error(w, "渲染模板出错:"+err.Error(), http.StatusInternalServerError)
log.Printf("模板渲染完成") }
} log.Printf("模板渲染完成")
}
// 处理获取传感器数据的API
func handleGetData(w http.ResponseWriter, r *http.Request) { // 处理获取传感器数据的API
log.Printf("接收到获取数据请求: %s", r.URL.String()) func handleGetData(w http.ResponseWriter, r *http.Request) {
log.Printf("接收到获取数据请求: %s", r.URL.String())
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Content-Type", "application/json")
sensorIDStr := r.URL.Query().Get("sensor_id")
limitStr := r.URL.Query().Get("limit") sensorIDStr := r.URL.Query().Get("sensor_id")
startDateStr := r.URL.Query().Get("start_date") limitStr := r.URL.Query().Get("limit")
endDateStr := r.URL.Query().Get("end_date") startDateStr := r.URL.Query().Get("start_date")
endDateStr := r.URL.Query().Get("end_date")
limit := 500 // 默认限制为500条数据
noLimit := false // 是否不限制数据条数 limit := 500 // 默认限制为500条数据
noLimit := false // 是否不限制数据条数
var sensorID int
var err error var sensorID int
if sensorIDStr != "" && sensorIDStr != "all" { var err error
sensorID, err = strconv.Atoi(sensorIDStr) if sensorIDStr != "" && sensorIDStr != "all" {
if err != nil { sensorID, err = strconv.Atoi(sensorIDStr)
log.Printf("错误: 无效的传感器ID: %s", sensorIDStr) if err != nil {
http.Error(w, "无效的传感器ID", http.StatusBadRequest) log.Printf("错误: 无效的传感器ID: %s", sensorIDStr)
return http.Error(w, "无效的传感器ID", http.StatusBadRequest)
} return
} }
}
if limitStr != "" {
if limitStr == "all" { if limitStr != "" {
noLimit = true if limitStr == "all" {
limit = 0 // 设置为0表示不使用LIMIT子句 noLimit = true
} else { limit = 0 // 设置为0表示不使用LIMIT子句
limit, err = strconv.Atoi(limitStr) } else {
if err != nil || limit <= 0 { limit, err = strconv.Atoi(limitStr)
log.Printf("错误: 无效的记录数限制: %s", limitStr) if err != nil || limit <= 0 {
http.Error(w, "无效的记录数限制", http.StatusBadRequest) log.Printf("错误: 无效的记录数限制: %s", limitStr)
return http.Error(w, "无效的记录数限制", http.StatusBadRequest)
} return
} }
} }
}
var startDate, endDate time.Time
if startDateStr != "" { var startDate, endDate time.Time
startDate, err = time.Parse("2006-01-02T15:04", startDateStr) if startDateStr != "" {
if err != nil { startDate, err = time.Parse("2006-01-02T15:04", startDateStr)
log.Printf("错误: 无效的开始日期: %s, %v", startDateStr, err) if err != nil {
http.Error(w, "无效的开始日期", http.StatusBadRequest) log.Printf("错误: 无效的开始日期: %s, %v", startDateStr, err)
return http.Error(w, "无效的开始日期", http.StatusBadRequest)
} return
} }
}
if endDateStr != "" {
endDate, err = time.Parse("2006-01-02T15:04", endDateStr) if endDateStr != "" {
if err != nil { endDate, err = time.Parse("2006-01-02T15:04", endDateStr)
log.Printf("错误: 无效的结束日期: %s, %v", endDateStr, err) if err != nil {
http.Error(w, "无效的结束日期", http.StatusBadRequest) log.Printf("错误: 无效的结束日期: %s, %v", endDateStr, err)
return http.Error(w, "无效的结束日期", http.StatusBadRequest)
} return
} }
}
var data []SensorData
if sensorIDStr == "all" || sensorIDStr == "" { var data []SensorData
data, err = GetAllSensorData(limit, startDate, endDate) if sensorIDStr == "all" || sensorIDStr == "" {
} else { data, err = GetAllSensorData(limit, startDate, endDate)
data, err = GetSensorData(sensorID, limit, startDate, endDate) } else {
} data, err = GetSensorData(sensorID, limit, startDate, endDate)
}
if err != nil {
log.Printf("错误: 获取数据失败: %v", err) if err != nil {
http.Error(w, "获取数据失败:"+err.Error(), http.StatusInternalServerError) log.Printf("错误: 获取数据失败: %v", err)
return http.Error(w, "获取数据失败:"+err.Error(), http.StatusInternalServerError)
} return
}
if noLimit {
log.Printf("成功获取到所有数据记录(%d条", len(data)) if noLimit {
} else { log.Printf("成功获取到所有数据记录(%d条", len(data))
log.Printf("成功获取到 %d 条数据记录(限制:%d条", len(data), limit) } else {
} log.Printf("成功获取到 %d 条数据记录(限制:%d条", len(data), limit)
}
if err := json.NewEncoder(w).Encode(data); err != nil {
log.Printf("错误: 编码JSON失败: %v", err) if err := json.NewEncoder(w).Encode(data); err != nil {
http.Error(w, "编码JSON失败"+err.Error(), http.StatusInternalServerError) log.Printf("错误: 编码JSON失败: %v", err)
} http.Error(w, "编码JSON失败"+err.Error(), http.StatusInternalServerError)
} }
}
// 处理获取所有传感器ID的API
func handleGetSensors(w http.ResponseWriter, r *http.Request) { // 处理获取所有传感器ID的API
log.Printf("接收到获取传感器列表请求") func handleGetSensors(w http.ResponseWriter, r *http.Request) {
log.Printf("接收到获取传感器列表请求")
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Content-Type", "application/json")
sensorIDs, err := GetAllSensorIDs()
if err != nil { sensorIDs, err := GetAllSensorIDs()
log.Printf("错误: 获取传感器ID失败: %v", err) if err != nil {
http.Error(w, "获取传感器ID失败"+err.Error(), http.StatusInternalServerError) log.Printf("错误: 获取传感器ID失败: %v", err)
return http.Error(w, "获取传感器ID失败"+err.Error(), http.StatusInternalServerError)
} return
}
log.Printf("成功获取到 %d 个传感器ID", len(sensorIDs))
log.Printf("成功获取到 %d 个传感器ID", len(sensorIDs))
if err := json.NewEncoder(w).Encode(sensorIDs); err != nil {
log.Printf("错误: 编码JSON失败: %v", err) if err := json.NewEncoder(w).Encode(sensorIDs); err != nil {
http.Error(w, "编码JSON失败"+err.Error(), http.StatusInternalServerError) log.Printf("错误: 编码JSON失败: %v", err)
} http.Error(w, "编码JSON失败"+err.Error(), http.StatusInternalServerError)
} }
func handleGetClients(w http.ResponseWriter, r *http.Request) { }
w.Header().Set("Content-Type", "application/json")
func handleGetClients(w http.ResponseWriter, r *http.Request) {
clients := getAllClients() w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(clients); err != nil { clients := getAllClients()
log.Printf("错误: 编码客户端信息JSON失败: %v", err)
http.Error(w, "编码JSON失败"+err.Error(), http.StatusInternalServerError) if err := json.NewEncoder(w).Encode(clients); err != nil {
} log.Printf("错误: 编码客户端信息JSON失败: %v", err)
} http.Error(w, "编码JSON失败"+err.Error(), http.StatusInternalServerError)
}
}
// 处理手动触发查询指令的API
func handleTriggerQuery(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if r.Method != "POST" {
http.Error(w, "只支持POST请求", http.StatusMethodNotAllowed)
return
}
// 触发向所有在线客户端发送查询指令
sent := triggerManualQuery()
response := map[string]interface{}{
"success": true,
"message": fmt.Sprintf("已向%d个客户端发送查询指令", sent),
"sent_count": sent,
}
if err := json.NewEncoder(w).Encode(response); err != nil {
log.Printf("错误: 编码响应JSON失败: %v", err)
http.Error(w, "编码JSON失败"+err.Error(), http.StatusInternalServerError)
}
}

View File

@ -22,6 +22,7 @@ type ClientInfo struct {
var ( var (
clientsMutex sync.Mutex clientsMutex sync.Mutex
clients = make(map[string]*ClientInfo) clients = make(map[string]*ClientInfo)
clientConns = make(map[string]net.Conn) // 存储客户端连接
) )
// StartTCPServer 启动TCP服务器 // StartTCPServer 启动TCP服务器
@ -55,6 +56,11 @@ func handleConnection(conn net.Conn) {
addClient(remoteAddr) addClient(remoteAddr)
// 存储连接以便手动查询使用
clientsMutex.Lock()
clientConns[remoteAddr] = conn
clientsMutex.Unlock()
// 启动定时发送指令的goroutine // 启动定时发送指令的goroutine
go sendPeriodicCommand(conn, remoteAddr) go sendPeriodicCommand(conn, remoteAddr)
@ -69,6 +75,10 @@ func handleConnection(conn net.Conn) {
Logger.Printf("客户端断开连接 %s", remoteAddr) Logger.Printf("客户端断开连接 %s", remoteAddr)
} }
removeClient(remoteAddr) removeClient(remoteAddr)
// 清理连接映射
clientsMutex.Lock()
delete(clientConns, remoteAddr)
clientsMutex.Unlock()
break break
} }
@ -92,6 +102,10 @@ func handleConnection(conn net.Conn) {
if _, err := conn.Write([]byte(resp)); err != nil { if _, err := conn.Write([]byte(resp)); err != nil {
Logger.Printf("发送响应到客户端 %s 失败: %v", remoteAddr, err) Logger.Printf("发送响应到客户端 %s 失败: %v", remoteAddr, err)
removeClient(remoteAddr) removeClient(remoteAddr)
// 清理连接映射
clientsMutex.Lock()
delete(clientConns, remoteAddr)
clientsMutex.Unlock()
break break
} }
@ -282,6 +296,7 @@ func startClientCleanup() {
for addr, client := range clients { for addr, client := range clients {
if now.Sub(client.LastSeen) > 24*time.Hour { if now.Sub(client.LastSeen) > 24*time.Hour {
delete(clients, addr) delete(clients, addr)
delete(clientConns, addr) // 同时清理连接
Logger.Printf("移除过期客户端: %s", addr) Logger.Printf("移除过期客户端: %s", addr)
} }
} }
@ -290,3 +305,31 @@ func startClientCleanup() {
} }
}() }()
} }
// triggerManualQuery 手动触发向所有在线客户端发送查询指令
func triggerManualQuery() int {
clientsMutex.Lock()
defer clientsMutex.Unlock()
sentCount := 0
command := "@1602301014A*0!\n"
for addr, client := range clients {
// 检查客户端是否在线最近10分钟内活跃
if time.Since(client.LastSeen) < 10*time.Minute {
if conn, exists := clientConns[addr]; exists {
if _, err := conn.Write([]byte(command)); err != nil {
Logger.Printf("手动发送查询指令到客户端 %s 失败: %v", addr, err)
// 连接可能已断开,从映射中移除
delete(clientConns, addr)
} else {
TCPDataLogger.Printf("手动发送查询指令到客户端 %s: %s", addr, strings.TrimSpace(command))
sentCount++
}
}
}
}
Logger.Printf("手动查询指令已发送到 %d 个客户端", sentCount)
return sentCount
}

View File

@ -275,6 +275,9 @@
// 检查连接状态 // 检查连接状态
checkConnectionStatus(); checkConnectionStatus();
connectionCheckTimer = setInterval(checkConnectionStatus, 30000); // 每30秒检查一次 connectionCheckTimer = setInterval(checkConnectionStatus, 30000); // 每30秒检查一次
// 显示数据库中的最新数据不发送TCP查询指令
fetchLatestData();
}); });
// 初始化日期选择器 // 初始化日期选择器
@ -784,13 +787,35 @@
// 先获取一次当前最新数据 // 先获取一次当前最新数据
fetchLatestData(); fetchLatestData();
// 触发TCP服务器发送查询指令等待3秒后再次获取最新数据 // 发送TCP查询指令
setTimeout(() => { fetch('/api/trigger-query', {
fetchLatestData(); method: 'POST',
loadData(); // 也刷新一下表格数据 headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
console.log(`查询指令已发送到 ${data.sent_count} 个设备`);
// 等待3秒后获取最新数据给设备响应时间
setTimeout(() => {
fetchLatestData();
loadData(); // 也刷新一下表格数据
latestDataElement.style.opacity = 1;
document.getElementById('queryLatestBtn').textContent = '查询最新数据';
}, 3000);
} else {
console.error('发送查询指令失败:', data.message);
latestDataElement.style.opacity = 1;
document.getElementById('queryLatestBtn').textContent = '查询最新数据';
}
})
.catch(error => {
console.error('发送查询指令出错:', error);
latestDataElement.style.opacity = 1; latestDataElement.style.opacity = 1;
document.getElementById('queryLatestBtn').textContent = '查询最新数据'; document.getElementById('queryLatestBtn').textContent = '查询最新数据';
}, 3000); });
} }
// 页面卸载时清除定时器 // 页面卸载时清除定时器