package model import ( "fmt" "kpt-pasture/util" "math" "time" pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow" ) type Cow struct { Id int64 `json:"id"` PastureId int64 `json:"pastureId"` // 牧场id Sex pasturePb.Genders_Kind `json:"sex"` // 性别 NeckRingNumber string `json:"neckRingNumber"` // 脖环号 EarNumber string `json:"earNumber"` // 耳标号 EarOldNumber string `json:"earOldNumber"` // 旧耳标号 PenId int32 `json:"penId"` // 栏舍id PenName string `json:"penName"` // 栏舍名称 Lact int32 `json:"lact"` // 胎次 DayAge int32 `json:"dayAge"` // 日龄 CalvingAge int32 `json:"calvingAge"` // 产后天使 PregnancyAge int32 `json:"pregnancyAge"` // 怀孕天数 孕检结果有阳性更新,产犊后至0 AdmissionAge int32 `json:"admissionAge"` // 入场日龄 AbortionAge int32 `json:"abortionAge"` // 流产天数 CowType pasturePb.CowType_Kind `json:"cowType"` // 牛只类型 BreedStatus pasturePb.BreedStatus_Kind `json:"breedStatus"` // 繁殖状态 CowKind pasturePb.CowKind_Kind `json:"cowKind"` // 牛只品种 BirthWeight int64 `json:"birthWeight"` // 出生体重 CurrentWeight int64 `json:"currentWeight"` // 当前体重 AdmissionWeight int64 `json:"admissionWeight"` // 入场体重 SourceId pasturePb.CowSource_Kind `json:"sourceId"` // 来源哪里 FatherNumber string `json:"fatherNumber"` // 父号 MotherNumber string `json:"motherNumber"` // 母号 AdmissionStatus pasturePb.AdmissionStatus_Kind `json:"admissionStatus"` // 在场状态 IsPregnant pasturePb.IsShow_Kind `json:"isPregnant"` // 是否怀孕 HealthStatus pasturePb.HealthStatus_Kind `json:"healthStatus"` // 健康状态 WeaningAt int64 `json:"weaningAt"` // 断奶时间 BirthAt int64 `json:"birthAt"` // 出生时间 AdmissionAt int64 `json:"admissionAt"` // 入场时间 DepartureAt int64 `json:"departureAt"` // 离场时间 FirstMatingAt int64 `json:"firstMatingAt"` // 首次配种时间 MatingTimes int32 `json:"matingTimes"` // 配种次数 AbortionTimes int32 `json:"abortionTimes"` // 流产次数 WeeklyActive int32 `json:"weeklyActive"` // 每周活跃度 LastEstrusAt int64 `json:"lastEstrusAt"` // 最后一次发情时间 LastCalvingAt int64 `json:"lastCalvingAt"` // 最后一次产犊时间 LastMatingAt int64 `json:"lastMatingAt"` // 最后一次配种时间 LastBullNumber string `json:"lastBullNumber"` // 最后一次配种牛号 LastPregnantCheckAt int64 `json:"lastPregnantCheckAt"` // 最后一次孕检时间 LastDryMilkAt int64 `json:"lastDryMilkAt"` // 最近一次干奶日期 LastSecondWeight int64 `json:"lastSecondWeight"` // 最后第二次称重 LastSecondWeightAt int64 `json:"lastSecondWeightAt"` // 最后第二次称重时间 LastAbortionAt int64 `json:"lastAbortionAt"` // 最近一次流产时间 LastWeightAt int64 `json:"lastWeightAt"` // 最近一次称重时间 CreatedAt int64 `json:"createdAt"` UpdatedAt int64 `json:"updatedAt"` } func (c *Cow) TableName() string { return "cow" } func (c *Cow) EventInfoUpdate() { c.DayAge = c.GetDayAge() c.CalvingAge = c.GetCalvingAge() c.PregnancyAge = c.GetDaysPregnant() c.AdmissionAge = c.GetAdmissionAge() c.AbortionAge = c.GetAbortionAge() if c.DayAge == 60 { c.CowType = pasturePb.CowType_Weaned_Calf } } // EventCalvingUpdate 产犊更新 func (c *Cow) EventCalvingUpdate(calvingAt int64) { c.Lact += 1 c.MatingTimes = 0 c.PregnancyAge = 0 c.AbortionTimes = 0 c.BreedStatus = pasturePb.BreedStatus_Calving c.IsPregnant = pasturePb.IsShow_No c.LastCalvingAt = calvingAt c.CalvingAge = c.GetCalvingAge() c.CowType = pasturePb.CowType_Breeding_Calf } // EventWeaningUpdate 断奶更新 func (c *Cow) EventWeaningUpdate(weaningAt int64, penId int32, currentWeight int64) { c.PenId = penId c.WeaningAt = weaningAt c.CurrentWeight = currentWeight c.LastWeightAt = weaningAt } // EventPregnantCheckUpdate 孕检更新 func (c *Cow) EventPregnantCheckUpdate(breedStatus pasturePb.BreedStatus_Kind, pregnantCheckAt int64, isPregnant pasturePb.IsShow_Kind) { c.BreedStatus = breedStatus c.LastPregnantCheckAt = pregnantCheckAt c.IsPregnant = isPregnant } // EventAbortionUpdate 流产更新 func (c *Cow) EventAbortionUpdate(abortionAt int64) { c.IsPregnant = pasturePb.IsShow_No c.LastAbortionAt = abortionAt c.BreedStatus = pasturePb.BreedStatus_Abort c.AbortionTimes += 1 } // EventWeightUpdate 称重更新 func (c *Cow) EventWeightUpdate(weight int64, weightAt int64) { c.LastSecondWeight = c.CurrentWeight c.LastSecondWeightAt = c.LastWeightAt c.LastWeightAt = weightAt c.CurrentWeight = weight } // EventHealthStatusUpdate 健康状态更新 func (c *Cow) EventHealthStatusUpdate(healthStatus pasturePb.HealthStatus_Kind) { c.HealthStatus = healthStatus } // EventPenUpdate 更新栏舍 func (c *Cow) EventPenUpdate(pen *Pen) { c.PenId = pen.Id c.PenName = pen.Name } // EventEarNumberUpdate 更新耳标号 func (c *Cow) EventEarNumberUpdate(newEarNumber string) { c.EarOldNumber = c.EarNumber c.EarNumber = newEarNumber } // EventDepartureUpdate 更新牛只离场信息 func (c *Cow) EventDepartureUpdate(departureAt int64, departureType pasturePb.DepartureType_Kind) { if departureType == pasturePb.DepartureType_Death { c.AdmissionStatus = pasturePb.AdmissionStatus_Die c.HealthStatus = pasturePb.HealthStatus_Dead } if departureType == pasturePb.DepartureType_Out { c.AdmissionStatus = pasturePb.AdmissionStatus_Out c.HealthStatus = pasturePb.HealthStatus_Out } c.DepartureAt = departureAt } // EventMatingUpdate 配种更新 func (c *Cow) EventMatingUpdate(matingAt int64, bullNumber string, isReMating bool) { c.LastMatingAt = matingAt if c.FirstMatingAt <= 0 { c.FirstMatingAt = matingAt } c.LastBullNumber = bullNumber c.IsPregnant = pasturePb.IsShow_No c.BreedStatus = pasturePb.BreedStatus_Breeding if !isReMating { c.MatingTimes += 1 } } type CowSlice []*Cow func (c CowSlice) ToPB( penMap map[int32]*Pen, cowTypeMap map[pasturePb.CowType_Kind]string, breedStatusMap map[pasturePb.BreedStatus_Kind]string, cowKindMap map[pasturePb.CowKind_Kind]string, cowSourceMap map[pasturePb.CowSource_Kind]string, admissionStatusMap map[pasturePb.AdmissionStatus_Kind]string, healthStatusMap map[pasturePb.HealthStatus_Kind]string, ) []*pasturePb.CowDetails { res := make([]*pasturePb.CowDetails, len(c)) for i, v := range c { penName := "" if pen, ok := penMap[v.PenId]; ok { penName = pen.Name } sex := "公" if v.Sex == pasturePb.Genders_Female { sex = "母" } lastWeightAtFormat := "" if v.LastWeightAt > 0 { lastWeightAtFormat = time.Unix(v.LastWeightAt, 0).Format(LayoutDate2) } isPregnantName := "" if v.IsPregnant == pasturePb.IsShow_Ok { isPregnantName = "已孕" } else { isPregnantName = "未孕" } admissionAtFormat := "" if v.AdmissionAt > 0 { admissionAtFormat = time.Unix(v.AdmissionAt, 0).Format(LayoutDate2) } birthAtFormat := "" if v.BirthAt > 0 { birthAtFormat = time.Unix(v.BirthAt, 0).Format(LayoutDate2) } weaningAtFormat := "" if v.WeaningAt > 0 { weaningAtFormat = time.Unix(v.WeaningAt, 0).Format(LayoutDate2) } firstMatingAtFormat := "" if v.FirstMatingAt > 0 { firstMatingAtFormat = time.Unix(v.FirstMatingAt, 0).Format(LayoutDate2) } lastMatingAtFormat := "" if v.LastMatingAt > 0 { lastMatingAtFormat = time.Unix(v.LastMatingAt, 0).Format(LayoutDate2) } lastPregnantCheckAtFormat := "" if v.LastPregnantCheckAt > 0 { lastPregnantCheckAtFormat = time.Unix(v.LastPregnantCheckAt, 0).Format(LayoutDate2) } lastCalvingAtFormat := "" if v.LastCalvingAt > 0 { lastCalvingAtFormat = time.Unix(v.LastCalvingAt, 0).Format(LayoutDate2) } lastAbortionAtFormat := "" if v.LastAbortionAt > 0 { lastAbortionAtFormat = time.Unix(v.LastAbortionAt, 0).Format(LayoutDate2) } lastSecondWeightAtFormat := "" if v.LastSecondWeightAt > 0 { lastSecondWeightAtFormat = time.Unix(v.LastSecondWeightAt, 0).Format(LayoutDate2) } res[i] = &pasturePb.CowDetails{ CowId: int32(v.Id), Sex: sex, NeckRingNumber: v.NeckRingNumber, PenName: penName, Lact: v.Lact, CowTypeName: cowTypeMap[v.CowType], BreedStatusName: breedStatusMap[v.BreedStatus], CowKindName: cowKindMap[v.CowKind], EarNumber: v.EarNumber, BirthWeight: float32(v.BirthWeight) / 1000, CurrentWeight: float32(v.CurrentWeight) / 1000, DayAge: v.DayAge, SourceName: cowSourceMap[v.SourceId], MotherNumber: v.MotherNumber, FatherNumber: v.FatherNumber, AdmissionStatusName: admissionStatusMap[v.AdmissionStatus], HealthStatusName: healthStatusMap[v.HealthStatus], IsPregnantName: isPregnantName, AdmissionAtFormat: admissionAtFormat, BirthAtFormat: birthAtFormat, WeaningAtFormat: weaningAtFormat, CalvingAge: v.GetCalvingAge(), AbortionAge: v.AbortionAge, MatingTimes: v.MatingTimes, FirstMatingAtFormat: firstMatingAtFormat, LastMatingAtFormat: lastMatingAtFormat, LastBullNumber: v.LastBullNumber, LastPregnantCheckAtFormat: lastPregnantCheckAtFormat, LastWeightAtFormat: lastWeightAtFormat, LastCalvingAtFormat: lastCalvingAtFormat, LastAbortionAtFormat: lastAbortionAtFormat, LastSecondWeight: float32(v.LastSecondWeight) / 1000, LastSecondWeightAtFormat: lastSecondWeightAtFormat, } } return res } func (c CowSlice) ToPB2(penMap map[int32]*Pen, penWeightSlice PenWeightSlice) []*pasturePb.CowList { res := make([]*pasturePb.CowList, len(c)) for i, v := range c { penName := "" if pen, ok := penMap[v.PenId]; ok { penName = pen.Name } penWeight := penWeightSlice.GetPenWeight(v.PenId) lastWeightDay := util.Ceil(float64(v.LastWeightAt-v.LastSecondWeightAt) / 86400) penAvgWeight := float32(0) previousStageDailyWeight := float32(0) cowPenAvgWeightDiffValue := float32(0) if penWeight != nil { penAvgWeight = float32(penWeight.AvgWeight) / 1000 cowPenAvgWeightDiffValue = float32(v.CurrentWeight-int64(penWeight.AvgWeight)) / 1000 if lastWeightDay > 0 { previousStageDailyWeight = float32(v.CurrentWeight-v.LastSecondWeight) / 1000 / float32(lastWeightDay) } } res[i] = &pasturePb.CowList{ CowId: int32(v.Id), DayAge: v.DayAge, DailyWeightGain: float32(v.GetDayWeight()), AverageDailyWeightGain: float32(v.GetAverageDailyWeight()), EarNumber: v.EarNumber, PenName: penName, BirthAt: int32(v.BirthAt), BirthWeight: float32(v.BirthWeight) / 1000, CurrentWeight: float32(v.CurrentWeight) / 1000, LastWeightAt: int32(v.LastWeightAt), AdmissionAge: v.AdmissionAge, AdmissionWeight: float32(v.AbortionAge) / 1000, PreviousStageDailyWeight: previousStageDailyWeight, PenAvgWeight: penAvgWeight, CowPenAvgWeightDiffValue: cowPenAvgWeightDiffValue, } } return res } func NewCow(pastureId int64, req *pasturePb.EventEnterRequest, penMap map[int32]*Pen) *Cow { var isPregnant = pasturePb.IsShow_No if req.BreedStatus == pasturePb.BreedStatus_Pregnant { isPregnant = pasturePb.IsShow_Ok } admissionAt := int64(0) switch req.CowSource { case pasturePb.CowSource_Calving: admissionAt = int64(req.BirthAt) case pasturePb.CowSource_Transfer_In: admissionAt = int64(req.EnterAt) case pasturePb.CowSource_Buy: admissionAt = int64(req.EnterAt) } return &Cow{ PastureId: pastureId, Sex: req.Sex, EarNumber: req.EarNumber, PenId: req.PenId, PenName: penMap[req.PenId].Name, Lact: req.Lact, CowType: req.CowType, BreedStatus: req.BreedStatus, CowKind: req.CowKind, SourceId: req.CowSource, FatherNumber: req.FatherNumber, MotherNumber: req.MotherNumber, AdmissionStatus: pasturePb.AdmissionStatus_Admission, HealthStatus: pasturePb.HealthStatus_Health, IsPregnant: isPregnant, WeaningAt: int64(req.WeaningAt), BirthAt: int64(req.BirthAt), AdmissionWeight: int64(req.Weight * 1000), FirstMatingAt: int64(req.MatingAt), LastMatingAt: int64(req.MatingAt), LastPregnantCheckAt: int64(req.PregnancyCheckAt), AdmissionAt: admissionAt, BirthWeight: int64(req.Weight * 1000), LastWeightAt: int64(req.EstrusAt), CurrentWeight: int64(req.Weight * 1000), } } func NewCalfCow(motherNumber, fatherNumber string, calf *CalvingCalf) *Cow { return &Cow{ PastureId: calf.PastureId, Sex: calf.Sex, EarNumber: calf.EarNumber, PenId: calf.PenId, PenName: calf.PenName, CowType: pasturePb.CowType_Lactating_Calf, // 哺乳犊牛 BreedStatus: pasturePb.BreedStatus_UnBreed, // 未配 CowKind: calf.CowKind, // 牛只品种 BirthWeight: calf.BirthWeight, BirthAt: calf.BirthAt, SourceId: pasturePb.CowSource_Calving, // 产犊方式 FatherNumber: fatherNumber, MotherNumber: motherNumber, AdmissionStatus: pasturePb.AdmissionStatus_Admission, IsPregnant: pasturePb.IsShow_No, AdmissionAt: calf.BirthAt, } } type BarCowStruct struct { Number int32 `json:"number"` TypeId pasturePb.CowType_Kind `json:"type_id"` } // BarCowStructSlice 首页牛群结构 type BarCowStructSlice []*BarCowStruct func (b BarCowStructSlice) ToPB(cowTypeMap map[pasturePb.CowType_Kind]string, count int32) []*pasturePb.BarCowStruct { var pb []*pasturePb.BarCowStruct for _, v := range b { name := fmt.Sprintf("%s", cowTypeMap[v.TypeId]) pb = append(pb, &pasturePb.BarCowStruct{Name: name, Value: v.Number}) } return pb } // GetDayAge 日龄 func (c *Cow) GetDayAge() int32 { if c.BirthAt <= 0 { return 0 } return int32(math.Floor(float64(time.Now().Unix()-c.BirthAt) / 86400)) } // GetCalvingAge 产后天数 func (c *Cow) GetCalvingAge() int32 { if c.LastCalvingAt <= 0 { return 0 } return int32(math.Floor(float64(time.Now().Unix()-c.LastCalvingAt) / 86400)) } // GetDaysPregnant 怀孕天数 func (c *Cow) GetDaysPregnant() int32 { if c.BreedStatus == pasturePb.BreedStatus_Pregnant && c.AdmissionStatus == pasturePb.AdmissionStatus_Admission && c.IsPregnant == pasturePb.IsShow_Ok { return int32(math.Floor(float64(time.Now().Unix()-c.LastMatingAt) / 86400)) } return 0 } // GetLactationDays 泌乳天数 func (c *Cow) GetLactationDays() int32 { if c.BreedStatus == pasturePb.BreedStatus_Calving && c.AdmissionStatus == pasturePb.AdmissionStatus_Admission { return int32(math.Floor(float64(time.Now().Unix()-c.LastCalvingAt) / 86400)) } return 0 } // GetAdmissionAge 入场天数 func (c *Cow) GetAdmissionAge() int32 { if c.AdmissionAt > 0 && c.AdmissionStatus == pasturePb.AdmissionStatus_Admission { return int32(math.Floor(float64(time.Now().Unix()-c.AdmissionAt) / 86400)) } return 0 } // GetDayWeight 日增重 func (c *Cow) GetDayWeight() float64 { if c.CurrentWeight-c.LastSecondWeight > 0 && c.LastWeightAt > c.LastSecondWeightAt { days := int32(math.Floor(float64(c.LastWeightAt-c.LastSecondWeightAt) / 86400)) if days <= 0 { return float64(c.CurrentWeight - c.LastSecondWeight) } dayWeight := math.Round(1.0 * float64(c.CurrentWeight-c.LastSecondWeight) / float64(days)) return dayWeight / 1000 } return 0 } // GetAverageDailyWeight 平均日增重 func (c *Cow) GetAverageDailyWeight() float64 { if c.CurrentWeight-c.BirthWeight > 0 && c.LastWeightAt > c.BirthAt { days := int32(math.Floor(float64(c.LastWeightAt-c.BirthAt) / 86400)) if days <= 0 { return 0 } dailyWeight := math.Round(1.0 * float64(c.CurrentWeight-c.BirthWeight) / float64(days)) return dailyWeight / 1000 } return 0 } func (c *Cow) GetAbortionAge() int32 { if c.LastAbortionAt > 0 && c.AdmissionStatus == pasturePb.AdmissionStatus_Admission { return int32(math.Floor(float64(time.Now().Unix()-c.LastAbortionAt) / 86400)) } return 0 } type CowWeightRange struct { WeightRange string `json:"weight_range"` Count int32 `json:"count"` } func (c CowSlice) WeightRangeToPB(penMap map[int32]*Pen) []*pasturePb.CowList { res := make([]*pasturePb.CowList, len(c)) for i, v := range c { penName := "" if pen, ok := penMap[v.PenId]; ok { penName = pen.Name } res[i] = &pasturePb.CowList{ CowId: int32(v.Id), DayAge: v.DayAge, DailyWeightGain: float32(v.GetDayWeight()), AverageDailyWeightGain: float32(v.GetAverageDailyWeight()), EarNumber: v.EarNumber, PenName: penName, BirthAt: int32(v.BirthAt), BirthWeight: float32(v.BirthWeight) / 1000, CurrentWeight: float32(v.CurrentWeight) / 1000, LastWeightAt: int32(v.LastWeightAt), } } return res } // CowBehaviorCurveResponse 脖环行为数据 type CowBehaviorCurveResponse struct { Code int32 `json:"code"` Msg string `json:"msg"` Data *CowBehaviorCurveData `json:"data"` } type CowBehaviorCurveData struct { OriginalDateList []int32 `json:"originalDateList"` // 原始行为数据 ChangeDateList []int32 `json:"changeDateList"` // 变化数据 SumDateList []int32 `json:"sumDateList"` // 累计24小时数据 DateTimeList []string `json:"dateTimeList"` // 时间数据 EstrusList map[pasturePb.EstrusLevel_Kind][]string `json:"estrusList"` // 发情预警 EventList map[string][]string `json:"eventList"` // 事件数据 EventMap map[pasturePb.EventType_Kind]string `json:"eventMap"` // 所有事件 }