package admin import ( "github.com/gofiber/fiber/v2" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/model/dto" "github.com/break/junhong_cmp_fiber/internal/service/polling" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/response" ) // PollingAlertHandler 轮询告警处理器 type PollingAlertHandler struct { service *polling.AlertService } // NewPollingAlertHandler 创建轮询告警处理器 func NewPollingAlertHandler(service *polling.AlertService) *PollingAlertHandler { return &PollingAlertHandler{service: service} } // CreateRule 创建告警规则 // @Summary 创建轮询告警规则 // @Description 创建新的轮询告警规则 // @Tags 轮询管理-告警 // @Accept json // @Produce json // @Security BearerAuth // @Param request body dto.CreatePollingAlertRuleReq true "创建请求" // @Success 200 {object} response.Response{data=dto.PollingAlertRuleResp} // @Router /api/admin/polling-alert-rules [post] func (h *PollingAlertHandler) CreateRule(c *fiber.Ctx) error { ctx := c.UserContext() var req dto.CreatePollingAlertRuleReq if err := c.BodyParser(&req); err != nil { return errors.New(errors.CodeInvalidParam) } rule := &model.PollingAlertRule{ RuleName: req.RuleName, TaskType: req.TaskType, MetricType: req.MetricType, Operator: req.Operator, Threshold: req.Threshold, AlertLevel: req.AlertLevel, CooldownMinutes: req.CooldownMinutes, NotificationChannels: req.NotifyChannels, } if err := h.service.CreateRule(ctx, rule); err != nil { return err } return response.Success(c, h.toRuleResp(rule)) } // ListRules 获取告警规则列表 // @Summary 获取轮询告警规则列表 // @Description 获取所有轮询告警规则 // @Tags 轮询管理-告警 // @Accept json // @Produce json // @Security BearerAuth // @Success 200 {object} response.Response{data=dto.PollingAlertRuleListResp} // @Router /api/admin/polling-alert-rules [get] func (h *PollingAlertHandler) ListRules(c *fiber.Ctx) error { ctx := c.UserContext() rules, err := h.service.ListRules(ctx) if err != nil { return err } items := make([]*dto.PollingAlertRuleResp, 0, len(rules)) for _, rule := range rules { items = append(items, h.toRuleResp(rule)) } return response.Success(c, &dto.PollingAlertRuleListResp{Items: items}) } // GetRule 获取告警规则详情 // @Summary 获取轮询告警规则详情 // @Description 获取指定轮询告警规则的详细信息 // @Tags 轮询管理-告警 // @Accept json // @Produce json // @Security BearerAuth // @Param id path int true "规则ID" // @Success 200 {object} response.Response{data=dto.PollingAlertRuleResp} // @Router /api/admin/polling-alert-rules/{id} [get] func (h *PollingAlertHandler) GetRule(c *fiber.Ctx) error { ctx := c.UserContext() id, err := c.ParamsInt("id") if err != nil || id <= 0 { return errors.New(errors.CodeInvalidParam, "无效的规则ID") } rule, err := h.service.GetRule(ctx, uint(id)) if err != nil { return err } return response.Success(c, h.toRuleResp(rule)) } // UpdateRule 更新告警规则 // @Summary 更新轮询告警规则 // @Description 更新指定轮询告警规则 // @Tags 轮询管理-告警 // @Accept json // @Produce json // @Security BearerAuth // @Param id path int true "规则ID" // @Param request body dto.UpdatePollingAlertRuleReq true "更新请求" // @Success 200 {object} response.Response // @Router /api/admin/polling-alert-rules/{id} [put] func (h *PollingAlertHandler) UpdateRule(c *fiber.Ctx) error { ctx := c.UserContext() id, err := c.ParamsInt("id") if err != nil || id <= 0 { return errors.New(errors.CodeInvalidParam, "无效的规则ID") } var req dto.UpdatePollingAlertRuleReq if err := c.BodyParser(&req); err != nil { return errors.New(errors.CodeInvalidParam) } updates := make(map[string]interface{}) if req.RuleName != nil { updates["rule_name"] = *req.RuleName } if req.Threshold != nil { updates["threshold"] = *req.Threshold } if req.AlertLevel != nil { updates["alert_level"] = *req.AlertLevel } if req.Status != nil { updates["status"] = *req.Status } if req.CooldownMinutes != nil { updates["cooldown_minutes"] = *req.CooldownMinutes } if req.NotifyChannels != nil { updates["notification_channels"] = *req.NotifyChannels } if err := h.service.UpdateRule(ctx, uint(id), updates); err != nil { return err } return response.Success(c, nil) } // DeleteRule 删除告警规则 // @Summary 删除轮询告警规则 // @Description 删除指定轮询告警规则 // @Tags 轮询管理-告警 // @Accept json // @Produce json // @Security BearerAuth // @Param id path int true "规则ID" // @Success 200 {object} response.Response // @Router /api/admin/polling-alert-rules/{id} [delete] func (h *PollingAlertHandler) DeleteRule(c *fiber.Ctx) error { ctx := c.UserContext() id, err := c.ParamsInt("id") if err != nil || id <= 0 { return errors.New(errors.CodeInvalidParam, "无效的规则ID") } if err := h.service.DeleteRule(ctx, uint(id)); err != nil { return err } return response.Success(c, nil) } // ListHistory 获取告警历史 // @Summary 获取轮询告警历史 // @Description 获取轮询告警历史记录 // @Tags 轮询管理-告警 // @Accept json // @Produce json // @Security BearerAuth // @Param rule_id query int false "规则ID" // @Param page query int false "页码" // @Param page_size query int false "每页数量" // @Success 200 {object} response.Response{data=dto.PollingAlertHistoryListResp} // @Router /api/admin/polling-alert-history [get] func (h *PollingAlertHandler) ListHistory(c *fiber.Ctx) error { ctx := c.UserContext() var req dto.ListPollingAlertHistoryReq if err := c.QueryParser(&req); err != nil { return errors.New(errors.CodeInvalidParam) } if req.Page < 1 { req.Page = 1 } if req.PageSize < 1 || req.PageSize > 100 { req.PageSize = 20 } histories, total, err := h.service.ListHistory(ctx, req.Page, req.PageSize, req.RuleID) if err != nil { return err } items := make([]*dto.PollingAlertHistoryResp, 0, len(histories)) for _, h := range histories { items = append(items, &dto.PollingAlertHistoryResp{ ID: h.ID, RuleID: h.RuleID, RuleName: "", // 历史记录中没有规则名称,需要单独查询 TaskType: h.TaskType, MetricType: h.MetricType, AlertLevel: h.AlertLevel, Threshold: h.Threshold, CurrentValue: h.CurrentValue, Message: h.AlertMessage, CreatedAt: h.CreatedAt, }) } totalPages := int(total) / req.PageSize if int(total)%req.PageSize > 0 { totalPages++ } return response.Success(c, &dto.PollingAlertHistoryListResp{ Items: items, Total: total, Page: req.Page, PageSize: req.PageSize, TotalPages: totalPages, }) } func (h *PollingAlertHandler) toRuleResp(rule *model.PollingAlertRule) *dto.PollingAlertRuleResp { return &dto.PollingAlertRuleResp{ ID: rule.ID, RuleName: rule.RuleName, TaskType: rule.TaskType, TaskTypeName: h.getTaskTypeName(rule.TaskType), MetricType: rule.MetricType, MetricTypeName: h.getMetricTypeName(rule.MetricType), Operator: rule.Operator, Threshold: rule.Threshold, AlertLevel: rule.AlertLevel, Status: int(rule.Status), CooldownMinutes: rule.CooldownMinutes, NotifyChannels: rule.NotificationChannels, CreatedAt: rule.CreatedAt, UpdatedAt: rule.UpdatedAt, } } func (h *PollingAlertHandler) getTaskTypeName(taskType string) string { switch taskType { case constants.TaskTypePollingRealname: return "实名检查" case constants.TaskTypePollingCarddata: return "流量检查" case constants.TaskTypePollingPackage: return "套餐检查" default: return taskType } } func (h *PollingAlertHandler) getMetricTypeName(metricType string) string { switch metricType { case "queue_size": return "队列积压" case "success_rate": return "成功率" case "avg_duration": return "平均耗时" case "concurrency": return "并发数" default: return metricType } }