analysis.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. package backend
  2. import (
  3. "context"
  4. "fmt"
  5. "kpt-pasture/model"
  6. "net/http"
  7. "strings"
  8. "time"
  9. "gitee.com/xuyiping_admin/pkg/xerr"
  10. pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
  11. )
  12. // GrowthCurve 生长曲线 获取图表数据
  13. func (s *StoreEntry) GrowthCurve(ctx context.Context, req *pasturePb.SearchGrowthCurvesRequest) (*pasturePb.GrowthCurvesResponse, error) {
  14. // 查询数据
  15. cowList := make([]*model.Cow, 0)
  16. pref := s.DB.Model(new(model.Cow)).Where("is_remove = ?", pasturePb.IsShow_Ok)
  17. if req.GetCowId() != "" {
  18. pref.Where("id IN ?", strings.Split(req.CowId, ","))
  19. }
  20. if len(req.BirthDate) == 2 && req.BirthDate[0] != "" && req.BirthDate[1] != "" {
  21. t0, _ := time.Parse(time.RFC3339, req.BirthDate[0])
  22. t1, _ := time.Parse(time.RFC3339, req.BirthDate[1])
  23. pref.Where("birth_at BETWEEN ? AND ?", t0.Unix(), t1.Unix()+86399)
  24. }
  25. if err := pref.Find(&cowList).Error; err != nil {
  26. return nil, err
  27. }
  28. penList, err := s.GetPenList(ctx)
  29. if err != nil {
  30. return nil, xerr.WithStack(err)
  31. }
  32. // 计算图表数据
  33. chartsList := &pasturePb.Charts{
  34. CowId: make([]int32, 0),
  35. Weight: make([]float32, 0),
  36. DayAge: make([]int32, 0),
  37. }
  38. cowData := make([]*pasturePb.CowList, 0)
  39. for _, cow := range cowList {
  40. currentWeight := float32(cow.CurrentWeight) / 100
  41. penName := ""
  42. for _, v := range penList {
  43. if int64(cow.PenId) != v.Id {
  44. continue
  45. }
  46. penName = v.Name
  47. }
  48. cowData = append(cowData, &pasturePb.CowList{
  49. CowId: int32(cow.Id),
  50. EarNumber: cow.EarNumber,
  51. DayAge: cow.GetDayAge(),
  52. PenName: penName,
  53. CurrentWeight: currentWeight,
  54. BirthAt: int32(cow.BirthAt),
  55. BirthWeight: float32(cow.BirthWeight) / 100,
  56. LastWeightAt: int32(cow.LastWeightAt),
  57. DailyWeightGain: float32(cow.GetDayWeight() / 100),
  58. AverageDailyWeightGain: float32(cow.GetAverageDailyWeight() / 100),
  59. })
  60. chartsList.CowId = append(chartsList.CowId, int32(cow.Id))
  61. chartsList.Weight = append(chartsList.Weight, currentWeight)
  62. chartsList.DayAge = append(chartsList.DayAge, cow.GetDayAge())
  63. }
  64. // 返回数据
  65. return &pasturePb.GrowthCurvesResponse{
  66. Code: http.StatusOK,
  67. Message: "success",
  68. Data: &pasturePb.GrowthCurveData{
  69. Table: cowData,
  70. Charts: chartsList,
  71. },
  72. }, nil
  73. }
  74. func (s *StoreEntry) WeightRange(ctx context.Context, req *pasturePb.WeightRangeRequest) (*pasturePb.WeightRangeResponse, error) {
  75. cowWeightRange := make([]*model.CowWeightRange, 0)
  76. prefix := s.DB.Model(new(model.Cow)).Where("is_remove = ?", pasturePb.IsShow_Ok)
  77. if req.CowKind > 0 {
  78. prefix.Where("cow_kind = ?", req.CowKind)
  79. }
  80. if err := prefix.Select(`
  81. CASE
  82. WHEN current_weight BETWEEN 0 AND 50000 THEN '0-50'
  83. WHEN current_weight BETWEEN 50001 AND 100000 THEN '51-100'
  84. WHEN current_weight BETWEEN 100001 AND 150000 THEN '101-150'
  85. WHEN current_weight BETWEEN 150001 AND 200000 THEN '151-200'
  86. WHEN current_weight BETWEEN 200001 AND 250000 THEN '201-250'
  87. WHEN current_weight BETWEEN 250001 AND 300000 THEN '251-300'
  88. WHEN current_weight BETWEEN 300001 AND 350000 THEN '301-350'
  89. WHEN current_weight BETWEEN 350001 AND 400000 THEN '351-400'
  90. WHEN current_weight BETWEEN 400001 AND 450000 THEN '401-450'
  91. WHEN current_weight BETWEEN 450001 AND 500000 THEN '451-500'
  92. WHEN current_weight BETWEEN 500001 AND 550000 THEN '500-550'
  93. WHEN current_weight BETWEEN 550001 AND 600000 THEN '551-600'
  94. WHEN current_weight BETWEEN 600001 AND 650000 THEN '601-650'
  95. WHEN current_weight BETWEEN 650001 AND 700000 THEN '651-700'
  96. WHEN current_weight BETWEEN 700001 AND 750000 THEN '701-750'
  97. ELSE '750+'
  98. END AS weight_range,
  99. COUNT(*) AS count `,
  100. ).Group("weight_range").Order("MIN(current_weight)").Find(&cowWeightRange).Error; err != nil {
  101. return nil, err
  102. }
  103. if len(cowWeightRange) == 0 {
  104. return &pasturePb.WeightRangeResponse{
  105. Code: http.StatusOK,
  106. Message: "ok",
  107. Data: &pasturePb.WeightRangeData{
  108. CowList: make([]*pasturePb.CowList, 0),
  109. WeightBarChart: &pasturePb.WeightBarChart{
  110. Header: make([]string, 0),
  111. Data: make([]int32, 0),
  112. },
  113. },
  114. }, nil
  115. }
  116. header := make([]string, 0)
  117. data := make([]int32, 0)
  118. for _, v := range cowWeightRange {
  119. header = append(header, v.WeightRange)
  120. data = append(data, v.Count)
  121. }
  122. // 牛只详情列表
  123. pref := s.DB.Model(new(model.Cow)).Where("is_remove = ?", pasturePb.IsShow_Ok)
  124. if req.CowKind > 0 {
  125. pref.Where("cow_kind = ?", req.CowKind)
  126. }
  127. cowList := make([]*model.Cow, 0)
  128. if req.MinWeight >= 0 && req.MaxWeight >= 0 && req.MinWeight < req.MaxWeight {
  129. pref.Where("current_weight BETWEEN ? AND ? ", req.MinWeight*1000, req.MaxWeight*1000)
  130. }
  131. if err := pref.Find(&cowList).Error; err != nil {
  132. return nil, err
  133. }
  134. penMap := s.PenMap(ctx)
  135. return &pasturePb.WeightRangeResponse{
  136. Code: http.StatusOK,
  137. Message: "ok",
  138. Data: &pasturePb.WeightRangeData{
  139. CowList: model.CowSlice(cowList).WeightRangeToPB(penMap),
  140. WeightBarChart: &pasturePb.WeightBarChart{
  141. Header: header,
  142. Data: data,
  143. },
  144. },
  145. }, nil
  146. }
  147. func (s *StoreEntry) MatingTimely(ctx context.Context, req *pasturePb.MatingTimelyRequest) (*model.MatingTimelyResponse, error) {
  148. matingTimelyChart := make([]*model.MatingTimelyChart, 0)
  149. sql := `SELECT calving_age,cow_type, DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') AS reality_day, lact_group
  150. FROM (
  151. SELECT calving_age, cow_type,reality_day, '0' AS lact_group
  152. FROM event_mating
  153. WHERE lact = 0 AND status = 1
  154. UNION ALL
  155. SELECT calving_age,cow_type, reality_day, '1' AS lact_group
  156. FROM event_mating
  157. WHERE lact = 1 AND status = 1
  158. UNION ALL
  159. SELECT calving_age,cow_type, reality_day, '2' AS lact_group
  160. FROM event_mating
  161. WHERE lact = 2 AND status = 1
  162. UNION ALL
  163. SELECT calving_age, cow_type, reality_day, '3+' AS lact_group
  164. FROM event_mating
  165. WHERE lact >= 3 AND status = 1
  166. ) AS subquery WHERE 1 = 1 `
  167. whereSql := ""
  168. if req.CowType > 0 {
  169. whereSql += fmt.Sprintf("AND cow_type = %d ", req.CowType)
  170. }
  171. if req.StartDayAt > 0 && req.EndDayAt > 0 {
  172. whereSql += fmt.Sprintf("AND reality_day BETWEEN %d AND %d", req.StartDayAt, req.EndDayAt)
  173. }
  174. if err := s.DB.Raw(fmt.Sprintf("%s %s", sql, whereSql)).Find(&matingTimelyChart).Error; err != nil {
  175. return nil, err
  176. }
  177. chart := &model.CowMatingChart{
  178. Lact0: make([][]string, 0),
  179. Lact1: make([][]string, 0),
  180. Lact2: make([][]string, 0),
  181. Lact3: make([][]string, 0),
  182. }
  183. if len(matingTimelyChart) == 0 {
  184. return &model.MatingTimelyResponse{
  185. Code: http.StatusOK,
  186. Message: "ok",
  187. Data: &model.MatingTimelyData{
  188. CowList: make([]*pasturePb.CowList, 0),
  189. Chart: chart,
  190. },
  191. }, nil
  192. }
  193. for _, v := range matingTimelyChart {
  194. switch v.LactGroup {
  195. case "0":
  196. chart.Lact0 = append(chart.Lact0, []string{fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
  197. case "1":
  198. chart.Lact1 = append(chart.Lact1, []string{fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
  199. case "2":
  200. chart.Lact2 = append(chart.Lact2, []string{fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
  201. case "3+":
  202. chart.Lact3 = append(chart.Lact3, []string{fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
  203. }
  204. }
  205. // 牛只详情列表
  206. eventMatingList := make([]*model.EventMating, 0)
  207. pref := s.DB.Model(new(model.EventMating)).
  208. Where("status = ?", pasturePb.IsShow_Ok)
  209. if req.CowType > 0 {
  210. pref.Where("cow_type = ?", req.CowType)
  211. }
  212. if req.StartDayAt > 0 && req.EndDayAt > 0 {
  213. pref.Where("reality_day BETWEEN ? AND ?", req.StartDayAt, req.EndDayAt)
  214. }
  215. if err := pref.Find(&eventMatingList).Error; err != nil {
  216. return nil, err
  217. }
  218. return &model.MatingTimelyResponse{
  219. Code: http.StatusOK,
  220. Message: "ok",
  221. Data: &model.MatingTimelyData{
  222. CowList: model.EventMatingSlice(eventMatingList).ToPB2(),
  223. Chart: chart,
  224. },
  225. }, nil
  226. }
  227. func (s *StoreEntry) PenWeight(ctx context.Context, req *pasturePb.PenWeightRequest, pagination *pasturePb.PaginationModel) (*pasturePb.PenWeightResponse, error) {
  228. penWeightList := make([]*model.PenWeight, 0)
  229. pref := s.DB.Model(new(model.Cow)).
  230. Select(`
  231. pen_id,
  232. CEILING(AVG(current_weight) / 1000 ) AS avg_weight,
  233. CEILING(SUM(current_weight) / 1000 ) AS all_weight,
  234. COUNT(*) AS cow_count`,
  235. ).Where("is_remove = ?", pasturePb.IsShow_Ok)
  236. if len(req.PenId) > 0 {
  237. pref.Where("pen_id IN ?", req.PenId)
  238. }
  239. if err := pref.Group("pen_id").
  240. Order("pen_id").
  241. Find(&penWeightList).Error; err != nil {
  242. return nil, err
  243. }
  244. chart := &pasturePb.PenWeightChart{
  245. Header: make([]string, 0),
  246. AllWeight: make([]int32, 0),
  247. AvgWeight: make([]int32, 0),
  248. CowCount: make([]int32, 0),
  249. }
  250. if len(penWeightList) <= 0 {
  251. return &pasturePb.PenWeightResponse{
  252. Code: http.StatusOK,
  253. Message: "ok",
  254. Data: &pasturePb.PenWeightData{
  255. CowList: make([]*pasturePb.CowList, 0),
  256. Chart: chart,
  257. },
  258. }, nil
  259. }
  260. cowList := make([]*model.Cow, 0)
  261. var count int64 = 0
  262. prefList := s.DB.Model(new(model.Cow)).
  263. Where("is_remove = ?", pasturePb.IsShow_Ok)
  264. if len(req.PenId) > 0 {
  265. prefList.Where("pen_id IN ?", req.PenId)
  266. }
  267. if err := prefList.Count(&count).Limit(int(pagination.PageSize)).
  268. Offset(int(pagination.PageOffset)).Order("pen_id").
  269. Find(&cowList).Error; err != nil {
  270. return nil, xerr.WithStack(err)
  271. }
  272. penMap := s.PenMap(ctx)
  273. return &pasturePb.PenWeightResponse{
  274. Code: http.StatusOK,
  275. Message: "ok",
  276. Data: &pasturePb.PenWeightData{
  277. CowList: model.CowSlice(cowList).ToPB2(penMap, penWeightList),
  278. Total: int32(count),
  279. Page: pagination.Page,
  280. PageSize: pagination.PageSize,
  281. Chart: model.PenWeightSlice(penWeightList).ToPB(penMap),
  282. },
  283. }, nil
  284. }