package backend import ( "context" "fmt" "kpt-pasture/model" "kpt-pasture/util" "net/http" "strconv" "strings" "time" pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow" "gitee.com/xuyiping_admin/pkg/logger/zaplog" "gitee.com/xuyiping_admin/pkg/xerr" "go.uber.org/zap" ) func (s *StoreEntry) NeckRingWarning(ctx context.Context) (*pasturePb.IndexNeckRingResponse, error) { userModel, err := s.GetUserModel(ctx) if err != nil { return nil, xerr.WithStack(err) } var count int64 neckRingEstrusList := make([]*model.NeckRingEstrusWarning, 0) estrusWarningLevelItems := map[int32]int32{ int32(pasturePb.EstrusLevel_Low): 0, int32(pasturePb.EstrusLevel_Middle): 0, int32(pasturePb.EstrusLevel_High): 0, } pref, err := s.EstrusWarningQuery(ctx, userModel.AppPasture.Id) if err != nil { return nil, xerr.Customf("系统错误!") } if err = pref.Group("a.cow_id"). Order("a.level,a.id DESC"). Count(&count). Find(&neckRingEstrusList).Error; err != nil { return nil, xerr.WithStack(err) } countEstrusWarning := 0 nowTime := time.Now().Local() optimumMating := map[string]int32{ "front": 0, "middle": 0, "behind": 0, } cowIds := make([]int64, 0) for _, v := range neckRingEstrusList { cowIds = append(cowIds, v.CowId) } cowList := make([]*model.Cow, 0) if err = s.DB.Model(new(model.Cow)). Where("pasture_id = ?", userModel.AppPasture.Id). Where("admission_status = ?", pasturePb.AdmissionStatus_Admission). Where("id IN ?", cowIds). Find(&cowList).Error; err != nil { zaplog.Error("NeckRingWarning", zap.Any("err", err)) } cowByIdMap := map[int64]*model.Cow{} for _, v := range cowList { cowByIdMap[v.Id] = v } for _, v := range neckRingEstrusList { estrusWarningLevelItems[int32(v.Level)] += 1 countEstrusWarning += 1 cowInfo, ok := cowByIdMap[v.CowId] if !ok { zaplog.Info("NeckRingWarning", zap.Any("v", v), zap.Any("cowByIdMap", cowByIdMap)) continue } pzHour := v.CalculatePzHour(cowInfo.Lact) optimumMatingStartTime := pzHour.Add(-4 * time.Hour) optimumMatingEndTime := pzHour.Add(4 * time.Hour) // 判断当前时间是否在 pzHour-4h 到 pzHour+4h 之间 if nowTime.After(optimumMatingStartTime) && nowTime.Before(optimumMatingEndTime) { optimumMating["middle"] += 1 } if nowTime.After(optimumMatingEndTime) { optimumMating["behind"] += 1 } if nowTime.Before(optimumMatingStartTime) { optimumMating["front"] += 1 } } abortionCount := int64(0) pref, err = s.AbortionWarningQuery(ctx, userModel.AppPasture.Id) if err != nil { return nil, xerr.Customf("系统错误!") } if err = pref.Group("cow_id"). Count(&abortionCount).Error; err != nil { return nil, xerr.WithStack(err) } 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(countEstrusWarning), HealthWarningNumber: int32(healthWarningNumber), AbortionWarningNumber: int32(abortionCount), StressWarningNumber: 0, EstrusWarningLevelItems: estrusWarningLevelItems, OptimumMating: optimumMating, }, }, 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, ",") // 获取用户关注的指标 userFocusIndicatorsDetailsList := make([]*model.IndicatorsDetails, 0) if err = s.DB.Model(new(model.IndicatorsDetails)). Where("kind in (?)", userFocusIndicatorsList). Find(&userFocusIndicatorsDetailsList).Error; err != nil { zaplog.Error("FocusIndicators", zap.Any("err", err)) } nowTime := time.Now().Local() currentMonth := nowTime.Format(model.LayoutMonth) lastMonth := nowTime.AddDate(0, -1, 0).Format(model.LayoutMonth) lastYear := nowTime.AddDate(-1, 0, 0).Format(model.LayoutYear) indicatorsDataList := make([]*model.IndicatorsData, 0) if err = s.DB.Model(new(model.IndicatorsData)). Where("pasture_id = ?", userModel.AppPasture.Id). Where("kind in (?)", userFocusIndicatorsList). Where("date IN ?", []string{currentMonth, lastMonth, lastYear}). Order("kind,date"). Find(&indicatorsDataList).Error; err != nil { zaplog.Error("FocusIndicators", zap.Any("err", err)) } focusIndicatorsList := make([]*pasturePb.FocusIndicators, 0) indicatorsDataByKindMap := map[string][]*model.IndicatorsData{} for _, v := range indicatorsDataList { if indicatorsDataByKindMap[v.Kind] == nil { indicatorsDataByKindMap[v.Kind] = make([]*model.IndicatorsData, 0) } indicatorsDataByKindMap[v.Kind] = append(indicatorsDataByKindMap[v.Kind], v) } for _, indicatorsDetails := range userFocusIndicatorsDetailsList { indicatorsList := indicatorsDataByKindMap[indicatorsDetails.Kind] onYear, onMonth, currValue, onValue := "", "", float64(0), "" isUp := pasturePb.IsShow_Ok for _, v := range indicatorsList { if v.Date == currentMonth { currValue, _ = strconv.ParseFloat(v.Value, 64) } if v.Date == lastYear { onYear = v.Value } if v.Date == lastMonth { onMonth = v.Value } } oldValue := float64(0) if dimension == "Year" { oldValue, _ = strconv.ParseFloat(onYear, 64) } if dimension == "Month" { oldValue, _ = strconv.ParseFloat(onMonth, 64) } if currValue > 0 && oldValue > 0 { b := float64(0) if oldValue > 0 { b = (oldValue - currValue) / oldValue * 100 } omv := util.RoundToTwoDecimals(b) if omv < 0 { isUp = pasturePb.IsShow_No } onValue = strconv.FormatFloat(omv, 'f', 2, 64) + "%" } focusIndicatorsList = append(focusIndicatorsList, &pasturePb.FocusIndicators{ Kind: indicatorsDetails.Kind, Name: indicatorsDetails.Name, Value: fmt.Sprintf("%f", currValue), Describe: indicatorsDetails.Zh, UnitName: indicatorsDetails.Unit, IsUp: isUp, OnYear: onValue, OnMonth: onValue, }) } indicatorsDetailsList, _ := s.FindIndicatorsDetailsList() 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) Equipment(ctx context.Context) (*pasturePb.EquipmentResponse, error) { userModel, err := s.GetUserModel(ctx) if err != nil { return nil, xerr.WithStack(err) } equipmentList := make([]*pasturePb.Equipment, 0) dashboardNeckRingList := make([]*model.DashboardNeckRing, 0) if err = s.DB.Model(new(model.NeckRing)). Select("status, count(*) as number"). Where("pasture_id = ?", userModel.AppPasture.Id). Group("status"). Find(&dashboardNeckRingList).Error; err != nil { } normalNumber, abnormalNumber := int32(0), int32(0) for _, v := range dashboardNeckRingList { if v.Status == pasturePb.NeckRingStatus_Normal { normalNumber = v.Number } if v.Status == pasturePb.NeckRingStatus_Abnormal { abnormalNumber = v.Number } } var receiverCount int64 if err = s.DB.Model(new(model.AppPastureReceiver)). Where("pasture_id = ?", userModel.AppPasture.Id). Count(&receiverCount).Error; err != nil { } equipmentList = append(equipmentList, &pasturePb.Equipment{ Name: "异常脖环数", Describe: "脖环", NormalNumber: normalNumber, AbnormalNumber: abnormalNumber, Icon: "/assets/welcome/ring@2x.png", Kind: pasturePb.EquipmentType_Neck_Ring, }, &pasturePb.Equipment{ Name: "离线接收器", Describe: "接收器", NormalNumber: int32(receiverCount), AbnormalNumber: int32(0), Icon: "/assets/welcome/device@2x.png", Kind: pasturePb.EquipmentType_Receiver, }) return &pasturePb.EquipmentResponse{ Code: http.StatusOK, Msg: "ok", Data: &pasturePb.EquipmentData{EquipmentList: equipmentList}, }, nil }