neck_ring_handle.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  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. const (
  14. MinChangeFilter = -99
  15. MinRuminaFilter = -99
  16. MinChewFilter = -99
  17. MinChangeHigh = -99
  18. DefaultNb = 30
  19. DefaultScore = 100
  20. )
  21. var (
  22. defaultLimit = int32(1000)
  23. isDelete bool
  24. )
  25. // NeckRingOriginalMergeData 把脖环数据合并成2个小时的
  26. func (e *Entry) NeckRingOriginalMergeData() error {
  27. var err error
  28. limit := e.Cfg.NeckRingLimit
  29. if limit <= 0 {
  30. limit = defaultLimit
  31. }
  32. newTime := time.Now()
  33. createdAt := newTime.Add(-1 * time.Hour)
  34. neckRingList := make([]*model.NeckRingOriginal, 0)
  35. if err = e.DB.Model(new(model.NeckRingOriginal)).
  36. Where("is_show <= ?", pasturePb.IsShow_No).
  37. Where("created_at <= ?", createdAt.Unix()).
  38. Order("neck_ring_number,active_date,frameid").
  39. Limit(int(limit)).Find(&neckRingList).Error; err != nil {
  40. return xerr.WithStack(err)
  41. }
  42. if len(neckRingList) <= 0 {
  43. return nil
  44. }
  45. defer func() {
  46. if newTime.Day()%15 == 0 && !isDelete {
  47. // 原始数据删除15天前的
  48. e.DB.Model(new(model.NeckRingOriginal)).
  49. Where("created_at < ?", newTime.AddDate(0, 0, -15).Unix()).
  50. Delete(new(model.NeckRingOriginal))
  51. // 活动数据删除6个月前的数据
  52. e.DB.Model(new(model.NeckActiveHabit)).
  53. Where("created_at < ?", newTime.AddDate(0, -6, 0).Unix()).
  54. Delete(new(model.NeckActiveHabit))
  55. isDelete = true
  56. }
  57. }()
  58. // 计算合并
  59. neckActiveHabitList := e.recalculate(neckRingList)
  60. if len(neckActiveHabitList) <= 0 {
  61. return nil
  62. }
  63. zaplog.Info("NeckRingOriginalMergeData start", zap.Any("neckRingListLen", len(neckRingList)))
  64. for _, neckActiveHabit := range neckActiveHabitList {
  65. //更新脖环牛只相关信息 新数据直接插入
  66. historyNeckActiveHabit, ct := e.IsExistNeckActiveHabit(neckActiveHabit.NeckRingNumber, neckActiveHabit.HeatDate, neckActiveHabit.Frameid)
  67. if ct <= 0 {
  68. if err = e.DB.Create(neckActiveHabit).Error; err != nil {
  69. zaplog.Info("NeckRingOriginalMergeData-1", zap.Any("err", err), zap.Any("neckActiveHabit", neckActiveHabit))
  70. }
  71. newNeckRingProcess := model.NewNeckRingProcess(neckActiveHabit)
  72. if err = e.DB.Create(newNeckRingProcess).Error; err != nil {
  73. zaplog.Info("NeckRingOriginalMergeData-2", zap.Any("err", err), zap.Any("neckActiveHabit", neckActiveHabit))
  74. }
  75. if err = e.UpdateNeckRingOriginalIsShow(neckActiveHabit); err != nil {
  76. zaplog.Error("NeckRingOriginalMergeData-3", zap.Any("err", err), zap.Any("neckActiveHabit", neckActiveHabit))
  77. }
  78. continue
  79. }
  80. if historyNeckActiveHabit == nil || historyNeckActiveHabit.Id <= 0 {
  81. zaplog.Error("NeckRingOriginalMergeData-4", zap.Any("historyNeckActiveHabit", historyNeckActiveHabit), zap.Any("ct", ct), zap.Any("neckActiveHabit", neckActiveHabit))
  82. continue
  83. }
  84. // 重新计算
  85. newNeckActiveHabit := e.againRecalculate(historyNeckActiveHabit)
  86. if newNeckActiveHabit != nil {
  87. if err = e.DB.Model(new(model.NeckActiveHabit)).
  88. Select("rumina", "intake", "inactive", "gasp", "other", "high", "active").
  89. Where("id = ?", historyNeckActiveHabit.Id).
  90. Updates(newNeckActiveHabit).Error; err != nil {
  91. zaplog.Error("NeckRingOriginalMergeData-5", zap.Any("historyNeckActiveHabit", historyNeckActiveHabit), zap.Any("ct", ct), zap.Any("newNeckActiveHabit", newNeckActiveHabit))
  92. }
  93. }
  94. }
  95. return nil
  96. }
  97. func (e *Entry) NeckRingCalculate() error {
  98. pastureList := e.FindPastureList()
  99. if pastureList == nil || len(pastureList) == 0 {
  100. return nil
  101. }
  102. for _, pasture := range pastureList {
  103. if err := e.EntryUpdateActiveHabit(pasture.Id); err != nil {
  104. zaplog.Error("PastureUpdateActiveHabit", zap.Any("err", err), zap.Any("pasture", pasture))
  105. }
  106. zaplog.Info(fmt.Sprintf("PastureUpdateActiveHabit Success %d", pasture.Id))
  107. }
  108. return nil
  109. }
  110. // recalculate 合并计算
  111. func (e *Entry) recalculate(neckRingList []*model.NeckRingOriginal) []*model.NeckActiveHabit {
  112. originalMapData := make(map[string]*model.NeckRingOriginalMerge)
  113. // 合并成2个小时的
  114. for _, v := range neckRingList {
  115. xframeId := util.XFrameId(v.Frameid)
  116. mapKey := fmt.Sprintf("%s%s%s%s%d", v.NeckRingNumber, model.JoinKey, v.ActiveDate, model.JoinKey, xframeId) // 0001/2023-12-04/0 0001/2023-12-03/4
  117. if originalMapData[mapKey] == nil {
  118. originalMapData[mapKey] = new(model.NeckRingOriginalMerge)
  119. }
  120. originalMapData[mapKey].IsMageData(v, xframeId)
  121. }
  122. currTime := time.Now()
  123. // 算平均值
  124. for k, v := range originalMapData {
  125. // 过滤掉合并后不满6条数据
  126. if v.RecordCount != 6 {
  127. currMaxXframeId := util.FrameIdMapReverse[int32(currTime.Hour())]
  128. activeDateString := fmt.Sprintf("%s %02d:00:00", v.ActiveDate, v.XframeId*2+1)
  129. activeDate, _ := time.Parse(model.LayoutTime, activeDateString)
  130. if currMaxXframeId-v.XframeId <= 1 && currTime.Add(-1*time.Hour).Unix() < activeDate.Unix() {
  131. delete(originalMapData, k)
  132. }
  133. }
  134. v.SumAvg()
  135. }
  136. return model.NeckRingOriginalMap(originalMapData).ForMatData()
  137. }
  138. func (e *Entry) againRecalculate(data *model.NeckActiveHabit) *model.NeckActiveHabit {
  139. originalList := make([]*model.NeckRingOriginal, 0)
  140. frameIds := util.FrameIds(data.Frameid)
  141. if err := e.DB.Model(new(model.NeckRingOriginal)).
  142. Where("neck_ring_number = ?", data.NeckRingNumber).
  143. Where("active_date = ?", data.HeatDate).
  144. Where("frameid IN (?)", frameIds).
  145. Find(&originalList).Error; err != nil {
  146. return nil
  147. }
  148. newDataList := e.recalculate(originalList)
  149. if len(newDataList) != 1 {
  150. return nil
  151. }
  152. return newDataList[0]
  153. }
  154. func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
  155. lastMaxHabitData, err := e.GetSystemConfigure(pastureId, model.MaxHabit)
  156. if err != nil {
  157. return xerr.WithStack(err)
  158. }
  159. lastMaxHabitId := lastMaxHabitData.Value
  160. currMaxHabit := &model.NeckActiveHabit{}
  161. if err = e.DB.Model(new(model.NeckActiveHabit)).
  162. Where("id > ?", lastMaxHabitId).
  163. Where("pasture_id = ?", pastureId).
  164. Where("is_show = ?", pasturePb.IsShow_No).
  165. Order("id desc").First(currMaxHabit).Error; err != nil {
  166. return xerr.WithStack(err)
  167. }
  168. if currMaxHabit.Id <= 0 || currMaxHabit.Id <= lastMaxHabitId {
  169. return nil
  170. }
  171. defer func() {
  172. // 更新最后一次执行的id值
  173. if err == nil {
  174. e.DB.Model(new(model.SystemConfigure)).
  175. Where("name = ?", model.MaxHabit).
  176. Where("pasture_id = ?", pastureId).
  177. Update("value", currMaxHabit.Id)
  178. }
  179. }()
  180. // 获取这段执行数据内最大日期和最小日期
  181. xToday := &XToday{}
  182. activeLowest, err := e.GetSystemConfigure(pastureId, model.High)
  183. if err != nil {
  184. return xerr.WithStack(err)
  185. }
  186. ruminaLowest, err := e.GetSystemConfigure(pastureId, model.Rumina)
  187. if err != nil {
  188. return xerr.WithStack(err)
  189. }
  190. xRuminaDisc, err := e.GetSystemConfigure(pastureId, model.XRuminaDisc)
  191. if err != nil {
  192. return err
  193. }
  194. xChangeDiscount, err := e.GetSystemConfigure(pastureId, model.XChangeDiscount)
  195. if err != nil {
  196. return err
  197. }
  198. weeklyActive, err := e.GetSystemConfigure(pastureId, model.WeeklyActive)
  199. if err != nil {
  200. return xerr.WithStack(err)
  201. }
  202. xToday.High = int32(activeLowest.Value)
  203. xToday.Rumina = int32(ruminaLowest.Value)
  204. xToday.XRuminaDisc = int32(xRuminaDisc.Value)
  205. xToday.XChangeDiscount = int32(xChangeDiscount.Value)
  206. xToday.CurrMaxHabitId = currMaxHabit.Id
  207. xToday.LastMaxHabitId = lastMaxHabitId
  208. xToday.WeeklyActive = int32(weeklyActive.Value)
  209. // 更新活动滤波
  210. if err = e.FirstFilterUpdate(pastureId, xToday); err != nil {
  211. zaplog.Error("EntryUpdateActiveHabit", zap.Any("FirstFilterUpdate", err), zap.Any("xToday", xToday))
  212. }
  213. // 更新周平均值
  214. if err = e.WeeklyActiveAvgUpdate(pastureId, xToday); err != nil {
  215. zaplog.Error("EntryUpdateActiveHabit", zap.Any("WeeklyActiveAvgUpdate", err), zap.Any("xToday", xToday))
  216. }
  217. // 二次更新滤波
  218. if err = e.SecondUpdateChangeFilter(pastureId, xToday); err != nil {
  219. zaplog.Error("EntryUpdateActiveHabit", zap.Any("SecondUpdateChangeFilter", err), zap.Any("xToday", xToday))
  220. }
  221. // 活动量校正系数和健康评分
  222. if err = e.FilterCorrectAndScoreUpdate(pastureId, xToday); err != nil {
  223. zaplog.Error("EntryUpdateActiveHabit", zap.Any("ActivityVolumeChanges", err), zap.Any("xToday", xToday))
  224. }
  225. if err = e.DB.Model(new(model.NeckActiveHabit)).
  226. Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId).
  227. Where("pasture_id = ?", pastureId).
  228. Where("is_show = ?", pasturePb.IsShow_No).
  229. Where("change_filter = ?", model.InitChangeFilter).
  230. Updates(map[string]interface{}{
  231. "change_filter": model.DefaultChangeFilter,
  232. "rumina_filter": model.DefaultRuminaFilter,
  233. "chew_filter": model.DefaultChewFilter,
  234. }).Error; err != nil {
  235. zaplog.Error("EntryUpdateActiveHabit", zap.Any("change_filter", err), zap.Any("xToday", xToday))
  236. }
  237. if err = e.DB.Model(new(model.NeckActiveHabit)).
  238. Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId).
  239. Where("pasture_id = ?", pastureId).
  240. Where("is_show = ?", pasturePb.IsShow_No).
  241. Where("change_filter < ?", 0).
  242. Where("filter_correct < ?", model.DefaultFilterCorrect).
  243. Updates(map[string]interface{}{
  244. "filter_correct": model.DefaultFilterCorrect,
  245. "is_show": pasturePb.IsShow_Ok,
  246. }).Error; err != nil {
  247. zaplog.Error("EntryUpdateActiveHabit", zap.Any("filter_correct", err), zap.Any("xToday", xToday))
  248. }
  249. // 插入群体校正表
  250. if err = e.UpdateChangeAdJust(pastureId, xToday); err != nil {
  251. zaplog.Error("EntryUpdateActiveHabit", zap.Any("UpdateChangeAdJust", err), zap.Any("xToday", xToday))
  252. }
  253. return nil
  254. }
  255. // CurrentMaxXFrameId 当前最大frameid
  256. func (e *Entry) CurrentMaxXFrameId(neckRingNumber, activeDate string) (frameid int32) {
  257. type Fm struct {
  258. Frameid int32
  259. }
  260. maxFx := &Fm{}
  261. if err := e.DB.Model(new(model.NeckRingOriginal)).
  262. Select("frameid").
  263. Where("neck_ring_number = ?", neckRingNumber).
  264. Where("active_date = ?", activeDate).
  265. Order("frameid DESC").First(maxFx).Error; err != nil {
  266. zaplog.Error("CurrentMaxXFrameId", zap.Any("err", err))
  267. return 0
  268. }
  269. return maxFx.Frameid
  270. }
  271. // FirstFilterUpdate 首次更新活动滤波
  272. func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) error {
  273. newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  274. if err := e.DB.Model(new(model.NeckActiveHabit)).
  275. Where("id <= ?", xToDay.CurrMaxHabitId).
  276. Where("pasture_id = ?", pastureId).
  277. Where("is_show = ?", pasturePb.IsShow_No).
  278. Where("change_filter = ?", model.InitChangeFilter).
  279. Where(e.DB.Where("high >= ?", xToDay.High).Or("rumina >= ?", xToDay.Rumina)). // 活动量过低牛只不参与计算
  280. Order("neck_ring_number,heat_date,frameid").
  281. Limit(int(defaultLimit)).Find(&newNeckActiveHabitList).Error; err != nil {
  282. return xerr.WithStack(err)
  283. }
  284. // 活动量滤波
  285. for _, v := range newNeckActiveHabitList {
  286. // 过滤牛只未绑定的脖环的数据
  287. cowInfo := e.GetCowInfoByNeckRingNumber(v.PastureId, v.NeckRingNumber)
  288. if cowInfo == nil || cowInfo.Id <= 0 {
  289. continue
  290. }
  291. firstFilterData := &FirstFilterData{}
  292. frameId := v.Frameid
  293. heatDate := v.HeatDate
  294. if v.Frameid == 0 {
  295. frameId = 11
  296. heatDateParse, _ := time.Parse(model.LayoutDate2, heatDate)
  297. heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2)
  298. }
  299. if err := e.DB.Model(new(model.NeckActiveHabit)).
  300. Select("neck_ring_number", "filter_high", "filter_rumina", "filter_chew").
  301. Where("neck_ring_number = ?", v.NeckRingNumber).
  302. Where("heat_date = ?", heatDate).
  303. Where("frameid = ?", frameId).
  304. First(&firstFilterData).Error; err != nil {
  305. zaplog.Error("FirstFilterUpdate",
  306. zap.Any("err", err),
  307. zap.Any("NeckRingNumber", v.NeckRingNumber),
  308. zap.Any("heatDate", heatDate),
  309. zap.Any("frameId", frameId),
  310. )
  311. }
  312. if v.FilterHigh > 0 {
  313. firstFilterData.FilterHigh = v.FilterHigh
  314. } else {
  315. if v.NeckRingNumber == firstFilterData.NeckRingNumber {
  316. firstFilterData.FilterHigh = int32(computeIfPositiveElse(float64(v.High), float64(firstFilterData.FilterHigh), 0.23, 0.77))
  317. } else {
  318. firstFilterData.FilterHigh = v.High
  319. }
  320. }
  321. if v.FilterRumina > 0 {
  322. firstFilterData.FilterRumina = v.FilterRumina
  323. } else {
  324. if v.NeckRingNumber == firstFilterData.NeckRingNumber {
  325. firstFilterData.FilterRumina = int32(computeIfPositiveElse(float64(v.Rumina), float64(firstFilterData.FilterRumina), 0.33, 0.67))
  326. } else {
  327. firstFilterData.FilterRumina = v.Rumina
  328. }
  329. }
  330. if v.FilterChew > 0 {
  331. firstFilterData.FilterChew = v.FilterChew
  332. } else {
  333. if v.NeckRingNumber == firstFilterData.NeckRingNumber {
  334. firstFilterData.FilterChew = int32(computeIfPositiveElse(float64(v.Rumina+v.Intake), float64(firstFilterData.FilterChew), 0.33, 0.67))
  335. } else {
  336. firstFilterData.FilterChew = v.Rumina + v.Intake
  337. }
  338. }
  339. // 更新过滤值
  340. if err := e.DB.Model(new(model.NeckActiveHabit)).
  341. Select("filter_high", "filter_rumina", "filter_chew", "cow_id", "lact", "calving_age").
  342. Where("id = ?", v.Id).
  343. Updates(map[string]interface{}{
  344. "filter_high": firstFilterData.FilterHigh,
  345. "filter_rumina": firstFilterData.FilterRumina,
  346. "filter_chew": firstFilterData.FilterChew,
  347. "cow_id": cowInfo.Id,
  348. "lact": cowInfo.Lact,
  349. "calving_age": cowInfo.CalvingAge,
  350. }).Error; err != nil {
  351. return xerr.WithStack(err)
  352. }
  353. }
  354. zaplog.Info("EntryUpdateActiveHabit-FilterUpdate-Success")
  355. return nil
  356. }
  357. // WeeklyActiveAvgUpdate 更新周平均值
  358. func (e *Entry) WeeklyActiveAvgUpdate(pastureId int64, xToday *XToday) (err error) {
  359. neckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  360. if err = e.DB.Model(new(model.NeckActiveHabit)).
  361. Where("id <= ?", xToday.CurrMaxHabitId).
  362. Where("pasture_id = ?", pastureId).
  363. Where("change_filter = ?", model.InitChangeFilter).
  364. Where("is_show = ?", pasturePb.IsShow_No).
  365. Where(e.DB.Where("high > ?", xToday.High).Or("rumina >= ?", xToday.Rumina)).
  366. Order("neck_ring_number,heat_date,frameid").
  367. Limit(int(defaultLimit)).Find(&neckActiveHabitList).Error; err != nil {
  368. return xerr.WithStack(err)
  369. }
  370. for _, v := range neckActiveHabitList {
  371. beginDayDate, _ := time.Parse(model.LayoutDate2, v.HeatDate)
  372. before7DayDate := beginDayDate.AddDate(0, 0, -7).Format(model.LayoutDate2)
  373. before1DayDate := beginDayDate.AddDate(0, 0, -1).Format(model.LayoutDate2)
  374. activeTime := fmt.Sprintf("%s %02d:00:00", v.HeatDate, v.Frameid*2+1)
  375. activeStartTimeParse, _ := time.Parse(model.LayoutTime, activeTime)
  376. activeStartTime := activeStartTimeParse.Add(-23 * time.Hour).Format(model.LayoutTime)
  377. weekHabitData := &WeekHabit{}
  378. if err = e.DB.Model(new(model.NeckActiveHabit)).
  379. Select(
  380. "neck_ring_number",
  381. "IF(COUNT(1)>=3, ROUND((SUM(filter_high) -MIN(filter_high) -MAX(filter_high))/ABS(COUNT(1) -2),0), -1) as week_high_habit",
  382. "IF(COUNT(1)>=3, ROUND((SUM(filter_rumina) -MIN(filter_rumina) -MAX(filter_rumina))/ABS(COUNT(1) -2),0), -1) as week_rumina_habit",
  383. "IF(COUNT(1)>=3, ROUND((SUM(filter_chew) -MIN(filter_chew) -MAX(filter_chew))/ABS(COUNT(1) -2),0), -1) as week_chew_habit",
  384. "ROUND(AVG(intake),0) as week_intake_habit",
  385. "ROUND(AVG(inactive),0) as week_inactive_habit",
  386. ).Where("pasture_id = ?", pastureId).
  387. Where("heat_date BETWEEN ? AND ?", before7DayDate, before1DayDate).
  388. Where("neck_ring_number = ? ", v.NeckRingNumber).
  389. Where("frameid = ?", v.Frameid).
  390. Where(e.DB.Where("high > ?", xToday.High).Or("rumina >= ?", xToday.Rumina)).
  391. Group("neck_ring_number").First(weekHabitData).Error; err != nil {
  392. zaplog.Error("WeeklyActiveAvgUpdate-1", zap.Any("error", err), zap.Any("xToday", xToday))
  393. }
  394. // 累计24小时数值
  395. sumHabitData := &SumHabit{}
  396. if err = e.DB.Model(new(model.NeckActiveHabit)).
  397. Select(
  398. "neck_ring_number",
  399. "IF(COUNT(1)>6, ROUND(AVG(filter_rumina)*12,0), 0) as sum_rumina",
  400. "IF(COUNT(1)>6, ROUND(AVG(intake)*12,0), 0) as sum_intake",
  401. "IF(COUNT(1)>6, ROUND(AVG(inactive)*12,0), 0) as sum_inactive",
  402. "IF(COUNT(1)>6, ROUND(AVG(active)*12,0), 0) as sum_active",
  403. "MAX(change_filter) as sum_max_high",
  404. fmt.Sprintf("MIN(IF(change_filter > %d, change_filter, %d)) as sum_min_high", model.DefaultChangeFilter, model.InitChangeFilter),
  405. fmt.Sprintf("MIN( CASE WHEN filter_chew > %d THEN filter_chew WHEN filter_rumina >= %d THEN filter_rumina ELSE 0 END) as sum_min_chew", model.DefaultChangeFilter, model.DefaultRuminaFilter),
  406. ).
  407. Where("pasture_id = ?", pastureId).
  408. Where("heat_date BETWEEN ? AND ?", before1DayDate, beginDayDate).
  409. Where("active_time BETWEEN ? AND ?", activeStartTime, activeTime).
  410. Where(e.DB.Where("high > ?", xToday.High).Or("rumina >= ?", xToday.Rumina)).
  411. Where("neck_ring_number = ? AND frameid = ?", v.NeckRingNumber, v.Frameid).
  412. Group("neck_ring_number").First(sumHabitData).Error; err != nil {
  413. zaplog.Error("WeeklyActiveAvgUpdate-2", zap.Any("error", err), zap.Any("xToday", xToday))
  414. }
  415. highDiff := v.FilterHigh - weekHabitData.WeekHighHabit
  416. denominator := float64(v.WeekHigh)*0.6 + float64(weekHabitData.WeekHighHabit)*0.2 + float64(xToday.WeeklyActive)*0.2
  417. if highDiff > 0 {
  418. v.ChangeHigh = int32(math.Round((float64(highDiff) / denominator) * 100))
  419. } else {
  420. v.ChangeHigh = int32(math.Round(float64(highDiff) / denominator * 100))
  421. }
  422. if weekHabitData.WeekRuminaHabit != 0 {
  423. v.ChangeRumina = int32(math.Round(float64(v.FilterRumina-weekHabitData.WeekRuminaHabit) / float64(weekHabitData.WeekRuminaHabit) * 100))
  424. } else {
  425. v.ChangeRumina = 0
  426. }
  427. if weekHabitData.WeekChewHabit != 0 {
  428. v.ChangeChew = int32(math.Round(float64(v.FilterChew-weekHabitData.WeekChewHabit) / float64(weekHabitData.WeekChewHabit) * 100))
  429. } else {
  430. v.ChangeChew = 0
  431. }
  432. // 三天前的反刍和采食
  433. before3DaysNeckActiveHabit := &model.NeckActiveHabit{}
  434. before3DayDate := beginDayDate.AddDate(0, 0, -3).Format(model.LayoutDate2)
  435. if err = e.DB.Model(new(model.NeckActiveHabit)).
  436. Select("sum_rumina", "sum_intake").
  437. Where("pasture_id = ?", pastureId).
  438. Where("neck_ring_number = ?", v.NeckRingNumber).
  439. Where("heat_date = ?", before3DayDate).
  440. Where("frameid = ? ", v.Frameid).
  441. First(before3DaysNeckActiveHabit).Error; err != nil {
  442. zaplog.Error("WeeklyActiveAvgUpdate-3", zap.Any("error", err), zap.Any("xToday", xToday))
  443. }
  444. if err = e.DB.Model(new(model.NeckActiveHabit)).
  445. Select(
  446. "week_high_habit", "week_rumina_habit", "week_chew_habit", "week_intake_habit", "week_inactive_habit",
  447. "sum_rumina", "sum_intake", "sum_inactive", "sum_active", "sum_max_high", "sum_min_high", "sum_min_chew",
  448. "change_high", "change_rumina", "change_chew", "before_three_sum_rumina", "before_three_sum_intake",
  449. ).Where("id = ?", v.Id).
  450. Updates(map[string]interface{}{
  451. "week_high_habit": weekHabitData.WeekHighHabit,
  452. "week_rumina_habit": weekHabitData.WeekRuminaHabit,
  453. "week_chew_habit": weekHabitData.WeekChewHabit,
  454. "week_intake_habit": weekHabitData.WeekIntakeHabit,
  455. "week_inactive_habit": weekHabitData.WeekIntakeHabit,
  456. "sum_rumina": sumHabitData.SumRumina,
  457. "sum_intake": sumHabitData.SumIntake,
  458. "sum_inactive": sumHabitData.SumInactive,
  459. "sum_active": sumHabitData.SumActive,
  460. "sum_max_high": sumHabitData.SumMaxHigh,
  461. "sum_min_high": sumHabitData.SumMinHigh,
  462. "sum_min_chew": sumHabitData.SumMinChew,
  463. "change_high": v.ChangeHigh,
  464. "change_rumina": v.ChangeRumina,
  465. "change_chew": v.ChangeChew,
  466. "before_three_sum_rumina": before3DaysNeckActiveHabit.SumRumina,
  467. "before_three_sum_intake": before3DaysNeckActiveHabit.SumIntake,
  468. }).Error; err != nil {
  469. zaplog.Error("WeeklyActiveAvgUpdate-6", zap.Any("error", err), zap.Any("xToday", xToday))
  470. }
  471. }
  472. return nil
  473. }
  474. // SecondUpdateChangeFilter 第二次更新变化趋势滤波
  475. func (e *Entry) SecondUpdateChangeFilter(pastureId int64, xToday *XToday) (err error) {
  476. newChangeFilterList := make([]*ChangeFilterData, 0)
  477. if err = e.DB.Model(new(model.NeckActiveHabit)).
  478. Select("id", "neck_ring_number", "change_high", "change_filter", "rumina_filter", "change_rumina",
  479. "chew_filter", "change_chew", "heat_date", "frameid", "IF(lact = 0, 0.8, 1) as xlc_dis_count").
  480. Where("heat_date >= ?", time.Now().AddDate(0, 0, -2).Format(model.LayoutDate2)).
  481. Where("pasture_id = ?", pastureId).
  482. Where("change_filter = ?", model.InitChangeFilter).
  483. Where("change_high > ?", MinChangeHigh).
  484. Order("neck_ring_number,heat_date,frameid").
  485. Find(&newChangeFilterList).Error; err != nil {
  486. return xerr.WithStack(err)
  487. }
  488. for _, v := range newChangeFilterList {
  489. secondFilterData := &SecondFilterData{}
  490. frameId := v.FrameId
  491. heatDate := v.HeatDate
  492. if v.FrameId == 0 {
  493. frameId = 11
  494. heatDateParse, _ := time.Parse(model.LayoutDate2, heatDate)
  495. heatDate = heatDateParse.AddDate(0, 0, -1).Format(model.LayoutDate2)
  496. }
  497. if err = e.DB.Model(new(model.NeckActiveHabit)).
  498. Select("neck_ring_number", "filter_high", "filter_rumina", "filter_chew").
  499. Where("neck_ring_number = ?", v.NeckRingNumber).
  500. Where("heat_date = ?", heatDate).
  501. Where("frameid = ?", frameId).
  502. First(&secondFilterData).Error; err != nil {
  503. zaplog.Error("EntryUpdateActiveHabit", zap.Any("FirstFilterUpdate", err))
  504. }
  505. if v.ChangeFilter > MinChangeFilter {
  506. secondFilterData.ChangeFilter = float64(v.ChangeFilter)
  507. } else {
  508. if v.NeckRingNumber == secondFilterData.NeckRingNumber {
  509. secondFilterData.ChangeFilter = secondFilterData.ChangeFilter*(1-(float64(xToday.XChangeDiscount)/10)*v.XlcDisCount) +
  510. math.Min(float64(v.ChangeHigh), secondFilterData.ChangeFilter+135)*(float64(xToday.XChangeDiscount)/10)*v.XlcDisCount
  511. } else {
  512. secondFilterData.ChangeFilter = 0
  513. }
  514. }
  515. if v.RuminaFilter > MinRuminaFilter {
  516. secondFilterData.RuminaFilter = float64(v.ChangeFilter)
  517. } else {
  518. if v.NeckRingNumber == secondFilterData.NeckRingNumber {
  519. discount := float64(xToday.XRuminaDisc) / 10 * v.XlcDisCount
  520. if math.Abs(float64(v.ChangeRumina)) > 60 {
  521. discount *= 0.5
  522. }
  523. secondFilterData.RuminaFilter = secondFilterData.RuminaFilter*(1-discount) + float64(v.ChangeRumina)*discount
  524. } else {
  525. secondFilterData.RuminaFilter = 0
  526. }
  527. }
  528. secondFilterData.RuminaFilter = math.Min(50, secondFilterData.RuminaFilter)
  529. if v.ChewFilter > MinChewFilter {
  530. secondFilterData.ChewFilter = float64(v.ChangeChew)
  531. } else {
  532. if v.NeckRingNumber == secondFilterData.NeckRingNumber {
  533. discount := float64(xToday.XRuminaDisc) / 10
  534. if math.Abs(float64(v.ChangeChew)) > 60 {
  535. discount *= 0.5
  536. }
  537. secondFilterData.ChewFilter = secondFilterData.ChewFilter*(1-discount) + float64(v.ChangeChew)*discount
  538. } else {
  539. secondFilterData.ChewFilter = 0
  540. }
  541. }
  542. secondFilterData.ChewFilter = math.Min(50, secondFilterData.ChewFilter)
  543. if err = e.DB.Model(new(model.NeckActiveHabit)).
  544. Select("change_filter", "rumina_filter", "chew_filter").
  545. Where("id = ?", v.Id).
  546. Updates(map[string]interface{}{
  547. "change_filter": secondFilterData.ChangeFilter,
  548. "rumina_filter": secondFilterData.RuminaFilter,
  549. "chew_filter": secondFilterData.ChewFilter,
  550. }).Error; err != nil {
  551. zaplog.Error("SecondUpdateChangeFilter-1", zap.Any("error", err), zap.Any("xToday", xToday))
  552. }
  553. }
  554. zaplog.Info("SecondUpdateChangeFilter-Success")
  555. return nil
  556. }
  557. // FilterCorrectAndScoreUpdate 计算活动量变化趋势校正值(活跃度校正)和健康评分
  558. func (e *Entry) FilterCorrectAndScoreUpdate(pastureId int64, xToday *XToday) error {
  559. beginDayDate := time.Now()
  560. before7DayDate := beginDayDate.AddDate(0, 0, -7).Format(model.LayoutDate2)
  561. before1DayDate := beginDayDate.AddDate(0, 0, -1).Format(model.LayoutDate2)
  562. activityVolumeList := make([]*ActivityVolume, 0)
  563. activityVolumeMap := make(map[string]*ActivityVolume)
  564. if err := e.DB.Model(new(model.NeckActiveHabit)).
  565. Select("neck_ring_number", "AVG(IF(change_filter>=60, 60, change_filter)) as avg_filter", "ROUND(STD(IF(change_filter>=60, 60, change_filter))) as std_filter", "COUNT(1) as nb").
  566. Where("heat_date BETWEEN ? AND ?", before7DayDate, before1DayDate).
  567. Where("pasture_id = ?", pastureId).
  568. Where(e.DB.Where("high > ?", xToday.High).Or("rumina >= ?", xToday.Rumina)).
  569. Where("active_time <= ?", beginDayDate.Add(-12*time.Hour).Format(model.LayoutTime)).
  570. Where("change_filter > ?", MinChangeFilter).
  571. Having("nb > ?", DefaultNb).
  572. Group("neck_ring_number").
  573. Find(&activityVolumeList).Error; err != nil {
  574. zaplog.Error("ActivityVolumeChanges-0", zap.Any("error", err), zap.Any("xToday", xToday))
  575. }
  576. if len(activityVolumeList) > 0 {
  577. for _, v := range activityVolumeList {
  578. activityVolumeMap[v.NeckRingNumber] = v
  579. }
  580. }
  581. neckActiveHabitList := make([]*model.NeckActiveHabit, 0)
  582. if err := e.DB.Model(new(model.NeckActiveHabit)).
  583. Where("id <= ?", xToday.CurrMaxHabitId).
  584. Where("heat_date >= ?", before1DayDate).
  585. Where("pasture_id = ?", pastureId).
  586. Where(e.DB.Where("high > ?", xToday.High).Or("rumina > ?", xToday.Rumina)).
  587. Find(&neckActiveHabitList).Error; err != nil {
  588. zaplog.Error("ActivityVolumeChanges-1", zap.Any("error", err), zap.Any("xToday", xToday))
  589. return xerr.WithStack(err)
  590. }
  591. for _, v := range neckActiveHabitList {
  592. if filterCorrectMap, ok := activityVolumeMap[v.NeckRingNumber]; ok {
  593. filterCorrect := model.DefaultFilterCorrect - int(math.Floor(float64(filterCorrectMap.AvgFilter)/3+float64(filterCorrectMap.StdFilter)/2))
  594. // 活动量校正系数
  595. if err := e.DB.Model(new(model.NeckActiveHabit)).
  596. Where("id = ?", v.Id).
  597. Where("neck_ring_number = ?", v.NeckRingNumber).
  598. Update("filter_correct", filterCorrect).Error; err != nil {
  599. zaplog.Error("ActivityVolumeChanges-2", zap.Any("error", err), zap.Any("xToday", xToday))
  600. continue
  601. }
  602. }
  603. cowScore := calculateScore(v)
  604. if err := e.DB.Model(new(model.NeckActiveHabit)).
  605. Where("id = ?", v.Id).
  606. Update("score", cowScore).Error; err != nil {
  607. zaplog.Error("ActivityVolumeChanges-2", zap.Any("error", err), zap.Any("xToday", xToday))
  608. continue
  609. }
  610. }
  611. zaplog.Info("EntryUpdateActiveHabit-ActivityVolumeChanges-Success")
  612. return nil
  613. }
  614. // UpdateChangeAdJust 更新群体校正数据
  615. func (e *Entry) UpdateChangeAdJust(pastureId int64, xToday *XToday) error {
  616. res := make([]*model.NeckRingBarChange, 0)
  617. oneDayAgo := time.Now().AddDate(0, 0, -1).Format(model.LayoutDate2)
  618. //SELECT h.neck_ring_number,h.heat_date, h.frameid, c.pen_id, c.pen_name, COUNT(*) as nb, ROUND(AVG(h.change_high)) as change_high,
  619. //ROUND(AVG(h.change_filter)) as change_filter F
  620. //ROM neck_active_habit as h JOIN cow as c ON h.neck_ring_number = c.neck_ring_number
  621. //WHERE h.pasture_id = 1 AND h.heat_date >= '2025-01-16' AND h.cow_id >= 0
  622. //GROUP BY h.heat_date, h.frameid, c.pen_id ORDER BY h.heat_date, h.frameid, c.pen_name
  623. if err := e.DB.Table(fmt.Sprintf("%s as h", new(model.NeckActiveHabit).TableName())).
  624. Select("h.neck_ring_number,h.heat_date, h.frameid, c.pen_id, c.pen_name, COUNT(*) as nb, ROUND(AVG(h.change_high)) as change_high, ROUND(AVG(h.change_filter)) as change_filter").
  625. Joins("JOIN cow as c ON h.neck_ring_number = c.neck_ring_number").
  626. Where("h.pasture_id = ?", pastureId).
  627. Where("h.heat_date >= ?", oneDayAgo).
  628. Where("h.cow_id >= ?", 0).
  629. Group("h.heat_date, h.frameid, c.pen_id").
  630. Order("h.heat_date, h.frameid, c.pen_name").
  631. Find(&res).Error; err != nil {
  632. return xerr.WithStack(err)
  633. }
  634. for _, v := range res {
  635. if err := e.DB.Model(new(model.NeckActiveHabit)).
  636. Where("id > ?", xToday.LastMaxHabitId).
  637. Where("heat_date = ?", v.HeatDate).
  638. Where("frameid = ?", v.FrameId).
  639. Where("neck_ring_number = ?", v.NeckRingNumber).
  640. Update("change_adjust", v.ChangeHigh).Error; err != nil {
  641. zaplog.Error("UpdateChangeAdJust-1", zap.Any("error", err), zap.Any("xToday", xToday))
  642. }
  643. }
  644. return nil
  645. }
  646. func (e *Entry) UpdateNeckRingOriginalIsShow(neckRingList *model.NeckActiveHabit) error {
  647. if err := e.DB.Model(new(model.NeckRingOriginal)).
  648. Where("neck_ring_number = ?", neckRingList.NeckRingNumber).
  649. Where("active_date = ?", neckRingList.HeatDate).
  650. Where("frameid IN (?)", util.FrameIds(neckRingList.Frameid)).
  651. Update("is_show", pasturePb.IsShow_Ok).Error; err != nil {
  652. return xerr.WithStack(err)
  653. }
  654. return nil
  655. }
  656. // computeIfPositiveElse 辅助函数来计算过滤值
  657. func computeIfPositiveElse(newValue, prevFilterValue float64, weightPrev, weightNew float64) float64 {
  658. return math.Ceil((prevFilterValue * weightPrev) + (weightNew * newValue))
  659. }
  660. // 计算 score 的逻辑
  661. func calculateScore(habit *model.NeckActiveHabit) int {
  662. // 第一部分逻辑
  663. var part1 float64
  664. switch {
  665. case (habit.CalvingAge <= 1 && habit.Lact >= 1) ||
  666. (habit.CalvingAge >= 2 && habit.CalvingAge <= 13 && (habit.SumRumina+habit.SumIntake) == 0) ||
  667. ((habit.Lact == 0 || habit.CalvingAge >= 14) && habit.ChangeFilter == -99):
  668. part1 = -199
  669. case habit.CalvingAge >= 2 && habit.CalvingAge <= 13:
  670. part1 = math.Min((float64(habit.SumRumina+habit.SumIntake)-(100+math.Min(7, float64(habit.CalvingAge))*60))/10*2, 0)
  671. case habit.ChangeFilter > -99:
  672. part1 = math.Min(0, math.Min(getValueOrDefault(float64(habit.ChangeFilter), 0), getValueOrDefault(float64(habit.SumMinHigh), 0)))*0.2 +
  673. math.Min(0, math.Min(getValueOrDefault(float64(habit.ChangeFilter), 0), getValueOrDefault(float64(habit.SumMinChew), 0)))*0.2 +
  674. getRuminaSumIntakeSumScore(float64(habit.SumRumina+habit.SumIntake)) + getAdditionalScore(habit)
  675. default:
  676. part1 = -299
  677. }
  678. // 第二部分逻辑
  679. var part2 float64
  680. switch {
  681. case habit.FirmwareVersion%100 >= 52:
  682. part2 = 1
  683. case habit.FirmwareVersion%100 >= 30 && habit.FirmwareVersion%100 <= 43:
  684. part2 = 0.8
  685. default:
  686. part2 = 0.6
  687. }
  688. // 最终 score
  689. return DefaultScore + int(math.Floor(part1*part2))
  690. }
  691. // 获取值或默认值
  692. func getValueOrDefault(value, defaultValue float64) float64 {
  693. if value > -99 {
  694. return value
  695. }
  696. return defaultValue
  697. }
  698. // 计算累计反刍得分
  699. func getRuminaSumIntakeSumScore(sum float64) float64 {
  700. switch {
  701. case sum < 80:
  702. return -30
  703. case sum < 180:
  704. return -20
  705. case sum < 280:
  706. return -10
  707. default:
  708. return 0
  709. }
  710. }
  711. // 计算额外得分
  712. func getAdditionalScore(habit *model.NeckActiveHabit) float64 {
  713. var score float64
  714. if (habit.SumRumina+habit.SumIntake < 280 || habit.SumMinHigh+habit.SumMinChew < -50) && habit.SumMaxHigh > 50 {
  715. score += 10
  716. }
  717. if habit.ChangeFilter < -30 && habit.ChangeFilter <= habit.SumMinHigh && habit.ChewFilter < -30 && habit.ChewFilter <= habit.SumMinChew {
  718. score -= 5
  719. }
  720. return score
  721. }