feat: ToNav-go v1.0.0 - 内部服务导航系统

功能:
- 前台导航: 分类Tab切换、实时搜索、健康状态指示、响应式适配
- 后台管理: 服务/分类CRUD、系统设置、登录认证(bcrypt)
- 健康检查: 定时检测(5min)、独立检查URL、三态指示(在线/离线/未检测)
- 云端备份: WebDAV上传/下载/恢复/删除、定时自动备份、本地备份管理

技术栈: Go + Gin + GORM + SQLite
This commit is contained in:
2026-02-14 05:09:23 +08:00
commit efaf787981
23 changed files with 2735 additions and 0 deletions

62
handlers/health.go Normal file
View File

@@ -0,0 +1,62 @@
package handlers
import (
"fmt"
"log"
"net/http"
"time"
"tonav-go/database"
"tonav-go/models"
)
// StartHealthCheck 启动异步健康检查Goroutine
func StartHealthCheck() {
go checkAllServices()
ticker := time.NewTicker(5 * time.Minute)
go func() {
for range ticker.C {
checkAllServices()
}
}()
}
func checkAllServices() {
var services []models.Service
database.DB.Find(&services)
client := http.Client{
Timeout: 10 * time.Second,
}
checked := 0
for _, s := range services {
// 未开启健康检查的,状态设为 unknown
if !s.HealthCheckEnabled {
if s.Status != "unknown" {
database.DB.Model(&s).Update("status", "unknown")
}
continue
}
// 开启了健康检查的,执行检测
checkURL := s.URL
if s.HealthCheckURL != "" {
checkURL = s.HealthCheckURL
}
resp, err := client.Get(checkURL)
status := "offline"
if err == nil && resp.StatusCode >= 200 && resp.StatusCode < 400 {
status = "online"
}
if resp != nil {
resp.Body.Close()
}
database.DB.Model(&s).Update("status", status)
checked++
}
log.Printf("[%s] 健康检查完成,共 %d 个服务,实际检测 %d 个", time.Now().Format("2006-01-02 15:04:05"), len(services), checked)
fmt.Printf("[%s] 健康检查完成\n", time.Now().Format("2006-01-02 15:04:05"))
}