dashboard_service.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. package backend
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "kpt-tmr-group/model"
  7. "net/http"
  8. "sort"
  9. "sync"
  10. "time"
  11. operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"
  12. "gitee.com/xuyiping_admin/pkg/logger/zaplog"
  13. "gitee.com/xuyiping_admin/pkg/tool"
  14. "gitee.com/xuyiping_admin/pkg/xerr"
  15. "go.uber.org/multierr"
  16. "go.uber.org/zap"
  17. )
  18. const (
  19. compareTime = 10 * 60
  20. )
  21. // PasturePrefAnalysisData PasturePrefExecTimeData PastureSprinkleFeedTime TODO 后期三个函数封装一下
  22. func (s *StoreEntry) PasturePrefAnalysisData(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (map[int64]*model.PastureAnalysisAccuracyData, error) {
  23. res := make(map[int64]*model.PastureAnalysisAccuracyData, 0)
  24. wg := sync.WaitGroup{}
  25. wg.Add(len(req.PastureIds))
  26. for _, pastureId := range req.PastureIds {
  27. go func(pId int32) {
  28. defer wg.Done()
  29. response := &model.PastureAnalysisAccuracyResponse{}
  30. groupPasture, err := s.GetGroupPastureListById(ctx, int64(pId))
  31. if err != nil {
  32. zaplog.Error("PasturePrefAnalysisData",
  33. zap.Any("GetGroupPastureListById", err),
  34. zap.Any("pId", pId))
  35. return
  36. }
  37. body := &model.DashboardAccuracyRequest{
  38. PastureId: int32(groupPasture.PastureId),
  39. FeedFormulaId: req.FeedFormulaId,
  40. CattleParentCategoryId: int32(req.CattleParentCategoryId),
  41. StartDate: req.StartDate,
  42. EndDate: req.EndDate,
  43. }
  44. if err = s.PastureHttpClient(ctx, model.DashboardAccuracyUrl, int64(pId), body, response); err != nil {
  45. zaplog.Error("PasturePrefAnalysisData",
  46. zap.String("url", model.DashboardAccuracyUrl),
  47. zap.Any("pasture", groupPasture), zap.Any("body", body),
  48. zap.Any("err", err), zap.Any("response", response))
  49. b, _ := json.Marshal(body)
  50. resB, _ := json.Marshal(response)
  51. pastureDataLog := model.NewPastureDataLog(groupPasture.Id, PastureDataLogType["FeedFormula_Distribute"], model.DashboardAccuracyUrl, string(b), string(resB))
  52. s.DB.Create(pastureDataLog)
  53. return
  54. }
  55. if response.Code != http.StatusOK {
  56. zaplog.Error("PasturePrefAnalysisData-response",
  57. zap.String("url", model.DashboardAccuracyUrl),
  58. zap.Any("pasture", groupPasture), zap.Any("body", body),
  59. zap.Any("response", response), zap.Any("response", response))
  60. return
  61. }
  62. res[groupPasture.Id] = response.Data
  63. }(pastureId)
  64. }
  65. wg.Wait()
  66. return res, nil
  67. }
  68. func (s *StoreEntry) PasturePrefExecTimeData(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (map[string]*model.ExecTimeData, error) {
  69. res := make(map[string]*model.ExecTimeData, 0)
  70. wg := sync.WaitGroup{}
  71. wg.Add(len(req.PastureIds))
  72. for _, pastureId := range req.PastureIds {
  73. go func(pId int32) {
  74. defer wg.Done()
  75. groupPasture, err := s.GetGroupPastureListById(ctx, int64(pId))
  76. if err != nil {
  77. return
  78. }
  79. response := &model.PastureExecTimeData{}
  80. body := &model.DashboardAccuracyRequest{
  81. PastureId: int32(groupPasture.PastureId),
  82. FeedFormulaId: req.FeedFormulaId,
  83. CattleParentCategoryId: int32(req.CattleParentCategoryId),
  84. StartDate: req.StartDate,
  85. EndDate: req.EndDate,
  86. }
  87. if err = s.PastureHttpClient(ctx, model.DashboardExecTimeUrl, int64(pId), body, response); err != nil {
  88. zaplog.Error("PasturePrefExecTimeData",
  89. zap.String("url", model.DashboardExecTimeUrl),
  90. zap.Any("pasture", groupPasture), zap.Any("body", body),
  91. zap.Any("err", err), zap.Any("response", response))
  92. b, _ := json.Marshal(body)
  93. resB, _ := json.Marshal(response)
  94. pastureDataLog := model.NewPastureDataLog(groupPasture.Id, PastureDataLogType["PasturePrefExecTimeData"], model.DashboardExecTimeUrl, string(b), string(resB))
  95. s.DB.Create(pastureDataLog)
  96. return
  97. }
  98. if response.Code != http.StatusOK {
  99. zaplog.Error("PasturePrefExecTimeData-response",
  100. zap.String("url", model.DashboardExecTimeUrl),
  101. zap.Any("pasture", groupPasture), zap.Any("body", body),
  102. zap.Any("err", err), zap.Any("response", response))
  103. return
  104. }
  105. res[groupPasture.Name] = response.Data
  106. }(pastureId)
  107. }
  108. wg.Wait()
  109. return res, nil
  110. }
  111. func (s *StoreEntry) PastureSprinkleFeedTime(ctx context.Context, req *operationPb.SprinkleFeedTimeRequest) (map[int64][]*model.SprinkleStatisticsDataList, map[int64]*model.GroupPasture, error) {
  112. res, pastureList := make(map[int64][]*model.SprinkleStatisticsDataList), make(map[int64]*model.GroupPasture, 0)
  113. wg := sync.WaitGroup{}
  114. wg.Add(len(req.PastureIds))
  115. var muError error
  116. for _, pasture := range req.PastureIds {
  117. go func(pId int32) {
  118. defer wg.Done()
  119. groupPasture, err := s.GetGroupPastureListById(ctx, int64(pId))
  120. if err != nil {
  121. zaplog.Error("PastureSprinkleFeedTime", zap.Any("GetGroupPastureListById", err))
  122. return
  123. }
  124. response := &model.PastureSprinkleStatisticsDataList{}
  125. body := &model.DashboardAccuracyRequest{
  126. PastureId: int32(groupPasture.PastureId),
  127. FeedFormulaId: req.FeedFormulaId,
  128. StartDate: req.StartDate,
  129. EndDate: req.EndDate,
  130. }
  131. if err = s.PastureHttpClient(ctx, model.DashboardSprinkleFeedTimeUrl, int64(pId), body, response); err != nil {
  132. muError = multierr.Append(muError, err)
  133. zaplog.Error("PastureSprinkleFeedTime",
  134. zap.String("url", model.DashboardSprinkleFeedTimeUrl),
  135. zap.Any("pasture", groupPasture), zap.Any("body", body),
  136. zap.Any("err", err), zap.Any("response", response))
  137. b, _ := json.Marshal(body)
  138. resB, _ := json.Marshal(response)
  139. pastureDataLog := model.NewPastureDataLog(groupPasture.Id, PastureDataLogType["PasturePrefExecTimeData"], model.DashboardSprinkleFeedTimeUrl, string(b), string(resB))
  140. s.DB.Create(pastureDataLog)
  141. }
  142. if response.Code != http.StatusOK {
  143. muError = multierr.Append(muError, xerr.Custom(response.Msg))
  144. }
  145. res[groupPasture.Id] = response.Data
  146. pastureList[groupPasture.Id] = groupPasture
  147. }(pasture)
  148. }
  149. wg.Wait()
  150. return res, pastureList, nil
  151. }
  152. // SearchAnalysisAccuracy 准确性分析
  153. func (s *StoreEntry) SearchAnalysisAccuracy(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (*model.SearchAnalysisAccuracyResponse1, error) {
  154. res := &model.SearchAnalysisAccuracyResponse1{
  155. Code: http.StatusOK,
  156. Msg: "ok",
  157. Data: &model.AnalysisAccuracyData1{
  158. Table: &model.Table{
  159. TitleList: make([]*model.TableList, 0),
  160. DataList: &model.DataList{},
  161. },
  162. Chart: nil,
  163. },
  164. }
  165. res.Data.Table.TitleList = append(res.Data.Table.TitleList, &model.TableList{
  166. Name: "title",
  167. Value: "牧场",
  168. })
  169. dashboardTopData, pastureAnalysisAccuracy, err := s.DashboardTopPasture(ctx, req)
  170. if err != nil {
  171. return nil, xerr.WithStack(err)
  172. }
  173. res.Data.Table = s.TitleList(ctx, pastureAnalysisAccuracy)
  174. dashboardTopData1 := &model.Chart1{
  175. MixedFodderAccurateRatio: &model.PastureTopData1{
  176. Title: make([]string, 0),
  177. Ratio: make([]float64, 0),
  178. },
  179. MixedFodderCorrectRatio: &model.PastureTopData1{
  180. Title: make([]string, 0),
  181. Ratio: make([]float64, 0),
  182. },
  183. SprinkleFodderAccurateRatio: &model.PastureTopData1{
  184. Title: make([]string, 0),
  185. Ratio: make([]float64, 0),
  186. },
  187. SprinkleFodderCorrectRatio: &model.PastureTopData1{
  188. Title: make([]string, 0),
  189. Ratio: make([]float64, 0),
  190. },
  191. }
  192. pastureDayTimeRatioList := make(map[operationPb.DashboardTopType_Kind][]*model.PastureDayTimeRatio)
  193. for _, v := range dashboardTopData.MixedFodderCorrectRatio {
  194. pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_ACCURATE] =
  195. append(pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_ACCURATE],
  196. &model.PastureDayTimeRatio{
  197. PastureId: v.PastureId,
  198. PastureName: v.PastureName,
  199. Ratio: v.Ratio,
  200. })
  201. dashboardTopData1.MixedFodderCorrectRatio.Title = append(dashboardTopData1.MixedFodderCorrectRatio.Title, v.PastureName)
  202. dashboardTopData1.MixedFodderCorrectRatio.Ratio = append(dashboardTopData1.MixedFodderCorrectRatio.Ratio, v.Ratio)
  203. }
  204. for _, v := range dashboardTopData.MixedFodderAccurateRatio {
  205. pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_CORRECT] =
  206. append(pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_CORRECT],
  207. &model.PastureDayTimeRatio{
  208. PastureId: v.PastureId,
  209. PastureName: v.PastureName,
  210. Ratio: v.Ratio,
  211. })
  212. dashboardTopData1.MixedFodderAccurateRatio.Title = append(dashboardTopData1.MixedFodderAccurateRatio.Title, v.PastureName)
  213. dashboardTopData1.MixedFodderAccurateRatio.Ratio = append(dashboardTopData1.MixedFodderAccurateRatio.Ratio, v.Ratio)
  214. }
  215. for _, v := range dashboardTopData.SprinkleFodderAccurateRatio {
  216. pastureDayTimeRatioList[operationPb.DashboardTopType_SPRINKLE_ACCURATE] =
  217. append(pastureDayTimeRatioList[operationPb.DashboardTopType_SPRINKLE_ACCURATE],
  218. &model.PastureDayTimeRatio{
  219. PastureId: v.PastureId,
  220. PastureName: v.PastureName,
  221. Ratio: v.Ratio,
  222. })
  223. dashboardTopData1.SprinkleFodderAccurateRatio.Title = append(dashboardTopData1.SprinkleFodderAccurateRatio.Title, v.PastureName)
  224. dashboardTopData1.SprinkleFodderAccurateRatio.Ratio = append(dashboardTopData1.SprinkleFodderAccurateRatio.Ratio, v.Ratio)
  225. }
  226. for _, v := range dashboardTopData.SprinkleFodderCorrectRatio {
  227. pastureDayTimeRatioList[operationPb.DashboardTopType_Sprinkle_CORRECT] =
  228. append(pastureDayTimeRatioList[operationPb.DashboardTopType_Sprinkle_CORRECT],
  229. &model.PastureDayTimeRatio{
  230. PastureId: v.PastureId,
  231. PastureName: v.PastureName,
  232. Ratio: v.Ratio,
  233. })
  234. dashboardTopData1.SprinkleFodderCorrectRatio.Title = append(dashboardTopData1.SprinkleFodderCorrectRatio.Title, v.PastureName)
  235. dashboardTopData1.SprinkleFodderCorrectRatio.Ratio = append(dashboardTopData1.SprinkleFodderCorrectRatio.Ratio, v.Ratio)
  236. }
  237. // 排序 最大值。最小值。中位数
  238. sort.Slice(pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_ACCURATE], func(i, j int) bool {
  239. return pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_ACCURATE][i].Ratio < pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_ACCURATE][j].Ratio
  240. })
  241. sort.Slice(pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_CORRECT], func(i, j int) bool {
  242. return pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_CORRECT][i].Ratio < pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_CORRECT][j].Ratio
  243. })
  244. sort.Slice(pastureDayTimeRatioList[operationPb.DashboardTopType_SPRINKLE_ACCURATE], func(i, j int) bool {
  245. return pastureDayTimeRatioList[operationPb.DashboardTopType_SPRINKLE_ACCURATE][i].Ratio < pastureDayTimeRatioList[operationPb.DashboardTopType_SPRINKLE_ACCURATE][j].Ratio
  246. })
  247. sort.Slice(pastureDayTimeRatioList[operationPb.DashboardTopType_Sprinkle_CORRECT], func(i, j int) bool {
  248. return pastureDayTimeRatioList[operationPb.DashboardTopType_Sprinkle_CORRECT][i].Ratio < pastureDayTimeRatioList[operationPb.DashboardTopType_Sprinkle_CORRECT][j].Ratio
  249. })
  250. // 混料准确率
  251. dashboardTopData1.MixedFodderAccurateRatio.MaxValue = fmt.Sprintf("%.2f", pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_ACCURATE][len(pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_ACCURATE])-1].Ratio)
  252. dashboardTopData1.MixedFodderAccurateRatio.MinValue = fmt.Sprintf("%.2f", pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_ACCURATE][0].Ratio)
  253. dashboardTopData1.MixedFodderAccurateRatio.MiddleValue = fmt.Sprintf("%.2f", getPastureDayTimeRatioMiddleValue(pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_ACCURATE]))
  254. dashboardTopData1.MixedFodderAccurateRatio.TopOneName = pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_ACCURATE][len(pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_ACCURATE])-1].PastureName
  255. // 混料正确率
  256. dashboardTopData1.MixedFodderCorrectRatio.MaxValue = fmt.Sprintf("%.2f", pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_CORRECT][len(pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_CORRECT])-1].Ratio)
  257. dashboardTopData1.MixedFodderCorrectRatio.MinValue = fmt.Sprintf("%.2f", pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_CORRECT][0].Ratio)
  258. dashboardTopData1.MixedFodderCorrectRatio.MiddleValue = fmt.Sprintf("%.2f", getPastureDayTimeRatioMiddleValue(pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_CORRECT]))
  259. dashboardTopData1.MixedFodderCorrectRatio.TopOneName = pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_CORRECT][len(pastureDayTimeRatioList[operationPb.DashboardTopType_MIXED_CORRECT])-1].PastureName
  260. // 散料准确率
  261. dashboardTopData1.SprinkleFodderAccurateRatio.MaxValue = fmt.Sprintf("%.2f", pastureDayTimeRatioList[operationPb.DashboardTopType_SPRINKLE_ACCURATE][len(pastureDayTimeRatioList[operationPb.DashboardTopType_SPRINKLE_ACCURATE])-1].Ratio)
  262. dashboardTopData1.SprinkleFodderAccurateRatio.MinValue = fmt.Sprintf("%.2f", pastureDayTimeRatioList[operationPb.DashboardTopType_SPRINKLE_ACCURATE][0].Ratio)
  263. dashboardTopData1.SprinkleFodderAccurateRatio.MiddleValue = fmt.Sprintf("%.2f", getPastureDayTimeRatioMiddleValue(pastureDayTimeRatioList[operationPb.DashboardTopType_SPRINKLE_ACCURATE]))
  264. dashboardTopData1.SprinkleFodderAccurateRatio.TopOneName = pastureDayTimeRatioList[operationPb.DashboardTopType_SPRINKLE_ACCURATE][len(pastureDayTimeRatioList[operationPb.DashboardTopType_SPRINKLE_ACCURATE])-1].PastureName
  265. // 散料正确率
  266. dashboardTopData1.SprinkleFodderCorrectRatio.MaxValue = fmt.Sprintf("%.2f", pastureDayTimeRatioList[operationPb.DashboardTopType_Sprinkle_CORRECT][len(pastureDayTimeRatioList[operationPb.DashboardTopType_Sprinkle_CORRECT])-1].Ratio)
  267. dashboardTopData1.SprinkleFodderCorrectRatio.MinValue = fmt.Sprintf("%.2f", pastureDayTimeRatioList[operationPb.DashboardTopType_Sprinkle_CORRECT][0].Ratio)
  268. dashboardTopData1.SprinkleFodderCorrectRatio.MiddleValue = fmt.Sprintf("%.2f", getPastureDayTimeRatioMiddleValue(pastureDayTimeRatioList[operationPb.DashboardTopType_Sprinkle_CORRECT]))
  269. dashboardTopData1.SprinkleFodderCorrectRatio.TopOneName = pastureDayTimeRatioList[operationPb.DashboardTopType_Sprinkle_CORRECT][len(pastureDayTimeRatioList[operationPb.DashboardTopType_Sprinkle_CORRECT])-1].PastureName
  270. res.Data.Chart = dashboardTopData1
  271. return res, nil
  272. }
  273. // TopPasture 牧场排名
  274. func (s *StoreEntry) TopPasture(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (*model.GetPastureTopResponse, error) {
  275. res := &model.GetPastureTopResponse{
  276. Code: http.StatusOK,
  277. Msg: "ok",
  278. Data: nil,
  279. }
  280. dashboardTopData, _, err := s.DashboardTopPasture(ctx, req)
  281. if err != nil {
  282. return nil, xerr.WithStack(err)
  283. }
  284. res.Data = dashboardTopData
  285. return res, nil
  286. }
  287. func (s *StoreEntry) DashboardTopPasture(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (*model.PastureTop, map[int64]*model.PastureAnalysisAccuracyData, error) {
  288. dashboardTopData := &model.PastureTop{
  289. MixedFodderAccurateRatio: make([]*model.PastureTopData, 0),
  290. MixedFodderCorrectRatio: make([]*model.PastureTopData, 0),
  291. SprinkleFodderAccurateRatio: make([]*model.PastureTopData, 0),
  292. SprinkleFodderCorrectRatio: make([]*model.PastureTopData, 0),
  293. }
  294. analysisAccuracy, err := s.PasturePrefAnalysisData(ctx, req)
  295. if err != nil {
  296. return nil, nil, xerr.WithStack(err)
  297. }
  298. for pastureId, data := range analysisAccuracy {
  299. groupPasture, err := s.GetGroupPastureListById(ctx, pastureId)
  300. if err != nil {
  301. zaplog.Error("TopPasture", zap.Any("GetGroupPastureListById", pastureId), zap.Any("err", err))
  302. continue
  303. }
  304. if data == nil {
  305. continue
  306. }
  307. allMaRatio, allMcRatio, allSaRatio, allScRatio := 0.0, 0.0, 0.0, 0.0
  308. for _, v := range data.MixedFodderAccurateRatio {
  309. allMaRatio += v.Ratio
  310. }
  311. dashboardTopData.MixedFodderAccurateRatio = append(dashboardTopData.MixedFodderAccurateRatio, &model.PastureTopData{
  312. PastureId: pastureId,
  313. PastureName: groupPasture.Name,
  314. Ratio: tool.Decimal(allMaRatio / float64(len(data.MixedFodderAccurateRatio))),
  315. })
  316. for _, v := range data.MixedFodderCorrectRatio {
  317. allMcRatio += v.Ratio
  318. }
  319. dashboardTopData.MixedFodderCorrectRatio = append(dashboardTopData.MixedFodderCorrectRatio, &model.PastureTopData{
  320. PastureId: pastureId,
  321. PastureName: groupPasture.Name,
  322. Ratio: tool.Decimal(allMcRatio / float64(len(data.MixedFodderCorrectRatio))),
  323. })
  324. for _, v := range data.SprinkleFodderAccurateRatio {
  325. allSaRatio += v.Ratio
  326. }
  327. dashboardTopData.SprinkleFodderAccurateRatio = append(dashboardTopData.SprinkleFodderAccurateRatio, &model.PastureTopData{
  328. PastureId: pastureId,
  329. PastureName: groupPasture.Name,
  330. Ratio: tool.Decimal(allSaRatio / float64(len(data.SprinkleFodderAccurateRatio))),
  331. })
  332. for _, v := range data.SprinkleFodderCorrectRatio {
  333. allScRatio += v.Ratio
  334. }
  335. dashboardTopData.SprinkleFodderCorrectRatio = append(dashboardTopData.SprinkleFodderCorrectRatio, &model.PastureTopData{
  336. PastureId: pastureId,
  337. PastureName: groupPasture.Name,
  338. Ratio: tool.Decimal(allScRatio / float64(len(data.SprinkleFodderCorrectRatio))),
  339. })
  340. }
  341. sort.Slice(dashboardTopData.MixedFodderAccurateRatio, func(i, j int) bool {
  342. return dashboardTopData.MixedFodderAccurateRatio[i].Ratio > dashboardTopData.MixedFodderAccurateRatio[j].Ratio
  343. })
  344. sort.Slice(dashboardTopData.MixedFodderCorrectRatio, func(i, j int) bool {
  345. return dashboardTopData.MixedFodderCorrectRatio[i].Ratio > dashboardTopData.MixedFodderCorrectRatio[j].Ratio
  346. })
  347. sort.Slice(dashboardTopData.SprinkleFodderAccurateRatio, func(i, j int) bool {
  348. return dashboardTopData.SprinkleFodderAccurateRatio[i].Ratio > dashboardTopData.SprinkleFodderAccurateRatio[j].Ratio
  349. })
  350. sort.Slice(dashboardTopData.SprinkleFodderCorrectRatio, func(i, j int) bool {
  351. return dashboardTopData.SprinkleFodderCorrectRatio[i].Ratio > dashboardTopData.SprinkleFodderCorrectRatio[j].Ratio
  352. })
  353. if req.DashboardTopType > 0 {
  354. switch req.DashboardTopType {
  355. case operationPb.DashboardTopType_MIXED_ACCURATE:
  356. dashboardTopData.MixedFodderAccurateRatio = dashboardTopRand(req, dashboardTopData.MixedFodderAccurateRatio)
  357. case operationPb.DashboardTopType_MIXED_CORRECT:
  358. dashboardTopData.MixedFodderCorrectRatio = dashboardTopRand(req, dashboardTopData.MixedFodderCorrectRatio)
  359. case operationPb.DashboardTopType_SPRINKLE_ACCURATE:
  360. dashboardTopData.SprinkleFodderAccurateRatio = dashboardTopRand(req, dashboardTopData.SprinkleFodderAccurateRatio)
  361. case operationPb.DashboardTopType_Sprinkle_CORRECT:
  362. dashboardTopData.SprinkleFodderCorrectRatio = dashboardTopRand(req, dashboardTopData.SprinkleFodderCorrectRatio)
  363. }
  364. }
  365. return dashboardTopData, analysisAccuracy, nil
  366. }
  367. func (s *StoreEntry) TitleList(ctx context.Context, pastureAnalysisList map[int64]*model.PastureAnalysisAccuracyData) *model.Table {
  368. res := &model.Table{
  369. TitleList: make([]*model.TableList, 0),
  370. DataList: &model.DataList{
  371. MixedFodderAccurateRatio: make([]map[string]string, 0),
  372. MixedFodderCorrectRatio: make([]map[string]string, 0),
  373. SprinkleFodderAccurateRatio: make([]map[string]string, 0),
  374. SprinkleFodderCorrectRatio: make([]map[string]string, 0),
  375. },
  376. }
  377. for pastureId, data := range pastureAnalysisList {
  378. groupPasture, err := s.GetGroupPastureListById(ctx, pastureId)
  379. if err != nil {
  380. zaplog.Info("TitleList", zap.Any("GetGroupPastureListById", pastureId), zap.Any("err", err))
  381. continue
  382. }
  383. if len(res.TitleList) <= len(data.MixedFodderAccurateRatio) {
  384. res.TitleList = append(res.TitleList, &model.TableList{
  385. Name: "title",
  386. Value: "牧场",
  387. })
  388. }
  389. maMap := map[string]string{
  390. "title": groupPasture.Name,
  391. }
  392. for i, v := range data.MixedFodderCorrectRatio {
  393. maMap[fmt.Sprintf("data%d", i+1)] = fmt.Sprintf("%.2f", v.Ratio)
  394. if len(res.TitleList) <= len(data.MixedFodderAccurateRatio) {
  395. res.TitleList = append(res.TitleList, &model.TableList{
  396. Name: fmt.Sprintf("data%d", i+1),
  397. Value: v.DayTime,
  398. })
  399. }
  400. }
  401. res.DataList.MixedFodderAccurateRatio = append(res.DataList.MixedFodderAccurateRatio, maMap)
  402. mcMap := map[string]string{
  403. "title": groupPasture.Name,
  404. }
  405. for i, v := range data.MixedFodderCorrectRatio {
  406. mcMap[fmt.Sprintf("data%d", i+1)] = fmt.Sprintf("%.2f", v.Ratio)
  407. }
  408. res.DataList.MixedFodderCorrectRatio = append(res.DataList.MixedFodderCorrectRatio, mcMap)
  409. saMap := map[string]string{
  410. "title": groupPasture.Name,
  411. }
  412. for i, v := range data.SprinkleFodderAccurateRatio {
  413. saMap[fmt.Sprintf("data%d", i+1)] = fmt.Sprintf("%.2f", v.Ratio)
  414. }
  415. res.DataList.SprinkleFodderAccurateRatio = append(res.DataList.SprinkleFodderAccurateRatio, saMap)
  416. scMap := map[string]string{
  417. "title": groupPasture.Name,
  418. }
  419. for i, v := range data.SprinkleFodderCorrectRatio {
  420. scMap[fmt.Sprintf("data%d", i+1)] = fmt.Sprintf("%.2f", v.Ratio)
  421. }
  422. res.DataList.SprinkleFodderCorrectRatio = append(res.DataList.SprinkleFodderCorrectRatio, scMap)
  423. }
  424. return res
  425. }
  426. func (s *StoreEntry) ExecutionTime(ctx context.Context, req *operationPb.SearchAnalysisAccuracyRequest) (*model.ExecTimeResponse, error) {
  427. res := &model.ExecTimeResponse{
  428. Code: http.StatusOK,
  429. Msg: "ok",
  430. Data: &model.ExecTimeDataList{
  431. Chart: &model.ExecTimeDataListChart{
  432. Title: make([]string, 0),
  433. AddFeedTime: make([][]string, 0),
  434. SprinkleTime: make([][]string, 0),
  435. StirTime: make([][]string, 0),
  436. },
  437. TableList: make([]map[string]string, 0),
  438. },
  439. }
  440. pastureExecTime, err := s.PasturePrefExecTimeData(ctx, req)
  441. if err != nil {
  442. return nil, xerr.WithStack(err)
  443. }
  444. for pastureName, execTime := range pastureExecTime {
  445. res.Data.Chart.Title = append(res.Data.Chart.Title, pastureName)
  446. addFeedTimeStr, sprinkleTimeStr, stirTimeStr := make([]string, 0), make([]string, 0), make([]string, 0)
  447. if execTime != nil {
  448. addFeedTimeStr = append(addFeedTimeStr, execTime.AddFeedTime.MaxValue, execTime.AddFeedTime.UpMiddleValue,
  449. execTime.AddFeedTime.MiddleValue, execTime.AddFeedTime.DownMiddleValue, execTime.AddFeedTime.MinValue)
  450. sprinkleTimeStr = append(sprinkleTimeStr, execTime.SprinkleTime.MaxValue, execTime.SprinkleTime.UpMiddleValue,
  451. execTime.SprinkleTime.MiddleValue, execTime.SprinkleTime.DownMiddleValue, execTime.SprinkleTime.MinValue)
  452. stirTimeStr = append(stirTimeStr, execTime.StirTime.MaxValue, execTime.StirTime.UpMiddleValue,
  453. execTime.StirTime.MiddleValue, execTime.StirTime.DownMiddleValue, execTime.StirTime.MinValue)
  454. }
  455. res.Data.Chart.AddFeedTime = append(res.Data.Chart.AddFeedTime, addFeedTimeStr)
  456. res.Data.Chart.SprinkleTime = append(res.Data.Chart.SprinkleTime, sprinkleTimeStr)
  457. res.Data.Chart.StirTime = append(res.Data.Chart.StirTime, stirTimeStr)
  458. if execTime == nil {
  459. continue
  460. }
  461. tableList := map[string]string{
  462. "title": pastureName,
  463. "add_feed_time": "加料时间",
  464. "add_feed_time_max_value": execTime.AddFeedTime.MaxValue,
  465. "add_feed_time_up_middle_value": execTime.AddFeedTime.UpMiddleValue,
  466. "add_feed_time_middle_value": execTime.AddFeedTime.MiddleValue,
  467. "add_feed_time_down_middle_value": execTime.AddFeedTime.DownMiddleValue,
  468. "add_feed_time_min_value": execTime.AddFeedTime.MinValue,
  469. "sprinkle_time": "撒料时间",
  470. "sprinkle_time_max_value": execTime.SprinkleTime.MaxValue,
  471. "sprinkle_time_up_middle_value": execTime.SprinkleTime.UpMiddleValue,
  472. "sprinkle_time_middle_value": execTime.SprinkleTime.MiddleValue,
  473. "sprinkle_time_down_middle_value": execTime.SprinkleTime.DownMiddleValue,
  474. "sprinkle_time_min_value": execTime.SprinkleTime.MinValue,
  475. "stir_time": "搅拌延迟时间",
  476. "stir_time_max_value": execTime.StirTime.MaxValue,
  477. "stir_time_up_middle_value": execTime.StirTime.UpMiddleValue,
  478. "stir_time_middle_value": execTime.StirTime.MiddleValue,
  479. "stir_time_down_middle_value": execTime.StirTime.DownMiddleValue,
  480. "stir_time_min_value": execTime.StirTime.MinValue,
  481. }
  482. res.Data.TableList = append(res.Data.TableList, tableList)
  483. }
  484. return res, nil
  485. }
  486. func (s *StoreEntry) SprinkleFeedTime(ctx context.Context, req *operationPb.SprinkleFeedTimeRequest) (*model.SprinkleFeedTimeResponse, error) {
  487. res := &model.SprinkleFeedTimeResponse{
  488. Code: http.StatusOK,
  489. Msg: "ok",
  490. Data: &model.SprinkleFeedTimeData{
  491. Chart: &model.SprinkleFeedTimeChart{
  492. Title: make([]string, 0),
  493. SprinkleNumberList: make([][]int32, 0),
  494. },
  495. TableList: make([]*model.SprinkleFeedTimeTable, 0),
  496. },
  497. }
  498. pastureSprinkleDataList, pastureList, err := s.PastureSprinkleFeedTime(ctx, req)
  499. if err != nil {
  500. return nil, xerr.WithStack(err)
  501. }
  502. tableList := make([]*model.SprinkleFeedTimeTable, 0)
  503. infoSprinkleNumber, errorSprinkleNumber, pastureIds := make([]int32, 0), make([]int32, 0), make([]int, 0)
  504. for pastureId, _ := range pastureSprinkleDataList {
  505. pastureIds = append(pastureIds, int(pastureId))
  506. }
  507. sort.Ints(pastureIds)
  508. pastureInfo := &model.GroupPasture{}
  509. for _, pastureId := range pastureIds {
  510. if pastureData, ok := pastureList[int64(pastureId)]; ok {
  511. pastureInfo = pastureData
  512. }
  513. if data, ok := pastureSprinkleDataList[int64(pastureId)]; ok {
  514. sprinkleFeedTimeList := make(map[int32]map[int32][]int64, 0)
  515. for _, v := range data {
  516. tableList = append(tableList, &model.SprinkleFeedTimeTable{
  517. PastureName: pastureInfo.Name,
  518. BarnName: v.FName,
  519. ClassNumber: fmt.Sprintf("%d", v.Times),
  520. RealitySprinkleFeedTime: tool.TimeSub(v.InTime, v.ProcessTime),
  521. })
  522. realityTime := tool.TimeSub(v.InTime, v.ProcessTime)
  523. realityTimeUnix, _ := time.Parse(model.LayoutTime, realityTime)
  524. if sprinkleFeedTimeList[v.FBarId] == nil {
  525. sprinkleFeedTimeList[v.FBarId] = make(map[int32][]int64, 0)
  526. }
  527. sprinkleFeedTimeList[v.FBarId][v.Times] = append(sprinkleFeedTimeList[v.FBarId][v.Times], realityTimeUnix.Unix())
  528. }
  529. res.Data.Chart.Title = append(res.Data.Chart.Title, pastureInfo.Name)
  530. infoNumber, errNumber := sprinkleExecTimeAnalysis(sprinkleFeedTimeList)
  531. infoSprinkleNumber = append(infoSprinkleNumber, infoNumber)
  532. errorSprinkleNumber = append(errorSprinkleNumber, errNumber)
  533. }
  534. }
  535. res.Data.Chart.SprinkleNumberList = append(res.Data.Chart.SprinkleNumberList, infoSprinkleNumber, errorSprinkleNumber)
  536. res.Data.TableList = tableList
  537. return res, nil
  538. }
  539. func (s *StoreEntry) FeedMixedAndTmrName(ctx context.Context, req *operationPb.MixedCategoryTmrName) (*model.PastureCommonResponse, error) {
  540. groupPasture, err := s.GetGroupPastureListById(ctx, int64(req.PastureId))
  541. if err != nil {
  542. return nil, xerr.WithStack(err)
  543. }
  544. pastureId := req.PastureId
  545. if groupPasture.PastureId > 0 {
  546. pastureId = int32(groupPasture.PastureId)
  547. }
  548. body := &model.PastureCommonRequest{
  549. Name: req.ApiName,
  550. ReturnType: "Map",
  551. ParamMaps: &model.MixedCategoryTmrNameParams{
  552. PastureId: fmt.Sprintf("%d", pastureId),
  553. StartTime: req.StartTime,
  554. EndTime: req.EndTime,
  555. },
  556. }
  557. response := &model.PastureCommonResponse{Data: &model.PastureCommonData{}}
  558. if err = s.PastureHttpClient(ctx, model.UrlDataByName, int64(req.PastureId), body, response); err != nil {
  559. return nil, xerr.WithStack(err)
  560. }
  561. return response, nil
  562. }
  563. func (s *StoreEntry) FeedTemplateHistory(ctx context.Context, req *operationPb.FeedTemplateHistoryRequest) (*model.PastureFeedTemplateHistoryResponse, error) {
  564. groupPasture, err := s.GetGroupPastureListById(ctx, int64(req.PastureId))
  565. if err != nil {
  566. return nil, xerr.WithStack(err)
  567. }
  568. pastureId := req.PastureId
  569. if groupPasture.PastureId > 0 {
  570. pastureId = int32(groupPasture.PastureId)
  571. }
  572. body := &model.PastureFeedTemplateHistoryRequest{
  573. PastureId: fmt.Sprintf("%d", pastureId),
  574. FTid: int64(req.Ftid),
  575. StartDate: req.StartTime,
  576. EndDate: req.EndTime,
  577. }
  578. response := &model.PastureFeedTemplateHistoryResponse{}
  579. if err = s.PastureHttpClient(ctx, model.UrlFeedTemplateHistory, int64(req.PastureId), body, response); err != nil {
  580. return nil, xerr.WithStack(err)
  581. }
  582. return response, nil
  583. }
  584. func (s *StoreEntry) BarnHistory(ctx context.Context, req *operationPb.BarnHistoryRequest) (*model.PastureBarnHistoryResponse, error) {
  585. _, err := s.GetGroupPastureListById(ctx, int64(req.PastureId))
  586. if err != nil {
  587. return nil, xerr.WithStack(err)
  588. }
  589. body := &model.PastureBarnHistoryRequest{
  590. BarName: req.BarnName,
  591. StartDate: req.StartTime,
  592. EndDate: req.EndTime,
  593. }
  594. response := &model.PastureBarnHistoryResponse{}
  595. if err = s.PastureHttpClient(ctx, model.UrlBarnHistory, int64(req.PastureId), body, response); err != nil {
  596. return nil, xerr.WithStack(err)
  597. }
  598. return response, nil
  599. }
  600. func (s *StoreEntry) SpillageAllHistory(ctx context.Context, req *operationPb.BarnHistoryRequest) (*model.PastureBarnHistoryResponse, error) {
  601. groupPasture, err := s.GetGroupPastureListById(ctx, int64(req.PastureId))
  602. if err != nil {
  603. return nil, xerr.WithStack(err)
  604. }
  605. pastureId := req.PastureId
  606. if groupPasture.PastureId > 0 {
  607. pastureId = int32(groupPasture.PastureId)
  608. }
  609. body := &model.PastureBarnHistoryRequest{
  610. PastureId: fmt.Sprintf("%d", pastureId),
  611. BarName: req.BarnName,
  612. StartDate: req.StartTime,
  613. EndDate: req.EndTime,
  614. }
  615. response := &model.PastureBarnHistoryResponse{}
  616. if err = s.PastureHttpClient(ctx, model.UrlSpillageAllHistory, int64(req.PastureId), body, response); err != nil {
  617. return nil, xerr.WithStack(err)
  618. }
  619. return response, nil
  620. }
  621. func sprinkleExecTimeAnalysis(sprinkleFeedTimeList map[int32]map[int32][]int64) (int32, int32) {
  622. var infoSprinkleNumber, errorSprinkleNumber int32 = 0, 0
  623. if len(sprinkleFeedTimeList) <= 0 {
  624. return infoSprinkleNumber, errorSprinkleNumber
  625. } else {
  626. for _, value := range sprinkleFeedTimeList {
  627. for _, execTimeList := range value {
  628. middleValue := tool.MedianInt64(execTimeList)
  629. for _, v := range execTimeList {
  630. if v >= middleValue-int64(compareTime) && v <= middleValue+int64(compareTime) {
  631. infoSprinkleNumber += 1
  632. } else {
  633. errorSprinkleNumber += 1
  634. }
  635. }
  636. }
  637. }
  638. }
  639. return infoSprinkleNumber, errorSprinkleNumber
  640. }
  641. func dashboardTopRand(req *operationPb.SearchAnalysisAccuracyRequest, data []*model.PastureTopData) []*model.PastureTopData {
  642. if req.TopRandStart < 0 || req.TopRandEnd < 0 || req.TopRandStart > req.TopRandEnd {
  643. return data
  644. }
  645. res := make([]*model.PastureTopData, 0)
  646. for _, v := range data {
  647. if v.Ratio >= float64(req.TopRandStart) && v.Ratio <= float64(req.TopRandEnd) {
  648. res = append(res, v)
  649. }
  650. }
  651. return res
  652. }
  653. func getPastureDayTimeRatioMiddleValue(pastureDayTimeRatio []*model.PastureDayTimeRatio) float64 {
  654. if len(pastureDayTimeRatio) <= 0 {
  655. return 0
  656. }
  657. ratioList := make([]float64, 0)
  658. for _, v := range pastureDayTimeRatio {
  659. ratioList = append(ratioList, v.Ratio)
  660. }
  661. sort.Float64s(ratioList)
  662. return tool.Median(ratioList)
  663. }