Browse Source

eventCowLog: 增加事件日志落库

Yi 3 months ago
parent
commit
445676f936

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20241224084901-9a0b78705dd6
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20241226082956-7a730dffe7ba
 	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

+ 16 - 0
go.sum

@@ -80,6 +80,22 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20241223072631-d6d7cc8fef31 h1:KSfnFVKS
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241223072631-d6d7cc8fef31/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241224084901-9a0b78705dd6 h1:dw2s50DrIIf7wOxOcIspSRFKNgvadWMgrEZZNpbO9Ho=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241224084901-9a0b78705dd6/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241225065133-fd61d6c760a3 h1:MjADeMzUIM6dmShAuYeqyz8DPzCmRBWdsFPnvZ6IQTE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241225065133-fd61d6c760a3/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241225070554-b4f496c60ddf h1:g4pcj4EJPmsuWRv6pDYvHaeIls4X5k0YIwmXU7tOidc=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241225070554-b4f496c60ddf/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241225071614-71960ce0e967 h1:nFcpJG9E+YM9XUVFjZ290jxTmvdQrqjEmz1WKvu72vs=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241225071614-71960ce0e967/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241225090543-f6e1bd2be3c9 h1:YszVUdVh1Hh8iTqzSShSPELH5nhVn1XWGYPaPjS12dw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241225090543-f6e1bd2be3c9/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241225110632-d4472512412e h1:2Ch8Yx/m+//0Hbzl3yjFxwBOe1CFDfFdri+fzDHQcQQ=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241225110632-d4472512412e/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241226071350-4226aff28f62 h1:NfhUVP7lNOhzaoOnHDnjksZQkqUyTphbwGR8xgNmx3E=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241226071350-4226aff28f62/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241226082350-bd279d6d7998 h1:66soxkvWLLsTW1oDd4Bf+DC95C90Y5yjGnFA+BtIyYs=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241226082350-bd279d6d7998/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241226082956-7a730dffe7ba h1:6j33896HgXCH4UBcFpVqqM3sEy1QvEm5Q8VtcBWxC1k=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241226082956-7a730dffe7ba/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=

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

@@ -228,3 +228,38 @@ func WeightBatch(c *gin.Context) {
 		Data: &operationPb.Success{Success: true},
 	})
 }
+
+func Departure(c *gin.Context) {
+	var req pasturePb.EventDepartureBatch
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.Item, valid.Required, valid.Each(valid.By(func(value interface{}) error {
+			s := value.(pasturePb.EventDeparture)
+			return valid.ValidateStruct(&s,
+				valid.Field(&s.DepartureAt, valid.Required),
+				valid.Field(&s.DepartureType, valid.Required),
+				valid.Field(&s.DepartureReason, valid.Required),
+				valid.Field(&s.OperationId, valid.Required),
+				valid.Field(&s.CowId, valid.Required),
+			)
+		}))),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.BackendOperation(c).OpsService.DepartureBatch(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}

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

@@ -268,12 +268,7 @@ func SameTimeBatch(c *gin.Context) {
 		valid.Field(&req.OperationId, valid.Required),
 		valid.Field(&req.DrugsId, valid.Required),
 		valid.Field(&req.SameTimeAt, valid.Required),
-		valid.Field(&req.Item, valid.Required, valid.Each(valid.By(func(value interface{}) error {
-			item := value.(pasturePb.EventSameTimeItem)
-			return valid.ValidateStruct(&item,
-				valid.Field(&item.CowId, valid.Required),
-			)
-		}))),
+		valid.Field(&req.CowIds, valid.Required),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return

+ 36 - 0
http/handler/pasture/seme_time.go

@@ -96,3 +96,39 @@ func SameTimeIsShow(c *gin.Context) {
 		Data: &operationPb.Success{Success: true},
 	})
 }
+
+func SystemBasicList(c *gin.Context) {
+	res, err := middleware.BackendOperation(c).OpsService.SystemBasicList(c)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, res)
+}
+
+func SystemBasicEdit(c *gin.Context) {
+	var req pasturePb.BaseDataConfig
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.Id, valid.Required),
+		valid.Field(&req.Name, valid.Required),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	err := middleware.BackendOperation(c).OpsService.SystemBasicEdit(c, &req)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}

+ 2 - 0
http/route/event_api.go

@@ -63,5 +63,7 @@ func EventAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		eventRoute.POST("/disease/treatment/details", event.CowDiseaseTreatmentDetail)
 		// 批量治愈
 		eventRoute.POST("/disease/curable/batch", event.CowDiseaseCurable)
+		// 离场(死亡淘汰)
+		eventRoute.POST("/departure/batch", event.Departure)
 	}
 }

+ 4 - 0
http/route/pasture_api.go

@@ -50,5 +50,9 @@ func PastureManageAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		pastureRoute.POST("/same/time/createOrUpdate", pasture.SameTimeCreatedOrUpdate)
 		pastureRoute.POST("/same/time/list", pasture.SameTimeList)
 		pastureRoute.PUT("/same/time/is_show/:id", pasture.SameTimeIsShow)
+
+		// 基础参数
+		pastureRoute.POST("/system/basic/list", pasture.SystemBasicList)
+		pastureRoute.POST("/system/basic/edit", pasture.SystemBasicEdit)
 	}
 }

+ 41 - 0
model/cow.go

@@ -59,6 +59,47 @@ func (c *Cow) TableName() string {
 	return "cow"
 }
 
+// EventCalvingUpdate 产犊更新
+func (c *Cow) EventCalvingUpdate(calvingAt int64) {
+	c.Lact += 1
+	c.CalvingAge = int64(time.Now().Sub(time.Unix(calvingAt, 0)).Hours() / 24)
+	c.MatingTimes = 0
+	c.PregnancyAge = 0
+	c.BreedStatus = pasturePb.BreedStatus_Calving
+	c.IsPregnant = pasturePb.IsShow_No
+	c.LastCalvingAt = calvingAt
+}
+
+// EventWeaningUpdate 断奶更新
+func (c *Cow) EventWeaningUpdate(weaningAt int64, penId int32, currentWeight int64) {
+	c.PenId = penId
+	c.WeaningAt = weaningAt
+	c.CurrentWeight = currentWeight
+	c.LastWeightAt = weaningAt
+}
+
+// EventPregnantCheckUpdate 孕检更新
+func (c *Cow) EventPregnantCheckUpdate(breedStatus pasturePb.BreedStatus_Kind, pregnantCheckAt int64, isPregnant pasturePb.IsShow_Kind) {
+	c.BreedStatus = breedStatus
+	c.LastPregnantCheckAt = pregnantCheckAt
+	c.IsPregnant = isPregnant
+}
+
+// EventAbortionUpdate 流产更新
+func (c *Cow) EventAbortionUpdate(abortionAt int64) {
+	c.IsPregnant = pasturePb.IsShow_No
+	c.LastAbortionAt = abortionAt
+	c.BreedStatus = pasturePb.BreedStatus_Abort
+}
+
+// EventWeightUpdate 称重更新
+func (c *Cow) EventWeightUpdate(weight int64, weightAt int64) {
+	c.LastSecondWeight = c.CurrentWeight
+	c.LastSecondWeightAt = c.LastWeightAt
+	c.LastWeightAt = weightAt
+	c.CurrentWeight = weight
+}
+
 type CowSlice []*Cow
 
 func (c CowSlice) ToPB(

+ 30 - 31
model/event_cow_log.go

@@ -20,7 +20,7 @@ type EventCowLog struct {
 	EventType        pasturePb.EventType_Kind `json:"eventType"`
 	EventTypeName    string                   `json:"eventTypeName"`
 	EventDescription string                   `json:"eventDescription"`
-	OperationId      int32                    `json:"operationId"`
+	OperationId      int64                    `json:"operationId"`
 	OperationName    string                   `json:"operationName"`
 	EventAt          int64                    `json:"eventAt"`
 	Remarks          string                   `json:"remarks"`
@@ -38,41 +38,40 @@ func (e *EventCowLog) TableName() string {
 }
 
 type EventCowLogModel struct {
-	Cow         *Cow
-	EventType   pasturePb.EventType_Kind
-	Operation   *SystemUser
-	Description string
-	EventAt     int64
+	Cow              *Cow
+	EventType        pasturePb.EventType_Kind
+	OperationUser    *SystemUser
+	CurrentUser      *SystemUser
+	EventAt          int64
+	ExposeEstrusType pasturePb.ExposeEstrusType_Kind
+	PenName          string
+	Remarks          string
+	CowTypeName      string
+	EventTypeName    string
+	Description      string
 }
 
-func NewEventCowLog(
-	cow *Cow,
-	penMap map[int32]*Pen,
-	cowType map[pasturePb.CowType_Kind]string,
-	eventType pasturePb.EventType_Kind,
-	eventTypeName string,
-	operationId int32,
-	operationName string,
-	description string,
-	eventAt int64,
-) *EventCowLog {
-	penName := ""
-	if pen, ok := penMap[cow.PenId]; ok {
-		penName = pen.Name
+func NewEventCowLog(req *EventCowLogModel) *EventCowLog {
+	operationId := int64(0)
+	operationName := ""
+	if req.OperationUser != nil && req.OperationUser.Id > 0 {
+		operationId = req.OperationUser.Id
+		operationName = req.OperationUser.Name
 	}
 	return &EventCowLog{
-		CowId:            cow.Id,
-		DayAge:           cow.GetDayAge(),
-		Lact:             cow.Lact,
-		PenId:            cow.PenId,
-		PenName:          penName,
-		CowType:          cow.CowType,
-		CowTypeName:      cowType[cow.CowType],
-		EventType:        eventType,
-		EventTypeName:    eventTypeName,
-		EventDescription: description,
+		CowId:            req.Cow.Id,
+		DayAge:           req.Cow.GetDayAge(),
+		Lact:             req.Cow.Lact,
+		PenId:            req.Cow.PenId,
+		PenName:          req.PenName,
+		CowType:          req.Cow.CowType,
+		CowTypeName:      req.CowTypeName,
+		EventType:        req.EventType,
+		EventTypeName:    req.EventTypeName,
+		EventDescription: req.Description,
 		OperationId:      operationId,
 		OperationName:    operationName,
-		EventAt:          eventAt,
+		EventAt:          req.EventAt,
+		Remarks:          req.Remarks,
 	}
 }

+ 16 - 1
model/event_cow_same_time.go

@@ -22,9 +22,12 @@ type EventCowSameTime struct {
 	Status        pasturePb.IsShow_Kind       `json:"status"`
 	DrugsId       int64                       `json:"drugsId"`
 	Unit          pasturePb.Unit_Kind         `json:"unit"`
-	Usage         int32                       `json:"usage"`
+	Usage         float32                     `json:"usage"`
+	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"`
 }
@@ -33,6 +36,18 @@ func (s *EventCowSameTime) TableName() string {
 	return "event_cow_same_time"
 }
 
+func (s *EventCowSameTime) Update(drugs *Drugs, usage float32, remarks string, currentUser, operationUser *SystemUser) {
+	s.Status = pasturePb.IsShow_Ok
+	s.DrugsId = drugs.Id
+	s.Unit = drugs.Unit
+	s.Usage = usage
+	s.Remarks = remarks
+	s.OperationId = operationUser.Id
+	s.OperationName = operationUser.Name
+	s.MessageId = currentUser.Id
+	s.MessageName = currentUser.Name
+}
+
 func NewEventCowSameTime(cow *Cow, planTime int64, sameTime *SameTime, sameTimeType pasturePb.SameTimeType_Kind) *EventCowSameTime {
 	return &EventCowSameTime{
 		CowId:        cow.Id,

+ 42 - 0
model/event_departure.go

@@ -0,0 +1,42 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type EventDeparture struct {
+	Id            int64                        `json:"id"`
+	CowId         int64                        `json:"cowId"`
+	Lact          int32                        `json:"lact"`
+	DayAge        int32                        `json:"dayAge"`
+	DepartureAt   int64                        `json:"departureAt"`
+	DepartureType pasturePb.DepartureType_Kind `json:"departureType"`
+	ReasonId      int32                        `json:"reasonId"`
+	ReasonName    string                       `json:"reasonName"`
+	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 *EventDeparture) TableName() string {
+	return "event_departure"
+}
+
+func NewEventDeparture(cow *Cow, req *pasturePb.EventDeparture, reasonName string, currentUser, operationUser *SystemUser) *EventDeparture {
+	return &EventDeparture{
+		CowId:         cow.Id,
+		Lact:          cow.Lact,
+		DayAge:        cow.GetDayAge(),
+		DepartureAt:   int64(req.DepartureAt),
+		DepartureType: req.DepartureType,
+		ReasonId:      req.DepartureReason,
+		ReasonName:    reasonName,
+		Remarks:       req.Remarks,
+		OperationId:   operationUser.Id,
+		OperationName: operationUser.Name,
+		MessageId:     currentUser.Id,
+		MessageName:   currentUser.Name,
+	}
+}

+ 30 - 0
model/event_mating.go

@@ -39,6 +39,36 @@ func (e *EventMating) TableName() string {
 	return "event_mating"
 }
 
+func (e *EventMating) EventUpdate(matingAt int64, bullNumber string, operationUser, currentUser *SystemUser) {
+	e.MatingResult = pasturePb.MatingResult_Unknown
+	e.Status = pasturePb.IsShow_Ok
+	e.RealityDay = matingAt
+	e.FrozenSemenNumber = bullNumber
+	e.OperationName = operationUser.Name
+	e.OperationId = operationUser.Id
+	e.MessageName = currentUser.Name
+	e.MessageId = currentUser.Id
+}
+
+// EventAbortionUpdate 流产更新
+func (e *EventMating) EventAbortionUpdate(abortionAt int64) {
+	e.MatingResult = pasturePb.MatingResult_Abort
+	e.MatingResultAt = abortionAt
+}
+
+func EventMatingUpdateMap(matingAt int64, bullNumber string, operationUser, currentUser *SystemUser) map[string]interface{} {
+	return map[string]interface{}{
+		"mating_result":       pasturePb.MatingResult_Unknown,
+		"status":              pasturePb.IsShow_Ok,
+		"reality_day":         matingAt,
+		"frozen_semen_number": bullNumber,
+		"operation_id":        operationUser.Id,
+		"operation_name":      operationUser.Name,
+		"message_id":          currentUser.Id,
+		"message_name":        currentUser.Name,
+	}
+}
+
 func NewEventMating(cow *Cow, planDay int64, exposeEstrusType pasturePb.ExposeEstrusType_Kind) *EventMating {
 	return &EventMating{
 		CowId:            cow.Id,

+ 18 - 0
model/event_pregnant_check.go

@@ -37,6 +37,24 @@ func (e *EventPregnantCheck) TableName() string {
 	return "event_pregnant_check"
 }
 
+func (e *EventPregnantCheck) EventUpdate(
+	pregnantCheckAt int64,
+	pregnantCheckResult pasturePb.PregnantCheckResult_Kind,
+	pregnantCheckMethod pasturePb.PregnantCheckMethod_Kind,
+	operationUser, currentUser *SystemUser,
+	remarks string,
+) {
+	e.RealityDay = pregnantCheckAt
+	e.PregnantCheckResult = pregnantCheckResult
+	e.PregnantCheckMethod = pregnantCheckMethod
+	e.OperationId = operationUser.Id
+	e.OperationName = operationUser.Name
+	e.MessageId = currentUser.Id
+	e.MessageName = currentUser.Name
+	e.Remarks = remarks
+	e.Status = pasturePb.IsShow_Ok
+}
+
 func NewEventPregnantCheck(cow *Cow, penMap map[int32]*Pen, pregnantCheckName string) *EventPregnantCheck {
 	penName := ""
 	if pen, ok := penMap[cow.PenId]; ok {

+ 5 - 0
model/event_transfer_group.go

@@ -24,6 +24,11 @@ func (e *EventTransferGroup) TableName() string {
 	return "event_transfer_group"
 }
 
+type EventTransferGroupModel struct {
+	Cow                *Cow
+	EventTransferGroup *EventTransferGroup
+}
+
 func NewEventTransferGroup(cow *Cow, req *pasturePb.TransferGroupEventData, currentUser *SystemUser, operationUser *SystemUser) *EventTransferGroup {
 	return &EventTransferGroup{
 		CowId:            int64(req.CowId),

+ 14 - 1
model/event_weaning.go

@@ -19,14 +19,27 @@ type EventWeaning struct {
 	Remarks       string                `json:"remarks"`
 	OperationId   int32                 `json:"operationId"`
 	OperationName string                `json:"operationName"`
+	MessageId     int32                 `json:"messageId"`
+	MessageName   string                `json:"messageName"`
 	CreatedAt     int64                 `json:"createdAt"`
 	UpdatedAt     int64                 `json:"updatedAt"`
 }
 
-func (c *EventWeaning) TableName() string {
+func (e *EventWeaning) TableName() string {
 	return "event_weaning"
 }
 
+func (e *EventWeaning) EventUpdate(weaningAt int64, remarks string, afterPenId int32, operationUser, currentUser *SystemUser) {
+	e.Status = pasturePb.IsShow_Ok
+	e.RealityDay = weaningAt
+	e.OperationId = int32(operationUser.Id)
+	e.OperationName = operationUser.Name
+	e.MessageId = int32(currentUser.Id)
+	e.MessageName = currentUser.Name
+	e.Remarks = remarks
+	e.AfterPenId = afterPenId
+}
+
 func NewEventWeaning(cowId int64, penId int32) *EventWeaning {
 	return &EventWeaning{
 		CowId:       cowId,

+ 52 - 14
model/system_basic.go

@@ -5,8 +5,8 @@ import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 const (
 	ProactivelyStopBreedingForBackup = "proactively_stop_breeding_for_backup" // 后备牛主动停配
 	ProactivelyStopBreedingForAdult  = "proactively_stop_breeding_for_adult"  // 成母牛主动停配
-	PregnantCheckForFirst            = "pregnant_check_for_first"             // 怀孕检查-第一次
-	PregnantCheckForSecond           = "pregnant_check_for_second"            // 怀孕检查-第二次
+	PregnantCheckForFirst            = "pregnant_check_for_first"             // 初检
+	PregnantCheckForSecond           = "pregnant_check_for_second"            // 复检
 	PregnancyAge                     = "pregnancy_age"                        // 怀孕天数
 	WeaningAge                       = "weaning_age"                          // 断奶天数
 
@@ -28,20 +28,58 @@ var PregnantCheckNameValueMap = map[int32]string{
 }
 
 type SystemBasic struct {
-	Id           int32                 `json:"id"`
-	Name         string                `json:"name"`
-	CategoryName string                `json:"categoryName"`
-	CategoryId   int32                 `json:"categoryId"`
-	MinValue     int32                 `json:"minValue"`
-	MaxValue     int32                 `json:"maxValue"`
-	WeekValue    pasturePb.Week_Kind   `json:"weekValue"`
-	ValueType    int8                  `json:"valueType"`
-	Remarks      string                `json:"remarks"`
-	IsShow       pasturePb.IsShow_Kind `json:"isShow"`
-	CreatedAt    int64                 `json:"createdAt"`
-	UpdatedAt    int64                 `json:"updatedAt"`
+	Id            int32                    `json:"id"`
+	Name          string                   `json:"name"`
+	CategoryName  string                   `json:"categoryName"`
+	CategoryId    int32                    `json:"categoryId"`
+	MinValue      int32                    `json:"minValue"`
+	MaxValue      int32                    `json:"maxValue"`
+	WeekValue     pasturePb.Week_Kind      `json:"weekValue"`
+	ValueType     pasturePb.ValueType_Kind `json:"valueType"`
+	Remarks       string                   `json:"remarks"`
+	IsShow        pasturePb.IsShow_Kind    `json:"isShow"`
+	OperationId   int32                    `json:"operationId"`
+	OperationName string                   `json:"operationName"`
+	CreatedAt     int64                    `json:"createdAt"`
+	UpdatedAt     int64                    `json:"updatedAt"`
 }
 
 func (s *SystemBasic) TableName() string {
 	return "system_basic"
 }
+
+func (s *SystemBasic) EditUpdate(minValue, maxValue int32, weekValue pasturePb.Week_Kind, currentUser *SystemUser) {
+	s.MinValue = minValue
+	if s.ValueType == pasturePb.ValueType_Range {
+		s.MaxValue = maxValue
+	}
+
+	if s.WeekValue > -1 {
+		s.WeekValue = weekValue
+	}
+
+	s.OperationId = int32(currentUser.Id)
+	s.OperationName = currentUser.Name
+}
+
+type SystemBasicSlice []*SystemBasic
+
+func (s SystemBasicSlice) ToPb() []*pasturePb.BaseDataConfig {
+	res := make([]*pasturePb.BaseDataConfig, len(s))
+	for i, v := range s {
+		res[i] = &pasturePb.BaseDataConfig{
+			Id:           v.Id,
+			Name:         v.Name,
+			CategoryName: v.CategoryName,
+			CategoryId:   pasturePb.BasicDataCategory_Kind(v.CategoryId),
+			MinValue:     v.MinValue,
+			MaxValue:     v.MaxValue,
+			WeekValue:    v.WeekValue,
+			ValueType:    v.ValueType,
+			Remarks:      v.Remarks,
+			CreatedAt:    int32(v.CreatedAt),
+			UpdatedAt:    int32(v.UpdatedAt),
+		}
+	}
+	return res
+}

+ 153 - 0
module/backend/config_data_base.go

@@ -0,0 +1,153 @@
+package backend
+
+import (
+	"kpt-pasture/model"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+func (s *StoreEntry) DepartureTypeEnumList(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.DepartureType_Death),
+		Label:    "死亡",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DepartureType_Out),
+		Label:    "淘汰",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) OutReasonEnumList(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.OutReason_Long_Term_infertility),
+		Label:    "久配不孕",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Multiple_Miscarriages),
+		Label:    "多次流产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Long_Treatment_Without_Recovery),
+		Label:    "久治不愈",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Postpartum_Paralysis),
+		Label:    "产后瘫痪",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Mastitis),
+		Label:    "乳房炎",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Hoof_Disease),
+		Label:    "蹄病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Congenital_Malformation),
+		Label:    "先天畸形",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Dysplasia),
+		Label:    "发育不良",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Hernia),
+		Label:    "疝气",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Excessive_Age),
+		Label:    "月龄过大",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Excessive_Weight),
+		Label:    "体重过肥",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Other_Disease),
+		Label:    "其他疾病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Weak_Child),
+		Label:    "弱仔",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Obsessive_Bull),
+		Label:    "恶癖牛",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Splitting),
+		Label:    "滑倒卧地不起",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.OutReason_Other),
+		Label:    "其他",
+		Disabled: true,
+	})
+	return configOptions
+}
+
+func (s *StoreEntry) DeadReasonEnumList(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.DeadReason_Digestive_System_Diseases),
+		Label:    "消化性疾病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DeadReason_Respiratory_System_Diseases),
+		Label:    "呼吸性疾病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DeadReason_Reproductive_System_Diseases),
+		Label:    "繁殖性疾病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DeadReason_Metabolic_System_Diseases),
+		Label:    "代谢性疾病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DeadReason_Infectious_Diseases),
+		Label:    "传染性疾病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DeadReason_Difficult_Birth),
+		Label:    "难产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DeadReason_Accident_Dead),
+		Label:    "意外死亡",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.DeadReason_Other),
+		Label:    "其他",
+		Disabled: true,
+	})
+	return configOptions
+}

+ 24 - 0
module/backend/config_data_other.go

@@ -500,6 +500,30 @@ func (s *StoreEntry) EventTypeEnumList(isAll string) []*pasturePb.ConfigOptionsL
 		Value:    int32(pasturePb.EventType_Immunication),
 		Label:    "免疫",
 		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Weaning),
+		Label:    "断奶",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Sale),
+		Label:    "出售",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Abort),
+		Label:    "流产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Weight),
+		Label:    "称重",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Castrated),
+		Label:    "去势",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.EventType_Insect_Repellent),
+		Label:    "驱虫",
+		Disabled: true,
 	})
 	return configOptions
 }

+ 16 - 0
module/backend/enum_map.go

@@ -254,3 +254,19 @@ func (s *StoreEntry) DystociaReasonMap() map[pasturePb.DystociaReason_Kind]strin
 	}
 	return res
 }
+
+func (s *StoreEntry) DeadReasonMap() map[pasturePb.DeadReason_Kind]string {
+	res := make(map[pasturePb.DeadReason_Kind]string)
+	for _, v := range s.DeadReasonEnumList("") {
+		res[pasturePb.DeadReason_Kind(v.Value)] = v.Label
+	}
+	return res
+}
+
+func (s *StoreEntry) OutReasonMap() map[pasturePb.OutReason_Kind]string {
+	res := make(map[pasturePb.OutReason_Kind]string)
+	for _, v := range s.OutReasonEnumList("") {
+		res[pasturePb.OutReason_Kind(v.Value)] = v.Label
+	}
+	return res
+}

+ 3 - 0
module/backend/enum_options.go

@@ -195,6 +195,9 @@ func (s *StoreEntry) SystemBaseConfigOptions(ctx context.Context, optionsName, i
 		"pregnantCheckName":          s.PregnantCheckNameEnumList,
 		"unMatingReasons":            s.UnMatingReasonsEnumList,
 		"evenType":                   s.EventTypeEnumList,
+		"departureType":              s.DepartureTypeEnumList,
+		"outReason":                  s.OutReasonEnumList,
+		"deadReason":                 s.DeadReasonEnumList,
 	}
 
 	getConfigFunc, ok := getConfigFuncMap[optionsName]

+ 101 - 35
module/backend/event_base.go

@@ -8,6 +8,9 @@ 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"
@@ -130,13 +133,13 @@ func (s *StoreEntry) GroupTransferList(ctx context.Context, req *pasturePb.Searc
 	}, nil
 }
 
-func (s *StoreEntry) CreateGroupTransfer(ctx context.Context, req *pasturePb.TransferGroupEventRequest) error {
+func (s *StoreEntry) CreateGroupTransfer(ctx context.Context, req *pasturePb.TransferGroupEventRequest) (err error) {
 	currentUser, err := s.GetCurrentSystemUser(ctx)
 	if err != nil || currentUser.Id <= 0 {
 		return xerr.Customf("当前用户信息错误")
 	}
 
-	newEventTransferGroupList := make([]*model.EventTransferGroup, 0)
+	newEventTransferGroupModelList := make([]*model.EventTransferGroupModel, 0)
 	for _, v := range req.Body {
 		cow, err := s.GetCowInfoByCowId(ctx, int64(v.CowId))
 		if err != nil {
@@ -151,22 +154,30 @@ func (s *StoreEntry) CreateGroupTransfer(ctx context.Context, req *pasturePb.Tra
 			return xerr.WithStack(err)
 		}
 		newEventTransferGroup := model.NewEventTransferGroup(cow, v, currentUser, operationUser)
-		newEventTransferGroupList = append(newEventTransferGroupList, newEventTransferGroup)
+		newEventTransferGroupModelList = append(newEventTransferGroupModelList, &model.EventTransferGroupModel{
+			Cow:                cow,
+			EventTransferGroup: newEventTransferGroup,
+		})
 	}
-	if len(newEventTransferGroupList) <= 0 {
+	if len(newEventTransferGroupModelList) <= 0 {
 		return nil
 	}
 
-	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-		if err = tx.Create(newEventTransferGroupList).Error; err != nil {
-			return xerr.WithStack(err)
+	defer func() {
+		if err != nil {
+			for _, etg := range newEventTransferGroupModelList {
+				cowLogs := s.SubmitEventLog(ctx, etg.Cow, pasturePb.EventType_Transfer_Ben, pasturePb.ExposeEstrusType_Invalid, etg.EventTransferGroup)
+				s.DB.Table(cowLogs.TableName()).Create(cowLogs)
+			}
 		}
-		for _, v := range newEventTransferGroupList {
-			cow, err := s.GetCowInfoByCowId(ctx, v.CowId)
-			if err != nil {
+	}()
+
+	if err = s.DB.Transaction(func(tx *gorm.DB) error {
+		for _, v := range newEventTransferGroupModelList {
+			if err = tx.Create(v.EventTransferGroup).Error; err != nil {
 				return xerr.WithStack(err)
 			}
-			if err = s.DB.Model(cow).Update("pen_id", v.PenInId).Error; err != nil {
+			if err = tx.Model(v.Cow).Update("pen_id", v.EventTransferGroup.PenInId).Error; err != nil {
 				return xerr.WithStack(err)
 			}
 		}
@@ -264,13 +275,14 @@ func (s *StoreEntry) WeightList(ctx context.Context, req *pasturePb.SearchEventR
 	}, nil
 }
 
-func (s *StoreEntry) WeightBatch(ctx context.Context, req *pasturePb.EventWeight) error {
+func (s *StoreEntry) WeightBatch(ctx context.Context, req *pasturePb.EventWeight) (err error) {
 	if len(req.WeightItems) <= 0 {
 		return xerr.Custom("请选择相关牛只")
 	}
+
 	currentUser, err := s.GetCurrentSystemUser(ctx)
 	if err != nil {
-		return xerr.Customf("获取当前登录用户失败: %s", err.Error())
+		return xerr.Custom("当前登录用户失败,请退出重新登录")
 	}
 
 	operationUser, err := s.GetSystemUserById(ctx, int64(req.OperationId))
@@ -278,40 +290,94 @@ func (s *StoreEntry) WeightBatch(ctx context.Context, req *pasturePb.EventWeight
 		return xerr.WithStack(err)
 	}
 	req.OperationName = operationUser.Name
-	weightEvent := make([]*model.EventWeight, 0)
+
+	defer func() {
+		if err == nil {
+			// 记录事件日志
+			for _, item := range req.WeightItems {
+				cow, _ := s.GetCowInfoByCowId(ctx, int64(item.CowId))
+				cowLogs := s.SubmitEventLog(ctx, cow, pasturePb.EventType_Weight, pasturePb.ExposeEstrusType_Invalid, req)
+				s.DB.Table(cowLogs.TableName()).Create(cowLogs)
+			}
+		}
+	}()
+	cow := &model.Cow{}
 	for _, item := range req.WeightItems {
-		cow, err := s.GetCowInfoByCowId(ctx, int64(item.CowId))
+		cow, err = s.GetCowInfoByCowId(ctx, int64(item.CowId))
 		if err != nil {
 			return xerr.WithStack(err)
 		}
-		var weight = int32(item.Weight * 100)
-		weightEvent = append(weightEvent, model.NewEventWeight(cow, currentUser, weight, item.Height, req))
+		item.WeightAt = req.WeightAt
+
+		// 更新牛只信息
+		cow.EventWeightUpdate(int64(item.Weight), int64(req.WeightAt))
+		if err = s.DB.Model(new(model.Cow)).
+			Select("last_second_weight_at,last_second_weight,last_weight_at,current_weight").
+			Where("id = ?", cow.Id).
+			Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
+			Updates(cow).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+		// 创建牛只的体重记录
+		eventWeight := model.NewEventWeight(cow, currentUser, int32(item.Weight*1000), item.Height, req)
+		if err = s.DB.Create(eventWeight).Error; err != nil {
+			return xerr.WithStack(err)
+		}
 	}
+	return err
+}
 
-	if len(weightEvent) <= 0 {
-		return nil
+func (s *StoreEntry) DepartureBatch(ctx context.Context, req *pasturePb.EventDepartureBatch) (err error) {
+	if len(req.Item) <= 0 {
+		return xerr.Custom("请选择相关牛只")
 	}
 
-	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-		for _, item := range weightEvent {
-			if err = tx.Model(new(model.Cow)).
-				Where("id = ?", item.CowId).
-				Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
-				Updates(map[string]interface{}{
-					"last_second_weight_at": gorm.Expr("last_weight_at"),
-					"last_second_weight":    gorm.Expr("current_weight"),
-					"last_weight_at":        item.WeightAt,
-					"current_weight":        item.Weight,
-				}).Error; err != nil {
-				return xerr.WithStack(err)
-			}
+	currentUser, err := s.GetCurrentSystemUser(ctx)
+	if err != nil {
+		return xerr.Custom("当前登录用户失败,请退出重新登录")
+	}
+
+	newEventDepartureList := make([]*model.EventDeparture, 0)
+	cow := &model.Cow{}
+	for _, item := range req.Item {
+		cow, err = s.GetCowInfoByCowId(ctx, int64(item.CowId))
+		if err != nil {
+			zaplog.Error("DepartureBatch", zap.Any("item", item), zap.Any("err", err))
+			return xerr.Customf("获取牛只信息失败: %d", item.CowId)
 		}
-		if err = tx.Create(weightEvent).Error; err != nil {
-			return xerr.WithStack(err)
+
+		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.DepartureReason)]
+		case pasturePb.DepartureType_Out:
+			reasonName = s.OutReasonMap()[pasturePb.OutReason_Kind(item.DepartureReason)]
 		}
+		newEventDepartureList = append(newEventDepartureList, model.NewEventDeparture(cow, item, reasonName, currentUser, operationUser))
+	}
+
+	if len(newEventDepartureList) <= 0 {
 		return nil
-	}); err != nil {
+	}
+
+	if err = s.DB.Create(newEventDepartureList).Error; err != nil {
 		return xerr.WithStack(err)
 	}
+
+	// 记录事件日志
+	for _, item := range newEventDepartureList {
+		eventType := pasturePb.EventType_Death
+		if item.DepartureType == pasturePb.DepartureType_Out {
+			eventType = pasturePb.EventType_Out
+		}
+		cowLogs := s.SubmitEventLog(ctx, cow, eventType, pasturePb.ExposeEstrusType_Invalid, item)
+		s.DB.Table(cowLogs.TableName()).Create(cowLogs)
+	}
 	return nil
 }

+ 168 - 116
module/backend/event_breed.go

@@ -77,9 +77,17 @@ func (s *StoreEntry) CalvingCreate(ctx context.Context, req *pasturePb.EventCalv
 	defer func() {
 		if err == nil {
 			// 母牛事件日志
-			cowLogs := s.SubmitEventLog(ctx, cow, pasturePb.EventType_Calving, req)
+			cowLogs := s.SubmitEventLog(ctx, cow, pasturePb.EventType_Calving, pasturePb.ExposeEstrusType_Invalid, req)
 			s.DB.Table(cowLogs.TableName()).Create(cowLogs)
-			// todo 犊牛的
+			// 犊牛事件日志
+			for _, v := range req.CalfItemList {
+				if v.IsLive == pasturePb.IsShow_No || v.IsAdoption == pasturePb.IsShow_No {
+					continue
+				}
+				cow, _ = s.GetCowInfoByCowId(ctx, int64(v.CowId))
+				cowLogs = s.SubmitEventLog(ctx, cow, pasturePb.EventType_Birth, pasturePb.ExposeEstrusType_Invalid, v)
+				s.DB.Table(cowLogs.TableName()).Create(cowLogs)
+			}
 		}
 	}()
 
@@ -118,16 +126,11 @@ func (s *StoreEntry) CalvingCreate(ctx context.Context, req *pasturePb.EventCalv
 		}
 
 		// 更新母牛信息
-		if err = tx.Model(new(model.Cow)).Where("id = ?", cow.Id).
-			Updates(map[string]interface{}{
-				"calving_age":     int32(time.Now().Sub(time.Unix(int64(req.CalvingAt), 0)).Hours() / 24),
-				"mating_times":    0,
-				"pregnancy_age":   0,
-				"lact":            cow.Lact + 1,
-				"breed_status":    pasturePb.BreedStatus_Calving,
-				"is_pregnant":     pasturePb.IsShow_No,
-				"last_calving_at": int64(req.CalvingAt),
-			}).Error; err != nil {
+		cow.EventCalvingUpdate(int64(req.CalvingAt))
+		if err = tx.Model(cow).
+			Select("calving_age,mating_times,pregnancy_age,lact,breed_status,is_pregnant,last_calving_at").
+			Where("id = ?", cow.Id).
+			Updates(cow).Error; err != nil {
 			return xerr.WithStack(err)
 		}
 		return nil
@@ -177,8 +180,7 @@ func (s *StoreEntry) EstrusList(ctx context.Context, req *pasturePb.EstrusItemsR
 	}, nil
 }
 
-func (s *StoreEntry) EstrusBatch(ctx context.Context, req *pasturePb.EventEstrus) error {
-	eventMatingList := make([]*model.EventMating, 0)
+func (s *StoreEntry) EstrusBatch(ctx context.Context, req *pasturePb.EventEstrus) (err error) {
 	currentUser, err := s.GetCurrentSystemUser(ctx)
 	if err != nil {
 		return xerr.Custom("当前用户信息错误")
@@ -187,8 +189,10 @@ func (s *StoreEntry) EstrusBatch(ctx context.Context, req *pasturePb.EventEstrus
 	if err != nil {
 		return xerr.Customf("该用户不存在: %d", req.OperationId)
 	}
+	req.OperationName = operationUser.Name
 
 	eventEstrusIds := make([]string, 0)
+	eventMatingList := make([]*model.EventMating, 0)
 	for _, cowId := range req.CowIds {
 		cowInfo := GetCowInfoByCowId(s.DB, int64(cowId))
 		if cowInfo == nil {
@@ -212,10 +216,19 @@ func (s *StoreEntry) EstrusBatch(ctx context.Context, req *pasturePb.EventEstrus
 		}
 		eventMatingList = append(eventMatingList, newEventMating)
 	}
-
 	if len(eventMatingList) <= 0 {
 		return nil
 	}
+	defer func() {
+		// 记录牛只事件日志
+		if err == nil {
+			for _, v := range eventMatingList {
+				cow, _ := s.GetCowInfoByCowId(ctx, v.CowId)
+				cowLogs := s.SubmitEventLog(ctx, cow, pasturePb.EventType_Mating, pasturePb.ExposeEstrusType_Neck_Ring, req)
+				s.DB.Table(cowLogs.TableName()).Create(cowLogs)
+			}
+		}
+	}()
 
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		if len(eventEstrusIds) > 0 {
@@ -241,90 +254,111 @@ func (s *StoreEntry) EstrusBatch(ctx context.Context, req *pasturePb.EventEstrus
 	return nil
 }
 
-func (s *StoreEntry) SameTimeCreate(ctx context.Context, req *pasturePb.EventSameTime) error {
-	eventCowSameTime, err := s.GetEventCowSameTimeById(ctx, int64(req.Id))
+func (s *StoreEntry) SameTimeCreate(ctx context.Context, req *pasturePb.EventSameTime) (err error) {
+	eventCowSameTime, err := s.GetEventCowSameTimeByCowId(ctx, int64(req.CowId))
 	if err != nil {
-		return xerr.WithStack(err)
-	}
-
-	if eventCowSameTime.Status == pasturePb.IsShow_Ok {
-		return xerr.Custom("该事件已处理")
-	}
-
-	if eventCowSameTime.CowId != int64(req.CowId) {
-		return xerr.Custom("牛只Id 不匹配")
+		zaplog.Error("SameTimeCreate", zap.Any("err", err), zap.Any("req", req))
+		return xerr.Customf("异常数据")
 	}
 
 	drugs := &model.Drugs{}
-	if req.DrugsId > 0 {
-		if drugs, err = s.GetDrugsById(ctx, int64(req.DrugsId)); err != nil {
-			return xerr.WithStack(err)
-		}
+	if drugs, err = s.GetDrugsById(ctx, int64(req.DrugsId)); err != nil {
+		zaplog.Error("SameTimeCreate", zap.Any("err", err), zap.Any("req", req))
+		return xerr.Customf("该药品不存在: %d", req.DrugsId)
 	}
+	req.DrugsName = drugs.Name
+
 	operationUser, err := s.GetSystemUserById(ctx, int64(req.OperationId))
 	if err != nil {
 		return xerr.WithStack(err)
 	}
 
-	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-		if err = tx.Model(new(model.CowSameTime)).
-			Where("cow_id = ?", eventCowSameTime.CowId).
-			Where("same_time_id = ?", eventCowSameTime.Id).
-			Where("same_time_status = ?", pasturePb.SameTimeStatus_No_Start).
-			Update("same_time_status", pasturePb.SameTimeStatus_In_Progress).Error; err != nil {
-			zaplog.Error("SameTimeCreate", zap.Any("err", err), zap.Any("req", req))
-		}
+	currentUser, err := s.GetCurrentSystemUser(ctx)
+	if err != nil {
+		return xerr.Custom("当前用户信息错误")
+	}
 
-		if err = tx.Model(new(model.EventCowSameTime)).
-			Where("id = ?", eventCowSameTime.Id).
-			Where("cow_id = ?", eventCowSameTime.CowId).
-			Where("status = ?", pasturePb.IsShow_No).
-			Updates(map[string]interface{}{
-				"status":         pasturePb.IsShow_Ok,
-				"drug_id":        drugs.Id,
-				"unit":           drugs.Unit,
-				"usage":          req.Usage,
-				"remarks":        req.Remarks,
-				"operation_id":   operationUser.Id,
-				"operation_name": operationUser.Name,
-			}).Error; err != nil {
-			return xerr.WithStack(err)
+	eventCowSameTime.Update(drugs, req.Usage, req.Remarks, operationUser, currentUser)
+	defer func() {
+		if err == nil {
+			// 记录牛只事件日志
+			cow, _ := s.GetCowInfoByCowId(ctx, eventCowSameTime.CowId)
+			cowLogs := s.SubmitEventLog(ctx, cow, pasturePb.EventType_Seme_Time, pasturePb.ExposeEstrusType_Same_Time, req)
+			s.DB.Table(cowLogs.TableName()).Create(cowLogs)
+
+			if err = s.DB.Model(new(model.CowSameTime)).
+				Where("cow_id = ?", eventCowSameTime.CowId).
+				Where("same_time_id = ?", eventCowSameTime.Id).
+				Where("same_time_status = ?", pasturePb.SameTimeStatus_No_Start).
+				Update("same_time_status", pasturePb.SameTimeStatus_In_Progress).Error; err != nil {
+				zaplog.Error("SameTimeCreate", zap.Any("err", err), zap.Any("req", req))
+			}
 		}
-		return nil
-	}); err != nil {
+	}()
+
+	if err = s.DB.Model(new(model.EventCowSameTime)).
+		Select("status,drugs_id,unit,usage,remarks,operation_id,operation_name").
+		Where("id = ?", eventCowSameTime.Id).
+		Updates(eventCowSameTime).Error; err != nil {
 		return xerr.WithStack(err)
 	}
 	return nil
 }
 
-func (s *StoreEntry) SameTimeBatch(ctx context.Context, req *pasturePb.EventSameTimeBatch) error {
-	drugs := &model.Drugs{}
-	var err error
-	if req.DrugsId > 0 {
-		if drugs, err = s.GetDrugsById(ctx, int64(req.DrugsId)); err != nil {
-			return xerr.WithStack(err)
-		}
-	}
+func (s *StoreEntry) SameTimeBatch(ctx context.Context, req *pasturePb.EventSameTimeBatch) (err error) {
 	operationUser, err := s.GetSystemUserById(ctx, int64(req.OperationId))
 	if err != nil {
-		return xerr.WithStack(err)
+		return xerr.Customf("异常数据")
+	}
+	req.OperationName = operationUser.Name
+
+	currentUser, err := s.GetCurrentSystemUser(ctx)
+	if err != nil {
+		return xerr.Customf("异常数据")
+	}
+	drugs := &model.Drugs{}
+	if drugs, err = s.GetDrugsById(ctx, int64(req.DrugsId)); err != nil {
+		zaplog.Error("SameTimeBatch", zap.Any("err", err), zap.Any("req", req))
+		return xerr.Customf("该药物不存在: %d", req.DrugsId)
 	}
+	req.DrugsName = drugs.Name
+
 	eventCowSameTimeList := make([]*model.EventCowSameTime, 0)
-	for _, v := range req.Item {
-		eventCowSameTime, err := s.GetEventCowSameTimeById(ctx, int64(v.Id))
+	for _, v := range req.CowIds {
+		eventCowSameTime, err := s.GetEventCowSameTimeByCowId(ctx, int64(v))
 		if err != nil {
+			zaplog.Error("SameTimeCreate", zap.Any("err", err), zap.Any("req", req))
 			return xerr.WithStack(err)
 		}
-
-		if eventCowSameTime.Status == pasturePb.IsShow_Ok {
-			return xerr.Custom("该事件已处理")
-		}
-
-		if eventCowSameTime.CowId != int64(v.CowId) {
-			return xerr.Custom(" 牛只Id 不匹配")
-		}
 		eventCowSameTimeList = append(eventCowSameTimeList, eventCowSameTime)
 	}
+	defer func() {
+		// 记录牛只事件日志
+		if err == nil {
+			for _, v := range eventCowSameTimeList {
+				cow, _ := s.GetCowInfoByCowId(ctx, v.CowId)
+				cowLogs := s.SubmitEventLog(
+					ctx,
+					cow,
+					pasturePb.EventType_Seme_Time,
+					pasturePb.ExposeEstrusType_Same_Time,
+					&pasturePb.EventSameTime{
+						Id:               int32(v.Id),
+						CowId:            int32(v.CowId),
+						SameTimeId:       int32(v.SameTimeId),
+						SameTimeType:     v.SameTimeType,
+						SameTimeTypeName: v.SameTimeName,
+						DrugsId:          int32(v.DrugsId),
+						DrugsName:        drugs.Name,
+						Usage:            req.Usage,
+						OperationId:      int32(operationUser.Id),
+						OperationName:    operationUser.Name,
+						SameTimeAt:       req.SameTimeAt,
+					})
+				s.DB.Table(cowLogs.TableName()).Create(cowLogs)
+			}
+		}
+	}()
 
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		for _, v := range eventCowSameTimeList {
@@ -336,19 +370,12 @@ func (s *StoreEntry) SameTimeBatch(ctx context.Context, req *pasturePb.EventSame
 				zaplog.Error("SameTimeCreate", zap.Any("err", err), zap.Any("req", req))
 			}
 
+			// 更新SameTime
+			v.Update(drugs, req.Usage, req.Remarks, currentUser, operationUser)
 			if err = tx.Model(new(model.EventCowSameTime)).
+				Select("status,drugs_id,unit,usage,remarks,operation_id,operation_name").
 				Where("id = ?", v.Id).
-				Where("cow_id = ?", v.CowId).
-				Where("status = ?", pasturePb.IsShow_No).
-				Updates(map[string]interface{}{
-					"status":         pasturePb.IsShow_Ok,
-					"drugs_id":       drugs.Id,
-					"unit":           drugs.Unit,
-					"usage":          req.Usage,
-					"remarks":        req.Remarks,
-					"operation_id":   operationUser.Id,
-					"operation_name": operationUser.Name,
-				}).Error; err != nil {
+				Updates(v).Error; err != nil {
 				return xerr.WithStack(err)
 			}
 		}
@@ -423,7 +450,8 @@ func (s *StoreEntry) MatingList(ctx context.Context, req *pasturePb.SearchEventR
 	}, nil
 }
 
-func (s *StoreEntry) MatingCreate(ctx context.Context, req *pasturePb.EventMating) error {
+// MatingCreate 牛只配种
+func (s *StoreEntry) MatingCreate(ctx context.Context, req *pasturePb.EventMating) (err error) {
 	eventCheckModel, err := s.MatingCreateCheck(ctx, req)
 	if err != nil {
 		return xerr.WithStack(err)
@@ -507,6 +535,16 @@ func (s *StoreEntry) MatingCreate(ctx context.Context, req *pasturePb.EventMatin
 		)
 		return xerr.Custom("配种信息有误")
 	}
+	defer func() {
+		if err != nil {
+			// 记录事件日志
+			for _, cowId := range cowIds {
+				cow, _ := s.GetCowInfoByCowId(ctx, cowId)
+				cowLogs := s.SubmitEventLog(ctx, cow, pasturePb.EventType_Mating, req.ExposeEstrusType, req)
+				s.DB.Table(cowLogs.TableName()).Create(cowLogs)
+			}
+		}
+	}()
 
 	itemFrozenSemenLog := model.NewEventFrozenSemenLog(req)
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
@@ -515,16 +553,9 @@ func (s *StoreEntry) MatingCreate(ctx context.Context, req *pasturePb.EventMatin
 			if err = tx.Model(new(model.EventMating)).
 				Where("id IN ?", updateMatingList).
 				Where("status = ?", pasturePb.IsShow_No).
-				Updates(map[string]interface{}{
-					"mating_result":       pasturePb.MatingResult_Unknown,
-					"status":              pasturePb.IsShow_Ok,
-					"reality_day":         int64(req.MatingAt),
-					"frozen_semen_number": req.FrozenSemenNumber,
-					"operation_id":        eventCheckModel.OperationUser.Id,
-					"operation_name":      eventCheckModel.OperationUser.Name,
-					"message_id":          eventCheckModel.CurrentUser.Id,
-					"message_name":        eventCheckModel.CurrentUser.Name,
-				}).Error; err != nil {
+				Updates(
+					model.EventMatingUpdateMap(int64(req.MatingAt), req.FrozenSemenNumber, eventCheckModel.OperationUser, eventCheckModel.CurrentUser),
+				).Error; err != nil {
 				return xerr.WithStack(err)
 			}
 		}
@@ -610,7 +641,6 @@ func (s *StoreEntry) MatingCreate(ctx context.Context, req *pasturePb.EventMatin
 				}
 			}
 		}
-
 		return nil
 	}); err != nil {
 		return xerr.WithStack(err)
@@ -619,7 +649,7 @@ func (s *StoreEntry) MatingCreate(ctx context.Context, req *pasturePb.EventMatin
 	return nil
 }
 
-func (s *StoreEntry) WeaningBatch(ctx context.Context, req *pasturePb.EventWeaningBatchRequest) error {
+func (s *StoreEntry) WeaningBatch(ctx context.Context, req *pasturePb.EventWeaningBatchRequest) (err error) {
 	if len(req.Item) <= 0 {
 		return nil
 	}
@@ -631,8 +661,7 @@ func (s *StoreEntry) WeaningBatch(ctx context.Context, req *pasturePb.EventWeani
 	}
 
 	eventWeaningList := make([]*model.EventWeaning, 0)
-
-	if err := s.DB.Model(new(model.EventWeaning)).
+	if err = s.DB.Model(new(model.EventWeaning)).
 		Where("cow_id IN ?", cowIds).
 		Where("status = ?", pasturePb.IsShow_No).
 		Find(&eventWeaningList).Error; err != nil {
@@ -649,27 +678,50 @@ func (s *StoreEntry) WeaningBatch(ctx context.Context, req *pasturePb.EventWeani
 		return xerr.WithStack(err)
 	}
 
+	defer func() {
+		if err != nil {
+			for _, cowId := range cowIds {
+				cow, _ := s.GetCowInfoByCowId(ctx, cowId)
+				cowLogs := s.SubmitEventLog(ctx, 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 _, v := range eventWeaningList {
-			if err = tx.Model(new(model.EventWeaning)).Where("id = ?", v.Id).Updates(map[string]interface{}{
-				"status":         pasturePb.IsShow_Ok,
-				"reality_day":    int64(req.WeaningAt),
-				"operation_id":   req.OperationId,
-				"operation_name": operation.Name,
-				"message_id":     currentUser.Id,
-				"message_name":   currentUser.Name,
-				"remarks":        req.Remarks,
-				"after_pen_id":   req.PenId,
-			}).Error; err != nil {
+			v.EventUpdate(int64(req.WeaningAt), req.Remarks, req.PenId, operation, currentUser)
+			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 = ?", v.Id).
+				Updates(v).Error; err != nil {
 				return xerr.WithStack(err)
 			}
-
-			if err = tx.Model(new(model.Cow)).Where("id = ?", v.CowId).Updates(map[string]interface{}{
-				"pen_id":         req.PenId,
-				"current_weight": cowWeightMap[v.CowId],
-				"weaning_at":     req.WeaningAt,
-				"last_weight_at": req.WeaningAt,
-			}).Error; err != nil {
+			cowInfo, err = s.GetCowInfoByCowId(ctx, v.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 = ?", v.CowId).
+				Updates(cowInfo).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+			// 创建牛只的体重记录
+			newEventWeight := model.NewEventWeight(
+				cowInfo,
+				currentUser,
+				int32(cowWeightMap[v.CowId]*1000),
+				0,
+				&pasturePb.EventWeight{
+					WeightAt:      req.WeaningAt,
+					OperationId:   req.OperationId,
+					OperationName: req.OperationName,
+					Remarks:       req.Remarks,
+				})
+			if err = tx.Create(newEventWeight).Error; err != nil {
 				return xerr.WithStack(err)
 			}
 		}

+ 36 - 101
module/backend/event_breed_more.go

@@ -43,7 +43,7 @@ func (s *StoreEntry) PregnantCheckList(ctx context.Context, req *pasturePb.Searc
 	}, nil
 }
 
-func (s *StoreEntry) PregnantCheckCreateBatch(ctx context.Context, req *pasturePb.EventPregnantCheckBatch) error {
+func (s *StoreEntry) PregnantCheckCreateBatch(ctx context.Context, req *pasturePb.EventPregnantCheckBatch) (err error) {
 	pregnantCheckBatchModelList, err := s.PregnantCheckDataCheck(ctx, req)
 	if err != nil {
 		return xerr.WithStack(err)
@@ -53,43 +53,26 @@ func (s *StoreEntry) PregnantCheckCreateBatch(ctx context.Context, req *pastureP
 		return xerr.Customf("获取当前用户失败: %s", err.Error())
 	}
 
-	penMap := s.PenMap(ctx)
-	// 新增孕检牛只
-	newEventPregnantCheckList := make([]*model.EventPregnantCheck, 0)
+	cowIds := make([]int64, 0)
 	// 更新孕检牛只
 	newPregnantCheckBatchModelList := make([]*PregnantCheckBatchModel, 0)
 	for _, item := range pregnantCheckBatchModelList {
-		itemEventPregnantCheck, err := s.GetEventPregnantCheckIsExIstByCowId(ctx, item.Cow)
-		if err != nil {
-			return xerr.WithStack(err)
-		}
-
-		// 孕检清单里面没有的,需要新增孕检事件
-		eventCheckModel := model.NewEventPregnantCheck2(&model.EventPregnantCheck2{
-			Cow:                 item.Cow,
-			OperationUser:       item.OperationUser,
-			CurrentUser:         currentUser,
-			PregnantCheckAt:     int64(item.PregnantCheckAt),
-			PregnantCheckMethod: item.PregnantCheckMethod,
-			PregnantCheckResult: item.PregnantCheckResult,
-			Remarks:             item.Remarks,
-		}, penMap)
-		if itemEventPregnantCheck.Id <= 0 {
-			newEventPregnantCheckList = append(newEventPregnantCheckList, eventCheckModel)
-		} else {
-			item.EventPregnancyCheck = itemEventPregnantCheck
-			newPregnantCheckBatchModelList = append(newPregnantCheckBatchModelList, item)
-		}
+		newPregnantCheckBatchModelList = append(newPregnantCheckBatchModelList, item)
+		cowIds = append(cowIds, item.Cow.Id)
 	}
 
-	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-		// 新增孕检事件
-		if len(newEventPregnantCheckList) > 0 {
-			if err = tx.Create(newEventPregnantCheckList).Error; err != nil {
-				return xerr.WithStack(err)
+	defer func() {
+		if err == nil {
+			// 提交事件日志
+			for _, cowId := range cowIds {
+				cow, _ := s.GetCowInfoByCowId(ctx, cowId)
+				cowLogs := s.SubmitEventLog(ctx, cow, pasturePb.EventType_Pregnancy_Check, pasturePb.ExposeEstrusType_Invalid, req)
+				s.DB.Table(cowLogs.TableName()).Create(cowLogs)
 			}
 		}
+	}()
 
+	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		for _, item := range newPregnantCheckBatchModelList {
 			breedStatus := pasturePb.BreedStatus_Pregnant
 			isPregnant := pasturePb.IsShow_Ok
@@ -103,14 +86,12 @@ func (s *StoreEntry) PregnantCheckCreateBatch(ctx context.Context, req *pastureP
 				breedStatus = pasturePb.BreedStatus_Abort
 			}
 
+			item.Cow.EventPregnantCheckUpdate(breedStatus, int64(item.PregnantCheckAt), isPregnant)
 			// 更新牛只基本信息
 			if err = tx.Model(&model.Cow{}).
+				Select("breed_status,last_pregnant_check_at,is_pregnant").
 				Where("cow_id = ?", item.Cow.Id).
-				Updates(map[string]interface{}{
-					"breed_status":           breedStatus,
-					"last_pregnant_check_at": item.PregnantCheckAt,
-					"is_pregnant":            isPregnant,
-				}).Error; err != nil {
+				Updates(item.Cow).Error; err != nil {
 				return xerr.WithStack(err)
 			}
 
@@ -125,20 +106,13 @@ func (s *StoreEntry) PregnantCheckCreateBatch(ctx context.Context, req *pastureP
 				return xerr.WithStack(err)
 			}
 
+			// 更新事件表
+			item.EventPregnancyCheck.EventUpdate(int64(item.PregnantCheckAt), item.PregnantCheckResult, item.PregnantCheckMethod, item.OperationUser, currentUser, item.Remarks)
 			// 更新孕检事件表
 			if err = tx.Model(new(model.EventPregnantCheck)).
+				Select("reality_day,pregnant_check_result,pregnant_check_method,operation_id,operation_name,message_id,message_name,remarks,status").
 				Where("id = ?", item.EventPregnancyCheck.Id).
-				Updates(map[string]interface{}{
-					"reality_day":           item.PregnantCheckAt,
-					"pregnant_check_result": item.PregnantCheckResult,
-					"pregnant_check_method": item.PregnantCheckMethod,
-					"operation_id":          item.OperationUser.Id,
-					"operation_name":        item.OperationUser.Name,
-					"message_id":            currentUser.Id,
-					"message_name":          currentUser.Name,
-					"remarks":               item.Remarks,
-					"status":                pasturePb.IsShow_Ok,
-				}).Error; err != nil {
+				Updates(item.EventPregnancyCheck).Error; err != nil {
 				return xerr.WithStack(err)
 			}
 		}
@@ -171,29 +145,35 @@ func (s *StoreEntry) AbortionCreate(ctx context.Context, req *pasturePb.EventAbo
 		Order("id desc").First(lastCowMating).Error; err != nil {
 		return xerr.WithStack(err)
 	}
+	// 更新最近一次配种结果为流产
+	lastCowMating.EventAbortionUpdate(int64(req.AbortionAt))
+	// 更新流产数据
+	cow.EventAbortionUpdate(int64(req.AbortionAt))
 
+	defer func() {
+		if err != nil {
+			cowLogs := s.SubmitEventLog(ctx, cow, pasturePb.EventType_Abort, pasturePb.ExposeEstrusType_Invalid, req)
+			s.DB.Table(cowLogs.TableName()).Create(cowLogs)
+		}
+	}()
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		// 创建牛只流产事件数据
 		if err = tx.Create(newEventAbortion).Error; err != nil {
 			return xerr.WithStack(err)
 		}
 		// 更新牛只状态
-		if err = tx.Model(new(model.Cow)).Where("id = ?", req.CowId).
-			Updates(map[string]interface{}{
-				"is_pregnant":      pasturePb.IsShow_No,
-				"last_abortion_at": req.AbortionAt,
-				"breed_status":     pasturePb.BreedStatus_Abort,
-			}).Error; err != nil {
+		if err = tx.Model(new(model.Cow)).
+			Select("is_pregnant,last_abortion_at,breed_status").
+			Where("id = ?", req.CowId).
+			Updates(cow).Error; err != nil {
 			return xerr.WithStack(err)
 		}
 
 		// 更新最近一次配种结果为流产
 		if err = tx.Model(new(model.EventMating)).
+			Select("mating_result,mating_result_at").
 			Where("id = ?", lastCowMating.Id).
-			Updates(map[string]interface{}{
-				"mating_result":    pasturePb.MatingResult_Abort,
-				"mating_result_at": req.AbortionAt,
-			}).Error; err != nil {
+			Updates(lastCowMating).Error; err != nil {
 		}
 		return nil
 	}); err != nil {
@@ -252,48 +232,3 @@ func (s *StoreEntry) AbortionList(
 		},
 	}, nil
 }
-
-func (s *StoreEntry) SubmitEventLog(ctx context.Context, cow *model.Cow, eventType pasturePb.EventType_Kind, req interface{}) *model.EventCowLog {
-	var (
-		desc          = ""
-		eventTypeName = s.EventTypeMap()[eventType]
-		eventAt       = int64(0)
-		penMap        = s.PenMap(ctx)
-		cowTypeMap    = s.CowTypeMap()
-	)
-
-	switch eventType {
-	case pasturePb.EventType_Enter:
-	case pasturePb.EventType_Transfer_Ben:
-	case pasturePb.EventType_Body_Score:
-	case pasturePb.EventType_Pregnancy_Check:
-	case pasturePb.EventType_Estrus:
-	case pasturePb.EventType_Calving:
-		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(";犊牛ID: %d; 出生体重: %f", v.CowId, v.Weight)
-			}
-		}
-		if data.IsInducingChildbirth == pasturePb.IsShow_Ok {
-			desc += fmt.Sprintf("; 难产原因: %s", s.DystociaReasonMap()[data.DystociaReason])
-		}
-		newEventCowLog := model.NewEventCowLog(cow, penMap, cowTypeMap, eventType, eventTypeName, data.OperationId, data.OperationName, desc, eventAt)
-		return newEventCowLog
-	case pasturePb.EventType_Seme_Time:
-	case pasturePb.EventType_Mating:
-	case pasturePb.EventType_Birth:
-		data := req.(*pasturePb.EventCalving)
-		eventAt = int64(data.CalvingAt)
-		desc = fmt.Sprintf("出生体重: %dKG;", data.CalvingAt, data.ChildNumber)
-
-	case pasturePb.EventType_Death:
-	case pasturePb.EventType_Transfer_Out:
-	case pasturePb.EventType_Transfer_In:
-	case pasturePb.EventType_Out:
-	case pasturePb.EventType_Immunication:
-	}
-	return nil
-}

+ 18 - 1
module/backend/event_check.go

@@ -4,6 +4,10 @@ import (
 	"context"
 	"kpt-pasture/model"
 
+	"go.uber.org/zap"
+
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
+
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	"gitee.com/xuyiping_admin/pkg/xerr"
 )
@@ -93,8 +97,10 @@ func (s *StoreEntry) PregnantCheckDataCheck(ctx context.Context, req *pasturePb.
 	for _, pregnantCheckData := range req.Item {
 		operationUser, err := s.GetSystemUserById(ctx, int64(pregnantCheckData.OperationId))
 		if err != nil {
-			return nil, xerr.WithStack(err)
+			zaplog.Error("PregnantCheckDataCheck", zap.Any("id", pregnantCheckData.OperationId), zap.Any("error", err.Error()))
+			return nil, xerr.Customf("获取操作人员信息失败")
 		}
+		pregnantCheckData.OperationName = operationUser.Name
 		cow, err := s.GetCowInfoByCowId(ctx, int64(pregnantCheckData.CowId))
 		if err != nil {
 			return nil, xerr.WithStack(err)
@@ -105,6 +111,16 @@ func (s *StoreEntry) PregnantCheckDataCheck(ctx context.Context, req *pasturePb.
 			return nil, xerr.Customf("牛只: %d,当前状态为: %s,不能进行孕检", cow.Id, cow.BreedStatus.String())
 		}
 
+		itemEventPregnantCheck, err := s.GetEventPregnantCheckIsExIstByCowId(ctx, cow)
+		if err != nil {
+			zaplog.Error("GetEventPregnantCheckIsExIstByCowId", zap.Any("err", err), zap.Any("cow", cow))
+			return nil, xerr.Customf("该牛只孕检事件数据异常, cowId: %d", pregnantCheckData.CowId)
+		}
+
+		if itemEventPregnantCheck.Id <= 0 {
+			return nil, xerr.Customf("该牛只孕检事件数据异常, cowId: %d", pregnantCheckData.CowId)
+		}
+
 		pregnantCheckBatchModelList = append(pregnantCheckBatchModelList, &PregnantCheckBatchModel{
 			Cow:                 cow,
 			OperationUser:       operationUser,
@@ -112,6 +128,7 @@ func (s *StoreEntry) PregnantCheckDataCheck(ctx context.Context, req *pasturePb.
 			PregnantCheckMethod: pregnantCheckData.PregnantCheckMethod,
 			PregnantCheckResult: pregnantCheckData.PregnantCheckResult,
 			Remarks:             pregnantCheckData.Remarks,
+			EventPregnancyCheck: itemEventPregnantCheck,
 		})
 	}
 

+ 164 - 0
module/backend/event_cow_log.go

@@ -0,0 +1,164 @@
+package backend
+
+import (
+	"context"
+	"fmt"
+	"kpt-pasture/model"
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+func (s *StoreEntry) SubmitEventLog(
+	ctx context.Context,
+	cow *model.Cow,
+	eventType pasturePb.EventType_Kind,
+	exposeEstrusType pasturePb.ExposeEstrusType_Kind,
+	req interface{},
+) *model.EventCowLog {
+	var (
+		desc, remarks = "", ""
+		eventTypeName = s.EventTypeMap()[eventType]
+		eventAt       = int64(0)
+		penMap        = s.PenMap(ctx)
+		cowTypeMap    = s.CowTypeMap()
+		operationUser = &model.SystemUser{}
+	)
+
+	switch eventType {
+	case pasturePb.EventType_Enter:
+	case pasturePb.EventType_Transfer_Ben:
+		data := req.(*model.EventTransferGroup)
+		transferAt, _ := time.Parse(model.LayoutDate2, data.TransferDate)
+		eventAt = transferAt.Unix()
+		remarks = data.Remarks
+		operationUser.Id = data.OperationId
+		operationUser.Name = data.OperationName
+		desc = fmt.Sprintf("转出栏舍: %s; 转入栏舍: %s", penMap[data.PenOutId].Name, penMap[data.PenInId].Name)
+	case pasturePb.EventType_Body_Score:
+	case pasturePb.EventType_Pregnancy_Check:
+		data := req.(*pasturePb.EventPregnantCheckBatch)
+		for _, v := range data.Item {
+			if int64(v.CowId) != cow.Id {
+				continue
+			}
+			eventAt = int64(v.PregnantCheckAt)
+			if v.PregnantCheckResult == pasturePb.PregnantCheckResult_Pregnant {
+				desc += fmt.Sprintf("孕检方式: %s; 孕检结果: 怀孕", s.PregnantCheckMethodMap()[v.PregnantCheckMethod])
+			}
+			if v.PregnantCheckResult == pasturePb.PregnantCheckResult_UnPregnant {
+				desc += fmt.Sprintf("孕检方式: %s", s.PregnantCheckMethodMap()[v.PregnantCheckMethod])
+				if cow.BreedStatus == pasturePb.BreedStatus_Abort {
+					desc += fmt.Sprintf("; 复检结果: 流产")
+				}
+				if cow.BreedStatus == pasturePb.BreedStatus_Empty {
+					desc += fmt.Sprintf("; 孕检结果: 空怀")
+				}
+			}
+			operationUser.Id = int64(v.OperationId)
+			operationUser.Name = v.OperationName
+			remarks = v.Remarks
+		}
+	case pasturePb.EventType_Estrus:
+		eventType = pasturePb.EventType_Mating // 发情配种批量提交
+		data := req.(*pasturePb.EventEstrus)
+		eventAt = int64(data.MatingAt)
+		desc = fmt.Sprintf("配种公牛: %s;发情揭发方式:%s;配种结果:未知", data.BullNumber, s.ExposeEstrusTypeMap()[pasturePb.ExposeEstrusType_Neck_Ring])
+		operationUser.Id = int64(data.OperationId)
+		operationUser.Name = data.OperationName
+		remarks = data.Remarks
+	case pasturePb.EventType_Calving:
+		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(";犊牛ID: %d; 出生体重: %f", v.CowId, v.Weight)
+			}
+		}
+		if data.IsInducingChildbirth == pasturePb.IsShow_Ok {
+			desc += fmt.Sprintf("; 难产原因: %s", s.DystociaReasonMap()[data.DystociaReason])
+		}
+		operationUser.Id = int64(data.OperationId)
+		operationUser.Name = data.OperationName
+		remarks = data.Remarks
+	case pasturePb.EventType_Seme_Time:
+		data := req.(*pasturePb.EventSameTime)
+		eventAt = int64(data.SameTimeAt)
+		desc = fmt.Sprintf("同期名称: %s;激素名称: %s;剂量:%f;操作人: %s", data.SameTimeTypeName, data.DrugsName, data.Usage, data.OperationName)
+		operationUser.Id = int64(data.OperationId)
+		operationUser.Name = data.OperationName
+		remarks = data.Remarks
+	case pasturePb.EventType_Mating:
+		data := req.(*pasturePb.EventMating)
+		eventAt = int64(data.MatingAt)
+		desc = fmt.Sprintf("配种公牛: %s;发情揭发方式:%s;配种结果:未知", data.FrozenSemenNumber, s.ExposeEstrusTypeMap()[exposeEstrusType])
+		operationUser.Id = int64(data.OperationId)
+		operationUser.Name = data.OperationName
+		remarks = data.Remarks
+	case pasturePb.EventType_Birth:
+		eventAt = cow.BirthAt
+		desc = fmt.Sprintf("出生体重: %fKG;母号:%s;父号: %s", float32(cow.BirthWeight)/100, cow.MotherNumber, cow.LastBullNumber)
+	case pasturePb.EventType_Death:
+		data := req.(*model.EventDeparture)
+		eventAt = data.DepartureAt
+		desc = fmt.Sprintf("死亡原因: %s", data.ReasonName)
+		operationUser.Id = data.OperationId
+		operationUser.Name = data.OperationName
+	case pasturePb.EventType_Transfer_Out:
+	case pasturePb.EventType_Transfer_In:
+	case pasturePb.EventType_Out:
+		data := req.(*model.EventDeparture)
+		eventAt = data.DepartureAt
+		desc = fmt.Sprintf("淘汰原因: %s", data.ReasonName)
+		operationUser.Id = data.OperationId
+		operationUser.Name = data.OperationName
+	case pasturePb.EventType_Immunication:
+	case pasturePb.EventType_Weaning:
+		data := req.(*pasturePb.EventWeaningBatchRequest)
+		eventAt = int64(data.WeaningAt)
+		operationUser.Id = int64(data.OperationId)
+		operationUser.Name = data.OperationName
+		remarks = data.Remarks
+		for _, v := range data.Item {
+			if int64(v.CowId) == cow.Id {
+				desc = fmt.Sprintf("具体体重: %f", v.Weight)
+				break
+			}
+		}
+	case pasturePb.EventType_Sale:
+	case pasturePb.EventType_Abort:
+		data := req.(*pasturePb.EventAbortionRequest)
+		eventAt = int64(data.AbortionAt)
+		operationUser.Id = int64(data.OperationId)
+		operationUser.Name = data.OperationName
+		remarks = data.Remarks
+		desc = fmt.Sprintf("流产原因: %s", s.AbortionReasonsMap()[data.AbortionReasons])
+	case pasturePb.EventType_Weight:
+		data := req.(*pasturePb.EventWeight)
+		eventAt = int64(data.WeightAt)
+		operationUser.Id = int64(data.OperationId)
+		operationUser.Name = data.OperationName
+		remarks = data.Remarks
+		for _, v := range data.WeightItems {
+			if int64(v.CowId) == cow.Id {
+				desc = fmt.Sprintf("日龄: %d;具体体重: %f", cow.DayAge, v.Weight)
+				break
+			}
+		}
+	case pasturePb.EventType_Castrated:
+	case pasturePb.EventType_Insect_Repellent:
+	}
+	newEventCowLogModel := &model.EventCowLogModel{
+		Cow:           cow,
+		CowTypeName:   cowTypeMap[cow.CowType],
+		OperationUser: operationUser,
+		EventAt:       eventAt,
+		EventType:     eventType,
+		EventTypeName: eventTypeName,
+		Description:   desc,
+		Remarks:       remarks,
+		PenName:       penMap[cow.PenId].Name,
+	}
+	return model.NewEventCowLog(newEventCowLogModel)
+}

+ 6 - 1
module/backend/interface.go

@@ -128,6 +128,9 @@ type PastureManageService interface {
 	ImmunizationList(ctx context.Context, req *pasturePb.ImmunizationRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SearchImmunizationResponse, error)
 	CreatedOrUpdateImmunization(ctx context.Context, req *pasturePb.ImmunizationRequest) error
 	ImmunizationIsShow(ctx context.Context, id int64) error
+
+	SystemBasicEdit(ctx context.Context, req *pasturePb.BaseDataConfig) error
+	SystemBasicList(ctx context.Context) (*pasturePb.SearchBaseDataConfigResponse, error)
 }
 
 //go:generate mockgen -destination mock/ConfigDataService.go -package kptservicemock kpt-pasture/module/backend ConfigDataService
@@ -195,9 +198,11 @@ type EventService interface {
 	CowDiseaseTreatmentDetail(ctx context.Context, req *pasturePb.EventCowTreatmentDetailRequest, pagination *pasturePb.PaginationModel) (*pasturePb.EventCowTreatmentDetailResponse, error)
 	// CowDiseaseCurable 治愈
 	CowDiseaseCurable(ctx context.Context, req *pasturePb.EventCowCurableRequest) error
+	// DepartureBatch 离场
+	DepartureBatch(ctx context.Context, req *pasturePb.EventDepartureBatch) error
 
 	// SubmitEventLog 记录提交事件结果日志
-	SubmitEventLog(ctx context.Context, cow *model.Cow, eventType pasturePb.EventType_Kind, req interface{}) []*model.EventCowLog
+	SubmitEventLog(ctx context.Context, cow *model.Cow, eventType pasturePb.EventType_Kind, exposeEstrusType pasturePb.ExposeEstrusType_Kind, req interface{}) *model.EventCowLog
 }
 
 //go:generate mockgen -destination mock/CowService.go -package kptservicemock kpt-pasture/module/backend CowService

+ 39 - 0
module/backend/prescription.go

@@ -9,6 +9,9 @@ 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"
@@ -448,3 +451,39 @@ func (s *StoreEntry) ImmunizationIsShow(ctx context.Context, id int64) error {
 	}
 	return nil
 }
+
+func (s *StoreEntry) SystemBasicList(ctx context.Context) (*pasturePb.SearchBaseDataConfigResponse, error) {
+	systemBasicList := make([]*model.SystemBasic, 0)
+	if err := s.DB.Model(new(model.SystemBasic)).Where("is_show = ?", pasturePb.IsShow_Ok).Find(&systemBasicList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	return &pasturePb.SearchBaseDataConfigResponse{
+		Code:    http.StatusOK,
+		Message: "ok",
+		Data: &pasturePb.SearchBaseDataConfigData{
+			List:  model.SystemBasicSlice(systemBasicList).ToPb(),
+			Total: int32(len(systemBasicList)),
+		},
+	}, nil
+}
+
+func (s *StoreEntry) SystemBasicEdit(ctx context.Context, req *pasturePb.BaseDataConfig) error {
+	currentUser, err := s.GetCurrentSystemUser(ctx)
+	if err != nil {
+		return xerr.Custom("当前用户信息错误,请退出重新登录")
+	}
+
+	systemBasic := &model.SystemBasic{Id: req.Id}
+	if err = s.DB.Model(systemBasic).Where("is_show = ?", pasturePb.IsShow_Ok).First(systemBasic).Error; err != nil {
+		zaplog.Error("SystemBasicEdit", zap.Any("err", err), zap.Any("req", req))
+		return xerr.Customf("该配置信息不存在: %d", req.Id)
+	}
+	systemBasic.EditUpdate(req.MinValue, req.MaxValue, req.WeekValue, currentUser)
+	if err = s.DB.Model(systemBasic).Select("min_value,max_value,week_value,operation_id,operation_name").
+		Updates(systemBasic).Error; err != nil {
+		zaplog.Error("SystemBasicEdit", zap.Any("err", err), zap.Any("req", req))
+		return xerr.WithStack(err)
+	}
+
+	return nil
+}

+ 6 - 2
module/backend/sql.go

@@ -222,9 +222,11 @@ func (s *StoreEntry) GetWorkOrderSubByWorkOrderId(ctx context.Context, workOrder
 	return workOrderSubList, nil
 }
 
-func (s *StoreEntry) GetEventCowSameTimeById(ctx context.Context, id int64) (*model.EventCowSameTime, error) {
-	eventCowSameTime := &model.EventCowSameTime{Id: id}
+func (s *StoreEntry) GetEventCowSameTimeByCowId(ctx context.Context, cowId int64) (*model.EventCowSameTime, error) {
+	eventCowSameTime := &model.EventCowSameTime{}
 	if err := s.DB.Model(new(model.EventCowSameTime)).
+		Where("cow_id = ?", cowId).
+		Where("status = ?", pasturePb.IsShow_No).
 		First(eventCowSameTime).Error; err != nil {
 		return nil, xerr.WithStack(err)
 	}
@@ -380,6 +382,8 @@ func (s *StoreEntry) NeckRingIsExist(ctx context.Context, number string) (*model
 		First(neckRing).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
 			return nil, false
+		} else {
+			return nil, false
 		}
 	}
 	return neckRing, true