Ver Fonte

analysis: 体重范围图

Yi há 6 meses atrás
pai
commit
2ba94913e0

+ 2 - 2
go.mod

@@ -3,8 +3,8 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20241010014128-49b4c7bbdc67
-	gitee.com/xuyiping_admin/pkg v0.0.0-20241008063555-121a776fd331
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20241010074707-9018744d83d1
+	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
 	github.com/getsentry/sentry-go v0.23.0

+ 4 - 0
go.sum

@@ -70,10 +70,14 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20240926092955-f27b0fa96718 h1:QB8QkNqf
 gitee.com/xuyiping_admin/go_proto v0.0.0-20240926092955-f27b0fa96718/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241010014128-49b4c7bbdc67 h1:P9y7LRQu0PJrYBTlVD39lriGPwYiqPinXdklUqPKiMI=
 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/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=
 gitee.com/xuyiping_admin/pkg v0.0.0-20241008063555-121a776fd331/go.mod h1:Fk4GYI/v0IK3XFrm1Gn+VkgCz5Y7mfswD5hsTJYOG6A=
+gitee.com/xuyiping_admin/pkg v0.0.0-20241010101255-0c6bd229b939 h1:ubU0RZ/fiElF9NfDDaJh+czYryqKSoEiMd4ec1emtH8=
+gitee.com/xuyiping_admin/pkg v0.0.0-20241010101255-0c6bd229b939/go.mod h1:Fk4GYI/v0IK3XFrm1Gn+VkgCz5Y7mfswD5hsTJYOG6A=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=

+ 27 - 1
http/handler/analysis/analysis.go

@@ -4,6 +4,8 @@ import (
 	"kpt-pasture/http/middleware"
 	"net/http"
 
+	"gitee.com/xuyiping_admin/pkg/valid"
+
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	"gitee.com/xuyiping_admin/pkg/apierr"
 	"gitee.com/xuyiping_admin/pkg/ginutil"
@@ -22,5 +24,29 @@ func GrowthCurve(c *gin.Context) {
 		apierr.ClassifiedAbort(c, err)
 		return
 	}
-	c.JSON(http.StatusOK, res)
+
+	ginutil.JSONResp(c, res)
+}
+
+func WeightRange(c *gin.Context) {
+	var req pasturePb.WeightRangeRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.MaxWeight, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.WeightRange(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, res)
 }

+ 1 - 0
http/route/analysis_api.go

@@ -14,5 +14,6 @@ func AnalysisAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		// pasture API 组  牧场管理
 		pastureRoute := authRouteGroup(s, "/api/v1/analysis/")
 		pastureRoute.POST("/growth/curve", analysis.GrowthCurve)
+		pastureRoute.POST("/weight/range", analysis.WeightRange)
 	}
 }

+ 31 - 2
model/cow.go

@@ -201,7 +201,8 @@ func (c *Cow) GetDayWeight() float64 {
 		if days <= 0 {
 			return 0
 		}
-		return math.Round(1.0 * float64(c.CurrentWeight-c.LastSecondWeight) / float64(days))
+		dayWeight := math.Round(1.0 * float64(c.CurrentWeight-c.LastSecondWeight) / float64(days))
+		return dayWeight / 1000
 	}
 	return 0
 }
@@ -214,7 +215,7 @@ func (c *Cow) GetAverageDailyWeight() float64 {
 			return 0
 		}
 		dailyWeight := math.Round(1.0 * float64(c.CurrentWeight-c.BirthWeight) / float64(days))
-		return dailyWeight
+		return dailyWeight / 1000
 	}
 	return 0
 }
@@ -226,3 +227,31 @@ func (c *Cow) GetAbortionAge() int32 {
 	return 0
 
 }
+
+type CowWeightRange struct {
+	WeightRange string `json:"weight_range"`
+	Count       int32  `json:"count"`
+}
+
+func (c CowSlice) WeightRangeToPB(penMap map[int32]*Pen) []*pasturePb.CowList {
+	res := make([]*pasturePb.CowList, len(c))
+	for i, v := range c {
+		penName := ""
+		if pen, ok := penMap[v.PenId]; ok {
+			penName = pen.Name
+		}
+		res[i] = &pasturePb.CowList{
+			CowId:                  int32(v.Id),
+			DayAge:                 v.DayAge,
+			DailyWeightGain:        float32(v.GetDayWeight()),
+			AverageDailyWeightGain: float32(v.GetAverageDailyWeight()),
+			EarNumber:              v.EarNumber,
+			PenName:                penName,
+			BirthAt:                int32(v.BirthAt),
+			BirthWeight:            float32(v.BirthWeight) / 1000,
+			CurrentWeight:          float32(v.CurrentWeight) / 1000,
+			LastWeightAt:           int32(v.LastWeightAt),
+		}
+	}
+	return res
+}

+ 68 - 0
module/backend/analysis.go

@@ -80,3 +80,71 @@ func (s *StoreEntry) GrowthCurve(ctx context.Context, req *pasturePb.SearchGrowt
 	}, nil
 
 }
+
+func (s *StoreEntry) WeightRange(ctx context.Context, req *pasturePb.WeightRangeRequest) (*pasturePb.WeightRangeResponse, error) {
+	cowWeightRange := make([]*model.CowWeightRange, 0)
+
+	prefix := s.DB.Model(new(model.Cow)).Where("is_remove = ?", pasturePb.IsShow_Ok)
+	if req.CowKind > 0 {
+		prefix.Where("cow_kind = ?", req.CowKind)
+	}
+	if err := prefix.Select(`
+		CASE 
+			WHEN current_weight BETWEEN 0 AND 50000 THEN '0-50'  
+			WHEN current_weight BETWEEN 50001 AND 100000 THEN '51-100' 
+			WHEN current_weight BETWEEN 100001 AND 150000 THEN '101-150' 
+			WHEN current_weight BETWEEN 150001 AND 200000 THEN '151-200' 
+			WHEN current_weight BETWEEN 200001 AND 250000 THEN '201-250' 
+			WHEN current_weight BETWEEN 250001 AND 300000 THEN '251-300' 
+			WHEN current_weight BETWEEN 300001 AND 350000 THEN '301-350' 
+			WHEN current_weight BETWEEN 350001 AND 400000 THEN '351-400' 
+			WHEN current_weight BETWEEN 400001 AND 450000 THEN '401-450' 
+			WHEN current_weight BETWEEN 450001 AND 500000 THEN '451-500' 
+			WHEN current_weight BETWEEN 500001 AND 550000 THEN '500-550' 
+			WHEN current_weight BETWEEN 550001 AND 600000 THEN '551-600' 
+			WHEN current_weight BETWEEN 600001 AND 650000 THEN '601-650' 
+			WHEN current_weight BETWEEN 650001 AND 700000 THEN '651-700' 
+			WHEN current_weight BETWEEN 700001 AND 750000 THEN '701-750' 
+			ELSE '750+'  
+		END AS weight_range, 
+		COUNT(*) AS count `,
+	).Group("weight_range").Order("MIN(current_weight)").Find(&cowWeightRange).Error; err != nil {
+		return nil, err
+	}
+
+	if len(cowWeightRange) == 0 {
+		return nil, xerr.Customf("没有数据")
+	}
+	header := make([]string, 0)
+	data := make([]int32, 0)
+	for _, v := range cowWeightRange {
+		header = append(header, v.WeightRange)
+		data = append(data, v.Count)
+	}
+	// 牛只详情列表
+	pref := s.DB.Model(new(model.Cow)).Where("is_remove = ?", pasturePb.IsShow_Ok)
+	if req.CowKind > 0 {
+		pref.Where("cow_kind = ?", req.CowKind)
+	}
+	cowList := make([]*model.Cow, 0)
+	if req.MinWeight >= 0 && req.MaxWeight >= 0 && req.MinWeight < req.MaxWeight {
+		pref.Where("current_weight BETWEEN  ? AND ? ", req.MinWeight*1000, req.MaxWeight*1000)
+	}
+
+	if err := pref.Find(&cowList).Error; err != nil {
+		return nil, err
+	}
+
+	penMap := s.PenMap(ctx)
+	return &pasturePb.WeightRangeResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.WeightRangeData{
+			CowList: model.CowSlice(cowList).WeightRangeToPB(penMap),
+			WeightBarChart: &pasturePb.WeightBarChart{
+				Header: header,
+				Data:   data,
+			},
+		},
+	}, nil
+}

+ 1 - 0
module/backend/interface.go

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