package backend import ( "context" "fmt" "kpt-pasture/model" "kpt-pasture/util" "math" "net/http" "time" pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow" "gitee.com/xuyiping_admin/pkg/xerr" ) func (s *StoreEntry) TwentyOnePregnantRate(ctx context.Context, req *pasturePb.TwentyOnePregnantRateRequest) (*pasturePb.TwentyOnePregnantRateResponse, error) { userModel, err := s.GetUserModel(ctx) if err != nil { return nil, xerr.WithStack(err) } startUnix := util.TimeParseLocalUnix(req.StartDate) endUnix := util.TimeParseLocalUnix(req.EndDate) if startUnix > endUnix { return nil, xerr.Customf("开始时间不能大于结束时间: %s ~ %d", req.StartDate, req.EndDate) } nowDateTime := time.Now().Local() if endUnix > nowDateTime.Unix() { return nil, xerr.Customf("结束时间不能大于当前时间: %s ~ %s", req.EndDate, nowDateTime.Format(model.LayoutDate2)) } dataRange, err := util.Get21DayPeriods(req.StartDate, req.EndDate) if err != nil { return nil, xerr.WithStack(err) } chart := &pasturePb.TwentyOnePregnantRateChart{ Header: make([]string, 0), PregnantRate: make([]float32, 0), MatingRate: make([]float32, 0), } // 牛只主动停配期 systemBasicName := "" switch req.CowType { case pasturePb.CowType_Breeding_Calf: systemBasicName = model.ProactivelyStopBreedingForAdult case pasturePb.CowType_Reserve_Calf: systemBasicName = model.ProactivelyStopBreedingForBackup default: return nil, xerr.Customf("不支持的牛只类型: %d", req.CowType) } systemBasic, err := s.GetSystemBasicByName(ctx, userModel.AppPasture.Id, systemBasicName) if err != nil { return nil, xerr.WithStack(err) } stopBreedingDay := systemBasic.MinValue twentyOnePregnantRateList := make([]*pasturePb.TwentyOnePregnantRateList, 0) for _, v := range dataRange { middleDay, err := util.GetRangeDayMiddleDay(v, 11) if err != nil { return nil, xerr.WithStack(err) } _, shouldBreedCount := s.TwentyOnePregnantShouldBreedList(userModel.AppPasture.Id, req.CowType, stopBreedingDay, middleDay) realityBreedCowList, realityBreedCount := s.TwentyOnePregnantRealityBreedList(userModel.AppPasture.Id, req.CowType, v[0], v[1]) breedRate, abortionRate, realityPregnantRate := float32(0), float32(0), float32(0) if realityBreedCount > 0 && shouldBreedCount > 0 { breedRate = float32(math.Round(float64(realityBreedCount)/float64(shouldBreedCount)*100) / 100) } realityPregnantCount, shouldPregnantCount, realityAbortionCount := int32(0), int32(0), int32(0) for _, eventMating := range realityBreedCowList { if eventMating.MatingResult == pasturePb.MatingResult_Pregnant { realityPregnantCount++ } if eventMating.MatingResult == pasturePb.MatingResult_Abort { realityAbortionCount++ } if s.IsDeparture(ctx, userModel.AppPasture.Id, eventMating.CowId, 35) { shouldPregnantCount++ } } if realityPregnantCount > 0 && shouldPregnantCount > 0 { realityPregnantRate = float32(math.Round(float64(realityPregnantCount)/float64(shouldPregnantCount)*100) / 100) } if realityAbortionCount > 0 && realityPregnantCount > 0 { abortionRate = float32(math.Round(float64(realityAbortionCount)/float64(realityPregnantCount)*100) / 100) } chart.Header = append(chart.Header, fmt.Sprintf("%s ~ %s", v[0][5:], v[1][5:])) chart.PregnantRate = append(chart.PregnantRate, realityPregnantRate) chart.MatingRate = append(chart.MatingRate, breedRate) twentyOnePregnantRateList = append(twentyOnePregnantRateList, &pasturePb.TwentyOnePregnantRateList{ StartDay: v[0], EndDay: v[1], ShouldBreedCount: shouldBreedCount, // 应配种 RealityBreedCount: realityBreedCount, // 实际配种 BreedRate: breedRate, // 配种率 ShouldPregnantCount: shouldPregnantCount, // 应怀孕 RealityPregnantCount: realityPregnantCount, // 实际怀孕 PregnantRate: realityPregnantRate, // 怀孕率 RealityAbortionCount: realityAbortionCount, // 实际流产 AbortionRate: abortionRate, // 流产率 }) } return &pasturePb.TwentyOnePregnantRateResponse{ Code: http.StatusOK, Msg: "ok", Data: &pasturePb.TwentyOnePregnantRateData{ Chart: chart, Table: &pasturePb.TwentyOnePregnantRateTable{ List: twentyOnePregnantRateList, Total: int32(len(dataRange)), }, }, }, nil } // TwentyOnePregnantShouldBreedList 21天牛应配牛只列表 func (s *StoreEntry) TwentyOnePregnantShouldBreedList(pastureId int64, cowType pasturePb.CowType_Kind, stopBreedingDay int32, middleDay string) ([]*model.CowCalving, int32) { everyDayCalvingList := make([]*model.CowCalving, 0) if err := s.DB.Model(new(model.CowCalving)). Where("pasture_id = ?", pastureId). Where("cow_type = ?", cowType). Where("date_time = ?", middleDay). Where("calving_age >= ?", stopBreedingDay). Where("is_abortion = ?", pasturePb.IsShow_No). Where("is_departure = ?", pasturePb.IsShow_No). Where("is_forbidden = ?", pasturePb.IsShow_No). Find(&everyDayCalvingList).Error; err != nil { return everyDayCalvingList, 0 } return everyDayCalvingList, int32(len(everyDayCalvingList)) } func (s *StoreEntry) TwentyOnePregnantRealityBreedList(pastureId int64, cowType pasturePb.CowType_Kind, startDate, endDate string) ([]*model.EventMating, int32) { eventMatingList := make([]*model.EventMating, 0) if err := s.DB.Model(new(model.EventMating)). Where("pasture_id = ?", pastureId). Where("cow_type = ?", cowType). Where("reality_day BETWEEN ? AND ?", util.TimeParseLocalUnix(startDate), util.TimeParseLocalEndUnix(endDate)). Where("status = ?", pasturePb.IsShow_Ok). Find(&eventMatingList).Error; err != nil { return eventMatingList, 0 } return eventMatingList, int32(len(eventMatingList)) } // IsDeparture 是否离场并且在配种后35天 func (s *StoreEntry) IsDeparture(ctx context.Context, pastureId, cowId int64, days int32) bool { cowInfo := &model.Cow{} if err := s.DB.Model(new(model.Cow)). Where("pasture_id = ?", pastureId). Where("sex = ?", pasturePb.Genders_Female). Where("id = ?", cowId).First(cowInfo).Error; err != nil { return false } matingUnix := time.Unix(cowInfo.LastMatingAt, 0).Local().AddDate(0, 0, int(days)).Unix() departureAt := cowInfo.DepartureAt if departureAt > 0 && matingUnix >= matingUnix { return true } return false } func (s *StoreEntry) TwentyOnePregnantDetail(ctx context.Context, req *pasturePb.TwentyOnePregnantDetailsRequest) (*pasturePb.TwentyOnePregnantDetailsResponse, error) { userModel, err := s.GetUserModel(ctx) if err != nil { return nil, xerr.WithStack(err) } pastureId := userModel.AppPasture.Id list := make([]*pasturePb.TwentyOnePregnantItems, 0) // 牛只主动停配期 systemBasicName := "" switch req.CowType { case pasturePb.CowType_Breeding_Calf: systemBasicName = model.ProactivelyStopBreedingForAdult case pasturePb.CowType_Reserve_Calf: systemBasicName = model.ProactivelyStopBreedingForBackup default: return nil, xerr.Customf("不支持的牛只类型: %d", req.CowType) } systemBasic, err := s.GetSystemBasicByName(ctx, userModel.AppPasture.Id, systemBasicName) if err != nil { return nil, xerr.WithStack(err) } stopBreedingDay := systemBasic.MinValue middleDay, err := util.GetRangeDayMiddleDay([]string{req.StartDate, req.EndDate}, 11) if err != nil { return nil, xerr.WithStack(err) } cowTypeMap := s.CowTypeMap() switch req.Type { case pasturePb.TwentyOnePregnantType_ShouldBreed: shouldBreedCowList, _ := s.TwentyOnePregnantShouldBreedList(pastureId, req.CowType, stopBreedingDay, middleDay) list = model.CowCalvingSlice(shouldBreedCowList).ToPB() case pasturePb.TwentyOnePregnantType_RealityBreed: realityBreedCowList, _ := s.TwentyOnePregnantRealityBreedList(userModel.AppPasture.Id, req.CowType, req.StartDate, req.EndDate) list = model.EventMatingSlice(realityBreedCowList).ToPB3(false, cowTypeMap) case pasturePb.TwentyOnePregnantType_ShouldPregnant: realityBreedCowList, _ := s.TwentyOnePregnantRealityBreedList(userModel.AppPasture.Id, req.CowType, req.StartDate, req.EndDate) newShouldBreedCowList := make([]*model.EventMating, 0) for _, v := range realityBreedCowList { if s.IsDeparture(ctx, v.PastureId, v.CowId, stopBreedingDay) { newShouldBreedCowList = append(newShouldBreedCowList, v) } } list = model.EventMatingSlice(newShouldBreedCowList).ToPB3(false, cowTypeMap) case pasturePb.TwentyOnePregnantType_RealityPregnant: realityBreedCowList, _ := s.TwentyOnePregnantRealityBreedList(userModel.AppPasture.Id, req.CowType, req.StartDate, req.EndDate) list = model.EventMatingSlice(realityBreedCowList).ToPB3(true, cowTypeMap) case pasturePb.TwentyOnePregnantType_RealityAbortion: realityBreedCowList, _ := s.TwentyOnePregnantRealityBreedList(userModel.AppPasture.Id, req.CowType, req.StartDate, req.EndDate) list = model.EventMatingSlice(realityBreedCowList).ToPB4(cowTypeMap) } return &pasturePb.TwentyOnePregnantDetailsResponse{ Code: http.StatusOK, Msg: "ok", Data: &pasturePb.TwentyOnePregnantData{ List: list, Header: map[string]string{ "earNumber": "牛号", "lact": "胎次", "matingDateFormat": "配种日期", "matingTimes": "配次", "pregnantCheckDateFormat": "孕检日期", "isMating": "是否有胎", "abortionDateFormat": "流产日期", "departureDateFormat": "离场日期", "expectedProductionDateFormat": "预产日期", }, HeaderSort: []string{"earNumber", "lact", "matingDateFormat", "matingTimes", "pregnantCheckDateFormat", "isMating", "abortionDateFormat", "departureDateFormat", "expectedProductionDateFormat"}, }, }, nil }