Browse Source

crontab: behavior 栏舍行为曲线

Yi 4 days ago
parent
commit
f1defe2058
7 changed files with 62 additions and 37 deletions
  1. 1 1
      go.mod
  2. 2 0
      go.sum
  3. 8 0
      model/cow.go
  4. 22 0
      model/pen_behavior.go
  5. 5 6
      module/backend/event_base.go
  6. 10 11
      module/backend/event_breed_more_more.go
  7. 14 19
      module/crontab/pen_behavior.go

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250324120913-88e4f53314db
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250325011618-727f0797ea27
 	gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/eclipse/paho.mqtt.golang v1.4.3

+ 2 - 0
go.sum

@@ -82,6 +82,8 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250324091419-f7fa3ad96c0e h1:Dv1OgQfY
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250324091419-f7fa3ad96c0e/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250324120913-88e4f53314db h1:QLLT24YPsIii/vCJYawzA2t5uwpoYb77y83WOqvlwtY=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250324120913-88e4f53314db/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250325011618-727f0797ea27 h1:DruuERLrwZPshZoCQjgRDTYzsQd1CgAFJmoSq8PdVVk=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250325011618-727f0797ea27/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b h1:w05MxH7yqveRlaRbxHhbif5YjPrJFodRPfOjYhXn7Zk=
 gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b/go.mod h1:8tF25X6pE9WkFCczlNAC0K2mrjwKvhhp02I7o0HtDxY=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=

+ 8 - 0
model/cow.go

@@ -195,12 +195,14 @@ func (c *Cow) EventDryMilkUpdate(dryMilkAt int64, pen *Pen) {
 func (c *Cow) ForbiddenMatingUpdate(forbiddenMatingAt int64) {
 	c.IsForbiddenMating = pasturePb.IsShow_Ok
 	c.LastForbiddenMatingAt = forbiddenMatingAt
+	c.BreedStatus = pasturePb.BreedStatus_No_Mating
 }
 
 // UnForbiddenMatingUpdate 解禁配更新
 func (c *Cow) UnForbiddenMatingUpdate() {
 	c.IsForbiddenMating = pasturePb.IsShow_No
 	c.LastForbiddenMatingAt = 0
+	c.BreedStatus = pasturePb.BreedStatus_UnBreed
 }
 
 type CowSlice []*Cow
@@ -369,6 +371,11 @@ func NewEnterCow(pastureId int64, req *pasturePb.EventEnterRequest, penMap map[i
 	case pasturePb.CowSource_Buy:
 		admissionAt = int64(req.EnterAt)
 	}
+
+	isForbiddenMating := pasturePb.IsShow_No
+	if req.BreedStatus == pasturePb.BreedStatus_No_Mating {
+		isForbiddenMating = pasturePb.IsShow_Ok
+	}
 	return &Cow{
 		PastureId:           pastureId,
 		Sex:                 req.Sex,
@@ -387,6 +394,7 @@ func NewEnterCow(pastureId int64, req *pasturePb.EventEnterRequest, penMap map[i
 		PurposeKind:         req.PurposeKind,
 		EleEarNumber:        req.EleEarNumber,
 		IsPregnant:          isPregnant,
+		IsForbiddenMating:   isForbiddenMating,
 		WeaningAt:           int64(req.WeaningAt),
 		BirthAt:             int64(req.BirthAt),
 		AdmissionWeight:     int64(req.Weight * 1000),

+ 22 - 0
model/pen_behavior.go

@@ -11,6 +11,7 @@ type PenBehavior struct {
 	PastureId      int64  `json:"pastureId"`
 	HeatDate       string `json:"heatDate"`
 	ActiveTime     string `json:"activeTime"`
+	Frameid        int32  `json:"frameid"`
 	PenId          int32  `json:"penId"`
 	PenName        string `json:"penName"`
 	CowCount       int32  `json:"cowCount"`
@@ -39,6 +40,27 @@ func (p *PenBehavior) TableName() string {
 	return "pen_behavior"
 }
 
+func NewPenBehavior(data *PenBehaviorData, activeTime string) *PenBehavior {
+	return &PenBehavior{
+		PastureId:  data.PastureId,
+		HeatDate:   data.HeatDate,
+		ActiveTime: activeTime,
+		Frameid:    data.Frameid,
+		PenId:      data.PenId,
+		PenName:    data.PenName,
+		CowCount:   data.CowCount,
+		AvgHigh:    data.AvgHigh,
+		SumRumina:  data.SumRumina,
+		SumIntake:  data.SumIntake,
+		SumRest:    data.SumRest,
+		SumGasp:    data.SumGasp,
+		RuminaRate: data.RuminaRate,
+		IntakeRate: data.IntakeRate,
+		RestRate:   data.RestRate,
+		GaspRate:   data.GaspRate,
+	}
+}
+
 type PenBehaviorSlice []*PenBehavior
 
 func (p PenBehaviorSlice) ToPB() *pasturePb.BarnBehaviorCurveItem {

+ 5 - 6
module/backend/event_base.go

@@ -106,12 +106,6 @@ func (s *StoreEntry) CreateEnter(ctx context.Context, req *pasturePb.EventEnterR
 	}
 
 	newCow := model.NewEnterCow(userModel.AppPasture.Id, req, penMap)
-	defer func() {
-		if err == nil {
-			cowLogs := s.SubmitEventLog(ctx, userModel.AppPasture.Id, newCow, pasturePb.EventType_Enter, req)
-			s.DB.Table(cowLogs.TableName()).Create(cowLogs)
-		}
-	}()
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		if err = tx.Create(newCow).Error; err != nil {
 			return xerr.WithStack(err)
@@ -134,6 +128,11 @@ func (s *StoreEntry) CreateEnter(ctx context.Context, req *pasturePb.EventEnterR
 		if err = tx.Create(eventWeight).Error; err != nil {
 			return xerr.WithStack(err)
 		}
+
+		cowLogs := s.SubmitEventLog(ctx, userModel.AppPasture.Id, newCow, pasturePb.EventType_Enter, req)
+		if err = tx.Table(cowLogs.TableName()).Create(cowLogs).Error; err != nil {
+			return xerr.WithStack(err)
+		}
 		return nil
 	}); err != nil {
 		return xerr.WithStack(err)

+ 10 - 11
module/backend/event_breed_more_two.go → module/backend/event_breed_more_more.go

@@ -140,7 +140,6 @@ func (s *StoreEntry) ForbiddenMatingBatch(ctx context.Context, req *pasturePb.Ev
 	}
 
 	eventForbiddenMatingList := make([]*model.EventForbiddenMating, 0)
-	cowLogList := make([]*model.EventCowLog, 0)
 
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		for _, item := range items {
@@ -149,7 +148,6 @@ func (s *StoreEntry) ForbiddenMatingBatch(ctx context.Context, req *pasturePb.Ev
 				item.ForbiddenMatingReasonsKind, item.ForbiddenMatingReasonsName, item.Remarks, item.OperationUser, userModel.SystemUser)
 
 			eventForbiddenMatingList = append(eventForbiddenMatingList, eventForbiddenMating)
-			cowLogList = append(cowLogList, cowLog)
 
 			// 更新牛只信息
 			item.Cow.ForbiddenMatingUpdate(item.ForbiddenMatingAt)
@@ -158,6 +156,12 @@ func (s *StoreEntry) ForbiddenMatingBatch(ctx context.Context, req *pasturePb.Ev
 				Updates(item.Cow).Error; err != nil {
 				return xerr.WithStack(err)
 			}
+
+			// 记录日志
+			if err = tx.Table(cowLog.TableName()).
+				Create(cowLog).Error; err != nil {
+				return xerr.WithStack(err)
+			}
 		}
 
 		if err = tx.Model(new(model.EventForbiddenMating)).
@@ -165,11 +169,6 @@ func (s *StoreEntry) ForbiddenMatingBatch(ctx context.Context, req *pasturePb.Ev
 			return xerr.WithStack(err)
 		}
 
-		if err = tx.Model(new(model.EventCowLog)).
-			Create(cowLogList).Error; err != nil {
-			return xerr.WithStack(err)
-		}
-
 		return nil
 	}); err != nil {
 		return xerr.WithStack(err)
@@ -223,11 +222,11 @@ func (s *StoreEntry) UnForbiddenMating(ctx context.Context, req *pasturePb.Event
 		return xerr.WithStack(err)
 	}
 
-	if len(req.EarNumber) <= 0 {
+	if len(req.EarNumbers) <= 0 {
 		return xerr.Custom("请选择相关牛只")
 	}
 
-	if len(req.EarNumber) > 50 {
+	if len(req.EarNumbers) > 50 {
 		return xerr.Custom("最多只能添加50条数据")
 	}
 
@@ -235,7 +234,7 @@ func (s *StoreEntry) UnForbiddenMating(ctx context.Context, req *pasturePb.Event
 	if err = s.DB.Model(new(model.EventForbiddenMating)).
 		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("is_show = ?", pasturePb.IsShow_Ok).
-		Where("ear_number IN (?)", req.EarNumber).
+		Where("ear_number IN (?)", req.EarNumbers).
 		Find(&eventForbiddenMatingList).Error; err != nil {
 		return xerr.WithStack(err)
 	}
@@ -271,7 +270,7 @@ func (s *StoreEntry) UnForbiddenMating(ctx context.Context, req *pasturePb.Event
 			}
 
 			cowLog := s.SubmitEventLog(ctx, userModel.AppPasture.Id, cowInfo, pasturePb.EventType_UnForbiddenMating, item)
-			if err = tx.Model(new(model.EventCowLog)).Create(cowLog).Error; err != nil {
+			if err = tx.Table(cowLog.TableName()).Create(cowLog).Error; err != nil {
 				return xerr.WithStack(err)
 			}
 		}

+ 14 - 19
module/crontab/pen_behavior.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"kpt-pasture/model"
 	"sort"
+	"time"
 
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
 	"go.uber.org/zap"
@@ -134,7 +135,6 @@ func (e *Entry) processPenBehaviorData(neckRingOriginalList []*model.NeckRingOri
 				CowCount:  1,
 				AvgHigh:   v.High,
 			}
-
 		}
 	}
 	return penData
@@ -163,29 +163,14 @@ func (e *Entry) savePenBehaviorData(penData map[string]*model.PenBehaviorData) e
 		activeTime := e.calculateActiveTime(data.HeatDate, data.Frameid)
 
 		// 构建保存数据
-		penBehavior := &model.PenBehavior{
-			PastureId:  data.PastureId,
-			HeatDate:   data.HeatDate,
-			ActiveTime: activeTime,
-			PenId:      data.PenId,
-			PenName:    data.PenName,
-			CowCount:   data.CowCount,
-			AvgHigh:    data.AvgHigh,
-			SumRumina:  data.SumRumina,
-			SumIntake:  data.SumIntake,
-			SumRest:    data.SumRest,
-			SumGasp:    data.SumGasp,
-			RuminaRate: data.RuminaRate,
-			IntakeRate: data.IntakeRate,
-			RestRate:   data.RestRate,
-			GaspRate:   data.GaspRate,
-		}
+		penBehavior := model.NewPenBehavior(data, activeTime)
 
 		// 使用 Upsert 操作
 		if err := e.DB.Model(new(model.PenBehavior)).
 			Where("pasture_id = ? AND heat_date = ? AND pen_id = ? AND active_time = ?",
 				penBehavior.PastureId, penBehavior.HeatDate, penBehavior.PenId, penBehavior.ActiveTime).
 			Assign(map[string]interface{}{
+				"frameid":     penBehavior.Frameid,
 				"cow_count":   penBehavior.CowCount,
 				"avg_high":    penBehavior.AvgHigh,
 				"sum_rumina":  penBehavior.SumRumina,
@@ -209,9 +194,19 @@ func (e *Entry) calculateActiveTime(heatDate string, frameid int32) string {
 	// 计算小时和分钟
 	hour := (frameid / 10) * 2
 	minute := (frameid%10)*20 - 1
+	if minute < 0 {
+		minute = 0
+	}
 
+	baseDate, err := time.Parse(model.LayoutDate2, heatDate)
+	if err != nil {
+		zaplog.Error("PenBehavior", zap.Any("calculateActiveTime", err))
+		return ""
+	}
+	baseTime := time.Date(baseDate.Year(), baseDate.Month(), baseDate.Day(), int(hour), 0, 0, 0, baseDate.Location())
+	finalTime := baseTime.Add(time.Duration(minute) * time.Minute)
 	// 构建时间字符串
-	return fmt.Sprintf("%s %02d:%02d", heatDate, hour, minute)
+	return finalTime.Format(model.LayoutTime)
 }
 
 // ifThenElse 条件判断函数