pen_behavior.go 8.7 KB

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