Bläddra i källkod

analysis: 栏舍行为曲线

Yi 1 vecka sedan
förälder
incheckning
9d58ca1da9

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250320095321-6b7069667e91
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250324063941-72d937ade669
 	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

+ 4 - 0
go.sum

@@ -66,6 +66,10 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250320093538-d89d5835caf8 h1:af0uUTZD
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250320093538-d89d5835caf8/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250320095321-6b7069667e91 h1:GBpZpPJV/5FPsv3pUZ6AYEEMjoYrVj4clyFvzjC1t0Y=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250320095321-6b7069667e91/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324061924-bf4abbba60b1 h1:9fg6SXor/LJ94S4oQhrApKq/M2fVSai0i+FrprJ9W90=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324061924-bf4abbba60b1/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324063941-72d937ade669 h1:RWi9BpB1kW42E3A84YsZzaN/+O0C795i2uiLReD7KQs=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324063941-72d937ade669/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=

+ 21 - 0
http/handler/analysis/analysis.go

@@ -309,5 +309,26 @@ func MultiFactorInfantSurvivalRate(c *gin.Context) {
 }
 
 func PenBehaviorAnalysis(c *gin.Context) {
+	var req pasturePb.BarnBehaviorCurveRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.StartAt, valid.Required),
+		valid.Field(&req.EndAt, valid.Required),
+		valid.Field(&req.BarnId, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.PenBehavior(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
 
+	c.JSON(http.StatusOK, res)
 }

+ 19 - 0
model/cow.go

@@ -25,6 +25,7 @@ type Cow struct {
 	AdmissionAge        int32                          `json:"admissionAge"`        // 入场日龄
 	AbortionAge         int32                          `json:"abortionAge"`         // 流产天数
 	LactationAge        int32                          `json:"lactationAge"`        // 泌乳天数
+	DryMilkAge          int32                          `json:"dryMilkAge"`          // 干奶天数
 	CowType             pasturePb.CowType_Kind         `json:"cowType"`             // 牛只类型
 	MilkKind            pasturePb.CowMilk_Kind         `json:"milkKind"`            // 牛只奶属性
 	BreedStatus         pasturePb.BreedStatus_Kind     `json:"breedStatus"`         // 繁殖状态
@@ -76,6 +77,8 @@ func (c *Cow) EventUpdate(weeklyActive int32) {
 		c.CowType = pasturePb.CowType_Weaned_Calf
 	}
 	c.WeeklyActive = weeklyActive
+	c.LactationAge = c.GetLactationAge()
+	c.DryMilkAge = c.GetDryMilkAge()
 }
 
 // EventCalvingUpdate 产犊更新
@@ -499,6 +502,22 @@ func (c *Cow) GetAbortionAge() int32 {
 	return 0
 }
 
+// GetLactationAge 泌乳天数
+func (c *Cow) GetLactationAge() int32 {
+	if c.MilkKind == pasturePb.CowMilk_Lactation {
+		return int32(math.Floor(float64(time.Now().Unix()-c.LastCalvingAt) / 86400))
+	}
+	return c.LactationAge
+}
+
+// GetDryMilkAge 干奶天数
+func (c *Cow) GetDryMilkAge() int32 {
+	if c.MilkKind == pasturePb.CowMilk_Dry_Milk {
+		return int32(math.Floor(float64(time.Now().Unix()-c.LastDryMilkAt) / 86400))
+	}
+	return c.DryMilkAge
+}
+
 type CowWeightRange struct {
 	WeightRange string `json:"weight_range"`
 	Count       int32  `json:"count"`

+ 41 - 0
model/pen_behavior.go

@@ -1,5 +1,11 @@
 package model
 
+import (
+	"kpt-pasture/util"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
 type PenBehavior struct {
 	Id             int64  `json:"id"`
 	PastureId      int64  `json:"pastureId"`
@@ -33,6 +39,41 @@ func (p *PenBehavior) TableName() string {
 	return "pen_behavior"
 }
 
+type PenBehaviorSlice []*PenBehavior
+
+func (p PenBehaviorSlice) ToPB() *pasturePb.BarnBehaviorCurveItem {
+	res := &pasturePb.BarnBehaviorCurveItem{
+		EventTime: &pasturePb.EventTime{
+			FeedTime: make([]string, 0),
+			MilkTime: make([]string, 0),
+		},
+		DateTime:      make([]string, 0),
+		Rumina:        make([]int32, 0),
+		Intake:        make([]int32, 0),
+		Rest:          make([]int32, 0),
+		WeekAvgRumina: make([]int32, 0),
+		WeekAvgIntake: make([]int32, 0),
+		WeekAvgReset:  make([]int32, 0),
+	}
+
+	for _, v := range p {
+		dateTime := ""
+		if v.ActiveTime != "" {
+			dt, _ := util.TimeParseLocal(LayoutTime, v.ActiveTime)
+			dateTime = dt.Format(LayoutHour)
+		}
+		res.DateTime = append(res.DateTime, dateTime)
+		res.Rumina = append(res.Rumina, v.RuminaStd)
+		res.Intake = append(res.Intake, v.IntakeStd)
+		res.Rest = append(res.Rest, v.RestStd)
+		res.WeekAvgRumina = append(res.WeekAvgRumina, v.WeekRuminaRate)
+		res.WeekAvgIntake = append(res.WeekAvgIntake, v.WeekIntakeRate)
+		res.WeekAvgReset = append(res.WeekAvgReset, v.WeekRestRate)
+	}
+
+	return res
+}
+
 type PenBehaviorData struct {
 	PastureId  int64  `json:"pastureId"`
 	PenId      int32  `json:"penId"`

+ 39 - 0
module/backend/analysis_more.go

@@ -0,0 +1,39 @@
+package backend
+
+import (
+	"context"
+	"kpt-pasture/model"
+	"net/http"
+	"time"
+
+	"gitee.com/xuyiping_admin/pkg/xerr"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+func (s *StoreEntry) PenBehavior(ctx context.Context, req *pasturePb.BarnBehaviorCurveRequest) (*pasturePb.BarnBehaviorCurveResponse, error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	if req.StartAt == 0 || req.EndAt == 0 || req.EndAt < req.StartAt {
+		return nil, xerr.Customf("时间范围错误")
+	}
+	startTime := time.Unix(int64(req.StartAt), 0).Format(model.LayoutDate2)
+	endTime := time.Unix(int64(req.EndAt), 0).Format(model.LayoutDate2)
+	penBehaviorList := make([]*model.PenBehavior, 0)
+	if err = s.DB.Model(new(model.PenBehavior)).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Where("pen_id = ?", req.BarnId).
+		Where("heat_date BETWEEN ? AND ?", startTime, endTime).
+		Find(&penBehaviorList).Error; err != nil {
+		return nil, err
+	}
+
+	return &pasturePb.BarnBehaviorCurveResponse{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: model.PenBehaviorSlice(penBehaviorList).ToPB(),
+	}, nil
+}

+ 2 - 0
module/backend/interface.go

@@ -279,6 +279,8 @@ type AnalyseService interface {
 	SaleCowReport(ctx context.Context, req *pasturePb.SaleCowReportRequest) (*pasturePb.SaleCowReportResponse, error)
 	SingleFactorInfantSurvivalRateAnalysis(ctx context.Context, req *pasturePb.SingleFactorPregnancyRateRequest) (*pasturePb.SingleFactorPregnancyRateResponse, error)
 	MultipleFactorAnalysis(ctx context.Context, req *pasturePb.MultiFactorPregnancyRateRequest) (*model.MultiFactorPregnancyRateResponse, error)
+
+	PenBehavior(ctx context.Context, req *pasturePb.BarnBehaviorCurveRequest) (*pasturePb.BarnBehaviorCurveResponse, error)
 }
 
 //go:generate mockgen -destination mock/DashboardService.go -package kptservicemock kpt-pasture/module/backend DashboardService

+ 2 - 1
module/crontab/cow_cron.go

@@ -121,7 +121,8 @@ func (e *Entry) UpdateCowInfo() error {
 		weeklyActive := e.UpdateCowWeeklyHigh(cow)
 		cow.EventUpdate(weeklyActive)
 		if err := e.DB.Model(new(model.Cow)).
-			Select("day_age", "calving_age", "pregnancy_age", "admission_age", "abortion_age", "cow_type", "weekly_active").
+			Select("day_age", "calving_age", "pregnancy_age", "admission_age", "abortion_age", "cow_type",
+				"weekly_active", "lactation_age", "dry_milk_age").
 			Where("id = ?", cow.Id).
 			Updates(cow).Error; err != nil {
 			zaplog.Error("Crontab", zap.Any("UpdateCowDayAge", err))

+ 1 - 0
module/crontab/pen_behavior.go

@@ -72,6 +72,7 @@ func (e *Entry) getNeckRingOriginalList(pastureId, maxPenBehavior int64) ([]*mod
 	var neckRingOriginalList []*model.NeckRingOriginal
 	if err := e.DB.Model(new(model.NeckRingOriginal)).
 		Where("id > ? AND pasture_id = ?", maxPenBehavior, pastureId).
+		Where("cow_id > ?", 0).
 		Order("active_date,neck_ring_number,frameid").
 		Limit(int(defaultLimit)).
 		Find(&neckRingOriginalList).Error; err != nil {