Browse Source

event: calving

Yi 1 month ago
parent
commit
6c336cad0a

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250220090818-98fa5abffb33
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250224070445-464185db4857
 	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

+ 10 - 0
go.sum

@@ -222,6 +222,16 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250220023058-9a5a7f8cc04a h1:MBavBgyT
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250220023058-9a5a7f8cc04a/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250220090818-98fa5abffb33 h1:1anBE/Z+35WmwJjMh5T4LP4JeakKq/64oFz6Ade2RoU=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250220090818-98fa5abffb33/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250224021008-13ba78841d1c h1:AUAAlITK1qZde9WtRdq3VLDlQswMQbrIgF7pkJZwZnY=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250224021008-13ba78841d1c/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250224030051-3f56f915121f h1:vQQm68Tmop7R88c8+6i1CWY/DCtQ7dORL4pmr0uLIug=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250224030051-3f56f915121f/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250224035655-3401deeb3d59 h1:xHsE9KlguSyJA/VxXX8X2ObPOjCWbukX4V3yQ/X9N5Q=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250224035655-3401deeb3d59/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250224061833-6c7b2a3558b8 h1:PYUFDZcDc6mH59HsfZLmjvyxGbI28JVow6imE4XyW+Q=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250224061833-6c7b2a3558b8/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250224070445-464185db4857 h1:fYMnYdzFo/crU6pXCiCpvFtLBsztN8/gyrXJaYrgj64=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250224070445-464185db4857/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=

+ 0 - 9
http/handler/dashboard/dashboard.go

@@ -15,15 +15,6 @@ import (
 	"github.com/gin-gonic/gin"
 )
 
-func Bar(c *gin.Context) {
-	res, err := middleware.Dependency(c).StoreEventHub.OpsService.Bar(c)
-	if err != nil {
-		apierr.ClassifiedAbort(c, err)
-		return
-	}
-	ginutil.JSONResp(c, res)
-}
-
 func NeckRingWarning(c *gin.Context) {
 	res, err := middleware.Dependency(c).StoreEventHub.OpsService.NeckRingWarning(c)
 	if err != nil {

+ 43 - 0
http/handler/event/event_base.go

@@ -291,3 +291,46 @@ func CowEarNumber(c *gin.Context) {
 		Data: &operationPb.Success{Success: true},
 	})
 }
+
+func CowSale(c *gin.Context) {
+	var req pasturePb.EventCowSale
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.DealerId, valid.Required),
+		valid.Field(&req.SaleAt, valid.Required),
+		valid.Field(&req.SaleAllPrice, valid.Required),
+		valid.Field(&req.SaleAllWeight, valid.Required),
+		valid.Field(&req.SalePrice, valid.Required),
+		valid.Field(&req.SaleTicket, valid.Required),
+		valid.Field(&req.CowIds, valid.Required),
+		valid.Field(&req.QuarantineReport, valid.Required),
+		valid.Field(&req.SaleVehicleItems, valid.Required, valid.Each(valid.By(func(value interface{}) error {
+			s := value.(pasturePb.SaleVehicleItem)
+			return valid.ValidateStruct(&s,
+				valid.Field(&s.CarNumber, valid.Required),
+				valid.Field(&s.CowCount, valid.Required),
+				valid.Field(&s.CowWeight, valid.Required),
+				valid.Field(&s.WeighbridgePhotos, valid.Required),
+				valid.Field(&s.VehiclePhotos, valid.Required),
+			)
+		}))),
+	); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.CowSaleCreate(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}

+ 6 - 6
http/handler/event/event_breed.go

@@ -369,18 +369,18 @@ func AbortionList(c *gin.Context) {
 }
 
 func WeaningCreateBatch(c *gin.Context) {
-	var req pasturePb.EventWeaningBatchRequest
+	var req pasturePb.EventWeaningBatch
 	if err := ginutil.BindProto(c, &req); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(req.WeaningAt, valid.Required),
-		valid.Field(req.OperationId, valid.Required),
-		valid.Field(req.PenId, valid.Required),
-		valid.Field(&req.Item, valid.Required, valid.Each(valid.By(func(value interface{}) error {
-			item := value.(pasturePb.BatchWeaning)
+		valid.Field(&req.WeaningAt, valid.Required),
+		valid.Field(&req.OperationId, valid.Required),
+		valid.Field(&req.PenId, valid.Required),
+		valid.Field(&req.Items, valid.Required, valid.Each(valid.By(func(value interface{}) error {
+			item := value.(pasturePb.WeaningItem)
 			return valid.ValidateStruct(&item,
 				valid.Field(&item.CowId, valid.Required),
 				valid.Field(&item.Weight, valid.Required),

+ 12 - 12
http/route/analysis_api.go

@@ -13,17 +13,17 @@ func AnalysisAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		}
 		// analysis API 组
 		analysisRoute := authRouteGroup(s, "/api/v1/analysis/")
-		analysisRoute.POST("/weight/scatter/plot", analysis.WeightScatterPlot) // 体重散点图
-		analysisRoute.POST("/weight/range", analysis.WeightRange)
-		analysisRoute.POST("/mating/timely", analysis.MatingTimeLy)
-		analysisRoute.POST("/pen/weight", analysis.PenWeight)
-		analysisRoute.POST("/abortion/rate", analysis.AbortionRate)
-		analysisRoute.POST("/twenty/one/pregnant/rate", analysis.TwentyOnePregnantRate)
-		analysisRoute.POST("/pregnancy/report", analysis.PregnancyReport)
-		analysisRoute.POST("/calving/report", analysis.CalvingReport)
-		analysisRoute.POST("/disease/cure/report", analysis.DiseaseCureReport)
-		analysisRoute.POST("/sale/cow/report", analysis.SaleCowReport)
-		analysisRoute.POST("/single/factor/pregnant/report", analysis.SingleFactorInfantSurvivalRate)
-		analysisRoute.POST("/multi/factor/pregnant/report", analysis.MultiFactorInfantSurvivalRate)
+		analysisRoute.POST("/weight/scatter/plot", analysis.WeightScatterPlot)                        // 体重散点图
+		analysisRoute.POST("/weight/range", analysis.WeightRange)                                     // 体重区间图
+		analysisRoute.POST("/mating/timely", analysis.MatingTimeLy)                                   // 配种及时性
+		analysisRoute.POST("/pen/weight", analysis.PenWeight)                                         // 栏舍体重
+		analysisRoute.POST("/abortion/rate", analysis.AbortionRate)                                   // 流产率
+		analysisRoute.POST("/twenty/one/pregnant/rate", analysis.TwentyOnePregnantRate)               // 21天怀孕率
+		analysisRoute.POST("/pregnancy/report", analysis.PregnancyReport)                             // 孕检报告
+		analysisRoute.POST("/calving/report", analysis.CalvingReport)                                 // 产犊报告
+		analysisRoute.POST("/disease/cure/report", analysis.DiseaseCureReport)                        // 疾病治疗报告
+		analysisRoute.POST("/sale/cow/report", analysis.SaleCowReport)                                // 销售牛牛报告
+		analysisRoute.POST("/single/factor/pregnant/report", analysis.SingleFactorInfantSurvivalRate) // 单因素受胎率
+		analysisRoute.POST("/multi/factor/pregnant/report", analysis.MultiFactorInfantSurvivalRate)   // 多因素受胎率
 	}
 }

+ 0 - 1
http/route/dashboard_api.go

@@ -13,7 +13,6 @@ func DashboardApi(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		}
 		// dashboard API 组
 		dashboardRoute := authRouteGroup(s, "/api/v1/dashboard/")
-		//dashboardRoute.GET("/bar", dashboard.Bar)
 		dashboardRoute.GET("/neck_ring/warning", dashboard.NeckRingWarning)
 		dashboardRoute.GET("/focus/indicators/:dimension", dashboard.FocusIndicators)
 		dashboardRoute.POST("/focus/indicators/set", dashboard.FocusIndicatorsSet)

+ 3 - 0
http/route/event_api.go

@@ -64,5 +64,8 @@ func EventAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		eventRoute.POST("/departure/batch", event.Departure)
 		// 更换耳标号
 		eventRoute.PUT("/cow/ear/number", event.CowEarNumber)
+		// 牛只销售
+		eventRoute.POST("/sale/create", event.CowSale)
+		eventRoute.POST("/sale/list", event.CowSale)
 	}
 }

+ 31 - 29
model/cow.go

@@ -305,7 +305,6 @@ func (c CowSlice) ToPB2(penMap map[int32]*Pen, penWeightSlice PenWeightSlice) []
 		res[i] = &pasturePb.CowList{
 			CowId:                    int32(v.Id),
 			DayAge:                   v.DayAge,
-			DailyWeightGain:          float32(v.GetDayWeight()),
 			AverageDailyWeightGain:   float32(v.GetAverageDailyWeight()),
 			EarNumber:                v.EarNumber,
 			PenName:                  penName,
@@ -323,7 +322,8 @@ func (c CowSlice) ToPB2(penMap map[int32]*Pen, penWeightSlice PenWeightSlice) []
 	return res
 }
 
-func NewCow(pastureId int64, req *pasturePb.EventEnterRequest, penMap map[int32]*Pen) *Cow {
+// NewEnterCow 入场新增牛只
+func NewEnterCow(pastureId int64, req *pasturePb.EventEnterRequest, penMap map[int32]*Pen) *Cow {
 	var isPregnant = pasturePb.IsShow_No
 	if req.BreedStatus == pasturePb.BreedStatus_Pregnant {
 		isPregnant = pasturePb.IsShow_Ok
@@ -367,6 +367,7 @@ func NewCow(pastureId int64, req *pasturePb.EventEnterRequest, penMap map[int32]
 	}
 }
 
+// NewCalfCow 产犊新增
 func NewCalfCow(motherNumber, fatherNumber string, calf *CalvingCalf) *Cow {
 	return &Cow{
 		PastureId:       calf.PastureId,
@@ -447,9 +448,23 @@ func (c *Cow) GetAdmissionAge() int32 {
 	return 0
 }
 
-// GetDayWeight 日增重
-func (c *Cow) GetDayWeight() float64 {
-	if c.CurrentWeight-c.LastSecondWeight > 0 && c.LastWeightAt > c.LastSecondWeightAt {
+// GetAverageDailyWeight 平均日增重 (最后一次称重 -  第一次称重 ) ÷ 在群天数
+func (c *Cow) GetAverageDailyWeight() float64 {
+	if c.CurrentWeight <= 0 || c.AdmissionAge <= 0 {
+		return 0
+	}
+	firstWeight := c.BirthWeight
+	if c.SourceId == pasturePb.CowSource_Buy {
+		firstWeight = c.AdmissionWeight
+
+	}
+	res := math.Round(1.0 * float64(c.CurrentWeight-firstWeight) / float64(c.AdmissionAge))
+	return res / 1000
+}
+
+// GetPreviousStageDailyWeight 上一个阶段日增重
+func (c *Cow) GetPreviousStageDailyWeight() float64 {
+	if c.CurrentWeight-c.LastSecondWeight > 0 && c.LastWeightAt-c.LastSecondWeightAt > 0 {
 		days := int32(math.Floor(float64(c.LastWeightAt-c.LastSecondWeightAt) / 86400))
 		if days <= 0 {
 			return float64(c.CurrentWeight - c.LastSecondWeight)
@@ -460,25 +475,12 @@ func (c *Cow) GetDayWeight() float64 {
 	return 0
 }
 
-// GetAverageDailyWeight 平均日增重
-func (c *Cow) GetAverageDailyWeight() float64 {
-	if c.CurrentWeight-c.BirthWeight > 0 && c.LastWeightAt > c.BirthAt {
-		days := int32(math.Floor(float64(c.LastWeightAt-c.BirthAt) / 86400))
-		if days <= 0 {
-			return 0
-		}
-		dailyWeight := math.Round(1.0 * float64(c.CurrentWeight-c.BirthWeight) / float64(days))
-		return dailyWeight / 1000
-	}
-	return 0
-}
-
+// GetAbortionAge 流产天数
 func (c *Cow) GetAbortionAge() int32 {
 	if c.LastAbortionAt > 0 && c.AdmissionStatus == pasturePb.AdmissionStatus_Admission {
 		return int32(math.Floor(float64(time.Now().Unix()-c.LastAbortionAt) / 86400))
 	}
 	return 0
-
 }
 
 type CowWeightRange struct {
@@ -494,16 +496,16 @@ func (c CowSlice) WeightRangeToPB(penMap map[int32]*Pen) []*pasturePb.CowList {
 			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),
+			CowId:                    int32(v.Id),
+			DayAge:                   v.DayAge,
+			AverageDailyWeightGain:   float32(v.GetAverageDailyWeight()),
+			PreviousStageDailyWeight: float32(v.GetPreviousStageDailyWeight()),
+			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

+ 47 - 18
model/event_sale.go

@@ -1,26 +1,55 @@
 package model
 
+import (
+	"strings"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
 type EventSale struct {
-	Id            int64  `json:"id"`
-	PastureId     int64  `json:"pastureId"`
-	DealerId      int32  `json:"dealerId"`
-	DealerName    string `json:"dealerName"`
-	VehicleId     int32  `json:"vehicleId"`
-	SalePrice     int32  `json:"salePrice"`
-	SaleAllWeight int32  `json:"saleAllWeight"`
-	SaleAllAmount int32  `json:"saleAllAmount"`
-	SaleCowCount  int32  `json:"saleCowCount"`
-	CowIds        string `json:"cowIds"`
-	SaleAt        int64  `json:"saleAt"`
-	Remarks       string `json:"remarks"`
-	OperationId   int32  `json:"operationId"`
-	OperationName string `json:"operationName"`
-	MessageId     int64  `json:"messageId"`
-	MessageName   string `json:"messageName"`
-	CreatedAt     int64  `json:"createdAt"`
-	UpdatedAt     int64  `json:"updatedAt"`
+	Id               int64   `json:"id"`
+	PastureId        int64   `json:"pastureId"`
+	DealerId         int32   `json:"dealerId"`
+	DealerName       string  `json:"dealerName"`
+	SalePrice        float64 `json:"salePrice"`
+	SaleAllWeight    int32   `json:"saleAllWeight"`
+	SaleAllAmount    float64 `json:"saleAllAmount"`
+	SaleCowCount     int32   `json:"saleCowCount"`
+	CowIds           string  `json:"cowIds"`
+	SaleAt           int64   `json:"saleAt"`
+	SaleTicker       string  `json:"saleTicker"`
+	QuarantineReport string  `json:"quarantineReport"`
+	Remarks          string  `json:"remarks"`
+	OperationId      int64   `json:"operationId"`
+	OperationName    string  `json:"operationName"`
+	MessageId        int64   `json:"messageId"`
+	MessageName      string  `json:"messageName"`
+	CreatedAt        int64   `json:"createdAt"`
+	UpdatedAt        int64   `json:"updatedAt"`
 }
 
 func (e *EventSale) TableName() string {
 	return "event_sale"
 }
+
+func NewEventSale(pastureId int64, dealerInfo *SaleDealer, cowIds string, req *pasturePb.EventCowSale, operationUser, currUser *SystemUser) *EventSale {
+
+	return &EventSale{
+		PastureId:        pastureId,
+		DealerId:         dealerInfo.Id,
+		DealerName:       dealerInfo.Name,
+		SalePrice:        float64(req.SalePrice),
+		SaleAllWeight:    int32(req.SaleAllWeight * 1000),
+		SaleAllAmount:    float64(req.SaleAllPrice),
+		SaleCowCount:     int32(len(req.CowIds)),
+		CowIds:           cowIds,
+		SaleAt:           int64(req.SaleAt),
+		SaleTicker:       strings.Join(req.SaleTicket, ","),
+		QuarantineReport: strings.Join(req.QuarantineReport, ","),
+		Remarks:          req.Remarks,
+		OperationId:      operationUser.Id,
+		OperationName:    operationUser.Name,
+		MessageId:        currUser.Id,
+		MessageName:      currUser.Name,
+	}
+}

+ 46 - 0
model/event_sale_car.go

@@ -0,0 +1,46 @@
+package model
+
+import (
+	"strings"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type EventSaleCar struct {
+	Id                int64  `json:"id"`
+	SaleId            int64  `json:"saleId"`
+	SaleAt            int64  `json:"saleAt"`
+	CarNumber         string `json:"carNumber"`
+	CowCount          int32  `json:"cowCount"`
+	CowIds            string `json:"cowIds"`
+	OutboundTicket    string `json:"outbound_ticket"`
+	WeighbridgePhotos string `json:"weighbridgePhotos"`
+	CarPhotos         string `json:"carPhotos"`
+	CreatedAt         int64  `json:"createdAt"`
+	UpdatedAt         int64  `json:"updatedAt"`
+}
+
+func (e *EventSaleCar) TableName() string {
+	return "event_sale_car"
+}
+
+func NewEventSaleCar(saleId, saleAt int64, saleVehicleItem *pasturePb.SaleVehicleItem) *EventSaleCar {
+	return &EventSaleCar{
+		SaleId:            saleId,
+		SaleAt:            saleAt,
+		CarNumber:         saleVehicleItem.CarNumber,
+		CowCount:          saleVehicleItem.CowCount,
+		CowIds:            "",
+		OutboundTicket:    saleVehicleItem.OutboundTicket,
+		WeighbridgePhotos: strings.Join(saleVehicleItem.WeighbridgePhotos, ","),
+		CarPhotos:         strings.Join(saleVehicleItem.VehiclePhotos, ","),
+	}
+}
+
+func NewEventSaleCarList(saleId, saleAt int64, req []*pasturePb.SaleVehicleItem) []*EventSaleCar {
+	res := make([]*EventSaleCar, 0)
+	for _, saleVehicleItem := range req {
+		res = append(res, NewEventSaleCar(saleId, saleAt, saleVehicleItem))
+	}
+	return res
+}

+ 0 - 20
model/event_sale_vehicle.go

@@ -1,20 +0,0 @@
-package model
-
-type EventSaleVehicle struct {
-	Id              int64  `json:"id"`
-	DealerId        int32  `json:"dealerId"`
-	DealerName      string `json:"dealerName"`
-	SaleAt          int64  `json:"saleAt"`
-	VehicleNumber   string `json:"vehicleNumber"`
-	VehicleCowCount int32  `json:"vehicleCowCount"`
-	CowIds          string `json:"cowIds"`
-	Photo1          string `json:"photo1"`
-	Photo2          string `json:"photo2"`
-	Photo3          string `json:"photo3"`
-	CreatedAt       int64  `json:"createdAt"`
-	UpdatedAt       int64  `json:"updatedAt"`
-}
-
-func (e *EventSaleVehicle) TableName() string {
-	return "event_sale_vehicle"
-}

+ 1 - 1
model/sale_dealer.go

@@ -1,7 +1,7 @@
 package model
 
 type SaleDealer struct {
-	Id        int64  `json:"id"`
+	Id        int32  `json:"id"`
 	Name      string `json:"name"`
 	Phone     string `json:"phone"`
 	Address   string `json:"address"`

+ 15 - 15
module/backend/analysis.go

@@ -61,17 +61,17 @@ func (s *StoreEntry) WeightScatterPlot(ctx context.Context, req *pasturePb.Searc
 			penName = v.Name
 		}
 		cowData = append(cowData, &pasturePb.CowList{
-			CowId:                  int32(cow.Id),
-			EarNumber:              cow.EarNumber,
-			DayAge:                 cow.GetDayAge(),
-			PenName:                penName,
-			CurrentWeight:          currentWeight,
-			BirthAt:                int32(cow.BirthAt),
-			BirthWeight:            float32(cow.BirthWeight) / 1000,
-			LastWeightAt:           int32(cow.LastWeightAt),
-			DailyWeightGain:        float32(cow.GetDayWeight() / 1000),
-			AverageDailyWeightGain: float32(cow.GetAverageDailyWeight() / 1000),
-			AdmissionAge:           cow.GetAdmissionAge(),
+			CowId:                    int32(cow.Id),
+			EarNumber:                cow.EarNumber,
+			DayAge:                   cow.GetDayAge(),
+			PenName:                  penName,
+			CurrentWeight:            currentWeight,
+			BirthAt:                  int32(cow.BirthAt),
+			BirthWeight:              float32(cow.BirthWeight) / 1000,
+			LastWeightAt:             int32(cow.LastWeightAt),
+			AverageDailyWeightGain:   float32(cow.GetAverageDailyWeight() / 1000),
+			PreviousStageDailyWeight: float32(cow.GetPreviousStageDailyWeight() / 1000),
+			AdmissionAge:             cow.GetAdmissionAge(),
 		})
 
 		chartsList.CowId = append(chartsList.CowId, int32(cow.Id))
@@ -318,10 +318,10 @@ func (s *StoreEntry) PenWeight(ctx context.Context, req *pasturePb.PenWeightRequ
 	prefList := s.DB.Model(new(model.Cow)).
 		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission)
 
-	if len(req.PenId) <= 0 && req.BarId > 0 {
-		prefList.Where("pen_id IN ?", []int32{req.BarId})
-	} else {
-		prefList.Where("pen_id IN ?", req.PenId)
+	if len(req.PenId) > 0 {
+		prefList.Where("pen_id IN (?)", req.PenId)
+	} else if req.BarId > 0 {
+		prefList.Where("pen_id = ?", []int32{req.BarId})
 	}
 
 	if err = prefList.Count(&count).Limit(int(pagination.PageSize)).

+ 35 - 12
module/backend/calendar.go

@@ -52,16 +52,17 @@ func (s *StoreEntry) CalendarToDoList(ctx context.Context, req *pasturePb.Calend
 		SELECT cow_id,plan_day ,'产犊' as calendar_type_name FROM event_calving WHERE status = 2 ` + pastureWhereSql + `
 	) as a JOIN cow b ON a.cow_id = b.id WHERE 1 = 1 `
 
-	completeSql := fmt.Sprintf("%s %s ORDER BY a.plan_day ASC LIMIT %d OFFSET %d", sql, whereSql, pagination.PageSize, pagination.PageOffset)
+	completeSql := fmt.Sprintf("%s %s ORDER BY a.plan_day ASC", sql, whereSql)
 	if err = s.DB.Raw(completeSql).Find(&calendarToDoList).Error; err != nil {
 		return nil, err
 	}
 
+	list := Paginate(calendarToDoList, pagination.Page, pagination.PageSize)
 	return &pasturePb.CalendarToDoResponse{
 		Code: http.StatusOK,
 		Msg:  "ok",
 		Data: &pasturePb.CalendarToDoData{
-			List:     calendarToDoList,
+			List:     list,
 			Total:    int32(len(calendarToDoList)),
 			PageSize: pagination.PageSize,
 			Page:     pagination.Page,
@@ -351,7 +352,8 @@ func (s *StoreEntry) WeaningCowList(ctx context.Context, req *pasturePb.ItemsReq
 	weaningItems := make([]*pasturePb.WeaningItems, 0)
 	count := int64(0)
 	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventWeaning).TableName())).
-		Select("a.id,a.cow_id,b.current_weight as weight,a.status,b.birth_at,b.day_age,b.pen_name").
+		Select(`a.id,a.cow_id,ROUND(b.current_weight / 1000,2) as current_weight,DATE_FORMAT(FROM_UNIXTIME(a.plan_day), '%Y-%m-%d') AS plan_day_format,
+			b.day_age,b.pen_name,b.ear_number,DATE_FORMAT(FROM_UNIXTIME(b.birth_at), '%Y-%m-%d') AS birth_at_format`).
 		Joins("left join cow as b on a.cow_id = b.id").
 		Where("b.admission_status = ?", pasturePb.AdmissionStatus_Admission).
 		Where("a.status = ?", pasturePb.IsShow_No).
@@ -377,15 +379,14 @@ func (s *StoreEntry) WeaningCowList(ctx context.Context, req *pasturePb.ItemsReq
 			Page:     pagination.Page,
 			PageSize: pagination.PageSize,
 			Header: map[string]string{
-				"id":        "编号",
-				"cowId":     "牛号",
-				"earNumber": "耳标号",
-				"penName":   "栏舍",
-				"planDay":   "断奶日期",
-				"dayAge":    "日龄",
-				"status":    "状态",
-				"birthAt":   "出生日期",
-				"weight":    "体重",
+				"id":            "编号",
+				"cowId":         "牛号",
+				"earNumber":     "耳标号",
+				"penName":       "栏舍",
+				"dayAge":        "日龄",
+				"planDayFormat": "断奶日期",
+				"birthAtFormat": "出生日期",
+				"currentWeight": "体重",
 			},
 			List: weaningItems,
 		},
@@ -533,3 +534,25 @@ func (s *StoreEntry) WorkOrderCowList(ctx context.Context, req *pasturePb.ItemsR
 func (s *StoreEntry) TreatmentCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (interface{}, error) {
 	return nil, nil
 }
+
+// Paginate 函数用于对切片进行分页
+func Paginate(slice []*pasturePb.CalendarToDoList, page int32, pageSize int32) []*pasturePb.CalendarToDoList {
+	// 计算起始索引
+	start := (page - 1) * pageSize
+
+	// 如果起始索引超出切片长度,返回空切片
+	if start >= int32(len(slice)) {
+		return []*pasturePb.CalendarToDoList{}
+	}
+
+	// 计算结束索引
+	end := start + pageSize
+
+	// 如果结束索引超出切片长度,调整到切片末尾
+	if end > int32(len(slice)) {
+		end = int32(len(slice))
+	}
+
+	// 返回分页后的切片
+	return slice[start:end]
+}

+ 1 - 25
module/backend/dashboard.go

@@ -18,31 +18,6 @@ import (
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 )
 
-func (s *StoreEntry) Bar(ctx context.Context) (*pasturePb.BarCowStructResponse, error) {
-	barCowStructList := make([]*model.BarCowStruct, 0)
-	var count int32 = 0
-	if err := s.DB.Model(new(model.Cow)).
-		Select("COUNT(*) AS number ,cow_type").
-		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
-		Group("cow_type").
-		Find(&barCowStructList).Error; err != nil {
-		return nil, xerr.WithStack(err)
-	}
-	cowTypeMap := s.CowTypeMap()
-
-	for _, v := range barCowStructList {
-		count += v.Number
-	}
-	return &pasturePb.BarCowStructResponse{
-		Code: http.StatusOK,
-		Msg:  "ok",
-		Data: &pasturePb.BarCowStructData{
-			List:  model.BarCowStructSlice(barCowStructList).ToPB(cowTypeMap, count),
-			Total: 38563,
-		},
-	}, nil
-}
-
 func (s *StoreEntry) NeckRingWarning(ctx context.Context) (*pasturePb.IndexNeckRingResponse, error) {
 	userModel, err := s.GetUserModel(ctx)
 	if err != nil {
@@ -55,6 +30,7 @@ func (s *StoreEntry) NeckRingWarning(ctx context.Context) (*pasturePb.IndexNeckR
 		int32(pasturePb.EstrusLevel_Middle): 0,
 		int32(pasturePb.EstrusLevel_High):   0,
 	}
+
 	if err = s.DB.Model(new(model.EventEstrus)).
 		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("is_show = ?", pasturePb.IsShow_Ok).

+ 1 - 104
module/backend/event_base.go

@@ -8,9 +8,6 @@ import (
 	"strconv"
 	"strings"
 
-	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
-	"go.uber.org/zap"
-
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	"gitee.com/xuyiping_admin/pkg/xerr"
 	"gorm.io/gorm"
@@ -95,7 +92,7 @@ func (s *StoreEntry) CreateEnter(ctx context.Context, req *pasturePb.EventEnterR
 	}
 
 	penMap := s.PenMap(ctx, userModel.AppPasture.Id)
-	newCow := model.NewCow(userModel.AppPasture.Id, req, penMap)
+	newCow := model.NewEnterCow(userModel.AppPasture.Id, req, penMap)
 	defer func() {
 		if err == nil {
 			cowLogs := s.SubmitEventLog(ctx, userModel.AppPasture.Id, newCow, pasturePb.EventType_Enter, pasturePb.ExposeEstrusType_Invalid, req)
@@ -351,103 +348,3 @@ func (s *StoreEntry) WeightBatch(ctx context.Context, req *pasturePb.BatchEventW
 	}
 	return err
 }
-
-func (s *StoreEntry) DepartureBatch(ctx context.Context, req *pasturePb.EventDepartureBatch) (err error) {
-	if len(req.Item) <= 0 {
-		return xerr.Custom("请选择相关牛只")
-	}
-
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-
-	newEventDepartureModelList := make([]*model.EventDepartureModel, 0)
-	cow := &model.Cow{}
-	for _, item := range req.Item {
-		cow, err = s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, int64(item.CowId))
-		if err != nil {
-			zaplog.Error("DepartureBatch", zap.Any("item", item), zap.Any("err", err))
-			return xerr.Customf("获取牛只信息失败: %d", item.CowId)
-		}
-
-		operationUser, err := s.GetSystemUserById(ctx, int64(item.OperationId))
-		if err != nil {
-			zaplog.Error("DepartureBatch", zap.Any("item", item), zap.Any("err", err))
-			return xerr.Customf("获取操作人员信息失败: %d", item.OperationId)
-		}
-		reasonName := ""
-		switch item.DepartureType {
-		case pasturePb.DepartureType_Death:
-			reasonName = s.DeadReasonMap()[pasturePb.DeadReason_Kind(item.DepartureReasonKind)]
-		case pasturePb.DepartureType_Out:
-			reasonName = s.OutReasonMap()[pasturePb.OutReason_Kind(item.DepartureReasonKind)]
-		default:
-			return xerr.Custom("未知的离场类型")
-		}
-		newEventDeparture := model.NewEventDeparture(userModel.AppPasture.Id, cow, item, reasonName, userModel.SystemUser, operationUser)
-		newEventDepartureModelList = append(newEventDepartureModelList, &model.EventDepartureModel{
-			EventDeparture: newEventDeparture,
-			Cow:            cow,
-			DepartureAt:    int64(item.DepartureAt),
-		})
-	}
-
-	if len(newEventDepartureModelList) <= 0 {
-		return nil
-	}
-
-	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-		// 记录事件日志
-		for _, item := range newEventDepartureModelList {
-			eventType := pasturePb.EventType_Death
-			if item.EventDeparture.DepartureType == pasturePb.DepartureType_Out {
-				eventType = pasturePb.EventType_Out
-			}
-
-			if err = tx.Create(item.EventDeparture).Error; err != nil {
-				return xerr.WithStack(err)
-			}
-
-			cow.EventDepartureUpdate(item.DepartureAt, item.EventDeparture.DepartureType)
-			if err = tx.Model(cow).
-				Select("admission_status", "health_status", "departure_at").
-				Where("id = ?", cow.Id).
-				Updates(cow).Error; err != nil {
-				return xerr.WithStack(err)
-			}
-
-			// 记录事件日志
-			cowLogs := s.SubmitEventLog(ctx, userModel.AppPasture.Id, item.Cow, eventType, pasturePb.ExposeEstrusType_Invalid, item)
-			if err = tx.Table(cowLogs.TableName()).Create(cowLogs).Error; err != nil {
-				return xerr.WithStack(err)
-			}
-		}
-		return nil
-	}); err != nil {
-		return xerr.WithStack(err)
-	}
-	return nil
-}
-
-func (s *StoreEntry) CowEarNumberUpdate(ctx context.Context, req *pasturePb.EventReplaceEarNumber) (err error) {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-
-	cow, err := s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, int64(req.CowId))
-	if err != nil {
-		return xerr.Custom("未找到该牛只信息")
-	}
-
-	cow.EventEarNumberUpdate(req.EarNumber)
-	if err = s.DB.Model(cow).
-		Select("ear_number", "ear_old_number").
-		Where("id = ?", cow.Id).
-		Updates(cow).Error; err != nil {
-		return xerr.WithStack(err)
-	}
-
-	return nil
-}

+ 190 - 0
module/backend/event_base_more.go

@@ -0,0 +1,190 @@
+package backend
+
+import (
+	"context"
+	"kpt-pasture/model"
+	"kpt-pasture/util"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
+	"gitee.com/xuyiping_admin/pkg/xerr"
+	"go.uber.org/zap"
+	"gorm.io/gorm"
+)
+
+func (s *StoreEntry) DepartureBatch(ctx context.Context, req *pasturePb.EventDepartureBatch) (err error) {
+	if len(req.Item) <= 0 {
+		return xerr.Custom("请选择相关牛只")
+	}
+
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	newEventDepartureModelList := make([]*model.EventDepartureModel, 0)
+	cow := &model.Cow{}
+	for _, item := range req.Item {
+		cow, err = s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, int64(item.CowId))
+		if err != nil {
+			zaplog.Error("DepartureBatch", zap.Any("item", item), zap.Any("err", err))
+			return xerr.Customf("获取牛只信息失败: %d", item.CowId)
+		}
+
+		operationUser, err := s.GetSystemUserById(ctx, int64(item.OperationId))
+		if err != nil {
+			zaplog.Error("DepartureBatch", zap.Any("item", item), zap.Any("err", err))
+			return xerr.Customf("获取操作人员信息失败: %d", item.OperationId)
+		}
+		reasonName := ""
+		switch item.DepartureType {
+		case pasturePb.DepartureType_Death:
+			reasonName = s.DeadReasonMap()[pasturePb.DeadReason_Kind(item.DepartureReasonKind)]
+		case pasturePb.DepartureType_Out:
+			reasonName = s.OutReasonMap()[pasturePb.OutReason_Kind(item.DepartureReasonKind)]
+		default:
+			return xerr.Custom("未知的离场类型")
+		}
+		newEventDeparture := model.NewEventDeparture(userModel.AppPasture.Id, cow, item, reasonName, userModel.SystemUser, operationUser)
+		newEventDepartureModelList = append(newEventDepartureModelList, &model.EventDepartureModel{
+			EventDeparture: newEventDeparture,
+			Cow:            cow,
+			DepartureAt:    int64(item.DepartureAt),
+		})
+	}
+
+	if len(newEventDepartureModelList) <= 0 {
+		return nil
+	}
+
+	if err = s.DB.Transaction(func(tx *gorm.DB) error {
+		// 记录事件日志
+		for _, item := range newEventDepartureModelList {
+			eventType := pasturePb.EventType_Death
+			if item.EventDeparture.DepartureType == pasturePb.DepartureType_Out {
+				eventType = pasturePb.EventType_Out
+			}
+
+			if err = tx.Create(item.EventDeparture).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+
+			cow.EventDepartureUpdate(item.DepartureAt, item.EventDeparture.DepartureType)
+			if err = tx.Model(cow).
+				Select("admission_status", "health_status", "departure_at").
+				Where("id = ?", cow.Id).
+				Updates(cow).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+
+			// 记录事件日志
+			cowLogs := s.SubmitEventLog(ctx, userModel.AppPasture.Id, item.Cow, eventType, pasturePb.ExposeEstrusType_Invalid, item)
+			if err = tx.Table(cowLogs.TableName()).Create(cowLogs).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+		}
+		return nil
+	}); err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}
+
+func (s *StoreEntry) CowEarNumberUpdate(ctx context.Context, req *pasturePb.EventReplaceEarNumber) (err error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	cow, err := s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, int64(req.CowId))
+	if err != nil {
+		return xerr.Custom("未找到该牛只信息")
+	}
+
+	cow.EventEarNumberUpdate(req.EarNumber)
+	if err = s.DB.Model(cow).
+		Select("ear_number", "ear_old_number").
+		Where("id = ?", cow.Id).
+		Updates(cow).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+
+	return nil
+}
+
+func (s *StoreEntry) CowSaleCreate(ctx context.Context, req *pasturePb.EventCowSale) error {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	cowIds := make([]int64, 0)
+	if len(req.CowIds) <= 0 {
+		return xerr.Custom("请选择牛只")
+	}
+
+	for _, v := range req.CowIds {
+		cowIds = append(cowIds, int64(v))
+	}
+
+	cowList, err := s.GetCowInfoByCowIds(ctx, userModel.AppPasture.Id, cowIds)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+	if len(cowList) != len(req.CowIds) {
+		return xerr.Custom("数据异常")
+	}
+
+	if len(cowList) <= 0 {
+		return nil
+	}
+
+	dealerInfo := &model.SaleDealer{}
+	if err = s.DB.Model(new(model.SaleDealer)).Where("id = ?", req.DealerId).First(dealerInfo).Error; err != nil {
+		return xerr.Custom("经销商数据异常")
+	}
+	req.DealerName = dealerInfo.Name
+
+	operationUser, err := s.GetSystemUserById(ctx, int64(req.OperationId))
+	if err != nil {
+		return xerr.Custom("获取操作人员信息失败")
+	}
+	req.OperationName = operationUser.Name
+
+	cowIdsStr := util.ArrayInt32ToStrings(req.CowIds, ",")
+	newEventSale := model.NewEventSale(userModel.AppPasture.Id, dealerInfo, cowIdsStr, req, operationUser, userModel.SystemUser)
+	eventCowLogList := make([]*model.EventCowLog, 0)
+	for _, cow := range cowList {
+		newEventCowLog := s.SubmitEventLog(ctx, userModel.AppPasture.Id, cow, pasturePb.EventType_Sale, pasturePb.ExposeEstrusType_Invalid, req)
+		eventCowLogList = append(eventCowLogList, newEventCowLog)
+	}
+
+	if err = s.DB.Transaction(func(tx *gorm.DB) error {
+		// 创建销售数据
+		if err = tx.Model(new(model.EventSale)).Create(newEventSale).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+		newEventSaleCarList := model.NewEventSaleCarList(newEventSale.Id, newEventSale.SaleAt, req.SaleVehicleItems)
+		if err = tx.Model(new(model.EventSaleCar)).Create(&newEventSaleCarList).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+		// 更新牛只状态
+		if err = tx.Model(new(model.Cow)).Where("id IN (?)", cowIds).Update("admission_status", pasturePb.AdmissionStatus_Sale).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+		//  记录日志
+		if len(eventCowLogList) > 0 {
+			if err = tx.Model(new(model.EventCowLog)).Create(&eventCowLogList).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+		}
+
+		return nil
+	}); err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}

+ 0 - 254
module/backend/event_breed.go

@@ -2,7 +2,6 @@ package backend
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"kpt-pasture/model"
 	"kpt-pasture/util"
@@ -399,256 +398,3 @@ func (s *StoreEntry) EstrusBatchMating(ctx context.Context, req *pasturePb.Event
 	}
 	return nil
 }
-
-func (s *StoreEntry) MatingList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.EventMatingResponse, error) {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return nil, xerr.WithStack(err)
-	}
-
-	matingList := make([]*model.EventMating, 0)
-	var count int64 = 0
-	pref := s.DB.Model(new(model.EventMating)).
-		Where("mating_result > ?", pasturePb.MatingResult_Invalid).
-		Where("status = ?", pasturePb.IsShow_Ok).
-		Where("pasture_id = ?", userModel.AppPasture.Id)
-	if len(req.CowId) > 0 {
-		cowIds := strings.Split(req.CowId, ",")
-		pref.Where("cow_id IN ?", cowIds)
-	}
-
-	if err = pref.Order("id desc").
-		Count(&count).Limit(int(pagination.PageSize)).
-		Offset(int(pagination.PageOffset)).
-		Find(&matingList).Error; err != nil {
-		return nil, xerr.WithStack(err)
-	}
-
-	exposeEstrusTypeMap := s.ExposeEstrusTypeMap()
-	return &pasturePb.EventMatingResponse{
-		Code: http.StatusOK,
-		Msg:  "ok",
-		Data: &pasturePb.SearchMatingData{
-			List:     model.EventMatingSlice(matingList).ToPB(exposeEstrusTypeMap),
-			Total:    int32(count),
-			PageSize: pagination.PageSize,
-			Page:     pagination.Page,
-		},
-	}, nil
-}
-
-// MatingCreate 牛只配种
-func (s *StoreEntry) MatingCreate(ctx context.Context, req *pasturePb.EventMating) (err error) {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-
-	eventMatingCheckModel, err := s.MatingCreateCheck(ctx, userModel.AppPasture.Id, req)
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-
-	req.OperationName = eventMatingCheckModel.OperationUser.Name
-	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-		for _, cow := range eventMatingCheckModel.CowList {
-			// 获取牛只最近一次配种信息
-			lastEventMating, err := s.FindLastEventMatingByCowId(ctx, userModel.AppPasture.Id, cow.Id)
-			if err != nil {
-				// 1. 没有配种信息,(第一次参加配种的牛只,并且没有参与同期的牛只 )
-				if errors.Is(err, gorm.ErrRecordNotFound) {
-					newMating := model.NewEventMatingNaturalEstrus(userModel.AppPasture.Id, cow, req, userModel.SystemUser)
-					if err = tx.Create(newMating).Error; err != nil {
-						return xerr.WithStack(err)
-					}
-					if err = s.MatingCowUpdate(ctx, userModel.AppPasture.Id, cow, req, false); err != nil {
-						return xerr.WithStack(err)
-					}
-					continue
-				} else {
-					return xerr.WithStack(err)
-				}
-			}
-
-			// 2. 所有有配种数据的牛只
-			if lastEventMating == nil || lastEventMating.Id <= 0 || lastEventMating.Status != pasturePb.IsShow_No {
-				zaplog.Error("MatingCreate", zap.Any("cow", cow), zap.Any("UserModel", userModel))
-				return xerr.Customf("牛只配种数据异常: %d", cow.EarNumber)
-			}
-
-			// 2.1 复配 => 本胎次配次不加1
-			isReMating := lastEventMating.IsReMating(cow, int64(req.MatingAt))
-			if isReMating {
-				lastEventMating.EventReMatingUpdate(int64(req.MatingAt))
-				if err = tx.Model(lastEventMating).
-					Select("mating_result", "mating_result_at", "status").
-					Where("id = ?", lastEventMating.Id).
-					Updates(lastEventMating).Error; err != nil {
-				}
-			}
-
-			// 2.2.  同期初配
-			IsMatingUpdate := lastEventMating.IsMatingUpdate()
-			if IsMatingUpdate {
-				lastEventMating.EventUpdate(int64(req.MatingAt), req.FrozenSemenNumber, isReMating, eventMatingCheckModel.OperationUser, userModel.SystemUser)
-				if err = tx.Model(lastEventMating).
-					Select("mating_at", "status", "reality_day", "frozen_semen_number", "operation_id", "operation_name", "message_id", "message_name").
-					Where("id = ?", lastEventMating.Id).
-					Updates(lastEventMating).Error; err != nil {
-					return xerr.WithStack(err)
-				}
-			}
-
-			// 2.3. 提交的配种数据中,定位出空怀的牛只,
-			isEmptyMating := lastEventMating.IsEmptyMating(cow, int64(req.MatingAt))
-			if isEmptyMating {
-				// 把上次配种结果信息更新成空怀
-				lastEventMating.EventMatingResultUpdate(pasturePb.MatingResult_Empty, int64(req.MatingAt))
-				if err = tx.Model(lastEventMating).
-					Select("mating_result", "mating_result_at").
-					Where("id = ?", lastEventMating.Id).
-					Updates(lastEventMating).Error; err != nil {
-					return xerr.WithStack(err)
-				}
-				// 先创建一条新的配种数据
-				newMating := model.NewEventMating(userModel.AppPasture.Id, cow, int64(req.MatingAt), req.ExposeEstrusType)
-				newMating.EventUpdate(int64(req.MatingAt), req.FrozenSemenNumber, isReMating, eventMatingCheckModel.OperationUser, userModel.SystemUser)
-				if err = tx.Model(newMating).Create(newMating).Error; err != nil {
-					return xerr.WithStack(err)
-				}
-
-				// 更新牛只配种结果日志
-				if err = s.UpdateMatingResultEventCowLogByCowId(ctx, cow.Id, s.MatingResultMap()[pasturePb.MatingResult_Empty]); err != nil {
-					zaplog.Error("MatingCreate", zap.Any("UpdateEventCowLogByCowId", err), zap.Any("cow", cow))
-				}
-			}
-
-			// 牛只基本中配种信息更新
-			if err = s.MatingCowUpdate(ctx, userModel.AppPasture.Id, cow, req, isReMating); err != nil {
-				return xerr.WithStack(err)
-			}
-		}
-
-		// 创建冻精使用记录日志
-		itemFrozenSemenLog := model.NewEventFrozenSemenLog(eventMatingCheckModel.FrozenSemen.PastureId, req)
-		if err = tx.Create(itemFrozenSemenLog).Error; err != nil {
-			return xerr.WithStack(err)
-		}
-
-		// 减去精液的数量
-		eventMatingCheckModel.FrozenSemen.EventQuantityUpdate(req.FrozenSemenCount)
-		if err = tx.Model(eventMatingCheckModel.FrozenSemen).
-			Select("quantity").
-			Where("id = ?", eventMatingCheckModel.FrozenSemen.Id).
-			Updates(eventMatingCheckModel.FrozenSemen).Error; err != nil {
-			return xerr.WithStack(err)
-		}
-		return nil
-	}); err != nil {
-		return xerr.WithStack(err)
-	}
-
-	return nil
-}
-
-func (s *StoreEntry) MatingCowUpdate(ctx context.Context, pastureId int64, cow *model.Cow, req *pasturePb.EventMating, isReMating bool) error {
-	// 牛只基本中配种信息更新
-	cow.EventMatingUpdate(int64(req.MatingAt), req.FrozenSemenNumber, isReMating)
-	if err := s.DB.Model(cow).
-		Select("last_mating_at", "mating_times", "last_bull_number", "first_mating_at", "is_pregnant", "breed_status").
-		Where("id = ?", cow.Id).
-		Updates(cow).Error; err != nil {
-		return xerr.WithStack(err)
-	}
-	// 记录日志
-	cowLogs := s.SubmitEventLog(ctx, pastureId, cow, pasturePb.EventType_Mating, req.ExposeEstrusType, req)
-	if err := s.DB.Table(cowLogs.TableName()).Create(cowLogs).Error; err != nil {
-		return xerr.WithStack(err)
-	}
-	return nil
-}
-
-func (s *StoreEntry) WeaningBatch(ctx context.Context, req *pasturePb.EventWeaningBatchRequest) (err error) {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-
-	if len(req.Item) <= 0 {
-		return nil
-	}
-	cowIds := make([]int64, 0)
-	cowWeightMap := make(map[int64]float64)
-	for _, item := range req.Item {
-		cowIds = append(cowIds, int64(item.CowId))
-		cowWeightMap[int64(item.CowId)] = float64(item.Weight)
-	}
-
-	eventWeaningList := make([]*model.EventWeaning, 0)
-	if err = s.DB.Model(new(model.EventWeaning)).
-		Where("cow_id IN ?", cowIds).
-		Where("status = ?", pasturePb.IsShow_No).
-		Find(&eventWeaningList).Error; err != nil {
-		return xerr.WithStack(err)
-	}
-
-	operation, err := s.GetSystemUserById(ctx, int64(req.OperationId))
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-
-	defer func() {
-		if err != nil {
-			for _, cowId := range cowIds {
-				cow, _ := s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, cowId)
-				cowLogs := s.SubmitEventLog(ctx, userModel.AppPasture.Id, cow, pasturePb.EventType_Weaning, pasturePb.ExposeEstrusType_Invalid, req)
-				s.DB.Table(cowLogs.TableName()).Create(cowLogs)
-			}
-		}
-	}()
-
-	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-		cowInfo := &model.Cow{}
-		for _, eventWeaning := range eventWeaningList {
-			eventWeaning.EventUpdate(int64(req.WeaningAt), int32(cowWeightMap[cowInfo.Id]*1000), req.Remarks, req.PenId, operation, userModel.SystemUser)
-			if err = tx.Model(new(model.EventWeaning)).
-				Select("status", "reality_day", "operation_id", "operation_name", "message_id", "message_name", "remarks", "after_pen_id").
-				Where("id = ?", eventWeaning.Id).
-				Updates(eventWeaning).Error; err != nil {
-				return xerr.WithStack(err)
-			}
-			cowInfo, err = s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, eventWeaning.CowId)
-			if err != nil {
-				return xerr.WithStack(err)
-			}
-			cowInfo.EventWeaningUpdate(int64(req.WeaningAt), req.PenId, int64(cowWeightMap[cowInfo.Id]*1000))
-			if err = tx.Model(new(model.Cow)).
-				Select("pen_id", "current_weight", "weaning_at", "last_weight_at").
-				Where("id = ?", cowInfo.Id).
-				Updates(cowInfo).Error; err != nil {
-				return xerr.WithStack(err)
-			}
-			// 创建牛只的体重记录
-			newEventWeight := model.NewEventWeight(
-				userModel.AppPasture.Id,
-				cowInfo,
-				userModel.SystemUser,
-				&pasturePb.EventWeight{
-					WeightAt:      req.WeaningAt,
-					OperationId:   req.OperationId,
-					OperationName: req.OperationName,
-					Remarks:       req.Remarks,
-					Weight:        float32(cowWeightMap[cowInfo.Id]),
-					Height:        0,
-				})
-			if err = tx.Create(newEventWeight).Error; err != nil {
-				return xerr.WithStack(err)
-			}
-		}
-
-		return nil
-	}); err != nil {
-		return xerr.WithStack(err)
-	}
-	return nil
-}

+ 246 - 0
module/backend/event_breed_more.go

@@ -2,6 +2,7 @@ package backend
 
 import (
 	"context"
+	"errors"
 	"kpt-pasture/model"
 	"kpt-pasture/util"
 	"net/http"
@@ -252,3 +253,248 @@ func (s *StoreEntry) AbortionList(
 		},
 	}, nil
 }
+
+func (s *StoreEntry) MatingList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.EventMatingResponse, error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	matingList := make([]*model.EventMating, 0)
+	var count int64 = 0
+	pref := s.DB.Model(new(model.EventMating)).
+		Where("mating_result > ?", pasturePb.MatingResult_Invalid).
+		Where("status = ?", pasturePb.IsShow_Ok).
+		Where("pasture_id = ?", userModel.AppPasture.Id)
+	if len(req.CowId) > 0 {
+		cowIds := strings.Split(req.CowId, ",")
+		pref.Where("cow_id IN ?", cowIds)
+	}
+
+	if err = pref.Order("id desc").
+		Count(&count).Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Find(&matingList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	exposeEstrusTypeMap := s.ExposeEstrusTypeMap()
+	return &pasturePb.EventMatingResponse{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &pasturePb.SearchMatingData{
+			List:     model.EventMatingSlice(matingList).ToPB(exposeEstrusTypeMap),
+			Total:    int32(count),
+			PageSize: pagination.PageSize,
+			Page:     pagination.Page,
+		},
+	}, nil
+}
+
+// MatingCreate 牛只配种
+func (s *StoreEntry) MatingCreate(ctx context.Context, req *pasturePb.EventMating) (err error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	eventMatingCheckModel, err := s.MatingCreateCheck(ctx, userModel.AppPasture.Id, req)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	req.OperationName = eventMatingCheckModel.OperationUser.Name
+	if err = s.DB.Transaction(func(tx *gorm.DB) error {
+		for _, cow := range eventMatingCheckModel.CowList {
+			// 获取牛只最近一次配种信息
+			lastEventMating, err := s.FindLastEventMatingByCowId(ctx, userModel.AppPasture.Id, cow.Id)
+			if err != nil {
+				// 1. 没有配种信息,(第一次参加配种的牛只,并且没有参与同期的牛只 )
+				if errors.Is(err, gorm.ErrRecordNotFound) {
+					newMating := model.NewEventMatingNaturalEstrus(userModel.AppPasture.Id, cow, req, userModel.SystemUser)
+					if err = tx.Create(newMating).Error; err != nil {
+						return xerr.WithStack(err)
+					}
+					if err = s.MatingCowUpdate(ctx, userModel.AppPasture.Id, cow, req, false); err != nil {
+						return xerr.WithStack(err)
+					}
+					continue
+				} else {
+					return xerr.WithStack(err)
+				}
+			}
+
+			// 2. 所有有配种数据的牛只
+			if lastEventMating == nil || lastEventMating.Id <= 0 || lastEventMating.Status != pasturePb.IsShow_No {
+				zaplog.Error("MatingCreate", zap.Any("cow", cow), zap.Any("UserModel", userModel))
+				return xerr.Customf("牛只配种数据异常: %d", cow.EarNumber)
+			}
+
+			// 2.1 复配 => 本胎次配次不加1
+			isReMating := lastEventMating.IsReMating(cow, int64(req.MatingAt))
+			if isReMating {
+				lastEventMating.EventReMatingUpdate(int64(req.MatingAt))
+				if err = tx.Model(lastEventMating).
+					Select("mating_result", "mating_result_at", "status").
+					Where("id = ?", lastEventMating.Id).
+					Updates(lastEventMating).Error; err != nil {
+				}
+			}
+
+			// 2.2.  同期初配
+			IsMatingUpdate := lastEventMating.IsMatingUpdate()
+			if IsMatingUpdate {
+				lastEventMating.EventUpdate(int64(req.MatingAt), req.FrozenSemenNumber, isReMating, eventMatingCheckModel.OperationUser, userModel.SystemUser)
+				if err = tx.Model(lastEventMating).
+					Select("mating_at", "status", "reality_day", "frozen_semen_number", "operation_id", "operation_name", "message_id", "message_name").
+					Where("id = ?", lastEventMating.Id).
+					Updates(lastEventMating).Error; err != nil {
+					return xerr.WithStack(err)
+				}
+			}
+
+			// 2.3. 提交的配种数据中,定位出空怀的牛只,
+			isEmptyMating := lastEventMating.IsEmptyMating(cow, int64(req.MatingAt))
+			if isEmptyMating {
+				// 把上次配种结果信息更新成空怀
+				lastEventMating.EventMatingResultUpdate(pasturePb.MatingResult_Empty, int64(req.MatingAt))
+				if err = tx.Model(lastEventMating).
+					Select("mating_result", "mating_result_at").
+					Where("id = ?", lastEventMating.Id).
+					Updates(lastEventMating).Error; err != nil {
+					return xerr.WithStack(err)
+				}
+				// 先创建一条新的配种数据
+				newMating := model.NewEventMating(userModel.AppPasture.Id, cow, int64(req.MatingAt), req.ExposeEstrusType)
+				newMating.EventUpdate(int64(req.MatingAt), req.FrozenSemenNumber, isReMating, eventMatingCheckModel.OperationUser, userModel.SystemUser)
+				if err = tx.Model(newMating).Create(newMating).Error; err != nil {
+					return xerr.WithStack(err)
+				}
+
+				// 更新牛只配种结果日志
+				if err = s.UpdateMatingResultEventCowLogByCowId(ctx, cow.Id, s.MatingResultMap()[pasturePb.MatingResult_Empty]); err != nil {
+					zaplog.Error("MatingCreate", zap.Any("UpdateEventCowLogByCowId", err), zap.Any("cow", cow))
+				}
+			}
+
+			// 牛只基本中配种信息更新
+			if err = s.MatingCowUpdate(ctx, userModel.AppPasture.Id, cow, req, isReMating); err != nil {
+				return xerr.WithStack(err)
+			}
+		}
+
+		// 创建冻精使用记录日志
+		itemFrozenSemenLog := model.NewEventFrozenSemenLog(eventMatingCheckModel.FrozenSemen.PastureId, req)
+		if err = tx.Create(itemFrozenSemenLog).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+		// 减去精液的数量
+		eventMatingCheckModel.FrozenSemen.EventQuantityUpdate(req.FrozenSemenCount)
+		if err = tx.Model(eventMatingCheckModel.FrozenSemen).
+			Select("quantity").
+			Where("id = ?", eventMatingCheckModel.FrozenSemen.Id).
+			Updates(eventMatingCheckModel.FrozenSemen).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+		return nil
+	}); err != nil {
+		return xerr.WithStack(err)
+	}
+
+	return nil
+}
+
+func (s *StoreEntry) MatingCowUpdate(ctx context.Context, pastureId int64, cow *model.Cow, req *pasturePb.EventMating, isReMating bool) error {
+	// 牛只基本中配种信息更新
+	cow.EventMatingUpdate(int64(req.MatingAt), req.FrozenSemenNumber, isReMating)
+	if err := s.DB.Model(cow).
+		Select("last_mating_at", "mating_times", "last_bull_number", "first_mating_at", "is_pregnant", "breed_status").
+		Where("id = ?", cow.Id).
+		Updates(cow).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	// 记录日志
+	cowLogs := s.SubmitEventLog(ctx, pastureId, cow, pasturePb.EventType_Mating, req.ExposeEstrusType, req)
+	if err := s.DB.Table(cowLogs.TableName()).Create(cowLogs).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}
+
+func (s *StoreEntry) WeaningBatch(ctx context.Context, req *pasturePb.EventWeaningBatch) (err error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if len(req.Items) <= 0 {
+		return nil
+	}
+	cowIds := make([]int64, 0)
+	cowWeightMap := make(map[int64]float64)
+	for _, item := range req.Items {
+		cowIds = append(cowIds, int64(item.CowId))
+		cowWeightMap[int64(item.CowId)] = float64(item.Weight)
+	}
+
+	eventWeaningList := make([]*model.EventWeaning, 0)
+	if err = s.DB.Model(new(model.EventWeaning)).
+		Where("cow_id IN ?", cowIds).
+		Where("status = ?", pasturePb.IsShow_No).
+		Find(&eventWeaningList).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+
+	operation, err := s.GetSystemUserById(ctx, int64(req.OperationId))
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if err = s.DB.Transaction(func(tx *gorm.DB) error {
+		cowInfo := &model.Cow{}
+		for _, eventWeaning := range eventWeaningList {
+			eventWeaning.EventUpdate(int64(req.WeaningAt), int32(cowWeightMap[cowInfo.Id]*1000), req.Remarks, req.PenId, operation, userModel.SystemUser)
+			if err = tx.Model(new(model.EventWeaning)).
+				Select("status", "reality_day", "operation_id", "operation_name", "message_id", "message_name", "remarks", "after_pen_id").
+				Where("id = ?", eventWeaning.Id).
+				Updates(eventWeaning).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+			cowInfo, err = s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, eventWeaning.CowId)
+			if err != nil {
+				return xerr.WithStack(err)
+			}
+			cowInfo.EventWeaningUpdate(int64(req.WeaningAt), req.PenId, int64(cowWeightMap[cowInfo.Id]*1000))
+			if err = tx.Model(new(model.Cow)).
+				Select("pen_id", "current_weight", "weaning_at", "last_weight_at").
+				Where("id = ?", cowInfo.Id).
+				Updates(cowInfo).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+			// 创建牛只的体重记录
+			eventWeight := &pasturePb.EventWeight{
+				WeightAt:      req.WeaningAt,
+				OperationId:   req.OperationId,
+				OperationName: req.OperationName,
+				Remarks:       req.Remarks,
+				Weight:        float32(cowWeightMap[cowInfo.Id]),
+				Height:        0,
+			}
+			newEventWeight := model.NewEventWeight(userModel.AppPasture.Id, cowInfo, userModel.SystemUser, eventWeight)
+			if err = tx.Create(newEventWeight).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+			// 记录事件日志
+			cowLogs := s.SubmitEventLog(ctx, userModel.AppPasture.Id, cowInfo, pasturePb.EventType_Weaning, pasturePb.ExposeEstrusType_Invalid, req)
+			if err = tx.Table(cowLogs.TableName()).Create(cowLogs).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+		}
+
+		return nil
+	}); err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}

+ 29 - 9
module/backend/event_cow_log.go

@@ -85,14 +85,26 @@ func (s *StoreEntry) SubmitEventLog(
 		data := req.(*pasturePb.EventCalving)
 		eventAt = int64(data.CalvingAt)
 		desc = fmt.Sprintf("怀孕天数:%d;难产等级: %s;产子数量: %d;", cow.PregnancyAge, s.CalvingLevelMap()[data.CalvingLevel], data.ChildNumber)
-		for _, v := range data.CalfItemList {
-			if v.CowId > 0 {
-				desc += fmt.Sprintf("犊牛耳号: %s; 出生体重: %s KG;", v.EarNumber, strconv.FormatFloat(float64(v.Weight), 'f', 2, 64))
-			}
-		}
-		if data.IsInducingChildbirth == pasturePb.IsShow_Ok {
+		if data.CalvingLevel > pasturePb.CalvingLevel_Natural_Childbirth {
 			desc += fmt.Sprintf("难产原因: %s", s.DystociaReasonMap()[data.DystociaReason])
 		}
+		ly, qy, die := 0, 0, 0
+		earNumber := ""
+		if len(data.CalfItemList) > 0 {
+			for _, v := range data.CalfItemList {
+				if v.IsLive == pasturePb.IsShow_Ok && v.IsAdoption == pasturePb.IsShow_No {
+					qy++
+				}
+				if v.IsLive == pasturePb.IsShow_No {
+					die++
+				}
+				if v.IsAdoption == pasturePb.IsShow_Ok {
+					ly++
+					earNumber += fmt.Sprintf("犊牛耳号: %s,出生体重: %s KG;", v.EarNumber, strconv.FormatFloat(float64(v.Weight), 'f', 2, 64))
+				}
+			}
+		}
+		desc += fmt.Sprintf("留养: %d个 %s;弃养: %d; 死亡: %d个", ly, earNumber, qy, die)
 		operationUser.Id = int64(data.OperationId)
 		operationUser.Name = data.OperationName
 		remarks = data.Remarks
@@ -129,18 +141,26 @@ func (s *StoreEntry) SubmitEventLog(
 		operationUser.Name = data.OperationName
 	case pasturePb.EventType_Immunication:
 	case pasturePb.EventType_Weaning:
-		data := req.(*pasturePb.EventWeaningBatchRequest)
+		data := req.(*pasturePb.EventWeaningBatch)
 		eventAt = int64(data.WeaningAt)
 		operationUser.Id = int64(data.OperationId)
 		operationUser.Name = data.OperationName
 		remarks = data.Remarks
-		for _, v := range data.Item {
+		for _, v := range data.Items {
 			if int64(v.CowId) == cow.Id {
-				desc = fmt.Sprintf("具体体重: %f", v.Weight)
+				desc = fmt.Sprintf("具体体重: %s", strconv.FormatFloat(float64(v.Weight), 'f', 2, 64))
 				break
 			}
 		}
 	case pasturePb.EventType_Sale:
+		data := req.(*pasturePb.EventCowSale)
+		eventAt = int64(data.SaleAt)
+		for _, v := range data.CowIds {
+			if int64(v) == cow.Id {
+				desc = fmt.Sprintf("经销商: %s,单价: %s", data.DealerName, strconv.FormatFloat(float64(data.SalePrice), 'f', 2, 64))
+				break
+			}
+		}
 	case pasturePb.EventType_Abort:
 		data := req.(*pasturePb.EventAbortionItem)
 		eventAt = int64(data.AbortionAt)

+ 4 - 2
module/backend/interface.go

@@ -180,7 +180,7 @@ type EventService interface {
 	AbortionList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.EventAbortionResponse, error)
 	AbortionCreateBatch(ctx context.Context, req *pasturePb.EventAbortionBatch) error
 	// WeaningBatch 断奶
-	WeaningBatch(ctx context.Context, req *pasturePb.EventWeaningBatchRequest) error
+	WeaningBatch(ctx context.Context, req *pasturePb.EventWeaningBatch) error
 	// SameTimeCreate 同期
 	SameTimeCreate(ctx context.Context, req *pasturePb.EventSameTime) error
 	SameTimeBatch(ctx context.Context, req *pasturePb.EventSameTimeBatch) error
@@ -207,6 +207,9 @@ type EventService interface {
 	CowEarNumberUpdate(ctx context.Context, req *pasturePb.EventReplaceEarNumber) error
 	// SubmitEventLog 记录提交事件结果日志
 	SubmitEventLog(ctx context.Context, pastureId int64, cow *model.Cow, eventType pasturePb.EventType_Kind, exposeEstrusType pasturePb.ExposeEstrusType_Kind, req interface{}) *model.EventCowLog
+
+	CowSaleCreate(ctx context.Context, req *pasturePb.EventCowSale) error
+	//CowSaleList(ctx context.Context, req *pasturePb.EventCowSale) error
 }
 
 //go:generate mockgen -destination mock/CowService.go -package kptservicemock kpt-pasture/module/backend CowService
@@ -260,7 +263,6 @@ type AnalyseService interface {
 
 //go:generate mockgen -destination mock/DashboardService.go -package kptservicemock kpt-pasture/module/backend DashboardService
 type DashboardService interface {
-	Bar(ctx context.Context) (*pasturePb.BarCowStructResponse, error)
 	NeckRingWarning(ctx context.Context) (*pasturePb.IndexNeckRingResponse, error)
 	FocusIndicatorsList(ctx context.Context, dimension string) (*pasturePb.IndexFocusIndicatorsResponse, error)
 	FocusIndicatorsSet(ctx context.Context, req *pasturePb.IndexFocusIndicatorsSetRequest) error

+ 9 - 5
util/util.go

@@ -1,6 +1,7 @@
 package util
 
 import (
+	"bytes"
 	"fmt"
 	"math"
 	"math/rand"
@@ -532,14 +533,17 @@ func CurrentMaxFrameId() int32 {
 }
 
 func ArrayInt32ToStrings(cowIds []int32, cutset string) string {
-	cows := ""
+	var cows bytes.Buffer
 	if len(cowIds) <= 0 {
-		return cows
+		return cows.String()
 	}
-	for _, v := range cowIds {
-		cows += fmt.Sprintf("%d,", v)
+	for i, v := range cowIds {
+		if i > 0 {
+			cows.WriteString(cutset)
+		}
+		cows.WriteString(strconv.Itoa(int(v))) // 将整数转换为字符串
 	}
-	return strings.TrimRight(cows, cutset)
+	return cows.String()
 }
 
 // ConvertCowIdsToInt64Slice 将逗号拼接的字符串转换为 int64 切片

+ 2 - 20
util/util_test.go

@@ -1,13 +1,10 @@
 package util
 
 import (
-	"encoding/json"
 	"fmt"
 	"testing"
 	"time"
 
-	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
-
 	"github.com/stretchr/testify/assert"
 )
 
@@ -511,21 +508,6 @@ func TestGetNeckRingActiveTimer(t *testing.T) {
 
 func Test_demo(t *testing.T) {
 
-	s := `[{"id":1,"sameTimeName":"PG保健1","sameTimeType":1,"nextNodeDay":7,"nextId":2,"showDays":"7 ~ 14","sumStart":7,"sumEnd":14},{"id":2,"sameTimeName":"PG保健2","sameTimeType":1,"nextNodeDay":7,"nextId":3,"showDays":"14 ~ 21","sumStart":14,"sumEnd":21},{"id":3,"sameTimeName":"PG保健3","sameTimeType":1,"nextNodeDay":3,"nextId":4,"showDays":"21 ~ 28","sumStart":21,"sumEnd":28},{"id":4,"sameTimeName":"RnGH1","sameTimeType":3,"nextNodeDay":7,"nextId":5,"showDays":"24 - 31","sumStart":24,"sumEnd":31},{"id":5,"sameTimeName":"PG同期1","sameTimeType":2,"nextNodeDay":2,"nextId":6,"showDays":"31 - 38","sumStart":31,"sumEnd":38},{"id":6,"sameTimeName":"RnGH2","sameTimeType":3,"nextNodeDay":1,"nextId":7,"showDays":"33 - 40","sumStart":33,"sumEnd":40},{"id":7,"sameTimeName":"TAI输精","sameTimeType":4,"showDays":"34 - 41","sumStart":34,"sumEnd":41}]`
-	collateNodes := make([]*pasturePb.CollateNode, 0)
-	err := json.Unmarshal([]byte(s), &collateNodes)
-	if err != nil {
-		fmt.Println(err)
-		return
-	}
-
-	nowTime := time.Now()
-	for i, collateNode := range collateNodes {
-		showDay := nowTime
-		if i > 0 {
-			showDay = nowTime.AddDate(0, 0, int(collateNode.NextNodeDay))
-		}
-		fmt.Println(collateNode.NextNodeDay, showDay.Format("2006-01-02"))
-	}
-
+	a := []int32{}
+	fmt.Println(ArrayInt32ToStrings(a, ","))
 }