瀏覽代碼

crontab: update

Yi 2 周之前
父節點
當前提交
a88bbf8328

+ 3 - 1
model/cow.go

@@ -34,6 +34,7 @@ type Cow struct {
 	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"`             // 出生时间
@@ -61,7 +62,7 @@ func (c *Cow) TableName() string {
 	return "cow"
 }
 
-func (c *Cow) EventInfoUpdate() {
+func (c *Cow) EventUpdate(weeklyActive int32) {
 	c.DayAge = c.GetDayAge()
 	c.CalvingAge = c.GetCalvingAge()
 	c.PregnancyAge = c.GetDaysPregnant()
@@ -70,6 +71,7 @@ func (c *Cow) EventInfoUpdate() {
 	if c.DayAge == 60 {
 		c.CowType = pasturePb.CowType_Weaned_Calf
 	}
+	c.WeeklyActive = weeklyActive
 }
 
 // EventCalvingUpdate 产犊更新

+ 1 - 1
model/event_cow_log.go

@@ -19,7 +19,7 @@ type EventCowLog struct {
 	PenName           string                       `json:"penName"`
 	CowType           pasturePb.CowType_Kind       `json:"cowType"`
 	CowTypeName       string                       `json:"cowTypeName"`
-	EventCategoryKind pasturePb.EventCategory_Kind `json:"eventCategoryId"`
+	EventCategoryKind pasturePb.EventCategory_Kind `json:"eventCategoryKind"`
 	EventType         pasturePb.EventType_Kind     `json:"eventType"`
 	EventTypeName     string                       `json:"eventTypeName"`
 	EventDescription  string                       `json:"eventDescription"`

+ 12 - 1
model/neck_active_habit.go

@@ -185,8 +185,12 @@ func (n NeckActiveHabitSlice) ToPB(curveName string) *CowBehaviorCurveData {
 		res.DateTimeList = append(res.DateTimeList, hourStr)
 		switch curveName {
 		case "active": // 活动量
+			changeDateList := v.ChangeFilter * v.FilterCorrect / 100
+			if changeDateList == DefaultChangeFilter {
+				changeDateList = 0
+			}
 			res.OriginalDateList = append(res.OriginalDateList, v.High)
-			res.ChangeDateList = append(res.ChangeDateList, v.ChangeFilter*v.FilterCorrect/100)
+			res.ChangeDateList = append(res.ChangeDateList, changeDateList)
 			res.RuminaChange = append(res.RuminaChange, v.FilterRumina)
 		case "rumina": // 反刍
 			res.OriginalDateList = append(res.OriginalDateList, v.Rumina)
@@ -213,3 +217,10 @@ func (n NeckActiveHabitSlice) ToPB(curveName string) *CowBehaviorCurveData {
 type MaxHabitIdModel struct {
 	Id int64 `json:"id"`
 }
+
+type WeeklyActiveModel struct {
+	CowId    int64  `json:"cow_id"`
+	HeatDate string `json:"heat_date"`
+	Nb       int32  `json:"nb"`
+	High     int32  `json:"high"`
+}

+ 1 - 0
model/neck_ring_configure.go

@@ -13,6 +13,7 @@ const (
 	ActiveHigh      = "active_high"
 	MaxHabit        = "max_habit"
 	HealthWarning   = "health_warning"
+	MinWeeklyActive = "min_weekly_active"
 )
 
 type NeckRingConfigure struct {

+ 4 - 3
model/neck_ring_estrus.go

@@ -18,6 +18,7 @@ type NeckRingEstrus struct {
 	IsPeak         pasturePb.IsShow_Kind      `json:"isPeak"`
 	DayHigh        int32                      `json:"dayHigh"`
 	MaxHigh        int32                      `json:"maxHigh"`
+	MaxCft         int32                      `json:"maxCft"`
 	CheckResult    pasturePb.CheckResult_Kind `json:"checkResult"`
 	CheckAt        int64                      `json:"checkAt"`
 	IsShow         pasturePb.IsShow_Kind      `json:"isShow"`
@@ -29,9 +30,8 @@ func (n *NeckRingEstrus) TableName() string {
 	return "neck_ring_estrus"
 }
 
-func NewNeckRingEstrus(pastureId int64, cow *Cow, level pasturePb.EstrusLevel_Kind,
-	checkResult pasturePb.CheckResult_Kind, isShow pasturePb.IsShow_Kind,
-) *NeckRingEstrus {
+func NewNeckRingEstrus(pastureId int64, cow *Cow, level pasturePb.EstrusLevel_Kind, maxCft int32,
+	checkResult pasturePb.CheckResult_Kind, isShow pasturePb.IsShow_Kind) *NeckRingEstrus {
 	return &NeckRingEstrus{
 		PastureId:      pastureId,
 		CowId:          cow.Id,
@@ -41,6 +41,7 @@ func NewNeckRingEstrus(pastureId int64, cow *Cow, level pasturePb.EstrusLevel_Ki
 		ActiveLevel:    level,
 		IsShow:         isShow,
 		CheckResult:    checkResult,
+		MaxCft:         maxCft,
 	}
 }
 

+ 18 - 17
model/system_basic.go

@@ -9,6 +9,7 @@ const (
 	PregnantCheckForSecond           = "pregnant_check_for_second"            // 复检
 	PregnancyAge                     = "pregnancy_age"                        // 怀孕天数
 	WeaningAge                       = "weaning_age"                          // 断奶天数
+	EstrusWaringDays                 = "estrus_waring_days"                   // 发情预警产后天数
 
 	ValueTypeFixed = 1 // 固定值
 	ValueTypeRange = 2 // 范围值
@@ -28,28 +29,28 @@ var PregnantCheckNameValueMap = map[int32]string{
 }
 
 type SystemBasic struct {
-	Id            int32                    `json:"id"`
-	PastureId     int64                    `json:"pastureId"`
-	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"`
+	Id            int32                            `json:"id"`
+	PastureId     int64                            `json:"pastureId"`
+	Name          string                           `json:"name"`
+	CategoryName  string                           `json:"categoryName"`
+	CategoryId    pasturePb.BasicDataCategory_Kind `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(pastureId int64, minValue, maxValue int32, weekValue pasturePb.Week_Kind, currentUser *SystemUser) {
+func (s *SystemBasic) EditUpdate(minValue, maxValue int32, weekValue pasturePb.Week_Kind, currentUser *SystemUser) {
 	s.MinValue = minValue
 	s.MaxValue = maxValue
 	if s.WeekValue > -1 {
@@ -68,7 +69,7 @@ func (s SystemBasicSlice) ToPb() []*pasturePb.BaseDataConfig {
 			Id:           v.Id,
 			Name:         v.Name,
 			CategoryName: v.CategoryName,
-			CategoryId:   pasturePb.BasicDataCategory_Kind(v.CategoryId),
+			CategoryId:   v.CategoryId,
 			MinValue:     v.MinValue,
 			MaxValue:     v.MaxValue,
 			WeekValue:    v.WeekValue,

+ 17 - 0
module/backend/event_health.go

@@ -194,11 +194,28 @@ func (s *StoreEntry) EstrusCowList(ctx context.Context, req *pasturePb.EstrusIte
 		return nil, xerr.WithStack(err)
 	}
 
+	systemBasic, err := s.FindSystemBasic(ctx, userModel.AppPasture.Id, model.EstrusWaringDays)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	nowTime := time.Now()
+	startTime := time.Unix(util.TimeParseLocalUnix(nowTime.Format(model.LayoutDate2)), 0).Format(model.LayoutTime)
+	entTime := time.Unix(util.TimeParseLocalEndUnix(nowTime.AddDate(0, 0, 1).Format(model.LayoutDate2)), 0).Format(model.LayoutTime)
 	var count int64
 	neckRingEstrusList := make([]*model.NeckRingEstrusWarning, 0)
 	pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.NeckRingEstrusWarning).TableName())).
 		Joins(fmt.Sprintf("JOIN %s AS b on a.cow_id = b.id", new(model.Cow).TableName())).
+		Where("b.last_mating_at < UNIX_TIMESTAMP(a.date_time)").
+		Where("b.admission_status = ?", pasturePb.AdmissionStatus_Admission).
+		Where("b.is_not_mating = ?", pasturePb.IsShow_No).
+		Where("a.level >= ?", pasturePb.EstrusLevel_Low).
 		Where("a.pasture_id = ?", userModel.AppPasture.Id).
+		Where("a.date_time BETWEEN ? AND ?", startTime, entTime).
+		Where(s.DB.Where("b.last_mating_at < UNIX_TIMESTAMP(a.first_time)").
+			Or(s.DB.Where("b.last_mating_at = ?", 0).
+				Where("b.calving_age > ?", systemBasic.MinValue).
+				Or("b.lact = ?", 0))).
 		Where("a.is_show = ?", pasturePb.IsShow_Ok)
 
 	if len(req.EarNumber) > 0 {

+ 0 - 52
module/backend/prescription.go

@@ -9,9 +9,6 @@ import (
 	"strconv"
 	"strings"
 
-	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
-	"go.uber.org/zap"
-
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	"gitee.com/xuyiping_admin/pkg/xerr"
 	"gorm.io/gorm"
@@ -536,52 +533,3 @@ func (s *StoreEntry) ImmunizationIsShow(ctx context.Context, id int64) error {
 	}
 	return nil
 }
-
-func (s *StoreEntry) SystemBasicList(ctx context.Context) (*pasturePb.SearchBaseDataConfigResponse, error) {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return nil, xerr.WithStack(err)
-	}
-
-	systemBasicList := make([]*model.SystemBasic, 0)
-	if err = s.DB.Model(new(model.SystemBasic)).
-		Where("pasture_id = ?", userModel.AppPasture.Id).
-		Where("is_show = ?", pasturePb.IsShow_Ok).Find(&systemBasicList).Error; err != nil {
-		return nil, xerr.WithStack(err)
-	}
-	return &pasturePb.SearchBaseDataConfigResponse{
-		Code: http.StatusOK,
-		Msg:  "ok",
-		Data: &pasturePb.SearchBaseDataConfigData{
-			List:  model.SystemBasicSlice(systemBasicList).ToPb(),
-			Total: int32(len(systemBasicList)),
-		},
-	}, nil
-}
-
-func (s *StoreEntry) SystemBasicEdit(ctx context.Context, req *pasturePb.BaseDataConfigBatch) error {
-	userModel, err := s.GetUserModel(ctx)
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-
-	for _, v := range req.Item {
-		systemBasic := &model.SystemBasic{Id: v.Id}
-		if err = s.DB.Model(systemBasic).
-			Where("is_show = ?", pasturePb.IsShow_Ok).
-			Where("pasture_id = ?", userModel.AppPasture.Id).
-			First(systemBasic).Error; err != nil {
-			zaplog.Error("SystemBasicEdit", zap.Any("err", err), zap.Any("req", req))
-			return xerr.Customf("该配置信息不存在: %d", v.Id)
-		}
-
-		systemBasic.EditUpdate(userModel.AppPasture.Id, v.MinValue, v.MaxValue, v.WeekValue, userModel.SystemUser)
-		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
-}

+ 3 - 2
module/backend/sql.go

@@ -500,10 +500,11 @@ func (s *StoreEntry) GetCowLastEvent(pastureId, cowId int64, eventCategoryId pas
 	pref := s.DB.Table(newEventCowLog.TableName()).
 		Where("cow_id = ?", cowId).Where("pasture_id = ?", pastureId)
 	if eventCategoryId > 0 {
-		pref.Where("event_category_id = ?", eventCategoryId)
+		pref.Where("event_category_kind = ?", eventCategoryId)
 	}
 
-	if err := pref.Order("id desc").First(newEventCowLog); err != nil {
+	if err := pref.Order("id desc").
+		First(newEventCowLog); err != nil {
 		return nil
 	}
 	return newEventCowLog

+ 82 - 0
module/backend/system_basic.go

@@ -0,0 +1,82 @@
+package backend
+
+import (
+	"context"
+	"kpt-pasture/model"
+	"net/http"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
+	"gitee.com/xuyiping_admin/pkg/xerr"
+	"go.uber.org/zap"
+)
+
+func (s *StoreEntry) SystemBasicList(ctx context.Context) (*pasturePb.SearchBaseDataConfigResponse, error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	systemBasicList := make([]*model.SystemBasic, 0)
+	if err = s.DB.Model(new(model.SystemBasic)).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Where("is_show = ?", pasturePb.IsShow_Ok).Find(&systemBasicList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	return &pasturePb.SearchBaseDataConfigResponse{
+		Code: http.StatusOK,
+		Msg:  "ok",
+		Data: &pasturePb.SearchBaseDataConfigData{
+			List:  model.SystemBasicSlice(systemBasicList).ToPb(),
+			Total: int32(len(systemBasicList)),
+		},
+	}, nil
+}
+
+func (s *StoreEntry) SystemBasicEdit(ctx context.Context, req *pasturePb.BaseDataConfigBatch) error {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	for _, v := range req.Item {
+		systemBasic := &model.SystemBasic{Id: v.Id}
+		if err = s.DB.Model(systemBasic).
+			Where("is_show = ?", pasturePb.IsShow_Ok).
+			Where("pasture_id = ?", userModel.AppPasture.Id).
+			First(systemBasic).Error; err != nil {
+			zaplog.Error("SystemBasicEdit", zap.Any("err", err), zap.Any("req", req))
+			return xerr.Customf("该配置信息不存在: %d", v.Id)
+		}
+
+		systemBasic.EditUpdate(v.MinValue, v.MaxValue, v.WeekValue, userModel.SystemUser)
+		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
+}
+
+func (s *StoreEntry) FindSystemBasic(ctx context.Context, pastureId int64, name string) (*pasturePb.BaseDataConfig, error) {
+	systemBasic := &model.SystemBasic{}
+	if err := s.DB.Model(new(model.SystemBasic)).
+		Where("pasture_id = ?", pastureId).
+		Where("name = ?", name).
+		Where("is_show = ?", pasturePb.IsShow_Ok).
+		Find(&systemBasic).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	return &pasturePb.BaseDataConfig{
+		Id:           systemBasic.Id,
+		Name:         systemBasic.Name,
+		CategoryId:   systemBasic.CategoryId,
+		CategoryName: systemBasic.CategoryName,
+		MinValue:     systemBasic.MinValue,
+		MaxValue:     systemBasic.MinValue,
+		ValueType:    systemBasic.ValueType,
+		WeekValue:    systemBasic.WeekValue,
+	}, nil
+}

+ 61 - 2
module/crontab/cow_cron.go

@@ -119,9 +119,10 @@ func (e *Entry) UpdateCowInfo() error {
 		e.CreateCrontabLog(UpdateCowInfo)
 	}()
 	for _, cow := range cowList {
-		cow.EventInfoUpdate()
+		weeklyActive := e.UpdateCowWeeklyHigh(cow)
+		cow.EventUpdate(weeklyActive)
 		if err := e.DB.Model(new(model.Cow)).
-			Select("day_age", "calving_age", "pregnancy_age", "admission_age", "abortion_age", "cow_type").
+			Select("day_age", "calving_age", "pregnancy_age", "admission_age", "abortion_age", "cow_type", "weekly_active").
 			Where("id = ?", cow.Id).
 			Updates(cow).Error; err != nil {
 			zaplog.Error("Crontab", zap.Any("UpdateCowDayAge", err))
@@ -451,3 +452,61 @@ func (e *Entry) InitEventData(cowList []*model.Cow, systemBasic *model.SystemBas
 	}
 	e.CreatedCalendar(systemBasic.PastureId, calendarType, startDay, endDay, int32(len(cowList)))
 }
+
+// UpdateCowWeeklyHigh 更新牛只周活动量
+func (e *Entry) UpdateCowWeeklyHigh(cow *model.Cow) int32 {
+	highData, err := e.GetSystemNeckRingConfigure(cow.PastureId, model.High)
+	if err != nil || highData == nil || highData.Value <= 0 {
+		return 0
+	}
+
+	minWeeklyActive, er := e.GetSystemNeckRingConfigure(cow.PastureId, model.MinWeeklyActive)
+	if er != nil || minWeeklyActive == nil || minWeeklyActive.Value <= 0 {
+		return 0
+	}
+
+	weeklyActiveModelList := make([]*model.WeeklyActiveModel, 0)
+	startTime := time.Now().AddDate(0, 0, -8).Format(model.LayoutDate2)
+	endTime := time.Now().AddDate(0, 0, -2).Format(model.LayoutDate2)
+	selectStr := fmt.Sprintf(`IF(ROUND(AVG( h.high))>%d, ROUND(AVG( h.high)), %d) AS high`, minWeeklyActive.Value, minWeeklyActive.Value)
+	if err = e.DB.Model(new(model.NeckActiveHabit)).
+		Select("cow_id,heat_date,count(1) AS nb").
+		Select(selectStr).
+		Where("cow_id = ?", cow.Id).
+		Where("heat_date BETWEEN ? AND ?", startTime, endTime).
+		Where("high > ?", highData.Value).
+		Having("nb > ?", 8).
+		Order("high").
+		Group("heat_date").
+		Find(&weeklyActiveModelList).Error; err != nil {
+		zaplog.Error("crontab", zap.Any("UpdateCowWeeklyHigh", err))
+		return 0
+	}
+
+	if len(weeklyActiveModelList) < 3 {
+		return 0
+	}
+
+	countHigh := len(weeklyActiveModelList)
+	sumHigh := int32(0)
+	minHigh := weeklyActiveModelList[0].High
+	maxHigh := int32(0)
+	for _, v := range weeklyActiveModelList {
+		sumHigh += v.High
+		if v.High > maxHigh {
+			maxHigh = v.High
+		}
+
+		if v.High < minHigh {
+			minHigh = v.High
+		}
+	}
+	diff := 3
+	x := int32(0)
+	if countHigh == 3 {
+		diff = 2
+		x = weeklyActiveModelList[1].High
+	}
+	avgHigh := float64(sumHigh-minHigh-maxHigh-x) / float64(countHigh-diff)
+	return int32(avgHigh)
+}

+ 7 - 5
module/crontab/estrus_warning.go

@@ -71,6 +71,8 @@ func (e *Entry) UpdateNeckRingWarning(pastureId int64) (err error) {
 	minId := e.getMinId(pastureId)
 	// 更新HighChange字段
 	// e.UpdateHighChange(pastureId,minId)
+
+	// 更新IsPeak字段
 	e.UpdateNeckRingWarningIsPeak(pastureId, minId)
 
 	return nil
@@ -85,7 +87,8 @@ func (e *Entry) UpdateNeckRingWarningIsPeak(pastureId, minId int64) {
 
 	if err := e.DB.Table(fmt.Sprintf("%s as b", new(model.NeckRingEstrusWarning).TableName())).
 		Where("b.pasture_id = ?", pastureId).
-		Where("EXISTS (?)", sqlQuery).Update("is_peak", pasturePb.IsShow_Ok).Error; err != nil {
+		Where("EXISTS (?)", sqlQuery).
+		Update("is_peak", pasturePb.IsShow_Ok).Error; err != nil {
 		zaplog.Error("UpdateNeckRingWarningIsPeak", zap.Any("err", err))
 	}
 }
@@ -152,10 +155,9 @@ func (e *Entry) GroupAndProcessData(records []*model.NeckRingEstrus) []*model.Ne
 		}
 
 		// 检查是否在移牛列表中
-		// 假设通过CowID判断,需要根据实际关联关系调整
-		/*if _, moved := movedCows[record.CowId]; moved {
+		if moved := e.getRecentMovedCows(record.PastureId, record.CowId); moved {
 			groups[key].Moved = true
-		}*/
+		}
 		groups[key].Records = append(groups[key].Records, record)
 	}
 
@@ -213,7 +215,7 @@ func (e *Entry) getRecentMovedCows(pastureId, cowId int64) bool {
 	table := &model.EventCowLog{CowId: cowId}
 	if err := e.DB.Table(table.TableName()).
 		Where("cow_id = ?", cowId).
-		Where("pasture = ?", pastureId).
+		Where("pasture_id = ?", pastureId).
 		Where("event_type = ?", pasturePb.EventType_Transfer_Ben).
 		Where("event_at >= ?", startDate.Unix()).
 		Count(&count).Error; err != nil {

+ 1 - 1
module/crontab/health_warning.go

@@ -71,7 +71,7 @@ func (e *Entry) NeckRingHealthWarning() error {
 }
 
 func (e *Entry) UpdateNeckRingHealth(pastureId int64) error {
-	neckRingConfigureList, err := e.GetSystemNeckRingConfigure(pastureId)
+	neckRingConfigureList, err := e.FindSystemNeckRingConfigure(pastureId)
 	if err != nil {
 		return xerr.WithStack(err)
 	}

+ 1 - 1
module/crontab/model.go

@@ -88,7 +88,7 @@ type ChangeFilterData struct {
 	ChangeChew     int32
 	XlcDisCount    float64
 	HeatDate       string
-	FrameId        int32
+	Frameid        int32
 }
 
 type SecondFilterData struct {

+ 17 - 11
module/crontab/neck_ring_calculate.go

@@ -105,6 +105,12 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds [
 
 	// 活动量滤波
 	for _, v := range newNeckActiveHabitList {
+		// 4小时数据不全的不参与滤波
+		activeTime, _ := util.TimeParseLocal(model.LayoutTime, v.ActiveTime)
+		if v.RecordCount != model.DefaultRecordCount && time.Now().Sub(activeTime).Hours() <= 4 {
+			continue
+		}
+
 		// 过滤牛只未绑定的脖环的数据
 		cowInfo := e.GetCowInfoByNeckRingNumber(v.PastureId, v.NeckRingNumber)
 		if cowInfo == nil || cowInfo.Id <= 0 {
@@ -118,12 +124,6 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds [
 			continue
 		}
 
-		// 8小时数据不全的不参与滤波
-		activeTime, _ := util.TimeParseLocal(model.LayoutTime, v.ActiveTime)
-		if v.RecordCount != model.DefaultRecordCount && time.Now().Sub(activeTime).Hours() < 8 {
-			continue
-		}
-
 		frameId := v.Frameid
 		heatDate := v.HeatDate
 		if v.Frameid == 0 {
@@ -163,11 +163,15 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds [
 				firstFilterData.FilterChew = v.Rumina + v.Intake
 			}
 		}
+		cowWeeklyActive := cowInfo.WeeklyActive
+		if cowWeeklyActive <= 0 {
+			cowWeeklyActive = v.WeekHigh
+		}
 
 		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").
+			Select("filter_high", "filter_rumina", "filter_chew", "cow_id", "lact", "calving_age", "ear_number", "week_high").
 			Where("id = ?", v.Id).
 			Updates(map[string]interface{}{
 				"filter_high":   firstFilterData.FilterHigh,
@@ -177,6 +181,7 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds [
 				"lact":          0,
 				"calving_age":   cowInfo.CalvingAge,
 				"ear_number":    cowInfo.EarNumber,
+				"week_high":     cowWeeklyActive,
 			}).Error; err != nil {
 			zaplog.Error("FirstFilterUpdate",
 				zap.Any("error", err),
@@ -199,16 +204,16 @@ func (e *Entry) SecondUpdateChangeFilter(pastureId int64, processIds []int64, xT
 		Where("id IN (?)", processIds).
 		Where("change_filter = ?", model.InitChangeFilter).
 		Where("change_high > ?", MinChangeHigh).
-		Order("neck_ring_number,heat_date,frameid").
+		Order("heat_date,neck_ring_number,frameid").
 		Find(&newChangeFilterList).Error; err != nil {
 		zaplog.Error("SecondUpdateChangeFilter", zap.Any("error", err), zap.Any("xToday", xToday))
 		return
 	}
 
 	for _, v := range newChangeFilterList {
-		frameId := v.FrameId
+		frameId := v.Frameid
 		heatDate := v.HeatDate
-		if v.FrameId == 0 {
+		if v.Frameid == 0 {
 			frameId = 11
 			heatDateParse, _ := util.TimeParseLocal(model.LayoutDate2, heatDate)
 			heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2)
@@ -255,6 +260,7 @@ func (e *Entry) SecondUpdateChangeFilter(pastureId int64, processIds []int64, xT
 		if chewFilter > 50 {
 			chewFilter = 50
 		}
+
 		if err := e.DB.Model(new(model.NeckActiveHabit)).
 			Select("change_filter", "rumina_filter", "chew_filter").
 			Where("id = ?", v.Id).
@@ -394,7 +400,7 @@ func (e *Entry) UpdateIsShow(pastureId int64, processIds []int64) {
 
 func (e *Entry) XToday(pastureId int64) (*XToday, error) {
 	xToday := &XToday{}
-	systemConfigureList, err := e.GetSystemNeckRingConfigure(pastureId)
+	systemConfigureList, err := e.FindSystemNeckRingConfigure(pastureId)
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}

+ 41 - 21
module/crontab/neck_ring_estrus.go

@@ -42,7 +42,7 @@ func (e *Entry) UpdateCowEstrus() (err error) {
 
 func (e *Entry) EntryCowEstrus(pastureId int64) (err error) {
 	xToday := &XToday{}
-	systemConfigureList, err := e.GetSystemNeckRingConfigure(pastureId)
+	systemConfigureList, err := e.FindSystemNeckRingConfigure(pastureId)
 	if err != nil {
 		return xerr.WithStack(err)
 	}
@@ -81,7 +81,6 @@ func (e *Entry) CowEstrusWarning(pastureId int64, xToday *XToday, nowTime time.T
 		return
 	}
 
-	zaplog.Info("CowEstrusWarning", zap.Any("neckActiveHabitList", neckActiveHabitList))
 	neckActiveHabitMap := make(map[int64][]*model.NeckActiveHabit)
 	for _, habit := range neckActiveHabitList {
 		cft := calculateCFT(habit)
@@ -96,19 +95,21 @@ func (e *Entry) CowEstrusWarning(pastureId int64, xToday *XToday, nowTime time.T
 		neckActiveHabitMap[habit.CowId] = append(neckActiveHabitMap[habit.CowId], habit)
 	}
 
-	zaplog.Info("CowEstrusWarning", zap.Any("neckActiveHabitMap", neckActiveHabitMap))
 	neckRingEstrusList := make([]*model.NeckRingEstrus, 0)
 	for cowId, cowHabitList := range neckActiveHabitMap {
 		// 最近3天最大发情记录,小于该变化趋势的不再插入
 		before3Data := e.GetBeforeThreeDaysCowEstrus(cowId, nowTime.AddDate(0, 0, -2).Format(model.LayoutTime))
+
 		// 判断最近50天内是否存在发情记录(发情等级>=2),如果18~25天@xadjust21,如果36~50天@xadjust42
-		cowEstrus := e.GetTwoEstrus(pastureId, cowId, nowTime.AddDate(0, 0, -100).Format(model.LayoutTime), nowTime.AddDate(0, 0, -2).Format(model.LayoutTime))
-		activeDateTime, _ := util.TimeParseLocal(model.LayoutTime, cowEstrus.ActiveDate)
-		if activeDateTime.Unix() >= nowTime.AddDate(0, 0, -25).Unix() && activeDateTime.Unix() <= nowTime.AddDate(0, 0, -18).Unix() {
-			cowEstrus.HadJust = XAdjust21
-		}
-		if activeDateTime.Unix() >= nowTime.AddDate(0, 0, -50).Unix() && activeDateTime.Unix() <= nowTime.AddDate(0, 0, -36).Unix() {
-			cowEstrus.HadJust = XAdjust42
+		cow21Estrus := e.GetTwoEstrus(pastureId, cowId, nowTime.AddDate(0, 0, -100).Format(model.LayoutTime), nowTime.AddDate(0, 0, -2).Format(model.LayoutTime))
+		if cow21Estrus.ActiveDate != "" {
+			activeDateTime, _ := util.TimeParseLocal(model.LayoutTime, cow21Estrus.ActiveDate)
+			if activeDateTime.Unix() >= nowTime.AddDate(0, 0, -25).Unix() && activeDateTime.Unix() <= nowTime.AddDate(0, 0, -18).Unix() {
+				cow21Estrus.HadJust = XAdjust21
+			}
+			if activeDateTime.Unix() >= nowTime.AddDate(0, 0, -50).Unix() && activeDateTime.Unix() <= nowTime.AddDate(0, 0, -36).Unix() {
+				cow21Estrus.HadJust = XAdjust42
+			}
 		}
 
 		maxCft := float32(0)
@@ -130,11 +131,13 @@ func (e *Entry) CowEstrusWarning(pastureId int64, xToday *XToday, nowTime time.T
 		}
 
 		b48 := float64(0)
-		t3, _ := util.TimeParseLocal(model.LayoutTime, before3Data.ActiveTime)
-		b48 = t3.Sub(lastActiveDate).Hours()
+		if len(before3Data.ActiveTime) > 0 {
+			t3, _ := util.TimeParseLocal(model.LayoutTime, before3Data.ActiveTime)
+			b48 = t3.Sub(lastActiveDate).Hours()
+		}
 
-		if (int32(maxCft) > before3Data.DayHigh || before3Data.CowId == 0 || b48 > B48) && int32(maxCft)+cowEstrus.HadJust > xToday.ActiveLow {
-			level := calculateActiveLevel(maxCft, cowEstrus, xToday)
+		if (int32(maxCft) > before3Data.DayHigh || before3Data.CowId == 0 || b48 > B48) && int32(maxCft)+cow21Estrus.HadJust > xToday.ActiveLow {
+			level := calculateActiveLevel(maxCft, cow21Estrus, xToday)
 			cowInfo := e.FindCowInfoByCowId(cowId)
 			if cowInfo == nil {
 				zaplog.Error("CowEstrusWarning", zap.Any("FindCowInfoByCowId", cowId))
@@ -144,10 +147,15 @@ func (e *Entry) CowEstrusWarning(pastureId int64, xToday *XToday, nowTime time.T
 			if cowInfo != nil && cowInfo.IsPregnant == pasturePb.IsShow_Ok && level == pasturePb.EstrusLevel_Low {
 				isShow = pasturePb.IsShow_No
 			}
-			dayHigh := int32(maxCft) + cowEstrus.HadJust
-			lastEstrusDate := cowEstrus.ActiveDate
-			checkResult := getResult(before3Data, maxCft, cowEstrus)
+			dayHigh := int32(maxCft) + cow21Estrus.HadJust
+			lastEstrusDate := cow21Estrus.ActiveDate
+			checkResult := getResult(before3Data, maxCft, cow21Estrus)
 			isPeak := pasturePb.IsShow_Ok
+			activeTime := lastActiveDate.Format(model.LayoutTime)
+
+			if e.HistoryNeckRingEstrus(pastureId, cowInfo.NeckRingNumber, activeTime) {
+				continue
+			}
 
 			zaplog.Info("CowEstrusWarning",
 				zap.Any("level", level),
@@ -158,15 +166,15 @@ func (e *Entry) CowEstrusWarning(pastureId int64, xToday *XToday, nowTime time.T
 				zap.Any("lastEstrusDate", lastEstrusDate),
 				zap.Any("activeDate", lastActiveDate),
 				zap.Any("dayHigh", dayHigh),
-				zap.Any("cft", maxCft),
+				zap.Any("maxCft", maxCft),
 				zap.Any("before3Data", before3Data),
-				zap.Any("cowEstrus", cowEstrus),
+				zap.Any("cowEstrus", cow21Estrus),
 				zap.Any("cowInfo", cowInfo),
 				zap.Any("cowHabitList", cowHabitList),
 			)
-			newNeckRingEstrus := model.NewNeckRingEstrus(pastureId, cowInfo, level, checkResult, isShow)
+			newNeckRingEstrus := model.NewNeckRingEstrus(pastureId, cowInfo, level, int32(maxCft), checkResult, isShow)
 			newNeckRingEstrus.LastTime = lastEstrusDate
-			newNeckRingEstrus.ActiveTime = lastActiveDate.Format(model.LayoutTime)
+			newNeckRingEstrus.ActiveTime = activeTime
 			newNeckRingEstrus.DayHigh = dayHigh
 			newNeckRingEstrus.MaxHigh = maxHigh
 			newNeckRingEstrus.IsPeak = isPeak
@@ -284,6 +292,18 @@ func (e *Entry) FindCowEstrusFirstTime1(pastureId, cowId int64, xToday time.Time
 	return firstTimeEventEstrus
 }
 
+func (e *Entry) HistoryNeckRingEstrus(pastureId int64, neckRingNumber string, activeTime string) bool {
+	var count int64
+	if err := e.DB.Model(new(model.NeckRingEstrus)).
+		Where("pasture_id = ?", pastureId).
+		Where("neck_ring_number = ?", neckRingNumber).
+		Where("active_time = ?", activeTime).
+		Count(&count).Error; err != nil {
+		return false
+	}
+	return count > 0
+}
+
 // calculateCFT 计算cft值
 func calculateCFT(habit *model.NeckActiveHabit) (cft float32) {
 	if habit.ChangeAdjust >= 10 {

+ 1 - 5
module/crontab/neck_ring_estus_test.go

@@ -5,7 +5,6 @@ import (
 	"fmt"
 	"kpt-pasture/model"
 	"kpt-pasture/util"
-	"math"
 	"sort"
 	"testing"
 	"time"
@@ -6099,8 +6098,5 @@ func TestRecalculate(t *testing.T) {
 }
 
 func TestIndex(t *testing.T) {
-	ruminaFilter := float64(100)
-	ruminaFilter1 := float64(58)
-	fmt.Println(int32(math.Min(50, ruminaFilter)))
-	fmt.Println(int32(math.Min(50, ruminaFilter1)))
+
 }

+ 13 - 1
module/crontab/sql.go

@@ -132,7 +132,7 @@ func (e *Entry) FindAppPastureReceiver() map[string]int64 {
 	return receiverMap
 }
 
-func (e *Entry) GetSystemNeckRingConfigure(pastureId int64) ([]*model.NeckRingConfigure, error) {
+func (e *Entry) FindSystemNeckRingConfigure(pastureId int64) ([]*model.NeckRingConfigure, error) {
 	res := make([]*model.NeckRingConfigure, 0)
 	if err := e.DB.Model(new(model.NeckRingConfigure)).
 		Where("pasture_id = ?", pastureId).
@@ -143,6 +143,18 @@ func (e *Entry) GetSystemNeckRingConfigure(pastureId int64) ([]*model.NeckRingCo
 	return res, nil
 }
 
+func (e *Entry) GetSystemNeckRingConfigure(pastureId int64, name string) (*model.NeckRingConfigure, error) {
+	res := &model.NeckRingConfigure{}
+	if err := e.DB.Model(new(model.NeckRingConfigure)).
+		Where("pasture_id = ?", pastureId).
+		Where("is_show = ?", pasturePb.IsShow_Ok).
+		Where("name = ?", name).
+		First(&res).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	return res, nil
+}
+
 func (e *Entry) GetCowInfoByNeckRingNumber(pastureId int64, neckRingNumber string) *model.Cow {
 	res := &model.Cow{}
 	if err := e.DB.Model(new(model.Cow)).