Bladeren bron

analysis: 配种及时性图表

Yi 7 maanden geleden
bovenliggende
commit
df5635b7bd

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20241010074707-9018744d83d1
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20241011085352-37867c4fa0d6
 	gitee.com/xuyiping_admin/pkg v0.0.0-20241010101255-0c6bd229b939
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/eko/gocache v1.1.0

+ 4 - 0
go.sum

@@ -72,6 +72,10 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20241010014128-49b4c7bbdc67 h1:P9y7LRQu
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241010014128-49b4c7bbdc67/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241010074707-9018744d83d1 h1:8djrve8OC4SKqeUled+rT5AUUg37eYR9JivmX15mqfU=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241010074707-9018744d83d1/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241011072822-c977a14e2254 h1:yH8qiJU8s8JpVfedf8BuoT/y2Vl9Z3ayqpfyVGdW1BQ=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241011072822-c977a14e2254/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241011085352-37867c4fa0d6 h1:FnfIC2wrku60IFnSLZz1WSiYOJrfQwpNeDMepp/h8hI=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241011085352-37867c4fa0d6/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/pkg v0.0.0-20231218082641-aac597b8a015 h1:dfb5dRd57L2HKjdwLT93UFmPYFPOmEl56gtZmqcNnaE=
 gitee.com/xuyiping_admin/pkg v0.0.0-20231218082641-aac597b8a015/go.mod h1:Fk4GYI/v0IK3XFrm1Gn+VkgCz5Y7mfswD5hsTJYOG6A=
 gitee.com/xuyiping_admin/pkg v0.0.0-20241008063555-121a776fd331 h1:qJcpJ3o+O7uxDqR0I9LijQmi607IKvhf4mGum/ZUPT0=

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

@@ -50,3 +50,27 @@ func WeightRange(c *gin.Context) {
 
 	ginutil.JSONResp(c, res)
 }
+
+func MatingTimeLy(c *gin.Context) {
+	var req pasturePb.MatingTimelyRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.StartDayAt, valid.Required),
+		valid.Field(&req.EndDayAt, valid.Required),
+		valid.Field(&req.CowType, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.MatingTimely(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}

+ 1 - 0
http/route/analysis_api.go

@@ -15,5 +15,6 @@ func AnalysisAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		pastureRoute := authRouteGroup(s, "/api/v1/analysis/")
 		pastureRoute.POST("/growth/curve", analysis.GrowthCurve)
 		pastureRoute.POST("/weight/range", analysis.WeightRange)
+		pastureRoute.POST("/mating/timely", analysis.MatingTimeLy)
 	}
 }

+ 4 - 4
model/event_cow_same_time.go

@@ -14,9 +14,9 @@ type EventCowSameTime struct {
 	Lact          int32                       `json:"lact"`
 	SameTimeId    int64                       `json:"sameTimeId"`
 	SameTimeType  pasturePb.SameTimeType_Kind `json:"sameTimeType"`
-	PlanDay       string                      `json:"planDay"`
-	EndDay        string                      `json:"endDay"`
-	RealityDay    string                      `json:"realityDay"`
+	PlanDay       int64                       `json:"planDay"`
+	EndDay        int64                       `json:"endDay"`
+	RealityDay    int64                       `json:"realityDay"`
 	Status        pasturePb.IsShow_Kind       `json:"status"`
 	DrugsId       int64                       `json:"drugsId"`
 	Unit          pasturePb.Unit_Kind         `json:"unit"`
@@ -31,7 +31,7 @@ func (s *EventCowSameTime) TableName() string {
 	return "event_cow_same_time"
 }
 
-func NewCowSameTimeDetailList(cowList []*Cow, sameTimeId int64, planTime string, sameTimeType pasturePb.SameTimeType_Kind) []*EventCowSameTime {
+func NewCowSameTimeDetailList(cowList []*Cow, sameTimeId int64, planTime int64, sameTimeType pasturePb.SameTimeType_Kind) []*EventCowSameTime {
 	res := make([]*EventCowSameTime, len(cowList))
 	for i, cow := range cowList {
 		res[i] = &EventCowSameTime{

+ 36 - 8
model/event_mating.go

@@ -1,16 +1,22 @@
 package model
 
-import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+import (
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
 
 type EventMating struct {
 	Id                int64                           `json:"id"`
 	CowId             int64                           `json:"cowId"`
 	DayAge            int64                           `json:"dayAge"`
 	Lact              int8                            `json:"lact"`
+	CowType           pasturePb.CowType_Kind          `json:"cowType"`
 	CalvingAge        int32                           `json:"calvingAge"`
-	PlanDay           string                          `json:"planDay"`
-	EndDay            string                          `json:"endDay"`
-	RealityDay        string                          `json:"realityDay"`
+	PlanDay           int64                           `json:"planDay"`
+	EndDay            int64                           `json:"endDay"`
+	CalvingAt         int64                           `json:"calvingAt"`
+	RealityDay        int64                           `json:"realityDay"`
 	Status            pasturePb.IsShow_Kind           `json:"status"`
 	MatingNumber      int64                           `json:"matingNumber"`
 	MatingResult      pasturePb.MatingResult_Kind     `json:"matingResult"`
@@ -28,10 +34,12 @@ func (e *EventMating) TableName() string {
 	return "event_mating"
 }
 
-func NewEventMating(cow *Cow, planDay string) *EventMating {
+func NewEventMating(cow *Cow, planDay int64) *EventMating {
 	return &EventMating{
 		CowId:            cow.Id,
 		Lact:             int8(cow.Lact),
+		CowType:          cow.CowType,
+		CalvingAt:        cow.CalvingAt,
 		PlanDay:          planDay,
 		EndDay:           planDay,
 		MatingResult:     pasturePb.MatingResult_Invalid,
@@ -40,7 +48,7 @@ func NewEventMating(cow *Cow, planDay string) *EventMating {
 	}
 }
 
-func NewEventMatingList(cowList []*Cow, planDay string) []*EventMating {
+func NewEventMatingList(cowList []*Cow, planDay int64) []*EventMating {
 	var matingList []*EventMating
 	for _, cow := range cowList {
 		matingList = append(matingList, NewEventMating(cow, planDay))
@@ -59,8 +67,8 @@ func (e EventMatingSlice) ToPB(exposeEstrusTypeMap map[pasturePb.ExposeEstrusTyp
 			DayAge:               int32(v.DayAge),
 			Lact:                 int32(v.Lact),
 			CalvingAge:           v.CalvingAge,
-			PlanDay:              v.PlanDay,
-			RealityDay:           v.RealityDay,
+			PlanDay:              time.Unix(v.PlanDay, 0).Format(LayoutDate2),
+			RealityDay:           time.Unix(v.RealityDay, 0).Format(LayoutDate2),
 			ExposeEstrusType:     v.ExposeEstrusType,
 			ExposeEstrusTypeName: exposeEstrusTypeMap[v.ExposeEstrusType],
 			FrozenSemenNumber:    v.FrozenSemenNumber,
@@ -132,3 +140,23 @@ func (s CowMatingBodySlice) ToPB(
 	}
 	return res
 }
+
+type MatingTimelyChart struct {
+	CalvingAge int32  `json:"calvingAge"`
+	RealityDay string `json:"realityDay"`
+	LactGroup  string `json:"lactGroup"`
+}
+
+func (e EventMatingSlice) ToPB2() []*pasturePb.CowList {
+	res := make([]*pasturePb.CowList, len(e))
+	for i, v := range e {
+		res[i] = &pasturePb.CowList{
+			CowId:           int32(v.CowId),
+			DayAge:          int32(v.DayAge),
+			CalvingAge:      v.CalvingAge,
+			MatingAtFormat:  time.Unix(v.RealityDay, 0).Format(LayoutDate2),
+			CalvingAtFormat: time.Unix(v.CalvingAt, 0).Format(LayoutDate2),
+		}
+	}
+	return res
+}

+ 90 - 0
module/backend/analysis.go

@@ -2,6 +2,7 @@ package backend
 
 import (
 	"context"
+	"fmt"
 	"kpt-pasture/model"
 	"net/http"
 	"strings"
@@ -148,3 +149,92 @@ func (s *StoreEntry) WeightRange(ctx context.Context, req *pasturePb.WeightRange
 		},
 	}, nil
 }
+
+func (s *StoreEntry) MatingTimely(ctx context.Context, req *pasturePb.MatingTimelyRequest) (*pasturePb.MatingTimelyResponse, error) {
+	matingTimelyChart := make([]*model.MatingTimelyChart, 0)
+	sql := `SELECT calving_age,cow_type, DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') AS reality_day, lact_group
+		FROM (
+			SELECT calving_age, cow_type,reality_day, '0' AS lact_group
+			FROM event_mating
+			WHERE lact = 0 AND status = 1
+			UNION ALL
+			SELECT calving_age,cow_type, reality_day, '1' AS lact_group
+			FROM event_mating
+			WHERE lact = 1 AND status = 1
+			UNION ALL
+			SELECT calving_age,cow_type,  reality_day, '2' AS lact_group
+			FROM event_mating
+			WHERE lact = 2 AND status = 1
+			UNION ALL
+			SELECT calving_age, cow_type, reality_day, '3+' AS lact_group
+			FROM event_mating
+			WHERE lact >= 3 AND status = 1
+		) AS subquery WHERE 1 = 1 `
+
+	whereSql := ""
+	if req.CowType > 0 {
+		whereSql += fmt.Sprintf("AND cow_type = %d ", req.CowType)
+	}
+
+	if req.StartDayAt > 0 && req.EndDayAt > 0 {
+		whereSql += fmt.Sprintf("AND reality_day BETWEEN %d AND %d", req.StartDayAt, req.EndDayAt)
+	}
+	if err := s.DB.Raw(sql).Find(&matingTimelyChart).Error; err != nil {
+		return nil, err
+	}
+
+	chart := &pasturePb.MatingTimelyChart{
+		Lact0: make([]int32, 0),
+		Lact1: make([]int32, 0),
+		Lact2: make([]int32, 0),
+		Lact3: make([]int32, 0),
+	}
+	if len(matingTimelyChart) == 0 {
+		return &pasturePb.MatingTimelyResponse{
+			Code:    http.StatusOK,
+			Message: "ok",
+			Data: &pasturePb.MatingTimelyData{
+				CowList: make([]*pasturePb.CowList, 0),
+				Chart:   chart,
+			},
+		}, nil
+	}
+
+	for _, v := range matingTimelyChart {
+		switch v.LactGroup {
+		case "0":
+			chart.Lact0 = append(chart.Lact0, v.CalvingAge)
+		case "1":
+			chart.Lact1 = append(chart.Lact1, v.CalvingAge)
+		case "2":
+			chart.Lact2 = append(chart.Lact2, v.CalvingAge)
+		case "3+":
+			chart.Lact3 = append(chart.Lact3, v.CalvingAge)
+		}
+	}
+
+	// 牛只详情列表
+	eventMatingList := make([]*model.EventMating, 0)
+	pref := s.DB.Model(new(model.EventMating)).
+		Where("status = ?", pasturePb.IsShow_Ok)
+	if req.CowType > 0 {
+		pref.Where("cow_type = ?", req.CowType)
+	}
+
+	if req.StartDayAt > 0 && req.EndDayAt > 0 {
+		pref.Where("reality_day BETWEEN ? AND ?", req.StartDayAt, req.EndDayAt)
+	}
+
+	if err := pref.Find(&eventMatingList).Error; err != nil {
+		return nil, err
+	}
+
+	return &pasturePb.MatingTimelyResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.MatingTimelyData{
+			CowList: model.EventMatingSlice(eventMatingList).ToPB2(),
+			Chart:   chart,
+		},
+	}, nil
+}

+ 11 - 11
module/backend/event_breed.go

@@ -5,7 +5,6 @@ import (
 	"encoding/json"
 	"fmt"
 	"kpt-pasture/model"
-	"kpt-pasture/util"
 	"net/http"
 	"strings"
 	"time"
@@ -82,7 +81,7 @@ func (s *StoreEntry) CalvingCreate(ctx context.Context, req *pasturePb.EventCalv
 		if err = tx.Model(new(model.EventCalving)).
 			Where("id = ?", newEventCalving.Id).
 			Updates(map[string]interface{}{
-				"reality_day":   time.Unix(int64(req.CalvingAt), 0).Format(model.LayoutTime),
+				"reality_day":   int64(req.CalvingAt),
 				"day_age":       cow.DayAge,
 				"lact":          cow.Lact + 1,
 				"pregnancy_age": cow.PregnancyAge,
@@ -110,14 +109,15 @@ func (s *StoreEntry) CalvingCreate(ctx context.Context, req *pasturePb.EventCalv
 			return xerr.WithStack(err)
 		}
 
-		if err = tx.Model(new(model.Cow)).Where("id = ?", cow.Id).Updates(map[string]interface{}{
-			"calving_age":     0,
-			"lact":            cow.Lact + 1,
-			"breed_status":    pasturePb.BreedStatus_Calving,
-			"is_pregnant":     pasturePb.IsShow_No,
-			"calving_at":      0,
-			"last_calving_at": time.Now().Unix(),
-		}).Error; err != nil {
+		if err = tx.Model(new(model.Cow)).Where("id = ?", cow.Id).
+			Updates(map[string]interface{}{
+				"calving_age":     0,
+				"lact":            cow.Lact + 1,
+				"breed_status":    pasturePb.BreedStatus_Calving,
+				"is_pregnant":     pasturePb.IsShow_No,
+				"calving_at":      int64(req.CalvingAt),
+				"last_calving_at": time.Now().Unix(),
+			}).Error; err != nil {
 			return xerr.WithStack(err)
 		}
 
@@ -340,7 +340,7 @@ func (s *StoreEntry) MatingCreate(ctx context.Context, req *pasturePb.EventMatin
 		}
 
 		// 判断当前输精时间距离上次输精时间是否超过2天,如果超过则更新为复配状态
-		itemBeforeTwoDays := nowTime.Sub(time.Unix(util.TimeParseLocalUnix(itemEventMating.RealityDay), 0)).Hours()
+		itemBeforeTwoDays := nowTime.Sub(time.Unix(itemEventMating.RealityDay, 0)).Hours()
 		if count > 0 && itemBeforeTwoDays > 48 {
 			matingUpdateIds = append(matingUpdateIds, itemEventMating.Id)
 		}

+ 1 - 0
module/backend/interface.go

@@ -205,6 +205,7 @@ type GoodsService interface {
 type AnalyseService interface {
 	GrowthCurve(ctx context.Context, req *pasturePb.SearchGrowthCurvesRequest) (*pasturePb.GrowthCurvesResponse, error)
 	WeightRange(ctx context.Context, req *pasturePb.WeightRangeRequest) (*pasturePb.WeightRangeResponse, error)
+	MatingTimely(ctx context.Context, req *pasturePb.MatingTimelyRequest) (*pasturePb.MatingTimelyResponse, error)
 }
 
 //go:generate mockgen -destination mock/DashboardService.go -package kptservicemock kpt-pasture/module/backend DashboardService

+ 5 - 5
module/crontab/work_cron.go

@@ -42,9 +42,9 @@ func (e *Entry) GenerateCalendarBySameTimePlan(cowList []*model.Cow, sameTime *m
 	var _ = json.Unmarshal([]byte(sameTime.CollateNodes), &collateNodes)
 	nowTime := time.Now()
 	for i, collateNode := range collateNodes {
-		showDay := nowTime.Format(model.LayoutDate2)
+		showDay := nowTime
 		if i > 0 {
-			showDay = nowTime.Add(time.Hour * 24 * time.Duration(collateNode.NextNodeDay)).Format(model.LayoutDate2)
+			showDay = nowTime.Add(time.Hour * 24 * time.Duration(collateNode.NextNodeDay))
 		}
 
 		calendarName := backend.CalendarTypeMap()[pasturePb.CalendarType_PG]
@@ -54,7 +54,7 @@ func (e *Entry) GenerateCalendarBySameTimePlan(cowList []*model.Cow, sameTime *m
 			calendarName = backend.CalendarTypeMap()[pasturePb.CalendarType_Mating]
 			calendarType = pasturePb.CalendarType_Mating
 			histCount = e.GetTowardTaiCowSum()
-			newEventMatingList = append(newEventMatingList, model.NewEventMatingList(newCowList, showDay)...)
+			newEventMatingList = append(newEventMatingList, model.NewEventMatingList(newCowList, showDay.Unix())...)
 			newEventItemList = append(newEventItemList, model.NewEventItemList(newCowList, calendarType)...)
 		} else {
 			if collateNode.SameTimeType == pasturePb.SameTimeType_RnGH {
@@ -65,7 +65,7 @@ func (e *Entry) GenerateCalendarBySameTimePlan(cowList []*model.Cow, sameTime *m
 			histCount = e.GetTowardSameTimeCowSum(sameTime.Id, collateNode.SameTimeType)
 			newSameTimeCowDetailList = append(
 				newSameTimeCowDetailList,
-				model.NewCowSameTimeDetailList(newCowList, sameTime.Id, showDay, collateNode.SameTimeType)...,
+				model.NewCowSameTimeDetailList(newCowList, sameTime.Id, showDay.Unix(), collateNode.SameTimeType)...,
 			)
 		}
 
@@ -73,7 +73,7 @@ func (e *Entry) GenerateCalendarBySameTimePlan(cowList []*model.Cow, sameTime *m
 			Name:         calendarName,
 			CalendarType: calendarType,
 			Count:        int32(len(newCowList)) + int32(histCount),
-			ShowDay:      showDay,
+			ShowDay:      time.Unix(showDay.Unix(), 0).Format(model.LayoutDate2),
 			IsShow:       pasturePb.IsShow_Ok,
 		})
 	}