Yi 1 неделя назад
Родитель
Сommit
1cba06a397

+ 1 - 1
go.mod

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

@@ -130,6 +130,12 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250407062707-261478382cce h1:ho0ZTyNj
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250407062707-261478382cce/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250407091052-1c45232ed0aa h1:JK8PEgl8XDRKeM59OCGR/KcEqn/8vqREYUyIQcqseyE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250407091052-1c45232ed0aa/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407093743-ab033b9b99a3 h1:zAqrn31oJ/vma/u6PH2FUXypG8GOTs/3ObyniENlXE8=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407093743-ab033b9b99a3/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407095058-f8caa961fa43 h1:pPnc99fNtmJ4J2B5VrHMB7wwJmiNjc+CBHDcVjDG7T8=
+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/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=

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

@@ -149,3 +149,32 @@ func IndicatorsComparison(c *gin.Context) {
 	}
 	c.JSON(http.StatusOK, res)
 }
+
+// LongTermInfertility 长期不孕
+func LongTermInfertility(c *gin.Context) {
+	var req pasturePb.LongTermInfertilityRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.CalvingAge, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.LongTermInfertility(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}

+ 1 - 0
http/route/cow_api.go

@@ -21,5 +21,6 @@ func CowAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 
 		searchRoute := authRouteGroup(s, "/api/v1/search/")
 		searchRoute.POST("/indicators/comparison", cow.IndicatorsComparison)
+		searchRoute.POST("/cow/long/term/infertility", cow.LongTermInfertility)
 	}
 }

+ 40 - 0
model/cow.go

@@ -284,7 +284,9 @@ func (c CowSlice) ToPB(
 			PenName:                   penName,
 			Lact:                      v.Lact,
 			CowTypeName:               cowTypeMap[v.CowType],
+			CowType:                   v.CowType,
 			BreedStatusName:           breedStatusMap[v.BreedStatus],
+			BreedStatus:               v.BreedStatus,
 			CowKindName:               cowKindMap[v.CowKind],
 			EarNumber:                 v.EarNumber,
 			BirthWeight:               float32(v.BirthWeight) / 1000,
@@ -562,6 +564,44 @@ func (c CowSlice) WeightRangeToPB(penMap map[int32]*Pen) []*pasturePb.CowList {
 	return res
 }
 
+func (c CowSlice) LongTermInfertilityToPB(breedStatusMap map[pasturePb.BreedStatus_Kind]string) []*pasturePb.LongTermInfertility {
+	res := make([]*pasturePb.LongTermInfertility, len(c))
+	for i, v := range c {
+		breedStatusName := ""
+		if breedStatus, ok := breedStatusMap[v.BreedStatus]; ok {
+			breedStatusName = breedStatus
+		}
+		lastCalvingAtFormat := ""
+		if v.LastCalvingAt > 0 {
+			lastCalvingAtFormat = time.Unix(v.LastCalvingAt, 0).Format(LayoutDate2)
+		}
+		lastAbortionAtFormat := ""
+		if v.LastAbortionAt > 0 {
+			lastAbortionAtFormat = time.Unix(v.LastAbortionAt, 0).Format(LayoutDate2)
+		}
+		lastMatingAtFormat := ""
+		if v.LastMatingAt > 0 {
+			lastMatingAtFormat = time.Unix(v.LastMatingAt, 0).Format(LayoutDate2)
+		}
+		res[i] = &pasturePb.LongTermInfertility{
+			CowId:                int32(v.Id),
+			EarNumber:            v.EarNumber,
+			Lact:                 v.Lact,
+			PenId:                v.PenId,
+			CalvingAge:           v.CalvingAge,
+			PenName:              v.PenName,
+			BreedStatusName:      breedStatusName,
+			LastCalvingAtFormat:  lastCalvingAtFormat,
+			LastAbortionAtFormat: lastAbortionAtFormat,
+			LastMatingAtFormat:   lastMatingAtFormat,
+			MatingTimes:          v.MatingTimes,
+			LastBullNumber:       v.LastBullNumber,
+			AbortionTimes:        v.AbortionTimes,
+		}
+	}
+	return res
+}
+
 // CowBehaviorCurveResponse 脖环行为数据
 type CowBehaviorCurveResponse struct {
 	Code int32                 `json:"code"`

+ 43 - 0
module/backend/indicators.go

@@ -92,3 +92,46 @@ func (s *StoreEntry) GetIndicatorsDataByDate(pastureId int64, Kind, date string)
 	}
 	return res, nil
 }
+
+func (s *StoreEntry) LongTermInfertility(ctx context.Context, req *pasturePb.LongTermInfertilityRequest, pagination *pasturePb.PaginationModel) (*pasturePb.LongTermInfertilityResponse, error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	cowList := make([]*model.Cow, 0)
+	pref := s.DB.Model(new(model.Cow)).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Where("calving_age > ?", req.CalvingAge).
+		Where("breed_status != ?", pasturePb.BreedStatus_Pregnant)
+
+	if req.EarNumber != "" {
+		pref.Where("ear_number = ?", req.EarNumber)
+	}
+
+	if req.PenId > 0 {
+		pref.Where("pen_id = ?", req.PenId)
+	}
+
+	var count int64
+	if err = pref.Model(new(model.Cow)).
+		Order("id desc").
+		Count(&count).Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Find(&cowList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	breedStatusMap := s.CowBreedStatusMap()
+	return &pasturePb.LongTermInfertilityResponse{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &pasturePb.LongTermInfertilityData{
+			List:     model.CowSlice(cowList).LongTermInfertilityToPB(breedStatusMap),
+			Total:    int32(count),
+			PageSize: pagination.PageSize,
+			Page:     pagination.Page,
+		},
+	}, nil
+
+}

+ 1 - 0
module/backend/interface.go

@@ -247,6 +247,7 @@ type CowService interface {
 	CowGrowthCurve(ctx context.Context, req *pasturePb.CowGrowthCurveRequest) (*pasturePb.CowGrowthCurveResponse, error)
 
 	IndicatorsComparison(ctx context.Context, req *pasturePb.IndicatorsComparisonRequest) (*model.IndicatorsComparisonResponse, error)
+	LongTermInfertility(ctx context.Context, req *pasturePb.LongTermInfertilityRequest, pagination *pasturePb.PaginationModel) (*pasturePb.LongTermInfertilityResponse, error)
 }
 
 //go:generate mockgen -destination mock/GoodsService.go -package kptservicemock kpt-pasture/module/backend GoodsService

+ 3 - 3
module/crontab/cow_cron.go

@@ -87,15 +87,15 @@ func (e *Entry) Indicators() error {
 		case model.YouthAbortionRate:
 			pastureIndicatorList = e.FindAdultAbortionRate(pastureList, "youth", startTime, endTime)
 		case model.AllDieNumber:
-			pastureIndicatorList = e.FindDepartureNumber(pastureList, pasturePb.DepartureType_Death, startTime, endTime)
+			pastureIndicatorList = e.FindDeathNumber(pastureList, startTime, endTime, false)
 		case model.DiseaseNumber:
 			pastureIndicatorList = e.FindDiseaseNumber(pastureList, startTime, endTime)
 		case model.CureNumber:
 			pastureIndicatorList = e.FindCureNumber(pastureList, startTime, endTime)
 		case model.OutNumber:
-			pastureIndicatorList = e.FindDepartureNumber(pastureList, pasturePb.DepartureType_Out, startTime, endTime)
+			pastureIndicatorList = e.FindDepartureNumber(pastureList, pasturePb.SalesType_Out, startTime, endTime)
 		case model.CalfDieNumber:
-			pastureIndicatorList = e.FindCalfDieNumber(pastureList, pasturePb.DepartureType_Death, startTime, endTime)
+			pastureIndicatorList = e.FindDeathNumber(pastureList, startTime, endTime, true)
 		case model.LactationCow:
 			pastureIndicatorList = e.LactationCow(pastureList, pasturePb.CowMilk_Lactation)
 		case model.DryMilkCow:

+ 11 - 9
module/crontab/cow_indicators_health.go

@@ -31,14 +31,14 @@ func (e *Entry) FindAdultAbortionRate(pastureList []*model.AppPastureList, cowTy
 	return res
 }
 
-func (e *Entry) FindDepartureNumber(pastureList []*model.AppPastureList, departureType pasturePb.DepartureType_Kind, startTime, endTime int64) map[int64]string {
+func (e *Entry) FindDepartureNumber(pastureList []*model.AppPastureList, saleKind pasturePb.SalesType_Kind, startTime, endTime int64) map[int64]string {
 	res := make(map[int64]string)
 	for _, pasture := range pastureList {
 		var count int64
-		if err := e.DB.Model(new(model.EventDeparture)).
+		if err := e.DB.Model(new(model.EventSale)).
 			Where("pasture_id = ?", pasture.Id).
 			Where("departure_at BETWEEN ? AND ?", startTime, endTime).
-			Where("departure_type = ?", departureType).
+			Where("sale_kind = ?", saleKind).
 			Count(&count).Error; err != nil {
 			zaplog.Error("FindAllDieNumber", zap.Any("pasture_id", pasture.Id), zap.Any("err", err))
 		}
@@ -79,16 +79,18 @@ func (e *Entry) FindCureNumber(pastureList []*model.AppPastureList, startTime, e
 	return res
 }
 
-func (e *Entry) FindCalfDieNumber(pastureList []*model.AppPastureList, departureType pasturePb.DepartureType_Kind, startTime, endTime int64) map[int64]string {
+func (e *Entry) FindDeathNumber(pastureList []*model.AppPastureList, startTime, endTime int64, isCalf bool) map[int64]string {
 	res := make(map[int64]string)
 	for _, pasture := range pastureList {
 		var count int64
-		if err := e.DB.Model(new(model.EventDeparture)).
+		pref := e.DB.Model(new(model.EventDeath)).
 			Where("pasture_id = ?", pasture.Id).
-			Where("departure_at BETWEEN ? AND ?", startTime, endTime).
-			Where("departure_type = ?", departureType).
-			Where("day_age <= ?", 60).
-			Count(&count).Error; err != nil {
+			Where("death_at BETWEEN ? AND ?", startTime, endTime)
+		if isCalf {
+			pref.Where("day_age <= ?", 60)
+		}
+
+		if err := pref.Count(&count).Error; err != nil {
 			zaplog.Error("FindAllDieNumber", zap.Any("pasture_id", pasture.Id), zap.Any("err", err))
 		}
 		res[pasture.Id] = fmt.Sprintf("%d", count)