Prechádzať zdrojové kódy

crontab: penBehavior 栏舍饲喂监测

Yi 1 deň pred
rodič
commit
31f0dbaca4

+ 1 - 0
config/app.develop.yaml

@@ -52,6 +52,7 @@ cron:
   neck_ring_estrus_warning: "*/50 * * * * ?"   # 脖环预警(每50分钟执行一次
   neck_ring_health_warning: "*/50 * * * * ?"   # 脖环预警(每50分钟执行一次
   update_pen_behavior: "0 45 * * * ?"  # 更新栏舍行行为数据
+  update_pen_behavior_daily: "0 05 2 * * ?"  # 更新栏舍饲养监测数据
 
 
 mqtt:

+ 1 - 0
config/app.go

@@ -67,6 +67,7 @@ type CronSetting struct {
 	NeckRingEstrusWarning   string `yaml:"neck_ring_estrus_warning"`   //  脖环发情预警
 	NeckRingHealthWarning   string `yaml:"neck_ring_health_warning"`   //  脖环健康预警
 	UpdatePenBehavior       string `yaml:"update_pen_behavior"`        //  栏舍行为数据
+	UpdatePenBehaviorDaily  string `yaml:"update_pen_behavior_daily"`  //  栏舍饲养监测
 }
 
 type JwtTokenKeyConfig struct {

+ 1 - 0
config/app.test.yaml

@@ -39,6 +39,7 @@ cron:
   neck_ring_estrus_warning: "*/50 * * * * ?"   # 脖环预警(每50分钟执行一次
   neck_ring_health_warning: "*/50 * * * * ?"   # 脖环预警(每50分钟执行一次
   update_pen_behavior: "0 45 * * * ?"  # 更新栏舍行行为数据
+  update_pen_behavior_daily: "0 05 2 * * ?"  # 更新栏舍饲养监测数据
 
 mqtt:
   broker: "kptyun.com:1983"

+ 6 - 0
dep/di_crontab.go

@@ -122,6 +122,12 @@ func EntryCrontab(dependency CrontabDependency) *cron.Crontab {
 		panic(err)
 	}
 
+	err = newCrontab.Bind("UpdatePenBehaviorDaily", cs.UpdatePenBehavior, dependency.CrontabHub.UpdatePenBehaviorDaily)
+	if err != nil {
+		zaplog.Error("EntryCrontab", zap.Any("UpdatePenBehaviorDaily", err))
+		panic(err)
+	}
+
 	/*err = newCrontab.Bind("GenerateWorkOrder", cs.GenerateWorkOrder, dependency.CrontabHub.GenerateAsynqWorkOrder)
 	if err != nil {
 		panic(err)

+ 42 - 0
model/milk_daily.go

@@ -0,0 +1,42 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type MilkDaily struct {
+	Id              int64                      `json:"id"`
+	PastureId       int64                      `json:"pastureId"`
+	HeatDate        string                     `json:"heatDate"`
+	CowId           int64                      `json:"cowId"`
+	Lact            int32                      `json:"lact"`
+	BreedStatus     pasturePb.BreedStatus_Kind `json:"breedStatus"`
+	LactationAge    int32                      `json:"lactationAge"`
+	PenId           int32                      `json:"penId"`
+	PenName         string                     `json:"penName"`
+	Conductivity    float32                    `json:"conductivity"`
+	DayYield        float32                    `json:"dayYield"`
+	MilkingDuration float32                    `json:"milkingDuration"`
+	DayHigh         int32                      `json:"dayHigh"`
+	WeekAvg         float32                    `json:"weekAvg"`
+	DayRumina       int32                      `json:"dayRumina"`
+	DayIntake       int32                      `json:"dayIntake"`
+	DayInactive     int32                      `json:"dayInactive"`
+	DayGasp         int32                      `json:"dayGasp"`
+	DayActive       int32                      `json:"dayActive"`
+	CreatedAt       int64                      `json:"createdAt"`
+	UpdatedAt       int64                      `json:"updatedAt"`
+}
+
+func (m *MilkDaily) TableName() string {
+	return "milk_daily"
+}
+
+type MilkDailyModel struct {
+	CowId       int64  `json:"cow_id"`
+	HeatDate    string `json:"heat_date"`
+	DayActive   int32  `json:"day_active"`
+	DayHigh     int32  `json:"day_high"`
+	DayInactive int32  `json:"day_inactive"`
+	DayIntake   int32  `json:"day_intake"`
+	DayRumina   int32  `json:"day_rumina"`
+	Nb          int32  `json:"nb"`
+}

+ 48 - 0
model/pen_behavior_day.go

@@ -0,0 +1,48 @@
+package model
+
+type PenBehaviorDay struct {
+	Id          int64   `json:"id"`
+	PastureId   int64   `json:"pastureId"`
+	HeatDate    string  `json:"heatDate"`
+	PenId       int32   `json:"penId"`
+	PenName     string  `json:"penName"`
+	CowCount    int32   `json:"cowCount"`
+	DayAvgMilk  float32 `json:"dayAvgMilk"`
+	DayHigh     int32   `json:"dayHigh"`
+	DayRumina   int32   `json:"dayRumina"`
+	DayIntake   int32   `json:"dayIntake"`
+	DayInactive int32   `json:"dayInactive"`
+	DayGasp     int32   `json:"dayGasp"`
+	DayActive   int32   `json:"dayActive"`
+	WeekAvgMilk float32 `json:"weekAvgMilk"`
+	RuminaStd   int32   `json:"ruminaStd"`
+	CreatedAt   int64   `json:"createdAt"`
+	UpdatedAt   int64   `json:"updatedAt"`
+}
+
+func (p *PenBehaviorDay) TableName() string {
+	return "pen_behavior_day"
+}
+
+func NewPenBehaviorDay(pastureId int64, heatDate string, penId int32, penName string, cowCount int32, dayAvgMilk float32,
+	dayHigh int32, dayRumina int32, dayIntake int32, dayInactive int32, dayGasp int32, dayActive int32, weekAvgMilk float32,
+	ruminaStd int32) *PenBehaviorDay {
+	return &PenBehaviorDay{
+		PastureId:   pastureId,
+		HeatDate:    heatDate,
+		PenId:       penId,
+		PenName:     penName,
+		CowCount:    cowCount,
+		DayAvgMilk:  dayAvgMilk,
+		DayHigh:     dayHigh,
+		DayRumina:   dayRumina,
+		DayIntake:   dayIntake,
+		DayInactive: dayInactive,
+		DayGasp:     dayGasp,
+		DayActive:   dayActive,
+		WeekAvgMilk: weekAvgMilk,
+		RuminaStd:   ruminaStd,
+	}
+}
+
+type PenBehaviorDaySlice []*PenBehaviorDay

+ 22 - 19
module/backend/enum_map.go

@@ -321,24 +321,27 @@ func (s *StoreEntry) ForbiddenMatingReasonsMap() map[pasturePb.ForbiddenMatingRe
 
 func (s *StoreEntry) eventCategoryMap() map[pasturePb.EventType_Kind]pasturePb.EventCategory_Kind {
 	return map[pasturePb.EventType_Kind]pasturePb.EventCategory_Kind{
-		pasturePb.EventType_Enter:            pasturePb.EventCategory_Base,
-		pasturePb.EventType_Transfer_Ben:     pasturePb.EventCategory_Base,
-		pasturePb.EventType_Body_Score:       pasturePb.EventCategory_Base,
-		pasturePb.EventType_Pregnancy_Check:  pasturePb.EventCategory_Base,
-		pasturePb.EventType_Weight:           pasturePb.EventCategory_Base,
-		pasturePb.EventType_Death:            pasturePb.EventCategory_Base,
-		pasturePb.EventType_Out:              pasturePb.EventCategory_Base,
-		pasturePb.EventType_Dry_Milk:         pasturePb.EventCategory_Breed,
-		pasturePb.EventType_Estrus:           pasturePb.EventCategory_Breed,
-		pasturePb.EventType_Calving:          pasturePb.EventCategory_Breed,
-		pasturePb.EventType_Seme_Time:        pasturePb.EventCategory_Breed,
-		pasturePb.EventType_Mating:           pasturePb.EventCategory_Breed,
-		pasturePb.EventType_Birth:            pasturePb.EventCategory_Breed,
-		pasturePb.EventType_Immunication:     pasturePb.EventCategory_Health,
-		pasturePb.EventType_Castrated:        pasturePb.EventCategory_Health,
-		pasturePb.EventType_Insect_Repellent: pasturePb.EventCategory_Health,
-		pasturePb.EventType_Weaning:          pasturePb.EventCategory_Breed,
-		pasturePb.EventType_Sale:             pasturePb.EventCategory_Other,
-		pasturePb.EventType_Abort:            pasturePb.EventCategory_Other,
+		pasturePb.EventType_Enter:             pasturePb.EventCategory_Base,
+		pasturePb.EventType_Transfer_Ben:      pasturePb.EventCategory_Base,
+		pasturePb.EventType_Body_Score:        pasturePb.EventCategory_Base,
+		pasturePb.EventType_Pregnancy_Check:   pasturePb.EventCategory_Base,
+		pasturePb.EventType_Weight:            pasturePb.EventCategory_Base,
+		pasturePb.EventType_Death:             pasturePb.EventCategory_Base,
+		pasturePb.EventType_Out:               pasturePb.EventCategory_Base,
+		pasturePb.EventType_Dry_Milk:          pasturePb.EventCategory_Breed,
+		pasturePb.EventType_Estrus:            pasturePb.EventCategory_Breed,
+		pasturePb.EventType_Calving:           pasturePb.EventCategory_Breed,
+		pasturePb.EventType_Seme_Time:         pasturePb.EventCategory_Breed,
+		pasturePb.EventType_Mating:            pasturePb.EventCategory_Breed,
+		pasturePb.EventType_Birth:             pasturePb.EventCategory_Breed,
+		pasturePb.EventType_ForbiddenMating:   pasturePb.EventCategory_Breed,
+		pasturePb.EventType_UnForbiddenMating: pasturePb.EventCategory_Breed,
+		pasturePb.EventType_Immunication:      pasturePb.EventCategory_Health,
+		pasturePb.EventType_Castrated:         pasturePb.EventCategory_Health,
+		pasturePb.EventType_Insect_Repellent:  pasturePb.EventCategory_Health,
+		pasturePb.EventType_Disease:           pasturePb.EventCategory_Health,
+		pasturePb.EventType_Weaning:           pasturePb.EventCategory_Breed,
+		pasturePb.EventType_Sale:              pasturePb.EventCategory_Other,
+		pasturePb.EventType_Abort:             pasturePb.EventCategory_Other,
 	}
 }

+ 2 - 1
module/crontab/interface.go

@@ -42,5 +42,6 @@ type Crontab interface {
 	NeckRingEstrusWarning() error // 发情预警
 	NeckRingHealthWarning() error // 健康预警
 
-	UpdatePenBehavior() error // 栏舍行为数据
+	UpdatePenBehavior() error      // 栏舍行为数据
+	UpdatePenBehaviorDaily() error // 栏舍饲养监测
 }

+ 115 - 0
module/crontab/pen_behavior_day.go

@@ -0,0 +1,115 @@
+package crontab
+
+import (
+	"kpt-pasture/model"
+	"time"
+
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
+	"gitee.com/xuyiping_admin/pkg/xerr"
+	"go.uber.org/zap"
+)
+
+const (
+	MaxDayHigh  = 500
+	MaxRumina   = 200
+	MaxCowCount = 10
+	MaxNB       = 8
+	Days        = 2
+)
+
+func (e *Entry) UpdatePenBehaviorDaily() error {
+	pastureList := e.FindPastureList()
+	if pastureList == nil || len(pastureList) == 0 {
+		return nil
+	}
+
+	for _, pasture := range pastureList {
+		e.BehaviorDaily(pasture.Id, Days)
+	}
+	return nil
+}
+
+// BehaviorDaily 更新牛只每日行为数据
+func (e *Entry) BehaviorDaily(pastureId int64, days int32) {
+	for i := days; i >= 1; i-- {
+		targetDate := time.Now().AddDate(0, 0, -int(i)).Format(model.LayoutDate2)
+
+		// 1. 更新milk_daily表
+		if err := e.updateMilkDaily(pastureId, targetDate); err != nil {
+			zaplog.Error("UpdateBehaviorDaily", zap.Any("pastureId", pastureId), zap.Any("targetDate", targetDate), zap.Any("err", err))
+			continue
+		}
+
+		// 2. 删除PenBehaviorDay表中的旧数据
+		if err := e.DB.Where("pasture_id = ? AND heat_date = ?", pastureId, targetDate).
+			Delete(new(model.PenBehaviorDay)).Error; err != nil {
+			zaplog.Error("UpdateBehaviorDaily", zap.Any("delete error", err))
+			continue
+		}
+
+		// 3. 插入新的PenBehaviorDay数据
+		if err := e.insertBarBehaviorDay(pastureId, targetDate); err != nil {
+			zaplog.Error("UpdateBehaviorDaily", zap.Any("insert error", err))
+			continue
+		}
+	}
+}
+
+// updateMilkDaily 更新milk_daily表中的行为数据
+func (e *Entry) updateMilkDaily(pastureId int64, targetDate string) error {
+	milkDailyModelList := make([]*model.MilkDailyModel, 0)
+	if err := e.DB.Model(new(model.NeckActiveHabit)).
+		Select(`cow_id,heat_date, ROUND(AVG(filter_high), 0) as day_high, ROUND(AVG(rumina)*12, 0) as day_rumina, ROUND(AVG(intake)*12, 0) as day_intake,
+				ROUND(AVG(inactive)*12, 0) as day_inactive, ROUND(AVG(active)*12, 0) as day_active, COUNT(1) as nb`).
+		Where("pasture_id = ? AND heat_date = ?", pastureId, targetDate).
+		Where("cow_id > ?", 0).
+		Group("cow_id").
+		Having("nb >= ?", MaxNB).
+		Find(&milkDailyModelList).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	for _, v := range milkDailyModelList {
+		if err := e.DB.Model(new(model.MilkDaily)).
+			Where("pasture_id = ?", pastureId).
+			Where("cow_id = ? AND heat_date = ?", v.CowId, targetDate).
+			Updates(map[string]interface{}{
+				"day_high":     v.DayHigh,
+				"day_rumina":   v.DayRumina,
+				"day_intake":   v.DayIntake,
+				"day_inactive": v.DayInactive,
+				"day_active":   v.DayActive,
+			}).Error; err != nil {
+			continue
+		}
+	}
+	return nil
+}
+
+// insertBarBehaviorDay 插入栏舍行为数据
+func (e *Entry) insertBarBehaviorDay(pastureId int64, targetDate string) error {
+	penBehaviorList := make([]*model.PenBehaviorDay, 0)
+	if err := e.DB.Model(new(model.MilkDaily)).
+		Select(`heat_date, pasture_id, pen_id, COUNT(1) as cow_count, ROUND(AVG(d.day_yield), 1) as day_milk,
+		ROUND(AVG(d.week_avg), 1) as week_milk,ROUND(AVG(d.day_high), 0) as day_high,
+		ROUND(AVG(d.day_rumina), 0) as day_rumina,ROUND(AVG(d.day_intake), 0) as day_intake,
+		ROUND(AVG(d.day_inactive), 0) as day_inactive,ROUND(AVG(d.day_gasp), 0) as day_gasp,
+		ROUND(AVG(d.day_active), 0) as day_active,STD(d.day_rumina) as rumina_std`).
+		Where("pasture_id = ?", pastureId).
+		Where("heat_date = ?", targetDate).
+		Where("day_high > ?", MaxDayHigh).
+		Where("day_rumina > ?", MaxRumina).
+		Group("pen_id").
+		Having("cow_count >= ?", MaxCowCount).
+		Order("pen_id").
+		Find(&penBehaviorList).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if len(penBehaviorList) > 0 {
+		if err := e.DB.Create(&penBehaviorList).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+	}
+
+	return nil
+}