Browse Source

event: update

Yi 4 weeks ago
parent
commit
c5d02f37bb

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250301090359-debc53863000
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250303084040-e9be94c74c2a
 	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

+ 6 - 0
go.sum

@@ -273,6 +273,12 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250228083339-f6b9576918dd h1:hqSeKVOL
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250228083339-f6b9576918dd/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250301090359-debc53863000 h1:gGF+69uDuE1ocf7k5tbvdqs730wEYYyMA2Vtsu2z/R8=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250301090359-debc53863000/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250303011351-e52717847500 h1:i7hjSJLO99fLsDsu/DMihZtDmmGx83cS5/EXBhA4mH4=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250303011351-e52717847500/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250303083156-fe44c0a9957d h1:vSbxOcwGH8IXtHyLJkm5LaO8S2dQiTdHw/I5SVQztmg=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250303083156-fe44c0a9957d/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250303084040-e9be94c74c2a h1:vJXz6WZY0xG+UH8UwNoK1z2IJgB3oR3/vKZO5GYhvZw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250303084040-e9be94c74c2a/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=

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

@@ -20,7 +20,7 @@ func Detail(c *gin.Context) {
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.CowId, valid.Required),
+		valid.Field(&req.EarNumber, valid.Required),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
@@ -63,7 +63,7 @@ func EventList(c *gin.Context) {
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.CowId, valid.Required),
+		valid.Field(&req.EarNumber, valid.Required),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return

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

@@ -208,7 +208,7 @@ func WeightBatch(c *gin.Context) {
 			s := value.(pasturePb.EventWeight)
 			return valid.ValidateStruct(&s,
 				valid.Field(&s.Weight, valid.Required),
-				valid.Field(&s.CowId, valid.Required),
+				valid.Field(&s.EarNumber, valid.Required),
 				valid.Field(&s.WeightAt, valid.Required),
 				valid.Field(&s.OperationId, valid.Required),
 			)

+ 5 - 5
http/handler/event/event_breed.go

@@ -41,7 +41,7 @@ func CalvingEventCreate(c *gin.Context) {
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.CowId, valid.Required),
+		valid.Field(&req.EarNumber, valid.Required),
 		valid.Field(&req.CalvingAt, valid.Required),
 		valid.Field(&req.ChildNumber, valid.Required),
 		valid.Field(&req.CalvingLevel, valid.Required),
@@ -104,7 +104,7 @@ func PregnantCheckEventCreateBatch(c *gin.Context) {
 		valid.Field(&req.Items, valid.Required, valid.Each(valid.By(func(value interface{}) error {
 			item := value.(pasturePb.EventPregnantCheckRequest)
 			return valid.ValidateStruct(&item,
-				valid.Field(&item.CowId, valid.Required),
+				valid.Field(&item.EarNumber, valid.Required),
 				valid.Field(&item.PregnantCheckAt, valid.Required),
 				valid.Field(&item.PregnantCheckResult, valid.Required),
 				valid.Field(&item.PregnantCheckMethod, valid.Required),
@@ -211,7 +211,7 @@ func EstrusBatchMating(c *gin.Context) {
 		valid.Field(&req.Items, valid.Required, valid.Each(valid.By(func(value interface{}) error {
 			item := value.(pasturePb.EventNaturalEstrusItems)
 			return valid.ValidateStruct(&item,
-				valid.Field(&item.CowId, valid.Required),
+				valid.Field(&item.EarNumber, valid.Required),
 				valid.Field(&item.EstrusAt, valid.Required),
 				valid.Field(&item.IsMating, valid.Required),
 				valid.Field(&item.OperationId, valid.Required),
@@ -323,7 +323,7 @@ func AbortionCreateBatch(c *gin.Context) {
 		valid.Field(&req.Items, valid.Required, valid.Each(valid.By(func(value interface{}) error {
 			item := value.(pasturePb.EventAbortionItem)
 			return valid.ValidateStruct(&item,
-				valid.Field(&item.CowId, valid.Required),
+				valid.Field(&item.EarNumber, valid.Required),
 				valid.Field(&item.IsAfterbirth, valid.Required),
 				valid.Field(&item.AbortionReasons, valid.Required),
 				valid.Field(&item.AbortionAt, valid.Required),
@@ -382,7 +382,7 @@ func WeaningCreateBatch(c *gin.Context) {
 		valid.Field(&req.Items, valid.Required, valid.Each(valid.By(func(value interface{}) error {
 			item := value.(pasturePb.WeaningItem)
 			return valid.ValidateStruct(&item,
-				valid.Field(&item.CowId, valid.Required),
+				valid.Field(&item.EarNumber, valid.Required),
 				valid.Field(&item.Weight, valid.Required),
 			)
 		}))),

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

@@ -21,7 +21,7 @@ func CowDiseaseCreate(c *gin.Context) {
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.CowId, valid.Required),
+		valid.Field(&req.EarNumber, valid.Required),
 		valid.Field(&req.DiseaseAt, valid.Required),
 		valid.Field(&req.DiseaseId, valid.Required),
 		valid.Field(&req.OperationId, valid.Required),

+ 22 - 19
model/neck_ring_estrus.go

@@ -5,31 +5,33 @@ import (
 )
 
 type NeckRingEstrus struct {
-	Id              int64                      `json:"id"`
-	PastureId       int64                      `json:"pastureId"`
-	CowId           int64                      `json:"cowId"`
-	NeckRingNumber  string                     `json:"neckRingNumber"`
-	EarNumber       string                     `json:"earNumber"`
-	Lact            int32                      `json:"lact"`
-	EstrusStartDate string                     `json:"estrusStartDate"`
-	LastEstrusDate  string                     `json:"lastEstrusDate"`
-	ActiveDate      string                     `json:"activeDate"`
-	ActiveLevel     pasturePb.EstrusLevel_Kind `json:"activeLevel"`
-	IsPeak          pasturePb.IsShow_Kind      `json:"isPeak"`
-	DayHigh         int32                      `json:"dayHigh"`
-	MaxHigh         int32                      `json:"maxHigh"`
-	CheckResult     pasturePb.CheckResult_Kind `json:"checkResult"`
-	CheckAt         int64                      `json:"checkAt"`
-	IsShow          pasturePb.IsShow_Kind      `json:"isShow"`
-	CreatedAt       int64                      `json:"createdAt"`
-	UpdatedAt       int64                      `json:"updatedAt"`
+	Id             int64                      `json:"id"`
+	PastureId      int64                      `json:"pastureId"`
+	CowId          int64                      `json:"cowId"`
+	NeckRingNumber string                     `json:"neckRingNumber"`
+	EarNumber      string                     `json:"earNumber"`
+	Lact           int32                      `json:"lact"`
+	FirstTime      string                     `json:"firstTime"`
+	LastTime       string                     `json:"lastTime"`
+	ActiveTime     string                     `json:"activeTime"`
+	ActiveLevel    pasturePb.EstrusLevel_Kind `json:"activeLevel"`
+	IsPeak         pasturePb.IsShow_Kind      `json:"isPeak"`
+	DayHigh        int32                      `json:"dayHigh"`
+	MaxHigh        int32                      `json:"maxHigh"`
+	CheckResult    pasturePb.CheckResult_Kind `json:"checkResult"`
+	CheckAt        int64                      `json:"checkAt"`
+	IsShow         pasturePb.IsShow_Kind      `json:"isShow"`
+	CreatedAt      int64                      `json:"createdAt"`
+	UpdatedAt      int64                      `json:"updatedAt"`
 }
 
 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,
+	checkResult pasturePb.CheckResult_Kind, isShow pasturePb.IsShow_Kind, firstTime string,
+) *NeckRingEstrus {
 	return &NeckRingEstrus{
 		PastureId:      pastureId,
 		CowId:          cow.Id,
@@ -39,6 +41,7 @@ func NewNeckRingEstrus(pastureId int64, cow *Cow, level pasturePb.EstrusLevel_Ki
 		ActiveLevel:    level,
 		IsShow:         isShow,
 		CheckResult:    checkResult,
+		FirstTime:      firstTime,
 	}
 }
 

+ 35 - 1
model/neck_ring_estrus_warning.go

@@ -1,6 +1,12 @@
 package model
 
-import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+import (
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
+
+const IntCurFetal = 3
 
 type NeckRingEstrusWarning struct {
 	Id               int64                      `json:"id"`
@@ -44,6 +50,28 @@ func NewNeckRingEstrusWarning(
 	}
 }
 
+// calculatePzHour 计算最佳配置时间
+func (n *NeckRingEstrusWarning) calculatePzHour(lact int32) time.Time {
+	var pzHour time.Time
+
+	dateTime := n.DateTime
+	firstTime := n.FirstTime
+
+	// 条件判断
+	if n.IsPeak == pasturePb.IsShow_Ok || n.DateTime.Sub(n.FirstTime).Hours() >= 8 {
+		pzHour = n.DateTime.Add(8 * time.Hour) // v.datetime + INTERVAL 8 HOUR
+	} else {
+		pzHour = n.FirstTime.Add(16 * time.Hour) // v.firsttime + INTERVAL 16 HOUR
+	}
+
+	// 时间调整
+	if lact >= 3 {
+		pzHour = pzHour.Add(-1 * time.Hour) // 减去 1 小时
+	}
+
+	return pzHour
+}
+
 type NeckRingEstrusWarningSlice []*NeckRingEstrusWarning
 
 func (n NeckRingEstrusWarningSlice) ToPB(cowMap map[int64]*Cow, eventLogMap map[int64]string) []*pasturePb.EstrusItems {
@@ -59,6 +87,7 @@ func (n NeckRingEstrusWarningSlice) ToPB(cowMap map[int64]*Cow, eventLogMap map[
 			lastBreedEventDetails = desc
 		}
 
+		pzHour := v.calculatePzHour(cow.Lact)
 		res[i] = &pasturePb.EstrusItems{
 			Id:                     int32(v.Id),
 			CowId:                  int32(v.CowId),
@@ -94,3 +123,8 @@ type EstrusWarning struct {
 	Nb1              int32  `json:"nb1"`
 	Nb2              int32  `json:"nb2"`
 }
+
+type DashboardNeckRingEstrusWarning struct {
+	Level pasturePb.EstrusLevel_Kind
+	Count int32
+}

+ 13 - 21
module/backend/cow.go

@@ -7,7 +7,6 @@ import (
 	"kpt-pasture/model"
 	"kpt-pasture/util"
 	"net/http"
-	"strconv"
 	"strings"
 	"time"
 
@@ -26,21 +25,13 @@ func (s *StoreEntry) Detail(ctx context.Context, req *pasturePb.SearchEventReque
 
 	cowInfo := &model.Cow{}
 	pref := s.DB.Model(new(model.Cow)).
-		Where("pasture_id = ?", userModel.AppPasture.Id)
-
-	if req.CowId != "" {
-		cowId, _ := strconv.Atoi(req.CowId)
-		pref.Where("id = ?", cowId)
-	}
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Where("ear_number = ?", req.EarNumber)
 
 	if req.NeckRingNumber != "" {
 		pref.Where("neck_ring_number = ?", req.NeckRingNumber)
 	}
 
-	if req.EarNumber != "" {
-		pref.Where("ear_number = ?", req.EarNumber)
-	}
-
 	if err = pref.Order("id desc").
 		First(cowInfo).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
@@ -157,14 +148,15 @@ func (s *StoreEntry) EventList(ctx context.Context, req *pasturePb.SearchCowEven
 		return nil, xerr.WithStack(err)
 	}
 	eventCowLogList := make([]*model.EventCowLog, 0)
-	eventCowLog := &model.EventCowLog{CowId: int64(req.CowId)}
+	cowInfo, err := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, req.EarNumber)
+	if err != nil {
+		return nil, xerr.Customf("错误的牛只信息: %s", req.EarNumber)
+	}
+
+	eventCowLog := &model.EventCowLog{CowId: cowInfo.Id}
 	pref := s.DB.Table(eventCowLog.TableName()).
 		Where("pasture_id = ?", userModel.AppPasture.Id)
 
-	if req.EarNumber != "" {
-		pref.Where("ear_number = ?", req.EarNumber)
-	}
-
 	if req.Lact >= 0 {
 		pref.Where("lact = ?", req.Lact)
 	}
@@ -246,9 +238,9 @@ func (s *StoreEntry) BehaviorCurve(ctx context.Context, req *pasturePb.CowBehavi
 	if err = s.DB.Table(new(model.NeckRingEstrus).TableName()).
 		Where("cow_id = ?", cowInfo.Id).
 		Where("pasture_id = ?", userModel.AppPasture.Id).
-		Where("estrus_start_date >= ?", startDataTime).
-		Where("estrus_start_date <= ?", endDataTime).
-		Order("estrus_start_date").
+		Where("first_time >= ?", startDataTime).
+		Where("first_time <= ?", endDataTime).
+		Order("first_time").
 		Find(&estrusList).Error; err != nil {
 		return nil, xerr.WithStack(err)
 	}
@@ -257,9 +249,9 @@ func (s *StoreEntry) BehaviorCurve(ctx context.Context, req *pasturePb.CowBehavi
 		if data.EstrusList[v.ActiveLevel] == nil {
 			data.EstrusList[v.ActiveLevel] = make([]string, 0)
 		}
-		if len(v.EstrusStartDate) > 0 {
+		if len(v.FirstTime) > 0 {
 			// 格式化为到小时的字符串
-			parsedTime, _ := time.Parse(model.LayoutTime, v.EstrusStartDate)
+			parsedTime, _ := time.Parse(model.LayoutTime, v.FirstTime)
 			hourStr := parsedTime.Format(model.LayoutHour)
 			data.EstrusList[v.ActiveLevel] = append(data.EstrusList[v.ActiveLevel], hourStr)
 		}

+ 12 - 8
module/backend/dashboard.go

@@ -2,6 +2,7 @@ package backend
 
 import (
 	"context"
+	"fmt"
 	"kpt-pasture/model"
 	"kpt-pasture/util"
 	"net/http"
@@ -24,22 +25,25 @@ func (s *StoreEntry) NeckRingWarning(ctx context.Context) (*pasturePb.IndexNeckR
 		return nil, xerr.WithStack(err)
 	}
 
-	estrusWarningCowList := make([]*model.NeckRingEstrus, 0)
+	estrusWarningCowList := make([]*model.DashboardNeckRingEstrusWarning, 0)
 	estrusWarningLevelItems := map[int32]int32{
 		int32(pasturePb.EstrusLevel_Low):    0,
 		int32(pasturePb.EstrusLevel_Middle): 0,
 		int32(pasturePb.EstrusLevel_High):   0,
 	}
 
-	if err = s.DB.Model(new(model.EventEstrus)).
-		Where("pasture_id = ?", userModel.AppPasture.Id).
-		Where("is_show = ?", pasturePb.IsShow_Ok).
-		Group("cow_id").Find(&estrusWarningCowList).Error; err != nil {
+	if err = s.DB.Table(fmt.Sprintf("%s as a", new(model.NeckRingEstrusWarning).TableName())).
+		Select("a.level, count(a.level) as count").
+		Where("a.pasture_id = ?", userModel.AppPasture.Id).
+		Where("a.is_show = ?", pasturePb.IsShow_Ok).
+		Group("a.level").
+		Find(&estrusWarningCowList).Error; err != nil {
 		zaplog.Error("NeckRingWarning", zap.Any("estrusWarningNumber", err))
 	}
-
+	countEstrusWarning := 0
 	for _, v := range estrusWarningCowList {
-		estrusWarningLevelItems[int32(v.ActiveLevel)] += estrusWarningLevelItems[int32(v.ActiveLevel)]
+		estrusWarningLevelItems[int32(v.Level)] = estrusWarningLevelItems[v.Count]
+		countEstrusWarning += int(v.Count)
 	}
 
 	healthWarningNumber := int64(0)
@@ -55,7 +59,7 @@ func (s *StoreEntry) NeckRingWarning(ctx context.Context) (*pasturePb.IndexNeckR
 		Code: http.StatusOK,
 		Msg:  "ok",
 		Data: &pasturePb.NeckRingData{
-			EstrusWarningNumber:     int32(len(estrusWarningCowList)),
+			EstrusWarningNumber:     int32(countEstrusWarning),
 			HealthWarningNumber:     int32(healthWarningNumber),
 			AbortionWarningNumber:   0,
 			StressWarningNumber:     0,

+ 1 - 1
module/backend/event_base.go

@@ -217,7 +217,7 @@ func (s *StoreEntry) CreateGroupTransfer(ctx context.Context, req *pasturePb.Tra
 			if err = s.DB.Model(cow).
 				Updates(map[string]interface{}{
 					"pen_id":   v.TransferInPenId,
-					"pen_name": penMap[v.TransferReasonId],
+					"pen_name": penMap[v.TransferReasonId].Name,
 				}).Error; err != nil {
 				return xerr.WithStack(err)
 			}

+ 8 - 4
module/backend/event_breed.go

@@ -76,7 +76,7 @@ func (s *StoreEntry) CalvingCreate(ctx context.Context, req *pasturePb.EventCalv
 		return xerr.WithStack(err)
 	}
 
-	cow, err := s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, int64(req.CowId))
+	cow, err := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, req.EarNumber)
 	if err != nil {
 		zaplog.Error("CalvingCreate", zap.Any("cow_id", req.CowId), zap.Any("err", err))
 		return xerr.Custom("请选择相关牛只")
@@ -336,9 +336,13 @@ func (s *StoreEntry) EstrusList(ctx context.Context, req *pasturePb.EstrusItemsR
 		Where("is_show = ?", pasturePb.IsShow_Ok).
 		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("expose_estrus_type = ?", pasturePb.ExposeEstrusType_Natural_Estrus)
-	if len(req.CowIds) > 0 {
-		cowIds := strings.Split(util.ArrayInt32ToStrings(req.CowIds, ","), ",")
-		pref.Where("cow_id IN ?", cowIds)
+	if len(req.EarNumbers) > 0 {
+		earNumberString := ""
+		for _, e := range req.EarNumbers {
+			earNumberString += fmt.Sprintf("%s,", e)
+		}
+
+		pref.Where("ear_number IN (?)", strings.TrimRight(earNumberString, ","))
 	}
 
 	if req.EarNumber != "" {

+ 1 - 1
module/backend/event_check.go

@@ -137,7 +137,7 @@ func (s *StoreEntry) PregnantCheckDataCheck(ctx context.Context, pastureId int64
 	cowInfo := &model.Cow{}
 	var err error
 	for _, item := range req.Items {
-		cowInfo, err = s.GetCowInfoByCowId(ctx, pastureId, int64(item.CowId))
+		cowInfo, err = s.GetCowInfoByEarNumber(ctx, pastureId, item.EarNumber)
 		if err != nil {
 			return nil, xerr.WithStack(err)
 		}

+ 1 - 1
module/backend/event_cow_log.go

@@ -45,7 +45,7 @@ func (s *StoreEntry) SubmitEventLog(
 			strconv.FormatFloat(float64(data.Price), 'f', 2, 64), sourceMap[cow.SourceId])
 	case pasturePb.EventType_Transfer_Ben:
 		data := req.(*model.EventTransferGroup)
-		transferAt, _ := time.Parse(model.LayoutDate2, data.TransferDate)
+		transferAt, _ := time.Parse(model.LayoutTime, data.TransferDate)
 		eventAt = transferAt.Unix()
 		remarks = data.Remarks
 		operationUser.Id = data.OperationId

+ 9 - 9
module/backend/event_health.go

@@ -187,25 +187,25 @@ func (s *StoreEntry) EstrusCowList(ctx context.Context, req *pasturePb.EstrusIte
 
 	var count int64
 	neckRingEstrusList := make([]*model.NeckRingEstrusWarning, 0)
-	pref := s.DB.Model(new(model.NeckRingEstrusWarning)).
-		Where("pasture_id = ?", userModel.AppPasture.Id).
-		Where("is_show = ?", pasturePb.IsShow_Ok)
+	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("a.pasture_id = ?", userModel.AppPasture.Id).
+		Where("a.is_show = ?", pasturePb.IsShow_Ok)
 
-	if len(req.CowIds) > 0 {
-		cowIds := strings.Split(util.ArrayInt32ToStrings(req.CowIds, ","), ",")
-		pref.Where("cow_id IN ?", cowIds)
+	if len(req.EarNumber) > 0 {
+		pref.Where("a.ear_number = ?", req.EarNumber)
 	}
 
 	if req.Level > 0 {
-		pref.Where("level = ?", req.Level)
+		pref.Where("a.level = ?", req.Level)
 	}
 
 	if len(req.PenIds) > 0 {
 		penIds := strings.Split(util.ArrayInt32ToStrings(req.PenIds, ","), ",")
-		pref.Where("pen_id IN ?", penIds)
+		pref.Where("b.pen_id IN ?", penIds)
 	}
 
-	if err = pref.Order("level DESC").
+	if err = pref.Order("a.level DESC").
 		Count(&count).
 		Limit(int(pagination.PageSize)).
 		Offset(int(pagination.PageOffset)).

+ 17 - 13
module/crontab/warning_handle.go → module/crontab/estrus_warning.go

@@ -26,9 +26,9 @@ func (e *Entry) UpdateNeckRingWarning() (err error) {
 			zaplog.Error("UpdateNeckRingWarning", zap.Any("delete", err), zap.Any("pasture", pasture))
 		}
 		if err = e.NeckRingWarning(pasture.Id); err != nil {
-			zaplog.Error("EntryCrontab", zap.Any("NeckRingWarning", err), zap.Any("pasture", pasture))
+			zaplog.Error("UpdateNeckRingWarning", zap.Any("NeckRingWarning", err), zap.Any("pasture", pasture))
 		}
-		zaplog.Info("UpdateNeckRingWarning-success", zap.Any("pasture", pasture.Id))
+		zaplog.Info("UpdateNeckRingWarning", zap.Any("success", pasture.Id))
 	}
 	return nil
 }
@@ -42,7 +42,7 @@ func (e *Entry) NeckRingWarning(pastureId int64) (err error) {
 		Select("a.*").
 		Joins("JOIN cow as b ON a.cow_id = b.id AND a.pasture_id = b.pasture_id").
 		Where("a.pasture_id = ?", pastureId).
-		Where("a.active_date >= ?", startTime.Format(model.LayoutTime)).
+		Where("a.active_time >= ?", startTime.Format(model.LayoutTime)).
 		Where("a.active_level >= ?", pasturePb.EstrusLevel_Low).
 		Where("a.check_result IN (?)", []pasturePb.CheckResult_Kind{pasturePb.CheckResult_Pending, pasturePb.CheckResult_Correct}).
 		Where("a.is_show = ?", pasturePb.IsShow_Ok).
@@ -51,11 +51,14 @@ func (e *Entry) NeckRingWarning(pastureId int64) (err error) {
 		Find(&neckRingEstrusList).Error; err != nil {
 		return xerr.WithStack(err)
 	}
-
+	zaplog.Info("UpdateNeckRingWarning", zap.Any("neckRingEstrusList", neckRingEstrusList))
 	if len(neckRingEstrusList) == 0 {
 		return nil
 	}
+
 	neckRingEstrusWarningList := e.GroupAndProcessData(neckRingEstrusList)
+	zaplog.Info("UpdateNeckRingWarning", zap.Any("neckRingEstrusWarningList", neckRingEstrusWarningList))
+
 	if len(neckRingEstrusWarningList) > 0 {
 		if err = e.DB.CreateInBatches(neckRingEstrusWarningList, 50).Error; err != nil {
 			return xerr.WithStack(err)
@@ -69,6 +72,7 @@ func (e *Entry) NeckRingWarning(pastureId int64) (err error) {
 	if err != nil {
 		return xerr.WithStack(err)
 	}
+	zaplog.Info("UpdateNeckRingWarning", zap.Any("estrusWarningList", estrusWarningList))
 
 	for _, v := range estrusWarningList {
 		neckRingEstrusWarning := &model.NeckRingEstrusWarning{}
@@ -79,7 +83,6 @@ func (e *Entry) NeckRingWarning(pastureId int64) (err error) {
 			continue
 		}
 
-		warningKind := pasturePb.Warning_Estrus
 		if v.Nb1 <= model.MinNb1 {
 			count := e.getCowHigh(pastureId, v.CowId, minId, v.DateTime)
 			if count <= 0 {
@@ -96,13 +99,12 @@ func (e *Entry) NeckRingWarning(pastureId int64) (err error) {
 		if err = e.DB.Model(new(model.NeckRingEstrusWarning)).
 			Where("neck_ring_estrus_id = ?", v.NeckRingEstrusId).
 			Updates(map[string]interface{}{
-				"warning_kind": warningKind,
+				"warning_kind": pasturePb.Warning_Estrus,
 				"high_change":  v.HighChange,
 			}).Error; err != nil {
 			zaplog.Error("UpdateNeckRingWarning", zap.Any("Updates", err), zap.Any("v", v))
 			continue
 		}
-
 	}
 
 	if err = e.UpdateNeckRingWarningIsPeak(pastureId, minId); err != nil {
@@ -169,14 +171,13 @@ func (e *Entry) GroupAndProcessData(records []*model.NeckRingEstrus) []*model.Ne
 		// 计算字段
 		latest := group.Records[0]
 		maxId := findMaxId(group.Records)
-		firstTime := findMaxTime(group.Records, func(r *model.NeckRingEstrus) string { return r.EstrusStartDate })
-		dateTime := findMaxTime(group.Records, func(r *model.NeckRingEstrus) string { return r.ActiveDate })
+		firstTime := findMaxTime(group.Records, func(r *model.NeckRingEstrus) string { return r.FirstTime })
+		dateTime := findMaxTime(group.Records, func(r *model.NeckRingEstrus) string { return r.ActiveTime })
 		neckRingEstrusWarning := model.NewNeckRingEstrusWarning(
 			maxId, group.PastureId, group.CowId, group.EarNumber,
-			firstTime, dateTime, latest.LastEstrusDate,
+			firstTime, dateTime, latest.LastTime,
 			pasturePb.Warning_Estrus, latest.ActiveLevel,
 		)
-
 		neckRingEstrusWarningList = append(neckRingEstrusWarningList, neckRingEstrusWarning)
 	}
 	return neckRingEstrusWarningList
@@ -187,7 +188,7 @@ func (e *Entry) GetCowHighChange(pastureId, minId int64) ([]*model.EstrusWarning
 	estrusWarningList := make([]*model.EstrusWarning, 0)
 	if err := e.DB.Table(fmt.Sprintf("%s as a", new(model.NeckActiveHabit).TableName())).
 		Select(
-			"GROUP_CONCAT( IF(ROUND(a.change_filter*a.filter_correct/100,0)=-99,'',ROUND(a.change_filter*a.filter_correct/100,0)) ) as high_change",
+			"GROUP_CONCAT(IF(ROUND(a.change_filter*a.filter_correct/100,0)=-99,'',ROUND(a.change_filter*a.filter_correct/100,0)) ) as high_change",
 			"b.neck_ring_estrus_id", "b.cow_id", "b.date_time", "COUNT(a.change_filter>-99) as nb1",
 			"COUNT(a.change_filter=-99 AND a.created_at>=(STR_TO_DATE(b.date_time,'%Y-%m-%d %H:%i:%s') -INTERVAL 48 HOUR )) as nb2").
 		Joins("JOIN neck_ring_estrus_warning as b ON a.cow_id = b.cow_id AND a.pasture_id = b.pasture_id").
@@ -195,7 +196,7 @@ func (e *Entry) GetCowHighChange(pastureId, minId int64) ([]*model.EstrusWarning
 		Where("a.pasture_id = ?", pastureId).
 		Where("a.created_at > ?", nowTime.Unix()).
 		Group("b.neck_ring_estrus_id").
-		Having("nb1 <= ? AND nb2 >=", model.Nb1, model.Nb2).
+		Having("nb1 <= ? AND nb2 >= ?", model.Nb1, model.Nb2).
 		Find(&estrusWarningList).
 		Error; err != nil {
 		return nil, xerr.WithStack(err)
@@ -275,6 +276,9 @@ func findMaxTime(records []*model.NeckRingEstrus, getter func(*model.NeckRingEst
 			max = t
 		}
 	}
+	if max.IsZero() {
+		return ""
+	}
 	return max.Format(model.LayoutTime)
 }
 

+ 5 - 5
module/crontab/model.go

@@ -60,14 +60,14 @@ type CowEstrus struct {
 }
 
 type EstrusStartData struct {
-	CowId           int64
-	EstrusStartDate string
+	CowId     int64
+	FirstTime string
 }
 
 type EstrusIsPeakData struct {
-	CowId           int64
-	EstrusStartDate string
-	ActiveDate      string
+	CowId      int64
+	FirstTime  string
+	ActiveDate string
 }
 
 type XToday struct {

+ 71 - 90
module/crontab/neck_ring_estrus.go

@@ -1,6 +1,7 @@
 package crontab
 
 import (
+	"fmt"
 	"kpt-pasture/model"
 	"time"
 
@@ -56,12 +57,14 @@ func (e *Entry) EntryCowEstrus(pastureId int64) (err error) {
 		zaplog.Error("EntryCowEstrus", zap.Any("CowEstrusWarning", err), zap.Any("xToday", xToday))
 	}
 
-	// 将历史发情预警数据更新为已过期
+	// 将3天前历史发情预警数据更新为已过期
 	if err = e.DB.Model(new(model.NeckRingEstrus)).
-		Where("estrus_start_date <= ?", time.Now().AddDate(0, 0, -4).Format(model.LayoutTime)).
-		Update("is_show", pasturePb.IsShow_No).Error; err != nil {
+		Where("first_time != ?", "").
+		Where("first_time <= ?", time.Now().AddDate(0, 0, -3).Format(model.LayoutTime)).
+		Update("check_result", pasturePb.CheckResult_Overdue).Error; err != nil {
 		zaplog.Error("EntryCowEstrus", zap.Any("UpdateEventEstrus", err))
 	}
+
 	return nil
 }
 
@@ -74,7 +77,8 @@ func (e *Entry) CowEstrusWarning(pastureId int64, xToday *XToday) (err error) {
 		Where("pasture_id = ?", pastureId).
 		Where("filter_high > 0 AND change_filter > ?", model.DefaultChangeFilter).
 		Where("cow_id > ?", 0).
-		Where(e.DB.Where("calving_age > ?", MinCalvingAge).Or("lact = ?", MinLact)). // 排除产后20天内的发情牛
+		Where(e.DB.Where("calving_age >= ?", MinCalvingAge).Or("lact = ?", MinLact)). // 排除产后20天内的发情牛
+		Order("cow_id").
 		Find(&neckActiveHabitList).Error; err != nil {
 		return xerr.WithStack(err)
 	}
@@ -86,9 +90,6 @@ func (e *Entry) CowEstrusWarning(pastureId int64, xToday *XToday) (err error) {
 		if cft < float32(xToday.ActiveLow-XAdjust21) {
 			continue
 		}
-		if _, ok := neckActiveHabitMap[habit.CowId]; !ok {
-			neckActiveHabitMap[habit.CowId] = make([]*model.NeckActiveHabit, 0)
-		}
 		neckActiveHabitMap[habit.CowId] = append(neckActiveHabitMap[habit.CowId], habit)
 	}
 
@@ -110,6 +111,7 @@ func (e *Entry) CowEstrusWarning(pastureId int64, xToday *XToday) (err error) {
 
 		maxCft := float32(0)
 		maxHigh := int32(0)
+		lastActiveDate := time.Time{}
 		for _, habit := range cowHabitList {
 			cft := calculateCFT(habit)
 			if cft > maxCft {
@@ -118,49 +120,59 @@ func (e *Entry) CowEstrusWarning(pastureId int64, xToday *XToday) (err error) {
 			if habit.FilterHigh > maxHigh {
 				maxHigh = habit.FilterHigh
 			}
-		}
-
-		activeDate := ""
-		if len(cowHabitList) > 0 {
-			sortHabits := sortHabitsByChangeFilter(cowHabitList)
-			activeDate = sortHabits[0].ActiveTime
+			// 获取最新的 CreateTime
+			activeTimeParse, _ := time.Parse(habit.ActiveTime, model.LayoutTime)
+			if activeTimeParse.After(lastActiveDate) {
+				lastActiveDate = activeTimeParse
+			}
 		}
 
 		b48 := float64(0)
-		t1, _ := time.Parse(model.LayoutTime, activeDate)
-		t3, err := time.Parse(model.LayoutTime, before3Data.ActiveDate)
-		if err == nil {
-			b48 = t3.Sub(t1).Hours()
-		}
+		t3, _ := time.Parse(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 {
 
-		if (int32(maxCft) > before3Data.DayHigh || b48 > B48) && int32(maxCft)+cowEstrus.HadJust > xToday.ActiveLow {
 			level := calculateActiveLevel(maxCft, cowEstrus, xToday)
-			cowInfo := e.FindCowInfoByNeckRingNumber(cowHabitList[0].NeckRingNumber)
+			cowInfo := e.FindCowInfoByCowId(cowId)
+			if cowInfo == nil {
+				zaplog.Error("CowEstrusWarning", zap.Any("FindCowInfoByCowId", cowId))
+				continue
+			}
 			isShow := pasturePb.IsShow_Ok
-			if cowInfo.IsPregnant == pasturePb.IsShow_Ok && level == pasturePb.EstrusLevel_Low {
+			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)
 			isPeak := pasturePb.IsShow_Ok
+
+			cowEstrusStartData := e.FindCowEstrusFirstTime(pastureId, cowId, nowTime)
+			firstTime := ""
+			if cowEstrusStartData != nil {
+				firstTime = cowEstrusStartData.FirstTime
+			}
+
 			zaplog.Info("CowEstrusWarning",
 				zap.Any("level", level),
+				zap.Any("b48", b48),
 				zap.Any("checkResult", checkResult),
 				zap.Any("isShow", isShow),
 				zap.Any("isPeak", isPeak),
 				zap.Any("lastEstrusDate", lastEstrusDate),
-				zap.Any("activeDate", activeDate),
+				zap.Any("activeDate", lastActiveDate),
 				zap.Any("dayHigh", dayHigh),
 				zap.Any("cft", maxCft),
 				zap.Any("before3Data", before3Data),
 				zap.Any("cowEstrus", cowEstrus),
 				zap.Any("cowInfo", cowInfo),
+				zap.Any("firstTime", firstTime),
 				zap.Any("cowHabitList", cowHabitList),
 			)
-			newNeckRingEstrus := model.NewNeckRingEstrus(pastureId, cowInfo, level, checkResult, isShow)
-			newNeckRingEstrus.LastEstrusDate = lastEstrusDate
-			newNeckRingEstrus.ActiveDate = activeDate
+			newNeckRingEstrus := model.NewNeckRingEstrus(pastureId, cowInfo, level, checkResult, isShow, firstTime)
+			newNeckRingEstrus.LastTime = lastEstrusDate
+			newNeckRingEstrus.ActiveTime = lastActiveDate.Format(model.LayoutTime)
 			newNeckRingEstrus.DayHigh = dayHigh
 			newNeckRingEstrus.MaxHigh = maxHigh
 			newNeckRingEstrus.IsPeak = isPeak
@@ -175,99 +187,68 @@ func (e *Entry) CowEstrusWarning(pastureId int64, xToday *XToday) (err error) {
 		}
 	}
 
-	if err = e.UpdateEstrusStartDate(pastureId, nowTime); err != nil {
-		zaplog.Error("UpdateEstrusStartDate", zap.Any("err", err))
-	}
 	return err
 }
 
-// UpdateEstrusStartDate 更新发情开始时间数据
-func (e *Entry) UpdateEstrusStartDate(pastureId int64, xToday time.Time) (err error) {
-	beforeEventEstrus := make([]*EstrusStartData, 0)
-	if err = e.DB.Model(new(model.NeckRingEstrus)).
-		Select("cow_id,MIN(estrus_start_date) as estrus_start_date").
-		Where("active_date BETWEEN  ? AND  ?", xToday.Add(-24*time.Hour).Format(model.LayoutTime), xToday.Format(model.LayoutTime)).
-		Where("estrus_start_date != ?", "").
-		Where("pasture_id = ?", pastureId).
-		Group("cow_id").Find(&beforeEventEstrus).Error; err != nil {
-		return xerr.WithStack(err)
-	}
-	if len(beforeEventEstrus) > 0 {
-		for _, v := range beforeEventEstrus {
-			if err = e.DB.Model(new(model.NeckRingEstrus)).
-				Where("cow_id = ?", v.CowId).
-				Where("active_date >= ? AND <= ?", xToday.Add(-1*time.Hour).Format(model.LayoutTime), xToday.Add(24*time.Hour).Format(model.LayoutTime)).
-				Update("estrus_start_date", v.EstrusStartDate).Error; err != nil {
-				zaplog.Error("UpdateEstrusStartDate", zap.Any("err", err))
-			}
-		}
+// FindCowEstrusFirstTime 查找牛只昨天是否有发情数据
+func (e *Entry) FindCowEstrusFirstTime(pastureId, cowId int64, xToday time.Time) *EstrusStartData {
+	firstTimeEventEstrus := &EstrusStartData{}
+	if err := e.DB.Model(new(model.NeckRingEstrus)).
+		Select("cow_id,MIN(STR_TO_DATE(first_time, '%Y-%m-%d %H:%i:%s')) as first_time").
+		Where("active_time BETWEEN ? AND ?",
+			fmt.Sprintf("%s 00:00:00", xToday.AddDate(0, 0, -1).Format(model.LayoutDate2)),
+			fmt.Sprintf("%s 23:59:59", xToday.Format(model.LayoutDate2)),
+		).Where("pasture_id = ?", pastureId).
+		Where("cow_id = ?", cowId).
+		First(&firstTimeEventEstrus).Error; err != nil {
+		return nil
 	}
-	return nil
-}
-
-// UpdateIsPeak 更新IsPeak是否是高峰字段 1 是 0 否
-func (e *Entry) UpdateIsPeak(pastureId int64, xToday time.Time) (err error) {
-	return nil
+	return firstTimeEventEstrus
 }
 
 // calculateCFT 计算cft值
 func calculateCFT(habit *model.NeckActiveHabit) (cft float32) {
-	cft = float32(habit.ChangeFilter) - float32(habit.ChangeAdjust) + 3
-	if habit.ChangeAdjust < 10 {
-		cft = float32(habit.ChangeFilter)
+	if habit.ChangeAdjust >= 10 {
+		cft = (float32(habit.ChangeFilter) - float32(habit.ChangeAdjust) + 3) * float32(habit.FilterCorrect) / 100
+	} else {
+		cft = float32(habit.ChangeFilter) * float32(habit.FilterCorrect) / 100
 	}
-	cft = cft * float32(habit.FilterCorrect) / 100
-	ruminaAdjust := float32(0)
+
 	switch {
 	case habit.RuminaFilter > MaxRuminaAdJust:
-		ruminaAdjust = float32(5)
+		cft -= float32(5)
 	case habit.RuminaFilter > 0:
-		ruminaAdjust = float32(habit.RuminaFilter) * 0.25
+		cft -= float32(habit.RuminaFilter) * 0.25
 	case habit.RuminaFilter < -MaxRuminaAdJust:
-		ruminaAdjust = -MaxRuminaAdJust * RumtoHeat
+		cft -= -MaxRuminaAdJust * RumtoHeat
 	default:
-		ruminaAdjust = float32(habit.RuminaFilter) * RumtoHeat
+		cft -= float32(habit.RuminaFilter) * RumtoHeat
 	}
-	cft -= ruminaAdjust
 	return cft
 }
 
 // calculateActiveLevel 计算活动量等级
 func calculateActiveLevel(cft float32, cowEstrus *CowEstrus, xToday *XToday) pasturePb.EstrusLevel_Kind {
-	activeLevel := pasturePb.EstrusLevel_High
 	if int32(cft)+cowEstrus.HadJust < xToday.ActiveMiddle {
-		activeLevel = pasturePb.EstrusLevel_Low
+		return pasturePb.EstrusLevel_Low
+	} else if int32(cft)+cowEstrus.HadJust >= xToday.ActiveHigh {
+		return pasturePb.EstrusLevel_Middle
+	} else {
+		return pasturePb.EstrusLevel_High
 	}
-
-	if int32(cft)+cowEstrus.HadJust >= xToday.ActiveHigh {
-		activeLevel = pasturePb.EstrusLevel_Middle
-	}
-	return activeLevel
 }
 
-// getResult 根据b3数据计算结果 0 1 2 3 -1 -2
+// getResult 根据b3数据计算结果
 func getResult(b3 *model.NeckRingEstrus, cft float32, cowEstrus *CowEstrus) pasturePb.CheckResult_Kind {
-	result := pasturePb.CheckResult_Invalid
-	if b3.CheckResult == pasturePb.CheckResult_Fail && b3.DayHigh > int32(cft)+cowEstrus.HadJust {
-		result = pasturePb.CheckResult_Fail
-	}
+	result := pasturePb.CheckResult_Pending
 
-	if b3.CheckResult == pasturePb.CheckResult_Overdue {
+	if b3.CheckResult == pasturePb.CheckResult_Correct {
 		result = pasturePb.CheckResult_Correct
 	}
-	return result
-}
 
-// sortHabitsByChangeFilter 根据change_filter排序
-func sortHabitsByChangeFilter(habits []*model.NeckActiveHabit) []*model.NeckActiveHabit {
-	sorted := make([]*model.NeckActiveHabit, len(habits))
-	copy(sorted, habits)
-	for i := range sorted {
-		for j := i + 1; j < len(sorted); j++ {
-			if sorted[i].ChangeFilter < sorted[j].ChangeFilter {
-				sorted[i], sorted[j] = sorted[j], sorted[i]
-			}
-		}
+	if b3.CheckResult == pasturePb.CheckResult_Fail && b3.DayHigh > int32(cft)+cowEstrus.HadJust {
+		result = pasturePb.CheckResult_Fail
 	}
-	return sorted
+
+	return result
 }

+ 0 - 0
module/crontab/neck_ring_handle.go → module/crontab/neck_ring_merge.go


+ 4 - 3
module/crontab/sql.go

@@ -56,7 +56,7 @@ func (e *Entry) GetBeforeThreeDaysCowEstrus(cowId int64, activeTime string) *mod
 		Select("MAX(max_high) as max_high,cow_id,MAX(day_high) as day_high").
 		Select("MAX(IF(check_result=1,3,check_result)) AS check_result").
 		Where("cow_id = ?", cowId).
-		Where("active_date >= ?", activeTime).
+		Where("active_time >= ?", activeTime).
 		First(neckRingEstrus).Error; err != nil {
 		return neckRingEstrus
 	}
@@ -78,12 +78,13 @@ func (e *Entry) GetTwoEstrus(pastureId, cowId int64, startActiveTime, endActiveT
 	return newCowEstrus
 }
 
-func (e *Entry) FindCowInfoByNeckRingNumber(neckRingNumber string) *model.Cow {
+func (e *Entry) FindCowInfoByCowId(cowId int64) *model.Cow {
 	res := &model.Cow{}
 	if err := e.DB.Model(new(model.Cow)).
-		Where("neck_ring_number = ?", neckRingNumber).
+		Where("id = ?", cowId).
 		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
 		First(res).Error; err != nil {
+		zaplog.Error("FindCowInfoByCowId", zap.Any("cowId", cowId), zap.Any("err", err))
 		return nil
 	}
 	return res

+ 2 - 570
util/util_test.go

@@ -508,574 +508,6 @@ func TestGetNeckRingActiveTimer(t *testing.T) {
 
 func Test_demo(t *testing.T) {
 
-	a := []int32{
-		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,
-		3207963,
-		3204259,
-		3207966,
-		2640,
-		3214316,
-		3205778,
-		3206897,
-		3207745,
-		3209052,
-		3208045,
-		211627,
-		3212873,
-		2100766,
-		9121950,
-		3206076,
-		3206438,
-		9466,
-		9121195,
-		9122044,
-		3209430,
-		3205599,
-		2100794,
-		3048,
-		9467,
-		3207480,
-		3216011,
-		9121725,
-		9120340,
-		9121597,
-		427,
-		3209387,
-		3209490,
-		3214311,
-		3206044,
-		211253,
-		3207553,
-		3215616,
-		211350,
-		3207551,
-		3205896,
-		417,
-		9121008,
-		3207694,
-		3209372,
-		3217873,
-		3207227,
-		3207568,
-		3210615,
-		3204769,
-		3216095,
-		9121338,
-		3209124,
-		211340,
-		3219695,
-		9121802,
-		3205517,
-		3210676,
-		9123325,
-		3204328,
-		9409,
-		211349,
-		3208860,
-		9121769,
-		3209221,
-		3210916,
-		3205880,
-		438,
-		3205557,
-		9421,
-		211229,
-		444,
-		9123260,
-		9121464,
-		3212818,
-		3204834,
-		3205408,
-		3207486,
-		498,
-		3206232,
-		3206315,
-		2100759,
-		9121955,
-		3204338,
-		3207606,
-		3208767,
-		450,
-		9123330,
-		9121278,
-		9121011,
-		9122280,
-		479,
-		434,
-		3207614,
-		2355,
-		211644,
-		453,
-		9121308,
-		3209449,
-		405,
-		3204240,
-		9120165,
-		9445,
-		9120456,
-		9123057,
-		471,
-		3206830,
-		464,
-		403,
-		2100749,
-		3218278,
-		3218600,
-		212168,
-		9470,
-		428,
-		3205448,
-		3209790,
-		3208163,
-		213134,
-		3207603,
-		3206394,
-		3204476,
-		9121569,
-		3206447,
-		3209456,
-		9120533,
-		3209044,
-		3214232,
-		3209337,
-		212193,
-		3216684,
-		3218450,
-		3207194,
-		3204853,
-		3205858,
-		3207922,
-		3204645,
-		212157,
-		3214707,
-		213126,
-		3219468,
-		9120766,
-		3218611,
-		3215948,
-		3211568,
-		9120227,
-		211348,
-		3212621,
-		3209898,
-		3207637,
-		9121071,
-		9123113,
-		3206491,
-		3209922,
-		9440,
-		3207075,
-		423,
-		3204875,
-		9121888,
-		3210395,
-		9120630,
-		9120214,
-		3208166,
-		211285,
-		3206880,
-		3209461,
-		3205597,
-		3216262,
-		3204942,
-		9123224,
-		3205918,
-		3204889,
-		3209047,
-		3207024,
-		3207277,
-		3207699,
-		3205771,
-		9500,
-		3204450,
-		3205495,
-		9483,
-		3209876,
-		3205533,
-		3216075,
-		9469,
-		3209827,
-		9122454,
-		413,
-		3216308,
-		3219301,
-		3210042,
-		3205064,
-		211390,
-		9121305,
-		3218596,
-		3204955,
-		3215274,
-		212171,
-		3209460,
-		3211376,
-		3213812,
-		3205184,
-		3209287,
-		3211769,
-		3205926,
-		3216585,
-		3213332,
-		3209340,
-		9123175,
-		3205843,
-		3207663,
-		3210829,
-		3209481,
-		9450,
-		9463,
-		3209763,
-		3215627,
-		9121424,
-		3212746,
-		3218533,
-		3209072,
-		3207359,
-		3205888,
-		3214228,
-		3204884,
-		3218613,
-		3209352,
-		3208192,
-		3216211,
-		3211454,
-		3217082,
-		3212728,
-		3206984,
-		3217750,
-		3213406,
-		3206305,
-		9122130,
-		9121695,
-		9492,
-		3207856,
-		3218263,
-		9121058,
-		9123309,
-		9122466,
-		9122287,
-		9120614,
-		3084,
-		3205559,
-		3205840,
-		9121444,
-		9121777,
-		3209308,
-		9122313,
-		9121672,
-		3210180,
-		3207645,
-		3206419,
-		9413,
-		211576,
-		3209201,
-		2601,
-		3211708,
-		3206969,
-		3206871,
-		3210430,
-		211674,
-		9122441,
-		3214386,
-		3206927,
-		3209332,
-		9462,
-		3206430,
-		3207485,
-		3204519,
-		3216214,
-		9123371,
-		9120847,
-		9123355,
-		211690,
-		3210362,
-		3218862,
-		3213687,
-		3066,
-		3209787,
-		9120359,
-		9468,
-		2315,
-		3207031,
-		211353,
-		211250,
-		3207688,
-		9122447,
-		3218688,
-		445,
-		3205848,
-		3214915,
-		3208866,
-		1739,
-		3204990,
-		2100716,
-		212130,
-		3204214,
-		3208985,
-		211388,
-		9123166,
-		3208856,
-		211648,
-		2311,
-		3204411,
-		3217860,
-		9523,
-		9524,
-		3209134,
-		3209212,
-		211630,
-		9123151,
-		3207375,
-		441,
-		9525,
-		3205815,
-		3205527,
-		3215344,
-		3207185,
-		211332,
-		3217466,
-		9526,
-		1783,
-		9122414,
-		3207617,
-		212150,
-		3204248,
-		3216316,
-		3209535,
-		3206873,
-		3208974,
-		9406,
-		9122407,
-		9121925,
-		2351,
-		3214481,
-		3204826,
-		3205906,
-		3205109,
-		3209014,
-		211240,
-		3070,
-		474,
-		3204667,
-		3205511,
-		409,
-		3209061,
-		3205074,
-		3206009,
-		9123010,
-		3207536,
-		3219231,
-		3207198,
-		9475,
-		9423,
-		9121871,
-		3204643,
-		3205471,
-		3206095,
-		9121981,
-		9120835,
-		3206427,
-		3218217,
-		3207493,
-		2100732,
-		3204886,
-		3208174,
-		9486,
-		2100772,
-		3209419,
-		3207087,
-		2328,
-		3207371,
-		3210597,
-		3206231,
-		3206931,
-		3204236,
-		3207411,
-		3206374,
-		3206452,
-		3207472,
-		9429,
-		3218802,
-		211381,
-		9474,
-		3204420,
-		3207026,
-		3206124,
-		3209608,
-		3209330,
-		3209485,
-		3216593,
-		3205921,
-		2375,
-		3204818,
-		3215544,
-		3213632,
-		3216924,
-		3204395,
-		3207111,
-		3206961,
-		212169,
-		9123027,
-		2100744,
-		9520,
-		3208708,
-		3214104,
-		3206329,
-		9512,
-		3211187,
-		3207674,
-		3206004,
-		3207748,
-		3209328,
-		3209033,
-		3205601,
-		3205776,
-		9438,
-		3205269,
-		3204664,
-		9514,
-		3204897,
-		9446,
-		3208827,
-		3209611,
-		3208050,
-		9501,
-		9121120,
-		3213788,
-		9121699,
-		3204409,
-		3210073,
-		3207546,
-		2100758,
-		3206082,
-		3208975,
-		9122051,
-		9518,
-		3207751,
-		9408,
-		3206437,
-		3207343,
-		3207021,
-		3216998,
-		3205349,
-		3214744,
-		3205905,
-		3212646,
-		3209740,
-		3206239,
-		3207473,
-		3207236,
-		3209730,
-		3204360,
-		3206895,
-		9120696,
-		3204901,
-		9508,
-		3207935,
-		3213977,
-		3214166,
-		448,
-		3205893,
-		3212052,
-		3205552,
-		3211112,
-		3213551,
-		3217077,
-		3206322,
-		9465,
-		3208807,
-		3205211,
-		3215051,
-		3207121,
-		3215725,
-		3207229,
-		3219426,
-		3213345,
-		3217541,
-		3216876,
-		3215675,
-		3214245,
-		3207012,
-		3218806,
-		3217024,
-		3212486,
-		3207620,
-		3211045,
-		3213712,
-		3215268,
-		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}
-
-	value := ``
-	for _, v := range a {
-		value += fmt.Sprintf(`"%d",`, v)
-	}
-
-	fmt.Println(value)
+	var max time.Time
+	fmt.Println(max)
 }