package logic import ( "context" "errors" "time" "bj_power_mes/ent" "bj_power_mes/ent/alert" "bj_power_mes/ent/alertrule" ) // CreateAlertRule 新增预警规则 func (s *Service) CreateAlertRule(ctx context.Context, name, typ string, threshold float64, receiver string, enabled bool, createdBy string) error { if name == "" || typ == "" { return errors.New("规则名称与类型必填") } _, err := s.ctx.EntClient.AlertRule.Create(). SetName(name).SetType(typ).SetThreshold(threshold). SetReceiver(receiver).SetEnabled(enabled).SetCreatedBy(createdBy).Save(ctx) return err } // UpdateAlertRule 修改预警规则 func (s *Service) UpdateAlertRule(ctx context.Context, id int, name, typ string, threshold float64, receiver string, enabled bool) error { if id <= 0 { return errors.New("规则ID无效") } if name == "" || typ == "" { return errors.New("规则名称与类型必填") } _, err := s.ctx.EntClient.AlertRule.UpdateOneID(id). SetName(name).SetType(typ).SetThreshold(threshold). SetReceiver(receiver).SetEnabled(enabled).Save(ctx) return err } // DeleteAlertRule 删除预警规则 func (s *Service) DeleteAlertRule(ctx context.Context, id int) error { if id <= 0 { return errors.New("规则ID无效") } return s.ctx.EntClient.AlertRule.DeleteOneID(id).Exec(ctx) } // ListAlertRules 查询全部预警规则 func (s *Service) ListAlertRules(ctx context.Context) ([]*ent.AlertRule, error) { return s.ctx.EntClient.AlertRule.Query(). Order(ent.Desc(alertrule.FieldCreatedAt), ent.Desc(alertrule.FieldID)).All(ctx) } // AlertQuery 预警查询条件:status/type 空=不限;from/to 为 YYYY-MM-DD(空=不限);page<=0 表示不分页。 type AlertQuery struct { Status string Type string From string To string OrderNo string // 工单号(模糊,客户第12条:记录查看加一项看工单号查询) Page int PageSize int } // ListAlerts 查询预警消息(支持状态/类型/时间范围筛选 + 分页),返回当前页数据与命中总数 func (s *Service) ListAlerts(ctx context.Context, q AlertQuery) ([]*ent.Alert, int, error) { query := s.ctx.EntClient.Alert.Query() if q.Status != "" { query = query.Where(alert.Status(q.Status)) } if q.Type != "" { query = query.Where(alert.Type(q.Type)) } if q.From != "" { if f, err := time.Parse("2006-01-02", q.From); err == nil { query = query.Where(alert.CreatedAtGTE(f)) } } if q.To != "" { if t, err := time.Parse("2006-01-02", q.To); err == nil { query = query.Where(alert.CreatedAtLT(t.Add(24 * time.Hour))) } } if q.OrderNo != "" { query = query.Where(alert.OrderNoContainsFold(q.OrderNo)) } total, err := query.Count(ctx) if err != nil { return nil, 0, err } if q.Page > 0 { size := q.PageSize if size <= 0 { size = 20 } query = query.Offset((q.Page - 1) * size).Limit(size) } list, err := query.Order(ent.Desc(alert.FieldCreatedAt), ent.Desc(alert.FieldID)).All(ctx) return list, total, err } // UnreadAlertCount 未读预警数 func (s *Service) UnreadAlertCount(ctx context.Context) (int, error) { return s.ctx.EntClient.Alert.Query().Where(alert.Status("UNREAD")).Count(ctx) } // MarkAlertRead 标记预警已读 func (s *Service) MarkAlertRead(ctx context.Context, id int) error { if id <= 0 { return errors.New("预警ID无效") } _, err := s.ctx.EntClient.Alert.UpdateOneID(id).SetStatus("READ").Save(ctx) return err } // alertDirection 阈值比较方向:inventory_low 为 <=,其余为 >= func alertDirection(typ string) int { if typ == "inventory_low" { return -1 } return 1 } // Evaluate 预警规则评估:遍历启用且类型匹配的规则,命中阈值则写 alert 消息。 // 由业务事件触发(如拧紧不合格),也可手动调用。 // orderNo:关联工单号(可空),写入 alert.order_no 供预警中心按工单号检索。 func (s *Service) Evaluate(ctx context.Context, typ string, value float64, title, content, refType, refId, orderNo string) { rules, err := s.ctx.EntClient.AlertRule.Query(). Where(alertrule.Type(typ), alertrule.Enabled(true)).All(ctx) if err != nil || len(rules) == 0 { return } dir := alertDirection(typ) for _, r := range rules { hit := (dir == 1 && value >= r.Threshold) || (dir == -1 && value <= r.Threshold) if !hit { continue } _ = s.createAlert(ctx, r.ID, typ, title, content, refType, refId, orderNo, r.Receiver) } } func (s *Service) createAlert(ctx context.Context, ruleId int, typ, title, content, refType, refId, orderNo, receiver string) error { _, err := s.ctx.EntClient.Alert.Create(). SetRuleId(ruleId).SetType(typ).SetTitle(title). SetContent(content).SetRefType(refType).SetRefId(refId). SetOrderNo(orderNo). SetReceiver(receiver).SetStatus("UNREAD").Save(ctx) return err }