Explorar o código

crontab: milk_daily

ping hai 1 día
pai
achega
3e67b64e61

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250414061726-cf591d3e4e66
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250415021421-cc74db5827d9
 	gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/eclipse/paho.mqtt.golang v1.4.3

+ 2 - 0
go.sum

@@ -44,6 +44,8 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250414060036-6d016734b75e h1:4G5Qytt6
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250414060036-6d016734b75e/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250414061726-cf591d3e4e66 h1:9MiP71UwVhQsKBdSY2M0re1kaLHQh+3Om4vXzMpTj44=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250414061726-cf591d3e4e66/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250415021421-cc74db5827d9 h1:WIXYHoPz+mC8HehE51gZys3/lmPAT9iqAAC3+KaCkWs=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250415021421-cc74db5827d9/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b h1:w05MxH7yqveRlaRbxHhbif5YjPrJFodRPfOjYhXn7Zk=
 gitee.com/xuyiping_admin/pkg v0.0.0-20241108060137-caea58c59f5b/go.mod h1:8tF25X6pE9WkFCczlNAC0K2mrjwKvhhp02I7o0HtDxY=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=

+ 1 - 1
http/handler/cow/cow.go

@@ -157,7 +157,7 @@ func BehaviorRate(c *gin.Context) {
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.CowId, valid.Required),
+		valid.Field(&req.EarNumber, valid.Required),
 		valid.Field(&req.StartTime, valid.Required),
 		valid.Field(&req.EndTime, valid.Required),
 	); err != nil {

+ 16 - 16
model/cow.go

@@ -257,7 +257,7 @@ func (c CowSlice) ToPB(
 		}
 		lastWeightAtFormat := ""
 		if v.LastWeightAt > 0 {
-			lastWeightAtFormat = time.Unix(v.LastWeightAt, 0).Format(LayoutDate2)
+			lastWeightAtFormat = time.Unix(v.LastWeightAt, 0).Local().Format(LayoutDate2)
 		}
 
 		isPregnantName := ""
@@ -269,62 +269,62 @@ func (c CowSlice) ToPB(
 
 		admissionAtFormat := ""
 		if v.AdmissionAt > 0 {
-			admissionAtFormat = time.Unix(v.AdmissionAt, 0).Format(LayoutDate2)
+			admissionAtFormat = time.Unix(v.AdmissionAt, 0).Local().Format(LayoutDate2)
 		}
 
 		birthAtFormat := ""
 		if v.BirthAt > 0 {
-			birthAtFormat = time.Unix(v.BirthAt, 0).Format(LayoutDate2)
+			birthAtFormat = time.Unix(v.BirthAt, 0).Local().Format(LayoutDate2)
 		}
 
 		weaningAtFormat := ""
 		if v.WeaningAt > 0 {
-			weaningAtFormat = time.Unix(v.WeaningAt, 0).Format(LayoutDate2)
+			weaningAtFormat = time.Unix(v.WeaningAt, 0).Local().Format(LayoutDate2)
 		}
 
 		firstMatingAtFormat := ""
 		if v.FirstMatingAt > 0 {
-			firstMatingAtFormat = time.Unix(v.FirstMatingAt, 0).Format(LayoutDate2)
+			firstMatingAtFormat = time.Unix(v.FirstMatingAt, 0).Local().Format(LayoutDate2)
 		}
 
 		lastMatingAtFormat := ""
 		if v.LastMatingAt > 0 {
-			lastMatingAtFormat = time.Unix(v.LastMatingAt, 0).Format(LayoutDate2)
+			lastMatingAtFormat = time.Unix(v.LastMatingAt, 0).Local().Format(LayoutDate2)
 		}
 
 		lastPregnantCheckAtFormat := ""
 		if v.LastPregnantCheckAt > 0 {
-			lastPregnantCheckAtFormat = time.Unix(v.LastPregnantCheckAt, 0).Format(LayoutDate2)
+			lastPregnantCheckAtFormat = time.Unix(v.LastPregnantCheckAt, 0).Local().Format(LayoutDate2)
 		}
 
 		lastCalvingAtFormat := ""
 		if v.LastCalvingAt > 0 {
-			lastCalvingAtFormat = time.Unix(v.LastCalvingAt, 0).Format(LayoutDate2)
+			lastCalvingAtFormat = time.Unix(v.LastCalvingAt, 0).Local().Format(LayoutDate2)
 		}
 
 		lastAbortionAtFormat := ""
 		if v.LastAbortionAt > 0 {
-			lastAbortionAtFormat = time.Unix(v.LastAbortionAt, 0).Format(LayoutDate2)
+			lastAbortionAtFormat = time.Unix(v.LastAbortionAt, 0).Local().Format(LayoutDate2)
 		}
 
 		lastSecondWeightAtFormat := ""
 		if v.LastSecondWeightAt > 0 {
-			lastSecondWeightAtFormat = time.Unix(v.LastSecondWeightAt, 0).Format(LayoutDate2)
+			lastSecondWeightAtFormat = time.Unix(v.LastSecondWeightAt, 0).Local().Format(LayoutDate2)
 		}
 
 		departureAtFormat := ""
 		if v.DepartureAt > 0 {
-			departureAtFormat = time.Unix(v.DepartureAt, 0).Format(LayoutDate2)
+			departureAtFormat = time.Unix(v.DepartureAt, 0).Local().Format(LayoutDate2)
 		}
 
 		lastForbiddenMatingAtFormat := ""
 		if v.LastForbiddenMatingAt > 0 {
-			lastForbiddenMatingAtFormat = time.Unix(v.LastForbiddenMatingAt, 0).Format(LayoutDate2)
+			lastForbiddenMatingAtFormat = time.Unix(v.LastForbiddenMatingAt, 0).Local().Format(LayoutDate2)
 		}
 
 		lastEstrusAtFormat := ""
 		if v.LastEstrusAt > 0 {
-			lastEstrusAtFormat = time.Unix(v.LastEstrusAt, 0).Format(LayoutDate2)
+			lastEstrusAtFormat = time.Unix(v.LastEstrusAt, 0).Local().Format(LayoutDate2)
 		}
 
 		cowTypeName := ""
@@ -707,15 +707,15 @@ func (c CowSlice) LongTermInfertilityToPB(breedStatusMap map[pasturePb.BreedStat
 		}
 		lastCalvingAtFormat := ""
 		if v.LastCalvingAt > 0 {
-			lastCalvingAtFormat = time.Unix(v.LastCalvingAt, 0).Format(LayoutDate2)
+			lastCalvingAtFormat = time.Unix(v.LastCalvingAt, 0).Local().Format(LayoutDate2)
 		}
 		lastAbortionAtFormat := ""
 		if v.LastAbortionAt > 0 {
-			lastAbortionAtFormat = time.Unix(v.LastAbortionAt, 0).Format(LayoutDate2)
+			lastAbortionAtFormat = time.Unix(v.LastAbortionAt, 0).Local().Format(LayoutDate2)
 		}
 		lastMatingAtFormat := ""
 		if v.LastMatingAt > 0 {
-			lastMatingAtFormat = time.Unix(v.LastMatingAt, 0).Format(LayoutDate2)
+			lastMatingAtFormat = time.Unix(v.LastMatingAt, 0).Local().Format(LayoutDate2)
 		}
 		res[i] = &pasturePb.LongTermInfertility{
 			CowId:                int32(v.Id),

+ 1 - 1
model/data_waring.go

@@ -60,7 +60,7 @@ func (d DataWarningSlice) ToPB() []*pasturePb.WarningDataShow {
 		}
 		dataUpdateTimeFormat := ""
 		if warningData.DataUpdateAt > 0 {
-			dataUpdateTimeFormat = time.Unix(warningData.DataUpdateAt, 0).Format(LayoutTime)
+			dataUpdateTimeFormat = time.Unix(warningData.DataUpdateAt, 0).Local().Format(LayoutTime)
 		}
 		res = append(res, &pasturePb.WarningDataShow{
 			Name:                 warningData.Name,

+ 2 - 2
model/event_cow_disease.go

@@ -119,11 +119,11 @@ func (e EventCowDiseaseSlice) ToPB(healthStatusMap map[pasturePb.HealthStatus_Ki
 	for i, v := range e {
 		lastTreatedTimeFormat := ""
 		if v.LastTreatmentAt > 0 {
-			lastTreatedTimeFormat = time.Unix(v.LastTreatmentAt, 0).Format(LayoutDate2)
+			lastTreatedTimeFormat = time.Unix(v.LastTreatmentAt, 0).Local().Format(LayoutDate2)
 		}
 		onsetDays := int32(0)
 		if v.FirstTreatmentAt > 0 {
-			firstTime := time.Unix(v.FirstTreatmentAt, 0)
+			firstTime := time.Unix(v.FirstTreatmentAt, 0).Local()
 			diff := time.Now().Local().Sub(firstTime)
 			onsetDays = int32(diff.Hours() / 24)
 		}

+ 1 - 1
model/event_cow_log.go

@@ -89,7 +89,7 @@ func (e EventCowLogSlice) ToPB(eventCategoryMap map[pasturePb.EventCategory_Kind
 	for i, v := range e {
 		eventAtFormat := ""
 		if v.EventAt > 0 {
-			eventAtFormat = time.Unix(v.EventAt, 0).Format(LayoutDate2)
+			eventAtFormat = time.Unix(v.EventAt, 0).Local().Format(LayoutDate2)
 		}
 		res[i] = &pasturePb.CowEvent{
 			Id:                int32(v.Id),

+ 3 - 3
model/event_cow_same_time.go

@@ -109,15 +109,15 @@ func (s SameTimeBodySlice) ToPB(
 	for i, v := range s {
 		calvingAtFormat, abortionAtFormat, playDayAtFormat := "", "", ""
 		if v.LastCalvingAt > 0 {
-			calvingAtFormat = time.Unix(v.LastCalvingAt, 0).Format(LayoutDate2)
+			calvingAtFormat = time.Unix(v.LastCalvingAt, 0).Local().Format(LayoutDate2)
 		}
 
 		if v.LastAbortionAt > 0 {
-			abortionAtFormat = time.Unix(v.LastAbortionAt, 0).Format(LayoutDate2)
+			abortionAtFormat = time.Unix(v.LastAbortionAt, 0).Local().Format(LayoutDate2)
 		}
 
 		if v.PlanDay > 0 {
-			playDayAtFormat = time.Unix(v.PlanDay, 0).Format(LayoutDate2)
+			playDayAtFormat = time.Unix(v.PlanDay, 0).Local().Format(LayoutDate2)
 		}
 
 		breedStatusName := ""

+ 1 - 1
model/event_immunization_plan.go

@@ -97,7 +97,7 @@ func (e EventImmunizationPlanSlice) ToPB() []*pasturePb.ImmunizationItems {
 	for i, v := range e {
 		planDay := ""
 		if v.PlanDay > 0 {
-			planDay = time.Unix(v.PlanDay, 0).Format(LayoutDate2)
+			planDay = time.Unix(v.PlanDay, 0).Local().Format(LayoutDate2)
 		}
 		res[i] = &pasturePb.ImmunizationItems{
 			Id:        int32(v.Id),

+ 8 - 8
model/event_mating.go

@@ -71,8 +71,8 @@ func (e *EventMating) EventMatingResultUpdate(matingResult pasturePb.MatingResul
 
 // IsReMating 判断是不是复配
 func (e *EventMating) IsReMating(cow *Cow, matingAt int64) bool {
-	lastMatingAt := time.Unix(cow.LastMatingAt, 0)
-	currentMatingAt := time.Unix(matingAt, 0)
+	lastMatingAt := time.Unix(cow.LastMatingAt, 0).Local()
+	currentMatingAt := time.Unix(matingAt, 0).Local()
 	daysBetween := util.DaysBetween(currentMatingAt.Unix(), lastMatingAt.Unix())
 	if (daysBetween == 1 || daysBetween == 0) && e.Status == pasturePb.IsShow_Ok && e.MatingResult == pasturePb.MatingResult_Unknown {
 		return true
@@ -90,8 +90,8 @@ func (e *EventMating) IsMatingUpdate() bool {
 
 // IsEmptyMating 判断上次配种结果是不是空怀
 func (e *EventMating) IsEmptyMating(cow *Cow, matingAt int64) bool {
-	lastMatingAt := time.Unix(cow.LastMatingAt, 0)
-	currentMatingAt := time.Unix(matingAt, 0)
+	lastMatingAt := time.Unix(cow.LastMatingAt, 0).Local()
+	currentMatingAt := time.Unix(matingAt, 0).Local()
 	daysBetween := util.DaysBetween(currentMatingAt.Unix(), lastMatingAt.Unix())
 	if (e.MatingResult == pasturePb.MatingResult_Unknown || e.MatingResult == pasturePb.MatingResult_ReMatch) && daysBetween >= 2 {
 		return true
@@ -167,8 +167,8 @@ func (e EventMatingSlice) ToPB(exposeEstrusTypeMap map[pasturePb.ExposeEstrusTyp
 			DayAge:               v.DayAge,
 			Lact:                 v.Lact,
 			CalvingAge:           v.CalvingAge,
-			PlanDay:              time.Unix(v.PlanDay, 0).Format(LayoutDate2),
-			RealityDay:           time.Unix(v.RealityDay, 0).Format(LayoutDate2),
+			PlanDay:              time.Unix(v.PlanDay, 0).Local().Format(LayoutDate2),
+			RealityDay:           time.Unix(v.RealityDay, 0).Local().Format(LayoutDate2),
 			ExposeEstrusType:     v.ExposeEstrusType,
 			ExposeEstrusTypeName: exposeEstrusTypeMap[v.ExposeEstrusType],
 			FrozenSemenNumber:    v.FrozenSemenNumber,
@@ -237,10 +237,10 @@ func (e EventMatingSlice) ToPB2() []*pasturePb.CowList {
 	for i, v := range e {
 		calvingAt, matingAtFormat := "", ""
 		if v.CalvingAt > 0 {
-			calvingAt = time.Unix(v.CalvingAt, 0).Format(LayoutDate2)
+			calvingAt = time.Unix(v.CalvingAt, 0).Local().Format(LayoutDate2)
 		}
 		if v.RealityDay > 0 {
-			matingAtFormat = time.Unix(v.RealityDay, 0).Format(LayoutDate2)
+			matingAtFormat = time.Unix(v.RealityDay, 0).Local().Format(LayoutDate2)
 		}
 		res[i] = &pasturePb.CowList{
 			CowId:           int32(v.CowId),

+ 1 - 1
model/event_pregnant_check.go

@@ -183,7 +183,7 @@ func (e EventPregnantCheckSlice) ToPB3(
 			CowId:                   int32(v.CowId),
 			Lact:                    int32(v.Lact),
 			PregnancyCheckName:      pregnancyCheckName,
-			PregnancyCheckAtFormat:  time.Unix(v.RealityDay, 0).Format(LayoutDate2),
+			PregnancyCheckAtFormat:  time.Unix(v.RealityDay, 0).Local().Format(LayoutDate2),
 			MatingAge:               v.MatingAge,
 			PregnantCheckMethod:     v.PregnantCheckMethod,
 			PregnantCheckMethodName: pregnantCheckMethodName,

+ 1 - 1
model/event_weight.go

@@ -56,7 +56,7 @@ func (e EventWeightSlice) ToPB() []*pasturePb.CowGrowthCurveData {
 	for i, v := range e {
 		weightAtFormat := ""
 		if v.WeightAt > 0 {
-			weightAtFormat = time.Unix(v.WeightAt, 0).Format(LayoutTime)
+			weightAtFormat = time.Unix(v.WeightAt, 0).Local().Format(LayoutTime)
 		}
 
 		avgWeight := float32(0)

+ 3 - 0
model/milk_daily.go

@@ -7,7 +7,10 @@ type MilkDaily struct {
 	PastureId    int64                      `json:"pastureId"`
 	HeatDate     string                     `json:"heatDate"`
 	CowId        int64                      `json:"cowId"`
+	EarNumber    string                     `json:"earNumber"`
 	Lact         int32                      `json:"lact"`
+	BirthDate    string                     `json:"birthDate"`
+	CalvingDate  string                     `json:"calvingDate"`
 	BreedStatus  pasturePb.BreedStatus_Kind `json:"breedStatus"`
 	LactationAge int32                      `json:"lactationAge"`
 	PenId        int32                      `json:"penId"`

+ 27 - 2
model/neck_active_habit.go

@@ -221,13 +221,38 @@ func (n NeckActiveHabitSlice) ToPB(curveName string) *CowBehaviorCurveData {
 }
 
 func (n NeckActiveHabitSlice) ToPB2(dataBetween []string) *pasturePb.CowBehaviorRateData {
-	return &pasturePb.CowBehaviorRateData{
+	data := &pasturePb.CowBehaviorRateData{
 		DateTime:     dataBetween,
 		RuminaRate:   make([]float32, 0),
 		IntakeRate:   make([]float32, 0),
 		InactiveRate: make([]float32, 0),
-		OtherRate:    make([]float32, 0),
+		GaspRate:     make([]float32, 0),
 	}
+
+	neckActiveHabitMap := make(map[string]*NeckActiveHabit)
+	for _, v := range n {
+		neckActiveHabitMap[v.HeatDate] = v
+	}
+
+	for _, t := range dataBetween {
+		ruminaRate, intakeRate, inactiveRate, gaspRate := float32(0), float32(0), float32(0), float32(0)
+		if v, ok := neckActiveHabitMap[t]; ok {
+			sum := v.Rumina + v.Intake + v.Inactive + v.Gasp
+			if sum > 0 {
+				// 保留小数点后两位
+				ruminaRate = float32(math.Round(float64(v.Rumina)/float64(sum)*100) / 100)
+				intakeRate = float32(math.Round(float64(v.Inactive)/float64(sum)*100) / 100)
+				inactiveRate = float32(math.Round(float64(v.Inactive)/float64(sum)*100) / 100)
+				gaspRate = float32(math.Round(float64(v.Gasp)/float64(sum)*100) / 100)
+			}
+		}
+		data.RuminaRate = append(data.RuminaRate, ruminaRate)
+		data.IntakeRate = append(data.IntakeRate, intakeRate)
+		data.InactiveRate = append(data.InactiveRate, inactiveRate)
+		data.GaspRate = append(data.GaspRate, gaspRate)
+	}
+
+	return data
 }
 
 type MaxHabitIdModel struct {

+ 2 - 2
model/neck_ring.go

@@ -63,8 +63,8 @@ func (n NeckRingSlice) ToPB(neckRingIsBind map[pasturePb.NeckRingIsBind_Kind]str
 		wearAtFormat := ""
 		wearDays := int32(0)
 		if v.WearAt > 0 {
-			wearAtFormat = time.Unix(v.WearAt, 0).Format(LayoutDate2)
-			wearDays = int32(time.Now().Local().Sub(time.Unix(v.WearAt, 0)).Hours() / 24)
+			wearAtFormat = time.Unix(v.WearAt, 0).Local().Format(LayoutDate2)
+			wearDays = int32(time.Now().Local().Sub(time.Unix(v.WearAt, 0).Local()).Hours() / 24)
 		}
 		res[i] = &pasturePb.SearchNeckRingList{
 			Id:           int32(v.Id),

+ 2 - 2
model/outbound.go

@@ -54,10 +54,10 @@ func (o OutboundSlice) ToPB(outTypeMap map[pasturePb.OutType_Kind]string, auditS
 	for i, v := range o {
 		applicantAtFormat, examineAtFormat, outTypeName, auditStatusName := "", "", "", ""
 		if v.ApplicantAt > 0 {
-			applicantAtFormat = time.Unix(v.ApplicantAt, 0).Format(LayoutTime)
+			applicantAtFormat = time.Unix(v.ApplicantAt, 0).Local().Format(LayoutTime)
 		}
 		if v.ExamineAt > 0 {
-			examineAtFormat = time.Unix(v.ExamineAt, 0).Format(LayoutTime)
+			examineAtFormat = time.Unix(v.ExamineAt, 0).Local().Format(LayoutTime)
 		}
 
 		if outType, ok := outTypeMap[v.OutType]; ok {

+ 2 - 2
model/system_menu.go

@@ -98,8 +98,8 @@ func (s SystemMenuSlice) ToPB() []*pasturePb.SearchMenuRequest {
 			HiddenTag:       hiddenTag,
 			ShowLink:        showLink,
 			ShowParent:      showParent,
-			CreatedAtFormat: time.Unix(menu.CreatedAt, 0).Format(LayoutTime),
-			UpdatedAtFormat: time.Unix(menu.UpdatedAt, 0).Format(LayoutTime),
+			CreatedAtFormat: time.Unix(menu.CreatedAt, 0).Local().Format(LayoutTime),
+			UpdatedAtFormat: time.Unix(menu.UpdatedAt, 0).Local().Format(LayoutTime),
 		}
 	}
 	return res

+ 2 - 2
model/system_role.go

@@ -40,8 +40,8 @@ func (s SystemRoleSlice) ToPB() []*pasturePb.SearchRoleRequest {
 			Name:            v.Name,
 			Remarks:         v.Remarks,
 			IsShow:          v.IsShow,
-			CreatedAtFormat: time.Unix(v.CreatedAt, 0).Format(LayoutTime),
-			UpdatedAtFormat: time.Unix(v.UpdatedAt, 0).Format(LayoutTime),
+			CreatedAtFormat: time.Unix(v.CreatedAt, 0).Local().Format(LayoutTime),
+			UpdatedAtFormat: time.Unix(v.UpdatedAt, 0).Local().Format(LayoutTime),
 		}
 	}
 	return res

+ 3 - 3
model/system_user.go

@@ -90,8 +90,8 @@ func (s SystemUserSlice) ToPB(deptList []*SystemDept, roleList []*SystemRole) []
 			DeptName:        deptName,
 			RoleId:          int32(v.RoleId),
 			RoleName:        roleName,
-			CreatedAtFormat: time.Unix(v.CreatedAt, 0).Format(LayoutTime),
-			UpdatedAtFormat: time.Unix(v.UpdatedAt, 0).Format(LayoutTime),
+			CreatedAtFormat: time.Unix(v.CreatedAt, 0).Local().Format(LayoutTime),
+			UpdatedAtFormat: time.Unix(v.UpdatedAt, 0).Local().Format(LayoutTime),
 		}
 	}
 	return res
@@ -102,7 +102,7 @@ func (s *SystemUser) ToPb() *operationPb.AddSystemUser {
 		Id:              int32(s.Id),
 		Name:            s.Name,
 		CreatedAt:       int32(s.CreatedAt),
-		CreatedAtFormat: time.Unix(s.CreatedAt, 0).Format(LayoutTime),
+		CreatedAtFormat: time.Unix(s.CreatedAt, 0).Local().Format(LayoutTime),
 		RoleIds:         []int32{},
 	}
 }

+ 1 - 1
model/work_order_master.go

@@ -107,7 +107,7 @@ func NewTaskWorkOrderOption(processAt int64) []asynq.Option {
 	return []asynq.Option{
 		asynq.MaxRetry(3),
 		AsynqQueueWorkOrder(),
-		asynq.ProcessAt(time.Unix(processAt, 64)),
+		asynq.ProcessAt(time.Unix(processAt, 64).Local()),
 	}
 }
 

+ 1 - 1
model/work_order_sub.go

@@ -78,7 +78,7 @@ func NewWorkOrderSub(req *WorkOrderMaster) []*WorkOrderSub {
 				continue
 			}
 			currentExecTime := execTime + int64(i)*secondsInDay
-			t := time.Unix(currentExecTime, 0)
+			t := time.Unix(currentExecTime, 0).Local()
 			if shouldGenerateSubOrder(req.Frequency, t, req.WeekMonthValue) {
 				sub := &WorkOrderSub{
 					WorkOrderMasterId:  req.Id,

+ 1 - 1
module/backend/analysis.go

@@ -61,7 +61,7 @@ func (s *StoreEntry) WeightScatterPlot(ctx context.Context, req *pasturePb.Searc
 		currentWeight := float32(cow.CurrentWeight) / 1000
 		admissionAtFormat := ""
 		if cow.AdmissionAt > 0 {
-			admissionAtFormat = time.Unix(cow.AdmissionAt, 0).Format(model.LayoutDate2)
+			admissionAtFormat = time.Unix(cow.AdmissionAt, 0).Local().Format(model.LayoutDate2)
 		}
 		cowData = append(cowData, &pasturePb.CowList{
 			CowId:                    int32(cow.Id),

+ 2 - 2
module/backend/analysis_more.go

@@ -21,8 +21,8 @@ func (s *StoreEntry) PenBehavior(ctx context.Context, req *pasturePb.BarnBehavio
 	if req.StartAt == 0 || req.EndAt == 0 || req.EndAt < req.StartAt {
 		return nil, xerr.Customf("时间范围错误")
 	}
-	startTime := time.Unix(int64(req.StartAt), 0).Format(model.LayoutDate2)
-	endTime := time.Unix(int64(req.EndAt), 0).Format(model.LayoutDate2)
+	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).

+ 6 - 4
module/backend/cow.go

@@ -259,7 +259,7 @@ func (s *StoreEntry) BehaviorCurve(ctx context.Context, req *pasturePb.CowBehavi
 			v.EventType == pasturePb.EventType_Castrated {
 			continue
 		}
-		eventAt := time.Unix(v.EventAt, 0)
+		eventAt := time.Unix(v.EventAt, 0).Local()
 		if data.EventList[v.EventTypeName] == nil {
 			data.EventList[v.EventTypeName] = make([]string, 0)
 		}
@@ -283,7 +283,7 @@ func (s *StoreEntry) BehaviorCurve(ctx context.Context, req *pasturePb.CowBehavi
 		}
 		if v.RealityDay > 0 {
 			// 格式化为到小时的字符串
-			hourStr := time.Unix(v.RealityDay, 0).Format(model.LayoutHour)
+			hourStr := time.Unix(v.RealityDay, 0).Local().Format(model.LayoutHour)
 			data.EstrusList[v.Level] = append(data.EstrusList[v.Level], hourStr)
 		}
 	}
@@ -401,7 +401,7 @@ func (s *StoreEntry) BehaviorRate(ctx context.Context, req *pasturePb.CowBehavio
 		return nil, xerr.WithStack(err)
 	}
 
-	cowInfo, err := s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, int64(req.CowId))
+	cowInfo, err := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, req.EarNumber)
 	if err != nil {
 		return nil, xerr.Customf("错误的牛只信息: %d", req.CowId)
 	}
@@ -412,11 +412,13 @@ func (s *StoreEntry) BehaviorRate(ctx context.Context, req *pasturePb.CowBehavio
 
 	neckActiveHabitList := make([]*model.NeckActiveHabit, 0)
 	if err = s.DB.Model(new(model.NeckActiveHabit)).
+		Select("heat_date,SUM(rumina) as rumina,SUM(intake) as intake,SUM(inactive) as inactive,SUM(gasp) AS gasp").
 		Where("neck_ring_number = ?", cowInfo.NeckRingNumber).
 		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("cow_id > ?", 0).
 		Where("heat_date BETWEEN ? AND ?", req.StartTime, req.EndTime).
-		Order("heat_date, frameid").
+		Order("heat_date").
+		Group("heat_date").
 		Find(&neckActiveHabitList).Error; err != nil {
 	}
 

+ 1 - 1
module/backend/event_base.go

@@ -181,7 +181,7 @@ func (s *StoreEntry) GroupTransferList(ctx context.Context, req *pasturePb.Searc
 	}
 
 	if req.StartDayAt > 0 && req.EndDayAt > 0 && req.EndDayAt >= req.StartDayAt {
-		pref.Where("a.transfer_date BETWEEN ? AND ?", time.Unix(int64(req.StartDayAt), 0).Format(model.LayoutDate2), time.Unix(int64(req.EndDayAt), 0).Format(model.LayoutDate2))
+		pref.Where("a.transfer_date BETWEEN ? AND ?", time.Unix(int64(req.StartDayAt), 0).Local().Format(model.LayoutDate2), time.Unix(int64(req.EndDayAt), 0).Format(model.LayoutDate2))
 	}
 
 	if err = pref.Order("a.id desc").Group("a.id").

+ 5 - 5
module/backend/event_breed.go

@@ -250,7 +250,7 @@ func (s *StoreEntry) SameTimeBatch(ctx context.Context, req *pasturePb.EventSame
 			zaplog.Error("SameTimeCreate", zap.Any("err", err), zap.Any("req", req))
 			return xerr.WithStack(err)
 		}
-		if time.Unix(eventCowSameTime.PlanDay, 0).Format(model.LayoutDate2) != nowTime {
+		if time.Unix(eventCowSameTime.PlanDay, 0).Local().Format(model.LayoutDate2) != nowTime {
 			return xerr.Customf("该牛只不是今日计划: %s", eventCowSameTime.EarNumber)
 		}
 		eventCowSameTimeList = append(eventCowSameTimeList, eventCowSameTime)
@@ -433,8 +433,8 @@ func (s *StoreEntry) EstrusBatchMating(ctx context.Context, req *pasturePb.Event
 		startTimeUnix := util.TimeParseLocalUnix(startTime)
 		endTimeUnix := util.TimeParseLocalUnix(endTime)
 
-		startTime = time.Unix(startTimeUnix, 0).Format(model.LayoutTime)
-		endTime = time.Unix(endTimeUnix, 0).Format(model.LayoutTime)
+		startTime = time.Unix(startTimeUnix, 0).Local().Format(model.LayoutTime)
+		endTime = time.Unix(endTimeUnix, 0).Local().Format(model.LayoutTime)
 
 		neckRingEstrusWarningList := make([]*model.NeckRingEstrusWarning, 0)
 		if err = tx.Model(new(model.NeckRingEstrusWarning)).
@@ -497,8 +497,8 @@ func (s *StoreEntry) NeckRingNoEstrusBatch(ctx context.Context, req *pasturePb.N
 	startTimeUnix := util.TimeParseLocalUnix(startTime)
 	endTimeUnix := util.TimeParseLocalUnix(endTime)
 
-	startTime = time.Unix(startTimeUnix, 0).Format(model.LayoutTime)
-	endTime = time.Unix(endTimeUnix, 0).Format(model.LayoutTime)
+	startTime = time.Unix(startTimeUnix, 0).Local().Format(model.LayoutTime)
+	endTime = time.Unix(endTimeUnix, 0).Local().Format(model.LayoutTime)
 	neckRingEstrusWarningList := make([]*model.NeckRingEstrusWarning, 0)
 	if err = s.DB.Model(new(model.NeckRingEstrusWarning)).
 		Where("pasture_id = ?", userModel.AppPasture.Id).

+ 2 - 2
module/backend/event_check.go

@@ -238,8 +238,8 @@ func (s *StoreEntry) EstrusCheckDataCheck(ctx context.Context, userModel *model.
 				zaplog.Info("EventNaturalEstrusBatch", zap.Any("existsEventEstrus", existsEventEstrus), zap.Any("item", item))
 				continue
 			}*/
-			realityDay := time.Unix(existsEventEstrus.RealityDay, 0).Format(model.LayoutDate2)
-			planDay := time.Unix(int64(item.EstrusAt), 0).Format(model.LayoutDate2)
+			realityDay := time.Unix(existsEventEstrus.RealityDay, 0).Local().Format(model.LayoutDate2)
+			planDay := time.Unix(int64(item.EstrusAt), 0).Local().Format(model.LayoutDate2)
 			if realityDay == planDay {
 				return nil, xerr.Customf("该牛只:%d,今天已经提交过发情数据", item.CowId)
 			}

+ 1 - 1
module/backend/event_cow_log.go

@@ -196,7 +196,7 @@ func (s *StoreEntry) SubmitEventLog(ctx context.Context, pastureId int64, cow *m
 		eventAt = data.UnForbiddenMatingAt
 		operationUser.Id = data.UnForbiddenOperationId
 		operationUser.Name = data.UnForbiddenOperationName
-		desc = fmt.Sprintf("解禁时间: %s", time.Unix(eventAt, 0).Format(model.LayoutDate2))
+		desc = fmt.Sprintf("解禁时间: %s", time.Unix(eventAt, 0).Local().Format(model.LayoutDate2))
 	}
 	newEventCowLogModel := &model.EventCowLogModel{
 		Cow:               cow,

+ 3 - 3
module/backend/event_health.go

@@ -605,10 +605,10 @@ func (s *StoreEntry) CowDiseaseCurable(ctx context.Context, req *pasturePb.Event
 			cowLogs := &model.EventCowLog{CowId: cow.Id}
 			curableAtFormat := ""
 			if eventCowDisease.CurableAt > 0 {
-				curableAtFormat = time.Unix(eventCowDisease.CurableAt, 0).Format(model.LayoutDate2)
+				curableAtFormat = time.Unix(eventCowDisease.CurableAt, 0).Local().Format(model.LayoutDate2)
 			}
-			curableAtParse := time.Unix(eventCowDisease.CurableAt, 0)
-			diseaseAtParse := time.Unix(eventCowDisease.DiseaseAt, 0)
+			curableAtParse := time.Unix(eventCowDisease.CurableAt, 0).Local()
+			diseaseAtParse := time.Unix(eventCowDisease.DiseaseAt, 0).Local()
 			curableDays := int64(curableAtParse.Sub(diseaseAtParse).Hours() / 24)
 
 			if err = tx.Table(cowLogs.TableName()).

+ 2 - 2
module/backend/goods.go

@@ -534,10 +534,10 @@ func (s *StoreEntry) OutboundDetail(ctx context.Context, id int64) (*pasturePb.O
 	auditStatusMap := s.AuditStatusMap()
 	applicantAtFormat, examineAtFormat := "", ""
 	if outbound.ApplicantAt > 0 {
-		applicantAtFormat = time.Unix(outbound.ApplicantAt, 0).Format(model.LayoutTime)
+		applicantAtFormat = time.Unix(outbound.ApplicantAt, 0).Local().Format(model.LayoutTime)
 	}
 	if outbound.ExamineAt > 0 {
-		examineAtFormat = time.Unix(outbound.ExamineAt, 0).Format(model.LayoutTime)
+		examineAtFormat = time.Unix(outbound.ExamineAt, 0).Local().Format(model.LayoutTime)
 	}
 	return &pasturePb.OutboundDetailResponse{
 		Code: http.StatusOK,

+ 2 - 2
module/backend/neck_ring_warning.go

@@ -88,8 +88,8 @@ func (s *StoreEntry) EstrusOrAbortionCowList(ctx context.Context, req *pasturePb
 
 func (s *StoreEntry) EstrusWarningQuery(ctx context.Context, pastureId int64) (*gorm.DB, error) {
 	nowTime := time.Now().Local()
-	startTime := time.Unix(util.TimeParseLocalUnix(nowTime.Format(model.LayoutDate2)), 0).Format(model.LayoutTime)
-	entTime := time.Unix(util.TimeParseLocalEndUnix(nowTime.AddDate(0, 0, 1).Format(model.LayoutDate2)), 0).Format(model.LayoutTime)
+	startTime := time.Unix(util.TimeParseLocalUnix(nowTime.Format(model.LayoutDate2)), 0).Local().Format(model.LayoutTime)
+	entTime := time.Unix(util.TimeParseLocalEndUnix(nowTime.AddDate(0, 0, 1).Local().Format(model.LayoutDate2)), 0).Format(model.LayoutTime)
 	systemBasic, err := s.FindSystemBasic(ctx, pastureId, model.EstrusWaringDays)
 	if err != nil {
 		return nil, xerr.WithStack(err)

+ 1 - 1
module/crontab/cow_indicators_base.go

@@ -141,7 +141,7 @@ func (e *Entry) FindSalesVolume(pastureList []*model.AppPastureList, startTime,
 }
 
 func (e *Entry) UpdatePastureIndicators(pastureId int64, indicatorsDetails *model.IndicatorsDetails, dateTime int64, value string) {
-	date := time.Unix(dateTime, 0).Format(model.LayoutMonth)
+	date := time.Unix(dateTime, 0).Local().Format(model.LayoutMonth)
 	where := &model.IndicatorsData{
 		PastureId: pastureId,
 		Date:      date,

+ 141 - 1
module/crontab/milk_daily.go

@@ -1,5 +1,16 @@
 package crontab
 
+import (
+	"kpt-pasture/model"
+	"kpt-pasture/util"
+	"time"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
+	"go.uber.org/zap"
+)
+
 func (e *Entry) InsertMilkDaily() error {
 	pastureList := e.FindPastureList()
 	if pastureList == nil || len(pastureList) == 0 {
@@ -14,6 +25,135 @@ func (e *Entry) InsertMilkDaily() error {
 }
 
 func (e *Entry) ProcessMilkDaily(pastureId int64) {
-	//nowTime := time.Now()
+	// 获取最大记录日期或默认日期
+	var maxDateTime string
+	if err := e.DB.Model(new(model.MilkDaily)).
+		Where("pasture_id = ?", pastureId).
+		Select("IFNULL(MAX(heat_date) + INTERVAL 1 DAY, CURDATE() - INTERVAL 1 MONTH) AS max_date_time").
+		Scan(&maxDateTime).Error; err != nil {
+		zaplog.Error("ProcessMilkDaily", zap.Any("pastureId", pastureId), zap.Any("err", err))
+		return
+	}
+
+	nowTime := time.Now().Local()
+	if maxDateTime == "" {
+		zaplog.Error("ProcessMilkDaily", zap.Any("pastureId", pastureId), zap.Any("maxDateTime", maxDateTime))
+		return
+	}
+
+	maxDate, err := util.TimeParseLocal(model.LayoutDate2, maxDateTime)
+	if err != nil {
+		zaplog.Error("ProcessMilkDaily", zap.Any("pastureId", pastureId), zap.Any("err", err))
+		return
+	}
+
+	// 处理每一天的数据
+	for maxDate.Before(nowTime) {
+		// 处理有胎次的奶牛
+		if err = e.processCowsWithLact(maxDate); err != nil {
+			zaplog.Error("ProcessMilkDaily", zap.Any("processCowsWithFetal", err))
+		}
+
+		// 处理无胎次的奶牛
+		if err = e.processCowsWithNoLact(maxDate); err != nil {
+			zaplog.Error("ProcessMilkDaily", zap.Any("processCowsWithoutFetal", err))
+		}
+
+		// 日期加1天
+		maxDate = maxDate.AddDate(0, 0, 1)
+	}
+}
+
+// 处理有胎次的奶牛
+func (e *Entry) processCowsWithLact(recordDate time.Time) error {
+	// 查询有胎次且在记录日期前有记录的奶牛
+	cowList := make([]*model.Cow, 0)
+	if err := e.DB.Model(new(model.Cow)).
+		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
+		Where("lact > ?", 0).
+		Where("last_calving_at <= ?", recordDate.Local().Unix()).
+		Find(&cowList).Error; err != nil {
+		return err
+	}
 
+	// 批量插入数据
+	milkDailyList := make([]*model.MilkDaily, 0)
+	for _, cow := range cowList {
+		calvingDate := ""
+		if cow.LastCalvingAt > 0 {
+			calvingDate = time.Unix(cow.LastCalvingAt, 0).Local().Format(model.LayoutDate2)
+		}
+		milkDaily := &model.MilkDaily{
+			CowId:        cow.Id,
+			Lact:         cow.Lact,
+			PastureId:    cow.PastureId,
+			EarNumber:    cow.EarNumber,
+			CalvingDate:  calvingDate,
+			HeatDate:     recordDate.Format(model.LayoutDate2),
+			LactationAge: cow.LactationAge,
+			PenId:        cow.PenId,
+			PenName:      cow.PenName,
+			BreedStatus:  cow.BreedStatus,
+		}
+		milkDailyList = append(milkDailyList, milkDaily)
+	}
+	if len(milkDailyList) > 0 {
+		if err := e.DB.Model(new(model.MilkDaily)).
+			Create(&milkDailyList).Error; err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// 处理无胎次的奶牛
+func (e *Entry) processCowsWithNoLact(recordDate time.Time) error {
+	// 查询无胎次且EID1>0的奶牛
+	cowList := make([]*model.Cow, 0)
+	err := e.DB.Model(new(model.Cow)).
+		//Select("c.intCowId as cow_id, c.intPastureId as pasture_id, c.varCowCode as cow_code,c.dateBirthDate as birth_date, c.intCurBar as cur_bar").
+		//Where("(c.dateLeave IS NULL OR c.dateLeave > ?) AND c.intCurFetal = 0 AND c.EID1 > 0", recordDate).
+		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
+		Where("lact = ?", 0).
+		Where("neck_ring_number != ?", "").
+		Find(&cowList).Error
+	if err != nil {
+		return err
+	}
+
+	// 批量插入数据
+	milkDailyList := make([]*model.MilkDaily, 0)
+	for _, cow := range cowList {
+
+		birthDate, calvingDate := "", ""
+		if cow.BirthAt > 0 {
+			birthDate = time.Unix(cow.BirthAt, 0).Local().Format(model.LayoutDate2)
+		}
+
+		if cow.LastCalvingAt > 0 {
+			calvingDate = time.Unix(cow.LastCalvingAt, 0).Local().Format(model.LayoutDate2)
+		}
+		milkDaily := &model.MilkDaily{
+			CowId:        cow.Id,
+			Lact:         cow.Lact,
+			PastureId:    cow.PastureId,
+			EarNumber:    cow.EarNumber,
+			BirthDate:    birthDate,
+			CalvingDate:  calvingDate,
+			LactationAge: cow.LactationAge,
+			HeatDate:     recordDate.Format(model.LayoutDate2),
+			PenId:        cow.PenId,
+			PenName:      cow.PenName,
+		}
+		milkDailyList = append(milkDailyList, milkDaily)
+	}
+
+	if len(milkDailyList) > 0 {
+		if err = e.DB.Model(new(model.MilkDaily)).Create(&milkDailyList).Error; err != nil {
+			return err
+		}
+	}
+
+	return nil
 }

+ 2 - 2
util/util.go

@@ -345,8 +345,8 @@ func RemoveDuplicates(slice []string) []string {
 
 // DaysBetween 计算两个日期(时间戳)之间的天数差
 func DaysBetween(startDayUnix int64, endDayUnix int64) int64 {
-	time1 := time.Unix(startDayUnix, 0)
-	time2 := time.Unix(endDayUnix, 0)
+	time1 := time.Unix(startDayUnix, 0).Local()
+	time2 := time.Unix(endDayUnix, 0).Local()
 	// Truncate to the start of the day (00:00:00)
 	startOfDay1 := time.Date(time1.Year(), time1.Month(), time1.Day(), 0, 0, 0, 0, time1.Location())
 	startOfDay2 := time.Date(time2.Year(), time2.Month(), time2.Day(), 0, 0, 0, 0, time2.Location())

+ 2 - 2
util/util_more.go

@@ -84,8 +84,8 @@ func GetMonthStartAndEndTimestamp() (startTimestamp, endTimestamp int64) {
 
 // SubDays 计算两个日期(时间戳)之间的天数差
 func SubDays(startDay, endDay int64) int32 {
-	s1 := time.Unix(startDay, 0)
-	s2 := time.Unix(endDay, 0)
+	s1 := time.Unix(startDay, 0).Local()
+	s2 := time.Unix(endDay, 0).Local()
 	return int32(s2.Sub(s1).Hours() / 24)
 }