neck_ring_calculate.go 22 KB

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