analysis.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. package backend
  2. import (
  3. "context"
  4. "fmt"
  5. "kpt-pasture/model"
  6. "kpt-pasture/util"
  7. "net/http"
  8. "strings"
  9. "time"
  10. pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
  11. "gitee.com/xuyiping_admin/pkg/logger/zaplog"
  12. "gitee.com/xuyiping_admin/pkg/xerr"
  13. "go.uber.org/zap"
  14. )
  15. // WeightScatterPlot 体重散点图 获取图表数据
  16. func (s *StoreEntry) WeightScatterPlot(ctx context.Context, req *pasturePb.SearchGrowthCurvesRequest) (*pasturePb.GrowthCurvesResponse, error) {
  17. userModel, err := s.GetUserModel(ctx)
  18. if err != nil {
  19. return nil, xerr.Custom("当前用户信息错误,请退出重新登录")
  20. }
  21. // 查询数据
  22. cowList := make([]*model.Cow, 0)
  23. pref := s.DB.Model(new(model.Cow)).
  24. Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
  25. Where("pasture_id = ?", userModel.AppPasture.Id)
  26. if req.GetCowId() != "" {
  27. pref.Where("id IN ?", strings.Split(req.CowId, ","))
  28. }
  29. if len(req.BirthDate) == 2 && req.BirthDate[0] != "" && req.BirthDate[1] != "" {
  30. t0, _ := time.Parse(time.RFC3339, req.BirthDate[0])
  31. t1, _ := time.Parse(time.RFC3339, req.BirthDate[1])
  32. pref.Where("birth_at BETWEEN ? AND ?", t0.Unix(), t1.Unix()+86399)
  33. }
  34. if err = pref.Find(&cowList).Error; err != nil {
  35. return nil, err
  36. }
  37. penList, err := s.GetPenList(ctx, userModel.AppPasture.Id)
  38. if err != nil {
  39. return nil, xerr.WithStack(err)
  40. }
  41. // 计算图表数据
  42. chartsList := &pasturePb.Charts{
  43. CowId: make([]int32, 0),
  44. Weight: make([]float32, 0),
  45. AdmissionAge: make([]int32, 0),
  46. }
  47. cowData := make([]*pasturePb.CowList, 0)
  48. for _, cow := range cowList {
  49. currentWeight := float32(cow.CurrentWeight) / 1000
  50. penName := ""
  51. for _, v := range penList {
  52. if cow.PenId != v.Id {
  53. continue
  54. }
  55. penName = v.Name
  56. }
  57. cowData = append(cowData, &pasturePb.CowList{
  58. CowId: int32(cow.Id),
  59. EarNumber: cow.EarNumber,
  60. DayAge: cow.GetDayAge(),
  61. PenName: penName,
  62. CurrentWeight: currentWeight,
  63. BirthAt: int32(cow.BirthAt),
  64. BirthWeight: float32(cow.BirthWeight) / 1000,
  65. LastWeightAt: int32(cow.LastWeightAt),
  66. DailyWeightGain: float32(cow.GetDayWeight() / 1000),
  67. AverageDailyWeightGain: float32(cow.GetAverageDailyWeight() / 1000),
  68. PreviousStageDailyWeight: float32(cow.GetPreviousStageDailyWeight() / 1000),
  69. AdmissionAge: cow.GetAdmissionAge(),
  70. })
  71. chartsList.CowId = append(chartsList.CowId, int32(cow.Id))
  72. chartsList.Weight = append(chartsList.Weight, currentWeight)
  73. chartsList.AdmissionAge = append(chartsList.AdmissionAge, cow.GetAdmissionAge())
  74. }
  75. // 返回数据
  76. return &pasturePb.GrowthCurvesResponse{
  77. Code: http.StatusOK,
  78. Msg: "success",
  79. Data: &pasturePb.GrowthCurveData{
  80. Table: cowData,
  81. Charts: chartsList,
  82. },
  83. }, nil
  84. }
  85. func (s *StoreEntry) WeightRange(ctx context.Context, req *pasturePb.WeightRangeRequest) (*pasturePb.WeightRangeResponse, error) {
  86. userModel, err := s.GetUserModel(ctx)
  87. if err != nil {
  88. return nil, xerr.WithStack(err)
  89. }
  90. cowWeightRange := make([]*model.CowWeightRange, 0)
  91. prefix := s.DB.Model(new(model.Cow)).
  92. Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
  93. Where("pasture_id = ?", userModel.AppPasture.Id)
  94. if req.CowKind > 0 {
  95. prefix.Where("cow_kind = ?", req.CowKind)
  96. }
  97. if err = prefix.Select(`
  98. CASE
  99. WHEN current_weight BETWEEN 0 AND 50000 THEN '0-50'
  100. WHEN current_weight BETWEEN 50001 AND 100000 THEN '51-100'
  101. WHEN current_weight BETWEEN 100001 AND 150000 THEN '101-150'
  102. WHEN current_weight BETWEEN 150001 AND 200000 THEN '151-200'
  103. WHEN current_weight BETWEEN 200001 AND 250000 THEN '201-250'
  104. WHEN current_weight BETWEEN 250001 AND 300000 THEN '251-300'
  105. WHEN current_weight BETWEEN 300001 AND 350000 THEN '301-350'
  106. WHEN current_weight BETWEEN 350001 AND 400000 THEN '351-400'
  107. WHEN current_weight BETWEEN 400001 AND 450000 THEN '401-450'
  108. WHEN current_weight BETWEEN 450001 AND 500000 THEN '451-500'
  109. WHEN current_weight BETWEEN 500001 AND 550000 THEN '500-550'
  110. WHEN current_weight BETWEEN 550001 AND 600000 THEN '551-600'
  111. WHEN current_weight BETWEEN 600001 AND 650000 THEN '601-650'
  112. WHEN current_weight BETWEEN 650001 AND 700000 THEN '651-700'
  113. WHEN current_weight BETWEEN 700001 AND 750000 THEN '701-750'
  114. ELSE '750+'
  115. END AS weight_range,
  116. COUNT(*) AS count `,
  117. ).Group("weight_range").Order("MIN(current_weight)").Find(&cowWeightRange).Error; err != nil {
  118. return nil, err
  119. }
  120. if len(cowWeightRange) == 0 {
  121. return &pasturePb.WeightRangeResponse{
  122. Code: http.StatusOK,
  123. Msg: "ok",
  124. Data: &pasturePb.WeightRangeData{
  125. CowList: make([]*pasturePb.CowList, 0),
  126. WeightBarChart: &pasturePb.WeightBarChart{
  127. Header: make([]string, 0),
  128. Data: make([]int32, 0),
  129. },
  130. },
  131. }, nil
  132. }
  133. header := make([]string, 0)
  134. data := make([]int32, 0)
  135. for _, v := range cowWeightRange {
  136. header = append(header, v.WeightRange)
  137. data = append(data, v.Count)
  138. }
  139. // 牛只详情列表
  140. pref := s.DB.Model(new(model.Cow)).
  141. Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
  142. Where("pasture_id = ?", userModel.AppPasture.Id)
  143. if req.CowKind > 0 {
  144. pref.Where("cow_kind = ?", req.CowKind)
  145. }
  146. cowList := make([]*model.Cow, 0)
  147. if req.MinWeight >= 0 && req.MaxWeight >= 0 && req.MinWeight < req.MaxWeight {
  148. pref.Where("current_weight BETWEEN ? AND ? ", req.MinWeight*1000, req.MaxWeight*1000)
  149. }
  150. if err = pref.Find(&cowList).Error; err != nil {
  151. return nil, err
  152. }
  153. penMap := s.PenMap(ctx, userModel.AppPasture.Id)
  154. return &pasturePb.WeightRangeResponse{
  155. Code: http.StatusOK,
  156. Msg: "ok",
  157. Data: &pasturePb.WeightRangeData{
  158. CowList: model.CowSlice(cowList).WeightRangeToPB(penMap),
  159. WeightBarChart: &pasturePb.WeightBarChart{
  160. Header: header,
  161. Data: data,
  162. },
  163. },
  164. }, nil
  165. }
  166. func (s *StoreEntry) MatingTimely(ctx context.Context, req *pasturePb.MatingTimelyRequest) (*model.MatingTimelyResponse, error) {
  167. userModel, err := s.GetUserModel(ctx)
  168. if err != nil {
  169. return nil, xerr.WithStack(err)
  170. }
  171. matingTimelyChart := make([]*model.MatingTimelyChart, 0)
  172. pastureWhereSql := fmt.Sprintf(" AND pasture_id = %d", userModel.AppPasture.Id)
  173. sql := `SELECT calving_age,cow_type, DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') AS reality_day, lact_group
  174. FROM (
  175. SELECT calving_age, cow_type,reality_day, '0' AS lact_group
  176. FROM event_mating
  177. WHERE lact = 0 AND status = 1 ` + pastureWhereSql + `
  178. UNION ALL
  179. SELECT calving_age,cow_type, reality_day, '1' AS lact_group
  180. FROM event_mating
  181. WHERE lact = 1 AND status = 1 ` + pastureWhereSql + `
  182. UNION ALL
  183. SELECT calving_age,cow_type, reality_day, '2' AS lact_group
  184. FROM event_mating
  185. WHERE lact = 2 AND status = 1 ` + pastureWhereSql + `
  186. UNION ALL
  187. SELECT calving_age, cow_type, reality_day, '3+' AS lact_group
  188. FROM event_mating
  189. WHERE lact >= 3 AND status = 1 ` + pastureWhereSql + `
  190. ) AS subquery WHERE 1 = 1 `
  191. whereSql := ""
  192. if req.CowType > 0 {
  193. whereSql += fmt.Sprintf("AND cow_type = %d ", req.CowType)
  194. }
  195. if req.StartDayAt > 0 && req.EndDayAt > 0 {
  196. whereSql += fmt.Sprintf("AND reality_day BETWEEN %d AND %d", req.StartDayAt, req.EndDayAt)
  197. }
  198. if err = s.DB.Raw(fmt.Sprintf("%s %s", sql, whereSql)).Find(&matingTimelyChart).Error; err != nil {
  199. return nil, err
  200. }
  201. chart := &model.CowMatingChart{
  202. Lact0: make([][]string, 0),
  203. Lact1: make([][]string, 0),
  204. Lact2: make([][]string, 0),
  205. Lact3: make([][]string, 0),
  206. }
  207. if len(matingTimelyChart) == 0 {
  208. return &model.MatingTimelyResponse{
  209. Code: http.StatusOK,
  210. Msg: "ok",
  211. Data: &model.MatingTimelyData{
  212. CowList: make([]*pasturePb.CowList, 0),
  213. Chart: chart,
  214. },
  215. }, nil
  216. }
  217. for _, v := range matingTimelyChart {
  218. t, _ := time.Parse(model.LayoutDate2, v.RealityDay)
  219. switch v.LactGroup {
  220. case "0":
  221. chart.Lact0 = append(chart.Lact0, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
  222. case "1":
  223. chart.Lact1 = append(chart.Lact1, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
  224. case "2":
  225. chart.Lact2 = append(chart.Lact2, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
  226. case "3+":
  227. chart.Lact3 = append(chart.Lact3, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
  228. }
  229. }
  230. // 牛只详情列表
  231. eventMatingList := make([]*model.EventMating, 0)
  232. pref := s.DB.Model(new(model.EventMating)).
  233. Where("status = ?", pasturePb.IsShow_Ok)
  234. if req.CowType > 0 {
  235. pref.Where("cow_type = ?", req.CowType)
  236. }
  237. if req.StartDayAt > 0 && req.EndDayAt > 0 {
  238. pref.Where("reality_day BETWEEN ? AND ?", req.StartDayAt, req.EndDayAt)
  239. }
  240. if err = pref.Find(&eventMatingList).Error; err != nil {
  241. return nil, err
  242. }
  243. return &model.MatingTimelyResponse{
  244. Code: http.StatusOK,
  245. Msg: "ok",
  246. Data: &model.MatingTimelyData{
  247. CowList: model.EventMatingSlice(eventMatingList).ToPB2(),
  248. Chart: chart,
  249. },
  250. }, nil
  251. }
  252. func (s *StoreEntry) PenWeight(ctx context.Context, req *pasturePb.PenWeightRequest, pagination *pasturePb.PaginationModel) (*pasturePb.PenWeightResponse, error) {
  253. userModel, err := s.GetUserModel(ctx)
  254. if err != nil {
  255. return nil, xerr.WithStack(err)
  256. }
  257. penWeightList := make([]*model.PenWeight, 0)
  258. pref := s.DB.Model(new(model.Cow)).
  259. Select(`
  260. pen_id,
  261. CEILING(AVG(current_weight) / 1000 ) AS avg_weight,
  262. CEILING(SUM(current_weight) / 1000 ) AS all_weight,
  263. COUNT(*) AS cow_count`,
  264. ).
  265. Where("pasture_id = ?", userModel.AppPasture.Id).
  266. Where("admission_status = ?", pasturePb.AdmissionStatus_Admission)
  267. if len(req.PenId) > 0 && req.BarId <= 0 {
  268. pref.Where("pen_id IN ?", req.PenId)
  269. }
  270. if err = pref.Group("pen_id").
  271. Order("pen_id").
  272. Find(&penWeightList).Error; err != nil {
  273. return nil, err
  274. }
  275. chart := &pasturePb.PenWeightChart{
  276. Header: make([]string, 0),
  277. AllWeight: make([]int32, 0),
  278. AvgWeight: make([]int32, 0),
  279. CowCount: make([]int32, 0),
  280. }
  281. if len(penWeightList) <= 0 {
  282. return &pasturePb.PenWeightResponse{
  283. Code: http.StatusOK,
  284. Msg: "ok",
  285. Data: &pasturePb.PenWeightData{
  286. CowList: make([]*pasturePb.CowList, 0),
  287. Chart: chart,
  288. },
  289. }, nil
  290. }
  291. cowList := make([]*model.Cow, 0)
  292. var count int64 = 0
  293. prefList := s.DB.Model(new(model.Cow)).
  294. Where("admission_status = ?", pasturePb.AdmissionStatus_Admission)
  295. if len(req.PenId) > 0 {
  296. prefList.Where("pen_id IN (?)", req.PenId)
  297. } else if req.BarId > 0 {
  298. prefList.Where("pen_id = ?", []int32{req.BarId})
  299. }
  300. if err = prefList.Count(&count).Limit(int(pagination.PageSize)).
  301. Offset(int(pagination.PageOffset)).Order("pen_id").
  302. Find(&cowList).Error; err != nil {
  303. return nil, xerr.WithStack(err)
  304. }
  305. penMap := s.PenMap(ctx, userModel.AppPasture.Id)
  306. return &pasturePb.PenWeightResponse{
  307. Code: http.StatusOK,
  308. Msg: "ok",
  309. Data: &pasturePb.PenWeightData{
  310. CowList: model.CowSlice(cowList).ToPB2(penMap, penWeightList),
  311. Total: int32(count),
  312. Page: pagination.Page,
  313. PageSize: pagination.PageSize,
  314. Chart: model.PenWeightSlice(penWeightList).ToPB(penMap),
  315. },
  316. }, nil
  317. }
  318. func (s *StoreEntry) AbortionRate(ctx context.Context, req *pasturePb.AbortionRateRequest) (*pasturePb.AbortionRateResponse, error) {
  319. userModel, err := s.GetUserModel(ctx)
  320. if err != nil {
  321. return nil, xerr.WithStack(err)
  322. }
  323. dayTimeList, err := util.GetMonthsInRange(req.StartDayTime, req.EndDayTime)
  324. if err != nil {
  325. return nil, xerr.WithStack(err)
  326. }
  327. lastDayForMonth := make([]string, 0)
  328. for _, v := range dayTimeList {
  329. lastDayTime, _ := util.GetLastDayOfMonth(v)
  330. lastDayForMonth = append(lastDayForMonth, lastDayTime)
  331. }
  332. // 历史每月怀孕牛头数量
  333. cowPregnantMonthList := make([]*model.CowPregnantMonth, 0)
  334. pref := s.DB.Model(new(model.EventMating)).
  335. Select(`
  336. COUNT(cow_id) AS cow_count,
  337. DATE_FORMAT(FROM_UNIXTIME(reality_day),'%Y-%m') as month`,
  338. ).Where("cow_type = ?", req.CowType).
  339. Where("pasture_id = ?", userModel.AppPasture.Id).
  340. Where("status = ?", pasturePb.IsShow_Ok).
  341. Where("mating_result = ?", pasturePb.MatingResult_Pregnant).
  342. Where("DATE_FORMAT(FROM_UNIXTIME(`reality_day`),'%Y-%m-%d') IN ?", lastDayForMonth)
  343. if req.Lact >= 0 && req.Lact <= 3 {
  344. pref.Where("lact = ?", req.Lact)
  345. } else {
  346. pref.Where("lact > ?", req.Lact)
  347. }
  348. if err = pref.Group("month").
  349. Find(&cowPregnantMonthList).Error; err != nil {
  350. return nil, xerr.WithStack(err)
  351. }
  352. // 历史每月流产牛头数量
  353. cowAbortionMonthList := make([]*model.CowPregnantMonth, 0)
  354. pref2 := s.DB.Model(new(model.EventAbortion)).
  355. Select(`
  356. COUNT(cow_id) AS cow_count,
  357. DATE_FORMAT(FROM_UNIXTIME(abortion_at),'%Y-%m') as month`,
  358. ).Where("cow_type = ?", req.CowType).
  359. Where("DATE_FORMAT(FROM_UNIXTIME(abortion_at),'%Y-%m') IN ?", dayTimeList)
  360. if req.Lact >= 0 {
  361. pref2.Where("lact = ?", req.Lact)
  362. }
  363. if err = pref2.Group("month").Find(&cowAbortionMonthList).Error; err != nil {
  364. return nil, xerr.WithStack(err)
  365. }
  366. chart := &pasturePb.AbortionRateChart{
  367. Header: make([]string, 0),
  368. AbortionCountMonth: make([]int32, 0),
  369. PregnantCountMonth: make([]int32, 0),
  370. AbortionRateMonth: make([]float32, 0),
  371. }
  372. table := make([]*pasturePb.AbortionRateTable, 0)
  373. for _, v2 := range cowAbortionMonthList {
  374. pregnantCountMonth := int32(0)
  375. for _, v := range cowPregnantMonthList {
  376. if v.Month == v2.Month {
  377. pregnantCountMonth = v.CowCount
  378. }
  379. }
  380. abortionRateMonth := float64(0)
  381. if pregnantCountMonth > 0 && v2.CowCount > 0 {
  382. abortionRateMonth = util.RoundToTwoDecimals(float64(v2.CowCount) / float64(pregnantCountMonth) * 100)
  383. }
  384. chart.Header = append(chart.Header, v2.Month)
  385. chart.AbortionCountMonth = append(chart.AbortionCountMonth, v2.CowCount)
  386. chart.PregnantCountMonth = append(chart.PregnantCountMonth, pregnantCountMonth)
  387. chart.AbortionRateMonth = append(chart.AbortionRateMonth, float32(abortionRateMonth))
  388. table = append(table, &pasturePb.AbortionRateTable{
  389. AbortionCount: v2.CowCount,
  390. MonthName: v2.Month,
  391. PregnantCount: pregnantCountMonth,
  392. AbortionRate: float32(abortionRateMonth),
  393. })
  394. }
  395. return &pasturePb.AbortionRateResponse{
  396. Code: http.StatusOK,
  397. Msg: "ok",
  398. Data: &pasturePb.AbortionRateData{
  399. Chart: chart,
  400. Table: table,
  401. },
  402. }, nil
  403. }
  404. func (s *StoreEntry) TwentyOnePregnantRate(ctx context.Context, req *pasturePb.TwentyOnePregnantRateRequest) (*pasturePb.TwentyOnePregnantRateResponse, error) {
  405. userModel, err := s.GetUserModel(ctx)
  406. if err != nil {
  407. return nil, xerr.WithStack(err)
  408. }
  409. startUnix := util.TimeParseLocalUnix(req.StartDate)
  410. endUnix := util.TimeParseLocalUnix(req.EndDate)
  411. if startUnix > endUnix {
  412. return nil, xerr.Customf("开始时间不能大于结束时间: %s ~ %d", req.StartDate, req.EndDate)
  413. }
  414. nowDateTime := time.Now()
  415. if endUnix > nowDateTime.Unix() {
  416. return nil, xerr.Customf("结束时间不能大于当前时间: %s ~ %s", req.EndDate, nowDateTime.Format(model.LayoutDate2))
  417. }
  418. dataRange, err := util.Get21DayPeriods(req.StartDate, req.EndDate)
  419. if err != nil {
  420. return nil, xerr.WithStack(err)
  421. }
  422. chart := &pasturePb.TwentyOnePregnantRateChart{
  423. Header: make([]string, 0),
  424. PregnantRate: make([]float32, 0),
  425. MatingRate: make([]float32, 0),
  426. }
  427. // 牛只主动停配期
  428. systemBasicName := ""
  429. switch req.CowType {
  430. case pasturePb.CowType_Breeding_Calf:
  431. systemBasicName = model.ProactivelyStopBreedingForAdult
  432. case pasturePb.CowType_Reserve_Calf:
  433. systemBasicName = model.ProactivelyStopBreedingForBackup
  434. default:
  435. return nil, xerr.Customf("不支持的牛只类型: %d", req.CowType)
  436. }
  437. systemBasic, err := s.GetSystemBasicByName(ctx, systemBasicName)
  438. if err != nil {
  439. return nil, xerr.WithStack(err)
  440. }
  441. stopBreedingDay := systemBasic.MinValue * 86400
  442. dateCowList := make([][]*model.Cow, len(dataRange))
  443. twentyOnePregnantRateList := make([]*pasturePb.TwentyOnePregnantRateList, 0)
  444. for i, v := range dataRange {
  445. middleDay, err := util.GetRangeDayMiddleDay(v, 11)
  446. if err != nil {
  447. return nil, xerr.WithStack(err)
  448. }
  449. middleDayUnix := util.TimeParseLocalEndUnix(middleDay)
  450. chart.Header = append(chart.Header, fmt.Sprintf("%s ~ %s", v[0], v[1]))
  451. cowList := s.TwentyOnePregnantCowList(userModel.AppPasture.Id, req.CowType, stopBreedingDay, middleDayUnix, []int64{})
  452. twentyOnePregnantRateList = append(twentyOnePregnantRateList, &pasturePb.TwentyOnePregnantRateList{
  453. StartDay: v[0],
  454. EndDay: v[1],
  455. ShouldBreedCount: int32(len(cowList)),
  456. RealityBreedCount: 0,
  457. BreedRate: 0,
  458. ShouldPregnantCount: 0,
  459. RealityPregnantCount: 0,
  460. PregnantRate: 0,
  461. RealityAbortionCount: 0,
  462. AbortionRate: 0,
  463. })
  464. dateCowList[i] = cowList
  465. }
  466. return &pasturePb.TwentyOnePregnantRateResponse{
  467. Code: http.StatusOK,
  468. Msg: "ok",
  469. Data: &pasturePb.TwentyOnePregnantRateData{
  470. Chart: chart,
  471. Table: &pasturePb.TwentyOnePregnantRateTable{
  472. List: twentyOnePregnantRateList,
  473. Total: int32(len(dataRange)),
  474. },
  475. },
  476. }, nil
  477. }
  478. // TwentyOnePregnantCowList 21天牛只停配期牛只列表
  479. func (s *StoreEntry) TwentyOnePregnantCowList(
  480. pastureId int64,
  481. cowType pasturePb.CowType_Kind,
  482. stopBreedingDay int32,
  483. middleDay int64,
  484. notInCow []int64,
  485. ) []*model.Cow {
  486. cowList := make([]*model.Cow, 0)
  487. switch cowType {
  488. case pasturePb.CowType_Reserve_Calf:
  489. pref := s.DB.Model(new(model.Cow)).
  490. Where("pasture_id = ?", pastureId).
  491. Where("cow_type = ?", cowType).
  492. Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
  493. Where("is_pregnant = ?", pasturePb.IsShow_No).
  494. Where("lact = ?", 0).
  495. Where("birth_at + ? < ?", stopBreedingDay, middleDay)
  496. if len(notInCow) > 0 {
  497. pref = pref.Where("id NOT IN ?", notInCow)
  498. }
  499. if err := pref.Find(&cowList).Error; err != nil {
  500. zaplog.Error("TwentyOnePregnantCowList",
  501. zap.Any("cowType", cowType),
  502. zap.Any("stopBreedingDay", stopBreedingDay),
  503. zap.Any("middleDay", middleDay),
  504. zap.Any("notInCow", notInCow),
  505. )
  506. }
  507. case pasturePb.CowType_Breeding_Calf:
  508. }
  509. return cowList
  510. }