浏览代码

crontab: penBehavior update

Yi 2 周之前
父节点
当前提交
b774462136
共有 2 个文件被更改,包括 86 次插入173 次删除
  1. 0 12
      model/pen_behavior.go
  2. 86 161
      module/crontab/pen_behavior.go

+ 0 - 12
model/pen_behavior.go

@@ -200,15 +200,3 @@ func (p PenBehaviorSlice) ToPB2() *BarnBehaviorCurveItem {
 
 	return res
 }
-
-type PenBehaviorWeekModel struct {
-	CowCount   int32     `json:"cowCount"`
-	SumRumina  int32     `json:"sumRumina"`
-	SumIntake  int32     `json:"sumIntake"`
-	SumRest    int32     `json:"sumRest"`
-	SumGasp    int32     `json:"sumGasp"`
-	RuminaRate []float64 `json:"ruminaRate"`
-	IntakeRate []float64 `json:"intakeRate"`
-	RestRate   []float64 `json:"restRate"`
-	GaspRate   []float64 `json:"gaspRate"`
-}

+ 86 - 161
module/crontab/pen_behavior.go

@@ -4,8 +4,6 @@ import (
 	"fmt"
 	"kpt-pasture/model"
 	"kpt-pasture/util"
-	"math"
-	"sort"
 	"time"
 
 	"gitee.com/xuyiping_admin/pkg/xerr"
@@ -23,20 +21,51 @@ func (e *Entry) UpdatePenBehavior() error {
 	}
 
 	for _, pasture := range pastureList {
-		e.PenBehavior(pasture.Id)
-		e.UpdatePenBehaviorWeekData(pasture.Id)
+		conf, err := e.GetSystemNeckRingConfigure(pasture.Id, model.MaxPenBehavior)
+		if err != nil {
+			zaplog.Error("UpdatePenBehavior", zap.Any("pasture", pasture), zap.Any("err", err))
+			continue
+		}
+		e.PenBehaviorEnter(pasture.Id, conf.Value)
 	}
 	return nil
 }
 
+// PenBehaviorEnter 栏舍行为曲线 对数据进行查缺补漏
+func (e *Entry) PenBehaviorEnter(pastureId int64, maxValue int64) {
+	var minHeatDate string
+	if err := e.DB.Model(new(model.NeckRingOriginal)).
+		Select("min(active_date) as min_heat_date").
+		Where("pasture_id = ?", pastureId).
+		Where("id >= ?", maxValue).
+		Scan(&minHeatDate).Error; err != nil {
+		zaplog.Error("PenBehaviorEnter", zap.Any("pastureId", pastureId), zap.Any("err", err))
+		return
+	}
+	e.PenBehavior(pastureId, minHeatDate)
+	var maxId int64
+	if err := e.DB.Model(new(model.NeckRingOriginal)).
+		Select("MAX(id) as id").
+		Where("pasture_id = ?", pastureId).
+		Where("id >= ?", maxValue).
+		Where("active_date = ?", minHeatDate).
+		Scan(&maxId).Error; err != nil {
+		zaplog.Error("PenBehaviorEnter", zap.Any("pastureId", pastureId), zap.Any("err", err))
+	}
+	if maxId > maxValue {
+		if err := e.UpdateSystemNeckRingConfigure(pastureId, model.MaxPenBehavior, maxId); err != nil {
+			zaplog.Error("UpdateSystemNeckRingConfigure", zap.Any("err", err))
+		}
+	}
+
+	e.UpdatePenBehaviorWeekData(pastureId, minHeatDate)
+}
+
 // PenBehavior 栏舍行为曲线
-func (e *Entry) PenBehavior(pastureId int64) {
-	heatDate := time.Now().Local().AddDate(0, 0, -1).Format(model.LayoutDate2)
+func (e *Entry) PenBehavior(pastureId int64, heatDate string) {
 	frameIds := util.FrameIdSlice
-
 	penBehaviorList := make([]*model.PenBehaviorData, 0)
 	for _, frameId := range frameIds {
-		// 1. 获取颈环原始数据
 		penBehaviorModel, err := e.getNeckRingOriginalList(pastureId, heatDate, frameId)
 		if err != nil {
 			zaplog.Error("PenBehavior",
@@ -138,150 +167,43 @@ func (e *Entry) savePenBehaviorData(penDataList []*model.PenBehaviorData) error
 	return nil
 }
 
-func (e *Entry) UpdatePenBehaviorWeekData(pastureId int64) {
-	penBehaviorList := e.findWeekPenBehaviorList(pastureId)
+func (e *Entry) UpdatePenBehaviorWeekData(pastureId int64, dateTime string) {
+	dateTime1, _ := util.TimeParseLocal(model.LayoutDate2, dateTime)
+	startTime := dateTime1.AddDate(0, 0, -7).Format(model.LayoutDate2)
+	endTime := dateTime1.AddDate(0, 0, -1).Format(model.LayoutDate2)
+	penBehaviorList, err := e.findWeekPenBehaviorList(pastureId, dateTime, startTime, endTime)
+	if err != nil {
+		zaplog.Error("UpdatePenBehaviorWeekData",
+			zap.Any("err", err),
+			zap.Any("pastureId", pastureId),
+			zap.Any("dateTime", dateTime),
+			zap.Any("startTime", startTime),
+			zap.Any("endTime", endTime),
+		)
+		return
+	}
 	if len(penBehaviorList) == 0 {
 		return
 	}
 
-	// 按日期和frameid排序
-	sort.Slice(penBehaviorList, func(i, j int) bool {
-		if penBehaviorList[i].HeatDate == penBehaviorList[j].HeatDate {
-			return penBehaviorList[i].Frameid < penBehaviorList[j].Frameid
-		}
-		return penBehaviorList[i].HeatDate < penBehaviorList[j].HeatDate
-	})
-
 	// 处理每个日期和frameid的数据
 	for _, item := range penBehaviorList {
-		currDate := item.HeatDate
-		currFrameid := item.Frameid
-		// 计算开始和结束日期
-		currTime, err := time.Parse(model.LayoutDate2, currDate)
-		if err != nil {
+		if err = e.DB.Model(new(model.PenBehavior)).
+			Where("id = ?", item.Id).
+			Updates(map[string]interface{}{
+				"week_rumina_rate": item.WeekRuminaRate,
+				"week_intake_rate": item.WeekIntakeRate,
+				"week_rest_rate":   item.WeekRestRate,
+				"week_gasp_rate":   item.WeekGaspRate,
+				"rumina_std":       item.RuminaStd,
+				"intake_std":       item.IntakeStd,
+				"rest_std":         item.RestStd,
+				"gasp_std":         item.GaspStd,
+				"is_show":          pasturePb.IsShow_Ok,
+			}).Error; err != nil {
 			zaplog.Error("UpdatePenBehaviorWeekData", zap.Error(err))
-			continue
 		}
-		startTime := currTime.AddDate(0, 0, -7).Format(model.LayoutDate2)
-		endTime := currTime.AddDate(0, 0, -1).Format(model.LayoutDate2)
-
-		// 获取历史数据
-		historyList := e.findHistoryPenBehaviorList(pastureId, startTime, endTime, currFrameid)
-		if len(historyList) == 0 {
-			// 如果没有历史数据,将所有记录标记为-1
-			if err = e.DB.Model(new(model.PenBehavior)).
-				Where("id = ?", item.Id).
-				Updates(map[string]interface{}{
-					"week_rumina_rate": -1,
-					"week_intake_rate": -1,
-					"week_rest_rate":   -1,
-					"week_gasp_rate":   -1,
-					"is_show":          pasturePb.IsShow_Ok,
-				}).Error; err != nil {
-				zaplog.Error("UpdatePenBehaviorWeekData", zap.Error(err))
-			}
-			continue
-		}
-
-		// 按pen_id分组计算统计数据
-		penStats := make(map[int32]*model.PenBehaviorWeekModel)
-		for _, v := range historyList {
-			if stats, exists := penStats[v.PenId]; exists {
-				stats.CowCount++
-				stats.SumRumina += v.RuminaRate
-				stats.SumIntake += v.IntakeRate
-				stats.SumRest += v.RestRate
-				stats.SumGasp += v.GaspRate
-				// 计算标准差
-				stats.RuminaRate = append(stats.RuminaRate, float64(v.RuminaRate))
-				stats.IntakeRate = append(stats.IntakeRate, float64(v.IntakeRate))
-				stats.RestRate = append(stats.RestRate, float64(v.RestRate))
-				stats.GaspRate = append(stats.GaspRate, float64(v.GaspRate))
-			} else {
-				penStats[v.PenId] = &model.PenBehaviorWeekModel{
-					CowCount:   1,
-					SumRumina:  v.RuminaRate,
-					SumIntake:  v.IntakeRate,
-					SumRest:    v.RestRate,
-					SumGasp:    v.GaspRate,
-					RuminaRate: []float64{float64(v.RuminaRate)},
-					IntakeRate: []float64{float64(v.IntakeRate)},
-					RestRate:   []float64{float64(v.RestRate)},
-					GaspRate:   []float64{float64(v.GaspRate)},
-				}
-			}
-		}
-
-		// 更新当前记录
-		if stats, exists := penStats[item.PenId]; exists {
-			if err = e.DB.Model(new(model.PenBehavior)).
-				Where("id = ?", item.Id).
-				Updates(map[string]interface{}{
-					"week_rumina_rate": int32(float64(stats.SumRumina) / float64(stats.CowCount)),
-					"week_intake_rate": int32(float64(stats.SumIntake) / float64(stats.CowCount)),
-					"week_rest_rate":   int32(float64(stats.SumRest) / float64(stats.CowCount)),
-					"week_gasp_rate":   int32(float64(stats.SumGasp) / float64(stats.CowCount)),
-					"rumina_std":       int32(calculateStd(stats.RuminaRate)),
-					"intake_std":       int32(calculateStd(stats.IntakeRate)),
-					"rest_std":         int32(calculateStd(stats.RestRate)),
-					"gasp_std":         int32(calculateStd(stats.GaspRate)),
-					"is_show":          pasturePb.IsShow_Ok,
-				}).Error; err != nil {
-				zaplog.Error("UpdatePenBehaviorWeekData", zap.Error(err))
-			}
-		} else {
-			// 如果没有历史数据,标记为-1
-			if err = e.DB.Model(new(model.PenBehavior)).
-				Where("id = ?", item.Id).
-				Updates(map[string]interface{}{
-					"week_rumina_rate": -1,
-					"week_intake_rate": -1,
-					"week_rest_rate":   -1,
-					"week_gasp_rate":   -1,
-					"is_show":          pasturePb.IsShow_Ok,
-				}).Error; err != nil {
-				zaplog.Error("UpdatePenBehaviorWeekData", zap.Error(err))
-			}
-		}
-	}
-}
-
-// findHistoryPenBehaviorList 获取历史数据
-func (e *Entry) findHistoryPenBehaviorList(pastureId int64, startTime, endTime string, frameid int32) []*model.PenBehavior {
-	res := make([]*model.PenBehavior, 0)
-	if err := e.DB.Model(new(model.PenBehavior)).
-		Where("pasture_id = ?", pastureId).
-		Where("heat_date BETWEEN ? AND ?", startTime, endTime).
-		Where("frameid = ?", frameid).
-		Find(&res).Error; err != nil {
-		zaplog.Error("findHistoryPenBehaviorList", zap.Error(err))
-		return nil
-	}
-	return res
-}
-
-// calculateStd 计算标准差
-func calculateStd(values []float64) float64 {
-	if len(values) == 0 {
-		return 0
-	}
-	// 计算平均值
-	var sum float64
-	for _, v := range values {
-		sum += v
-	}
-	mean := sum / float64(len(values))
-
-	// 计算方差
-	var variance float64
-	for _, v := range values {
-		diff := v - mean
-		variance += diff * diff
 	}
-	variance /= float64(len(values))
-
-	// 返回标准差
-	return math.Sqrt(variance)
 }
 
 // calculateActiveTime 计算活动时间
@@ -325,23 +247,26 @@ func (e *Entry) findPenBehavior(pastureId int64, heatDate string, penId int32, f
 	return res
 }
 
-func (e *Entry) findWeekPenBehaviorList(pastureId int64) []*model.PenBehavior {
-	res := make([]*model.PenBehavior, 0)
-	if err := e.DB.Model(new(model.PenBehavior)).
-		Where("pasture_id = ?", pastureId).
-		Where("is_show = ?", pasturePb.IsShow_No).
-		Where("cow_count >= ?", model.PenBehaviorMinCowCount).
-		Limit(int(defaultLimit)).
-		Find(&res).Error; err != nil {
-		return nil
-	}
-	return res
-}
-
-// ifThenElse 条件判断函数
-func ifThenElse(condition bool, a, b int32) int32 {
-	if condition {
-		return a
+func (e *Entry) findWeekPenBehaviorList(pastureId int64, heatDate, startTime, endTime string) ([]*model.PenBehavior, error) {
+	penBehaviorList := make([]*model.PenBehavior, 0)
+	sql := fmt.Sprintf(`
+		SELECT b1.id, 
+		ROUND(AVG(b0.rumina_rate)) week_rumina_rate,
+		ROUND(STD(b0.rumina_rate)) rumina_std, 
+		ROUND(AVG( b0.intake_rate)) week_intake_rate, 
+		ROUND(STD( b0.intake_rate)) intake_std, 
+		ROUND(AVG( b0.rest_rate)) week_rest_rate, 
+		ROUND(STD( b0.rest_rate)) rest_std, 
+		ROUND(AVG( b0.gasp_rate)) week_gasp_rate, 
+		ROUND(STD( b0.gasp_rate)) gasp_std
+		FROM pen_behavior b1 JOIN pen_behavior b0 
+		ON b1.pen_id=b0.pen_id AND b1.heat_date='%s' 
+		AND b1.frameid=b0.frameid AND b0.heat_date BETWEEN '%s' AND '%s'
+		WHERE  b1.cow_count>= %d AND b1.pasture_id = %d
+		GROUP BY b1.id
+	`, heatDate, startTime, endTime, model.PenBehaviorMinCowCount, pastureId)
+	if err := e.DB.Raw(sql).Find(&penBehaviorList).Error; err != nil {
+		return nil, xerr.WithStack(err)
 	}
-	return b
+	return penBehaviorList, nil
 }