pen_behavior.go 5.7 KB

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