package crontab import ( "kpt-pasture/model" "kpt-pasture/util" "math" "time" pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow" "gitee.com/xuyiping_admin/pkg/xerr" "gitee.com/xuyiping_admin/pkg/logger/zaplog" "go.uber.org/zap" ) // HealthWarning 健康预警 create_jbq_update_2024 func (e *Entry) HealthWarning(pastureId int64, processIds []int64) { newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0) if err := e.DB.Model(new(model.NeckActiveHabit)). Where("pasture_id = ?", pastureId). Where("id IN (?)", processIds). Where("score BETWEEN ? AND ?", model.MinScore, model.MaxScore). Order("neck_ring_number,heat_date,frameid"). Find(&newNeckActiveHabitList).Error; err != nil { zaplog.Error("HealthWarning", zap.Any("error", err), zap.Any("processIds", processIds)) } var ( lastCowID int64 = 0 lastHeatDate string = "2001-01-01" lastScore int32 = 100 healthWarningList []*model.NeckRingHealth ) for _, habit := range newNeckActiveHabitList { if habit.ChangeFilter <= -99 { habit.ChangeFilter = 0 } if habit.ChewFilter <= -99 { habit.ChewFilter = 0 } if habit.SumMinHigh <= -99 { habit.SumMinHigh = 0 } if habit.SumMaxHigh <= -99 { habit.SumMaxHigh = 0 } if habit.SumMinChew <= -99 { habit.SumMinChew = 0 } sumChew := habit.SumRumina + habit.SumIntake chew3dago := habit.BeforeThreeSumRumina + habit.BeforeThreeSumIntake isWorse := 1 if habit.CowId == lastCowID && habit.HeatDate == lastHeatDate && habit.Score >= lastScore { isWorse = 0 } lastCowID = habit.CowId lastHeatDate = habit.HeatDate lastScore = habit.Score if isWorse == 1 { newHealthWarning := model.NewNeckRingHealth(habit, sumChew, chew3dago) healthWarningList = append(healthWarningList, newHealthWarning) } } if len(healthWarningList) > 0 { e.updateNeckRingHealth(pastureId, healthWarningList) } } func (e *Entry) updateNeckRingHealth(pastureId int64, healthWarningList []*model.NeckRingHealth) { for _, v := range healthWarningList { startAt := util.TimeParseLocalUnix(v.HeatDate) endAt := util.TimeParseLocalEndUnix(v.HeatDate) isMove := e.isEventCowLog(pastureId, v.CowId, startAt, endAt, pasturePb.EventType_Transfer_Ben) if isMove { v.IsTransferGroup = pasturePb.IsShow_Ok } isDryMilk := e.isEventCowLog(pastureId, v.CowId, startAt, endAt, pasturePb.EventType_Dry_Milk) if isDryMilk { v.IsDryMilk = pasturePb.IsShow_Ok } isImmunization := e.isEventCowLog(pastureId, v.CowId, startAt, endAt, pasturePb.EventType_Immunication) if isImmunization { v.IsImmunization = pasturePb.IsShow_Ok } } zaplog.Info("HealthWarning", zap.Any("healthWarningList", healthWarningList)) if err := e.DB.Model(new(model.NeckRingHealth)).Create(&healthWarningList).Error; err != nil { zaplog.Error("HealthWarning", zap.Any("error", err), zap.Any("healthWarningList", healthWarningList)) } } func (e *Entry) isEventCowLog(pastureId int64, CowId int64, startAt, endAt int64, eventType pasturePb.EventType_Kind) bool { var count int64 eventCowLog := &model.EventCowLog{CowId: CowId} if err := e.DB.Table(eventCowLog.TableName()). Where("pasture_id = ?", pastureId). Where("cow_id = ?", CowId). Where("event_at BETWEEN ? AND ?", startAt, endAt). Where("event_type = ?", eventType). Count(&count).Error; err != nil { return false } return count > 0 } func (e *Entry) NeckRingHealthWarning() error { pastureList := e.FindPastureList() if pastureList == nil || len(pastureList) == 0 { return nil } for _, pasture := range pastureList { e.DB.Model(new(model.NeckRingHealthWarning)). Where("pasture_id = ?", pasture.Id). Delete(new(model.NeckRingHealthWarning)) if err := e.UpdateNeckRingHealth(pasture.Id); err != nil { zaplog.Error("NeckRingHealthWarning", zap.Any("UpdateNeckRingHealth", err), zap.Any("pasture", pasture), ) } } return nil } func (e *Entry) UpdateNeckRingHealth(pastureId int64) error { neckRingConfigureList, err := e.FindSystemNeckRingConfigure(pastureId) if err != nil { return xerr.WithStack(err) } healthValue := int32(0) for _, v := range neckRingConfigureList { if v.Name != model.HealthWarning { continue } healthValue = int32(v.Value) } newNeckRingHealthWarningList, err := e.FindNewNeckRingHealthWarning(pastureId, healthValue) if err != nil { return xerr.WithStack(err) } if len(newNeckRingHealthWarningList) > 0 { if err = e.DB.Model(new(model.NeckRingHealthWarning)). Create(&newNeckRingHealthWarningList).Error; err != nil { zaplog.Error("UpdateNeckRingHealth", zap.Any("error", err), zap.Any("newNeckRingHealthWarningList", newNeckRingHealthWarningList), ) } } return nil } func calculateNewScore(data *model.NeckRingHealth) int32 { otherScore := int32(0) otherScore += calculateMilkFilterScore(data.FilterMilk, data.MaxHigh) if data.IsTransferGroup == pasturePb.IsShow_Ok { otherScore += 3 } if data.IsDryMilk == pasturePb.IsShow_Ok { otherScore += 5 } if data.IsImmunization == pasturePb.IsShow_Ok { otherScore += 12 } return data.Score + otherScore } func calculateMilkFilterScore(milkFilter int32, maxHigh int32) int32 { // 处理NULL值,默认为0 milkFilterValue := int32(0) if milkFilter != 0 { milkFilterValue = milkFilter } // 计算系数:如果maxHigh>50则为0.5,否则为1 coefficient := 1.0 if maxHigh > 50 { coefficient = 0.5 } // 计算中间值:milkFilterValue * 0.3 * coefficient intermediateValue := float64(milkFilterValue) * 0.3 * coefficient // 四舍五入 roundedValue := math.Round(intermediateValue) // 取最小值(roundedValue和0中的较小值) result := int32(math.Min(roundedValue, 0)) return result } func (e *Entry) FindNewNeckRingHealthWarning(pastureId int64, healthValue int32) ([]*model.NeckRingHealthWarning, error) { nowTime := time.Now().Local() //endTime := nowTime.Format(model.LayoutDate2) startTime := nowTime.AddDate(0, 0, -1).Format(model.LayoutDate2) neckRingHealthList := make([]*model.NeckRingHealth, 0) if err := e.DB.Model(new(model.NeckRingHealth)). Select(`MAX(id) AS id,heat_date,neck_ring_number,cow_id,score,max_high,created_at,min_high,min_chew, min_intake,sum_chew,before_three_sum_chew`). Where("pasture_id = ?", pastureId). Where("heat_date >= ?", startTime). Group("neck_ring_number"). Find(&neckRingHealthList).Error; err != nil { return nil, xerr.WithStack(err) } newNeckRingHealthWarningList := make([]*model.NeckRingHealthWarning, 0) for _, v := range neckRingHealthList { if v.HeatDate == "" { continue } cowInfo, err := e.GetCowById(pastureId, v.CowId) if err != nil || cowInfo == nil { continue } newScore := calculateNewScore(v) zaplog.Info("calculateNewScore", zap.Any("newScore", newScore), zap.Any("v", v), zap.Any("healthValue", healthValue), zap.Any("cowInfo", cowInfo), ) if newScore > healthValue { continue } if e.HistoryNeckRingHealthWarning(pastureId, cowInfo.NeckRingNumber, v.HeatDate) { continue } if e.FindNeckRingError(pastureId, cowInfo.NeckRingNumber) { continue } newNeckRingHealthWarning := model.NewNeckRingHealthWarning(pastureId, v, cowInfo, newScore) zaplog.Info("newNeckRingHealthWarning", zap.Any("newNeckRingHealthWarning", newNeckRingHealthWarning), zap.Any("pastureId", pastureId), zap.Any("neckRingHealth", v), zap.Any("cowInfo", cowInfo), zap.Any("newScore", newScore), ) newNeckRingHealthWarningList = append(newNeckRingHealthWarningList, newNeckRingHealthWarning) } return newNeckRingHealthWarningList, nil } func (e *Entry) HistoryNeckRingHealthWarning(pastureId int64, neckRingNumber string, heatDate string) bool { var count int64 if err := e.DB.Model(new(model.NeckRingHealthWarning)). Where("pasture_id = ?", pastureId). Where("neck_ring_number = ?", neckRingNumber). Where("heat_date = ?", heatDate). Where("is_show = ?", pasturePb.IsShow_Ok). Count(&count).Error; err != nil { return false } return count > 0 } func (e *Entry) FindNeckRingError(pastureId int64, neckRingNumber string) bool { var count int64 if err := e.DB.Model(new(model.NeckRing)). Where("pasture_id = ?", pastureId). Where("neck_ring_number = ?", neckRingNumber). Where("status = ?", pasturePb.IsShow_No). Where("error_kind = ?", pasturePb.NeckRingNumberError_Suspected_Fall_Off). Count(&count).Error; err != nil { return false } return count > 0 }