123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561 |
- package backend
- import (
- "context"
- "fmt"
- "kpt-pasture/model"
- "kpt-pasture/util"
- "net/http"
- "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"
- )
- // WeightScatterPlot 体重散点图 获取图表数据
- func (s *StoreEntry) WeightScatterPlot(ctx context.Context, req *pasturePb.SearchGrowthCurvesRequest) (*pasturePb.GrowthCurvesResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.Custom("当前用户信息错误,请退出重新登录")
- }
- // 查询数据
- cowList := make([]*model.Cow, 0)
- pref := s.DB.Model(new(model.Cow)).
- Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
- Where("pasture_id = ?", userModel.AppPasture.Id)
- if req.GetCowId() != "" {
- pref.Where("id IN ?", strings.Split(req.CowId, ","))
- }
- if len(req.BirthDate) == 2 && req.BirthDate[0] != "" && req.BirthDate[1] != "" {
- t0, _ := time.Parse(time.RFC3339, req.BirthDate[0])
- t1, _ := time.Parse(time.RFC3339, req.BirthDate[1])
- pref.Where("birth_at BETWEEN ? AND ?", t0.Unix(), t1.Unix()+86399)
- }
- if err = pref.Find(&cowList).Error; err != nil {
- return nil, err
- }
- penList, err := s.GetPenList(ctx, userModel.AppPasture.Id)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- // 计算图表数据
- chartsList := &pasturePb.Charts{
- CowId: make([]int32, 0),
- Weight: make([]float32, 0),
- AdmissionAge: make([]int32, 0),
- }
- cowData := make([]*pasturePb.CowList, 0)
- for _, cow := range cowList {
- currentWeight := float32(cow.CurrentWeight) / 1000
- penName := ""
- for _, v := range penList {
- if cow.PenId != v.Id {
- continue
- }
- penName = v.Name
- }
- cowData = append(cowData, &pasturePb.CowList{
- CowId: int32(cow.Id),
- EarNumber: cow.EarNumber,
- DayAge: cow.GetDayAge(),
- PenName: penName,
- CurrentWeight: currentWeight,
- BirthAt: int32(cow.BirthAt),
- BirthWeight: float32(cow.BirthWeight) / 1000,
- LastWeightAt: int32(cow.LastWeightAt),
- DailyWeightGain: float32(cow.GetDayWeight() / 1000),
- AverageDailyWeightGain: float32(cow.GetAverageDailyWeight() / 1000),
- AdmissionAge: cow.GetAdmissionAge(),
- })
- chartsList.CowId = append(chartsList.CowId, int32(cow.Id))
- chartsList.Weight = append(chartsList.Weight, currentWeight)
- chartsList.AdmissionAge = append(chartsList.AdmissionAge, cow.GetAdmissionAge())
- }
- // 返回数据
- return &pasturePb.GrowthCurvesResponse{
- Code: http.StatusOK,
- Msg: "success",
- Data: &pasturePb.GrowthCurveData{
- Table: cowData,
- Charts: chartsList,
- },
- }, nil
- }
- func (s *StoreEntry) WeightRange(ctx context.Context, req *pasturePb.WeightRangeRequest) (*pasturePb.WeightRangeResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- cowWeightRange := make([]*model.CowWeightRange, 0)
- prefix := s.DB.Model(new(model.Cow)).
- Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
- Where("pasture_id = ?", userModel.AppPasture.Id)
- if req.CowKind > 0 {
- prefix.Where("cow_kind = ?", req.CowKind)
- }
- if err = prefix.Select(`
- CASE
- WHEN current_weight BETWEEN 0 AND 50000 THEN '0-50'
- WHEN current_weight BETWEEN 50001 AND 100000 THEN '51-100'
- WHEN current_weight BETWEEN 100001 AND 150000 THEN '101-150'
- WHEN current_weight BETWEEN 150001 AND 200000 THEN '151-200'
- WHEN current_weight BETWEEN 200001 AND 250000 THEN '201-250'
- WHEN current_weight BETWEEN 250001 AND 300000 THEN '251-300'
- WHEN current_weight BETWEEN 300001 AND 350000 THEN '301-350'
- WHEN current_weight BETWEEN 350001 AND 400000 THEN '351-400'
- WHEN current_weight BETWEEN 400001 AND 450000 THEN '401-450'
- WHEN current_weight BETWEEN 450001 AND 500000 THEN '451-500'
- WHEN current_weight BETWEEN 500001 AND 550000 THEN '500-550'
- WHEN current_weight BETWEEN 550001 AND 600000 THEN '551-600'
- WHEN current_weight BETWEEN 600001 AND 650000 THEN '601-650'
- WHEN current_weight BETWEEN 650001 AND 700000 THEN '651-700'
- WHEN current_weight BETWEEN 700001 AND 750000 THEN '701-750'
- ELSE '750+'
- END AS weight_range,
- COUNT(*) AS count `,
- ).Group("weight_range").Order("MIN(current_weight)").Find(&cowWeightRange).Error; err != nil {
- return nil, err
- }
- if len(cowWeightRange) == 0 {
- return &pasturePb.WeightRangeResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.WeightRangeData{
- CowList: make([]*pasturePb.CowList, 0),
- WeightBarChart: &pasturePb.WeightBarChart{
- Header: make([]string, 0),
- Data: make([]int32, 0),
- },
- },
- }, nil
- }
- header := make([]string, 0)
- data := make([]int32, 0)
- for _, v := range cowWeightRange {
- header = append(header, v.WeightRange)
- data = append(data, v.Count)
- }
- // 牛只详情列表
- pref := s.DB.Model(new(model.Cow)).
- Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
- Where("pasture_id = ?", userModel.AppPasture.Id)
- if req.CowKind > 0 {
- pref.Where("cow_kind = ?", req.CowKind)
- }
- cowList := make([]*model.Cow, 0)
- if req.MinWeight >= 0 && req.MaxWeight >= 0 && req.MinWeight < req.MaxWeight {
- pref.Where("current_weight BETWEEN ? AND ? ", req.MinWeight*1000, req.MaxWeight*1000)
- }
- if err = pref.Find(&cowList).Error; err != nil {
- return nil, err
- }
- penMap := s.PenMap(ctx, userModel.AppPasture.Id)
- return &pasturePb.WeightRangeResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.WeightRangeData{
- CowList: model.CowSlice(cowList).WeightRangeToPB(penMap),
- WeightBarChart: &pasturePb.WeightBarChart{
- Header: header,
- Data: data,
- },
- },
- }, nil
- }
- func (s *StoreEntry) MatingTimely(ctx context.Context, req *pasturePb.MatingTimelyRequest) (*model.MatingTimelyResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- matingTimelyChart := make([]*model.MatingTimelyChart, 0)
- pastureWhereSql := fmt.Sprintf(" AND pasture_id = %d", userModel.AppPasture.Id)
- sql := `SELECT calving_age,cow_type, DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') AS reality_day, lact_group
- FROM (
- SELECT calving_age, cow_type,reality_day, '0' AS lact_group
- FROM event_mating
- WHERE lact = 0 AND status = 1 ` + pastureWhereSql + `
- UNION ALL
- SELECT calving_age,cow_type, reality_day, '1' AS lact_group
- FROM event_mating
- WHERE lact = 1 AND status = 1 ` + pastureWhereSql + `
- UNION ALL
- SELECT calving_age,cow_type, reality_day, '2' AS lact_group
- FROM event_mating
- WHERE lact = 2 AND status = 1 ` + pastureWhereSql + `
- UNION ALL
- SELECT calving_age, cow_type, reality_day, '3+' AS lact_group
- FROM event_mating
- WHERE lact >= 3 AND status = 1 ` + pastureWhereSql + `
- ) AS subquery WHERE 1 = 1 `
- whereSql := ""
- if req.CowType > 0 {
- whereSql += fmt.Sprintf("AND cow_type = %d ", req.CowType)
- }
- if req.StartDayAt > 0 && req.EndDayAt > 0 {
- whereSql += fmt.Sprintf("AND reality_day BETWEEN %d AND %d", req.StartDayAt, req.EndDayAt)
- }
- if err = s.DB.Raw(fmt.Sprintf("%s %s", sql, whereSql)).Find(&matingTimelyChart).Error; err != nil {
- return nil, err
- }
- chart := &model.CowMatingChart{
- Lact0: make([][]string, 0),
- Lact1: make([][]string, 0),
- Lact2: make([][]string, 0),
- Lact3: make([][]string, 0),
- }
- if len(matingTimelyChart) == 0 {
- return &model.MatingTimelyResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &model.MatingTimelyData{
- CowList: make([]*pasturePb.CowList, 0),
- Chart: chart,
- },
- }, nil
- }
- for _, v := range matingTimelyChart {
- t, _ := time.Parse(model.LayoutDate2, v.RealityDay)
- switch v.LactGroup {
- case "0":
- chart.Lact0 = append(chart.Lact0, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
- case "1":
- chart.Lact1 = append(chart.Lact1, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
- case "2":
- chart.Lact2 = append(chart.Lact2, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
- case "3+":
- chart.Lact3 = append(chart.Lact3, []string{fmt.Sprintf("%d", t.Day()), fmt.Sprintf("%d", v.CalvingAge), v.RealityDay})
- }
- }
- // 牛只详情列表
- eventMatingList := make([]*model.EventMating, 0)
- pref := s.DB.Model(new(model.EventMating)).
- Where("status = ?", pasturePb.IsShow_Ok)
- if req.CowType > 0 {
- pref.Where("cow_type = ?", req.CowType)
- }
- if req.StartDayAt > 0 && req.EndDayAt > 0 {
- pref.Where("reality_day BETWEEN ? AND ?", req.StartDayAt, req.EndDayAt)
- }
- if err = pref.Find(&eventMatingList).Error; err != nil {
- return nil, err
- }
- return &model.MatingTimelyResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &model.MatingTimelyData{
- CowList: model.EventMatingSlice(eventMatingList).ToPB2(),
- Chart: chart,
- },
- }, nil
- }
- func (s *StoreEntry) PenWeight(ctx context.Context, req *pasturePb.PenWeightRequest, pagination *pasturePb.PaginationModel) (*pasturePb.PenWeightResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- penWeightList := make([]*model.PenWeight, 0)
- pref := s.DB.Model(new(model.Cow)).
- Select(`
- pen_id,
- CEILING(AVG(current_weight) / 1000 ) AS avg_weight,
- CEILING(SUM(current_weight) / 1000 ) AS all_weight,
- COUNT(*) AS cow_count`,
- ).
- Where("pasture_id = ?", userModel.AppPasture.Id).
- Where("admission_status = ?", pasturePb.AdmissionStatus_Admission)
- if len(req.PenId) > 0 && req.BarId <= 0 {
- pref.Where("pen_id IN ?", req.PenId)
- }
- if err = pref.Group("pen_id").
- Order("pen_id").
- Find(&penWeightList).Error; err != nil {
- return nil, err
- }
- chart := &pasturePb.PenWeightChart{
- Header: make([]string, 0),
- AllWeight: make([]int32, 0),
- AvgWeight: make([]int32, 0),
- CowCount: make([]int32, 0),
- }
- if len(penWeightList) <= 0 {
- return &pasturePb.PenWeightResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.PenWeightData{
- CowList: make([]*pasturePb.CowList, 0),
- Chart: chart,
- },
- }, nil
- }
- cowList := make([]*model.Cow, 0)
- var count int64 = 0
- prefList := s.DB.Model(new(model.Cow)).
- Where("admission_status = ?", pasturePb.AdmissionStatus_Admission)
- if len(req.PenId) <= 0 && req.BarId > 0 {
- prefList.Where("pen_id IN ?", []int32{req.BarId})
- } else {
- prefList.Where("pen_id IN ?", req.PenId)
- }
- if err = prefList.Count(&count).Limit(int(pagination.PageSize)).
- Offset(int(pagination.PageOffset)).Order("pen_id").
- Find(&cowList).Error; err != nil {
- return nil, xerr.WithStack(err)
- }
- penMap := s.PenMap(ctx, userModel.AppPasture.Id)
- return &pasturePb.PenWeightResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.PenWeightData{
- CowList: model.CowSlice(cowList).ToPB2(penMap, penWeightList),
- Total: int32(count),
- Page: pagination.Page,
- PageSize: pagination.PageSize,
- Chart: model.PenWeightSlice(penWeightList).ToPB(penMap),
- },
- }, nil
- }
- func (s *StoreEntry) AbortionRate(ctx context.Context, req *pasturePb.AbortionRateRequest) (*pasturePb.AbortionRateResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- dayTimeList, err := util.GetMonthsInRange(req.StartDayTime, req.EndDayTime)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- lastDayForMonth := make([]string, 0)
- for _, v := range dayTimeList {
- lastDayTime, _ := util.GetLastDayOfMonth(v)
- lastDayForMonth = append(lastDayForMonth, lastDayTime)
- }
- // 历史每月怀孕牛头数量
- cowPregnantMonthList := make([]*model.CowPregnantMonth, 0)
- pref := s.DB.Model(new(model.EventMating)).
- Select(`
- COUNT(cow_id) AS cow_count,
- DATE_FORMAT(FROM_UNIXTIME(reality_day),'%Y-%m') as month`,
- ).Where("cow_type = ?", req.CowType).
- Where("pasture_id = ?", userModel.AppPasture.Id).
- Where("status = ?", pasturePb.IsShow_Ok).
- Where("mating_result = ?", pasturePb.MatingResult_Pregnant).
- Where("DATE_FORMAT(FROM_UNIXTIME(`reality_day`),'%Y-%m-%d') IN ?", lastDayForMonth)
- if req.Lact >= 0 && req.Lact <= 3 {
- pref.Where("lact = ?", req.Lact)
- } else {
- pref.Where("lact > ?", req.Lact)
- }
- if err = pref.Group("month").
- Find(&cowPregnantMonthList).Error; err != nil {
- return nil, xerr.WithStack(err)
- }
- // 历史每月流产牛头数量
- cowAbortionMonthList := make([]*model.CowPregnantMonth, 0)
- pref2 := s.DB.Model(new(model.EventAbortion)).
- Select(`
- COUNT(cow_id) AS cow_count,
- DATE_FORMAT(FROM_UNIXTIME(abortion_at),'%Y-%m') as month`,
- ).Where("cow_type = ?", req.CowType).
- Where("DATE_FORMAT(FROM_UNIXTIME(abortion_at),'%Y-%m') IN ?", dayTimeList)
- if req.Lact >= 0 {
- pref2.Where("lact = ?", req.Lact)
- }
- if err = pref2.Group("month").Find(&cowAbortionMonthList).Error; err != nil {
- return nil, xerr.WithStack(err)
- }
- chart := &pasturePb.AbortionRateChart{
- Header: make([]string, 0),
- AbortionCountMonth: make([]int32, 0),
- PregnantCountMonth: make([]int32, 0),
- AbortionRateMonth: make([]float32, 0),
- }
- table := make([]*pasturePb.AbortionRateTable, 0)
- for _, v2 := range cowAbortionMonthList {
- pregnantCountMonth := int32(0)
- for _, v := range cowPregnantMonthList {
- if v.Month == v2.Month {
- pregnantCountMonth = v.CowCount
- }
- }
- abortionRateMonth := float64(0)
- if pregnantCountMonth > 0 && v2.CowCount > 0 {
- abortionRateMonth = util.RoundToTwoDecimals(float64(v2.CowCount) / float64(pregnantCountMonth) * 100)
- }
- chart.Header = append(chart.Header, v2.Month)
- chart.AbortionCountMonth = append(chart.AbortionCountMonth, v2.CowCount)
- chart.PregnantCountMonth = append(chart.PregnantCountMonth, pregnantCountMonth)
- chart.AbortionRateMonth = append(chart.AbortionRateMonth, float32(abortionRateMonth))
- table = append(table, &pasturePb.AbortionRateTable{
- AbortionCount: v2.CowCount,
- MonthName: v2.Month,
- PregnantCount: pregnantCountMonth,
- AbortionRate: float32(abortionRateMonth),
- })
- }
- return &pasturePb.AbortionRateResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.AbortionRateData{
- Chart: chart,
- Table: table,
- },
- }, nil
- }
- 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()
- 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, systemBasicName)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- stopBreedingDay := systemBasic.MinValue * 86400
- dateCowList := make([][]*model.Cow, len(dataRange))
- twentyOnePregnantRateList := make([]*pasturePb.TwentyOnePregnantRateList, 0)
- for i, v := range dataRange {
- middleDay, err := util.GetRangeDayMiddleDay(v, 11)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- middleDayUnix := util.TimeParseLocalEndUnix(middleDay)
- chart.Header = append(chart.Header, fmt.Sprintf("%s ~ %s", v[0], v[1]))
- cowList := s.TwentyOnePregnantCowList(userModel.AppPasture.Id, req.CowType, stopBreedingDay, middleDayUnix, []int64{})
- twentyOnePregnantRateList = append(twentyOnePregnantRateList, &pasturePb.TwentyOnePregnantRateList{
- StartDay: v[0],
- EndDay: v[1],
- ShouldBreedCount: int32(len(cowList)),
- RealityBreedCount: 0,
- BreedRate: 0,
- ShouldPregnantCount: 0,
- RealityPregnantCount: 0,
- PregnantRate: 0,
- RealityAbortionCount: 0,
- AbortionRate: 0,
- })
- dateCowList[i] = cowList
- }
- return &pasturePb.TwentyOnePregnantRateResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.TwentyOnePregnantRateData{
- Chart: chart,
- Table: &pasturePb.TwentyOnePregnantRateTable{
- List: twentyOnePregnantRateList,
- Total: int32(len(dataRange)),
- },
- },
- }, nil
- }
- // TwentyOnePregnantCowList 21天牛只停配期牛只列表
- func (s *StoreEntry) TwentyOnePregnantCowList(
- pastureId int64,
- cowType pasturePb.CowType_Kind,
- stopBreedingDay int32,
- middleDay int64,
- notInCow []int64,
- ) []*model.Cow {
- cowList := make([]*model.Cow, 0)
- switch cowType {
- case pasturePb.CowType_Reserve_Calf:
- pref := s.DB.Model(new(model.Cow)).
- Where("pasture_id = ?", pastureId).
- Where("cow_type = ?", cowType).
- Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
- Where("is_pregnant = ?", pasturePb.IsShow_No).
- Where("lact = ?", 0).
- Where("birth_at + ? < ?", stopBreedingDay, middleDay)
- if len(notInCow) > 0 {
- pref = pref.Where("id NOT IN ?", notInCow)
- }
- if err := pref.Find(&cowList).Error; err != nil {
- zaplog.Error("TwentyOnePregnantCowList",
- zap.Any("cowType", cowType),
- zap.Any("stopBreedingDay", stopBreedingDay),
- zap.Any("middleDay", middleDay),
- zap.Any("notInCow", notInCow),
- )
- }
- case pasturePb.CowType_Breeding_Calf:
- }
- return cowList
- }
|