analysis_cow.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. package backend
  2. import (
  3. "context"
  4. "fmt"
  5. "kpt-pasture/model"
  6. "kpt-pasture/util"
  7. "math"
  8. "net/http"
  9. "time"
  10. pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
  11. "gitee.com/xuyiping_admin/pkg/xerr"
  12. )
  13. func (s *StoreEntry) TwentyOnePregnantRate(ctx context.Context, req *pasturePb.TwentyOnePregnantRateRequest) (*pasturePb.TwentyOnePregnantRateResponse, error) {
  14. userModel, err := s.GetUserModel(ctx)
  15. if err != nil {
  16. return nil, xerr.WithStack(err)
  17. }
  18. startUnix := util.TimeParseLocalUnix(req.StartDate)
  19. endUnix := util.TimeParseLocalUnix(req.EndDate)
  20. if startUnix > endUnix {
  21. return nil, xerr.Customf("开始时间不能大于结束时间: %s ~ %d", req.StartDate, req.EndDate)
  22. }
  23. nowDateTime := time.Now().Local()
  24. if endUnix > nowDateTime.Unix() {
  25. return nil, xerr.Customf("结束时间不能大于当前时间: %s ~ %s", req.EndDate, nowDateTime.Format(model.LayoutDate2))
  26. }
  27. dataRange, err := util.Get21DayPeriods(req.StartDate, req.EndDate)
  28. if err != nil {
  29. return nil, xerr.WithStack(err)
  30. }
  31. chart := &pasturePb.TwentyOnePregnantRateChart{
  32. Header: make([]string, 0),
  33. PregnantRate: make([]float32, 0),
  34. MatingRate: make([]float32, 0),
  35. }
  36. // 牛只主动停配期
  37. systemBasicName := ""
  38. switch req.CowType {
  39. case pasturePb.CowType_Breeding_Calf:
  40. systemBasicName = model.ProactivelyStopBreedingForAdult
  41. case pasturePb.CowType_Reserve_Calf:
  42. systemBasicName = model.ProactivelyStopBreedingForBackup
  43. default:
  44. return nil, xerr.Customf("不支持的牛只类型: %d", req.CowType)
  45. }
  46. systemBasic, err := s.GetSystemBasicByName(ctx, userModel.AppPasture.Id, systemBasicName)
  47. if err != nil {
  48. return nil, xerr.WithStack(err)
  49. }
  50. stopBreedingDay := systemBasic.MinValue
  51. twentyOnePregnantRateList := make([]*pasturePb.TwentyOnePregnantRateList, 0)
  52. for _, v := range dataRange {
  53. middleDay, err := util.GetRangeDayMiddleDay(v, 11)
  54. if err != nil {
  55. return nil, xerr.WithStack(err)
  56. }
  57. _, shouldBreedCount := s.TwentyOnePregnantShouldBreedList(userModel.AppPasture.Id, req.CowType, stopBreedingDay, middleDay)
  58. realityBreedCowList, realityBreedCount := s.TwentyOnePregnantRealityBreedList(userModel.AppPasture.Id, req.CowType, v[0], v[1])
  59. breedRate, abortionRate, realityPregnantRate := float32(0), float32(0), float32(0)
  60. if realityBreedCount > 0 && shouldBreedCount > 0 {
  61. breedRate = float32(math.Round(float64(realityBreedCount)/float64(shouldBreedCount)*100) / 100)
  62. }
  63. realityPregnantCount, shouldPregnantCount, realityAbortionCount := int32(0), int32(0), int32(0)
  64. for _, eventMating := range realityBreedCowList {
  65. if eventMating.MatingResult == pasturePb.MatingResult_Pregnant {
  66. realityPregnantCount++
  67. }
  68. if eventMating.MatingResult == pasturePb.MatingResult_Abort {
  69. realityAbortionCount++
  70. }
  71. if s.IsDeparture(ctx, userModel.AppPasture.Id, eventMating.CowId, 35) {
  72. shouldPregnantCount++
  73. }
  74. }
  75. if realityPregnantCount > 0 && shouldPregnantCount > 0 {
  76. realityPregnantRate = float32(math.Round(float64(realityPregnantCount)/float64(shouldPregnantCount)*100) / 100)
  77. }
  78. if realityAbortionCount > 0 && realityPregnantCount > 0 {
  79. abortionRate = float32(math.Round(float64(realityAbortionCount)/float64(realityPregnantCount)*100) / 100)
  80. }
  81. chart.Header = append(chart.Header, fmt.Sprintf("%s ~ %s", v[0][5:], v[1][5:]))
  82. chart.PregnantRate = append(chart.PregnantRate, realityPregnantRate)
  83. chart.MatingRate = append(chart.MatingRate, breedRate)
  84. twentyOnePregnantRateList = append(twentyOnePregnantRateList, &pasturePb.TwentyOnePregnantRateList{
  85. StartDay: v[0],
  86. EndDay: v[1],
  87. ShouldBreedCount: shouldBreedCount, // 应配种
  88. RealityBreedCount: realityBreedCount, // 实际配种
  89. BreedRate: breedRate, // 配种率
  90. ShouldPregnantCount: shouldPregnantCount, // 应怀孕
  91. RealityPregnantCount: realityPregnantCount, // 实际怀孕
  92. PregnantRate: realityPregnantRate, // 怀孕率
  93. RealityAbortionCount: realityAbortionCount, // 实际流产
  94. AbortionRate: abortionRate, // 流产率
  95. })
  96. }
  97. return &pasturePb.TwentyOnePregnantRateResponse{
  98. Code: http.StatusOK,
  99. Msg: "ok",
  100. Data: &pasturePb.TwentyOnePregnantRateData{
  101. Chart: chart,
  102. Table: &pasturePb.TwentyOnePregnantRateTable{
  103. List: twentyOnePregnantRateList,
  104. Total: int32(len(dataRange)),
  105. },
  106. },
  107. }, nil
  108. }
  109. // TwentyOnePregnantShouldBreedList 21天牛应配牛只列表
  110. func (s *StoreEntry) TwentyOnePregnantShouldBreedList(pastureId int64, cowType pasturePb.CowType_Kind, stopBreedingDay int32, middleDay string) ([]*model.CowCalving, int32) {
  111. everyDayCalvingList := make([]*model.CowCalving, 0)
  112. if err := s.DB.Model(new(model.CowCalving)).
  113. Where("pasture_id = ?", pastureId).
  114. Where("cow_type = ?", cowType).
  115. Where("date_time = ?", middleDay).
  116. Where("calving_age >= ?", stopBreedingDay).
  117. Where("is_abortion = ?", pasturePb.IsShow_No).
  118. Where("is_departure = ?", pasturePb.IsShow_No).
  119. Where("is_forbidden = ?", pasturePb.IsShow_No).
  120. Find(&everyDayCalvingList).Error; err != nil {
  121. return everyDayCalvingList, 0
  122. }
  123. return everyDayCalvingList, int32(len(everyDayCalvingList))
  124. }
  125. func (s *StoreEntry) TwentyOnePregnantRealityBreedList(pastureId int64, cowType pasturePb.CowType_Kind, startDate, endDate string) ([]*model.EventMating, int32) {
  126. eventMatingList := make([]*model.EventMating, 0)
  127. if err := s.DB.Model(new(model.EventMating)).
  128. Where("pasture_id = ?", pastureId).
  129. Where("cow_type = ?", cowType).
  130. Where("reality_day BETWEEN ? AND ?", util.TimeParseLocalUnix(startDate), util.TimeParseLocalEndUnix(endDate)).
  131. Where("status = ?", pasturePb.IsShow_Ok).
  132. Find(&eventMatingList).Error; err != nil {
  133. return eventMatingList, 0
  134. }
  135. return eventMatingList, int32(len(eventMatingList))
  136. }
  137. // IsDeparture 是否离场并且在配种后35天
  138. func (s *StoreEntry) IsDeparture(ctx context.Context, pastureId, cowId int64, days int32) bool {
  139. cowInfo := &model.Cow{}
  140. if err := s.DB.Model(new(model.Cow)).
  141. Where("pasture_id = ?", pastureId).
  142. Where("sex = ?", pasturePb.Genders_Female).
  143. Where("id = ?", cowId).First(cowInfo).Error; err != nil {
  144. return false
  145. }
  146. matingUnix := time.Unix(cowInfo.LastMatingAt, 0).Local().AddDate(0, 0, int(days)).Unix()
  147. departureAt := cowInfo.DepartureAt
  148. if departureAt > 0 && matingUnix >= matingUnix {
  149. return true
  150. }
  151. return false
  152. }
  153. func (s *StoreEntry) TwentyOnePregnantDetail(ctx context.Context, req *pasturePb.TwentyOnePregnantDetailsRequest) (*pasturePb.TwentyOnePregnantDetailsResponse, error) {
  154. userModel, err := s.GetUserModel(ctx)
  155. if err != nil {
  156. return nil, xerr.WithStack(err)
  157. }
  158. pastureId := userModel.AppPasture.Id
  159. list := make([]*pasturePb.TwentyOnePregnantItems, 0)
  160. // 牛只主动停配期
  161. systemBasicName := ""
  162. switch req.CowType {
  163. case pasturePb.CowType_Breeding_Calf:
  164. systemBasicName = model.ProactivelyStopBreedingForAdult
  165. case pasturePb.CowType_Reserve_Calf:
  166. systemBasicName = model.ProactivelyStopBreedingForBackup
  167. default:
  168. return nil, xerr.Customf("不支持的牛只类型: %d", req.CowType)
  169. }
  170. systemBasic, err := s.GetSystemBasicByName(ctx, userModel.AppPasture.Id, systemBasicName)
  171. if err != nil {
  172. return nil, xerr.WithStack(err)
  173. }
  174. stopBreedingDay := systemBasic.MinValue
  175. middleDay, err := util.GetRangeDayMiddleDay([]string{req.StartDate, req.EndDate}, 11)
  176. if err != nil {
  177. return nil, xerr.WithStack(err)
  178. }
  179. cowTypeMap := s.CowTypeMap()
  180. switch req.Type {
  181. case pasturePb.TwentyOnePregnantType_ShouldBreed:
  182. shouldBreedCowList, _ := s.TwentyOnePregnantShouldBreedList(pastureId, req.CowType, stopBreedingDay, middleDay)
  183. list = model.CowCalvingSlice(shouldBreedCowList).ToPB()
  184. case pasturePb.TwentyOnePregnantType_RealityBreed:
  185. realityBreedCowList, _ := s.TwentyOnePregnantRealityBreedList(pastureId, req.CowType, req.StartDate, req.EndDate)
  186. list = model.EventMatingSlice(realityBreedCowList).ToPB3(false, cowTypeMap)
  187. case pasturePb.TwentyOnePregnantType_ShouldPregnant:
  188. realityBreedCowList, _ := s.TwentyOnePregnantRealityBreedList(pastureId, req.CowType, req.StartDate, req.EndDate)
  189. newShouldBreedCowList := make([]*model.EventMating, 0)
  190. for _, v := range realityBreedCowList {
  191. if s.IsDeparture(ctx, v.PastureId, v.CowId, stopBreedingDay) {
  192. newShouldBreedCowList = append(newShouldBreedCowList, v)
  193. }
  194. }
  195. list = model.EventMatingSlice(newShouldBreedCowList).ToPB3(false, cowTypeMap)
  196. case pasturePb.TwentyOnePregnantType_RealityPregnant:
  197. realityBreedCowList, _ := s.TwentyOnePregnantRealityBreedList(userModel.AppPasture.Id, req.CowType, req.StartDate, req.EndDate)
  198. list = model.EventMatingSlice(realityBreedCowList).ToPB3(true, cowTypeMap)
  199. case pasturePb.TwentyOnePregnantType_RealityAbortion:
  200. realityBreedCowList, _ := s.TwentyOnePregnantRealityBreedList(userModel.AppPasture.Id, req.CowType, req.StartDate, req.EndDate)
  201. list = model.EventMatingSlice(realityBreedCowList).ToPB4(cowTypeMap)
  202. }
  203. return &pasturePb.TwentyOnePregnantDetailsResponse{
  204. Code: http.StatusOK,
  205. Msg: "ok",
  206. Data: &pasturePb.TwentyOnePregnantData{
  207. List: list,
  208. Header: map[string]string{
  209. "earNumber": "牛号",
  210. "lact": "胎次",
  211. "matingDateFormat": "配种日期",
  212. "matingTimes": "配次",
  213. "pregnantCheckDateFormat": "孕检日期",
  214. "isMating": "是否有胎",
  215. "abortionDateFormat": "流产日期",
  216. "departureDateFormat": "离场日期",
  217. "expectedProductionDateFormat": "预产日期",
  218. },
  219. HeaderSort: []string{"earNumber", "lact", "matingDateFormat", "matingTimes", "pregnantCheckDateFormat",
  220. "isMating", "abortionDateFormat", "departureDateFormat", "expectedProductionDateFormat"},
  221. },
  222. }, nil
  223. }