| 
					
				 | 
			
			
				@@ -9,27 +9,61 @@ import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // PenBehavior 栏舍行为曲线 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func (e *Entry) PenBehavior(pastureId int64, processIds []int64) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	neckRingOriginalList := make([]*model.NeckRingOriginal, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (e *Entry) PenBehavior(pastureId int64, processIds []int64) error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 1. 获取颈环原始数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	neckRingOriginalList, err := e.getNeckRingOriginalList(pastureId, processIds) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return fmt.Errorf("获取颈环原始数据失败: %w", err) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 2. 获取牛只信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cowMap, err := e.getCowMap(pastureId, neckRingOriginalList) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return fmt.Errorf("获取牛只信息失败: %w", err) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 3. 处理栏舍行为数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	penData := e.processPenBehaviorData(neckRingOriginalList, cowMap) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 4. 计算平均值和百分比 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	e.calculateAveragesAndRates(penData) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 5. 保存数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if err := e.savePenBehaviorData(penData); err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return fmt.Errorf("保存栏舍行为数据失败: %w", err) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// getNeckRingOriginalList 获取颈环原始数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (e *Entry) getNeckRingOriginalList(pastureId int64, processIds []int64) ([]*model.NeckRingOriginal, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	var neckRingOriginalList []*model.NeckRingOriginal 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if err := e.DB.Model(new(model.NeckRingOriginal)). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		Where("id IN (?)", processIds). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		Where("pasture_id = ?", pastureId). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Where("id IN (?) AND pasture_id = ?", processIds, pastureId). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		Order("heat_date,neck_ring_number,frameid"). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		Find(&neckRingOriginalList).Error; err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		zaplog.Error("PenBehavior", zap.Any("error", err), zap.Any("processIds", processIds)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return nil, err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return neckRingOriginalList, nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	cowIds := make([]int64, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// getCowMap 获取牛只信息映射 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (e *Entry) getCowMap(pastureId int64, neckRingOriginalList []*model.NeckRingOriginal) (map[string]*model.Cow, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 提取牛只ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cowIds := make([]int64, 0, len(neckRingOriginalList)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	for _, v := range neckRingOriginalList { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		cowIds = append(cowIds, v.Id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 获取牛只信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	cowInfoList, err := e.GetCowByIds(pastureId, cowIds) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		zaplog.Error("PenBehavior", zap.Any("error", err), zap.Any("cowIds", cowIds)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return nil, err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	cowMap := make(map[string]*model.Cow) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 构建牛只信息映射 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cowMap := make(map[string]*model.Cow, len(cowInfoList)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	for _, v := range cowInfoList { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if v.NeckRingNumber == "" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			continue 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -37,18 +71,30 @@ func (e *Entry) PenBehavior(pastureId int64, processIds []int64) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		cowMap[v.NeckRingNumber] = v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	penData := make(map[string]*model.PenBehaviorData) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return cowMap, nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// processPenBehaviorData 处理栏舍行为数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (e *Entry) processPenBehaviorData(neckRingOriginalList []*model.NeckRingOriginal, cowMap map[string]*model.Cow) map[string]*model.PenBehaviorData { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	penData := make(map[string]*model.PenBehaviorData, len(neckRingOriginalList)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	for _, v := range neckRingOriginalList { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		cowInfo, ok := cowMap[v.NeckRingNumber] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if !ok { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			zaplog.Error("PenBehavior", zap.Any("error", err), zap.Any("neckRingNumber", v.NeckRingNumber)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			zaplog.Error("PenBehavior", zap.Any("neckRingNumber", v.NeckRingNumber)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			continue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		key := fmt.Sprintf("%s_%d_%d", v.ActiveDate, cowInfo.PenId, v.Frameid) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if penData[key] == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if data, exists := penData[key]; exists { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			data.CowCount++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			data.AvgHigh += v.High 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			data.SumRumina += ifThenElse(v.Rumina >= 8, 1, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			data.SumIntake += ifThenElse(v.Intake >= 8, 1, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			data.SumRest += ifThenElse(v.Inactive >= 8, 1, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			data.SumGasp += ifThenElse(v.Gasp >= 8, 1, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			penData[key] = &model.PenBehaviorData{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				PastureId: pastureId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				PastureId: cowInfo.PastureId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				PenId:     cowInfo.PenId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				PenName:   cowInfo.PenName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				HeatDate:  v.ActiveDate, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -56,22 +102,87 @@ func (e *Entry) PenBehavior(pastureId int64, processIds []int64) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				CowCount:  1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				AvgHigh:   v.High, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			penData[key].CowCount++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			penData[key].AvgHigh += v.High 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			penData[key].SumRumina += ifThenElse(v.Rumina >= 8, 1, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			penData[key].SumIntake += ifThenElse(v.Intake >= 8, 1, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			penData[key].SumRest += ifThenElse(v.Inactive >= 8, 1, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			penData[key].SumGasp += ifThenElse(v.Gasp >= 8, 1, 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	// 计算平均值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return penData 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// calculateAveragesAndRates 计算平均值和百分比 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (e *Entry) calculateAveragesAndRates(penData map[string]*model.PenBehaviorData) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	for _, data := range penData { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// 计算平均值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		data.AvgHigh = data.AvgHigh / data.CowCount 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// 计算百分比 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if data.CowCount > 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			data.RuminaRate = int32(float64(data.SumRumina) / float64(data.CowCount) * 100) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			data.IntakeRate = int32(float64(data.SumIntake) / float64(data.CowCount) * 100) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			data.RestRate = int32(float64(data.SumRest) / float64(data.CowCount) * 100) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			data.GaspRate = int32(float64(data.SumGasp) / float64(data.CowCount) * 100) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// savePenBehaviorData 保存栏舍行为数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (e *Entry) savePenBehaviorData(penData map[string]*model.PenBehaviorData) error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	for _, data := range penData { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// 构建活动时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		activeTime := e.calculateActiveTime(data.HeatDate, data.Frameid) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// 构建保存数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		penBehavior := &model.PenBehavior{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PastureId:  data.PastureId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			HeatDate:   data.HeatDate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ActiveTime: activeTime, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PenId:      data.PenId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PenName:    data.PenName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			CowCount:   data.CowCount, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			AvgHigh:    data.AvgHigh, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			SumRumina:  data.SumRumina, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			SumIntake:  data.SumIntake, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			SumRest:    data.SumRest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			SumGasp:    data.SumGasp, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			RuminaRate: data.RuminaRate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			IntakeRate: data.IntakeRate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			RestRate:   data.RestRate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			GaspRate:   data.GaspRate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// 使用 Upsert 操作 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if err := e.DB.Model(new(model.PenBehavior)). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			Where("pasture_id = ? AND heat_date = ? AND pen_id = ? AND active_time = ?", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				penBehavior.PastureId, penBehavior.HeatDate, penBehavior.PenId, penBehavior.ActiveTime). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			Assign(map[string]interface{}{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"cow_count":    penBehavior.CowCount, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"avg_high":     penBehavior.AvgHigh, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"sum_rumina":   penBehavior.SumRumina, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"sum_intake":   penBehavior.SumIntake, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"sum_rest":     penBehavior.SumRest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"sum_gasp":     penBehavior.SumGasp, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"rumina_rate":  penBehavior.RuminaRate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"intake_rate":  penBehavior.IntakeRate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"rest_rate":    penBehavior.RestRate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"gasp_rate":    penBehavior.GaspRate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			FirstOrCreate(penBehavior).Error; err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// calculateActiveTime 计算活动时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (e *Entry) calculateActiveTime(heatDate string, frameid int32) string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 计算小时和分钟 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	hour := (frameid / 10) * 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	minute := (frameid % 10) * 20 - 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// 构建时间字符串 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return fmt.Sprintf("%s %02d:%02d", heatDate, hour, minute) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// ifThenElse 条件判断函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func ifThenElse(condition bool, a, b int32) int32 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if condition { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return a 
			 |