瀏覽代碼

event: forbidenMating: 解配和禁配事件

Yi 1 周之前
父節點
當前提交
5a3faa3baa

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250324063941-72d937ade669
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250324091419-f7fa3ad96c0e
 	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

@@ -70,6 +70,16 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250324061924-bf4abbba60b1 h1:9fg6SXor
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250324061924-bf4abbba60b1/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250324063941-72d937ade669 h1:RWi9BpB1kW42E3A84YsZzaN/+O0C795i2uiLReD7KQs=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250324063941-72d937ade669/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324081525-c0737d6d27b0 h1:YJu1wFMVQ5pOl0tYLg2DNaGxbBBSOt1/SVFeMOxc2f8=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324081525-c0737d6d27b0/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324082653-a738e7b57d34 h1:yj12kf9/II1d4s1yXv/IebhFlKfI2AZiEp67A48MQLI=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324082653-a738e7b57d34/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324083036-3b6babd2ba15 h1:mKQaCaSiqfai+msdKi5P+r+Nk8FT8K5jPTZAu/kAFSU=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324083036-3b6babd2ba15/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324084120-e6352deeb1c5 h1:lSms9Fs2UgkAr7a5rKYGpdUbb9lSDFgtcnNiuRusR+0=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324084120-e6352deeb1c5/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324091419-f7fa3ad96c0e h1:Dv1OgQfYuzw6+O1FBaSg86CiAOiGPnUIWV2FeWoPYdM=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250324091419-f7fa3ad96c0e/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=

+ 76 - 0
http/handler/event/event_breed.go

@@ -462,3 +462,79 @@ func DryMilkList(c *gin.Context) {
 
 	ginutil.JSONResp(c, res)
 }
+
+func ForbiddenMatingBatch(c *gin.Context) {
+	var req pasturePb.EventForbiddenMatingBatch
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := valid.ValidateStruct(&req,
+		valid.Field(&req.Items, valid.Required, valid.Each(valid.By(func(value interface{}) error {
+			item := value.(pasturePb.ForbiddenMatingItem)
+			return valid.ValidateStruct(&item,
+				valid.Field(&item.EarNumber, valid.Required),
+				valid.Field(&item.ForbiddenMatingAt, valid.Required),
+				valid.Field(&item.ForbiddenMatingReasonsKind, valid.Required),
+				valid.Field(&item.OperationId, valid.Required),
+			)
+		}))),
+	); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	if err := middleware.Dependency(c).StoreEventHub.OpsService.ForbiddenMatingBatch(c, &req); err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, &operationPb.CommonOK{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &operationPb.Success{Success: true},
+	})
+}
+
+func ForbiddenMatingList(c *gin.Context) {
+	var req pasturePb.SearchEventRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	pagination := &pasturePb.PaginationModel{
+		Page:       int32(c.GetInt(middleware.Page)),
+		PageSize:   int32(c.GetInt(middleware.PageSize)),
+		PageOffset: int32(c.GetInt(middleware.PageOffset)),
+	}
+
+	res, err := middleware.Dependency(c).StoreEventHub.OpsService.ForbiddenMatingList(c, &req, pagination)
+	if err != nil {
+		apierr.ClassifiedAbort(c, err)
+		return
+	}
+
+	ginutil.JSONResp(c, res)
+}
+
+func UnForbiddenMating(c *gin.Context) {
+	var req pasturePb.EventUnForbiddenMatingRequest
+	if err := ginutil.BindProto(c, &req); err != nil {
+		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
+		return
+	}
+
+	err := middleware.Dependency(c).StoreEventHub.OpsService.UnForbiddenMating(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},
+	})
+}

+ 5 - 0
http/route/event_api.go

@@ -71,5 +71,10 @@ func EventAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		// 干奶
 		eventRoute.POST("/dry/milk/batch", event.DryMilkBatch)
 		eventRoute.POST("/dry/milk/list", event.DryMilkList)
+
+		// 禁配
+		eventRoute.POST("/forbidden/mating/batch", event.ForbiddenMatingBatch)
+		eventRoute.POST("/forbidden/mating/list", event.ForbiddenMatingList)
+		eventRoute.POST("/un_forbidden/mating", event.UnForbiddenMating)
 	}
 }

+ 66 - 52
model/cow.go

@@ -9,58 +9,59 @@ import (
 )
 
 type Cow struct {
-	Id                  int64                          `json:"id"`
-	PastureId           int64                          `json:"pastureId"`           // 牧场id
-	Sex                 pasturePb.Genders_Kind         `json:"sex"`                 // 性别
-	NeckRingNumber      string                         `json:"neckRingNumber"`      // 脖环号
-	EarNumber           string                         `json:"earNumber"`           // 耳标号
-	EleEarNumber        string                         `json:"eleEarNumber"`        // 电子耳标号
-	EarOldNumber        string                         `json:"earOldNumber"`        // 旧耳标号
-	PenId               int32                          `json:"penId"`               // 栏舍id
-	PenName             string                         `json:"penName"`             // 栏舍名称
-	Lact                int32                          `json:"lact"`                // 胎次
-	DayAge              int32                          `json:"dayAge"`              // 日龄
-	CalvingAge          int32                          `json:"calvingAge"`          // 产后天使
-	PregnancyAge        int32                          `json:"pregnancyAge"`        // 怀孕天数 孕检结果有阳性更新,产犊后至0
-	AdmissionAge        int32                          `json:"admissionAge"`        // 入场日龄
-	AbortionAge         int32                          `json:"abortionAge"`         // 流产天数
-	LactationAge        int32                          `json:"lactationAge"`        // 泌乳天数
-	DryMilkAge          int32                          `json:"dryMilkAge"`          // 干奶天数
-	CowType             pasturePb.CowType_Kind         `json:"cowType"`             // 牛只类型
-	MilkKind            pasturePb.CowMilk_Kind         `json:"milkKind"`            // 牛只奶属性
-	BreedStatus         pasturePb.BreedStatus_Kind     `json:"breedStatus"`         // 繁殖状态
-	CowKind             pasturePb.CowKind_Kind         `json:"cowKind"`             // 牛只品种
-	BirthWeight         int64                          `json:"birthWeight"`         // 出生体重
-	CurrentWeight       int64                          `json:"currentWeight"`       // 当前体重
-	AdmissionWeight     int64                          `json:"admissionWeight"`     // 入场体重
-	SourceKind          pasturePb.CowSource_Kind       `json:"sourceKind"`          // 来源哪里
-	PurposeKind         pasturePb.Purpose_Kind         `json:"purposeKind"`         // 用途
-	FatherNumber        string                         `json:"fatherNumber"`        // 父号
-	MotherNumber        string                         `json:"motherNumber"`        // 母号
-	AdmissionStatus     pasturePb.AdmissionStatus_Kind `json:"admissionStatus"`     // 在场状态
-	IsPregnant          pasturePb.IsShow_Kind          `json:"isPregnant"`          // 是否怀孕
-	IsNotMating         pasturePb.IsShow_Kind          `json:"isNotMating"`         // 是否禁配 1 是 2 否
-	HealthStatus        pasturePb.HealthStatus_Kind    `json:"healthStatus"`        // 健康状态
-	WeaningAt           int64                          `json:"weaningAt"`           // 断奶时间
-	BirthAt             int64                          `json:"birthAt"`             // 出生时间
-	AdmissionAt         int64                          `json:"admissionAt"`         // 入场时间
-	DepartureAt         int64                          `json:"departureAt"`         // 离场时间
-	FirstMatingAt       int64                          `json:"firstMatingAt"`       // 首次配种时间
-	MatingTimes         int32                          `json:"matingTimes"`         // 配种次数
-	AbortionTimes       int32                          `json:"abortionTimes"`       // 流产次数
-	WeeklyActive        int32                          `json:"weeklyActive"`        // 每周活跃度
-	LastEstrusAt        int64                          `json:"lastEstrusAt"`        // 最后一次发情时间
-	LastCalvingAt       int64                          `json:"lastCalvingAt"`       // 最后一次产犊时间
-	LastMatingAt        int64                          `json:"lastMatingAt"`        // 最后一次配种时间
-	LastBullNumber      string                         `json:"lastBullNumber"`      // 最后一次配种牛号
-	LastPregnantCheckAt int64                          `json:"lastPregnantCheckAt"` // 最后一次孕检时间
-	LastDryMilkAt       int64                          `json:"lastDryMilkAt"`       // 最近一次干奶日期
-	LastSecondWeight    int64                          `json:"lastSecondWeight"`    // 最后第二次称重
-	LastSecondWeightAt  int64                          `json:"lastSecondWeightAt"`  // 最后第二次称重时间
-	LastAbortionAt      int64                          `json:"lastAbortionAt"`      // 最近一次流产时间
-	LastWeightAt        int64                          `json:"lastWeightAt"`        // 最近一次称重时间
-	CreatedAt           int64                          `json:"createdAt"`
-	UpdatedAt           int64                          `json:"updatedAt"`
+	Id                    int64                          `json:"id"`
+	PastureId             int64                          `json:"pastureId"`             // 牧场id
+	Sex                   pasturePb.Genders_Kind         `json:"sex"`                   // 性别
+	NeckRingNumber        string                         `json:"neckRingNumber"`        // 脖环号
+	EarNumber             string                         `json:"earNumber"`             // 耳标号
+	EleEarNumber          string                         `json:"eleEarNumber"`          // 电子耳标号
+	EarOldNumber          string                         `json:"earOldNumber"`          // 旧耳标号
+	PenId                 int32                          `json:"penId"`                 // 栏舍id
+	PenName               string                         `json:"penName"`               // 栏舍名称
+	Lact                  int32                          `json:"lact"`                  // 胎次
+	DayAge                int32                          `json:"dayAge"`                // 日龄
+	CalvingAge            int32                          `json:"calvingAge"`            // 产后天使
+	PregnancyAge          int32                          `json:"pregnancyAge"`          // 怀孕天数 孕检结果有阳性更新,产犊后至0
+	AdmissionAge          int32                          `json:"admissionAge"`          // 入场日龄
+	AbortionAge           int32                          `json:"abortionAge"`           // 流产天数
+	LactationAge          int32                          `json:"lactationAge"`          // 泌乳天数
+	DryMilkAge            int32                          `json:"dryMilkAge"`            // 干奶天数
+	CowType               pasturePb.CowType_Kind         `json:"cowType"`               // 牛只类型
+	MilkKind              pasturePb.CowMilk_Kind         `json:"milkKind"`              // 牛只奶属性
+	BreedStatus           pasturePb.BreedStatus_Kind     `json:"breedStatus"`           // 繁殖状态
+	CowKind               pasturePb.CowKind_Kind         `json:"cowKind"`               // 牛只品种
+	BirthWeight           int64                          `json:"birthWeight"`           // 出生体重
+	CurrentWeight         int64                          `json:"currentWeight"`         // 当前体重
+	AdmissionWeight       int64                          `json:"admissionWeight"`       // 入场体重
+	SourceKind            pasturePb.CowSource_Kind       `json:"sourceKind"`            // 来源哪里
+	PurposeKind           pasturePb.Purpose_Kind         `json:"purposeKind"`           // 用途
+	FatherNumber          string                         `json:"fatherNumber"`          // 父号
+	MotherNumber          string                         `json:"motherNumber"`          // 母号
+	AdmissionStatus       pasturePb.AdmissionStatus_Kind `json:"admissionStatus"`       // 在场状态
+	IsPregnant            pasturePb.IsShow_Kind          `json:"isPregnant"`            // 是否怀孕
+	IsForbiddenMating     pasturePb.IsShow_Kind          `json:"isForbiddenMating"`     // 是否禁配 1 是 2 否
+	HealthStatus          pasturePb.HealthStatus_Kind    `json:"healthStatus"`          // 健康状态
+	WeaningAt             int64                          `json:"weaningAt"`             // 断奶时间
+	BirthAt               int64                          `json:"birthAt"`               // 出生时间
+	AdmissionAt           int64                          `json:"admissionAt"`           // 入场时间
+	DepartureAt           int64                          `json:"departureAt"`           // 离场时间
+	FirstMatingAt         int64                          `json:"firstMatingAt"`         // 首次配种时间
+	MatingTimes           int32                          `json:"matingTimes"`           // 配种次数
+	AbortionTimes         int32                          `json:"abortionTimes"`         // 流产次数
+	WeeklyActive          int32                          `json:"weeklyActive"`          // 每周活跃度
+	LastEstrusAt          int64                          `json:"lastEstrusAt"`          // 最后一次发情时间
+	LastCalvingAt         int64                          `json:"lastCalvingAt"`         // 最后一次产犊时间
+	LastMatingAt          int64                          `json:"lastMatingAt"`          // 最后一次配种时间
+	LastBullNumber        string                         `json:"lastBullNumber"`        // 最后一次配种牛号
+	LastPregnantCheckAt   int64                          `json:"lastPregnantCheckAt"`   // 最后一次孕检时间
+	LastDryMilkAt         int64                          `json:"lastDryMilkAt"`         // 最近一次干奶日期
+	LastForbiddenMatingAt int64                          `json:"lastForbiddenMatingAt"` // 最近一次禁配时间
+	LastSecondWeight      int64                          `json:"lastSecondWeight"`      // 最后第二次称重
+	LastSecondWeightAt    int64                          `json:"lastSecondWeightAt"`    // 最后第二次称重时间
+	LastAbortionAt        int64                          `json:"lastAbortionAt"`        // 最近一次流产时间
+	LastWeightAt          int64                          `json:"lastWeightAt"`          // 最近一次称重时间
+	CreatedAt             int64                          `json:"createdAt"`
+	UpdatedAt             int64                          `json:"updatedAt"`
 }
 
 func (c *Cow) TableName() string {
@@ -182,6 +183,7 @@ func (c *Cow) EstrusUpdate(estrusAt int64) {
 	c.LastEstrusAt = estrusAt
 }
 
+// EventDryMilkUpdate 干奶更新
 func (c *Cow) EventDryMilkUpdate(dryMilkAt int64, pen *Pen) {
 	c.LastDryMilkAt = dryMilkAt
 	c.MilkKind = pasturePb.CowMilk_Dry_Milk
@@ -189,6 +191,18 @@ func (c *Cow) EventDryMilkUpdate(dryMilkAt int64, pen *Pen) {
 	c.PenName = pen.Name
 }
 
+// ForbiddenMatingUpdate 禁配更新
+func (c *Cow) ForbiddenMatingUpdate(forbiddenMatingAt int64) {
+	c.IsForbiddenMating = pasturePb.IsShow_Ok
+	c.LastForbiddenMatingAt = forbiddenMatingAt
+}
+
+// UnForbiddenMatingUpdate 解禁配更新
+func (c *Cow) UnForbiddenMatingUpdate() {
+	c.IsForbiddenMating = pasturePb.IsShow_No
+	c.LastForbiddenMatingAt = 0
+}
+
 type CowSlice []*Cow
 
 func (c CowSlice) ToPB(

+ 83 - 0
model/event_forbidden_mating.go

@@ -0,0 +1,83 @@
+package model
+
+import (
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+type EventForbiddenMating struct {
+	Id                         int64                                 `json:"id"`
+	PastureId                  int64                                 `json:"pastureId"`
+	CowId                      int64                                 `json:"cowId"`
+	EarNumber                  string                                `json:"earNumber"`
+	ForbiddenMatingAt          int64                                 `json:"forbiddenMatingAt"`
+	ForbiddenMatingReasonsKind pasturePb.ForbiddenMatingReasons_Kind `json:"forbiddenMatingReasonsKind"`
+	ForbiddenMatingReasonsName string                                `json:"forbiddenMatingReasonsName"`
+	UnForbiddenMatingAt        int64                                 `json:"unForbiddenMatingAt"`
+	OperationId                int64                                 `json:"operationId"`
+	OperationName              string                                `json:"operationName"`
+	Remarks                    string                                `json:"remarks"`
+	IsShow                     pasturePb.IsShow_Kind                 `json:"isShow"`
+	MessageId                  int64                                 `json:"messageId"`
+	MessageName                string                                `json:"messageName"`
+	CreatedAt                  int64                                 `json:"createdAt"`
+	UpdatedAt                  int64                                 `json:"updatedAt"`
+}
+
+func (e *EventForbiddenMating) TableName() string {
+	return "event_forbidden_mating"
+}
+
+func (e *EventForbiddenMating) UnForbiddenMatingUpdate(unForbiddenMatingAt int64) {
+	e.UnForbiddenMatingAt = unForbiddenMatingAt
+	e.IsShow = pasturePb.IsShow_No
+}
+
+func NewEventForbiddenMating(pastureId int64, cow *Cow, forbiddenMatingAt int64, forbiddenMatingReasonsKind pasturePb.ForbiddenMatingReasons_Kind,
+	forbiddenMatingReasonsName, remarks string, operationUser, currentUser *SystemUser) *EventForbiddenMating {
+	return &EventForbiddenMating{
+		PastureId:                  pastureId,
+		CowId:                      cow.Id,
+		EarNumber:                  cow.EarNumber,
+		ForbiddenMatingAt:          forbiddenMatingAt,
+		ForbiddenMatingReasonsKind: forbiddenMatingReasonsKind,
+		ForbiddenMatingReasonsName: forbiddenMatingReasonsName,
+		OperationId:                operationUser.Id,
+		OperationName:              operationUser.Name,
+		Remarks:                    remarks,
+		MessageId:                  currentUser.Id,
+		MessageName:                currentUser.Name,
+		IsShow:                     pasturePb.IsShow_Ok,
+	}
+}
+
+type EventForbiddenMatingSlice []*EventForbiddenMating
+
+func (e EventForbiddenMatingSlice) ToPB() []*pasturePb.ForbiddenMatingItem {
+	res := make([]*pasturePb.ForbiddenMatingItem, len(e))
+	for i, v := range e {
+		res[i] = &pasturePb.ForbiddenMatingItem{
+			Id:                         int32(v.Id),
+			CowId:                      int32(v.CowId),
+			EarNumber:                  v.EarNumber,
+			ForbiddenMatingAt:          int32(v.ForbiddenMatingAt),
+			ForbiddenMatingReasonsKind: v.ForbiddenMatingReasonsKind,
+			ForbiddenMatingReasonsName: v.ForbiddenMatingReasonsName,
+			Remarks:                    v.Remarks,
+			OperationId:                int32(v.OperationId),
+			OperationName:              v.OperationName,
+			CreatedAt:                  int32(v.CreatedAt),
+			UpdatedAt:                  int32(v.UpdatedAt),
+		}
+	}
+	return res
+}
+
+type EventForbiddenMatingItem struct {
+	Cow                        *Cow                                  `json:"cow"`
+	ForbiddenMatingAt          int64                                 `json:"forbiddenMatingAt"`
+	ForbiddenMatingReasonsKind pasturePb.ForbiddenMatingReasons_Kind `json:"forbiddenMatingReasonsKind"`
+	ForbiddenMatingReasonsName string                                `json:"forbiddenMatingReasonsName"`
+	Remarks                    string                                `json:"remarks"`
+	OperationUser              *SystemUser                           `json:"operationUser"`
+	MessageUser                *SystemUser                           `json:"messageUser"`
+}

+ 42 - 0
module/backend/config_data_extend.go

@@ -39,3 +39,45 @@ func (s *StoreEntry) AdmissionStatusEnumList(isAll string) []*pasturePb.ConfigOp
 	})
 	return configOptions
 }
+
+func (s *StoreEntry) ForbiddenMatingReasonsEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
+	if isAll == model.IsAllYes {
+		configOptions = append(configOptions,
+			&pasturePb.ConfigOptionsList{
+				Value:    int32(pasturePb.AuditStatus_Invalid),
+				Label:    "全部",
+				Disabled: true,
+			})
+	}
+	configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.ForbiddenMatingReasons_Metritis),
+		Label:    "子宫炎",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.ForbiddenMatingReasons_Reproductive_Diseases),
+		Label:    "繁殖疾病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.ForbiddenMatingReasons_Reproductive_Failure),
+		Label:    "繁殖障碍",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.ForbiddenMatingReasons_Breast_Abnormalities),
+		Label:    "乳腺异常",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.ForbiddenMatingReasons_Low_Yield),
+		Label:    "低产",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.ForbiddenMatingReasons_Hoof_Disease),
+		Label:    "蹄病",
+		Disabled: true,
+	}, &pasturePb.ConfigOptionsList{
+		Value:    int32(pasturePb.ForbiddenMatingReasons_Other),
+		Label:    "其他",
+		Disabled: true,
+	})
+	return configOptions
+}

+ 8 - 0
module/backend/enum_map.go

@@ -311,6 +311,14 @@ func (s *StoreEntry) UnMatingReasonsMap() map[pasturePb.UnMatingReasons_Kind]str
 	return res
 }
 
+func (s *StoreEntry) ForbiddenMatingReasonsMap() map[pasturePb.ForbiddenMatingReasons_Kind]string {
+	res := make(map[pasturePb.ForbiddenMatingReasons_Kind]string)
+	for _, v := range s.ForbiddenMatingReasonsEnumList("") {
+		res[pasturePb.ForbiddenMatingReasons_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

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

+ 160 - 0
module/backend/event_breed_more_two.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"kpt-pasture/model"
 	"net/http"
+	"time"
 
 	"gorm.io/gorm"
 
@@ -118,3 +119,162 @@ func (s *StoreEntry) DryMilkBatch(ctx context.Context, req *pasturePb.EventMilkB
 	}
 	return nil
 }
+
+func (s *StoreEntry) ForbiddenMatingBatch(ctx context.Context, req *pasturePb.EventForbiddenMatingBatch) error {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if len(req.Items) > 50 {
+		return xerr.Custom("最多只能添加50条数据")
+	}
+
+	items, err := s.ForbiddenMatingCheck(ctx, userModel, req.Items)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if len(items) <= 0 {
+		return nil
+	}
+
+	eventForbiddenMatingList := make([]*model.EventForbiddenMating, 0)
+	cowLogList := make([]*model.EventCowLog, 0)
+
+	if err = s.DB.Transaction(func(tx *gorm.DB) error {
+		for _, item := range items {
+			cowLog := s.SubmitEventLog(ctx, userModel.AppPasture.Id, item.Cow, pasturePb.EventType_ForbiddenMating, item)
+			eventForbiddenMating := model.NewEventForbiddenMating(userModel.AppPasture.Id, item.Cow, item.ForbiddenMatingAt,
+				item.ForbiddenMatingReasonsKind, item.ForbiddenMatingReasonsName, item.Remarks, item.OperationUser, userModel.SystemUser)
+
+			eventForbiddenMatingList = append(eventForbiddenMatingList, eventForbiddenMating)
+			cowLogList = append(cowLogList, cowLog)
+
+			// 更新牛只信息
+			item.Cow.ForbiddenMatingUpdate(item.ForbiddenMatingAt)
+			if err = tx.Model(new(model.Cow)).
+				Select("is_forbidden_mating", "last_forbidden_mating_at").
+				Updates(item.Cow).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+		}
+
+		if err = tx.Model(new(model.EventForbiddenMating)).
+			Create(eventForbiddenMatingList).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+		if err = tx.Model(new(model.EventCowLog)).
+			Create(cowLogList).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+		return nil
+	}); err != nil {
+		return xerr.WithStack(err)
+	}
+
+	return nil
+}
+
+func (s *StoreEntry) ForbiddenMatingList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.EventForbiddenMatingResponse, error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	eventForbiddenMatingList := make([]*model.EventForbiddenMating, 0)
+	var count int64 = 0
+	pref := s.DB.Model(new(model.EventForbiddenMating)).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Where("is_show = ?", pasturePb.IsShow_Ok)
+
+	if req.EarNumber != "" {
+		pref.Where("ear_number = ?", req.EarNumber)
+	}
+
+	if req.StartDayAt > 0 && req.EndDayAt > 0 && req.StartDayAt <= req.EndDayAt {
+		pref.Where("reality_day BETWEEN ? AND ?", req.StartDayAt, req.EndDayAt)
+	}
+
+	if err = pref.Order("id desc").
+		Count(&count).Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Find(&eventForbiddenMatingList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return &pasturePb.EventForbiddenMatingResponse{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &pasturePb.EventForbiddenMatingData{
+			List:     model.EventForbiddenMatingSlice(eventForbiddenMatingList).ToPB(),
+			Total:    int32(count),
+			PageSize: pagination.PageSize,
+			Page:     pagination.Page,
+		},
+	}, nil
+}
+
+func (s *StoreEntry) UnForbiddenMating(ctx context.Context, req *pasturePb.EventUnForbiddenMatingRequest) error {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if len(req.EarNumber) <= 0 {
+		return xerr.Custom("请选择相关牛只")
+	}
+
+	if len(req.EarNumber) > 50 {
+		return xerr.Custom("最多只能添加50条数据")
+	}
+
+	eventForbiddenMatingList := make([]*model.EventForbiddenMating, 0)
+	if err = s.DB.Model(new(model.EventForbiddenMating)).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Where("is_show = ?", pasturePb.IsShow_Ok).
+		Where("ear_number IN (?)", req.EarNumber).
+		Find(&eventForbiddenMatingList).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+
+	if len(eventForbiddenMatingList) <= 0 {
+		return nil
+	}
+
+	nowTime := time.Now().Unix()
+
+	if err = s.DB.Transaction(func(tx *gorm.DB) error {
+		for _, item := range eventForbiddenMatingList {
+			cowInfo, err := s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, item.CowId)
+			if err != nil {
+				return xerr.WithStack(err)
+			}
+
+			// 牛只解配更新
+			cowInfo.UnForbiddenMatingUpdate()
+			if err = tx.Model(new(model.Cow)).
+				Select("is_forbidden_mating", "last_forbidden_mating_at").
+				Updates(cowInfo).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+
+			// 事件更新
+			item.UnForbiddenMatingUpdate(nowTime)
+			if err = tx.Model(new(model.EventForbiddenMating)).
+				Select("is_show", "un_forbidden_mating_at").
+				Where("id = ?", item.Id).
+				Updates(item).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+
+		}
+		return nil
+	}); err != nil {
+		return xerr.WithStack(err)
+	}
+
+	return nil
+}

+ 35 - 0
module/backend/event_check.go

@@ -295,3 +295,38 @@ func (s *StoreEntry) AbortionEventDataCheck(ctx context.Context, userModel *mode
 	}
 	return abortionCheckBatchModelList, nil
 }
+
+func (s *StoreEntry) ForbiddenMatingCheck(ctx context.Context, userModel *model.UserModel, items []*pasturePb.ForbiddenMatingItem) ([]*model.EventForbiddenMatingItem, error) {
+	res := make([]*model.EventForbiddenMatingItem, 0)
+	forbiddenMatingReasonsMap := s.ForbiddenMatingReasonsMap()
+	for _, v := range items {
+		cowInfo, err := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, v.EarNumber)
+		if err != nil {
+			return nil, xerr.WithStack(err)
+		}
+
+		if cowInfo.Sex != pasturePb.Genders_Female {
+			return nil, xerr.Customf("牛只: %s,不是母牛", cowInfo.EarNumber)
+		}
+
+		if v.ForbiddenMatingAt < int32(cowInfo.BirthAt) {
+			return nil, xerr.Customf("牛只: %s,禁止配种时间不能小于出生时间", cowInfo.EarNumber)
+		}
+
+		operationUser, err := s.GetSystemUserById(ctx, int64(v.OperationId))
+		if err != nil {
+			return nil, xerr.WithStack(err)
+		}
+
+		res = append(res, &model.EventForbiddenMatingItem{
+			Cow:                        cowInfo,
+			ForbiddenMatingAt:          int64(v.ForbiddenMatingAt),
+			ForbiddenMatingReasonsKind: v.ForbiddenMatingReasonsKind,
+			ForbiddenMatingReasonsName: forbiddenMatingReasonsMap[v.ForbiddenMatingReasonsKind],
+			Remarks:                    v.Remarks,
+			OperationUser:              operationUser,
+			MessageUser:                userModel.SystemUser,
+		})
+	}
+	return res, nil
+}

+ 7 - 0
module/backend/event_cow_log.go

@@ -186,6 +186,13 @@ func (s *StoreEntry) SubmitEventLog(ctx context.Context, pastureId int64, cow *m
 		desc = fmt.Sprintf("日龄: %d;体重: %s kg", cow.DayAge, strconv.FormatFloat(float64(data.Weight), 'f', 2, 64))
 	case pasturePb.EventType_Castrated:
 	case pasturePb.EventType_Insect_Repellent:
+	case pasturePb.EventType_ForbiddenMating:
+		data := req.(*model.EventForbiddenMatingItem)
+		eventAt = data.ForbiddenMatingAt
+		operationUser.Id = data.OperationUser.Id
+		operationUser.Name = data.OperationUser.Name
+		remarks = data.Remarks
+		desc = fmt.Sprintf("禁配原因: %s", data.ForbiddenMatingReasonsName)
 	}
 	newEventCowLogModel := &model.EventCowLogModel{
 		Cow:               cow,

+ 5 - 0
module/backend/interface.go

@@ -192,6 +192,11 @@ type EventService interface {
 	DryMilkList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.EventMilkResponse, error)
 	DryMilkBatch(ctx context.Context, req *pasturePb.EventMilkBatch) error
 
+	// ForbiddenMatingBatch 禁配
+	ForbiddenMatingBatch(ctx context.Context, req *pasturePb.EventForbiddenMatingBatch) error
+	ForbiddenMatingList(ctx context.Context, req *pasturePb.SearchEventRequest, pagination *pasturePb.PaginationModel) (*pasturePb.EventForbiddenMatingResponse, error)
+	UnForbiddenMating(ctx context.Context, req *pasturePb.EventUnForbiddenMatingRequest) error
+
 	// WeaningBatch 断奶
 	WeaningBatch(ctx context.Context, req *pasturePb.EventWeaningBatch) error