123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- package crontab
- import (
- "fmt"
- "kpt-pasture/model"
- "sort"
- "gitee.com/xuyiping_admin/pkg/logger/zaplog"
- "go.uber.org/zap"
- )
- func (e *Entry) UpdatePenBehavior() error {
- pastureList := e.FindPastureList()
- if pastureList == nil || len(pastureList) == 0 {
- return nil
- }
- for _, pasture := range pastureList {
- conf, err := e.GetSystemNeckRingConfigure(pasture.Id, model.MaxPenBehavior)
- if err != nil {
- zaplog.Error("UpdatePenBehavior", zap.Any("pasture", pasture), zap.Any("err", err))
- continue
- }
- e.PenBehavior(pasture.Id, conf.Value)
- }
- return nil
- }
- // PenBehavior 栏舍行为曲线
- func (e *Entry) PenBehavior(pastureId, maxPenBehavior int64) {
- // 1. 获取颈环原始数据
- neckRingOriginalList, err := e.getNeckRingOriginalList(pastureId, maxPenBehavior)
- if err != nil {
- zaplog.Error("PenBehavior", zap.Any("pastureId", pastureId), zap.Any("maxPenBehavior", maxPenBehavior), zap.Any("err", err))
- return
- }
- if len(neckRingOriginalList) <= 0 {
- return
- }
- // 2. 获取牛只信息
- cowMap, err := e.getCowMap(pastureId, neckRingOriginalList)
- if err != nil {
- zaplog.Error("PenBehavior", zap.Any("pastureId", pastureId), zap.Any("neckRingOriginalList", neckRingOriginalList), zap.Any("err", err))
- return
- }
- // 3. 处理栏舍行为数据
- penData := e.processPenBehaviorData(neckRingOriginalList, cowMap)
- // 4. 计算平均值和百分比
- e.calculateAveragesAndRates(penData)
- // 5. 保存数据
- if err = e.savePenBehaviorData(penData); err != nil {
- zaplog.Error("PenBehavior", zap.Any("penData", penData), zap.Any("err", err))
- return
- }
- sort.Slice(neckRingOriginalList, func(i, j int) bool {
- return neckRingOriginalList[i].Id > neckRingOriginalList[j].Id
- })
- if err = e.UpdateSystemNeckRingConfigure(pastureId, model.MaxPenBehavior, neckRingOriginalList[0].Id); err != nil {
- zaplog.Error("PenBehavior", zap.Any("UpdateSystemNeckRingConfigure", err), zap.Any("neckRingOriginalList", neckRingOriginalList))
- }
- }
- // getNeckRingOriginalList 获取颈环原始数据
- func (e *Entry) getNeckRingOriginalList(pastureId, maxPenBehavior int64) ([]*model.NeckRingOriginal, error) {
- var neckRingOriginalList []*model.NeckRingOriginal
- if err := e.DB.Model(new(model.NeckRingOriginal)).
- Where("id > ? AND pasture_id = ?", maxPenBehavior, pastureId).
- Order("active_date,neck_ring_number,frameid").
- Limit(int(defaultLimit)).
- Find(&neckRingOriginalList).Error; err != nil {
- return nil, err
- }
- return neckRingOriginalList, nil
- }
- // getCowMap 获取牛只信息映射
- func (e *Entry) getCowMap(pastureId int64, neckRingOriginalList []*model.NeckRingOriginal) (map[string]*model.Cow, error) {
- // 提取牛只ID
- neckRingNumberList := make([]string, 0, len(neckRingOriginalList))
- for _, v := range neckRingOriginalList {
- neckRingNumberList = append(neckRingNumberList, v.NeckRingNumber)
- }
- // 获取牛只信息
- cowInfoList, err := e.GetCowByNeckRingNumbers(pastureId, neckRingNumberList)
- if err != nil {
- return nil, err
- }
- // 构建牛只信息映射
- cowMap := make(map[string]*model.Cow, len(cowInfoList))
- for _, v := range cowInfoList {
- if v.NeckRingNumber == "" {
- continue
- }
- cowMap[v.NeckRingNumber] = v
- }
- return cowMap, nil
- }
- // processPenBehaviorData 处理栏舍行为数据
- func (e *Entry) processPenBehaviorData(neckRingOriginalList []*model.NeckRingOriginal, cowMap map[string]*model.Cow) map[string]*model.PenBehaviorData {
- penData := make(map[string]*model.PenBehaviorData, len(neckRingOriginalList))
- for _, v := range neckRingOriginalList {
- cowInfo, ok := cowMap[v.NeckRingNumber]
- if !ok {
- zaplog.Error("PenBehavior", zap.Any("neckRingNumber", v.NeckRingNumber))
- continue
- }
- key := fmt.Sprintf("%s_%d_%d", v.ActiveDate, cowInfo.PenId, v.Frameid)
- if data, exists := penData[key]; exists {
- data.CowCount++
- data.AvgHigh += v.High
- data.SumRumina += ifThenElse(v.Rumina >= 8, 1, 0)
- data.SumIntake += ifThenElse(v.Intake >= 8, 1, 0)
- data.SumRest += ifThenElse(v.Inactive >= 8, 1, 0)
- data.SumGasp += ifThenElse(v.Gasp >= 8, 1, 0)
- } else {
- penData[key] = &model.PenBehaviorData{
- PastureId: cowInfo.PastureId,
- PenId: cowInfo.PenId,
- PenName: cowInfo.PenName,
- HeatDate: v.ActiveDate,
- Frameid: v.Frameid,
- CowCount: 1,
- AvgHigh: v.High,
- }
- }
- }
- return penData
- }
- // calculateAveragesAndRates 计算平均值和百分比
- func (e *Entry) calculateAveragesAndRates(penData map[string]*model.PenBehaviorData) {
- for _, data := range penData {
- // 计算平均值
- data.AvgHigh = data.AvgHigh / data.CowCount
- // 计算百分比
- if data.CowCount > 0 {
- data.RuminaRate = int32(float64(data.SumRumina) / float64(data.CowCount) * 100)
- data.IntakeRate = int32(float64(data.SumIntake) / float64(data.CowCount) * 100)
- data.RestRate = int32(float64(data.SumRest) / float64(data.CowCount) * 100)
- data.GaspRate = int32(float64(data.SumGasp) / float64(data.CowCount) * 100)
- }
- }
- }
- // savePenBehaviorData 保存栏舍行为数据
- func (e *Entry) savePenBehaviorData(penData map[string]*model.PenBehaviorData) error {
- for _, data := range penData {
- // 构建活动时间
- activeTime := e.calculateActiveTime(data.HeatDate, data.Frameid)
- // 构建保存数据
- penBehavior := &model.PenBehavior{
- PastureId: data.PastureId,
- HeatDate: data.HeatDate,
- ActiveTime: activeTime,
- PenId: data.PenId,
- PenName: data.PenName,
- CowCount: data.CowCount,
- AvgHigh: data.AvgHigh,
- SumRumina: data.SumRumina,
- SumIntake: data.SumIntake,
- SumRest: data.SumRest,
- SumGasp: data.SumGasp,
- RuminaRate: data.RuminaRate,
- IntakeRate: data.IntakeRate,
- RestRate: data.RestRate,
- GaspRate: data.GaspRate,
- }
- // 使用 Upsert 操作
- if err := e.DB.Model(new(model.PenBehavior)).
- Where("pasture_id = ? AND heat_date = ? AND pen_id = ? AND active_time = ?",
- penBehavior.PastureId, penBehavior.HeatDate, penBehavior.PenId, penBehavior.ActiveTime).
- Assign(map[string]interface{}{
- "cow_count": penBehavior.CowCount,
- "avg_high": penBehavior.AvgHigh,
- "sum_rumina": penBehavior.SumRumina,
- "sum_intake": penBehavior.SumIntake,
- "sum_rest": penBehavior.SumRest,
- "sum_gasp": penBehavior.SumGasp,
- "rumina_rate": penBehavior.RuminaRate,
- "intake_rate": penBehavior.IntakeRate,
- "rest_rate": penBehavior.RestRate,
- "gasp_rate": penBehavior.GaspRate,
- }).
- FirstOrCreate(penBehavior).Error; err != nil {
- return err
- }
- }
- return nil
- }
- // calculateActiveTime 计算活动时间
- func (e *Entry) calculateActiveTime(heatDate string, frameid int32) string {
- // 计算小时和分钟
- hour := (frameid / 10) * 2
- minute := (frameid%10)*20 - 1
- // 构建时间字符串
- return fmt.Sprintf("%s %02d:%02d", heatDate, hour, minute)
- }
- // ifThenElse 条件判断函数
- func ifThenElse(condition bool, a, b int32) int32 {
- if condition {
- return a
- }
- return b
- }
|