|  | @@ -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
 | 
	
		
			
				|  |  |  }
 |