Przeglądaj źródła

event: sale 增加淘汰内容

Yi 1 tydzień temu
rodzic
commit
704e4a8fb4

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250403023152-3351c34ff8e2
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250407033055-a88907fe2237
 	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

@@ -114,6 +114,16 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250403015930-728ac52191ed h1:jdfxjd7T
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250403015930-728ac52191ed/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250403023152-3351c34ff8e2 h1:DxuqalLwzBemnGnXn3NK/WvtH3k1elUIVXEHRP2QSvA=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250403023152-3351c34ff8e2/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407020514-55972b3e4a6e h1:fTLVj1uD3o0VzxS0G2n3j8uqHGTGFmaEcJAAGum/rDs=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407020514-55972b3e4a6e/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407030104-bbed5685c433 h1:cD1+JL5SH7p3VDc/Ih+r3J1nvluUD7qmPdLoUAaZk8g=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407030104-bbed5685c433/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407030911-c3f05890c9db h1:isImECfyemll26Bd/aeGKCdTCC6W1cfLYWDKbozNMf4=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407030911-c3f05890c9db/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407031505-811f84cb2ef7 h1:pzfT/1FwyhgoNvn7V6Y7H5o8K2gb7l/btxJKJGHP754=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407031505-811f84cb2ef7/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407033055-a88907fe2237 h1:MrPG3W7f/Mbb7x3JpNnngDgHr/YQD6OOuGAyX3tqXyg=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250407033055-a88907fe2237/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=

+ 1 - 1
http/handler/cow/cow.go

@@ -28,7 +28,7 @@ func Detail(c *gin.Context) {
 
 	res, err := middleware.Dependency(c).StoreEventHub.OpsService.Detail(c, &req)
 	if err != nil {
-		apierr.ClassifiedAbort(c, err)
+		apierr.AbortBadRequest(c, http.StatusOK, err)
 		return
 	}
 	ginutil.JSONResp(c, res)

+ 1 - 1
http/handler/event/event_base.go

@@ -306,7 +306,7 @@ func CowSale(c *gin.Context) {
 		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.EarNumbers, 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)

+ 36 - 43
model/event_sale.go

@@ -1,39 +1,40 @@
 package model
 
 import (
-	"strconv"
 	"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"`
-	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"`
+	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"`
+	SaleKind         pasturePb.SalesType_Kind  `json:"saleKind"`
+	OutReasonsKind   pasturePb.OutReasons_Kind `json:"outReasonsKind"`
+	OutReasonsName   string                    `json:"outReasonsName"`
+	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 {
+func NewEventSale(pastureId int64, dealerInfo *SaleDealer, req *pasturePb.EventCowSale, operationUser, currUser *SystemUser) *EventSale {
 	return &EventSale{
 		PastureId:        pastureId,
 		DealerId:         dealerInfo.Id,
@@ -41,8 +42,10 @@ func NewEventSale(pastureId int64, dealerInfo *SaleDealer, cowIds string, req *p
 		SalePrice:        float64(req.SalePrice),
 		SaleAllWeight:    int32(req.SaleAllWeight * 1000),
 		SaleAllAmount:    float64(req.SaleAllPrice),
-		SaleCowCount:     int32(len(req.CowIds)),
-		CowIds:           cowIds,
+		SaleCowCount:     int32(len(req.EarNumbers)),
+		SaleKind:         req.SalesType,
+		OutReasonsKind:   req.OutReasonsKind,
+		OutReasonsName:   req.OutReasonsName,
 		SaleAt:           int64(req.SaleAt),
 		SaleTicker:       strings.Join(req.SaleTicket, ","),
 		QuarantineReport: strings.Join(req.QuarantineReport, ","),
@@ -56,29 +59,15 @@ func NewEventSale(pastureId int64, dealerInfo *SaleDealer, cowIds string, req *p
 
 type EventSaleSlice []*EventSale
 
-func (e EventSaleSlice) ToPB(eventSaleCarMap map[int64][]*EventSaleCar) []*pasturePb.EventCowSale {
+func (e EventSaleSlice) ToPB(eventSaleCarMap map[int64][]*EventSaleCar, eventSaleCowList []*EventSaleCow) []*pasturePb.EventCowSale {
 	res := make([]*pasturePb.EventCowSale, len(e))
 	for i, v := range e {
-		cowIds := make([]int32, 0)
-		if len(v.CowIds) > 0 {
-			for _, cowIdStr := range strings.Split(v.CowIds, ",") {
-				cowId, _ := strconv.Atoi(cowIdStr)
-				cowIds = append(cowIds, int32(cowId))
-			}
-		}
-
 		saleVehicleItems := make([]*pasturePb.SaleVehicleItem, 0)
 		eventSaleCarItems, ok := eventSaleCarMap[v.Id]
+		earNumbers := make([]string, 0)
 		if ok {
-
 			for _, item := range eventSaleCarItems {
-				carCowIds := make([]int32, 0)
-				if len(item.CowIds) > 0 {
-					for _, cowIdStr := range strings.Split(item.CowIds, ",") {
-						carCowId, _ := strconv.Atoi(cowIdStr)
-						carCowIds = append(carCowIds, int32(carCowId))
-					}
-				}
+				es := strings.Split(item.EarNumbers, ",")
 				saleVehicleItems = append(saleVehicleItems, &pasturePb.SaleVehicleItem{
 					CarNumber:         item.CarNumber,
 					CowCount:          item.CowCount,
@@ -86,15 +75,19 @@ func (e EventSaleSlice) ToPB(eventSaleCarMap map[int64][]*EventSaleCar) []*pastu
 					OutboundTicket:    item.OutboundTicket,
 					WeighbridgePhotos: strings.Split(item.WeighbridgePhotos, ","),
 					VehiclePhotos:     strings.Split(item.CarPhotos, ","),
-					CowIds:            carCowIds,
+					EarNumbers:        es,
 				})
+				earNumbers = append(earNumbers, es...)
 			}
 		}
 		res[i] = &pasturePb.EventCowSale{
 			DealerId:         v.DealerId,
 			DealerName:       v.DealerName,
 			SaleAt:           int32(v.SaleAt),
-			CowIds:           cowIds,
+			EarNumbers:       earNumbers,
+			SalesType:        v.SaleKind,
+			OutReasonsKind:   v.OutReasonsKind,
+			OutReasonsName:   v.OutReasonsName,
 			SaleAllWeight:    float32(v.SaleAllWeight) / 1000,
 			SaleAllPrice:     float32(v.SaleAllAmount),
 			SalePrice:        float32(v.SalePrice),
@@ -103,7 +96,7 @@ func (e EventSaleSlice) ToPB(eventSaleCarMap map[int64][]*EventSaleCar) []*pastu
 			Remarks:          v.Remarks,
 			SaleTicket:       strings.Split(v.SaleTicker, ","),
 			QuarantineReport: strings.Split(v.QuarantineReport, ","),
-			SaleVehicleItems: nil,
+			SaleVehicleItems: saleVehicleItems,
 		}
 	}
 	return res

+ 2 - 2
model/event_sale_car.go

@@ -14,7 +14,7 @@ type EventSaleCar struct {
 	CarNumber         string `json:"carNumber"`
 	CowCount          int32  `json:"cowCount"`
 	CowWeight         int64  `json:"cowWeight"`
-	CowIds            string `json:"cowIds"`
+	EarNumbers        string `json:"earNumbers"`
 	OutboundTicket    string `json:"outbound_ticket"`
 	WeighbridgePhotos string `json:"weighbridgePhotos"`
 	CarPhotos         string `json:"carPhotos"`
@@ -33,7 +33,7 @@ func NewEventSaleCar(pastureId, saleId, saleAt int64, saleVehicleItem *pasturePb
 		SaleAt:            saleAt,
 		CarNumber:         saleVehicleItem.CarNumber,
 		CowCount:          saleVehicleItem.CowCount,
-		CowIds:            "",
+		EarNumbers:        strings.Join(saleVehicleItem.EarNumbers, ","),
 		OutboundTicket:    saleVehicleItem.OutboundTicket,
 		WeighbridgePhotos: strings.Join(saleVehicleItem.WeighbridgePhotos, ","),
 		CarPhotos:         strings.Join(saleVehicleItem.VehiclePhotos, ","),

+ 45 - 0
model/event_sale_cow.go

@@ -0,0 +1,45 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type EventSaleCow struct {
+	Id           int64                      `json:"id"`
+	PastureId    int64                      `json:"pastureId"`
+	SaleId       int64                      `json:"saleId"`
+	CowId        int64                      `json:"cowId"`
+	EarNumber    string                     `json:"earNumber"`
+	Lact         int32                      `json:"lact"`
+	PregnancyAge int32                      `json:"pregnancyAge"`
+	BreedStatus  pasturePb.BreedStatus_Kind `json:"breedStatus"`
+	LactationAge int32                      `json:"lactationAge"`
+	CalvingAge   int32                      `json:"calvingAge"`
+	AdmissionAge int32                      `json:"admissionAge"`
+	CreatedAt    int64                      `json:"createdAt"`
+	UpdatedAt    int64                      `json:"updatedAt"`
+}
+
+func (e *EventSaleCow) TableName() string {
+	return "event_sale_cow"
+}
+
+func NewEventSaleCow(pastureId int64, saleId int64, cowInfo *Cow) *EventSaleCow {
+	return &EventSaleCow{
+		PastureId:    pastureId,
+		SaleId:       saleId,
+		CowId:        cowInfo.Id,
+		Lact:         cowInfo.Lact,
+		EarNumber:    cowInfo.EarNumber,
+		PregnancyAge: cowInfo.PregnancyAge,
+		BreedStatus:  cowInfo.BreedStatus,
+		LactationAge: cowInfo.LactationAge,
+		AdmissionAge: cowInfo.AdmissionAge,
+	}
+}
+
+func NewEventSaleCowList(pastureId int64, saleId int64, cowList []*Cow) []*EventSaleCow {
+	res := make([]*EventSaleCow, 0)
+	for _, cow := range cowList {
+		res = append(res, NewEventSaleCow(pastureId, saleId, cow))
+	}
+	return res
+}

+ 50 - 0
module/backend/config_data_base.go

@@ -265,3 +265,53 @@ func (s *StoreEntry) CowPurposeList(isAll string) []*pasturePb.ConfigOptionsList
 	})
 	return configOptions
 }
+
+func (s *StoreEntry) CowOutReasonList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(0),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReasons_Respiratory_System_Disease),
+		Label:    "呼吸系统疾病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReasons_Nutritional_Metabolic_Disease),
+		Label:    "营养代谢疾病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReasons_Breeding_Disease),
+		Label:    "繁殖疾病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReasons_Breast_Disease),
+		Label:    "乳房疾病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReasons_Hoof_Disease),
+		Label:    "蹄病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReasons_Low_Milk),
+		Label:    "低产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReasons_Slow_Growing),
+		Label:    "生长缓慢",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReasons_Slow_Growing),
+		Label:    "生长缓慢",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReasons_Other),
+		Label:    "其他原因",
+		Disabled: true,
+	})
+	return configOptions
+}

+ 8 - 0
module/backend/enum_map.go

@@ -319,6 +319,14 @@ func (s *StoreEntry) ForbiddenMatingReasonsMap() map[pasturePb.ForbiddenMatingRe
 	return res
 }
 
+func (s *StoreEntry) CowOutReasonsMap() map[pasturePb.OutReasons_Kind]string {
+	res := make(map[pasturePb.OutReasons_Kind]string)
+	for _, v := range s.CowOutReasonList("") {
+		res[pasturePb.OutReasons_Kind(v.Value)] = v.Label
+	}
+	return res
+}
+
 func (s *StoreEntry) eventCategoryMap() map[pasturePb.EventType_Kind]pasturePb.EventCategory_Kind {
 	return map[pasturePb.EventType_Kind]pasturePb.EventCategory_Kind{
 		pasturePb.EventType_Enter:             pasturePb.EventCategory_Base,

+ 1 - 0
module/backend/enum_options.go

@@ -219,6 +219,7 @@ func (s *StoreEntry) SystemBaseConfigOptions(ctx context.Context, optionsName, i
 		"indicatorsDetails":          s.IndicatorsDetailsList,
 		"purposeKind":                s.CowPurposeList,
 		"forbiddenMatingReasons":     s.ForbiddenMatingReasonsEnumList,
+		"cowOutReason":               s.CowOutReasonList,
 	}
 
 	getConfigFunc, ok := getConfigFuncMap[optionsName]

+ 38 - 19
module/backend/event_base_more.go

@@ -3,7 +3,6 @@ package backend
 import (
 	"context"
 	"kpt-pasture/model"
-	"kpt-pasture/util"
 	"net/http"
 	"strings"
 
@@ -120,20 +119,11 @@ func (s *StoreEntry) CowSaleCreate(ctx context.Context, req *pasturePb.EventCowS
 		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)
+	cowList, err := s.GetCowInfoByEarNumbers(ctx, userModel.AppPasture.Id, req.EarNumbers)
 	if err != nil {
 		return xerr.WithStack(err)
 	}
-	if len(cowList) != len(req.CowIds) {
+	if len(cowList) != len(req.EarNumbers) {
 		return xerr.Custom("数据异常")
 	}
 
@@ -142,7 +132,9 @@ func (s *StoreEntry) CowSaleCreate(ctx context.Context, req *pasturePb.EventCowS
 	}
 
 	dealerInfo := &model.SaleDealer{}
-	if err = s.DB.Model(new(model.SaleDealer)).Where("id = ?", req.DealerId).First(dealerInfo).Error; err != nil {
+	if err = s.DB.Model(new(model.SaleDealer)).
+		Where("id = ?", req.DealerId).
+		First(dealerInfo).Error; err != nil {
 		return xerr.Custom("经销商数据异常")
 	}
 	req.DealerName = dealerInfo.Name
@@ -153,8 +145,17 @@ func (s *StoreEntry) CowSaleCreate(ctx context.Context, req *pasturePb.EventCowS
 	}
 	req.OperationName = operationUser.Name
 
-	cowIdsStr := util.ArrayInt32ToStrings(req.CowIds, ",")
-	newEventSale := model.NewEventSale(userModel.AppPasture.Id, dealerInfo, cowIdsStr, req, operationUser, userModel.SystemUser)
+	if req.SalesType == pasturePb.SalesType_Sales {
+		req.OutReasonsKind = pasturePb.OutReasons_Invalid
+	}
+
+	if req.SalesType == pasturePb.SalesType_Out {
+		if name, ok := s.CowOutReasonsMap()[req.OutReasonsKind]; ok {
+			req.OutReasonsName = name
+		}
+	}
+
+	newEventSale := model.NewEventSale(userModel.AppPasture.Id, dealerInfo, req, operationUser, userModel.SystemUser)
 	eventCowLogList := make([]*model.EventCowLog, 0)
 	for _, cow := range cowList {
 		newEventCowLog := s.SubmitEventLog(ctx, userModel.AppPasture.Id, cow, pasturePb.EventType_Sale, req)
@@ -163,17 +164,27 @@ func (s *StoreEntry) CowSaleCreate(ctx context.Context, req *pasturePb.EventCowS
 
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		// 创建销售数据
-		if err = tx.Model(new(model.EventSale)).Create(newEventSale).Error; err != nil {
+		if err = tx.Model(new(model.EventSale)).
+			Create(newEventSale).Error; err != nil {
 			return xerr.WithStack(err)
 		}
 
 		newEventSaleCarList := model.NewEventSaleCarList(userModel.AppPasture.Id, newEventSale.Id, newEventSale.SaleAt, req.SaleVehicleItems)
-		if err = tx.Model(new(model.EventSaleCar)).Create(&newEventSaleCarList).Error; err != nil {
+		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 {
+		if err = tx.Model(new(model.Cow)).Where("ear_number IN (?)", req.EarNumbers).
+			Update("admission_status", pasturePb.AdmissionStatus_Sale).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+		// 新增销售牛只数据
+		newEventSaleCowList := model.NewEventSaleCowList(userModel.AppPasture.Id, newEventSale.Id, cowList)
+		if err = tx.Model(new(model.EventSaleCow)).
+			Create(&newEventSaleCowList).Error; err != nil {
 			return xerr.WithStack(err)
 		}
 
@@ -236,11 +247,19 @@ func (s *StoreEntry) CowSaleList(ctx context.Context, req *pasturePb.EventCowSal
 		eventSaleCarMap[car.SaleId] = append(eventSaleCarMap[car.SaleId], car)
 	}
 
+	eventSaleCowList := make([]*model.EventSaleCow, 0)
+	if err = s.DB.Model(new(model.EventSaleCow)).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Where("sale_id IN (?)", saleIds).
+		Find(&eventSaleCowList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
 	return &pasturePb.EventCowSaleResponse{
 		Code: http.StatusOK,
 		Msg:  "ok",
 		Data: &pasturePb.EventCowSaleData{
-			List:     model.EventSaleSlice(eventSale).ToPB(eventSaleCarMap),
+			List:     model.EventSaleSlice(eventSale).ToPB(eventSaleCarMap, eventSaleCowList),
 			Total:    int32(count),
 			PageSize: pagination.PageSize,
 			Page:     pagination.Page,

+ 2 - 2
module/backend/event_cow_log.go

@@ -160,8 +160,8 @@ func (s *StoreEntry) SubmitEventLog(ctx context.Context, pastureId int64, cow *m
 	case pasturePb.EventType_Sale:
 		data := req.(*pasturePb.EventCowSale)
 		eventAt = int64(data.SaleAt)
-		for _, v := range data.CowIds {
-			if int64(v) == cow.Id {
+		for _, v := range data.EarNumbers {
+			if v == cow.EarNumber {
 				desc = fmt.Sprintf("经销商: %s,单价: %s", data.DealerName, strconv.FormatFloat(float64(data.SalePrice), 'f', 2, 64))
 				break
 			}

+ 12 - 0
module/backend/sql.go

@@ -179,6 +179,18 @@ func (s *StoreEntry) GetCowInfoByEarNumber(ctx context.Context, pastureId int64,
 	return cowInfo, nil
 }
 
+func (s *StoreEntry) GetCowInfoByEarNumbers(ctx context.Context, pastureId int64, earNumbers []string) ([]*model.Cow, error) {
+	cowList := make([]*model.Cow, 0)
+	if err := s.DB.Model(new(model.Cow)).
+		Where("pasture_id = ?", pastureId).
+		Where("ear_number IN (?)", earNumbers).
+		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
+		Find(&cowList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	return cowList, nil
+}
+
 func (s *StoreEntry) GetCowInfoByCowId(ctx context.Context, pastureId, cowId int64) (*model.Cow, error) {
 	cowData := &model.Cow{Id: cowId}
 	if err := s.DB.Model(new(model.Cow)).