package crontab import ( "kpt-pasture/model" "kpt-pasture/util" "math" pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow" "gitee.com/xuyiping_admin/pkg/logger/zaplog" "go.uber.org/zap" ) // HealthWarning 健康预警 create_jbq_update_2024 func (e *Entry) HealthWarning(pastureId int64, processIds []int64) { healthWarningList := make([]*model.NeckRingHealth, 0) sqlQuery := `SELECT aa.pasture_id,aa.cow_id,aa.ear_number,aa.neck_ring_number,aa.lact,aa.calving_age,aa.heat_date,aa.frameid,aa.active_time, aa.change_filter,aa.chew_filter,aa.sum_chew,aa.sum_inactive,aa.before_three_sum_chew,aa.min_high,aa.max_high,aa.min_chew,aa.score FROM ( SELECT h.id,h.cow_id,h.pasture_id,h.ear_number,h.neck_ring_number,h.calving_age,h.heat_date,h.frameid,h.lact, IF(h.change_filter>-99, h.change_filter, 0) AS change_filter, IF(h.filter_chew>-99, h.filter_chew, 0) AS chew_filter, (h.sum_rumina +h.sum_intake) AS sum_chew, h.sum_inactive, (h.before_three_sum_rumina +h.before_three_sum_intake) AS before_three_sum_chew, IF(h.sum_min_high>-99, h.sum_min_high, 0) AS min_high, IF(h.sum_max_high>-99, h.sum_max_high, 0) AS max_high, IF(h.sum_min_chew>-99, h.sum_min_chew, 0) AS min_chew, h.score,h.active_time, IF(h.cow_id=@cow AND h.heat_date=@date AND h.score>=@score, 0, 1) is_worse, @cow:=h.cow_id, @date:=h.heat_date, @score:=h.score FROM neck_active_habit h, (SELECT @cow:=0, @date:='2001-01-01', @score:=100) aaa WHERE h.id IN ? AND h.score BETWEEN ? AND ? AND h.pasture_id = ? ) aa WHERE aa.is_worse = ? ORDER BY aa.id;` if err := e.DB.Raw(sqlQuery, processIds, model.MinScore, model.MaxScore, pastureId, pasturePb.IsShow_Ok). Find(&healthWarningList).Error; err != nil { zaplog.Error("HealthWarning", zap.Any("error", err), zap.Any("processIds", processIds)) } 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 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 }