Quellcode durchsuchen

event: 胎次数据

Yi vor 1 Woche
Ursprung
Commit
563652cbe6

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250407102009-df085f2ca575
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250408032224-57e63f411526
 	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

+ 6 - 0
go.sum

@@ -136,6 +136,12 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250407095058-f8caa961fa43 h1:pPnc99fN
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250407095058-f8caa961fa43/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250407102009-df085f2ca575 h1:xIww6nDUvoR961NthJbI4S/12/IkyPDez5oo/EFgqPU=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250407102009-df085f2ca575/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250408010625-534dc8ac81a1 h1:y7GI42qIScacVzlwCrvXqy5QjIxJhm/4vRWyx3WCxwA=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250408010625-534dc8ac81a1/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250408020446-8115565fe86e h1:wETx6NGE8Xsf2p8nvhq2mg8zujiOxCfequWhcCCGZ5s=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250408020446-8115565fe86e/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250408032224-57e63f411526 h1:oe8HolRGDYj30IltPmUMFq6i0+H8pJsj533WkjdIHSM=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250408032224-57e63f411526/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=

+ 22 - 0
http/handler/cow/cow.go

@@ -127,6 +127,28 @@ func GrowthCurve(c *gin.Context) {
 	ginutil.JSONResp(c, res)
 }
 
+func LactCurve(c *gin.Context) {
+	var req pasturePb.CowLactCurveRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.CowId, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.CowLactCurve(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
 // IndicatorsComparison 指标对比
 func IndicatorsComparison(c *gin.Context) {
 	var req pasturePb.IndicatorsComparisonRequest

+ 1 - 0
http/route/cow_api.go

@@ -18,6 +18,7 @@ func CowAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		cowRoute.POST("/event/list", cow.EventList)
 		cowRoute.POST("/behavior/curve", cow.BehaviorCurve)
 		cowRoute.POST("/growth/curve", cow.GrowthCurve)
+		cowRoute.POST("/lact/curve", cow.LactCurve)
 
 		searchRoute := authRouteGroup(s, "/api/v1/search/")
 		searchRoute.POST("/indicators/comparison", cow.IndicatorsComparison)

+ 6 - 1
model/cow.go

@@ -32,6 +32,7 @@ type Cow struct {
 	CowKind               pasturePb.CowKind_Kind         `json:"cowKind"`               // 牛只品种
 	BirthWeight           int64                          `json:"birthWeight"`           // 出生体重
 	CurrentWeight         int64                          `json:"currentWeight"`         // 当前体重
+	CurrentHeight         int64                          `json:"currentHeight"`         // 当前身高
 	AdmissionWeight       int64                          `json:"admissionWeight"`       // 入场体重
 	SourceKind            pasturePb.CowSource_Kind       `json:"sourceKind"`            // 来源哪里
 	PurposeKind           pasturePb.Purpose_Kind         `json:"purposeKind"`           // 用途
@@ -68,6 +69,7 @@ func (c *Cow) TableName() string {
 	return "cow"
 }
 
+// EventUpdate 牛只基本信息维护
 func (c *Cow) EventUpdate(weeklyActive int32) {
 	c.DayAge = c.GetDayAge()
 	c.CalvingAge = c.GetCalvingAge()
@@ -123,11 +125,12 @@ func (c *Cow) EventAbortionUpdate(abortionAt int64, isLact pasturePb.IsShow_Kind
 }
 
 // EventWeightUpdate 称重更新
-func (c *Cow) EventWeightUpdate(weight int64, weightAt int64) {
+func (c *Cow) EventWeightUpdate(weight, height, weightAt int64) {
 	c.LastSecondWeight = c.CurrentWeight
 	c.LastSecondWeightAt = c.LastWeightAt
 	c.LastWeightAt = weightAt
 	c.CurrentWeight = weight
+	c.CurrentHeight = height
 }
 
 // EventHealthStatusUpdate 健康状态更新
@@ -291,6 +294,7 @@ func (c CowSlice) ToPB(
 			EarNumber:                 v.EarNumber,
 			BirthWeight:               float32(v.BirthWeight) / 1000,
 			CurrentWeight:             float32(v.CurrentWeight) / 1000,
+			CurrentHeight:             int32(v.CurrentHeight),
 			DayAge:                    v.DayAge,
 			SourceName:                cowSourceMap[v.SourceKind],
 			MotherNumber:              v.MotherNumber,
@@ -371,6 +375,7 @@ func NewEnterCow(pastureId int64, req *pasturePb.EventEnterRequest, penMap map[i
 	if req.BreedStatus == pasturePb.BreedStatus_No_Mating {
 		isForbiddenMating = pasturePb.IsShow_Ok
 	}
+
 	return &Cow{
 		PastureId:           pastureId,
 		Sex:                 req.Sex,

+ 37 - 0
model/cow_lact.go

@@ -0,0 +1,37 @@
+package model
+
+import (
+	"time"
+)
+
+type CowLact struct {
+	Id        int64  `json:"id"`
+	PastureId int64  `json:"pastureId"`
+	CowId     int64  `json:"cowId"`
+	EarNumber string `json:"earNumber"`
+	Lact      int32  `json:"lact"`
+	StartTime string `json:"startTime"`
+	CreatedAt int64  `json:"createdAt"`
+	UpdatedAt int64  `json:"updatedAt"`
+}
+
+func (c *CowLact) TableName() string {
+	return "cow_lact"
+}
+
+func NewCowLact(pastureId int64, cow *Cow) *CowLact {
+	startTime := ""
+	if cow.Lact == 0 {
+		startTime = time.Unix(cow.AdmissionAt, 0).Local().Format(LayoutDate2)
+	} else {
+		startTime = time.Unix(cow.LastCalvingAt, 0).Local().Format(LayoutDate2)
+	}
+
+	return &CowLact{
+		PastureId: pastureId,
+		CowId:     cow.Id,
+		EarNumber: cow.EarNumber,
+		Lact:      cow.Lact,
+		StartTime: startTime,
+	}
+}

+ 39 - 0
module/backend/cow.go

@@ -292,3 +292,42 @@ func (s *StoreEntry) CowGrowthCurve(ctx context.Context, req *pasturePb.CowGrowt
 		Data: model.EventWeightSlice(weightList).ToPB(),
 	}, nil
 }
+
+func (s *StoreEntry) CowLactCurve(ctx context.Context, req *pasturePb.CowLactCurveRequest) (*pasturePb.CowLactCurveResponse, error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	cowInfo, err := s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, int64(req.CowId))
+	if err != nil {
+		return nil, xerr.Customf("错误的牛只信息: %d", req.CowId)
+	}
+
+	weightList := make([]*model.EventWeight, 0)
+	if err = s.DB.Table(new(model.EventWeight).TableName()).
+		Where("cow_id = ?", cowInfo.Id).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Order("weight_at").
+		Find(&weightList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return &pasturePb.CowLactCurveResponse{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &pasturePb.CowLactCurveData{
+			DateTime:            nil,
+			WeekAvgMilk:         nil,
+			DayMilk:             nil,
+			DHI:                 nil,
+			MilkProductionTrend: nil,
+			DayHigh:             nil,
+			DayRumina:           nil,
+			DayIntake:           nil,
+			DayInactive:         nil,
+			DayChew:             nil,
+			DayImmobility:       nil,
+			EstrusWarning:       nil,
+		},
+	}, nil
+}

+ 15 - 4
module/backend/event_base.go

@@ -107,13 +107,23 @@ func (s *StoreEntry) CreateEnter(ctx context.Context, req *pasturePb.EventEnterR
 
 	newCow := model.NewEnterCow(userModel.AppPasture.Id, req, penMap)
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-		if err = tx.Create(newCow).Error; err != nil {
+		// 新增牛只信息
+		if err = tx.Model(new(model.Cow)).Create(newCow).Error; err != nil {
 			return xerr.WithStack(err)
 		}
+
+		// 新增入场事件
 		newEventEnter := model.NewEventEnter(userModel.AppPasture.Id, newCow.Id, req)
-		if err = tx.Create(newEventEnter).Error; err != nil {
+		if err = tx.Model(new(model.EventEnter)).Create(newEventEnter).Error; err != nil {
 			return xerr.WithStack(err)
 		}
+
+		// 新增胎次数据
+		newCowLact := model.NewCowLact(userModel.AppPasture.Id, newCow)
+		if err = tx.Model(new(model.CowLact)).Create(newCowLact).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
 		eventWeight := model.NewEventWeight(
 			userModel.AppPasture.Id,
 			newCow,
@@ -125,10 +135,11 @@ func (s *StoreEntry) CreateEnter(ctx context.Context, req *pasturePb.EventEnterR
 				OperationName: req.OperationName,
 				Weight:        req.Weight,
 			})
-		if err = tx.Create(eventWeight).Error; err != nil {
+		if err = tx.Model(new(model.EventWeight)).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)
@@ -379,7 +390,7 @@ func (s *StoreEntry) WeightBatch(ctx context.Context, req *pasturePb.BatchEventW
 			}
 
 			// 更新牛只信息
-			cow.EventWeightUpdate(int64(item.Weight*1000), int64(item.WeightAt))
+			cow.EventWeightUpdate(int64(item.Weight*1000), int64(item.Height), int64(item.WeightAt))
 			if err = tx.Model(new(model.Cow)).
 				Select("last_second_weight_at", "last_second_weight", "last_weight_at", "current_weight").
 				Where("id = ?", cow.Id).

+ 12 - 0
module/backend/event_breed.go

@@ -134,6 +134,12 @@ func (s *StoreEntry) CalvingCreate(ctx context.Context, req *pasturePb.EventCalv
 				return xerr.WithStack(err)
 			}
 
+			// 新增胎次数据
+			newCowLact := model.NewCowLact(userModel.AppPasture.Id, newCalfCow)
+			if err = tx.Model(new(model.CowLact)).Create(newCowLact).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+
 			// 犊牛日志
 			cowLogs := s.SubmitEventLog(ctx, userModel.AppPasture.Id, newCalfCow, pasturePb.EventType_Birth, calf)
 			if err = tx.Table(cowLogs.TableName()).Create(cowLogs).Error; err != nil {
@@ -150,6 +156,12 @@ func (s *StoreEntry) CalvingCreate(ctx context.Context, req *pasturePb.EventCalv
 			return xerr.WithStack(err)
 		}
 
+		// 更新牛只胎次信息
+		newCowLact := model.NewCowLact(userModel.AppPasture.Id, cow)
+		if err = tx.Model(new(model.CowLact)).Create(newCowLact).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
 		// 母牛事件日志
 		cowLogs := s.SubmitEventLog(ctx, userModel.AppPasture.Id, cow, pasturePb.EventType_Calving, req)
 		if err = tx.Table(cowLogs.TableName()).Create(cowLogs).Error; err != nil {

+ 9 - 1
module/backend/event_breed_more.go

@@ -184,11 +184,19 @@ func (s *StoreEntry) AbortionCreateBatch(ctx context.Context, req *pasturePb.Eve
 
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		for _, item := range eventAbortionModelList {
+			// 新增流产事件
 			if err = tx.Create(item.EventAbortion).Error; err != nil {
 				return xerr.WithStack(err)
 			}
-
+			// 更新流产数据
 			item.Cow.EventAbortionUpdate(item.EventAbortion.AbortionAt, item.IsLact)
+			// 更新牛只胎次数据
+			if item.IsLact == pasturePb.IsShow_Ok {
+				newCowLact := model.NewCowLact(userModel.AppPasture.Id, item.Cow)
+				if err = tx.Create(newCowLact).Error; err != nil {
+					return xerr.WithStack(err)
+				}
+			}
 			// 更新牛只状态
 			if err = tx.Model(new(model.Cow)).
 				Select("is_pregnant", "last_abortion_at", "breed_status").

+ 2 - 0
module/backend/event_cow_log.go

@@ -31,6 +31,8 @@ func (s *StoreEntry) SubmitEventLog(ctx context.Context, pastureId int64, cow *m
 		eventAt = int64(data.EnterAt)
 		remarks = data.Remarks
 		sourceMap := s.CowSourceMap()
+		operationUser.Id = int64(data.OperationId)
+		operationUser.Name = data.OperationName
 		sex := "公"
 		if data.Sex == pasturePb.Genders_Female {
 			sex = "母"

+ 1 - 0
module/backend/interface.go

@@ -245,6 +245,7 @@ type CowService interface {
 	EventList(ctx context.Context, req *pasturePb.SearchCowEventListRequest, pagination *pasturePb.PaginationModel) (*pasturePb.CowEventListResponse, error)
 	BehaviorCurve(ctx context.Context, req *pasturePb.CowBehaviorCurveRequest) (*model.CowBehaviorCurveResponse, error)
 	CowGrowthCurve(ctx context.Context, req *pasturePb.CowGrowthCurveRequest) (*pasturePb.CowGrowthCurveResponse, error)
+	CowLactCurve(ctx context.Context, req *pasturePb.CowLactCurveRequest) (*pasturePb.CowLactCurveResponse, error)
 
 	IndicatorsComparison(ctx context.Context, req *pasturePb.IndicatorsComparisonRequest) (*model.IndicatorsComparisonResponse, error)
 	LongTermInfertility(ctx context.Context, req *pasturePb.LongTermInfertilityRequest, pagination *pasturePb.PaginationModel) (*pasturePb.LongTermInfertilityResponse, error)