pen_behavior.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. package crontab
  2. import (
  3. "fmt"
  4. "kpt-pasture/model"
  5. "kpt-pasture/util"
  6. "time"
  7. "gitee.com/xuyiping_admin/pkg/xerr"
  8. pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
  9. "gitee.com/xuyiping_admin/pkg/logger/zaplog"
  10. "go.uber.org/zap"
  11. )
  12. func (e *Entry) UpdatePenBehavior() error {
  13. pastureList := e.FindPastureList()
  14. if pastureList == nil || len(pastureList) == 0 {
  15. return nil
  16. }
  17. for _, pasture := range pastureList {
  18. conf, err := e.GetSystemNeckRingConfigure(pasture.Id, model.MaxPenBehavior)
  19. if err != nil {
  20. zaplog.Error("UpdatePenBehavior", zap.Any("pasture", pasture), zap.Any("err", err))
  21. continue
  22. }
  23. e.PenBehaviorEnter(pasture.Id, int(conf.Value))
  24. }
  25. return nil
  26. }
  27. // PenBehaviorEnter 栏舍行为曲线 对数据进行查缺补漏
  28. func (e *Entry) PenBehaviorEnter(pastureId int64, days int) {
  29. minHeatDate := time.Now().Local().AddDate(0, 0, -days).Format(model.LayoutDate2)
  30. e.PenBehavior(pastureId, minHeatDate)
  31. e.UpdatePenBehaviorWeekData(pastureId, minHeatDate)
  32. newDays := days - 1
  33. if newDays < 0 {
  34. return
  35. }
  36. if err := e.UpdateSystemNeckRingConfigure(pastureId, model.MaxPenBehavior, int64(newDays)); err != nil {
  37. zaplog.Error("PenBehaviorEnter", zap.Any("pastureId", pastureId), zap.Any("days", days))
  38. }
  39. }
  40. // PenBehavior 栏舍行为曲线
  41. func (e *Entry) PenBehavior(pastureId int64, heatDate string) {
  42. frameIds := util.FrameIdSlice
  43. penBehaviorList := make([]*model.PenBehaviorData, 0)
  44. for _, frameId := range frameIds {
  45. if frameId%10 == 8 {
  46. continue
  47. }
  48. penBehaviorModel, err := e.getNeckRingOriginalList(pastureId, heatDate, frameId)
  49. if err != nil {
  50. zaplog.Error("PenBehavior",
  51. zap.Any("pasture", pastureId),
  52. zap.Any("frameId", frameId),
  53. zap.Any("heatDate", heatDate),
  54. zap.Any("err", err),
  55. )
  56. continue
  57. }
  58. if penBehaviorModel != nil {
  59. penBehaviorList = append(penBehaviorList, penBehaviorModel)
  60. }
  61. }
  62. if len(penBehaviorList) <= 0 {
  63. return
  64. }
  65. // 2. 保存数据
  66. if err := e.savePenBehaviorData(penBehaviorList); err != nil {
  67. zaplog.Error("PenBehavior", zap.Any("penBehaviorList", penBehaviorList), zap.Any("err", err))
  68. return
  69. }
  70. }
  71. // getNeckRingOriginalList 获取颈环原始数据
  72. func (e *Entry) getNeckRingOriginalList(pastureId int64, dateTime string, frameId int32) (*model.PenBehaviorData, error) {
  73. penBehaviorModel := &model.PenBehaviorData{}
  74. sql := fmt.Sprintf(`
  75. SELECT bb.pasture_id, bb.heat_date, bb.frameid,
  76. bb.pen_id, bb.pen_name,bb.cow_count, bb.avg_high,
  77. bb.sum_rumina, bb.sum_intake, bb.sum_rest, bb.sum_gasp,
  78. ROUND(bb.sum_rumina/bb.cow_count*100, 0) rumina_rate ,
  79. ROUND(bb.sum_intake/bb.cow_count*100, 0) intake_rate,
  80. ROUND(bb.sum_rest/bb.cow_count*100, 0) rest_rate,
  81. ROUND(bb.sum_gasp/bb.cow_count*100, 0) gasp_rate
  82. FROM (
  83. SELECT aa.pasture_id, aa.pen_id, aa.pen_name, aa.heat_date, aa.frameid,
  84. COUNT(1) cow_count,
  85. ROUND(AVG(aa.high), 0) avg_high,
  86. SUM(IF(aa.rumina>=8, 1, 0)) sum_rumina,
  87. SUM(IF(aa.intake>=8, 1, 0)) sum_intake,
  88. SUM(IF(aa.inactive>=8, 1, 0)) sum_rest,
  89. SUM(IF(aa.gasp>=8, 1, 0) ) sum_gasp
  90. FROM (
  91. SELECT c.pasture_id, c.ear_number, c.pen_id, c.pen_name, h.neck_ring_number, h.active_date as heat_date,
  92. h.frameid, h.high, h.rumina, h.intake, h.inactive, h.gasp
  93. FROM neck_ring_original h JOIN cow c ON h.pasture_id=c.pasture_id AND h.neck_ring_number=c.neck_ring_number
  94. WHERE h.pasture_id = %d
  95. AND h.active_date='%s'
  96. AND h.frameid = %d
  97. GROUP BY h.neck_ring_number
  98. ) aa GROUP BY aa.pen_id
  99. ) bb`, pastureId, dateTime, frameId)
  100. if err := e.DB.Raw(sql).First(penBehaviorModel).Error; err != nil {
  101. return nil, xerr.WithStack(err)
  102. }
  103. return penBehaviorModel, nil
  104. }
  105. // savePenBehaviorData 保存栏舍行为数据
  106. func (e *Entry) savePenBehaviorData(penDataList []*model.PenBehaviorData) error {
  107. for _, data := range penDataList {
  108. // 构建活动时间
  109. activeTime := e.calculateActiveTime(data.HeatDate, data.Frameid)
  110. // 构建保存数据
  111. penBehavior := model.NewPenBehavior(data, activeTime)
  112. if e.isExistByPenBehavior(data.PastureId, data.HeatDate, data.PenId, data.Frameid) {
  113. historyData := e.findPenBehavior(data.PastureId, data.HeatDate, data.PenId, data.Frameid)
  114. if historyData == nil || historyData.Id <= 0 {
  115. continue
  116. }
  117. if err := e.DB.Model(new(model.PenBehavior)).
  118. Where("id = ?", historyData.Id).
  119. Updates(map[string]interface{}{
  120. "cow_count": data.CowCount,
  121. "avg_high": data.AvgHigh,
  122. "sum_rumina": data.SumRumina,
  123. "sum_intake": data.SumIntake,
  124. "sum_rest": data.SumRest,
  125. "sum_gasp": data.SumGasp,
  126. "rumina_rate": data.RuminaRate,
  127. "intake_rate": data.IntakeRate,
  128. "rest_rate": data.RestRate,
  129. "gasp_rate": data.GaspRate,
  130. }).Error; err != nil {
  131. zaplog.Error("savePenBehaviorData", zap.Any("penBehavior", penBehavior), zap.Any("err", err))
  132. }
  133. continue
  134. }
  135. if err := e.DB.Model(new(model.PenBehavior)).
  136. Create(penBehavior).Error; err != nil {
  137. zaplog.Error("savePenBehaviorData", zap.Any("penBehavior", penBehavior), zap.Any("err", err))
  138. }
  139. }
  140. return nil
  141. }
  142. func (e *Entry) UpdatePenBehaviorWeekData(pastureId int64, dateTime string) {
  143. dateTime1, _ := util.TimeParseLocal(model.LayoutDate2, dateTime)
  144. startTime := dateTime1.AddDate(0, 0, -7).Format(model.LayoutDate2)
  145. endTime := dateTime1.AddDate(0, 0, -1).Format(model.LayoutDate2)
  146. penBehaviorList, err := e.findWeekPenBehaviorList(pastureId, dateTime, startTime, endTime)
  147. if err != nil {
  148. zaplog.Error("UpdatePenBehaviorWeekData",
  149. zap.Any("err", err),
  150. zap.Any("pastureId", pastureId),
  151. zap.Any("dateTime", dateTime),
  152. zap.Any("startTime", startTime),
  153. zap.Any("endTime", endTime),
  154. )
  155. return
  156. }
  157. if len(penBehaviorList) == 0 {
  158. return
  159. }
  160. // 处理每个日期和frameid的数据
  161. for _, item := range penBehaviorList {
  162. if err = e.DB.Model(new(model.PenBehavior)).
  163. Where("id = ?", item.Id).
  164. Updates(map[string]interface{}{
  165. "week_rumina_rate": item.WeekRuminaRate,
  166. "week_intake_rate": item.WeekIntakeRate,
  167. "week_rest_rate": item.WeekRestRate,
  168. "week_gasp_rate": item.WeekGaspRate,
  169. "rumina_std": item.RuminaStd,
  170. "intake_std": item.IntakeStd,
  171. "rest_std": item.RestStd,
  172. "gasp_std": item.GaspStd,
  173. "is_show": pasturePb.IsShow_Ok,
  174. }).Error; err != nil {
  175. zaplog.Error("UpdatePenBehaviorWeekData", zap.Error(err))
  176. }
  177. }
  178. }
  179. // calculateActiveTime 计算活动时间
  180. func (e *Entry) calculateActiveTime(heatDate string, frameid int32) string {
  181. // 计算小时和分钟
  182. hour := (frameid / 10) * 2
  183. minute := (frameid%10)*20 - 1
  184. if minute < 0 {
  185. minute = 0
  186. }
  187. baseDate, err := time.Parse(model.LayoutDate2, heatDate)
  188. if err != nil {
  189. zaplog.Error("PenBehavior", zap.Any("calculateActiveTime", err))
  190. return ""
  191. }
  192. baseTime := time.Date(baseDate.Year(), baseDate.Month(), baseDate.Day(), int(hour), 0, 0, 0, baseDate.Location())
  193. finalTime := baseTime.Add(time.Duration(minute) * time.Minute)
  194. // 构建时间字符串
  195. return finalTime.Format(model.LayoutTime)
  196. }
  197. // isExistByPenBehavior 是否存在
  198. func (e *Entry) isExistByPenBehavior(pastureId int64, heatDate string, penId int32, frameid int32) bool {
  199. var count int64
  200. if err := e.DB.Model(new(model.PenBehavior)).
  201. Where("pasture_id = ? AND heat_date = ? AND frameid = ? AND pen_id = ?", pastureId, heatDate, frameid, penId).
  202. Count(&count).Error; err != nil {
  203. return false
  204. }
  205. return count > 0
  206. }
  207. func (e *Entry) findPenBehavior(pastureId int64, heatDate string, penId int32, frameid int32) *model.PenBehavior {
  208. res := &model.PenBehavior{}
  209. if err := e.DB.Model(new(model.PenBehavior)).
  210. Where("pasture_id = ? AND heat_date = ? AND frameid = ? AND pen_id = ?", pastureId, heatDate, penId, frameid).
  211. First(res).Error; err != nil {
  212. return nil
  213. }
  214. return res
  215. }
  216. func (e *Entry) findWeekPenBehaviorList(pastureId int64, heatDate, startTime, endTime string) ([]*model.PenBehavior, error) {
  217. penBehaviorList := make([]*model.PenBehavior, 0)
  218. sql := fmt.Sprintf(`
  219. SELECT b1.id,
  220. ROUND(AVG(b0.rumina_rate)) week_rumina_rate,
  221. ROUND(STD(b0.rumina_rate)) rumina_std,
  222. ROUND(AVG( b0.intake_rate)) week_intake_rate,
  223. ROUND(STD( b0.intake_rate)) intake_std,
  224. ROUND(AVG( b0.rest_rate)) week_rest_rate,
  225. ROUND(STD( b0.rest_rate)) rest_std,
  226. ROUND(AVG( b0.gasp_rate)) week_gasp_rate,
  227. ROUND(STD( b0.gasp_rate)) gasp_std
  228. FROM pen_behavior b1 JOIN pen_behavior b0
  229. ON b1.pen_id=b0.pen_id AND b1.heat_date='%s'
  230. AND b1.frameid=b0.frameid AND b0.heat_date BETWEEN '%s' AND '%s'
  231. WHERE b1.cow_count>= %d AND b1.pasture_id = %d
  232. GROUP BY b1.id
  233. `, heatDate, startTime, endTime, model.PenBehaviorMinCowCount, pastureId)
  234. if err := e.DB.Raw(sql).Find(&penBehaviorList).Error; err != nil {
  235. return nil, xerr.WithStack(err)
  236. }
  237. return penBehaviorList, nil
  238. }