package controller import ( "encoding/json" "net/http" "strconv" "time" "ezops/model" "github.com/gin-gonic/gin" ) // 告警静默规则 CRUD(AlertHandler 方法接收者) // Logan.Li // CreateSilenceRequest 创建静默规则请求 type CreateSilenceRequest struct { Name string `json:"name" binding:"required"` Description string `json:"description"` RuleIDs []uint `json:"rule_ids"` TargetIDs []uint `json:"target_ids"` Matchers []model.AlertSilenceMatcher `json:"matchers"` SilenceType string `json:"silence_type"` StartTime string `json:"start_time"` EndTime string `json:"end_time" binding:"required"` Weekdays []int `json:"weekdays"` Status *int `json:"status"` } // UpdateSilenceRequest 更新静默规则请求 type UpdateSilenceRequest struct { Name string `json:"name"` Description string `json:"description"` RuleIDs []uint `json:"rule_ids"` TargetIDs []uint `json:"target_ids"` Matchers []model.AlertSilenceMatcher `json:"matchers"` SilenceType string `json:"silence_type"` StartTime string `json:"start_time"` EndTime string `json:"end_time"` Weekdays []int `json:"weekdays"` Status *int `json:"status"` } // ListSilences GET /alerts/silences func (h *AlertHandler) ListSilences(c *gin.Context) { var silences []model.AlertSilence query := h.db.Order("created_at DESC") if status := c.Query("status"); status != "" { if status == "active" { now := time.Now() query = query.Where("status = ? AND start_time <= ? AND end_time >= ?", 1, now, now) } else if s, err := strconv.Atoi(status); err == nil { query = query.Where("status = ?", s) } } query.Find(&silences) // 解析 JSON 字段为前端友好的格式 type SilenceWithParsed struct { model.AlertSilence RuleIDList []uint `json:"rule_id_list"` TargetIDList []uint `json:"target_id_list"` MatcherList []model.AlertSilenceMatcher `json:"matcher_list"` WeekdayList []int `json:"weekday_list"` IsActive bool `json:"is_active"` } var result []SilenceWithParsed now := time.Now() for _, s := range silences { item := SilenceWithParsed{AlertSilence: s} if s.RuleIDs != "" { json.Unmarshal([]byte(s.RuleIDs), &item.RuleIDList) } if s.TargetIDs != "" { json.Unmarshal([]byte(s.TargetIDs), &item.TargetIDList) } if s.Matchers != "" { json.Unmarshal([]byte(s.Matchers), &item.MatcherList) } if s.Weekdays != "" { json.Unmarshal([]byte(s.Weekdays), &item.WeekdayList) } item.IsActive = s.Status == 1 && now.After(s.StartTime) && now.Before(s.EndTime) result = append(result, item) } c.JSON(http.StatusOK, model.Response{ Code: 200, Message: "success", Data: model.ListResponse{List: result, Total: int64(len(result))}, }) } // CreateSilence POST /alerts/silences func (h *AlertHandler) CreateSilence(c *gin.Context) { var req CreateSilenceRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "请求参数错误: " + err.Error()}) return } silenceType := model.AlertSilenceOneTime if req.SilenceType != "" { silenceType = model.AlertSilenceType(req.SilenceType) } // 解析时间 var startTime, endTime time.Time var err error if req.StartTime != "" { startTime, err = time.Parse(time.RFC3339, req.StartTime) if err != nil { startTime, err = time.ParseInLocation("2006-01-02 15:04:05", req.StartTime, time.Local) if err != nil { startTime = time.Now() } } } else { startTime = time.Now() } endTime, err = time.Parse(time.RFC3339, req.EndTime) if err != nil { endTime, err = time.ParseInLocation("2006-01-02 15:04:05", req.EndTime, time.Local) if err != nil { c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "结束时间格式错误"}) return } } ruleIDsJSON, _ := json.Marshal(req.RuleIDs) targetIDsJSON, _ := json.Marshal(req.TargetIDs) matchersJSON, _ := json.Marshal(req.Matchers) weekdaysJSON, _ := json.Marshal(req.Weekdays) silence := model.AlertSilence{ Name: req.Name, Description: req.Description, RuleIDs: string(ruleIDsJSON), TargetIDs: string(targetIDsJSON), Matchers: string(matchersJSON), SilenceType: silenceType, StartTime: startTime, EndTime: endTime, Weekdays: string(weekdaysJSON), Status: 1, } // 获取创建人 ID if userID, exists := c.Get("userID"); exists { if uid, ok := userID.(uint); ok { silence.CreatedBy = uid } } if err := h.db.Create(&silence).Error; err != nil { c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "创建失败: " + err.Error()}) return } c.JSON(http.StatusOK, model.Response{Code: 200, Message: "创建成功", Data: silence}) } // UpdateSilence PUT /alerts/silences/:id func (h *AlertHandler) UpdateSilence(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var req UpdateSilenceRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: "请求参数错误"}) return } var silence model.AlertSilence if err := h.db.First(&silence, id).Error; err != nil { c.JSON(http.StatusNotFound, model.Response{Code: 404, Message: "静默规则不存在"}) return } updates := map[string]interface{}{} if req.Name != "" { updates["name"] = req.Name } if req.Description != "" { updates["description"] = req.Description } if req.SilenceType != "" { updates["silence_type"] = req.SilenceType } if len(req.RuleIDs) > 0 || req.RuleIDs != nil { ruleIDsJSON, _ := json.Marshal(req.RuleIDs) updates["rule_ids"] = string(ruleIDsJSON) } if len(req.TargetIDs) > 0 || req.TargetIDs != nil { targetIDsJSON, _ := json.Marshal(req.TargetIDs) updates["target_ids"] = string(targetIDsJSON) } if len(req.Matchers) > 0 || req.Matchers != nil { matchersJSON, _ := json.Marshal(req.Matchers) updates["matchers"] = string(matchersJSON) } if len(req.Weekdays) > 0 || req.Weekdays != nil { weekdaysJSON, _ := json.Marshal(req.Weekdays) updates["weekdays"] = string(weekdaysJSON) } if req.StartTime != "" { if st, err := time.Parse(time.RFC3339, req.StartTime); err == nil { updates["start_time"] = st } else if st, err := time.ParseInLocation("2006-01-02 15:04:05", req.StartTime, time.Local); err == nil { updates["start_time"] = st } } if req.EndTime != "" { if et, err := time.Parse(time.RFC3339, req.EndTime); err == nil { updates["end_time"] = et } else if et, err := time.ParseInLocation("2006-01-02 15:04:05", req.EndTime, time.Local); err == nil { updates["end_time"] = et } } if req.Status != nil { updates["status"] = *req.Status } h.db.Model(&silence).Updates(updates) h.db.First(&silence, id) c.JSON(http.StatusOK, model.Response{Code: 200, Message: "更新成功", Data: silence}) } // DeleteSilence DELETE /alerts/silences/:id func (h *AlertHandler) DeleteSilence(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) if err := h.db.Delete(&model.AlertSilence{}, id).Error; err != nil { c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: "删除失败"}) return } c.JSON(http.StatusOK, model.Response{Code: 200, Message: "删除成功"}) } // ToggleSilence POST /alerts/silences/:id/toggle func (h *AlertHandler) ToggleSilence(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var silence model.AlertSilence if err := h.db.First(&silence, id).Error; err != nil { c.JSON(http.StatusNotFound, model.Response{Code: 404, Message: "静默规则不存在"}) return } newStatus := 0 if silence.Status == 0 { newStatus = 1 } h.db.Model(&silence).Update("status", newStatus) h.db.First(&silence, id) c.JSON(http.StatusOK, model.Response{Code: 200, Message: "切换成功", Data: silence}) }