neck_ring_calculate.go 24 KB

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