package handlers import ( "ezops/internal/models" "net/http" "strconv" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // SiteHandler 站点拨测管理 handler // Logan.Li type SiteHandler struct { db *gorm.DB } // NewSiteHandler 创建站点拨测 handler func NewSiteHandler(db *gorm.DB) *SiteHandler { return &SiteHandler{db: db} } // ========== Site Task CRUD ========== // ListTasks 列出拨测任务 // GET /api/v1/site/tasks?page=1&page_size=20&type=&status= func (h *SiteHandler) ListTasks(c *gin.Context) { var tasks []models.SiteTask q := h.db.Model(&models.SiteTask{}) if t := c.Query("type"); t != "" { q = q.Where("type = ?", t) } if s := c.Query("status"); s != "" { q = q.Where("status = ?", s) } if kw := c.Query("keyword"); kw != "" { q = q.Where("name LIKE ? OR url LIKE ?", "%"+kw+"%", "%"+kw+"%") } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) var total int64 q.Count(&total) q.Offset((page - 1) * pageSize).Limit(pageSize).Order("name ASC").Find(&tasks) if tasks == nil { tasks = []models.SiteTask{} } c.JSON(http.StatusOK, models.Response{Code: 200, Data: gin.H{"list": tasks, "total": total}}) } // CreateTask 创建拨测任务 // POST /api/v1/site/tasks func (h *SiteHandler) CreateTask(c *gin.Context) { var task models.SiteTask if err := c.ShouldBindJSON(&task); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: err.Error()}) return } if err := h.db.Create(&task).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: err.Error()}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Data: task, Message: "创建成功"}) } // UpdateTask 更新拨测任务 // PUT /api/v1/site/tasks/:id func (h *SiteHandler) UpdateTask(c *gin.Context) { id := c.Param("id") var task models.SiteTask if err := h.db.First(&task, id).Error; err != nil { c.JSON(http.StatusNotFound, models.Response{Code: 404, Message: "任务不存在"}) return } if err := c.ShouldBindJSON(&task); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: err.Error()}) return } h.db.Save(&task) c.JSON(http.StatusOK, models.Response{Code: 200, Data: task, Message: "更新成功"}) } // DeleteTask 删除拨测任务 // DELETE /api/v1/site/tasks/:id func (h *SiteHandler) DeleteTask(c *gin.Context) { id := c.Param("id") if err := h.db.Delete(&models.SiteTask{}, id).Error; err != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: err.Error()}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Message: "删除成功"}) } // BatchDeleteTasks 批量删除 // DELETE /api/v1/site/tasks/batch-delete func (h *SiteHandler) BatchDeleteTasks(c *gin.Context) { var req models.IDsRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: err.Error()}) return } h.db.Where("id IN ?", req.IDs).Delete(&models.SiteTask{}) c.JSON(http.StatusOK, models.Response{Code: 200, Message: "批量删除成功"}) } // ========== Site Results ========== // ListResults 查询拨测结果 // GET /api/v1/site/results?task_id=N&from=&to=&limit=100 func (h *SiteHandler) ListResults(c *gin.Context) { var results []models.SiteResult q := h.db.Model(&models.SiteResult{}) if tid := c.Query("task_id"); tid != "" { q = q.Where("task_id = ?", tid) } if from := c.Query("from"); from != "" { q = q.Where("created_at >= ?", from) } if to := c.Query("to"); to != "" { q = q.Where("created_at <= ?", to) } limit, _ := strconv.Atoi(c.DefaultQuery("limit", "100")) q.Order("created_at DESC").Limit(limit).Find(&results) if results == nil { results = []models.SiteResult{} } c.JSON(http.StatusOK, models.Response{Code: 200, Data: results}) } // ========== Site Statistics ========== // GetSiteStats 获取拨测概览统计 // GET /api/v1/site/stats func (h *SiteHandler) GetSiteStats(c *gin.Context) { var total, normal, abnormal int64 h.db.Model(&models.SiteTask{}).Count(&total) h.db.Model(&models.SiteTask{}).Where("status = ?", "active").Count(&normal) h.db.Model(&models.SiteTask{}).Where("status = ?", "error").Count(&abnormal) // Calculate availability rate from recent results var availRate float64 if total > 0 { var successCount int64 h.db.Model(&models.SiteResult{}). Where("created_at > datetime('now', '-1 hour') AND status = 'success'"). Count(&successCount) var totalRecent int64 h.db.Model(&models.SiteResult{}). Where("created_at > datetime('now', '-1 hour')"). Count(&totalRecent) if totalRecent > 0 { availRate = float64(successCount) / float64(totalRecent) * 100 } } c.JSON(http.StatusOK, models.Response{Code: 200, Data: gin.H{ "total": total, "normal": normal, "abnormal": abnormal, "avail_rate": availRate, }}) }