cow.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. package model
  2. import (
  3. "fmt"
  4. "kpt-pasture/util"
  5. "math"
  6. "time"
  7. pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
  8. )
  9. type Cow struct {
  10. Id int64 `json:"id"`
  11. PastureId int64 `json:"pastureId"` // 牧场id
  12. Sex pasturePb.Genders_Kind `json:"sex"` // 性别
  13. NeckRingNumber string `json:"neckRingNumber"` // 脖环号
  14. EarNumber string `json:"earNumber"` // 耳标号
  15. EarOldNumber string `json:"earOldNumber"` // 旧耳标号
  16. PenId int32 `json:"penId"` // 栏舍id
  17. PenName string `json:"penName"` // 栏舍名称
  18. Lact int32 `json:"lact"` // 胎次
  19. DayAge int32 `json:"dayAge"` // 日龄
  20. CalvingAge int64 `json:"calvingAge"` // 产后天使
  21. PregnancyAge int32 `json:"pregnancyAge"` // 怀孕天数 孕检结果有阳性更新,产犊后至0
  22. AdmissionAge int32 `json:"admissionAge"` // 入场日龄
  23. AbortionAge int32 `json:"abortionAge"` // 流产天数
  24. CowType pasturePb.CowType_Kind `json:"cowType"` // 牛只类型
  25. BreedStatus pasturePb.BreedStatus_Kind `json:"breedStatus"` // 繁殖状态
  26. CowKind pasturePb.CowKind_Kind `json:"cowKind"` // 牛只品种
  27. BirthWeight int64 `json:"birthWeight"` // 出生体重
  28. CurrentWeight int64 `json:"currentWeight"` // 当前体重
  29. AdmissionWeight int64 `json:"admissionWeight"` // 入场体重
  30. SourceId pasturePb.CowSource_Kind `json:"sourceId"` // 来源哪里
  31. FatherNumber string `json:"fatherNumber"` // 父号
  32. MotherNumber string `json:"motherNumber"` // 母号
  33. AdmissionStatus pasturePb.AdmissionStatus_Kind `json:"admissionStatus"` // 在场状态
  34. IsPregnant pasturePb.IsShow_Kind `json:"isPregnant"` // 是否怀孕
  35. HealthStatus pasturePb.HealthStatus_Kind `json:"healthStatus"` // 健康状态
  36. WeaningAt int64 `json:"weaningAt"` // 断奶时间
  37. BirthAt int64 `json:"birthAt"` // 出生时间
  38. AdmissionAt int64 `json:"admissionAt"` // 入场时间
  39. DepartureAt int64 `json:"departureAt"` // 离场时间
  40. FirstMatingAt int64 `json:"firstMatingAt"` // 首次配种时间
  41. MatingTimes int32 `json:"matingTimes"` // 配种次数
  42. WeeklyActive int32 `json:"weeklyActive"` // 每周活跃度
  43. LastEstrusAt int64 `json:"lastEstrusAt"` // 最后一次发情时间
  44. LastCalvingAt int64 `json:"lastCalvingAt"` // 最后一次产犊时间
  45. LastMatingAt int64 `json:"lastMatingAt"` // 最后一次配种时间
  46. LastBullNumber string `json:"lastBullNumber"` // 最后一次配种牛号
  47. LastPregnantCheckAt int64 `json:"lastPregnantCheckAt"` // 最后一次孕检时间
  48. LastDryMilkAt int64 `json:"lastDryMilkAt"` // 最近一次干奶日期
  49. LastSecondWeight int64 `json:"lastSecondWeight"` // 最后第二次称重
  50. LastSecondWeightAt int64 `json:"lastSecondWeightAt"` // 最后第二次称重时间
  51. LastAbortionAt int64 `json:"lastAbortionAt"` // 最近一次流产时间
  52. LastWeightAt int64 `json:"lastWeightAt"` // 最近一次称重时间
  53. CreatedAt int64 `json:"createdAt"`
  54. UpdatedAt int64 `json:"updatedAt"`
  55. }
  56. func (c *Cow) TableName() string {
  57. return "cow"
  58. }
  59. func (c *Cow) EventInfoUpdate() {
  60. c.DayAge = c.GetDayAge()
  61. c.CalvingAge = c.GetCalvingAge()
  62. c.PregnancyAge = c.GetDaysPregnant()
  63. c.AdmissionAge = c.GetAdmissionAge()
  64. c.AbortionAge = c.GetAbortionAge()
  65. if c.DayAge == 60 {
  66. c.CowType = pasturePb.CowType_Weaned_Calf
  67. }
  68. }
  69. // EventCalvingUpdate 产犊更新
  70. func (c *Cow) EventCalvingUpdate(calvingAt int64) {
  71. c.Lact += 1
  72. c.MatingTimes = 0
  73. c.PregnancyAge = 0
  74. c.BreedStatus = pasturePb.BreedStatus_Calving
  75. c.IsPregnant = pasturePb.IsShow_No
  76. c.LastCalvingAt = calvingAt
  77. c.CalvingAge = c.GetCalvingAge()
  78. }
  79. // EventWeaningUpdate 断奶更新
  80. func (c *Cow) EventWeaningUpdate(weaningAt int64, penId int32, currentWeight int64) {
  81. c.PenId = penId
  82. c.WeaningAt = weaningAt
  83. c.CurrentWeight = currentWeight
  84. c.LastWeightAt = weaningAt
  85. }
  86. // EventPregnantCheckUpdate 孕检更新
  87. func (c *Cow) EventPregnantCheckUpdate(breedStatus pasturePb.BreedStatus_Kind, pregnantCheckAt int64, isPregnant pasturePb.IsShow_Kind) {
  88. c.BreedStatus = breedStatus
  89. c.LastPregnantCheckAt = pregnantCheckAt
  90. c.IsPregnant = isPregnant
  91. }
  92. // EventAbortionUpdate 流产更新
  93. func (c *Cow) EventAbortionUpdate(abortionAt int64) {
  94. c.IsPregnant = pasturePb.IsShow_No
  95. c.LastAbortionAt = abortionAt
  96. c.BreedStatus = pasturePb.BreedStatus_Abort
  97. }
  98. // EventWeightUpdate 称重更新
  99. func (c *Cow) EventWeightUpdate(weight int64, weightAt int64) {
  100. c.LastSecondWeight = c.CurrentWeight
  101. c.LastSecondWeightAt = c.LastWeightAt
  102. c.LastWeightAt = weightAt
  103. c.CurrentWeight = weight
  104. }
  105. // EventHealthStatusUpdate 健康状态更新
  106. func (c *Cow) EventHealthStatusUpdate(healthStatus pasturePb.HealthStatus_Kind) {
  107. c.HealthStatus = healthStatus
  108. }
  109. // EventPenUpdate 更新栏舍
  110. func (c *Cow) EventPenUpdate(pen *Pen) {
  111. c.PenId = pen.Id
  112. c.PenName = pen.Name
  113. }
  114. // EventEarNumberUpdate 更新耳标号
  115. func (c *Cow) EventEarNumberUpdate(newEarNumber string) {
  116. c.EarOldNumber = c.EarNumber
  117. c.EarNumber = newEarNumber
  118. }
  119. // EventDepartureUpdate 更新牛只离场信息
  120. func (c *Cow) EventDepartureUpdate(departureAt int64, departureType pasturePb.DepartureType_Kind) {
  121. if departureType == pasturePb.DepartureType_Death {
  122. c.AdmissionStatus = pasturePb.AdmissionStatus_Die
  123. c.HealthStatus = pasturePb.HealthStatus_Dead
  124. }
  125. if departureType == pasturePb.DepartureType_Out {
  126. c.AdmissionStatus = pasturePb.AdmissionStatus_Out
  127. c.HealthStatus = pasturePb.HealthStatus_Out
  128. }
  129. c.DepartureAt = departureAt
  130. }
  131. // EventMatingUpdate 配种更新
  132. func (c *Cow) EventMatingUpdate(matingAt int64, bullNumber string, isReMating bool) {
  133. c.LastMatingAt = matingAt
  134. if c.LastBullNumber != "" {
  135. c.FirstMatingAt = matingAt
  136. }
  137. c.LastBullNumber = bullNumber
  138. c.IsPregnant = pasturePb.IsShow_No
  139. c.BreedStatus = pasturePb.BreedStatus_Breeding
  140. if !isReMating {
  141. c.MatingTimes += 1
  142. }
  143. }
  144. type CowSlice []*Cow
  145. func (c CowSlice) ToPB(
  146. penMap map[int32]*Pen,
  147. cowTypeMap map[pasturePb.CowType_Kind]string,
  148. breedStatusMap map[pasturePb.BreedStatus_Kind]string,
  149. cowKindMap map[pasturePb.CowKind_Kind]string,
  150. cowSourceMap map[pasturePb.CowSource_Kind]string,
  151. admissionStatusMap map[pasturePb.AdmissionStatus_Kind]string,
  152. healthStatusMap map[pasturePb.HealthStatus_Kind]string,
  153. ) []*pasturePb.CowDetails {
  154. res := make([]*pasturePb.CowDetails, len(c))
  155. for i, v := range c {
  156. penName := ""
  157. if pen, ok := penMap[v.PenId]; ok {
  158. penName = pen.Name
  159. }
  160. sex := "公"
  161. if v.Sex == pasturePb.Genders_Female {
  162. sex = "母"
  163. }
  164. lastWeightAtFormat := ""
  165. if v.LastWeightAt > 0 {
  166. lastWeightAtFormat = time.Unix(v.LastWeightAt, 0).Format(LayoutDate2)
  167. }
  168. isPregnantName := ""
  169. if v.IsPregnant == pasturePb.IsShow_Ok {
  170. isPregnantName = "已孕"
  171. } else {
  172. isPregnantName = "未孕"
  173. }
  174. admissionAtFormat := ""
  175. if v.AdmissionAt > 0 {
  176. admissionAtFormat = time.Unix(v.AdmissionAt, 0).Format(LayoutDate2)
  177. }
  178. birthAtFormat := ""
  179. if v.BirthAt > 0 {
  180. birthAtFormat = time.Unix(v.BirthAt, 0).Format(LayoutDate2)
  181. }
  182. weaningAtFormat := ""
  183. if v.WeaningAt > 0 {
  184. weaningAtFormat = time.Unix(v.WeaningAt, 0).Format(LayoutDate2)
  185. }
  186. firstMatingAtFormat := ""
  187. if v.FirstMatingAt > 0 {
  188. firstMatingAtFormat = time.Unix(v.FirstMatingAt, 0).Format(LayoutDate2)
  189. }
  190. lastMatingAtFormat := ""
  191. if v.LastMatingAt > 0 {
  192. lastMatingAtFormat = time.Unix(v.LastMatingAt, 0).Format(LayoutDate2)
  193. }
  194. lastPregnantCheckAtFormat := ""
  195. if v.LastPregnantCheckAt > 0 {
  196. lastPregnantCheckAtFormat = time.Unix(v.LastPregnantCheckAt, 0).Format(LayoutDate2)
  197. }
  198. lastCalvingAtFormat := ""
  199. if v.LastCalvingAt > 0 {
  200. lastCalvingAtFormat = time.Unix(v.LastCalvingAt, 0).Format(LayoutDate2)
  201. }
  202. res[i] = &pasturePb.CowDetails{
  203. CowId: int32(v.Id),
  204. Sex: sex,
  205. NeckRingNumber: v.NeckRingNumber,
  206. PenName: penName,
  207. Lact: v.Lact,
  208. CowTypeName: cowTypeMap[v.CowType],
  209. BreedStatusName: breedStatusMap[v.BreedStatus],
  210. CowKindName: cowKindMap[v.CowKind],
  211. EarNumber: v.EarNumber,
  212. BirthWeight: float32(v.BirthWeight) / 1000,
  213. CurrentWeight: float32(v.CurrentWeight) / 1000,
  214. DayAge: v.DayAge,
  215. SourceName: cowSourceMap[v.SourceId],
  216. MontherNumber: v.MotherNumber,
  217. FatherNumber: v.FatherNumber,
  218. AdmissionStatusName: admissionStatusMap[v.AdmissionStatus],
  219. HealthStatusName: healthStatusMap[v.HealthStatus],
  220. IsPregnantName: isPregnantName,
  221. AdmissionAtFormat: admissionAtFormat,
  222. BirthAtFormat: birthAtFormat,
  223. WeaningAtFormat: weaningAtFormat,
  224. CalvingAge: int32(v.GetCalvingAge()),
  225. AbortionAge: int32(v.AbortionAge),
  226. MatingTimes: v.MatingTimes,
  227. FirstMatingAtFormat: firstMatingAtFormat,
  228. LastMatingAtFormat: lastMatingAtFormat,
  229. LastBullNumber: v.LastBullNumber,
  230. LastPregnantCheckAtFormat: lastPregnantCheckAtFormat,
  231. LastWeightAtFormat: lastWeightAtFormat,
  232. LastCalvingAtFormat: lastCalvingAtFormat,
  233. //PregnancyAge: v.PregnancyAge,
  234. }
  235. }
  236. return res
  237. }
  238. func (c CowSlice) ToPB2(penMap map[int32]*Pen, penWeightSlice PenWeightSlice) []*pasturePb.CowList {
  239. res := make([]*pasturePb.CowList, len(c))
  240. for i, v := range c {
  241. penName := ""
  242. if pen, ok := penMap[v.PenId]; ok {
  243. penName = pen.Name
  244. }
  245. penWeight := penWeightSlice.GetPenWeight(v.PenId)
  246. lastWeightDay := util.Ceil(float64(v.LastWeightAt-v.LastSecondWeightAt) / 86400)
  247. penAvgWeight := float32(0)
  248. previousStageDailyWeight := float32(0)
  249. cowPenAvgWeightDiffValue := float32(0)
  250. if penWeight != nil {
  251. penAvgWeight = float32(penWeight.AvgWeight) / 1000
  252. cowPenAvgWeightDiffValue = float32(v.CurrentWeight-int64(penWeight.AvgWeight)) / 1000
  253. if lastWeightDay > 0 {
  254. previousStageDailyWeight = float32(v.CurrentWeight-v.LastSecondWeight) / 1000 / float32(lastWeightDay)
  255. }
  256. }
  257. res[i] = &pasturePb.CowList{
  258. CowId: int32(v.Id),
  259. DayAge: v.DayAge,
  260. DailyWeightGain: float32(v.GetDayWeight()),
  261. AverageDailyWeightGain: float32(v.GetAverageDailyWeight()),
  262. EarNumber: v.EarNumber,
  263. PenName: penName,
  264. BirthAt: int32(v.BirthAt),
  265. BirthWeight: float32(v.BirthWeight) / 1000,
  266. CurrentWeight: float32(v.CurrentWeight) / 1000,
  267. LastWeightAt: int32(v.LastWeightAt),
  268. AdmissionAge: int32(v.AdmissionAge),
  269. AdmissionWeight: float32(v.AbortionAge) / 1000,
  270. PreviousStageDailyWeight: previousStageDailyWeight,
  271. PenAvgWeight: penAvgWeight,
  272. CowPenAvgWeightDiffValue: cowPenAvgWeightDiffValue,
  273. }
  274. }
  275. return res
  276. }
  277. func NewCow(req *pasturePb.EventEnterRequest) *Cow {
  278. var isPregnant = pasturePb.IsShow_No
  279. if req.BreedStatus == pasturePb.BreedStatus_Pregnant {
  280. isPregnant = pasturePb.IsShow_Ok
  281. }
  282. return &Cow{
  283. Sex: req.Sex,
  284. EarNumber: req.EarNumber,
  285. PenId: req.PenId,
  286. Lact: req.Lact,
  287. CowType: req.CowType,
  288. BreedStatus: req.BreedStatus,
  289. CowKind: req.CowKind,
  290. SourceId: req.CowSource,
  291. FatherNumber: req.FatherNumber,
  292. MotherNumber: req.MotherNumber,
  293. AdmissionStatus: pasturePb.AdmissionStatus_Admission,
  294. HealthStatus: pasturePb.HealthStatus_Health,
  295. IsPregnant: isPregnant,
  296. WeaningAt: int64(req.WeaningAt),
  297. BirthAt: int64(req.BirthAt),
  298. AdmissionWeight: int64(req.Weight * 1000),
  299. FirstMatingAt: int64(req.MatingAt),
  300. LastMatingAt: int64(req.MatingAt),
  301. LastPregnantCheckAt: int64(req.PregnancyCheckAt),
  302. AdmissionAt: int64(req.BirthAt),
  303. }
  304. }
  305. func NewCalfCow(motherId int64, fatherNumber string, calf *CalvingCalf) *Cow {
  306. return &Cow{
  307. Sex: calf.Sex,
  308. EarNumber: calf.EarNumber,
  309. PenId: calf.PenId,
  310. CowType: pasturePb.CowType_Lactating_Calf, // 哺乳犊牛
  311. BreedStatus: pasturePb.BreedStatus_UnBreed, // 未配
  312. CowKind: calf.CowKind, // 牛只品种
  313. BirthWeight: calf.BirthWeight,
  314. BirthAt: calf.BirthAt,
  315. SourceId: pasturePb.CowSource_Calving, // 产犊方式
  316. FatherNumber: fatherNumber,
  317. MotherNumber: fmt.Sprintf("%d", motherId),
  318. AdmissionStatus: pasturePb.AdmissionStatus_Admission,
  319. IsPregnant: pasturePb.IsShow_No,
  320. AdmissionAt: calf.BirthAt,
  321. }
  322. }
  323. type BarCowStruct struct {
  324. Number int32 `json:"number"`
  325. TypeId pasturePb.CowType_Kind `json:"type_id"`
  326. }
  327. // BarCowStructSlice 首页牛群结构
  328. type BarCowStructSlice []*BarCowStruct
  329. func (b BarCowStructSlice) ToPB(cowTypeMap map[pasturePb.CowType_Kind]string, count int32) []*pasturePb.BarCowStruct {
  330. var pb []*pasturePb.BarCowStruct
  331. for _, v := range b {
  332. name := fmt.Sprintf("%s", cowTypeMap[v.TypeId])
  333. pb = append(pb, &pasturePb.BarCowStruct{Name: name, Value: v.Number})
  334. }
  335. return pb
  336. }
  337. // GetDayAge 日龄
  338. func (c *Cow) GetDayAge() int32 {
  339. if c.BirthAt <= 0 {
  340. return 0
  341. }
  342. return int32(math.Floor(float64(time.Now().Unix()-c.BirthAt) / 86400))
  343. }
  344. // GetCalvingAge 产后天数
  345. func (c *Cow) GetCalvingAge() int64 {
  346. if c.LastCalvingAt <= 0 {
  347. return 0
  348. }
  349. return int64(math.Floor(float64(time.Now().Unix()-c.LastCalvingAt) / 86400))
  350. }
  351. // GetDaysPregnant 怀孕天数
  352. func (c *Cow) GetDaysPregnant() int32 {
  353. if c.BreedStatus == pasturePb.BreedStatus_Pregnant &&
  354. c.AdmissionStatus == pasturePb.AdmissionStatus_Admission &&
  355. c.IsPregnant == pasturePb.IsShow_Ok {
  356. return int32(math.Floor(float64(time.Now().Unix()-c.LastMatingAt) / 86400))
  357. }
  358. return 0
  359. }
  360. // GetLactationDays 泌乳天数
  361. func (c *Cow) GetLactationDays() int32 {
  362. if c.BreedStatus == pasturePb.BreedStatus_Calving && c.AdmissionStatus == pasturePb.AdmissionStatus_Admission {
  363. return int32(math.Floor(float64(time.Now().Unix()-c.LastCalvingAt) / 86400))
  364. }
  365. return 0
  366. }
  367. // GetAdmissionAge 入场天数
  368. func (c *Cow) GetAdmissionAge() int32 {
  369. if c.AdmissionAt > 0 && c.AdmissionStatus == pasturePb.AdmissionStatus_Admission {
  370. return int32(math.Floor(float64(time.Now().Unix()-c.AdmissionAt) / 86400))
  371. }
  372. return 0
  373. }
  374. // GetDayWeight 日增重
  375. func (c *Cow) GetDayWeight() float64 {
  376. if c.CurrentWeight-c.LastSecondWeight > 0 && c.LastWeightAt > c.LastSecondWeightAt {
  377. days := int32(math.Floor(float64(c.LastWeightAt-c.LastSecondWeightAt) / 86400))
  378. if days <= 0 {
  379. return 0
  380. }
  381. dayWeight := math.Round(1.0 * float64(c.CurrentWeight-c.LastSecondWeight) / float64(days))
  382. return dayWeight / 1000
  383. }
  384. return 0
  385. }
  386. // GetAverageDailyWeight 平均日增重
  387. func (c *Cow) GetAverageDailyWeight() float64 {
  388. if c.CurrentWeight-c.BirthWeight > 0 && c.LastWeightAt > c.BirthAt {
  389. days := int32(math.Floor(float64(c.LastWeightAt-c.BirthAt) / 86400))
  390. if days <= 0 {
  391. return 0
  392. }
  393. dailyWeight := math.Round(1.0 * float64(c.CurrentWeight-c.BirthWeight) / float64(days))
  394. return dailyWeight / 1000
  395. }
  396. return 0
  397. }
  398. func (c *Cow) GetAbortionAge() int32 {
  399. if c.LastAbortionAt > 0 && c.AdmissionStatus == pasturePb.AdmissionStatus_Admission {
  400. return int32(math.Floor(float64(time.Now().Unix()-c.LastAbortionAt) / 86400))
  401. }
  402. return 0
  403. }
  404. type CowWeightRange struct {
  405. WeightRange string `json:"weight_range"`
  406. Count int32 `json:"count"`
  407. }
  408. func (c CowSlice) WeightRangeToPB(penMap map[int32]*Pen) []*pasturePb.CowList {
  409. res := make([]*pasturePb.CowList, len(c))
  410. for i, v := range c {
  411. penName := ""
  412. if pen, ok := penMap[v.PenId]; ok {
  413. penName = pen.Name
  414. }
  415. res[i] = &pasturePb.CowList{
  416. CowId: int32(v.Id),
  417. DayAge: v.DayAge,
  418. DailyWeightGain: float32(v.GetDayWeight()),
  419. AverageDailyWeightGain: float32(v.GetAverageDailyWeight()),
  420. EarNumber: v.EarNumber,
  421. PenName: penName,
  422. BirthAt: int32(v.BirthAt),
  423. BirthWeight: float32(v.BirthWeight) / 1000,
  424. CurrentWeight: float32(v.CurrentWeight) / 1000,
  425. LastWeightAt: int32(v.LastWeightAt),
  426. }
  427. }
  428. return res
  429. }
  430. // CowBehaviorCurveResponse 脖环行为数据
  431. type CowBehaviorCurveResponse struct {
  432. Code int32 `json:"code"`
  433. Msg string `json:"msg"`
  434. Data *CowBehaviorCurveData `json:"data"`
  435. }
  436. type CowBehaviorCurveData struct {
  437. OriginalDataList []int32 `json:"originalDataList"` // 原始行为数据
  438. ChangeDataList []int32 `json:"changeDataList"` // 变化数据
  439. SumDataList []int32 `json:"sumDataList"` // 累计24小时数据
  440. DataTimeList []string `json:"dataTimeList"` // 时间数据
  441. EstrusList map[pasturePb.EstrusLevel_Kind][]string `json:"estrusList"` // 发情预警
  442. EventList map[string][]string `json:"eventList"` // 事件数据
  443. EventMap map[pasturePb.EventType_Kind]string `json:"eventMap"` // 所有事件
  444. }