neck_ring_calculate.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. package crontab
  2. import (
  3. "fmt"
  4. "kpt-pasture/model"
  5. "kpt-pasture/util"
  6. "math"
  7. "strconv"
  8. "time"
  9. pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
  10. "gitee.com/xuyiping_admin/pkg/logger/zaplog"
  11. "gitee.com/xuyiping_admin/pkg/xerr"
  12. "go.uber.org/zap"
  13. )
  14. func (e *Entry) NeckRingCalculate() error {
  15. pastureList := e.FindPastureList()
  16. if pastureList == nil || len(pastureList) == 0 {
  17. return nil
  18. }
  19. for _, pasture := range pastureList {
  20. if err := e.EntryUpdateActiveHabit(pasture.Id); err != nil {
  21. zaplog.Error("NeckRingCalculate", zap.Any("err", err), zap.Any("pasture", pasture))
  22. }
  23. zaplog.Info(fmt.Sprintf("NeckRingCalculate Success %d", pasture.Id))
  24. }
  25. return nil
  26. }
  27. func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
  28. // 获取这段执行数据内最大日期和最小日期
  29. xToday, err := e.XToday(pastureId)
  30. if err != nil {
  31. return xerr.WithStack(err)
  32. }
  33. // 未配置的滤波数据不参与计算
  34. if xToday == nil {
  35. return nil
  36. }
  37. var processIds []int64
  38. // 更新活动滤波
  39. processIds, err = e.FirstFilterUpdate(pastureId, xToday)
  40. if err != nil {
  41. zaplog.Error("NeckRingCalculate", zap.Any("pastureId", pastureId), zap.Any("FirstFilterUpdate", err), zap.Any("xToday", xToday))
  42. }
  43. zaplog.Info("NeckRingCalculate", zap.Any("pastureId", pastureId), zap.Any("xToday", xToday), zap.Any("processIds", processIds))
  44. if len(processIds) <= 0 {
  45. return nil
  46. }
  47. e.WeeklyUpdateActiveHabit(pastureId, processIds, xToday)
  48. // 二次更新滤波
  49. e.SecondUpdateChangeFilter(pastureId, processIds, xToday)
  50. // 活动量校正系数和健康评分
  51. e.FilterCorrectAndScoreUpdate(pastureId, processIds, xToday)
  52. // 更新 ChangeFilter
  53. e.UpdateChangeFilter(pastureId, processIds)
  54. // 更新 FilterCorrect
  55. e.UpdateFilterCorrect(pastureId, processIds)
  56. // 插入群体校正表
  57. e.UpdateChangeAdJust(pastureId, xToday)
  58. // 更新 Cft
  59. e.UpdateCft(pastureId, processIds)
  60. // 更新所有的显示状态为否的记录为是
  61. e.UpdateIsShow(pastureId, processIds)
  62. // 健康预警
  63. e.HealthWarning(pastureId, processIds)
  64. return nil
  65. }
  66. // FirstFilterUpdate 首次更新活动滤波
  67. func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) (processIds []int64, err error) {
  68. limit := e.Cfg.NeckRingLimit
  69. if limit <= 0 {
  70. limit = defaultLimit
  71. }
  72. heatDate := time.Now().Local().AddDate(0, 0, -30).Format(model.LayoutDate2)
  73. querySql := `SELECT * FROM neck_active_habit WHERE pasture_id = ? AND is_show = ? AND heat_date >= ? AND high >= ?
  74. UNION
  75. SELECT * FROM neck_active_habit WHERE pasture_id = ? AND is_show = ? AND heat_date >= ? AND rumina >= ?
  76. ORDER BY heat_date, neck_ring_number, frameid LIMIT ?`
  77. newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  78. /*if err = e.DB.Model(new(model.NeckActiveHabit)).
  79. Where("heat_date >= ?", time.Now().Local().AddDate(0, 0, -30).Format(model.LayoutDate2)).
  80. Where("pasture_id = ?", pastureId).
  81. Where("is_show = ?", pasturePb.IsShow_No).
  82. Where(e.DB.Where("high >= ?", xToDay.High).Or("rumina >= ?", xToDay.Rumina)).
  83. Order("heat_date,neck_ring_number,frameid").
  84. Limit(int(limit)).
  85. Find(&newNeckActiveHabitList).Error; err != nil {
  86. return nil, xerr.WithStack(err)
  87. }*/
  88. if err = e.DB.Raw(
  89. querySql,
  90. pastureId, pasturePb.IsShow_No, heatDate, xToDay.High,
  91. pastureId, pasturePb.IsShow_No, heatDate, xToDay.Rumina,
  92. limit,
  93. ).Find(&newNeckActiveHabitList).Error; err != nil {
  94. return nil, xerr.WithStack(err)
  95. }
  96. // 活动量滤波
  97. for _, v := range newNeckActiveHabitList {
  98. /*if !(v.High >= xToDay.High || v.Rumina >= xToDay.Rumina) {
  99. continue
  100. }*/
  101. // 4小时数据不全的不参与滤波
  102. activeTime, _ := util.TimeParseLocal(model.LayoutTime, v.ActiveTime)
  103. if v.RecordCount != model.DefaultRecordCount && time.Now().Local().Sub(activeTime).Hours() <= 4 {
  104. continue
  105. }
  106. // 过滤牛只未绑定的脖环的数据
  107. cowInfo := e.GetCowInfoByNeckRingNumber(v.PastureId, v.NeckRingNumber)
  108. if cowInfo == nil || cowInfo.Id <= 0 {
  109. v.UpdateIsShowOk()
  110. if err = e.DB.Model(new(model.NeckActiveHabit)).
  111. Select("is_show").
  112. Where("id = ?", v.Id).
  113. Updates(v).Error; err != nil {
  114. zaplog.Error("EntryUpdateActiveHabit", zap.Any("error", err))
  115. }
  116. continue
  117. }
  118. frameId := v.Frameid
  119. heatDate := v.HeatDate
  120. if v.Frameid == 0 {
  121. frameId = 11
  122. heatDateParse, _ := util.TimeParseLocal(model.LayoutDate2, heatDate)
  123. heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2)
  124. } else {
  125. frameId -= 1
  126. }
  127. firstFilterData := e.FindFilterData(pastureId, v.NeckRingNumber, heatDate, frameId)
  128. if v.FilterHigh > 0 {
  129. firstFilterData.FilterHigh = v.FilterHigh
  130. } else {
  131. if v.NeckRingNumber == firstFilterData.NeckRingNumber {
  132. firstFilterData.FilterHigh = int32(computeIfPositiveElse(float64(v.High), float64(firstFilterData.FilterHigh), 0.23, 0.77))
  133. } else {
  134. firstFilterData.FilterHigh = v.High
  135. }
  136. }
  137. if v.FilterRumina > 0 {
  138. firstFilterData.FilterRumina = v.FilterRumina
  139. } else {
  140. if v.NeckRingNumber == firstFilterData.NeckRingNumber {
  141. firstFilterData.FilterRumina = int32(computeIfPositiveElse(float64(v.Rumina), float64(firstFilterData.FilterRumina), 0.33, 0.67))
  142. } else {
  143. firstFilterData.FilterRumina = v.Rumina
  144. }
  145. }
  146. if v.FilterChew > 0 {
  147. firstFilterData.FilterChew = v.FilterChew
  148. } else {
  149. if v.NeckRingNumber == firstFilterData.NeckRingNumber {
  150. firstFilterData.FilterChew = int32(computeIfPositiveElse(float64(v.Rumina+v.Intake), float64(firstFilterData.FilterChew), 0.33, 0.67))
  151. } else {
  152. firstFilterData.FilterChew = v.Rumina + v.Intake
  153. }
  154. }
  155. cowWeeklyActive := cowInfo.WeeklyActive
  156. if cowWeeklyActive <= 0 {
  157. cowWeeklyActive = v.WeekHigh
  158. }
  159. processIds = append(processIds, v.Id)
  160. // 更新过滤值
  161. if err = e.DB.Model(new(model.NeckActiveHabit)).
  162. Select("filter_high", "filter_rumina", "filter_chew", "cow_id", "lact", "calving_age", "ear_number", "week_high").
  163. Where("id = ?", v.Id).
  164. Updates(map[string]interface{}{
  165. "filter_high": firstFilterData.FilterHigh,
  166. "filter_rumina": firstFilterData.FilterRumina,
  167. "filter_chew": firstFilterData.FilterChew,
  168. "cow_id": cowInfo.Id,
  169. "lact": cowInfo.Lact,
  170. "calving_age": cowInfo.CalvingAge,
  171. "ear_number": cowInfo.EarNumber,
  172. "week_high": cowWeeklyActive,
  173. }).Error; err != nil {
  174. zaplog.Error("FirstFilterUpdate",
  175. zap.Any("error", err),
  176. zap.Any("firstFilterData", firstFilterData),
  177. zap.Any("NeckActiveHabit", v),
  178. zap.Any("cowInfo", cowInfo),
  179. zap.Any("xToday", xToDay),
  180. )
  181. }
  182. }
  183. return processIds, nil
  184. }
  185. // SecondUpdateChangeFilter 第二次更新变化趋势滤波
  186. func (e *Entry) SecondUpdateChangeFilter(pastureId int64, processIds []int64, xToday *XToday) {
  187. newChangeFilterList := make([]*ChangeFilterData, 0)
  188. if err := e.DB.Model(new(model.NeckActiveHabit)).
  189. Select("id", "neck_ring_number", "change_high", "change_filter", "rumina_filter", "change_rumina",
  190. "chew_filter", "change_chew", "heat_date", "frameid", "IF(lact = 0, 0.8, 1) as xlc_dis_count").
  191. Where("pasture_id = ?", pastureId).
  192. Where("id IN (?)", processIds).
  193. Where("change_filter = ?", model.InitChangeFilter).
  194. Where("change_high > ?", MinChangeHigh).
  195. Order("neck_ring_number,heat_date,frameid").
  196. Find(&newChangeFilterList).Error; err != nil {
  197. zaplog.Error("SecondUpdateChangeFilter", zap.Any("error", err))
  198. return
  199. }
  200. for _, v := range newChangeFilterList {
  201. frameId := v.Frameid
  202. heatDate := v.HeatDate
  203. if v.Frameid == 0 {
  204. frameId = 11
  205. heatDateParse, _ := util.TimeParseLocal(model.LayoutDate2, heatDate)
  206. heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2)
  207. } else {
  208. frameId -= 1
  209. }
  210. xChangeDiscount := float64(xToday.XChangeDiscount) / 10
  211. xRuminaDisc := float64(xToday.XRuminaDisc) / 10
  212. secondFilterData := e.FindFilterData(pastureId, v.NeckRingNumber, heatDate, frameId)
  213. if secondFilterData.ChangeFilter <= MinChangeFilter {
  214. secondFilterData.ChangeFilter = 0
  215. }
  216. if secondFilterData.RuminaFilter <= MinRuminaFilter {
  217. secondFilterData.RuminaFilter = 0
  218. }
  219. if secondFilterData.ChewFilter <= MinChewFilter {
  220. secondFilterData.ChewFilter = 0
  221. }
  222. changeFilter := float64(v.ChangeFilter)
  223. if v.ChangeFilter <= MinChangeFilter {
  224. changeFilter = float64(secondFilterData.ChangeFilter)*(1-xChangeDiscount*v.XlcDisCount) +
  225. math.Min(float64(v.ChangeHigh), float64(secondFilterData.ChangeFilter)+135)*xChangeDiscount*v.XlcDisCount
  226. }
  227. ruminaFilter := float64(v.RuminaFilter)
  228. discount := xRuminaDisc * v.XlcDisCount
  229. if math.Abs(float64(v.ChangeRumina)) > 60 {
  230. discount *= 0.5
  231. }
  232. ruminaFilter = float64(secondFilterData.RuminaFilter)*(1-discount) + float64(v.ChangeRumina)*discount
  233. if ruminaFilter > 50 {
  234. ruminaFilter = 50
  235. }
  236. chewFilter := float64(v.ChewFilter)
  237. chewFilterDiscount := float64(1)
  238. if math.Abs(float64(v.ChangeChew)) > 60 {
  239. chewFilterDiscount = 0.5
  240. }
  241. chewFilter = float64(secondFilterData.ChewFilter)*(1-xRuminaDisc*chewFilterDiscount) +
  242. float64(v.ChangeChew)*xRuminaDisc*chewFilterDiscount
  243. if chewFilter > 50 {
  244. chewFilter = 50
  245. }
  246. zaplog.Info("SecondUpdateChangeFilter",
  247. zap.Any("NeckActiveHabit", v),
  248. zap.Any("discount", discount),
  249. zap.Any("xChangeDiscount", xChangeDiscount),
  250. zap.Any("xRuminaDisc", xRuminaDisc),
  251. zap.Any("chewFilterDiscount", chewFilterDiscount),
  252. zap.Any("secondFilterData", secondFilterData),
  253. zap.Any("changeFilter", changeFilter),
  254. zap.Any("ruminaFilter", ruminaFilter),
  255. zap.Any("chewFilter", chewFilter),
  256. )
  257. if err := e.DB.Model(new(model.NeckActiveHabit)).
  258. Select("change_filter", "rumina_filter", "chew_filter").
  259. Where("id = ?", v.Id).
  260. Updates(map[string]interface{}{
  261. "change_filter": int32(changeFilter),
  262. "rumina_filter": int32(ruminaFilter),
  263. "chew_filter": int32(chewFilter),
  264. }).Error; err != nil {
  265. zaplog.Error("SecondUpdateChangeFilter", zap.Any("error", err), zap.Any("secondFilterData", secondFilterData))
  266. }
  267. }
  268. }
  269. // FilterCorrectAndScoreUpdate 计算活动量变化趋势校正值(活跃度校正)和健康评分
  270. func (e *Entry) FilterCorrectAndScoreUpdate(pastureId int64, processIds []int64, xToday *XToday) {
  271. beginDayDate := time.Now().Local()
  272. before7DayDate := beginDayDate.AddDate(0, 0, -7).Format(model.LayoutDate2)
  273. before1DayDate := beginDayDate.AddDate(0, 0, -1).Format(model.LayoutDate2)
  274. neckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  275. if err := e.DB.Model(new(model.NeckActiveHabit)).
  276. Where("id IN (?)", processIds).
  277. Where("pasture_id = ?", pastureId).
  278. Find(&neckActiveHabitList).Error; err != nil {
  279. zaplog.Error("ActivityVolumeChanges-1", zap.Any("error", err), zap.Any("xToday", xToday))
  280. return
  281. }
  282. for _, v := range neckActiveHabitList {
  283. activityVolume := &ActivityVolume{}
  284. if err := e.DB.Model(new(model.NeckActiveHabit)).
  285. Select("neck_ring_number", "AVG(IF(change_filter>=60, 60, change_filter)) as avg_filter",
  286. "ROUND(STD(IF(change_filter>=60, 60, change_filter))) as std_filter", "COUNT(1) as nb").
  287. Where("heat_date BETWEEN ? AND ?", before7DayDate, before1DayDate).
  288. Where("pasture_id = ?", pastureId).
  289. Where(e.DB.Where("high > ?", 12).Or("rumina >= ?", xToday.Rumina)).
  290. Where("active_time <= ?", beginDayDate.Add(-12*time.Hour).Format(model.LayoutTime)).
  291. Where("change_filter > ?", MinChangeFilter).
  292. Where("neck_ring_number = ?", v.NeckRingNumber).
  293. Having("nb >= ?", DefaultNb).
  294. First(&activityVolume).Error; err != nil {
  295. zaplog.Error("ActivityVolumeChanges-0", zap.Any("error", err), zap.Any("xToday", xToday))
  296. continue
  297. }
  298. if activityVolume != nil && activityVolume.NeckRingNumber != "" {
  299. //filterCorrect := model.DefaultFilterCorrect - int(math.Floor(activityVolume.AvgFilter/3+float64(activityVolume.StdFilter)/2))
  300. filterCorrect := model.DefaultFilterCorrect - int(math.Round(activityVolume.AvgFilter/3+float64(int(math.Round(activityVolume.StdFilter))/2)))
  301. // 活动量校正系数
  302. if err := e.DB.Model(new(model.NeckActiveHabit)).
  303. Where("id = ?", v.Id).
  304. Where("neck_ring_number = ?", v.NeckRingNumber).
  305. Update("filter_correct", filterCorrect).Error; err != nil {
  306. zaplog.Error("ActivityVolumeChanges-2", zap.Any("error", err), zap.Any("xToday", xToday))
  307. continue
  308. }
  309. }
  310. cowScore := calculateScore(v)
  311. if err := e.DB.Model(new(model.NeckActiveHabit)).
  312. Where("id = ?", v.Id).
  313. Update("score", cowScore).Error; err != nil {
  314. zaplog.Error("ActivityVolumeChanges-2", zap.Any("error", err), zap.Any("xToday", xToday))
  315. continue
  316. }
  317. }
  318. }
  319. func (e *Entry) UpdateChangeFilter(pastureId int64, processIds []int64) {
  320. if err := e.DB.Model(new(model.NeckActiveHabit)).
  321. Where("id IN (?)", processIds).
  322. Where("pasture_id = ?", pastureId).
  323. Where("is_show = ?", pasturePb.IsShow_No).
  324. Where("change_filter = ?", model.InitChangeFilter).
  325. Updates(map[string]interface{}{
  326. "change_filter": model.DefaultChangeFilter,
  327. "rumina_filter": model.DefaultRuminaFilter,
  328. "chew_filter": model.DefaultChewFilter,
  329. }).Error; err != nil {
  330. zaplog.Error("UpdateChangeFilter", zap.Any("change_filter", err))
  331. }
  332. }
  333. func (e *Entry) UpdateFilterCorrect(pastureId int64, processIds []int64) {
  334. if err := e.DB.Model(new(model.NeckActiveHabit)).
  335. Where("id IN (?)", processIds).
  336. Where("pasture_id = ?", pastureId).
  337. Where("change_filter < ?", 0).
  338. Where("filter_correct < ?", model.DefaultFilterCorrect).
  339. Updates(map[string]interface{}{
  340. "filter_correct": model.DefaultFilterCorrect,
  341. }).Error; err != nil {
  342. zaplog.Error("UpdateFilterCorrect", zap.Any("filter_correct", err))
  343. }
  344. }
  345. // UpdateChangeAdJust 更新群体校正数据
  346. func (e *Entry) UpdateChangeAdJust(pastureId int64, xToday *XToday) {
  347. res := make([]*model.NeckRingBarChange, 0)
  348. oneDayAgo := time.Now().Local().AddDate(0, 0, -1).Format(model.LayoutDate2)
  349. if err := e.DB.Table(fmt.Sprintf("%s as h", new(model.NeckActiveHabit).TableName())).
  350. Select(`h.neck_ring_number,h.heat_date, h.frameid, c.pen_id, c.pen_name, COUNT(*) as nb,
  351. ROUND(AVG(h.change_high)) as change_high, ROUND(AVG(h.change_filter)) as change_filter`).
  352. Joins("JOIN cow as c ON h.cow_id = c.id").
  353. Where("h.pasture_id = ?", pastureId).
  354. Where("h.heat_date >= ?", oneDayAgo).
  355. Where("h.cow_id > ?", 0).
  356. Where("c.pen_id > ?", 0).
  357. Group("h.heat_date, h.frameid, c.pen_id").
  358. Order("h.heat_date, h.frameid, c.pen_id").
  359. Find(&res).Error; err != nil {
  360. zaplog.Error("UpdateChangeAdJust", zap.Any("error", err), zap.Any("xToday", xToday))
  361. }
  362. for _, v := range res {
  363. if math.Abs(float64(v.ChangeFilter)) < 10 {
  364. continue
  365. }
  366. if err := e.DB.Model(new(model.NeckActiveHabit)).
  367. Where("pasture_id = ?", pastureId).
  368. Where("neck_ring_number = ?", v.NeckRingNumber).
  369. Where("heat_date = ?", v.HeatDate).
  370. //Where("pen_id = ?", v.PenId).
  371. Where("frameid = ?", v.FrameId).
  372. Update("change_adjust", v.ChangeFilter).Error; err != nil {
  373. zaplog.Error("UpdateChangeAdJust-1", zap.Any("error", err), zap.Any("xToday", xToday))
  374. }
  375. }
  376. }
  377. func (e *Entry) UpdateCft(pastureId int64, processIds []int64) {
  378. neckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  379. if err := e.DB.Model(new(model.NeckActiveHabit)).
  380. Where("id IN (?)", processIds).
  381. Where("pasture_id = ?", pastureId).
  382. Where("is_show = ?", pasturePb.IsShow_No).
  383. Find(&neckActiveHabitList).Error; err != nil {
  384. zaplog.Error("UpdateCft-1", zap.Any("error", err))
  385. }
  386. for _, v := range neckActiveHabitList {
  387. cft := CalculateCFT(v)
  388. if err := e.DB.Model(new(model.NeckActiveHabit)).
  389. Where("id = ?", v.Id).
  390. Where("neck_ring_number = ?", v.NeckRingNumber).
  391. Update("cft", strconv.FormatFloat(float64(cft), 'f', 2, 64)).Error; err != nil {
  392. zaplog.Error("UpdateCft-2", zap.Any("error", err))
  393. }
  394. }
  395. }
  396. func (e *Entry) UpdateIsShow(pastureId int64, processIds []int64) {
  397. if err := e.DB.Model(new(model.NeckActiveHabit)).
  398. Where("id IN (?)", processIds).
  399. Where("pasture_id = ?", pastureId).
  400. Update("is_show", pasturePb.IsShow_Ok).Error; err != nil {
  401. zaplog.Error("UpdateChangeAdJust-2", zap.Any("error", err))
  402. }
  403. }
  404. func (e *Entry) XToday(pastureId int64) (*XToday, error) {
  405. xToday := &XToday{}
  406. systemConfigureList, err := e.FindSystemNeckRingConfigure(pastureId)
  407. if err != nil {
  408. return nil, xerr.WithStack(err)
  409. }
  410. if len(systemConfigureList) <= 0 {
  411. return nil, nil
  412. }
  413. for _, v := range systemConfigureList {
  414. switch v.Name {
  415. case model.MaxHabit:
  416. xToday.LastMaxHabitId = v.Value
  417. case model.High:
  418. xToday.High = int32(v.Value)
  419. case model.Rumina:
  420. xToday.Rumina = int32(v.Value)
  421. case model.XRuminaDisc:
  422. xToday.XRuminaDisc = int32(v.Value)
  423. case model.XChangeDiscount:
  424. xToday.XChangeDiscount = int32(v.Value)
  425. case model.WeeklyActive:
  426. xToday.WeeklyActive = int32(v.Value)
  427. }
  428. }
  429. return xToday, nil
  430. }
  431. // WeeklyUpdateActiveHabit 时间点周平均值计算
  432. func (e *Entry) WeeklyUpdateActiveHabit(pastureId int64, processIds []int64, xToDay *XToday) {
  433. newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  434. if err := e.DB.Model(new(model.NeckActiveHabit)).
  435. Where("id IN (?)", processIds).
  436. Order("heat_date,neck_ring_number,frameid").
  437. Find(&newNeckActiveHabitList).Error; err != nil {
  438. zaplog.Error("WeeklyUpdateActiveHabit", zap.Any("error", err), zap.Any("processIds", processIds))
  439. }
  440. if len(newNeckActiveHabitList) <= 0 {
  441. return
  442. }
  443. e.HabitUpdateActiveHabit(pastureId, newNeckActiveHabitList, xToDay)
  444. e.SumUpdateActiveHabit(pastureId, newNeckActiveHabitList, xToDay)
  445. e.ActiveChange(pastureId, processIds, xToDay)
  446. e.Before3DaysNeckActiveHabit(pastureId, processIds)
  447. }
  448. func (e *Entry) HabitUpdateActiveHabit(pastureId int64, newNeckActiveHabitList []*model.NeckActiveHabit, xToDay *XToday) {
  449. for _, v := range newNeckActiveHabitList {
  450. // 前七天的
  451. weekHabitData := e.FindWeekHabitData(pastureId, v.NeckRingNumber, v.HeatDate, v.Frameid, xToDay)
  452. // 更新过滤值
  453. if err := e.DB.Model(new(model.NeckActiveHabit)).
  454. Select("high_habit", "rumina_habit", "chew_habit", "intake_habit", "inactive_habit").
  455. Where("id = ?", v.Id).
  456. Updates(map[string]interface{}{
  457. "high_habit": weekHabitData.HighHabit,
  458. "rumina_habit": weekHabitData.RuminaHabit,
  459. "chew_habit": weekHabitData.ChewHabit,
  460. "intake_habit": weekHabitData.IntakeHabit,
  461. "inactive_habit": weekHabitData.InactiveHabit,
  462. }).Error; err != nil {
  463. zaplog.Error("WeeklyUpdateActiveHabit",
  464. zap.Error(err),
  465. zap.Any("NeckActiveHabit", v),
  466. zap.Any("pastureId", pastureId),
  467. )
  468. }
  469. }
  470. }
  471. // SumUpdateActiveHabit -- 累计24小时数值
  472. func (e *Entry) SumUpdateActiveHabit(pastureId int64, newNeckActiveHabitList []*model.NeckActiveHabit, xToDay *XToday) {
  473. for _, v := range newNeckActiveHabitList {
  474. sumHabitData := e.FindSumHabitData(pastureId, v.NeckRingNumber, v.HeatDate, v.Frameid, xToDay)
  475. // 更新过滤值
  476. if err := e.DB.Model(new(model.NeckActiveHabit)).
  477. Select("sum_rumina", "sum_intake", "sum_inactive", "sum_active", "sum_max_high", "sum_min_high", "sum_min_chew").
  478. Where("id = ?", v.Id).
  479. Updates(map[string]interface{}{
  480. "sum_rumina": sumHabitData.SumRumina,
  481. "sum_intake": sumHabitData.SumIntake,
  482. "sum_inactive": sumHabitData.SumInactive,
  483. "sum_active": sumHabitData.SumActive,
  484. "sum_max_high": sumHabitData.SumMaxHigh,
  485. "sum_min_high": sumHabitData.SumMinHigh,
  486. "sum_min_chew": sumHabitData.SumMinChew,
  487. }).Error; err != nil {
  488. zaplog.Error("WeeklyUpdateActiveHabit",
  489. zap.Any("err", err),
  490. zap.Any("NeckActiveHabit", v),
  491. zap.Any("pastureId", pastureId),
  492. )
  493. }
  494. }
  495. }
  496. // ActiveChange -- 变化百分比
  497. func (e *Entry) ActiveChange(pastureId int64, processIds []int64, xToDay *XToday) {
  498. newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  499. if err := e.DB.Model(new(model.NeckActiveHabit)).
  500. Where("pasture_id = ?", pastureId).
  501. Where("id IN (?)", processIds).
  502. Where("high_habit > ?", 0).
  503. Where(e.DB.Where("high >= ?", xToDay.High).Or("rumina >= ?", xToDay.Rumina)).
  504. Find(&newNeckActiveHabitList).Error; err != nil {
  505. zaplog.Error("ActiveChange", zap.Any("error", err), zap.Any("processIds", processIds))
  506. }
  507. for _, v := range newNeckActiveHabitList {
  508. changeHigh := calculateChangeHigh(v, xToDay.WeeklyActive)
  509. changeRumina := int32(0)
  510. changeChew := int32(0)
  511. if v.RuminaHabit != 0 {
  512. changeRumina = int32(math.Round(float64(v.FilterRumina-v.RuminaHabit) / float64(v.RuminaHabit) * 100))
  513. }
  514. if v.ChewHabit != 0 {
  515. changeChew = int32(math.Round(float64(v.FilterChew-v.ChewHabit) / float64(v.ChewHabit) * 100))
  516. }
  517. // 更新过滤值
  518. if err := e.DB.Model(new(model.NeckActiveHabit)).
  519. Select("change_high", "change_rumina", "change_chew").
  520. Where("id = ?", v.Id).
  521. Updates(map[string]interface{}{
  522. "change_high": changeHigh,
  523. "change_rumina": changeRumina,
  524. "change_chew": changeChew,
  525. }).Error; err != nil {
  526. zaplog.Error("ActiveChange",
  527. zap.Any("err", err),
  528. zap.Any("NeckActiveHabit", v),
  529. )
  530. }
  531. }
  532. }
  533. func (e *Entry) Before3DaysNeckActiveHabit(pastureId int64, processIds []int64) {
  534. newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  535. if err := e.DB.Model(new(model.NeckActiveHabit)).
  536. Where("id IN (?)", processIds).
  537. Order("heat_date,neck_ring_number,frameid").
  538. Find(&newNeckActiveHabitList).Error; err != nil {
  539. zaplog.Error("Before3DaysNeckActiveHabit", zap.Any("error", err), zap.Any("processIds", processIds))
  540. }
  541. for _, v := range newNeckActiveHabitList {
  542. before3DaysNeckActiveHabit := e.FindBefore3DaysNeckActiveHabit(pastureId, v.NeckRingNumber, v.HeatDate, v.Frameid)
  543. if before3DaysNeckActiveHabit.SumRumina == 0 && before3DaysNeckActiveHabit.SumIntake == 0 {
  544. continue
  545. }
  546. // 更新过滤值
  547. if err := e.DB.Model(new(model.NeckActiveHabit)).
  548. Select("before_three_sum_rumina", "before_three_sum_intake").
  549. Where("id = ?", v.Id).
  550. Updates(map[string]interface{}{
  551. "before_three_sum_rumina": before3DaysNeckActiveHabit.SumRumina,
  552. "before_three_sum_intake": before3DaysNeckActiveHabit.SumIntake,
  553. }).Error; err != nil {
  554. zaplog.Error("Before3DaysNeckActiveHabit",
  555. zap.Error(err),
  556. zap.Any("NeckActiveHabit", v),
  557. zap.Any("pastureId", pastureId),
  558. )
  559. }
  560. }
  561. }
  562. // calculateChangeHigh 计算活动量变化
  563. func calculateChangeHigh(data *model.NeckActiveHabit, weeklyActive int32) int32 {
  564. highDiff := data.FilterHigh - data.HighHabit
  565. changeHigh := int32(0)
  566. if highDiff > 0 {
  567. denominator := float64(data.WeekHigh)*0.6 + float64(data.HighHabit)*0.2 + float64(weeklyActive)*0.2
  568. changeHigh = int32(math.Round((float64(highDiff) / denominator) * 100))
  569. } else {
  570. changeHigh = int32(math.Round(float64(highDiff) / float64(data.HighHabit) * 100))
  571. }
  572. return changeHigh
  573. }