statistic_service.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. package backend
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "kpt-tmr-group/model"
  7. "kpt-tmr-group/pkg/logger/zaplog"
  8. "kpt-tmr-group/pkg/xerr"
  9. operationPb "kpt-tmr-group/proto/go/backend/operation"
  10. "net/http"
  11. "strconv"
  12. "strings"
  13. "go.uber.org/zap"
  14. )
  15. type PastureClientHandler func(ctx context.Context, pastureId int64, body interface{}) error
  16. // type eventHandler func(ev map[string]interface{}, openID string, appID string, enterpriseID int, cts int64, conn redis.Conn) error
  17. // PastureDetailById 获取指定牧场详情
  18. func (s *StoreEntry) PastureDetailById(ctx context.Context, pastureId int64) (*model.GroupPasture, error) {
  19. result := &model.GroupPasture{Id: pastureId}
  20. if err := s.DB.Where("is_delete = ? and is_show = ?", operationPb.IsShow_OK, operationPb.IsShow_OK).First(result).Error; err != nil {
  21. return nil, xerr.WithStack(err)
  22. }
  23. return result, nil
  24. }
  25. func (s *StoreEntry) PastureHttpClient(ctx context.Context, apiUrl string, pastureId int64, body, response interface{}) error {
  26. pastureDetail, err := s.PastureDetailById(ctx, pastureId)
  27. if err != nil {
  28. zaplog.Error("SearchFormulaEstimateList", zap.Any("Err", err), zap.Int64("pastureId", pastureId))
  29. return xerr.Customf("该牧场数据错误,Err:%s", err)
  30. }
  31. pastureClient := model.NewPastureClient(pastureDetail)
  32. url := fmt.Sprintf("%s/%s", pastureDetail.Domain, apiUrl)
  33. result, err := pastureClient.DoPost(url, body)
  34. if err != nil {
  35. return xerr.WithStack(err)
  36. }
  37. zaplog.Info("PastureHttpClient", zap.String("url", url), zap.Any("request", body), zap.String("response", string(result)))
  38. if err = json.Unmarshal(result, response); err != nil {
  39. return xerr.WithStack(err)
  40. }
  41. return nil
  42. }
  43. // SearchFormulaEstimateList 配方评估
  44. func (s *StoreEntry) SearchFormulaEstimateList(ctx context.Context, req *operationPb.SearchFormulaEstimateRequest) (*model.PastureCommonResponse, error) {
  45. body := &model.PastureCommonRequest{
  46. Name: req.ApiName,
  47. Page: req.Pagination.Page,
  48. Offset: req.Pagination.PageOffset,
  49. PageCount: req.Pagination.PageSize,
  50. ReturnType: "Map",
  51. ParamMaps: &model.FormulaEstimateParams{
  52. PastureId: fmt.Sprintf("%d", req.PastureId),
  53. StartTime: req.StartTime,
  54. StopTime: req.EndTime,
  55. Search: fmt.Sprintf("%d", req.SearchType),
  56. TempletId: fmt.Sprintf("%d", req.TemplateId),
  57. Barid: fmt.Sprintf("%d", req.BarnId),
  58. },
  59. }
  60. response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
  61. if err := s.PastureHttpClient(ctx, model.UrlDataByName, int64(req.PastureId), body, response); err != nil {
  62. return nil, xerr.WithStack(err)
  63. }
  64. return response, nil
  65. }
  66. // SearchInventoryStatistics 库存管理-库存统计
  67. func (s *StoreEntry) SearchInventoryStatistics(ctx context.Context, req *operationPb.SearchInventoryStatisticsRequest) (*model.PastureCommonResponse, error) {
  68. body := &model.PastureCommonRequest{
  69. Name: req.ApiName,
  70. Page: req.Pagination.Page,
  71. Offset: req.Pagination.PageOffset,
  72. PageCount: req.Pagination.PageSize,
  73. ReturnType: "Map",
  74. ParamMaps: &model.InventoryStatisticsParams{
  75. PastureId: fmt.Sprintf("%d", req.PastureId),
  76. StartTime: req.StartTime,
  77. StopTime: req.EndTime,
  78. FeedName: req.FeedName,
  79. },
  80. }
  81. response := &model.PastureCommonResponse{
  82. Data: &model.PastureCommonData{
  83. List: make([]*model.InventoryStatisticsList, 0),
  84. },
  85. }
  86. if err := s.PastureHttpClient(ctx, model.UrlDataByName, int64(req.PastureId), body, response); err != nil {
  87. return nil, xerr.WithStack(err)
  88. }
  89. return response, nil
  90. }
  91. // SearchUserMaterialsStatistics 库存管理-用料分析
  92. func (s *StoreEntry) SearchUserMaterialsStatistics(ctx context.Context, req *operationPb.SearchUserMaterialsStatisticsRequest) (*model.PastureCommonResponse, error) {
  93. body := &model.PastureCommonRequest{
  94. Name: req.ApiName,
  95. Page: req.Pagination.Page,
  96. Offset: req.Pagination.PageOffset,
  97. PageCount: req.Pagination.PageSize,
  98. ReturnType: "Map",
  99. Checked: req.ErrorCheck,
  100. ParamMaps: &model.UserMaterialsStatisticsParams{
  101. PastureId: fmt.Sprintf("%d", req.PastureId),
  102. StartTime: req.StartTime,
  103. StopTime: req.EndTime,
  104. FeedName: req.FeedName,
  105. Typea: fmt.Sprintf("%d", req.TypeCheck),
  106. },
  107. }
  108. response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
  109. if err := s.PastureHttpClient(ctx, model.UrlReportForm, int64(req.PastureId), body, response); err != nil {
  110. return nil, xerr.WithStack(err)
  111. }
  112. return response, nil
  113. }
  114. // SearchPriceStatistics 库存管理-价格分析
  115. func (s *StoreEntry) SearchPriceStatistics(ctx context.Context, req *operationPb.SearchPriceStatisticsRequest) (*model.PastureCommonResponse, error) {
  116. body := &model.PastureCommonRequest{
  117. Name: req.ApiName,
  118. Page: req.Pagination.Page,
  119. Offset: req.Pagination.PageOffset,
  120. PageCount: req.Pagination.PageSize,
  121. ReturnType: "Map",
  122. ParamMaps: &model.PriceStatisticsParams{
  123. PastureId: fmt.Sprintf("%d", req.PastureId),
  124. StartTime: req.StartTime,
  125. StopTime: req.EndTime,
  126. FeedName: req.FeedName,
  127. },
  128. }
  129. response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
  130. if err := s.PastureHttpClient(ctx, model.UrlReportForm, int64(req.PastureId), body, response); err != nil {
  131. return nil, xerr.WithStack(err)
  132. }
  133. return response, nil
  134. }
  135. // SearchFeedStatistics 饲喂效率-效率统计
  136. func (s *StoreEntry) SearchFeedStatistics(ctx context.Context, req *operationPb.SearchFeedStatisticsRequest) (*model.PastureCommonResponse, error) {
  137. body := &model.PastureCommonRequest{
  138. Name: req.ApiName,
  139. Page: req.Pagination.Page,
  140. Offset: req.Pagination.PageOffset,
  141. PageCount: req.Pagination.PageSize,
  142. ReturnType: "Map",
  143. ParamMaps: &model.FeedStatisticsParams{
  144. PastureId: fmt.Sprintf("%d", req.PastureId),
  145. StartTime: req.StartTime,
  146. StopTime: req.StartTime,
  147. Date: req.StartTime,
  148. FeedTName: req.FormulaTemplate,
  149. BarName: req.BarnName,
  150. CowClass: req.CattleCategoryName,
  151. Times: fmt.Sprintf("%d", req.ClassNumber),
  152. },
  153. }
  154. response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
  155. if err := s.PastureHttpClient(ctx, model.UrlDataByName, int64(req.PastureId), body, response); err != nil {
  156. return nil, xerr.WithStack(err)
  157. }
  158. return response, nil
  159. }
  160. // FeedChartStatistics 饲喂效率图表分析
  161. func (s *StoreEntry) FeedChartStatistics(ctx context.Context, req *operationPb.FeedChartStatisticsRequest) (*model.PastureCommonResponse, error) {
  162. body := &model.FeedChartParams{
  163. ParamMaps: &model.ParamMaps{
  164. PastureId: fmt.Sprintf("%d", req.PastureId),
  165. StartTime: req.StartTime,
  166. StopTime: req.StartTime,
  167. Status: req.Status,
  168. },
  169. }
  170. url, ok := model.UrlChart[req.ApiType]
  171. if !ok {
  172. return nil, xerr.Customf("错误的接口类型:%s", req.ApiType)
  173. }
  174. response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
  175. if err := s.PastureHttpClient(ctx, url, int64(req.PastureId), body, response); err != nil {
  176. return nil, xerr.WithStack(err)
  177. }
  178. return response, nil
  179. }
  180. // CowsAnalysis 饲喂效率-牛群评估
  181. func (s *StoreEntry) CowsAnalysis(ctx context.Context, req *operationPb.CowsAnalysisRequest) (*model.PastureCommonResponse, error) {
  182. body := &model.PastureCommonRequest{
  183. Name: req.ApiName,
  184. Page: req.Pagination.Page,
  185. Offset: req.Pagination.PageOffset,
  186. PageCount: req.Pagination.PageSize,
  187. ReturnType: "Map",
  188. ParamMaps: &model.MixFeedStatisticsParams{
  189. PastureId: fmt.Sprintf("%d", req.PastureId),
  190. StartTime: req.StartTime,
  191. StopTime: req.StartTime,
  192. },
  193. }
  194. response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
  195. if err := s.PastureHttpClient(ctx, model.UrlDataByName, int64(req.PastureId), body, response); err != nil {
  196. return nil, xerr.WithStack(err)
  197. }
  198. return response, nil
  199. }
  200. // SearchAccuracyAggStatistics 准确性分析-汇总分析
  201. func (s *StoreEntry) SearchAccuracyAggStatistics(ctx context.Context, req *operationPb.AccuracyAggStatisticsRequest) (*model.PastureCommonResponse, error) {
  202. body := &model.FeedChartParams{
  203. ParamMaps: &model.AccuracyAggParams{
  204. PastureId: fmt.Sprintf("%d", req.PastureId),
  205. StartTime: req.StartTime,
  206. StopTime: req.EndTime,
  207. FName: req.Fname,
  208. Sort: req.Sort,
  209. Status: req.Status,
  210. Times: req.Times,
  211. Genre: req.Genre,
  212. IsDate: req.Isdate,
  213. Hlwc1: req.Hlwc1,
  214. Hlwc2: req.Hlwc2,
  215. Hlzq1: req.Hlzq1,
  216. Hlzq2: req.Hlzq2,
  217. Hlzql1: req.Hlzql1,
  218. Hlzql2: req.Hlzql2,
  219. Slwc1: req.Slwc1,
  220. Slwc2: req.Slwc2,
  221. Slzq1: req.Slzq1,
  222. Slzq2: req.Slzq2,
  223. Slzql1: req.Slzql1,
  224. Slzql2: req.Slzql2,
  225. Error: req.IsError,
  226. },
  227. }
  228. response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
  229. if err := s.PastureHttpClient(ctx, model.UrlSummary, int64(req.PastureId), body, response); err != nil {
  230. return nil, xerr.WithStack(err)
  231. }
  232. return response, nil
  233. }
  234. // SearchMixFeedStatistics 准确性分析-混料统计
  235. func (s *StoreEntry) SearchMixFeedStatistics(ctx context.Context, req *operationPb.MixFeedStatisticsRequest) (*model.PastureCommonResponse, error) {
  236. times := ""
  237. if req.ClassNumber > 0 {
  238. times = fmt.Sprintf("%d", req.ClassNumber)
  239. }
  240. body := &model.PastureCommonRequest{
  241. Name: req.ApiName,
  242. Page: req.Pagination.Page,
  243. Offset: req.Pagination.PageOffset,
  244. PageCount: req.Pagination.PageSize,
  245. ReturnType: "Map",
  246. ParamMaps: &model.MixFeedStatisticsParams{
  247. PastureId: fmt.Sprintf("%d", req.PastureId),
  248. StartTime: req.StartTime,
  249. StopTime: req.StartTime,
  250. TmrTName: req.EquipmentName,
  251. ProjName: req.TrainNumber,
  252. Times: times,
  253. ButtonType: req.ButtonType,
  254. TempletName: req.FormulationName,
  255. Isuse: req.IsUse,
  256. Hlwc1: req.Hlwc1,
  257. Hlwc2: req.Hlwc2,
  258. Hlzq1: req.Hlzq1,
  259. Hlzq2: req.Hlzq2,
  260. Hlzql1: req.Hlzql1,
  261. Hlzql2: req.Hlzql2,
  262. Error: req.IsError,
  263. },
  264. }
  265. response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
  266. if err := s.PastureHttpClient(ctx, model.UrlDataByName, int64(req.PastureId), body, response); err != nil {
  267. return nil, xerr.WithStack(err)
  268. }
  269. return response, nil
  270. }
  271. // SearchSprinkleStatistics 准确性分析-撒料统计
  272. func (s *StoreEntry) SearchSprinkleStatistics(ctx context.Context, req *operationPb.SprinkleStatisticsRequest) (*model.PastureCommonResponse, error) {
  273. times := ""
  274. if req.ClassNumber > 0 {
  275. times = fmt.Sprintf("%d", req.ClassNumber)
  276. }
  277. body := &model.PastureCommonRequest{
  278. Name: req.ApiName,
  279. Page: req.Pagination.Page,
  280. Offset: req.Pagination.PageOffset,
  281. PageCount: req.Pagination.PageSize,
  282. ReturnType: "Map",
  283. ParamMaps: &model.SprinkleStatisticsParams{
  284. PastureId: fmt.Sprintf("%d", req.PastureId),
  285. StartTime: req.StartTime,
  286. StopTime: req.StartTime,
  287. TmrTName: req.EquipmentName,
  288. ProjName: req.TrainNumber,
  289. Times: times,
  290. ButtonType: req.ButtonType,
  291. TempletName: req.FormulationName,
  292. Isuse: req.IsUse,
  293. Fname: req.BarnName,
  294. Slwc1: req.Slwc1,
  295. Slwc2: req.Slwc2,
  296. Slzq2: req.Slzq2,
  297. Slzq1: req.Slzq1,
  298. Slzql1: req.Slzql1,
  299. Slzql2: req.Slzql2,
  300. Error: req.IsError,
  301. },
  302. }
  303. response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
  304. if err := s.PastureHttpClient(ctx, model.UrlDataByName, int64(req.PastureId), body, response); err != nil {
  305. return nil, xerr.WithStack(err)
  306. }
  307. return response, nil
  308. }
  309. // SearchProcessAnalysis 过程分析
  310. func (s *StoreEntry) SearchProcessAnalysis(ctx context.Context, req *operationPb.ProcessAnalysisRequest) (*model.PastureCommonResponse, error) {
  311. body := &model.PastureCommonRequest{
  312. Name: req.ApiName,
  313. Page: req.Pagination.Page,
  314. Offset: req.Pagination.PageOffset,
  315. PageCount: req.Pagination.PageSize,
  316. ReturnType: "Map",
  317. ParamMaps: &model.ProcessAnalysisParams{
  318. PastureId: fmt.Sprintf("%d", req.PastureId),
  319. StartTime: req.StartTime,
  320. StopTime: req.StartTime,
  321. TmrTName: req.TmrName,
  322. IsCompleted: "",
  323. LpPlanType: fmt.Sprintf("%d", req.PlanType),
  324. FClassId: req.MixFeedType,
  325. Hlzq1: req.Hlzq1,
  326. Hlzq2: req.Hlzq2,
  327. Hlwc1: req.Hlwc1,
  328. Hlwc2: req.Hlwc2,
  329. Slwc1: req.Slwc1,
  330. Slwc2: req.Slwc2,
  331. Slzq2: req.Slzq2,
  332. Slzq1: req.Slzq1,
  333. Error: req.ErrorRange,
  334. },
  335. }
  336. response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
  337. if err := s.PastureHttpClient(ctx, model.UrlProcess, int64(req.PastureId), body, response); err != nil {
  338. return nil, xerr.WithStack(err)
  339. }
  340. return response, nil
  341. }
  342. func (s *StoreEntry) SearchAnalysisAccuracy(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (*model.SearchAnalysisAccuracyResponse, error) {
  343. dataList := &model.CommonValueRatio{
  344. MaxValue: "",
  345. MiddleValue: "",
  346. MinValue: "",
  347. PastureName: make([]string, 0),
  348. DateDay: make([]string, 0),
  349. DataList: make([][]string, 0),
  350. PastureIds: make([]int32, 0),
  351. }
  352. res := &model.SearchAnalysisAccuracyResponse{
  353. Code: http.StatusOK,
  354. Msg: "ok",
  355. Data: &model.AnalysisAccuracyData{
  356. Chart: &model.Chart{
  357. MixedFodderAccurateRatio: dataList,
  358. MixedFodderCorrectRatio: dataList,
  359. SprinkleFodderAccurateRatio: dataList,
  360. SprinkleFodderCorrectRatio: dataList,
  361. },
  362. Table: &model.Table{
  363. TitleList: make([]*model.TableList, 0),
  364. DataList: make([]*interface{}, 0),
  365. },
  366. },
  367. }
  368. res.Data.Table.TitleList = append(res.Data.Table.TitleList, &model.TableList{
  369. Name: "title",
  370. Value: "牧场",
  371. })
  372. analysisAccuracy := make([]*model.OptionsAnalysisAccuracy, 0)
  373. pref := s.DB.Model(new(model.AnalysisAccuracy))
  374. if req.EndDate != "" && req.StartDate != "" {
  375. pref.Where("date_day BETWEEN ? AND ?", req.StartDate, req.EndDate)
  376. }
  377. if req.CattleParentCategoryId > 0 {
  378. pref.Where("cattle_parent_category_id = ?", req.CattleParentCategoryId)
  379. }
  380. if req.FeedFormulaId > 0 {
  381. pref.Where("feed_formula_id = ?", req.FeedFormulaId)
  382. }
  383. if len(req.PastureIds) > 0 {
  384. pref.Where("pasture_id IN ?", req.PastureIds)
  385. }
  386. if err := pref.Select("pasture_id,pasture_name,date_day,sum(iweight) as all_iweight,sum(lweight) as all_lweight,sum(oweight) as all_oweight,sum(actual_weight_minus) as all_actual_weight_minus,sum(allow_ratio) as all_allow_ratio,sum(alweight) as all_alweight").
  387. Group("pasture_id,pasture_name,date_day").Order("pasture_name,date_day").Find(&analysisAccuracy).Debug().Error; err != nil {
  388. return nil, xerr.WithStack(err)
  389. }
  390. mixedFodderAccurateRatio := make([]float64, 0)
  391. mapPastureName := make(map[string]bool, 0)
  392. mapDateDay := make(map[string]bool, 0)
  393. mapRatio := make(map[string]bool, 0)
  394. tableList := make([]*model.TableList, 0)
  395. for k, v := range analysisAccuracy {
  396. if _, ok := mapPastureName[v.PastureName]; !ok {
  397. res.Data.Chart.MixedFodderAccurateRatio.PastureName = append(res.Data.Chart.MixedFodderAccurateRatio.PastureName, v.PastureName)
  398. res.Data.Chart.MixedFodderAccurateRatio.PastureIds = append(res.Data.Chart.MixedFodderAccurateRatio.PastureIds, int32(v.PastureId))
  399. mapPastureName[v.PastureName] = true
  400. }
  401. dataDayFormat := strings.TrimRight(v.DateDay, "T00:00:00+08:00")
  402. if _, ok := mapDateDay[v.DateDay]; !ok {
  403. res.Data.Chart.MixedFodderAccurateRatio.DateDay = append(res.Data.Chart.MixedFodderAccurateRatio.DateDay, dataDayFormat)
  404. mapDateDay[v.DateDay] = true
  405. }
  406. valueRatio1 := float64(v.AllIweight/v.AllLweight) / 100.0
  407. if _, ok := mapRatio[v.DateDay]; !ok {
  408. valueRatio := make([]string, 0)
  409. for _, a := range analysisAccuracy {
  410. if a.DateDay == v.DateDay {
  411. valueRatio = append(valueRatio, strconv.FormatFloat(float64(a.AllIweight/a.AllLweight)/100.0, 'f', 2, 64))
  412. }
  413. }
  414. res.Data.Chart.MixedFodderAccurateRatio.DataList = append(res.Data.Chart.MixedFodderAccurateRatio.DataList, valueRatio)
  415. mapRatio[v.DateDay] = true
  416. tableList = append(tableList, &model.TableList{
  417. Name: fmt.Sprintf("date%d", k),
  418. Value: dataDayFormat,
  419. })
  420. }
  421. mixedFodderAccurateRatio = append(mixedFodderAccurateRatio, valueRatio1)
  422. }
  423. mixedFodderAccurateRatioMaxValue, mixedFodderAccurateRatioMiddleValue, mixedFodderAccurateRatioMinValue := calculateRatio(mixedFodderAccurateRatio)
  424. res.Data.Chart.MixedFodderAccurateRatio.MaxValue = strconv.FormatFloat(mixedFodderAccurateRatioMaxValue, 'f', 2, 64)
  425. res.Data.Chart.MixedFodderAccurateRatio.MiddleValue = strconv.FormatFloat(mixedFodderAccurateRatioMiddleValue, 'f', 2, 64)
  426. res.Data.Chart.MixedFodderAccurateRatio.MinValue = strconv.FormatFloat(mixedFodderAccurateRatioMinValue, 'f', 2, 64)
  427. res.Data.Table.TitleList = append(res.Data.Table.TitleList, tableList...)
  428. return res, nil
  429. }
  430. func calculateRatio(res []float64) (float64, float64, float64) {
  431. var maxValue, middleValue, minValue, allValue float64 = 0, 0, 0, 0
  432. for _, v := range res {
  433. if v > maxValue {
  434. maxValue = v
  435. }
  436. if v <= maxValue {
  437. minValue = v
  438. }
  439. allValue += v
  440. }
  441. middleValue = allValue / float64(len(res))
  442. return maxValue, middleValue, minValue
  443. }