neck_ring_calculate.go 20 KB

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