pen_behavior.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package crontab
  2. import (
  3. "fmt"
  4. "kpt-pasture/model"
  5. "sort"
  6. "time"
  7. "gitee.com/xuyiping_admin/pkg/logger/zaplog"
  8. "go.uber.org/zap"
  9. )
  10. func (e *Entry) UpdatePenBehavior() error {
  11. pastureList := e.FindPastureList()
  12. if pastureList == nil || len(pastureList) == 0 {
  13. return nil
  14. }
  15. for _, pasture := range pastureList {
  16. conf, err := e.GetSystemNeckRingConfigure(pasture.Id, model.MaxPenBehavior)
  17. if err != nil {
  18. zaplog.Error("UpdatePenBehavior", zap.Any("pasture", pasture), zap.Any("err", err))
  19. continue
  20. }
  21. e.PenBehavior(pasture.Id, conf.Value)
  22. }
  23. return nil
  24. }
  25. // PenBehavior 栏舍行为曲线
  26. func (e *Entry) PenBehavior(pastureId, maxPenBehavior int64) {
  27. // 1. 获取颈环原始数据
  28. neckRingOriginalList, err := e.getNeckRingOriginalList(pastureId, maxPenBehavior)
  29. if err != nil {
  30. zaplog.Error("PenBehavior", zap.Any("pastureId", pastureId), zap.Any("maxPenBehavior", maxPenBehavior), zap.Any("err", err))
  31. return
  32. }
  33. if len(neckRingOriginalList) <= 0 {
  34. return
  35. }
  36. // 2. 获取牛只信息
  37. cowMap, err := e.getCowMap(pastureId, neckRingOriginalList)
  38. if err != nil {
  39. zaplog.Error("PenBehavior", zap.Any("pastureId", pastureId), zap.Any("neckRingOriginalList", neckRingOriginalList), zap.Any("err", err))
  40. return
  41. }
  42. // 3. 处理栏舍行为数据
  43. penData := e.processPenBehaviorData(neckRingOriginalList, cowMap)
  44. // 4. 计算平均值和百分比
  45. e.calculateAveragesAndRates(penData)
  46. // 5. 保存数据
  47. if err = e.savePenBehaviorData(penData); err != nil {
  48. zaplog.Error("PenBehavior", zap.Any("penData", penData), zap.Any("err", err))
  49. return
  50. }
  51. sort.Slice(neckRingOriginalList, func(i, j int) bool {
  52. return neckRingOriginalList[i].Id > neckRingOriginalList[j].Id
  53. })
  54. if err = e.UpdateSystemNeckRingConfigure(pastureId, model.MaxPenBehavior, neckRingOriginalList[0].Id); err != nil {
  55. zaplog.Error("PenBehavior", zap.Any("UpdateSystemNeckRingConfigure", err), zap.Any("neckRingOriginalList", neckRingOriginalList))
  56. }
  57. }
  58. // getNeckRingOriginalList 获取颈环原始数据
  59. func (e *Entry) getNeckRingOriginalList(pastureId, maxPenBehavior int64) ([]*model.NeckRingOriginal, error) {
  60. var neckRingOriginalList []*model.NeckRingOriginal
  61. if err := e.DB.Model(new(model.NeckRingOriginal)).
  62. Where("id > ? AND pasture_id = ?", maxPenBehavior, pastureId).
  63. Order("active_date,neck_ring_number,frameid").
  64. Limit(int(defaultLimit)).
  65. Find(&neckRingOriginalList).Error; err != nil {
  66. return nil, err
  67. }
  68. return neckRingOriginalList, nil
  69. }
  70. // getCowMap 获取牛只信息映射
  71. func (e *Entry) getCowMap(pastureId int64, neckRingOriginalList []*model.NeckRingOriginal) (map[string]*model.Cow, error) {
  72. // 提取牛只ID
  73. neckRingNumberList := make([]string, 0, len(neckRingOriginalList))
  74. for _, v := range neckRingOriginalList {
  75. neckRingNumberList = append(neckRingNumberList, v.NeckRingNumber)
  76. }
  77. // 获取牛只信息
  78. cowInfoList, err := e.GetCowByNeckRingNumbers(pastureId, neckRingNumberList)
  79. if err != nil {
  80. return nil, err
  81. }
  82. // 构建牛只信息映射
  83. cowMap := make(map[string]*model.Cow, len(cowInfoList))
  84. for _, v := range cowInfoList {
  85. if v.NeckRingNumber == "" {
  86. continue
  87. }
  88. cowMap[v.NeckRingNumber] = v
  89. }
  90. return cowMap, nil
  91. }
  92. // processPenBehaviorData 处理栏舍行为数据
  93. func (e *Entry) processPenBehaviorData(neckRingOriginalList []*model.NeckRingOriginal, cowMap map[string]*model.Cow) map[string]*model.PenBehaviorData {
  94. penData := make(map[string]*model.PenBehaviorData, len(neckRingOriginalList))
  95. for _, v := range neckRingOriginalList {
  96. cowInfo, ok := cowMap[v.NeckRingNumber]
  97. if !ok {
  98. zaplog.Error("PenBehavior", zap.Any("neckRingNumber", v.NeckRingNumber))
  99. continue
  100. }
  101. key := fmt.Sprintf("%s_%d_%d", v.ActiveDate, cowInfo.PenId, v.Frameid)
  102. if data, exists := penData[key]; exists {
  103. data.CowCount++
  104. data.AvgHigh += v.High
  105. data.SumRumina += ifThenElse(v.Rumina >= 8, 1, 0)
  106. data.SumIntake += ifThenElse(v.Intake >= 8, 1, 0)
  107. data.SumRest += ifThenElse(v.Inactive >= 8, 1, 0)
  108. data.SumGasp += ifThenElse(v.Gasp >= 8, 1, 0)
  109. } else {
  110. penData[key] = &model.PenBehaviorData{
  111. PastureId: cowInfo.PastureId,
  112. PenId: cowInfo.PenId,
  113. PenName: cowInfo.PenName,
  114. HeatDate: v.ActiveDate,
  115. Frameid: v.Frameid,
  116. CowCount: 1,
  117. AvgHigh: v.High,
  118. }
  119. }
  120. }
  121. return penData
  122. }
  123. // calculateAveragesAndRates 计算平均值和百分比
  124. func (e *Entry) calculateAveragesAndRates(penData map[string]*model.PenBehaviorData) {
  125. for _, data := range penData {
  126. // 计算平均值
  127. data.AvgHigh = data.AvgHigh / data.CowCount
  128. // 计算百分比
  129. if data.CowCount > 0 {
  130. data.RuminaRate = int32(float64(data.SumRumina) / float64(data.CowCount) * 100)
  131. data.IntakeRate = int32(float64(data.SumIntake) / float64(data.CowCount) * 100)
  132. data.RestRate = int32(float64(data.SumRest) / float64(data.CowCount) * 100)
  133. data.GaspRate = int32(float64(data.SumGasp) / float64(data.CowCount) * 100)
  134. }
  135. }
  136. }
  137. // savePenBehaviorData 保存栏舍行为数据
  138. func (e *Entry) savePenBehaviorData(penData map[string]*model.PenBehaviorData) error {
  139. for _, data := range penData {
  140. // 构建活动时间
  141. activeTime := e.calculateActiveTime(data.HeatDate, data.Frameid)
  142. // 构建保存数据
  143. penBehavior := model.NewPenBehavior(data, activeTime)
  144. // 使用 Upsert 操作
  145. if err := e.DB.Model(new(model.PenBehavior)).
  146. Where("pasture_id = ? AND heat_date = ? AND pen_id = ? AND active_time = ?",
  147. penBehavior.PastureId, penBehavior.HeatDate, penBehavior.PenId, penBehavior.ActiveTime).
  148. Assign(map[string]interface{}{
  149. "frameid": penBehavior.Frameid,
  150. "cow_count": penBehavior.CowCount,
  151. "avg_high": penBehavior.AvgHigh,
  152. "sum_rumina": penBehavior.SumRumina,
  153. "sum_intake": penBehavior.SumIntake,
  154. "sum_rest": penBehavior.SumRest,
  155. "sum_gasp": penBehavior.SumGasp,
  156. "rumina_rate": penBehavior.RuminaRate,
  157. "intake_rate": penBehavior.IntakeRate,
  158. "rest_rate": penBehavior.RestRate,
  159. "gasp_rate": penBehavior.GaspRate,
  160. }).
  161. FirstOrCreate(penBehavior).Error; err != nil {
  162. return err
  163. }
  164. }
  165. return nil
  166. }
  167. // calculateActiveTime 计算活动时间
  168. func (e *Entry) calculateActiveTime(heatDate string, frameid int32) string {
  169. // 计算小时和分钟
  170. hour := (frameid / 10) * 2
  171. minute := (frameid%10)*20 - 1
  172. if minute < 0 {
  173. minute = 0
  174. }
  175. baseDate, err := time.Parse(model.LayoutDate2, heatDate)
  176. if err != nil {
  177. zaplog.Error("PenBehavior", zap.Any("calculateActiveTime", err))
  178. return ""
  179. }
  180. baseTime := time.Date(baseDate.Year(), baseDate.Month(), baseDate.Day(), int(hour), 0, 0, 0, baseDate.Location())
  181. finalTime := baseTime.Add(time.Duration(minute) * time.Minute)
  182. // 构建时间字符串
  183. return finalTime.Format(model.LayoutTime)
  184. }
  185. // ifThenElse 条件判断函数
  186. func ifThenElse(condition bool, a, b int32) int32 {
  187. if condition {
  188. return a
  189. }
  190. return b
  191. }