pen_behavior.go 9.1 KB

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