dashboard.go 13 KB

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