package backend import ( "context" "kpt-pasture/model" "kpt-pasture/util" "net/http" "strconv" "strings" "time" "gorm.io/gorm" "gitee.com/xuyiping_admin/pkg/logger/zaplog" "gitee.com/xuyiping_admin/pkg/xerr" "go.uber.org/zap" pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow" ) func (s *StoreEntry) NeckRingWarning(ctx context.Context) (*pasturePb.IndexNeckRingResponse, error) { userModel, err := s.GetUserModel(ctx) if err != nil { return nil, xerr.WithStack(err) } estrusWarningCowList := make([]*model.NeckRingEstrus, 0) estrusWarningLevelItems := map[int32]int32{ int32(pasturePb.EstrusLevel_Low): 0, int32(pasturePb.EstrusLevel_Middle): 0, int32(pasturePb.EstrusLevel_High): 0, } if err = s.DB.Model(new(model.EventEstrus)). Where("pasture_id = ?", userModel.AppPasture.Id). Where("is_show = ?", pasturePb.IsShow_Ok). Group("cow_id").Find(&estrusWarningCowList).Error; err != nil { zaplog.Error("NeckRingWarning", zap.Any("estrusWarningNumber", err)) } for _, v := range estrusWarningCowList { estrusWarningLevelItems[int32(v.Level)] += estrusWarningLevelItems[int32(v.Level)] } healthWarningNumber := int64(0) if err = s.DB.Model(new(model.NeckRingHealthWarning)). Where("pasture_id = ?", userModel.AppPasture.Id). Where("is_show = ?", pasturePb.IsShow_Ok). Group("cow_id"). Count(&healthWarningNumber).Error; err != nil { zaplog.Error("NeckRingWarning", zap.Any("estrusWarningNumber", err)) } return &pasturePb.IndexNeckRingResponse{ Code: http.StatusOK, Msg: "ok", Data: &pasturePb.NeckRingData{ EstrusWarningNumber: int32(len(estrusWarningCowList)), HealthWarningNumber: int32(healthWarningNumber), AbortionWarningNumber: 0, StressWarningNumber: 0, EstrusWarningLevelItems: estrusWarningLevelItems, }, }, nil } func (s *StoreEntry) FocusIndicatorsList(ctx context.Context, dimension string) (*pasturePb.IndexFocusIndicatorsResponse, error) { userModel, err := s.GetUserModel(ctx) if err != nil { return nil, xerr.WithStack(err) } userFocusIndicators := userModel.SystemUser.IndicatorsKinds if len(userFocusIndicators) <= 0 { userFocusIndicators = model.DefaultFocusIndicators } userFocusIndicatorsList := strings.Split(userFocusIndicators, ",") indicatorsDataList := make([]*model.IndicatorsData, 0) pref := s.DB.Model(new(model.IndicatorsData)). Where("pasture_id = ?", userModel.AppPasture.Id). Where("kind in (?)", userFocusIndicatorsList) /*if dimension == "Year" { pref.Where("date = ?", time.Now().Format(model.LayoutMonth)) }*/ nowTime := time.Now() if dimension == "Month" { pref.Where("date = ?", nowTime.Format(model.LayoutMonth)) } if err = pref.Find(&indicatorsDataList).Error; err != nil { zaplog.Error("FocusIndicators", zap.Any("err", err)) } indicatorsDetailsMap, _, err := s.GetIndicatorsDetailsMap(ctx) if err != nil { return nil, xerr.WithStack(err) } focusIndicatorsList := make([]*pasturePb.FocusIndicators, 0) for _, v := range indicatorsDataList { indicatorsDetails, ok := indicatorsDetailsMap[v.Kind] if !ok { continue } onYear, onMonth := "", "" if dimension == "Year" { return nil, xerr.Custom("暂不支持该维度") } if dimension == "Month" { lastMonth := nowTime.AddDate(0, -1, 0).Format(model.LayoutMonth) oldIndicators, _ := s.GetIndicatorsDataByDate(userModel.AppPasture.Id, v.Kind, lastMonth) if oldIndicators != nil { if oldIndicators.Value != "" && oldIndicators.Value != "0" { oldValue, _ := strconv.ParseFloat(oldIndicators.Value, 64) currValue, _ := strconv.ParseFloat(v.Value, 64) onMonthValue := (oldValue - currValue) / oldValue * 100 omv := util.RoundToTwoDecimals(onMonthValue) onMonth = strconv.FormatFloat(omv, 'f', 2, 64) + "%" } } } focusIndicatorsList = append(focusIndicatorsList, &pasturePb.FocusIndicators{ Kind: indicatorsDetails.Kind, Name: indicatorsDetails.Name, Value: v.Value, Describe: indicatorsDetails.Zh, UnitName: indicatorsDetails.Unit, OnMonth: onMonth, OnYear: onYear, }) } indicatorsDetailsList, _ := s.FindIndicatorsDetailsList(ctx) return &pasturePb.IndexFocusIndicatorsResponse{ Code: http.StatusOK, Msg: "ok", Data: &pasturePb.FocusData{ FocusIndicators: focusIndicatorsList, IndicatorsSet: model.IndicatorsDetailsSlice(indicatorsDetailsList).ToPB(userFocusIndicatorsList), }, }, err } func (s *StoreEntry) FocusIndicatorsSet(ctx context.Context, req *pasturePb.IndexFocusIndicatorsSetRequest) error { userModel, err := s.GetUserModel(ctx) if err != nil { return xerr.WithStack(err) } if len(req.IndicatorsKind) <= 0 { return nil } userFocusIndicators := strings.Join(req.IndicatorsKind, ",") if err = s.DB.Model(new(model.SystemUser)). Where("id = ?", userModel.SystemUser.Id). Update("indicators_kinds", userFocusIndicators).Error; err != nil { return xerr.WithStack(err) } return nil } func (s *StoreEntry) DataWarningSet(ctx context.Context, req *pasturePb.IndexDataWarningSetRequest) error { userModel, err := s.GetUserModel(ctx) if err != nil { return xerr.WithStack(err) } if len(req.WarningDataSet) <= 0 { return nil } defaultDataWarning, _ := s.FindDataWarning(ctx, model.DefaultUserId) if len(defaultDataWarning) <= 0 { return xerr.Custom("默认预警数据不存在,请联系管理员!") } userDataWarningList, err := s.FindDataWarning(ctx, userModel.SystemUser.Id) if err != nil { return xerr.WithStack(err) } if len(userDataWarningList) <= 0 { // 新增 return s.addUserDataWarning(ctx, userModel.SystemUser.Id, defaultDataWarning, req.WarningDataSet) } return s.updateUserDataWarning(ctx, userModel.SystemUser.Id, userDataWarningList, req.WarningDataSet) } func (s *StoreEntry) DataWarningList(ctx context.Context) (*pasturePb.IndexDataWarningResponse, error) { userModel, err := s.GetUserModel(ctx) if err != nil { return nil, xerr.WithStack(err) } defaultDataWarning, _ := s.FindDataWarning(ctx, model.DefaultUserId) if len(defaultDataWarning) <= 0 { return nil, xerr.Custom("默认预警数据有误,请联系管理员!") } var isExist bool // 判断是否存在自己的设置的数据 userDataWarning, _ := s.FindDataWarning(ctx, userModel.SystemUser.Id) if len(userDataWarning) == 0 { // 如果用户没有配置自己的预警数据,则使用默认数据 isExist = true userDataWarning = defaultDataWarning } newTime := time.Now().Unix() needUpdateWarningIds := make([]int64, 0) for _, warningData := range userDataWarning { // 如果预警数据更新时间大于预警条件更新时间,并且更新时间距离当前时间小于2小时,则跳过 if warningData.DataUpdateAt > warningData.ConditionUpdateAt && newTime-warningData.DataUpdateAt < int64(2*time.Hour) { continue } needUpdateWarningIds = append(needUpdateWarningIds, warningData.Id) } // 需要重新计算更新的warningId if len(needUpdateWarningIds) > 0 { s.UpdateWarningData(ctx, needUpdateWarningIds) } userDataWarningItems := make([]*model.DataWarningItems, 0) // 计算过后重新获取数据 if isExist { userDataWarning, _ = s.FindDataWarning(ctx, model.DefaultUserId) userDataWarningItems, _ = s.FindDataWarningItems(ctx, model.DefaultUserId) } else { userDataWarning, _ = s.FindDataWarning(ctx, userModel.SystemUser.Id) userDataWarningItems, _ = s.FindDataWarningItems(ctx, userModel.SystemUser.Id) } return &pasturePb.IndexDataWarningResponse{ Code: http.StatusOK, Msg: "ok", Data: &pasturePb.DataWarning{ DataSet: model.DataWarningItemsSlice(userDataWarningItems).ToPB(userDataWarning), DataShow: model.DataWarningSlice(userDataWarning).ToPB(), }, }, nil } // 新增用户预警数据 func (s *StoreEntry) addUserDataWarning(ctx context.Context, userId int64, defaultDataWarning []*model.DataWarning, warningDataSet []*pasturePb.WarningDataSet) error { // 将默认预警数据按 Kind 映射 defaultDataWarningMap := make(map[string]*model.DataWarning) for _, v := range defaultDataWarning { defaultDataWarningMap[v.Kind] = v } // 在事务中执行新增操作 return s.DB.Transaction(func(tx *gorm.DB) error { addedKinds := make(map[string]bool) // 记录已添加的 Kind for _, set := range warningDataSet { dataWarning := model.NewDataWarning(userId, set.Kind, pasturePb.IsShow_Ok, defaultDataWarningMap[set.Kind]) // 如果该 Kind 已添加,跳过 if !addedKinds[set.Kind] { // 创建新的预警数据 if err := tx.Create(dataWarning).Error; err != nil { return xerr.WithStack(err) } } else { oldDataWarning := &model.DataWarning{} if err := tx.Model(new(model.DataWarning)). Where("user_id = ?", userId). Where("kind = ?", set.Kind). First(oldDataWarning).Error; err != nil { return xerr.WithStack(err) } dataWarning.Id = oldDataWarning.Id } // 创建预警项数据 if err := tx.Create(model.NewDataWarningItems(userId, dataWarning, set)).Error; err != nil { return xerr.WithStack(err) } addedKinds[set.Kind] = true } return nil }) } // 更新用户预警数据 func (s *StoreEntry) updateUserDataWarning(ctx context.Context, userId int64, userDataWarningList []*model.DataWarning, warningDataSet []*pasturePb.WarningDataSet) error { // 将请求数据按 WarningId 和 Id 映射 warningIsShowMap := make(map[int32]pasturePb.IsShow_Kind) warningItemDataMap := make(map[int32]*pasturePb.WarningDataSet) for _, set := range warningDataSet { warningIsShowMap[set.WarningId] = set.IsShow warningItemDataMap[set.Id] = set } // 获取用户预警项数据 userDataWarningItems, err := s.FindDataWarningItems(ctx, userId) if err != nil { return xerr.WithStack(err) } if len(userDataWarningItems) == 0 { return xerr.Custom("预警数据有误,请联系管理员!") } // 在事务中执行更新操作 return s.DB.Transaction(func(tx *gorm.DB) error { // 更新预警数据的 IsShow 字段 for _, warning := range userDataWarningList { if isShow, ok := warningIsShowMap[int32(warning.Id)]; ok { if err = tx.Model(&model.DataWarning{}). Where("id = ?", warning.Id). Update("is_show", isShow).Error; err != nil { return xerr.WithStack(err) } } } // 更新预警项数据的 IsShow 和 Value 字段 for _, item := range userDataWarningItems { if set, ok := warningItemDataMap[int32(item.Id)]; ok { if err = tx.Model(&model.DataWarningItems{}). Where("id = ?", item.Id). Updates(map[string]interface{}{ "is_show": set.IsShow, "value": set.Value, }).Error; err != nil { return xerr.WithStack(err) } } } return nil }) } func (s *StoreEntry) FindDataWarning(ctx context.Context, userId int64) ([]*model.DataWarning, error) { dataWarningList := make([]*model.DataWarning, 0) if err := s.DB.Model(new(model.DataWarning)). Where("user_id = ?", userId). Find(&dataWarningList).Error; err != nil { return nil, xerr.WithStack(err) } return dataWarningList, nil } func (s *StoreEntry) FindDataWarningItems(ctx context.Context, userId int64) ([]*model.DataWarningItems, error) { dataWarningItemsList := make([]*model.DataWarningItems, 0) if err := s.DB.Model(new(model.DataWarningItems)). Where("user_id = ?", userId). Find(&dataWarningItemsList).Error; err != nil { return nil, xerr.WithStack(err) } return dataWarningItemsList, nil } func (s *StoreEntry) FindDataWarningMap(ctx context.Context, userId int64) (map[int64]*model.DataWarning, error) { dataWarning, err := s.FindDataWarning(ctx, userId) if err != nil { return nil, xerr.Custom("默认预警数据有误,请联系管理员!") } dataWarningMap := make(map[int64]*model.DataWarning) for _, v := range dataWarning { dataWarningMap[v.Id] = v } return dataWarningMap, nil } func (s *StoreEntry) FindDataWarningItemsMap(ctx context.Context, userId int64) (map[int64]*model.DataWarningItems, error) { dataWarningItemsList := make([]*model.DataWarningItems, 0) if err := s.DB.Model(new(model.DataWarningItems)). Where("user_id = ?", userId). Find(&dataWarningItemsList).Error; err != nil { return nil, xerr.WithStack(err) } dataWarningItemsMap := make(map[int64]*model.DataWarningItems) for _, v := range dataWarningItemsList { dataWarningItemsMap[v.Id] = v } return dataWarningItemsMap, nil } // UpdateWarningData 更新计算数据 func (s *StoreEntry) UpdateWarningData(ctx context.Context, needUpdateWarningIds []int64) { if len(needUpdateWarningIds) <= 0 { return } for _, warningId := range needUpdateWarningIds { query, params, err := s.BuildQuery(warningId) if err != nil { zaplog.Error("UpdateWarningData", zap.Any("BuildQuery", err), zap.Any("warningId", warningId)) } if len(query) == 0 || len(params) == 0 { continue } var count int64 if err = s.DB.Model(new(model.Cow)).Where(query, params...).Count(&count).Error; err != nil { zaplog.Error("UpdateWarningData", zap.Any("err", err), zap.Any("query", query), zap.Any("params", params)) } if err = s.DB.Model(new(model.DataWarning)). Where("id = ?", warningId). Updates(map[string]interface{}{ "data_value": count, "data_update_at": time.Now().Unix(), }).Error; err != nil { zaplog.Error("UpdateWarningData", zap.Any("update", err)) } } }