| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 | 
							- package crontab
 
- import (
 
- 	"fmt"
 
- 	"kpt-pasture/model"
 
- 	"kpt-pasture/util"
 
- 	"time"
 
- 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 
- 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
 
- 	"go.uber.org/zap"
 
- 	"gitee.com/xuyiping_admin/pkg/xerr"
 
- )
 
- const (
 
- 	MaxRuminaAdJust = 20
 
- 	XAdjust21       = 15
 
- 	XAdjust42       = 10
 
- 	RumtoHeat       = 0.5
 
- 	MinCalvingAge   = 20
 
- 	MinLact         = 0
 
- 	NormalChangJust = 10
 
- 	B48             = 48
 
- )
 
- func (e *Entry) UpdateCowEstrus() (err error) {
 
- 	pastureList := e.FindPastureList()
 
- 	if pastureList == nil || len(pastureList) == 0 {
 
- 		return nil
 
- 	}
 
- 	for _, pasture := range pastureList {
 
- 		if err = e.EntryCowEstrus(pasture.Id); err != nil {
 
- 			zaplog.Error("EntryCrontab", zap.Any("PastureUpdateCowEstrus", err), zap.Any("pasture", pasture))
 
- 		}
 
- 		zaplog.Info("PastureUpdateCowEstrus-success", zap.Any("pasture", pasture.Id))
 
- 	}
 
- 	return nil
 
- }
 
- func (e *Entry) EntryCowEstrus(pastureId int64) (err error) {
 
- 	xToday := &XToday{}
 
- 	systemConfigureList, err := e.FindSystemNeckRingConfigure(pastureId)
 
- 	if err != nil {
 
- 		return xerr.WithStack(err)
 
- 	}
 
- 	if systemConfigureList == nil || len(systemConfigureList) == 0 {
 
- 		return nil
 
- 	}
 
- 	for _, v := range systemConfigureList {
 
- 		switch v.Name {
 
- 		case model.ActiveLow:
 
- 			xToday.ActiveLow = int32(v.Value)
 
- 		case model.ActiveMiddle:
 
- 			xToday.ActiveMiddle = int32(v.Value)
 
- 		case model.ActiveHigh:
 
- 			xToday.ActiveHigh = int32(v.Value)
 
- 		}
 
- 	}
 
- 	nowTime := time.Now().Local()
 
- 	e.CowEstrusWarning(pastureId, xToday, nowTime)
 
- 	e.UpdateNewNeckRingEstrus(pastureId, xToday, nowTime)
 
- 	return nil
 
- }
 
- // CowEstrusWarning 发情预警
 
- func (e *Entry) CowEstrusWarning(pastureId int64, xToday *XToday, nowTime time.Time) {
 
- 	cft := xToday.ActiveLow - XAdjust21
 
- 	neckActiveHabitList := make([]*model.NeckActiveHabit, 0)
 
- 	if err := e.DB.Model(new(model.NeckActiveHabit)).
 
- 		Where("heat_date BETWEEN ? AND ?", nowTime.AddDate(0, 0, -1).Format(model.LayoutDate2), nowTime.Format(model.LayoutDate2)).
 
- 		Where("pasture_id = ?", pastureId).
 
- 		Where("filter_high > 0 AND change_filter > ?", model.DefaultChangeFilter).
 
- 		Where("cow_id > ?", 0).
 
- 		Where("cft >= ?", cft).
 
- 		Where(e.DB.Where("calving_age >= ?", MinCalvingAge).Or("lact = ?", MinLact)). // 排除产后20天内的发情牛
 
- 		Order("cow_id").
 
- 		Find(&neckActiveHabitList).Error; err != nil {
 
- 		zaplog.Error("CowEstrusWarning", zap.Any("Find", err))
 
- 		return
 
- 	}
 
- 	neckActiveHabitMap := make(map[int64][]*model.NeckActiveHabit)
 
- 	for _, habit := range neckActiveHabitList {
 
- 		zaplog.Info("CowEstrusWarning", zap.Any("habit", habit))
 
- 		if neckActiveHabitMap[habit.CowId] == nil {
 
- 			neckActiveHabitMap[habit.CowId] = make([]*model.NeckActiveHabit, 0)
 
- 		}
 
- 		neckActiveHabitMap[habit.CowId] = append(neckActiveHabitMap[habit.CowId], habit)
 
- 	}
 
- 	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
 
- 		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)
 
- 		maxHigh := int32(0)
 
- 		lastActiveDate := time.Time{}
 
- 		for _, habit := range cowHabitList {
 
- 			if habit.Cft > maxCft {
 
- 				maxCft = habit.Cft
 
- 			}
 
- 			if habit.FilterHigh > maxHigh {
 
- 				maxHigh = habit.FilterHigh
 
- 			}
 
- 			// 获取最新的 CreateTime
 
- 			activeTimeParse, _ := util.TimeParseLocal(model.LayoutTime, habit.ActiveTime)
 
- 			if activeTimeParse.After(lastActiveDate) {
 
- 				lastActiveDate = activeTimeParse
 
- 			}
 
- 		}
 
- 		b48 := float64(0)
 
- 		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)+cow21Estrus.HadJust > xToday.ActiveLow {
 
- 			level := calculateActiveLevel(maxCft, cow21Estrus, xToday)
 
- 			cowInfo, err := e.GetCowById(pastureId, cowId)
 
- 			if err != nil || cowInfo == nil {
 
- 				zaplog.Error("CowEstrusWarning", zap.Any("FindCowInfoByCowId", cowId))
 
- 				continue
 
- 			}
 
- 			isShow := pasturePb.IsShow_Ok
 
- 			if cowInfo != nil && cowInfo.IsPregnant == pasturePb.IsShow_Ok && level == pasturePb.EstrusLevel_Low {
 
- 				isShow = pasturePb.IsShow_No
 
- 			}
 
- 			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),
 
- 				zap.Any("b48", b48),
 
- 				zap.Any("checkResult", checkResult),
 
- 				zap.Any("isShow", isShow),
 
- 				zap.Any("isPeak", isPeak),
 
- 				zap.Any("lastEstrusDate", lastEstrusDate),
 
- 				zap.Any("activeDate", lastActiveDate),
 
- 				zap.Any("dayHigh", dayHigh),
 
- 				zap.Any("maxCft", maxCft),
 
- 				zap.Any("before3Data", before3Data),
 
- 				zap.Any("cowEstrus", cow21Estrus),
 
- 				zap.Any("cowInfo", cowInfo),
 
- 				zap.Any("cowHabitList", cowHabitList),
 
- 				zap.Any("pasture", pastureId),
 
- 			)
 
- 			newNeckRingEstrus := model.NewNeckRingEstrus(pastureId, cowInfo, level, int32(maxCft), checkResult, isShow)
 
- 			newNeckRingEstrus.LastTime = lastEstrusDate
 
- 			newNeckRingEstrus.ActiveTime = activeTime
 
- 			newNeckRingEstrus.DayHigh = dayHigh
 
- 			newNeckRingEstrus.MaxHigh = maxHigh
 
- 			newNeckRingEstrus.IsPeak = isPeak
 
- 			neckRingEstrusList = append(neckRingEstrusList, newNeckRingEstrus)
 
- 		}
 
- 	}
 
- 	zaplog.Info("CowEstrusWarning", zap.Any("neckRingEstrusList", neckRingEstrusList))
 
- 	if len(neckRingEstrusList) > 0 {
 
- 		if err := e.DB.Model(new(model.NeckRingEstrus)).
 
- 			Create(neckRingEstrusList).Error; err != nil {
 
- 			zaplog.Error("CowEstrusWarningNew", zap.Any("eventEstrusList", neckRingEstrusList), zap.Any("err", err))
 
- 		}
 
- 	}
 
- }
 
- // UpdateNewNeckRingEstrus 更新牛只首次发情时间和是否是高峰期
 
- func (e *Entry) UpdateNewNeckRingEstrus(pastureId int64, xToday *XToday, nowTime time.Time) {
 
- 	e.UpdateEstrusFirstTime1(pastureId)
 
- 	e.UpdateEstrusIsPeak(pastureId)
 
- 	e.UpdateEstrusFirstTime2(pastureId, xToday, nowTime)
 
- 	e.UpdateEstrusFirstTime3(pastureId, nowTime)
 
- }
 
- // UpdateEstrusFirstTime1 更新牛只首次发情时间
 
- func (e *Entry) UpdateEstrusFirstTime1(pastureId int64) {
 
- 	// 获取牛只首次发情时间为空的记录
 
- 	neckRingEstrusList := e.FindNeckRingEstrusByFirstTimeEmpty(pastureId)
 
- 	for _, v := range neckRingEstrusList {
 
- 		cowEstrusStartData := e.FindCowEstrusFirstTime1(pastureId, v.CowId)
 
- 		if cowEstrusStartData != nil && cowEstrusStartData.FirstTime != "" {
 
- 			if err := e.DB.Model(new(model.NeckRingEstrus)).
 
- 				Where("id = ?", v.Id).
 
- 				Update("first_time", cowEstrusStartData.FirstTime).Error; err != nil {
 
- 				zaplog.Error("UpdateEstrusFirstTime1",
 
- 					zap.Any("v", v),
 
- 					zap.Any("err", err),
 
- 					zap.Any("cowEstrusStartData", cowEstrusStartData),
 
- 				)
 
- 			}
 
- 		}
 
- 	}
 
- }
 
- func (e *Entry) UpdateEstrusFirstTime2(pastureId int64, xToday *XToday, nowTime time.Time) {
 
- 	neckRingEstrusList := e.FindNeckRingEstrusByFirstTimeEmpty(pastureId)
 
- 	for _, v := range neckRingEstrusList {
 
- 		// 获取牛只最近12小时内的活动记录
 
- 		activeTime, _ := util.TimeParseLocal(model.LayoutTime, v.ActiveTime)
 
- 		startTime := activeTime.Add(-12 * time.Hour)
 
- 		// 查询符合条件的活动记录
 
- 		var firstTime string
 
- 		if err := e.DB.Model(new(model.NeckActiveHabit)).
 
- 			Select("MIN(active_time) as first_time").
 
- 			Where("pasture_id = ?", pastureId).
 
- 			Where("cow_id = ?", v.CowId).
 
- 			Where("heat_date = ?", activeTime.Format(model.LayoutDate2)).
 
- 			Where("active_time BETWEEN ? AND ?", startTime.Format(model.LayoutTime), v.ActiveTime).
 
- 			Where("cft >= ?", xToday.ActiveLow).
 
- 			Scan(&firstTime).Error; err != nil {
 
- 			zaplog.Error("UpdateEstrusFirstTime2", zap.Any("FindFirstTime", err))
 
- 			continue
 
- 		}
 
- 		if firstTime != "" {
 
- 			if err := e.DB.Model(new(model.NeckRingEstrus)).
 
- 				Where("id = ?", v.Id).
 
- 				Update("first_time", firstTime).Error; err != nil {
 
- 				zaplog.Error("UpdateEstrusFirstTime2", zap.Any("Update", err))
 
- 			}
 
- 		}
 
- 	}
 
- }
 
- func (e *Entry) UpdateEstrusFirstTime3(pastureId int64, xToday time.Time) {
 
- 	neckRingEstrusList := e.FindNeckRingEstrusByFirstTimeEmpty(pastureId)
 
- 	for _, v := range neckRingEstrusList {
 
- 		activeTime, _ := util.TimeParseLocal(model.LayoutTime, v.ActiveTime)
 
- 		if activeTime.After(xToday.AddDate(0, 0, -2)) {
 
- 			if err := e.DB.Model(new(model.NeckRingEstrus)).
 
- 				Where("id = ?", v.Id).
 
- 				Update("first_time", v.ActiveTime).Error; err != nil {
 
- 				zaplog.Error("UpdateEstrusFirstTime1", zap.Any("v", v), zap.Any("err", err))
 
- 			}
 
- 		}
 
- 	}
 
- }
 
- func (e *Entry) UpdateEstrusIsPeak(pastureId int64) {
 
- 	neckRingEstrusList := make([]*model.NeckRingEstrus, 0)
 
- 	if err := e.DB.Model(new(model.NeckRingEstrus)).
 
- 		Where("first_time >= ?", time.Now().Local().AddDate(0, 0, -3).Format(model.LayoutTime)).
 
- 		Where("active_time != ?", "").
 
- 		Where("pasture_id = ?", pastureId).
 
- 		Order("cow_id,first_time,active_time ASC").
 
- 		Find(&neckRingEstrusList).Error; err != nil {
 
- 		zaplog.Error("UpdateEstrusIsPeak", zap.Any("Find", err))
 
- 	}
 
- 	if len(neckRingEstrusList) <= 0 {
 
- 		return
 
- 	}
 
- 	neckRingEstrusFirstMap := make(map[string][]*model.NeckRingEstrus)
 
- 	for _, v := range neckRingEstrusList {
 
- 		if neckRingEstrusFirstMap[fmt.Sprintf("%s_%d", v.FirstTime, v.CowId)] == nil {
 
- 			neckRingEstrusFirstMap[fmt.Sprintf("%s_%d", v.FirstTime, v.CowId)] = make([]*model.NeckRingEstrus, 0)
 
- 		}
 
- 		neckRingEstrusFirstMap[fmt.Sprintf("%s_%d", v.FirstTime, v.CowId)] = append(neckRingEstrusFirstMap[fmt.Sprintf("%s_%d", v.FirstTime, v.CowId)], v)
 
- 	}
 
- 	nowTime := time.Now().Local()
 
- 	peakIsShow := make([]int64, 0)
 
- 	peakIsNo := make([]int64, 0)
 
- 	for _, estrusItems := range neckRingEstrusFirstMap {
 
- 		eLen := len(estrusItems)
 
- 		if eLen <= 0 {
 
- 			continue
 
- 		}
 
- 		// 判断是否是高峰期,和当前时间相比,如果超过2个小就是高峰期
 
- 		lastItem := estrusItems[eLen-1]
 
- 		lastActiveTime, err := time.Parse(model.LayoutTime, lastItem.ActiveTime)
 
- 		if err != nil {
 
- 			zaplog.Error("UpdateEstrusIsPeak", zap.Any("Parse", err), zap.Any("lastItem", lastItem))
 
- 			continue
 
- 		}
 
- 		sub := nowTime.Sub(lastActiveTime.Local()).Hours()
 
- 		if sub > 2 {
 
- 			peakIsShow = append(peakIsShow, lastItem.Id)
 
- 			for i := 0; i < eLen-1; i++ {
 
- 				peakIsNo = append(peakIsNo, estrusItems[i].Id)
 
- 			}
 
- 		} else {
 
- 			peakIsNo = append(peakIsNo, lastItem.Id)
 
- 		}
 
- 	}
 
- 	zaplog.Info("UpdateEstrusIsPeak",
 
- 		zap.Any("pastureId", pastureId),
 
- 		zap.Any("peakIsShow", peakIsShow),
 
- 		zap.Any("peakIsNo", peakIsNo),
 
- 	)
 
- 	if len(peakIsShow) > 0 {
 
- 		if err := e.DB.Model(new(model.NeckRingEstrus)).
 
- 			Where("id IN ?", peakIsShow).
 
- 			Where("pasture_id = ?", pastureId).
 
- 			Update("is_peak", pasturePb.IsShow_Ok).Error; err != nil {
 
- 			zaplog.Error("UpdateEstrusIsPeak", zap.Any("Update", err))
 
- 		}
 
- 	}
 
- 	if len(peakIsNo) > 0 {
 
- 		if err := e.DB.Model(new(model.NeckRingEstrus)).
 
- 			Where("id IN ?", peakIsNo).
 
- 			Where("pasture_id = ?", pastureId).
 
- 			Update("is_peak", pasturePb.IsShow_No).Error; err != nil {
 
- 			zaplog.Error("UpdateEstrusIsPeak", zap.Any("Update", err))
 
- 		}
 
- 	}
 
- }
 
- // FindCowEstrusFirstTime1 查找牛只昨天是否有发情数据
 
- func (e *Entry) FindCowEstrusFirstTime1(pastureId, cowId int64) *EstrusStartData {
 
- 	firstTimeEventEstrus := &EstrusStartData{}
 
- 	nowTime := time.Now().Local()
 
- 	startDate := fmt.Sprintf("%s 00:00:00", nowTime.AddDate(0, 0, -1).Format(model.LayoutDate2))
 
- 	endDate := fmt.Sprintf("%s 23:59:59", nowTime.Format(model.LayoutDate2))
 
- 	if err := e.DB.Model(new(model.NeckRingEstrus)).
 
- 		Select("cow_id,first_time").
 
- 		Where("active_time BETWEEN ? AND ?", startDate, endDate).
 
- 		Where("pasture_id = ?", pastureId).
 
- 		Where("cow_id = ?", cowId).
 
- 		Order("first_time ASC").
 
- 		First(&firstTimeEventEstrus).Error; err != nil {
 
- 		return nil
 
- 	}
 
- 	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 {
 
- 		cft = (float32(habit.ChangeFilter) - float32(habit.ChangeAdjust) + 3) * float32(habit.FilterCorrect) / 100
 
- 	} else {
 
- 		cft = float32(habit.ChangeFilter) * float32(habit.FilterCorrect) / 100
 
- 	}
 
- 	switch {
 
- 	case habit.RuminaFilter > MaxRuminaAdJust:
 
- 		cft -= float32(5)
 
- 	case habit.RuminaFilter > 0:
 
- 		cft -= float32(habit.RuminaFilter) * 0.25
 
- 	case habit.RuminaFilter < -MaxRuminaAdJust:
 
- 		cft -= -MaxRuminaAdJust * RumtoHeat
 
- 	default:
 
- 		cft -= float32(habit.RuminaFilter) * RumtoHeat
 
- 	}
 
- 	return cft
 
- }
 
- // calculateActiveLevel 计算活动量等级
 
- func calculateActiveLevel(cft float32, cowEstrus *CowEstrus, xToday *XToday) pasturePb.EstrusLevel_Kind {
 
- 	if int32(cft)+cowEstrus.HadJust < xToday.ActiveMiddle {
 
- 		return pasturePb.EstrusLevel_Low
 
- 	} else if int32(cft)+cowEstrus.HadJust >= xToday.ActiveHigh {
 
- 		return pasturePb.EstrusLevel_Middle
 
- 	} else {
 
- 		return pasturePb.EstrusLevel_High
 
- 	}
 
- }
 
- // getResult 根据b3数据计算结果
 
- func getResult(b3 *model.NeckRingEstrus, cft float32, cowEstrus *CowEstrus) pasturePb.CheckResult_Kind {
 
- 	result := pasturePb.CheckResult_Pending
 
- 	if b3.CheckResult == pasturePb.CheckResult_Correct {
 
- 		result = pasturePb.CheckResult_Correct
 
- 	}
 
- 	if b3.CheckResult == pasturePb.CheckResult_Fail && b3.DayHigh > int32(cft)+cowEstrus.HadJust {
 
- 		result = pasturePb.CheckResult_Fail
 
- 	}
 
- 	return result
 
- }
 
 
  |