analysis.go 18 KB

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