Browse Source

calendar: update

Yi 3 weeks ago
parent
commit
81d20e2862

+ 1 - 1
dep/di_crontab.go

@@ -98,7 +98,7 @@ func EntryCrontab(dependency CrontabDependency) *cron.Crontab {
 		panic(err)
 	}
 
-	err = newCrontab.Bind("NeckRingMerge", cs.NeckRingMerge, dependency.CrontabHub.NeckRingOriginalMergeData)
+	err = newCrontab.Bind("NeckRingMerge", cs.NeckRingMerge, dependency.CrontabHub.NeckRingOriginalMerge)
 	if err != nil {
 		zaplog.Error("EntryCrontab", zap.Any("NeckRingOriginalMergeData", err))
 		panic(err)

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250305125910-0c6e47c2e274
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250306060531-dfa1b97a964b
 	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

@@ -38,6 +38,14 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250305125910-0c6e47c2e274 h1:zbGuv1f9ZimRe8ViLJc16Pdvow7OV03itkuo7p/LDzM=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250305125910-0c6e47c2e274/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250306013635-4cf08c9620eb h1:Py16cQzWd5G1m86qGUd/xAjI9f3pshaQv8QwacNiHe4=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250306013635-4cf08c9620eb/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250306025059-d5af4673e2ff h1:hpjGfL/IH3p+hArgoZBvS8K221zxLCmUexicN/me6Rc=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250306025059-d5af4673e2ff/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250306030727-9cd4d60bdaa7 h1:s3qKKeNDVEKzUP8UjYyl46awP0JUj8vv5hEVHpy19hM=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250306030727-9cd4d60bdaa7/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250306060531-dfa1b97a964b h1:KBCoYhktN5Hm2aeYudrU1Qgq3g4GrI7Dnng/aoy+pR0=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250306060531-dfa1b97a964b/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=
@@ -172,6 +180,7 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
 github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
@@ -609,6 +618,7 @@ go.uber.org/dig v1.15.0/go.mod h1:pKHs0wMynzL6brANhB2hLMro+zalv1osARTviTcqHLM=
 go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
 go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
 go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
+go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=

+ 1 - 1
http/route/work_api.go

@@ -20,8 +20,8 @@ func WorkOrderAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		workRoute.GET("/user/order/list/:status", work.UserOrderList)
 
 		workRoute.POST("/calendar/list", work.CalendarList)
-		workRoute.POST("/calendar/detail", work.CalendarTableDetail)
 		workRoute.POST("/calendar/todo/list", work.CalendarToDoList)
+		workRoute.POST("/calendar/detail", work.CalendarTableDetail)
 
 		// 清单相关接口
 		workRoute.POST("/same/time/items", work.SameTimeCowList)

+ 13 - 0
model/app_pasture_receiver.go

@@ -0,0 +1,13 @@
+package model
+
+type AppPastureReceiver struct {
+	Id             int64  `json:"id"`
+	PastureId      int64  `json:"pastureId"`
+	ReceiverNumber string `json:"receiverNumber"`
+	CreatedAt      int64  `json:"createdAt"`
+	UpdatedAt      int64  `json:"updatedAt"`
+}
+
+func (a *AppPastureReceiver) TableName() string {
+	return "app_pasture_receiver"
+}

+ 3 - 0
model/cow.go

@@ -525,4 +525,7 @@ type CowBehaviorCurveData struct {
 	EstrusList       map[pasturePb.EstrusLevel_Kind][]string `json:"estrusList"`       // 发情预警
 	EventList        map[string][]string                     `json:"eventList"`        // 事件数据
 	EventMap         map[pasturePb.EventType_Kind]string     `json:"eventMap"`         // 所有事件
+	RuminaChange     []int32                                 `json:"ruminaChange"`     // 反刍变化
+	LowActivity      int32                                   `json:"lowActivity"`      // 低活动量参数
+	MiddleActivity   int32                                   `json:"middleActivity"`   // 中活动量行数
 }

+ 1 - 1
model/event_transfer_group.go

@@ -28,7 +28,7 @@ func (e *EventTransferGroup) TableName() string {
 func NewEventTransferGroup(pastureId int64, cow *Cow, req *pasturePb.TransferGroupEventData, transferPenMap map[int32]string, currentUser *SystemUser, operationUser *SystemUser) *EventTransferGroup {
 	return &EventTransferGroup{
 		PastureId:          pastureId,
-		CowId:              int64(req.CowId),
+		CowId:              cow.Id,
 		PenInId:            req.TransferInPenId,
 		PenOutId:           cow.PenId,
 		Lact:               cow.Lact,

+ 3 - 0
model/neck_active_habit.go

@@ -18,6 +18,7 @@ const (
 	DefaultChewFilter    = -99
 	DefaultFilterCorrect = 100
 	DefaultWeeklyActive  = 1500
+	DefaultRecordCount   = 6
 )
 
 type NeckActiveHabit struct {
@@ -124,6 +125,7 @@ func (n NeckActiveHabitSlice) ToPB(curveName string) *CowBehaviorCurveData {
 		EstrusList:       make(map[pasturePb.EstrusLevel_Kind][]string),
 		EventList:        make(map[string][]string),
 		EventMap:         make(map[pasturePb.EventType_Kind]string),
+		RuminaChange:     make([]int32, 0),
 	}
 	initFrameId := int32(0)
 	dateFrameMap := make(map[string][]int32)
@@ -172,6 +174,7 @@ func (n NeckActiveHabitSlice) ToPB(curveName string) *CowBehaviorCurveData {
 		case "active": // 活动量
 			res.OriginalDateList = append(res.OriginalDateList, v.High)
 			res.ChangeDateList = append(res.ChangeDateList, v.ChangeFilter)
+			res.RuminaChange = append(res.RuminaChange, v.ChangeRumina)
 		case "rumina": // 反刍
 			res.OriginalDateList = append(res.OriginalDateList, v.Rumina)
 			res.ChangeDateList = append(res.ChangeDateList, v.ChangeRumina)

+ 4 - 3
model/neck_ring_original.go

@@ -40,14 +40,15 @@ func (n *NeckRingOriginal) TableName() string {
 	return "neck_ring_original"
 }
 
-func NewNeckRingOriginal(neckLog *Behavior) *NeckRingOriginal {
+func NewNeckRingOriginal(neckLog *Behavior, pastureId int64) *NeckRingOriginal {
 	activeDateTimeType := pasturePb.ActiveTimeType_Twenty_Minutes
 	if neckLog.Frameid%10 == 8 {
 		activeDateTimeType = pasturePb.ActiveTimeType_Two_Hours
 	}
+
 	return &NeckRingOriginal{
 		Uuid:            neckLog.UUID,
-		PastureId:       1,
+		PastureId:       pastureId,
 		NeckRingNumber:  fmt.Sprintf("%d", neckLog.Ecowid),
 		Frameid:         neckLog.Frameid,
 		Rumina:          neckLog.Rumina,
@@ -96,7 +97,7 @@ func (n *NeckRingOriginalMerge) IsMageData(data *NeckRingOriginal, xframeId int3
 	avgParam := int32(1)
 	if n.ActiveDateType == pasturePb.ActiveTimeType_Two_Hours {
 		n.RecordCount = AvgHours
-		avgParam = 6
+		avgParam = DefaultRecordCount
 	} else {
 		n.RecordCount += 1
 	}

+ 65 - 23
module/backend/calendar.go

@@ -20,22 +20,23 @@ func (s *StoreEntry) CalendarToDoList(ctx context.Context, req *pasturePb.Calend
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}
+	whereSql := fmt.Sprintf(" AND pasture_id = %d AND end_day <= %d ", userModel.AppPasture.Id, util.TimeParseLocalEndUnix(time.Now().Format(model.LayoutDate2)))
 
 	calendarToDoList := make([]*pasturePb.CalendarToDoList, 0)
 	sql := `SELECT a.cow_id,b.pen_name,a.calendar_type_name,DATE_FORMAT(FROM_UNIXTIME(a.plan_day), '%Y-%m-%d') AS plan_day,a.remaining_days,b.lact,b.ear_number FROM (
-		SELECT cow_id,plan_day,'免疫' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_immunization_plan WHERE status = 2 AND pasture_id = ` + fmt.Sprintf("%d", userModel.AppPasture.Id) + `
+		SELECT cow_id,plan_day,'免疫' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_immunization_plan WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,plan_day,'同期' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_cow_same_time WHERE status = 2 AND pasture_id = ` + fmt.Sprintf("%d", userModel.AppPasture.Id) + `
+		SELECT cow_id,plan_day,'同期' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_cow_same_time WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,plan_day,'孕检' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_pregnant_check WHERE status = 2 AND pasture_id = ` + fmt.Sprintf("%d", userModel.AppPasture.Id) + `
+		SELECT cow_id,plan_day,'孕检' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_pregnant_check WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,plan_day,'断奶' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_weaning WHERE status = 2 AND pasture_id = ` + fmt.Sprintf("%d", userModel.AppPasture.Id) + `
+		SELECT cow_id,plan_day,'断奶' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_weaning WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,plan_day,'配种' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_mating WHERE status = 2 AND pasture_id = ` + fmt.Sprintf("%d", userModel.AppPasture.Id) + `
+		SELECT cow_id,plan_day,'配种' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_mating WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,plan_day,'产犊' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_calving WHERE status = 2 AND pasture_id = ` + fmt.Sprintf("%d", userModel.AppPasture.Id) + `
+		SELECT cow_id,plan_day,'产犊' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_calving WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,disease_at as plan_day,'疾病' as calendar_type_name,0 AS remaining_days FROM event_cow_disease WHERE diagnosed_result IN (2,3)
+		SELECT cow_id,disease_at as plan_day,'疾病' as calendar_type_name,0 AS remaining_days FROM event_cow_disease WHERE diagnosed_result IN (2,3) AND pasture_id = ` + fmt.Sprintf("%d", userModel.AppPasture.Id) + `
 	) as a JOIN cow b ON a.cow_id = b.id WHERE 1 = 1 `
 
 	completeSql := fmt.Sprintf("%s ORDER BY a.plan_day DESC", sql)
@@ -70,15 +71,14 @@ func (s *StoreEntry) CalendarToDoList(ctx context.Context, req *pasturePb.Calend
 		toDayCompletedCountMap[v.CalendarTypeName] = v.Count
 	}
 
-	list := Paginate(calendarToDoList, req, pagination)
-
+	list, total := Paginate(calendarToDoList, req, pagination)
 	return &pasturePb.CalendarToDoResponse{
 		Code: http.StatusOK,
 		Msg:  "ok",
 		Data: &pasturePb.CalendarToDoData{
 			List:     list,
 			Progress: ProgressList(calendarToDoList, toDayCompletedCountMap),
-			Total:    int32(len(calendarToDoList)),
+			Total:    total,
 			PageSize: pagination.PageSize,
 			Page:     pagination.Page,
 		},
@@ -114,7 +114,7 @@ func (s *StoreEntry) CalendarTableDetail(ctx context.Context, req *pasturePb.Cal
 	newCalendar := &model.Calendar{}
 	if err = s.DB.Model(&model.Calendar{}).
 		Where("calendar_type = ?", req.CalendarType).
-		Where("show_day = ?", req.Start).
+		Where("start_day = ?", req.Start).
 		Where("is_show = ?", pasturePb.IsShow_Ok).
 		Where("pasture_id = ?", userModel.AppPasture.Id).
 		First(newCalendar).Error; err != nil {
@@ -504,10 +504,6 @@ func (s *StoreEntry) CalvingCowList(ctx context.Context, req *pasturePb.ItemsReq
 		pref.Where("a.plan_day <= ?", dateTime)
 	}
 
-	if req.Status > 0 {
-		pref.Where("a.status = ?", req.Status)
-	}
-
 	if req.PenId > 0 {
 		pref.Where("b.pen_id = ?", req.PenId)
 	}
@@ -554,7 +550,56 @@ func (s *StoreEntry) CalvingCowList(ctx context.Context, req *pasturePb.ItemsReq
 			List: calvingItems,
 		},
 	}, nil
+}
+
+// TreatmentCowList 治疗清单
+func (s *StoreEntry) TreatmentCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (interface{}, error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
 
+	diseaseItems := make([]*model.EventCowDisease, 0)
+	count := int64(0)
+
+	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.EventCowDisease).TableName())).
+		Joins(fmt.Sprintf("JOIN %s AS b on a.cow_id = b.id", new(model.Cow).TableName())).
+		Where("a.pasture_id = ?", userModel.AppPasture.Id).
+		Where("a.health_status IN (?)", []pasturePb.HealthStatus_Kind{pasturePb.HealthStatus_Disease, pasturePb.HealthStatus_Treatment})
+
+	if req.PenId > 0 {
+		pref.Where("b.pen_id = ?", req.PenId)
+	}
+
+	if err = pref.Order("a.disease_at DESC").
+		Count(&count).
+		Limit(int(pagination.PageSize)).
+		Offset(int(pagination.PageOffset)).
+		Find(&diseaseItems).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return &pasturePb.EventCowDiseaseResponse{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &pasturePb.EventCowDiseaseData{
+			List:     model.EventCowDiseaseSlice(diseaseItems).ToPB(s.HealthStatusMap()),
+			Total:    int32(count),
+			PageSize: pagination.PageSize,
+			Page:     pagination.Page,
+			Header: map[string]string{
+				"id":                   "编号",
+				"cowId":                "牛号",
+				"earNumber":            "耳标",
+				"diagnoseName":         "疾病名称",
+				"healthStatus":         "健康状态",
+				"lastPrescriptionName": "处方名称",
+				"treatmentDays":        "治疗天数",
+				"onsetDays":            "发病天数",
+				"penName":              "栏舍名称",
+			},
+		},
+	}, nil
 }
 
 // WorkOrderCowList 暂时不处理工单业务
@@ -562,14 +607,10 @@ func (s *StoreEntry) WorkOrderCowList(ctx context.Context, req *pasturePb.ItemsR
 	return nil, nil
 }
 
-// TreatmentCowList 治疗清单
-func (s *StoreEntry) TreatmentCowList(ctx context.Context, req *pasturePb.ItemsRequest, pagination *pasturePb.PaginationModel) (interface{}, error) {
-	return nil, nil
-}
-
 // Paginate 函数用于对切片进行分页
-func Paginate(slice []*pasturePb.CalendarToDoList, req *pasturePb.CalendarToDoRequest, pagination *pasturePb.PaginationModel) []*pasturePb.CalendarToDoList {
+func Paginate(slice []*pasturePb.CalendarToDoList, req *pasturePb.CalendarToDoRequest, pagination *pasturePb.PaginationModel) ([]*pasturePb.CalendarToDoList, int32) {
 	newSlice := make([]*pasturePb.CalendarToDoList, 0)
+
 	if req.CalendarType > 0 {
 		calendarTypeName := CalendarTypeMap()[req.CalendarType]
 		if len(calendarTypeName) > 0 {
@@ -596,12 +637,13 @@ func Paginate(slice []*pasturePb.CalendarToDoList, req *pasturePb.CalendarToDoRe
 		}
 		newSlice = filteredSlice
 	}
+	total := int32(len(newSlice))
 	// 计算起始索引
 	start := (pagination.Page - 1) * pagination.PageSize
 
 	// 如果起始索引超出切片长度,返回空切片
 	if start >= int32(len(newSlice)) {
-		return []*pasturePb.CalendarToDoList{}
+		return []*pasturePb.CalendarToDoList{}, total
 	}
 
 	// 计算结束索引
@@ -613,7 +655,7 @@ func Paginate(slice []*pasturePb.CalendarToDoList, req *pasturePb.CalendarToDoRe
 	}
 
 	// 返回分页后的切片
-	return newSlice[start:end]
+	return newSlice[start:end], total
 }
 
 func ProgressList(dataList []*pasturePb.CalendarToDoList, toDayCompletedCountMap map[string]int32) map[string]*pasturePb.ProgressList {

+ 2 - 0
module/backend/cow.go

@@ -214,6 +214,8 @@ func (s *StoreEntry) BehaviorCurve(ctx context.Context, req *pasturePb.CowBehavi
 
 	data := model.NeckActiveHabitSlice(neckActiveHabitList).ToPB(req.CurveName)
 	data.EventMap = s.EventTypeMap()
+	data.LowActivity = 62
+	data.MiddleActivity = 80
 	// 牛只事件列表
 	eventLogList := make([]*model.EventCowLog, 0)
 	eventLog := &model.EventCowLog{CowId: cowInfo.Id}

+ 13 - 5
module/backend/event_base.go

@@ -7,6 +7,7 @@ import (
 	"net/http"
 	"strconv"
 	"strings"
+	"time"
 
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	"gitee.com/xuyiping_admin/pkg/xerr"
@@ -149,15 +150,22 @@ func (s *StoreEntry) GroupTransferList(ctx context.Context, req *pasturePb.Searc
 		Joins(fmt.Sprintf("JOIN %s AS f ON a.cow_id = f.id", new(model.Cow).TableName())).
 		Where("a.pasture_id = ?", userModel.AppPasture.Id)
 
-	if len(req.CowId) > 0 {
-		cowIds := strings.Split(req.CowId, ",")
-		pref.Where("a.cow_id IN ?", cowIds)
-	}
-
 	if req.EarNumber != "" {
 		pref.Where("a.ear_number = ?", req.EarNumber)
 	}
 
+	if req.TransferReasonId > 0 {
+		pref.Where("a.transfer_reason_id = ?", req.TransferReasonId)
+	}
+
+	if req.TransferInPenId > 0 {
+		pref.Where("a.pen_in_id = ?", req.TransferInPenId)
+	}
+
+	if req.StartDayAt > 0 && req.EndDayAt > 0 && req.EndDayAt >= req.StartDayAt {
+		pref.Where("a.transfer_date BETWEEN ? AND ?", time.Unix(int64(req.StartDayAt), 0).Format(model.LayoutDate2), time.Unix(int64(req.EndDayAt), 0).Format(model.LayoutDate2))
+	}
+
 	if err = pref.Order("a.id desc").Group("a.id").
 		Count(&count).Limit(int(pagination.PageSize)).
 		Offset(int(pagination.PageOffset)).

+ 2 - 0
module/backend/event_health.go

@@ -83,6 +83,8 @@ func (s *StoreEntry) CowDiseaseCreate(ctx context.Context, req *pasturePb.EventC
 		newEventCowDisease.DiagnosedResult = pasturePb.IsShow_Ok
 		newEventCowDisease.FirstTreatmentAt = int64(req.DiseaseAt)
 		newEventCowDisease.LastTreatmentAt = int64(req.DiseaseAt)
+		newEventCowDisease.DiagnoseId = int32(disease.Id)
+		newEventCowDisease.DiagnoseName = disease.Name
 	}
 
 	newEventCowTreatment := &model.EventCowTreatment{}

+ 4 - 7
module/backend/goods.go

@@ -4,7 +4,6 @@ import (
 	"context"
 	"fmt"
 	"kpt-pasture/model"
-	"kpt-pasture/util"
 	"net/http"
 	"time"
 
@@ -385,18 +384,16 @@ func (s *StoreEntry) OutboundList(ctx context.Context, req *pasturePb.SearchOutb
 		return nil, xerr.WithStack(err)
 	}
 
-	startUnix := util.TimeParseLocalUnix(req.StartDayTime)
-	endUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
-
 	var count int64 = 0
 	outboundList := make([]*model.Outbound, 0)
-	pref := s.DB.Model(new(model.Outbound)).Where("pasture_id = ?", userModel.AppPasture.Id)
+	pref := s.DB.Model(new(model.Outbound)).
+		Where("pasture_id = ?", userModel.AppPasture.Id)
 	if req.OutType > 0 {
 		pref.Where("out_type = ?", req.OutType)
 	}
 
-	if startUnix > 0 && endUnix > 0 && startUnix <= endUnix {
-		pref.Where("applicant_at BETWEEN ? AND ?", startUnix, endUnix)
+	if req.StartDayTime > 0 && req.EndDayTime > 0 && req.EndDayTime >= req.StartDayTime {
+		pref.Where("applicant_at BETWEEN ? AND ?", req.StartDayTime, req.EndDayTime)
 	}
 
 	if req.Number != "" {

+ 5 - 5
module/crontab/interface.go

@@ -35,9 +35,9 @@ type Crontab interface {
 	DeleteOldOriginal() error
 	UpdateDiseaseToCalendar() error
 
-	// UpdateCowEstrus 脖环数据
-	UpdateCowEstrus() error           // 获取牛只疑似发情数据
-	NeckRingOriginalMergeData() error // 合并脖环数据
-	NeckRingCalculate() error         // 更新脖环数据
-	UpdateNeckRingWarning() error     // 发情和健康预警
+	// NeckRingOriginalMerge 脖环数据
+	NeckRingOriginalMerge() error // 合并脖环数据
+	NeckRingCalculate() error     // 更新脖环数据
+	UpdateCowEstrus() error       // 获取牛只疑似发情数据
+	UpdateNeckRingWarning() error // 发情和健康预警
 }

+ 44 - 25
module/crontab/neck_ring_merge.go

@@ -28,8 +28,8 @@ var (
 	calculateIsRunning bool
 )
 
-// NeckRingOriginalMergeData 把脖环数据合并成2个小时的
-func (e *Entry) NeckRingOriginalMergeData() (err error) {
+// NeckRingOriginalMerge 把脖环数据合并成2个小时的
+func (e *Entry) NeckRingOriginalMerge() (err error) {
 	if ok := e.IsExistCrontabLog(NeckRingOriginal); !ok {
 		newTime := time.Now()
 		e.CreateCrontabLog(NeckRingOriginal)
@@ -43,14 +43,27 @@ func (e *Entry) NeckRingOriginalMergeData() (err error) {
 			Delete(new(model.NeckActiveHabit))
 	}
 
+	pastureList := e.FindPastureList()
+	if pastureList == nil || len(pastureList) == 0 {
+		return nil
+	}
+
+	for _, pasture := range pastureList {
+		if err = e.OriginalMergeData(pasture.Id); err != nil {
+			zaplog.Error("NeckRingOriginalMerge", zap.Any("OriginalMergeData", err), zap.Any("pasture", pasture))
+		}
+	}
+	return nil
+}
+
+func (e *Entry) OriginalMergeData(pastureId int64) error {
 	limit := e.Cfg.NeckRingLimit
 	if limit <= 0 {
 		limit = defaultLimit
 	}
 
-	//createdAt := newTime.Add(-1 * time.Hour)
-	neckRingNumber := []string{
-		/*"10026", "10027", "10028", "10029", "10030",
+	/*neckRingNumber := []string{
+		"10026", "10027", "10028", "10029", "10030",
 		"10031", "10032", "10033", "10034", "10035",
 		"10036", "10037", "10038", "10039", "10040",
 		"10041", "10042", "10043", "10044", "10046",
@@ -59,7 +72,7 @@ func (e *Entry) NeckRingOriginalMergeData() (err error) {
 		"9120007", "9120029", "9120040", "9120123", "9120164", "9120184", "9120219", "9120246", "9120321", "9120355",
 		"9120359", "9120375", "9120379", "9120391", "9120446", "9120493", "9120497", "9120512", "9120531", "9120533",
 		"9120540", "9120542", "9120612", "9120614", "9120615", "9120623", "9120625", "9120630", "9120653", "9120662",
-		"211670", "9121372", "3204736", "3212694", "3204532", "3214082", "9121667", "3212275", "3210345", "3217879",*/
+		"211670", "9121372", "3204736", "3212694", "3204532", "3214082", "9121667", "3212275", "3210345", "3217879",
 		"9422", "3206975", "9496", "3204907", "212194", "3211061", "9120840", "3207787", "3210201", "404", "3207104",
 		"3219173", "3216771", "3216872", "3209614", "3205455", "416", "9121026", "211622", "3207868", "3210340", "9120132",
 		"3207092", "3209390", "3205872", "3207367", "3219700", "9120022", "211246", "466", "3207565", "3208779", "3204863",
@@ -112,14 +125,15 @@ func (e *Entry) NeckRingOriginalMergeData() (err error) {
 		"3215061", "3209099", "3218820", "3212817", "3204659", "3210976", "3213266", "3211716", "3207860", "3213350", "9517",
 		"3215001", "3217667", "3213039", "3207248", "9510", "3215056", "3218732", "3216053", "3209995", "3215773", "3211035",
 		"3213295", "3205725", "9464", "3205636",
-	}
+	}*/
 	neckRingList := make([]*model.NeckRingOriginal, 0)
-	if err = e.DB.Model(new(model.NeckRingOriginal)).
+	if err := e.DB.Model(new(model.NeckRingOriginal)).
 		Where("is_show = ?", pasturePb.IsShow_No).
-		Where("neck_ring_number IN (?)", neckRingNumber).
-		Where("active_date = ?", time.Now().Format(model.LayoutDate2)).
+		//Where("neck_ring_number IN (?)", neckRingNumber).
+		Where("pasture_id = ?", pastureId).
+		//Where("active_date = ?", time.Now().Format(model.LayoutDate2)).
 		//Where("created_at <= ?", createdAt.Unix()).
-		Order("active_date,frameid,neck_ring_number").
+		Order("active_date,neck_ring_number,frameid").
 		Limit(int(limit)).Find(&neckRingList).Error; err != nil {
 		return xerr.WithStack(err)
 	}
@@ -128,16 +142,16 @@ func (e *Entry) NeckRingOriginalMergeData() (err error) {
 	}
 
 	// 计算合并
-	neckActiveHabitList := e.recalculate(neckRingList)
+	neckActiveHabitList := Recalculate(neckRingList)
 	if len(neckActiveHabitList) <= 0 {
 		return nil
 	}
 
 	for _, habit := range neckActiveHabitList {
 		//更新脖环牛只相关信息 新数据直接插入
-		historyNeckActiveHabit, ct := e.IsExistNeckActiveHabit(habit.NeckRingNumber, habit.HeatDate, habit.Frameid)
+		historyNeckActiveHabit, ct := e.IsExistNeckActiveHabit(pastureId, habit.NeckRingNumber, habit.HeatDate, habit.Frameid)
 		if ct <= 0 {
-			if err = e.DB.Create(habit).Error; err != nil {
+			if err := e.DB.Create(habit).Error; err != nil {
 				zaplog.Info("NeckRingOriginalMergeData-1",
 					zap.Any("err", err),
 					zap.Any("neckActiveHabit", habit),
@@ -149,11 +163,11 @@ func (e *Entry) NeckRingOriginalMergeData() (err error) {
 			if newNeckActiveHabit == nil {
 				continue
 			}
-			if err = e.DB.Model(new(model.NeckActiveHabit)).
+			if err := e.DB.Model(new(model.NeckActiveHabit)).
 				Select("rumina", "intake", "inactive", "gasp", "other", "high", "active", "is_show", "record_count").
 				Where("id = ?", historyNeckActiveHabit.Id).
 				Updates(newNeckActiveHabit).Error; err != nil {
-				zaplog.Error("NeckRingOriginalMergeData-3",
+				zaplog.Error("NeckRingOriginalMergeData-2",
 					zap.Any("err", err),
 					zap.Any("ct", ct),
 					zap.Any("historyNeckActiveHabit", historyNeckActiveHabit),
@@ -162,8 +176,8 @@ func (e *Entry) NeckRingOriginalMergeData() (err error) {
 			}
 		}
 
-		if err = e.UpdateNeckRingOriginalIsShow(habit); err != nil {
-			zaplog.Error("NeckRingOriginalMergeData-2",
+		if err := e.UpdateNeckRingOriginalIsShow(habit); err != nil {
+			zaplog.Error("NeckRingOriginalMergeData-4",
 				zap.Any("err", err),
 				zap.Any("neckActiveHabit", habit),
 			)
@@ -314,11 +328,14 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds [
 		Where("id BETWEEN ? AND ?", xToDay.LastMaxHabitId, xToDay.CurrMaxHabitId).
 		Where("pasture_id = ?", pastureId).
 		Where("is_show = ?", pasturePb.IsShow_No).
+		Where("record_count = ?", model.DefaultRecordCount).
 		Where(e.DB.Where("high >= ?", xToDay.High).Or("rumina >= ?", xToDay.Rumina)).
 		Order("heat_date,neck_ring_number,frameid").
-		Limit(int(defaultLimit)).Find(&newNeckActiveHabitList).Error; err != nil {
+		Limit(int(defaultLimit)).
+		Find(&newNeckActiveHabitList).Error; err != nil {
 		return nil, xerr.WithStack(err)
 	}
+
 	// 活动量滤波
 	for _, v := range newNeckActiveHabitList {
 		// 过滤牛只未绑定的脖环的数据
@@ -333,6 +350,8 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds [
 			frameId = 11
 			heatDateParse, _ := time.Parse(model.LayoutDate2, heatDate)
 			heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2)
+		} else {
+			frameId -= 1
 		}
 
 		firstFilterData := e.FindFirstFilter(pastureId, v.NeckRingNumber, heatDate, frameId)
@@ -366,7 +385,6 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds [
 		}
 
 		processIds = append(processIds, v.Id)
-
 		// 更新过滤值 // todo 记得更新胎次为牛只胎次,现在为了测试特意改成0
 		if err = e.DB.Model(new(model.NeckActiveHabit)).
 			Select("filter_high", "filter_rumina", "filter_chew", "cow_id", "lact", "calving_age", "ear_number").
@@ -703,8 +721,8 @@ func (e *Entry) UpdateNeckRingOriginalIsShow(habit *model.NeckActiveHabit) error
 	return nil
 }
 
-// recalculate 合并计算
-func (e *Entry) recalculate(neckRingList []*model.NeckRingOriginal) []*model.NeckActiveHabit {
+// Recalculate 合并计算
+func Recalculate(neckRingList []*model.NeckRingOriginal) []*model.NeckActiveHabit {
 	originalMapData := make(map[string]*model.NeckRingOriginalMerge)
 	// 合并成2个小时的
 	for _, v := range neckRingList {
@@ -721,10 +739,10 @@ func (e *Entry) recalculate(neckRingList []*model.NeckRingOriginal) []*model.Nec
 	// 算平均值
 	for k, v := range originalMapData {
 		// 过滤掉合并后不等于6条数据
-		if v.RecordCount > 6 {
+		if v.RecordCount > model.DefaultRecordCount {
 			delete(originalMapData, k)
 			continue
-		} else if v.RecordCount < 6 {
+		} else if v.RecordCount < model.DefaultRecordCount {
 			currMaxXframeId := util.FrameIdMapReverse[int32(currTime.Hour())]
 			activeDateString := fmt.Sprintf("%s %02d:00:00", v.ActiveDate, v.XframeId*2+1)
 			activeDate, _ := time.Parse(model.LayoutTime, activeDateString)
@@ -756,7 +774,8 @@ func (e *Entry) againRecalculate(data *model.NeckActiveHabit) *model.NeckActiveH
 		return nil
 	}
 
-	newDataList := e.recalculate(originalList)
+	newDataList := Recalculate(originalList)
+	zaplog.Info("againRecalculate", zap.Any("data", data), zap.Any("newDataList", newDataList))
 	if len(newDataList) != 1 {
 		return nil
 	}

+ 15 - 1
module/crontab/sql.go

@@ -104,10 +104,11 @@ func (e *Entry) IsExistEventEstrus(pastureId, cowId int64) *model.EventEstrus {
 	return res
 }
 
-func (e *Entry) IsExistNeckActiveHabit(neckRingNumber, heatDate string, frameId int32) (*model.NeckActiveHabit, int64) {
+func (e *Entry) IsExistNeckActiveHabit(pastureId int64, neckRingNumber, heatDate string, frameId int32) (*model.NeckActiveHabit, int64) {
 	count := int64(0)
 	neckActiveHabit := &model.NeckActiveHabit{}
 	if err := e.DB.Model(new(model.NeckActiveHabit)).
+		Where("pasture_id = ?", pastureId).
 		Where("neck_ring_number = ?", neckRingNumber).
 		Where("heat_date = ?", heatDate).
 		Where("frameid = ?", frameId).
@@ -117,6 +118,19 @@ func (e *Entry) IsExistNeckActiveHabit(neckRingNumber, heatDate string, frameId
 	return neckActiveHabit, count
 }
 
+func (e *Entry) FindAppPastureReceiver() map[string]int64 {
+	appPastureReceiverList := make([]*model.AppPastureReceiver, 0)
+	if err := e.DB.Model(new(model.AppPastureReceiver)).
+		Find(&appPastureReceiverList).Error; err != nil {
+		zaplog.Error("FindAppPastureReceiver", zap.Any("err", err))
+	}
+	receiverMap := make(map[string]int64)
+	for _, v := range appPastureReceiverList {
+		receiverMap[v.ReceiverNumber] = v.PastureId
+	}
+	return receiverMap
+}
+
 func (e *Entry) GetSystemNeckRingConfigure(pastureId int64) ([]*model.NeckRingConfigure, error) {
 	res := make([]*model.NeckRingConfigure, 0)
 	if err := e.DB.Model(new(model.NeckRingConfigure)).

+ 26 - 5
module/mqtt/mqtt_handle.go

@@ -27,10 +27,15 @@ var (
 		NeckRingErrorData:    make([]*model.NeckRingError, 0),
 	}
 	mu sync.Mutex
+
+	ReceiverMap map[string]int64 // 接收器数据
 )
 
 func (e *Entry) NeckRingHandle(data []byte) {
-	newData := e.MsgDataFormat2(data)
+	if len(ReceiverMap) <= 0 {
+		ReceiverMap = e.FindAppPastureReceiver()
+	}
+	newData := e.MsgDataFormat2(data, ReceiverMap)
 	if newData == nil {
 		return
 	}
@@ -42,6 +47,19 @@ func (e *Entry) NeckRingHandle(data []byte) {
 	}
 }
 
+func (e *Entry) FindAppPastureReceiver() map[string]int64 {
+	appPastureReceiverList := make([]*model.AppPastureReceiver, 0)
+	if err := e.DB.Model(new(model.AppPastureReceiver)).
+		Find(&appPastureReceiverList).Error; err != nil {
+		zaplog.Error("FindAppPastureReceiver", zap.Any("err", err))
+	}
+	receiverMap := make(map[string]int64)
+	for _, v := range appPastureReceiverList {
+		receiverMap[v.ReceiverNumber] = v.PastureId
+	}
+	return receiverMap
+}
+
 // 处理批量数据
 func (e *Entry) processBatch(batchList []*model.NeckRingOriginal) {
 	// 初始化分类数据
@@ -96,7 +114,6 @@ func (e *Entry) CreatedData(DSMLog *DataInsertNeckRingLog, originalData []byte)
 				return xerr.WithStack(err)
 			}
 		}
-		zaplog.Info("CreatedData", zap.Any("DSMLog", DSMLog), zap.Any("originalData", string(originalData)))
 		return nil
 	}); err != nil {
 		return xerr.WithStack(err)
@@ -104,7 +121,7 @@ func (e *Entry) CreatedData(DSMLog *DataInsertNeckRingLog, originalData []byte)
 	return nil
 }
 
-func (e *Entry) MsgDataFormat2(msg []byte) *DataInsertNeckRingLog {
+func (e *Entry) MsgDataFormat2(msg []byte, receiverMap map[string]int64) *DataInsertNeckRingLog {
 	mu.Lock()
 	defer mu.Unlock()
 	neckLogList := &model.NeckRingWrapper{}
@@ -120,8 +137,12 @@ func (e *Entry) MsgDataFormat2(msg []byte) *DataInsertNeckRingLog {
 	errorOriginal := make([]*model.NeckRingError, 0)
 
 	for _, neckLog := range neckLogList.NeckRing.NeckPck {
-		newOriginal := model.NewNeckRingOriginal(neckLog)
-		if ok := util.IsValidFrameId(neckLog.Frameid); !ok {
+		pastureId, ok := receiverMap[neckLog.Imei]
+		if !ok {
+			continue
+		}
+		newOriginal := model.NewNeckRingOriginal(neckLog, pastureId)
+		if ok = util.IsValidFrameId(neckLog.Frameid); !ok {
 			var ed model.NeckRingError
 			if err := copier.Copy(&ed, &newOriginal); err != nil {
 				zaplog.Error("MsgDataFormat2", zap.Any("copier", err), zap.Any("neckLog", neckLog))