123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- package backend
- import (
- "context"
- "fmt"
- "kpt-pasture/model"
- "kpt-pasture/util"
- "net/http"
- "sort"
- "time"
- "gitee.com/xuyiping_admin/pkg/xerr"
- pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
- )
- func (s *StoreEntry) PenBehavior(ctx context.Context, req *pasturePb.BarnBehaviorCurveRequest) (*pasturePb.BarnBehaviorCurveResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, err
- }
- if req.StartAt == 0 || req.EndAt == 0 || req.EndAt < req.StartAt {
- return nil, xerr.Customf("时间范围错误")
- }
- startTime := time.Unix(int64(req.StartAt), 0).Local().Format(model.LayoutDate2)
- endTime := time.Unix(int64(req.EndAt), 0).Local().Format(model.LayoutDate2)
- penBehaviorList := make([]*model.PenBehavior, 0)
- if err = s.DB.Model(new(model.PenBehavior)).
- Where("pasture_id = ?", userModel.AppPasture.Id).
- Where("pen_id = ?", req.PenId).
- Where("heat_date BETWEEN ? AND ?", startTime, endTime).
- Find(&penBehaviorList).Error; err != nil {
- return nil, err
- }
- return &pasturePb.BarnBehaviorCurveResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: model.PenBehaviorSlice(penBehaviorList).ToPB(),
- }, nil
- }
- func (s *StoreEntry) PenBehaviorDaily(ctx context.Context, req *pasturePb.BarnMonitorRequest) (*model.BarnMonitorResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- if req.StartAt == 0 || req.EndAt == 0 || req.EndAt < req.StartAt {
- return nil, xerr.Customf("时间范围错误")
- }
- startDate := time.Unix(int64(req.StartAt), 0).Local().Format(model.LayoutDate2)
- endDate := time.Unix(int64(req.EndAt), 0).Local().Format(model.LayoutDate2)
- dataTimeRange, err := util.GetDaysBetween(startDate, endDate)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- headers := make([]string, 0)
- if req.PenId <= 0 && req.BehaviorKind > 0 {
- penList, _ := s.GetPenList(ctx, userModel.AppPasture.Id)
- for _, v := range penList {
- headers = append(headers, v.Name)
- }
- } else {
- behaviorEnumList := s.Behavior("")
- for _, v := range behaviorEnumList {
- headers = append(headers, v.Label)
- }
- headers = append(headers, "方差")
- }
- penBehaviorDayModelList := make([]*model.PenBehaviorDayModel, 0)
- pref := s.DB.Model(new(model.PenBehaviorDay)).
- Select(`distinct(heat_date) as heat_date,pen_id,pen_name,rumina_std,cow_count,day_rumina,day_intake,
- day_inactive,day_milk,day_rumina+day_intake as day_chew,24*60 - day_active as day_immobility`).
- Where("pasture_id = ?", userModel.AppPasture.Id).
- Where("heat_date BETWEEN ? AND ?", startDate, endDate)
- if req.PenId <= 0 && req.BehaviorKind > 0 {
- if err = pref.Group("heat_date,pen_id").
- Order("heat_date,pen_id").
- Find(&penBehaviorDayModelList).Error; err != nil {
- return nil, xerr.WithStack(err)
- }
- } else {
- if err = pref.Where("pen_id = ?", req.PenId).
- Order("heat_date").
- Find(&penBehaviorDayModelList).Error; err != nil {
- return nil, xerr.WithStack(err)
- }
- }
- return &model.BarnMonitorResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: model.PenBehaviorDayModelSlice(penBehaviorDayModelList).ToPB(dataTimeRange, headers, req.BehaviorKind),
- }, err
- }
- func (s *StoreEntry) CowBehaviorDistribution(ctx context.Context, req *pasturePb.CowBehaviorDistributionRequest) (*pasturePb.CowBehaviorDistributionResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- // 校验时间必须比当天时间小一天
- if time.Now().Local().Format(model.LayoutDate2) == req.DateTime {
- return nil, xerr.Customf("时间范围错误")
- }
- milkDailList := make([]*model.MilkDaily, 0)
- pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.Cow).TableName())).
- Joins(fmt.Sprintf("JOIN %s AS b on a.id = b.cow_id", new(model.MilkDaily).TableName())).
- Select("b.*").
- Where("a.pasture_id = ?", userModel.AppPasture.Id).
- Where("a.neck_ring_number != ?", "").
- Where("a.sex = ?", pasturePb.Genders_Female).
- Where("b.heat_date = ? ", req.DateTime).
- Where("b.day_high > ?", 0)
- if len(req.PenIds) > 0 {
- pref.Where("a.pen_id IN (?)", req.PenIds)
- }
- if err = pref.Order("b.breed_status,b.lactation_age").
- Find(&milkDailList).Error; err != nil {
- return nil, xerr.WithStack(err)
- }
- // 未配 空怀 怀孕 配种
- data := &pasturePb.CowBehaviorDistributionItem{
- Headers: make([]string, 0),
- Color: make([]string, 0),
- MedianLine: make(map[string]float32),
- CalvingAge: make([]int32, 0),
- UnBreed: make([]*pasturePb.CowBehaviorData, 0),
- Breed: make([]*pasturePb.CowBehaviorData, 0),
- Pregnant: make([]*pasturePb.CowBehaviorData, 0),
- Empty: make([]*pasturePb.CowBehaviorData, 0),
- }
- breedStatus := s.BreedStatusEnumList()
- for _, v := range breedStatus {
- if v.Value == int32(pasturePb.BreedStatus_Abort) ||
- v.Value == int32(pasturePb.BreedStatus_Calving) ||
- v.Value == int32(pasturePb.BreedStatus_No_Mating) ||
- v.Value == int32(pasturePb.BreedStatus_Invalid) {
- continue
- }
- data.Headers = append(data.Headers, v.Label)
- switch v.Label {
- case "未配":
- data.Color = append(data.Color, "#b53827")
- case "空怀":
- data.Color = append(data.Color, "#2784b5")
- case "怀孕":
- data.Color = append(data.Color, "#2757b5")
- case "配种":
- data.Color = append(data.Color, "#27b560")
- }
- }
- if len(milkDailList) <= 0 {
- return &pasturePb.CowBehaviorDistributionResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: data,
- }, nil
- }
- for _, v := range milkDailList {
- dayData := int32(0)
- switch req.BehaviorKind {
- case pasturePb.Behavior_Rumina:
- dayData = v.DayRumina
- case pasturePb.Behavior_Intake:
- dayData = v.DayIntake
- case pasturePb.Behavior_Reset:
- dayData = v.DayInactive
- case pasturePb.Behavior_Immobility:
- dayData = 24*60 - v.DayActive
- case pasturePb.Behavior_Chew:
- dayData = v.DayRumina + v.DayIntake
- }
- switch v.BreedStatus {
- case pasturePb.BreedStatus_Calving:
- data.UnBreed = append(data.UnBreed, &pasturePb.CowBehaviorData{
- EarNumber: v.EarNumber,
- CalvingAge: v.LactationAge,
- DayData: dayData,
- })
- case pasturePb.BreedStatus_Empty:
- data.Empty = append(data.Empty, &pasturePb.CowBehaviorData{
- EarNumber: v.EarNumber,
- CalvingAge: v.LactationAge,
- DayData: dayData,
- })
- case pasturePb.BreedStatus_UnBreed:
- data.UnBreed = append(data.UnBreed, &pasturePb.CowBehaviorData{
- EarNumber: v.EarNumber,
- CalvingAge: v.LactationAge,
- DayData: dayData,
- })
- case pasturePb.BreedStatus_Breeding:
- data.Breed = append(data.Breed, &pasturePb.CowBehaviorData{
- EarNumber: v.EarNumber,
- CalvingAge: v.LactationAge,
- DayData: dayData,
- })
- case pasturePb.BreedStatus_Pregnant:
- data.Pregnant = append(data.Pregnant, &pasturePb.CowBehaviorData{
- EarNumber: v.EarNumber,
- CalvingAge: v.LactationAge,
- DayData: dayData,
- })
- }
- }
- // 获取Breed的中位数
- if len(data.Breed) > 0 {
- data.MedianLine["breed"] = float32(getMedian(data.Breed, func(p *pasturePb.CowBehaviorData) int {
- return int(p.DayData)
- }))
- }
- if len(data.Pregnant) > 0 {
- data.MedianLine["pregnant"] = float32(getMedian(data.Pregnant, func(p *pasturePb.CowBehaviorData) int {
- return int(p.DayData)
- }))
- }
- if len(data.Empty) > 0 {
- data.MedianLine["empty"] = float32(getMedian(data.Empty, func(p *pasturePb.CowBehaviorData) int {
- return int(p.DayData)
- }))
- }
- if len(data.UnBreed) > 0 {
- data.MedianLine["unBreed"] = float32(getMedian(data.UnBreed, func(p *pasturePb.CowBehaviorData) int {
- return int(p.DayData)
- }))
- }
- return &pasturePb.CowBehaviorDistributionResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: data,
- }, err
- }
- // 获取结构体切片中某个int字段的中位值
- func getMedian(dataList []*pasturePb.CowBehaviorData, getField func(*pasturePb.CowBehaviorData) int) float64 {
- // 1. 提取字段值
- values := make([]int, len(dataList))
- for i, p := range dataList {
- values[i] = getField(p)
- }
- // 2. 排序
- sort.Ints(values)
- // 3. 计算中位数
- n := len(values)
- if n == 0 {
- return 0
- }
- if n%2 == 1 {
- return float64(values[n/2])
- }
- return float64(values[n/2-1]+values[n/2]) / 2.0
- }
|