dashboard.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. package backend
  2. import (
  3. "context"
  4. "kpt-pasture/model"
  5. "kpt-pasture/util"
  6. "net/http"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "gorm.io/gorm"
  11. "gitee.com/xuyiping_admin/pkg/logger/zaplog"
  12. "gitee.com/xuyiping_admin/pkg/xerr"
  13. "go.uber.org/zap"
  14. pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
  15. )
  16. func (s *StoreEntry) NeckRingWarning(ctx context.Context) (*pasturePb.IndexNeckRingResponse, error) {
  17. userModel, err := s.GetUserModel(ctx)
  18. if err != nil {
  19. return nil, xerr.WithStack(err)
  20. }
  21. var count int64
  22. neckRingEstrusList := make([]*model.NeckRingEstrusWarning, 0)
  23. estrusWarningLevelItems := map[int32]int32{
  24. int32(pasturePb.EstrusLevel_Low): 0,
  25. int32(pasturePb.EstrusLevel_Middle): 0,
  26. int32(pasturePb.EstrusLevel_High): 0,
  27. }
  28. pref, err := s.EstrusWarningQuery(ctx, userModel.AppPasture.Id)
  29. if err != nil {
  30. return nil, xerr.Customf("系统错误!")
  31. }
  32. if err = pref.Order("a.level DESC").
  33. Count(&count).
  34. Find(&neckRingEstrusList).Error; err != nil {
  35. return nil, xerr.WithStack(err)
  36. }
  37. countEstrusWarning := 0
  38. nowTime := time.Now().Local()
  39. optimumMating := map[string]int32{
  40. "front": 0,
  41. "middle": 0,
  42. "behind": 0,
  43. }
  44. for _, v := range neckRingEstrusList {
  45. estrusWarningLevelItems[int32(v.Level)] += 1
  46. countEstrusWarning += 1
  47. cowInfo, _ := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, v.EarNumber)
  48. pzHour := v.CalculatePzHour(cowInfo.Lact)
  49. optimumMatingStartTime := pzHour.Add(-4 * time.Hour)
  50. optimumMatingEndTime := pzHour.Add(4 * time.Hour)
  51. // 判断当前时间是否在 pzHour-4h 到 pzHour+4h 之间
  52. if nowTime.After(optimumMatingStartTime) && nowTime.Before(optimumMatingEndTime) {
  53. optimumMating["middle"] += 1
  54. }
  55. if nowTime.After(optimumMatingEndTime) {
  56. optimumMating["behind"] += 1
  57. }
  58. if nowTime.Before(optimumMatingStartTime) {
  59. optimumMating["front"] += 1
  60. }
  61. }
  62. abortionCount := int64(0)
  63. pref, err = s.AbortionWarningQuery(ctx, userModel.AppPasture.Id)
  64. if err != nil {
  65. return nil, xerr.Customf("系统错误!")
  66. }
  67. if err = pref.Group("cow_id").Count(&abortionCount).Error; err != nil {
  68. return nil, xerr.WithStack(err)
  69. }
  70. healthWarningNumber := int64(0)
  71. if err = s.DB.Model(new(model.NeckRingHealth)).
  72. Where("pasture_id = ?", userModel.AppPasture.Id).
  73. Group("cow_id").
  74. Count(&healthWarningNumber).Error; err != nil {
  75. zaplog.Error("NeckRingWarning", zap.Any("estrusWarningNumber", err))
  76. }
  77. return &pasturePb.IndexNeckRingResponse{
  78. Code: http.StatusOK,
  79. Msg: "ok",
  80. Data: &pasturePb.NeckRingData{
  81. EstrusWarningNumber: int32(countEstrusWarning),
  82. HealthWarningNumber: int32(healthWarningNumber),
  83. AbortionWarningNumber: int32(abortionCount),
  84. StressWarningNumber: 0,
  85. EstrusWarningLevelItems: estrusWarningLevelItems,
  86. OptimumMating: optimumMating,
  87. },
  88. }, nil
  89. }
  90. func (s *StoreEntry) FocusIndicatorsList(ctx context.Context, dimension string) (*pasturePb.IndexFocusIndicatorsResponse, error) {
  91. userModel, err := s.GetUserModel(ctx)
  92. if err != nil {
  93. return nil, xerr.WithStack(err)
  94. }
  95. userFocusIndicators := userModel.SystemUser.IndicatorsKinds
  96. if len(userFocusIndicators) <= 0 {
  97. userFocusIndicators = model.DefaultFocusIndicators
  98. }
  99. userFocusIndicatorsList := strings.Split(userFocusIndicators, ",")
  100. indicatorsDataList := make([]*model.IndicatorsData, 0)
  101. pref := s.DB.Model(new(model.IndicatorsData)).
  102. Where("pasture_id = ?", userModel.AppPasture.Id).
  103. Where("kind in (?)", userFocusIndicatorsList)
  104. /*if dimension == "Year" {
  105. pref.Where("date = ?", time.Now().Local().Format(model.LayoutMonth))
  106. }*/
  107. nowTime := time.Now().Local()
  108. if dimension == "Month" {
  109. pref.Where("date = ?", nowTime.Format(model.LayoutMonth))
  110. }
  111. if err = pref.Find(&indicatorsDataList).Error; err != nil {
  112. zaplog.Error("FocusIndicators", zap.Any("err", err))
  113. }
  114. indicatorsDetailsMap, _, err := s.GetIndicatorsDetailsMap(ctx)
  115. if err != nil {
  116. return nil, xerr.WithStack(err)
  117. }
  118. focusIndicatorsList := make([]*pasturePb.FocusIndicators, 0)
  119. for _, v := range indicatorsDataList {
  120. indicatorsDetails, ok := indicatorsDetailsMap[v.Kind]
  121. if !ok {
  122. continue
  123. }
  124. onYear, onMonth := "", ""
  125. isUp := pasturePb.IsShow_Ok
  126. if dimension == "Year" {
  127. return nil, xerr.Custom("暂不支持该维度")
  128. }
  129. if dimension == "Month" {
  130. lastMonth := nowTime.AddDate(0, -1, 0).Format(model.LayoutMonth)
  131. oldIndicators, _ := s.GetIndicatorsDataByDate(userModel.AppPasture.Id, v.Kind, lastMonth)
  132. if oldIndicators != nil {
  133. if oldIndicators.Value != "" && oldIndicators.Value != "0" {
  134. oldValue, _ := strconv.ParseFloat(oldIndicators.Value, 64)
  135. currValue, _ := strconv.ParseFloat(v.Value, 64)
  136. onMonthValue := (oldValue - currValue) / oldValue * 100
  137. omv := util.RoundToTwoDecimals(onMonthValue)
  138. if omv < 0 {
  139. isUp = pasturePb.IsShow_No
  140. }
  141. onMonth = strconv.FormatFloat(omv, 'f', 2, 64) + "%"
  142. }
  143. }
  144. }
  145. focusIndicatorsList = append(focusIndicatorsList, &pasturePb.FocusIndicators{
  146. Kind: indicatorsDetails.Kind,
  147. Name: indicatorsDetails.Name,
  148. Value: v.Value,
  149. Describe: indicatorsDetails.Zh,
  150. UnitName: indicatorsDetails.Unit,
  151. OnMonth: onMonth,
  152. OnYear: onYear,
  153. IsUp: isUp,
  154. })
  155. }
  156. indicatorsDetailsList, _ := s.FindIndicatorsDetailsList(ctx)
  157. return &pasturePb.IndexFocusIndicatorsResponse{
  158. Code: http.StatusOK,
  159. Msg: "ok",
  160. Data: &pasturePb.FocusData{
  161. FocusIndicators: focusIndicatorsList,
  162. IndicatorsSet: model.IndicatorsDetailsSlice(indicatorsDetailsList).ToPB(userFocusIndicatorsList),
  163. },
  164. }, err
  165. }
  166. func (s *StoreEntry) FocusIndicatorsSet(ctx context.Context, req *pasturePb.IndexFocusIndicatorsSetRequest) error {
  167. userModel, err := s.GetUserModel(ctx)
  168. if err != nil {
  169. return xerr.WithStack(err)
  170. }
  171. if len(req.IndicatorsKind) <= 0 {
  172. return nil
  173. }
  174. userFocusIndicators := strings.Join(req.IndicatorsKind, ",")
  175. if err = s.DB.Model(new(model.SystemUser)).
  176. Where("id = ?", userModel.SystemUser.Id).
  177. Update("indicators_kinds", userFocusIndicators).Error; err != nil {
  178. return xerr.WithStack(err)
  179. }
  180. return nil
  181. }
  182. func (s *StoreEntry) DataWarningSet(ctx context.Context, req *pasturePb.IndexDataWarningSetRequest) error {
  183. userModel, err := s.GetUserModel(ctx)
  184. if err != nil {
  185. return xerr.WithStack(err)
  186. }
  187. pastureId := userModel.AppPasture.Id
  188. if len(req.WarningDataSet) <= 0 {
  189. return xerr.Custom("请选择预警数据")
  190. }
  191. defaultDataWarning, _ := s.FindDataWarning(ctx, pastureId, model.DefaultUserId)
  192. if len(defaultDataWarning) <= 0 {
  193. return xerr.Custom("默认预警数据不存在,请联系管理员!")
  194. }
  195. userDataWarningList, err := s.FindDataWarning(ctx, pastureId, userModel.SystemUser.Id)
  196. if err != nil {
  197. return xerr.WithStack(err)
  198. }
  199. if len(userDataWarningList) <= 0 { // 新增
  200. return s.addUserDataWarning(ctx, pastureId, userModel.SystemUser.Id, defaultDataWarning, req.WarningDataSet)
  201. }
  202. return s.updateUserDataWarning(ctx, pastureId, userModel.SystemUser.Id, userDataWarningList, req.WarningDataSet)
  203. }
  204. func (s *StoreEntry) DataWarningList(ctx context.Context) (*pasturePb.IndexDataWarningResponse, error) {
  205. userModel, err := s.GetUserModel(ctx)
  206. if err != nil {
  207. return nil, xerr.WithStack(err)
  208. }
  209. pastureId := userModel.AppPasture.Id
  210. defaultDataWarning, _ := s.FindDataWarning(ctx, pastureId, model.DefaultUserId)
  211. if len(defaultDataWarning) <= 0 {
  212. return nil, xerr.Custom("默认预警数据有误,请联系管理员!")
  213. }
  214. var isExist bool // 判断是否存在自己的设置的数据
  215. userDataWarning, _ := s.FindDataWarning(ctx, pastureId, userModel.SystemUser.Id)
  216. zaplog.Info("defaultDataWarning",
  217. zap.Any("defaultDataWarning", defaultDataWarning),
  218. zap.Any("pastureId", pastureId),
  219. zap.Any("userDataWarning", userDataWarning),
  220. zap.Any("userId", userModel.SystemUser.Id),
  221. )
  222. if len(userDataWarning) == 0 {
  223. // 如果用户没有配置自己的预警数据,则使用默认数据
  224. isExist = true
  225. userDataWarning = defaultDataWarning
  226. }
  227. newTime := time.Now().Local().Unix()
  228. needUpdateWarningIds := make([]int64, 0)
  229. for _, warningData := range userDataWarning {
  230. // 如果预警数据更新时间大于预警条件更新时间,并且更新时间距离当前时间小于2小时,则跳过
  231. if warningData.DataUpdateAt > warningData.ConditionUpdateAt && newTime-warningData.DataUpdateAt < int64(2*time.Hour) {
  232. continue
  233. }
  234. needUpdateWarningIds = append(needUpdateWarningIds, warningData.Id)
  235. }
  236. // 需要重新计算更新的warningId
  237. if len(needUpdateWarningIds) > 0 {
  238. s.UpdateWarningData(ctx, pastureId, needUpdateWarningIds)
  239. }
  240. userDataWarningItems := make([]*model.DataWarningItems, 0)
  241. // 计算过后重新获取数据
  242. if isExist {
  243. userDataWarning, _ = s.FindDataWarning(ctx, pastureId, model.DefaultUserId)
  244. userDataWarningItems, _ = s.FindDataWarningItems(ctx, pastureId, model.DefaultUserId)
  245. } else {
  246. userDataWarning, _ = s.FindDataWarning(ctx, pastureId, userModel.SystemUser.Id)
  247. userDataWarningItems, _ = s.FindDataWarningItems(ctx, pastureId, userModel.SystemUser.Id)
  248. }
  249. return &pasturePb.IndexDataWarningResponse{
  250. Code: http.StatusOK,
  251. Msg: "ok",
  252. Data: &pasturePb.DataWarning{
  253. DataSet: model.DataWarningItemsSlice(userDataWarningItems).ToPB(userDataWarning),
  254. DataShow: model.DataWarningSlice(userDataWarning).ToPB(),
  255. },
  256. }, nil
  257. }
  258. // 新增用户预警数据
  259. func (s *StoreEntry) addUserDataWarning(ctx context.Context, pastureId, userId int64, defaultDataWarning []*model.DataWarning, warningDataSet []*pasturePb.WarningDataSet) error {
  260. // 将默认预警数据按 Kind 映射
  261. defaultDataWarningMap := make(map[string]*model.DataWarning)
  262. for _, v := range defaultDataWarning {
  263. defaultDataWarningMap[v.Kind] = v
  264. }
  265. // 在事务中执行新增操作
  266. return s.DB.Transaction(func(tx *gorm.DB) error {
  267. addedKinds := make(map[string]bool) // 记录已添加的 Kind
  268. for _, set := range warningDataSet {
  269. dataWarning := model.NewDataWarning(pastureId, userId, set.Kind, pasturePb.IsShow_Ok, defaultDataWarningMap[set.Kind])
  270. // 如果该 Kind 已添加,跳过
  271. if !addedKinds[set.Kind] {
  272. // 创建新的预警数据
  273. if err := tx.Create(dataWarning).Error; err != nil {
  274. return xerr.WithStack(err)
  275. }
  276. } else {
  277. oldDataWarning := &model.DataWarning{}
  278. if err := tx.Model(new(model.DataWarning)).
  279. Where("user_id = ?", userId).
  280. Where("kind = ?", set.Kind).
  281. First(oldDataWarning).Error; err != nil {
  282. return xerr.WithStack(err)
  283. }
  284. dataWarning.Id = oldDataWarning.Id
  285. }
  286. // 创建预警项数据
  287. if err := tx.Create(model.NewDataWarningItems(pastureId, userId, dataWarning, set)).Error; err != nil {
  288. return xerr.WithStack(err)
  289. }
  290. addedKinds[set.Kind] = true
  291. }
  292. return nil
  293. })
  294. }
  295. // 更新用户预警数据
  296. func (s *StoreEntry) updateUserDataWarning(ctx context.Context, pastureId, userId int64, userDataWarningList []*model.DataWarning, warningDataSet []*pasturePb.WarningDataSet) error {
  297. // 将请求数据按 WarningId 和 Id 映射
  298. warningIsShowMap := make(map[int32]pasturePb.IsShow_Kind)
  299. warningItemDataMap := make(map[int32]*pasturePb.WarningDataSet)
  300. for _, set := range warningDataSet {
  301. warningIsShowMap[set.WarningId] = set.IsShow
  302. warningItemDataMap[set.Id] = set
  303. }
  304. // 获取用户预警项数据
  305. userDataWarningItems, err := s.FindDataWarningItems(ctx, pastureId, userId)
  306. if err != nil {
  307. return xerr.WithStack(err)
  308. }
  309. if len(userDataWarningItems) == 0 {
  310. return xerr.Custom("预警数据有误,请联系管理员!")
  311. }
  312. // 在事务中执行更新操作
  313. return s.DB.Transaction(func(tx *gorm.DB) error {
  314. // 更新预警数据的 IsShow 字段
  315. for _, warning := range userDataWarningList {
  316. if isShow, ok := warningIsShowMap[int32(warning.Id)]; ok {
  317. if err = tx.Model(&model.DataWarning{}).
  318. Where("id = ?", warning.Id).
  319. Update("is_show", isShow).Error; err != nil {
  320. return xerr.WithStack(err)
  321. }
  322. }
  323. }
  324. // 更新预警项数据的 IsShow 和 Value 字段
  325. for _, item := range userDataWarningItems {
  326. if set, ok := warningItemDataMap[int32(item.Id)]; ok {
  327. if err = tx.Model(&model.DataWarningItems{}).
  328. Where("id = ?", item.Id).
  329. Updates(map[string]interface{}{
  330. "is_show": set.IsShow,
  331. "value": set.Value,
  332. }).Error; err != nil {
  333. return xerr.WithStack(err)
  334. }
  335. }
  336. }
  337. return nil
  338. })
  339. }
  340. func (s *StoreEntry) FindDataWarning(ctx context.Context, pastureId, userId int64) ([]*model.DataWarning, error) {
  341. dataWarningList := make([]*model.DataWarning, 0)
  342. if err := s.DB.Model(new(model.DataWarning)).
  343. Where("user_id = ?", userId).
  344. Where("pasture_id = ?", pastureId).
  345. Where("is_show = ?", pasturePb.IsShow_Ok).
  346. Find(&dataWarningList).Error; err != nil {
  347. return nil, xerr.WithStack(err)
  348. }
  349. return dataWarningList, nil
  350. }
  351. func (s *StoreEntry) FindDataWarningItems(ctx context.Context, pastureId, userId int64) ([]*model.DataWarningItems, error) {
  352. dataWarningItemsList := make([]*model.DataWarningItems, 0)
  353. if err := s.DB.Model(new(model.DataWarningItems)).
  354. Where("pasture_id = ?", pastureId).
  355. Where("user_id = ?", userId).
  356. Where("is_show = ?", pasturePb.IsShow_Ok).
  357. Find(&dataWarningItemsList).Error; err != nil {
  358. return nil, xerr.WithStack(err)
  359. }
  360. return dataWarningItemsList, nil
  361. }
  362. func (s *StoreEntry) FindDataWarningMap(ctx context.Context, pastureId, userId int64) (map[int64]*model.DataWarning, error) {
  363. dataWarning, err := s.FindDataWarning(ctx, pastureId, userId)
  364. if err != nil {
  365. return nil, xerr.Custom("默认预警数据有误,请联系管理员!")
  366. }
  367. dataWarningMap := make(map[int64]*model.DataWarning)
  368. for _, v := range dataWarning {
  369. dataWarningMap[v.Id] = v
  370. }
  371. return dataWarningMap, nil
  372. }
  373. func (s *StoreEntry) FindDataWarningItemsMap(ctx context.Context, userId int64) (map[int64]*model.DataWarningItems, error) {
  374. dataWarningItemsList := make([]*model.DataWarningItems, 0)
  375. if err := s.DB.Model(new(model.DataWarningItems)).
  376. Where("user_id = ?", userId).
  377. Find(&dataWarningItemsList).Error; err != nil {
  378. return nil, xerr.WithStack(err)
  379. }
  380. dataWarningItemsMap := make(map[int64]*model.DataWarningItems)
  381. for _, v := range dataWarningItemsList {
  382. dataWarningItemsMap[v.Id] = v
  383. }
  384. return dataWarningItemsMap, nil
  385. }
  386. // UpdateWarningData 更新计算数据
  387. func (s *StoreEntry) UpdateWarningData(ctx context.Context, pastureId int64, needUpdateWarningIds []int64) {
  388. if len(needUpdateWarningIds) <= 0 {
  389. return
  390. }
  391. for _, warningId := range needUpdateWarningIds {
  392. query, params, err := s.BuildQuery(warningId)
  393. if err != nil {
  394. zaplog.Error("UpdateWarningData", zap.Any("BuildQuery", err), zap.Any("warningId", warningId))
  395. }
  396. if len(query) == 0 || len(params) == 0 {
  397. continue
  398. }
  399. var count int64
  400. if err = s.DB.Model(new(model.Cow)).
  401. Where("pasture_id = ?", pastureId).
  402. Where(query, params...).
  403. Count(&count).Error; err != nil {
  404. zaplog.Error("UpdateWarningData", zap.Any("err", err), zap.Any("query", query), zap.Any("params", params))
  405. }
  406. if err = s.DB.Model(new(model.DataWarning)).
  407. Where("id = ?", warningId).
  408. Updates(map[string]interface{}{
  409. "data_value": count,
  410. "data_update_at": time.Now().Local().Unix(),
  411. }).Error; err != nil {
  412. zaplog.Error("UpdateWarningData", zap.Any("update", err))
  413. }
  414. }
  415. }