package mqtt import ( "fmt" "kpt-pasture/model" "kpt-pasture/module/crontab" "math" "time" pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow" "gorm.io/gorm" "gitee.com/xuyiping_admin/pkg/logger/zaplog" "go.uber.org/zap" "gitee.com/xuyiping_admin/pkg/xerr" ) const ( MinChangeFilter = -99 MinRuminaFilter = -99 MinChewFilter = -99 MinChangeHigh = -99 DefaultNb = 30 DefaultScore = 100 ) func (e *Entry) PastureUpdateActiveHabit() { pastureList := e.FindPastureList() if pastureList == nil || len(pastureList) == 0 { return } for _, pasture := range pastureList { if err := e.EntryUpdateActiveHabit(pasture.Id); err != nil { zaplog.Error("PastureUpdateActiveHabit", zap.Any("PastureUpdateActiveHabit", err), zap.Any("pasture", pasture)) } zaplog.Info(fmt.Sprintf("PastureUpdateActiveHabit Success %d", pasture.Id)) } } func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) { lastMaxHabitData, err := e.GetSystemConfigure2(pastureId, model.MaxHabit) if err != nil { return xerr.WithStack(err) } lastMaxHabitId := lastMaxHabitData.Value currMaxHabit := &model.NeckActiveHabit{} if err = e.DB.Model(new(model.NeckActiveHabit)). Where("id > ?", lastMaxHabitId). Where("pasture_id = ?", pastureId). Where(e.DB.Where("record_count = ?", model.AvgHours).Or("is_show = ?", pasturePb.IsShow_Ok)). Order("id desc").First(currMaxHabit).Error; err != nil { return xerr.WithStack(err) } if currMaxHabit.Id <= 0 || currMaxHabit.Id <= lastMaxHabitId { return nil } defer func() { // 更新最后一次执行的id值 if err == nil { e.DB.Model(new(model.SystemConfigure)). Where("name = ?", model.MaxHabit). Where("pasture_id = ?", pastureId). Update("value", currMaxHabit.Id) } }() // 获取这段执行数据内最大日期和最小日期 xToday := &XToday{} activeLowest, err := e.GetSystemConfigure2(pastureId, model.ActiveLowest) if err != nil { return xerr.WithStack(err) } ruminaLowest, err := e.GetSystemConfigure2(pastureId, model.RuminaLowest) if err != nil { return xerr.WithStack(err) } xRuminaDisc, err := e.GetSystemConfigure2(pastureId, model.XRuminaDisc) if err != nil { return err } xChangeDiscount, err := e.GetSystemConfigure2(pastureId, model.XChangeDiscount) if err != nil { return err } xToday.ActiveLowest = int32(activeLowest.Value) xToday.RuminaLowest = int32(ruminaLowest.Value) xToday.XRuminaDisc = int32(xRuminaDisc.Value) xToday.XChangeDiscount = int32(xChangeDiscount.Value) xToday.LastMaxHabitId = lastMaxHabitId // 上次执行的id xToday.CurrMaxHabitId = currMaxHabit.Id // 本次执行的id // 更新活动滤波 if err = e.FirstFilterUpdate(pastureId, xToday); err != nil { zaplog.Error("EntryUpdateActiveHabit", zap.Any("FirstFilterUpdate", err), zap.Any("xToday", xToday)) } // 更新周平均值 if err = e.WeeklyActiveAvgUpdate(pastureId, xToday); err != nil { zaplog.Error("EntryUpdateActiveHabit", zap.Any("WeeklyActiveAvgUpdate", err), zap.Any("xToday", xToday)) } // 二次更新滤波 if err = e.SecondUpdateChangeFilter(pastureId, xToday); err != nil { zaplog.Error("EntryUpdateActiveHabit", zap.Any("SecondUpdateChangeFilter", err), zap.Any("xToday", xToday)) } // 活动量校正系数和健康评分 if err = e.FilterCorrectAndScoreUpdate(pastureId, xToday); err != nil { zaplog.Error("EntryUpdateActiveHabit", zap.Any("ActivityVolumeChanges", err), zap.Any("xToday", xToday)) } if err = e.DB.Model(new(model.NeckActiveHabit)). Where("pasture_id = ?", pastureId). Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId). Where("change_filter = ?", model.InitChangeFilter). Updates(map[string]interface{}{ "change_filter": model.DefaultChangeFilter, "rumina_filter": model.DefaultRuminaFilter, "chew_filter": model.DefaultChewFilter, }).Error; err != nil { zaplog.Error("EntryUpdateActiveHabit", zap.Any("change_filter", err), zap.Any("xToday", xToday)) } if err = e.DB.Model(new(model.NeckActiveHabit)). Where("pasture_id = ?", pastureId). Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId). Where("change_filter < ?", 0). Where("filter_correct < ?", model.DefaultFilterCorrect). Updates(map[string]interface{}{ "filter_correct": model.DefaultFilterCorrect, }).Error; err != nil { zaplog.Error("EntryUpdateActiveHabit", zap.Any("filter_correct", err), zap.Any("xToday", xToday)) } // 插入群体校正表 if err = e.UpdateChangeAdJust(pastureId, xToday); err != nil { zaplog.Error("EntryUpdateActiveHabit", zap.Any("UpdateChangeAdJust", err), zap.Any("xToday", xToday)) } return nil } // FirstFilterUpdate 首次更新活动滤波 func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) error { newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0) if err := e.DB.Model(new(model.NeckActiveHabit)). Where("id BETWEEN ? AND ?", xToDay.LastMaxHabitId, xToDay.CurrMaxHabitId). Where("pasture_id = ?", pastureId). Where("change_filter = ?", model.InitChangeFilter). Where(e.DB.Where("high >= ?", xToDay.ActiveLowest).Or("rumina >= ?", xToDay.RuminaLowest)). // 活动量过低牛只不参与计算 Order("neck_ring_number,heat_date,frameid"). Limit(int(defaultLimit)).Find(&newNeckActiveHabitList).Error; err != nil { return xerr.WithStack(err) } // 活动量滤波 for _, v := range newNeckActiveHabitList { firstFilterData := &FirstFilterData{} frameId := v.Frameid heatDate := v.HeatDate if v.Frameid == 0 { frameId = 11 heatDateParse, _ := time.Parse(model.LayoutDate2, heatDate) heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2) } if err := e.DB.Model(new(model.NeckActiveHabit)). Select("neck_ring_number", "filter_high", "filter_rumina", "filter_chew"). Where("neck_ring_number = ?", v.NeckRingNumber). Where("heat_date = ?", heatDate). Where("frameid = ?", frameId). First(&firstFilterData).Error; err != nil { zaplog.Error("EntryUpdateActiveHabit", zap.Any("FirstFilterUpdate", err)) } if v.FilterHigh > 0 { firstFilterData.FilterHigh = v.FilterHigh } else { if v.NeckRingNumber == firstFilterData.NeckRingNumber { firstFilterData.FilterHigh = int32(computeIfPositiveElse(float64(v.High), float64(firstFilterData.FilterHigh), 0.23, 0.77)) } else { firstFilterData.FilterHigh = v.High } } if v.FilterRumina > 0 { firstFilterData.FilterRumina = v.FilterRumina } else { if v.NeckRingNumber == firstFilterData.NeckRingNumber { firstFilterData.FilterRumina = int32(computeIfPositiveElse(float64(v.Rumina), float64(firstFilterData.FilterRumina), 0.33, 0.67)) } else { firstFilterData.FilterRumina = v.Rumina } } if v.FilterChew > 0 { firstFilterData.FilterChew = v.FilterChew } else { if v.NeckRingNumber == firstFilterData.NeckRingNumber { firstFilterData.FilterChew = int32(computeIfPositiveElse(float64(v.Rumina+v.Intake), float64(firstFilterData.FilterChew), 0.33, 0.67)) } else { firstFilterData.FilterChew = v.Rumina + v.Intake } } // 更新过滤值 if err := e.DB.Model(new(model.NeckActiveHabit)). Select("filter_high", "filter_rumina", "filter_chew"). Where("id = ?", v.Id). Updates(map[string]interface{}{ "filter_high": firstFilterData.FilterHigh, "filter_rumina": firstFilterData.FilterRumina, "filter_chew": firstFilterData.FilterChew, }).Error; err != nil { return xerr.WithStack(err) } } zaplog.Info("EntryUpdateActiveHabit-FilterUpdate-Success") return nil } // WeeklyActiveAvgUpdate 更新周平均值 func (e *Entry) WeeklyActiveAvgUpdate(pastureId int64, xToday *XToday) (err error) { weeklyActive, err := e.GetSystemConfigure2(pastureId, model.WeeklyActive) if err != nil { return xerr.WithStack(err) } if err = e.DB.Transaction(func(tx *gorm.DB) error { neckActiveHabitList := make([]*model.NeckActiveHabit, 0) if err = tx.Model(new(model.NeckActiveHabit)). Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId). Where("pasture_id = ?", pastureId). Where("change_filter = ?", model.InitChangeFilter). Where(e.DB.Where("high > ?", xToday.ActiveLowest).Or("rumina > ?", xToday.RuminaLowest)). Order("neck_ring_number,frameid"). Limit(int(defaultLimit)).Find(&neckActiveHabitList).Error; err != nil { return xerr.WithStack(err) } zaplog.Info("WeeklyActiveAvgUpdate-0", zap.Any("neckActiveHabitList", neckActiveHabitList)) for _, v := range neckActiveHabitList { beginDayDate, _ := time.Parse(model.LayoutDate2, v.HeatDate) before7DayDate := beginDayDate.AddDate(0, 0, -7).Format(model.LayoutDate2) before1DayDate := beginDayDate.AddDate(0, 0, -1).Format(model.LayoutDate2) weekHabitData := &crontab.WeekHabit{} if err = tx.Model(new(model.NeckActiveHabit)). Select("neck_ring_number"). Select("IF(COUNT(1)>=3, ROUND((SUM(filter_high) -MIN(filter_high) -MAX(filter_high))/ABS(COUNT(1) -2),0), -1) as avg_high_habit"). Select("IF(COUNT(1)>=3, ROUND((SUM(filter_rumina) -MIN(filter_rumina) -MAX(filter_rumina))/ABS(COUNT(1) -2),0), -1) as avg_rumina_habit"). Select("IF(COUNT(1)>=3, ROUND((SUM(filter_chew) -MIN(filter_chew) -MAX(filter_chew))/ABS(COUNT(1) -2),0), -1) as avg_chew_habit"). Select("ROUND(AVG(intake),0) as avg_intake_habit"). Select("ROUND(AVG(inactive),0) as avg_inactive_habit"). Where("heat_date BETWEEN ? AND ?", before7DayDate, before1DayDate). Where("pasture_id = ?", pastureId). Where("neck_ring_number = ? AND frameid = ?", v.NeckRingNumber, v.Frameid). Where(e.DB.Where("high > ?", xToday.ActiveLowest).Or("rumina > ?", xToday.RuminaLowest)). Group("neck_ring_number").First(weekHabitData).Error; err != nil { zaplog.Error("WeeklyActiveAvgUpdate-1", zap.Any("error", err), zap.Any("xToday", xToday)) } // 累计24小时数值 sumHabitData := &SumHabit{} if err = tx.Model(new(model.NeckActiveHabit)). Select("neck_ring_number"). Select("IF(COUNT(1)>6, ROUND(AVG( h2.filter_rumina)*12,0), 0) as sum_rumina"). Select("IF(COUNT(1)>6, ROUND(AVG( h2.intake)*12,0), 0) as sum_intake"). Select("IF(COUNT(1)>6, ROUND(AVG( h2.inactive)*12,0), 0) as sum_inactive"). Select("IF(COUNT(1)>6, ROUND(AVG( h2.active)*12,0), 0) as sum_active"). Select("MAX(h2.change_filter) as sum_max_high"). Select("MIN(IF(change_filter > ?, change_filter, ?)) as sum_min_high", model.DefaultChangeFilter, model.InitChangeFilter). Select("MIN( CASE WHEN filter_chew > ? THEN filter_chew WHEN filter_rumina >= ? THEN filter_rumina ELSE 0 END) as sum_min_chew", model.DefaultChangeFilter, model.DefaultRuminaFilter). Where("pasture_id = ?", pastureId). Where("heat_date BETWEEN ? AND ?", before1DayDate, beginDayDate). Where("active_time BETWEEN ? AND ?", beginDayDate.Add(-23*time.Hour).Format(model.LayoutTime), beginDayDate.Format(model.LayoutTime)). Where(e.DB.Where("high > ?", xToday.ActiveLowest).Or("rumina >= ?", xToday.RuminaLowest)). Where("neck_ring_number = ? AND frameid = ?", v.NeckRingNumber, v.Frameid). Group("neck_ring_number"). First(sumHabitData).Error; err != nil { zaplog.Error("WeeklyActiveAvgUpdate-2", zap.Any("error", err), zap.Any("xToday", xToday)) } // 变化百分比 if v.WeekHighHabit > 0 { if v.FilterHigh-v.WeekHighHabit > 0 { v.ChangeHigh = (v.FilterHigh - v.WeekHighHabit) / int32(float64(v.WeekHigh)*0.6+float64(v.WeekHighHabit)*0.2+float64(weeklyActive.Value)*0.2) } else { v.ChangeHigh = v.FilterHigh - v.WeekHighHabit/v.WeekHighHabit*100 } v.ChangeRumina = v.RuminaFilter - v.WeekRuminaHabit/v.WeekHighHabit*100 v.ChangeChew = v.FilterChew - v.WeekChewHabit/v.WeekHighHabit*100 if err = e.DB.Model(new(model.NeckActiveHabit)). Select("change_high", "change_rumina", "change_chew"). Where("id = ?", v.Id). Updates(v).Error; err != nil { return xerr.WithStack(err) } } // 三天前的反刍和采食 before3DaysNeckActiveHabit := &model.NeckActiveHabit{} before3DayDate := beginDayDate.AddDate(0, 0, -3).Format(model.LayoutDate2) if err = e.DB.Model(new(model.NeckActiveHabit)). Select("sum_rumina", "sum_intake"). Where("pasture_id = ?", pastureId). Where("neck_ring_number = ?", v.NeckRingNumber). Where("heat_date = ?", before3DayDate). Where("frameid = ? ", v.Frameid). First(before3DaysNeckActiveHabit).Error; err != nil { zaplog.Error("WeeklyActiveAvgUpdate-3", zap.Any("error", err), zap.Any("xToday", xToday)) } if err = tx.Model(new(model.NeckActiveHabit)). Select("avg_high_habit", "avg_rumina_habit", "avg_chew_habit", "avg_intake_habit", "avg_inactive_habit"). Select("sum_rumina", "sum_intake", "sum_inactive", "sum_active", "sum_max_high", "sum_min_high", "sum_min_chew"). Select("change_high", "change_rumina", "change_chew", "sum_rumina_before_three_day", "sum_intake_before_three_day"). Where("id = ?", v.Id). Updates(map[string]interface{}{ "week_high_habit": weekHabitData.AvgHighHabit, "week_rumina_habit": weekHabitData.AvgRuminaHabit, "week_chew_habit": weekHabitData.AvgChewHabit, "week_intake_habit": weekHabitData.AvgIntakeHabit, "week_inactive_habit": weekHabitData.AvgIntakeHabit, "sum_rumina": sumHabitData.SumRumina, "sum_intake": sumHabitData.SumIntake, "sum_inactive": sumHabitData.SumInactive, "sum_active": sumHabitData.SumActive, "sum_max_high": sumHabitData.SumMaxHigh, "sum_min_high": sumHabitData.SumMinHigh, "sum_min_chew": sumHabitData.SumMinChew, "change_high": v.ChangeHigh, "change_rumina": v.ChangeRumina, "change_chew": v.ChangeChew, "sum_rumina_before_three_day": before3DaysNeckActiveHabit.SumRumina, "sum_intake_before_three_day": before3DaysNeckActiveHabit.SumIntake, }).Error; err != nil { zaplog.Error("WeeklyActiveAvgUpdate-6", zap.Any("error", err), zap.Any("xToday", xToday)) } zaplog.Info("WeeklyActiveAvgUpdate-7", zap.Any("v", v), zap.Any("xToday", xToday), zap.Any("before3DaysNeckActiveHabit", before3DaysNeckActiveHabit), zap.Any("sumHabitData", sumHabitData), zap.Any("weekHabitData", weekHabitData), ) } return nil }); err != nil { return xerr.WithStack(err) } zaplog.Info("WeeklyActiveAvgUpdate-Success", zap.Any("xToday", xToday)) return nil } // SecondUpdateChangeFilter 第二次更新变化趋势滤波 func (e *Entry) SecondUpdateChangeFilter(pastureId int64, xToday *XToday) (err error) { newChangeFilterList := make([]*ChangeFilterData, 0) if err = e.DB.Model(new(model.NeckActiveHabit)). Select("id,neck_ring_number,change_high,change_filter,rumina_filter,change_rumina,chew_filter,change_chew,heat_date,frameid"). Select("IF(lact = 0, 0.8, 1) as xlc_dis_count"). Where("id BETWEEN ? AND ?", xToday.XMin2Id, xToday.CurrMaxHabitId). Where("pasture_id = ?", pastureId). Where("change_filter = ?", model.InitChangeFilter). Where("change_high > ?", MinChangeHigh). Order("neck_ring_number,heat_date,frameid"). Find(&newChangeFilterList).Error; err != nil { return xerr.WithStack(err) } for _, v := range newChangeFilterList { secondFilterData := &SecondFilterData{} frameId := v.FrameId heatDate := v.HeatDate if v.FrameId == 0 { frameId = 11 heatDateParse, _ := time.Parse(model.LayoutDate2, heatDate) heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2) } if err = e.DB.Model(new(model.NeckActiveHabit)). Select("neck_ring_number", "filter_high", "filter_rumina", "filter_chew"). Where("neck_ring_number = ?", v.NeckRingNumber). Where("heat_date = ?", heatDate). Where("frameid = ?", frameId). First(&secondFilterData).Error; err != nil { zaplog.Error("EntryUpdateActiveHabit", zap.Any("FirstFilterUpdate", err)) } if v.ChangeFilter > MinChangeFilter { secondFilterData.ChangeFilter = float64(v.ChangeFilter) } else { if v.NeckRingNumber == secondFilterData.NeckRingNumber { secondFilterData.ChangeFilter = secondFilterData.ChangeFilter*(1-(float64(xToday.XChangeDiscount)/10)*v.XlcDisCount) + math.Min(float64(v.ChangeHigh), secondFilterData.ChangeFilter+135)*(float64(xToday.XChangeDiscount)/10)*v.XlcDisCount } else { secondFilterData.ChangeFilter = 0 } } if v.RuminaFilter > MinRuminaFilter { secondFilterData.RuminaFilter = float64(v.ChangeFilter) } else { if v.NeckRingNumber == secondFilterData.NeckRingNumber { discount := float64(xToday.XRuminaDisc) / 10 * v.XlcDisCount if math.Abs(float64(v.ChangeRumina)) > 60 { discount *= 0.5 } secondFilterData.RuminaFilter = secondFilterData.RuminaFilter*(1-discount) + float64(v.ChangeRumina)*discount } else { secondFilterData.RuminaFilter = 0 } } secondFilterData.RuminaFilter = math.Min(50, secondFilterData.RuminaFilter) if v.ChewFilter > MinChewFilter { secondFilterData.ChewFilter = float64(v.ChangeChew) } else { if v.NeckRingNumber == secondFilterData.NeckRingNumber { discount := float64(xToday.XRuminaDisc) / 10 if math.Abs(float64(v.ChangeChew)) > 60 { discount *= 0.5 } secondFilterData.ChewFilter = secondFilterData.ChewFilter*(1-discount) + float64(v.ChangeChew)*discount } else { secondFilterData.ChewFilter = 0 } } secondFilterData.ChewFilter = math.Min(50, secondFilterData.ChewFilter) if err = e.DB.Model(new(model.NeckActiveHabit)). Select("change_filter", "rumina_filter", "chew_filter"). Where("id = ?", v.Id). Where("neck_ring_number = ?", v.NeckRingNumber). Where("change_filter = ?", model.InitChangeFilter). Updates(map[string]interface{}{ "change_filter": secondFilterData.ChangeFilter, "rumina_filter": secondFilterData.RuminaFilter, "chew_filter": secondFilterData.ChewFilter, }).Error; err != nil { zaplog.Error("SecondUpdateChangeFilter-1", zap.Any("error", err), zap.Any("xToday", xToday)) } zaplog.Info("SecondUpdateChangeFilter", zap.Any("secondFilterData", secondFilterData), zap.Any("xToday", xToday), zap.Any("v", v), ) } return nil } // FilterCorrectAndScoreUpdate 计算活动量变化趋势校正值(活跃度校正)和健康评分 func (e *Entry) FilterCorrectAndScoreUpdate(pastureId int64, xToday *XToday) error { beginDayDate := time.Now() before7DayDate := beginDayDate.AddDate(0, 0, -7).Format(model.LayoutDate2) before1DayDate := beginDayDate.AddDate(0, 0, -1).Format(model.LayoutDate2) activityVolumeList := make([]*crontab.ActivityVolume, 0) activityVolumeMap := make(map[string]*crontab.ActivityVolume) if err := e.DB.Model(new(model.NeckActiveHabit)). Select("neck_ring_number"). Select("AVG(IF(change_filter>=60, 60, change_filter)) as avg_filter"). Select("ROUND(STD(IF(change_filter>=60, 60, change_filter))) as std_filter"). Select("COUNT(1) as nb"). Where("heat_date BETWEEN ? AND ?", before7DayDate, before1DayDate). Where("pasture_id = ?", pastureId). Where(e.DB.Where("high > ?", xToday.ActiveLowest).Or("rumina >= ?", xToday.RuminaLowest)). Where("active_time <= ?", beginDayDate.Add(-12*time.Hour).Format(model.LayoutTime)). Where("change_filter > ?", MinChangeFilter). Having("nb > ?", DefaultNb). Group("neck_ring_number"). Find(&activityVolumeList).Error; err != nil { zaplog.Error("ActivityVolumeChanges-0", zap.Any("error", err), zap.Any("xToday", xToday)) } if len(activityVolumeList) > 0 { for _, v := range activityVolumeList { activityVolumeMap[v.NeckRingNumber] = v } } neckActiveHabitList := make([]*model.NeckActiveHabit, 0) if err := e.DB.Model(new(model.NeckActiveHabit)). Where("id BETWEEN ? AND ?", xToday.XMin2Id, xToday.CurrMaxHabitId). Where("pasture_id = ?", pastureId). Where(e.DB.Where("high > ?", xToday.ActiveLowest).Or("rumina > ?", xToday.RuminaLowest)). Find(&neckActiveHabitList).Error; err != nil { zaplog.Error("ActivityVolumeChanges-1", zap.Any("error", err), zap.Any("xToday", xToday)) return xerr.WithStack(err) } for _, v := range neckActiveHabitList { if filterCorrectMap, ok := activityVolumeMap[v.NeckRingNumber]; ok { filterCorrect := model.DefaultFilterCorrect - int(math.Floor(float64(filterCorrectMap.AvgFilter)/3+float64(filterCorrectMap.StdFilter)/2)) // 活动量校正系数 if err := e.DB.Model(new(model.NeckActiveHabit)). Where("id = ?", v.Id). Where("neck_ring_number = ?", v.NeckRingNumber). Update("filter_correct", filterCorrect).Error; err != nil { zaplog.Error("ActivityVolumeChanges-2", zap.Any("error", err), zap.Any("xToday", xToday)) continue } } // 健康评分 if v.Score != 0 { continue } cowScore := calculateScore(v) if err := e.DB.Model(new(model.NeckActiveHabit)). Where("id = ?", v.Id). Where("neck_ring_number = ?", v.NeckRingNumber). Update("score", cowScore).Error; err != nil { zaplog.Error("ActivityVolumeChanges-2", zap.Any("error", err), zap.Any("xToday", xToday)) continue } } zaplog.Info("EntryUpdateActiveHabit-ActivityVolumeChanges-Success") return nil } // UpdateChangeAdJust 更新群体校正数据 func (e *Entry) UpdateChangeAdJust(pastureId int64, xToday *XToday) error { res := make([]*model.NeckRingBarChange, 0) oneDayAgo := time.Now().AddDate(0, 0, -1).Format(model.LayoutDate2) if err := e.DB.Table(fmt.Sprintf("%s as h", new(model.NeckActiveHabit).TableName())). Select("h.neck_ring_number,h.heat_date, h.frameid, c.pen_id, c.pen_name, COUNT(*) as nb, ROUND(AVG(h.change_high)) as change_high, ROUND(AVG(h.change_filter)) as change_filter"). Joins("JOIN cow as c ON h.neck_ring_number = c.neck_ring_number"). Where("h.pasture_id = ?", pastureId). Where("h.heat_date >= ?", oneDayAgo). Where("h.cow_id >= ?", 0). Group("h.heat_date, h.frameid, c.pen_id"). Order("h.heat_date, h.frameid, c.pen_name"). Find(&res).Error; err != nil { return xerr.WithStack(err) } for _, v := range res { if err := e.DB.Model(new(model.NeckActiveHabit)). Where("id > ?", xToday.LastMaxHabitId). Where("heat_date = ?", v.HeatDate). Where("heat_date >= ?", oneDayAgo). Where("frameid = ?", v.FrameId). Where("neck_ring_number = ?", v.NeckRingNumber). Update("change_adjust", v.ChangeHigh).Error; err != nil { zaplog.Error("UpdateChangeAdJust-1", zap.Any("error", err), zap.Any("xToday", xToday)) } } return nil } // 辅助函数来计算过滤值 func computeIfPositiveElse(newValue, prevFilterValue float64, weightPrev, weightNew float64) float64 { return math.Ceil((prevFilterValue * weightPrev) + (weightNew * newValue)) } // 计算 score 的逻辑 func calculateScore(habit *model.NeckActiveHabit) int { // 第一部分逻辑 var part1 float64 switch { case (habit.CalvingAge <= 1 && habit.Lact >= 1) || (habit.CalvingAge >= 2 && habit.CalvingAge <= 13 && (habit.SumRumina+habit.SumIntake) == 0) || ((habit.Lact == 0 || habit.CalvingAge >= 14) && habit.ChangeFilter == -99): part1 = -199 case habit.CalvingAge >= 2 && habit.CalvingAge <= 13: part1 = math.Min((float64(habit.SumRumina+habit.SumIntake)-(100+math.Min(7, float64(habit.CalvingAge))*60))/10*2, 0) case habit.ChangeFilter > -99: part1 = math.Min(0, math.Min(getValueOrDefault(float64(habit.ChangeFilter), 0), getValueOrDefault(float64(habit.SumMinHigh), 0)))*0.2 + math.Min(0, math.Min(getValueOrDefault(float64(habit.ChangeFilter), 0), getValueOrDefault(float64(habit.SumMinChew), 0)))*0.2 + getRuminaSumIntakeSumScore(float64(habit.SumRumina+habit.SumIntake)) + getAdditionalScore(habit) default: part1 = -299 } // 第二部分逻辑 var part2 float64 switch { case habit.FirmwareVersion%100 >= 52: part2 = 1 case habit.FirmwareVersion%100 >= 30 && habit.FirmwareVersion%100 <= 43: part2 = 0.8 default: part2 = 0.6 } // 最终 score return DefaultScore + int(math.Floor(part1*part2)) } // 获取值或默认值 func getValueOrDefault(value, defaultValue float64) float64 { if value > -99 { return value } return defaultValue } // 计算累计反刍得分 func getRuminaSumIntakeSumScore(sum float64) float64 { switch { case sum < 80: return -30 case sum < 180: return -20 case sum < 280: return -10 default: return 0 } } // 计算额外得分 func getAdditionalScore(habit *model.NeckActiveHabit) float64 { var score float64 if (habit.SumRumina+habit.SumIntake < 280 || habit.SumMinHigh+habit.SumMinChew < -50) && habit.SumMaxHigh > 50 { score += 10 } if habit.ChangeFilter < -30 && habit.ChangeFilter <= habit.SumMinHigh && habit.ChewFilter < -30 && habit.ChewFilter <= habit.SumMinChew { score -= 5 } return score }