浏览代码

disease: 疾病提交

Yi 4 月之前
父节点
当前提交
0c2c2fec8a

+ 1 - 1
config/app.develop.yaml

@@ -43,7 +43,7 @@ cron:
   update_same_time: "0 20 1 * * ?"
   system_basic_crontab: "0 25 1 * * ?"
   cow_pregnant: "0 00 15 * * ?"
-  neck_ring: "0 30 * * * ?"
+  neck_ring: "*/30 * * * * ?"
 mqtt:
   broker: "47.92.95.119"
   port: 1883

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20241204093501-8c0752b62fac
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20241206015638-6b15cf82851d
 	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

+ 6 - 0
go.sum

@@ -49,6 +49,12 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20241204031342-3f1a7bd2d670/go.mod h1:B
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241204093501-8c0752b62fac h1:J4ZtqdRLDnofNd4M1qfm3ZUFDxoAxaPXiNvB5YuUgXI=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241204093501-8c0752b62fac/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20241204093535-10c3d976e5c7/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241205100848-b0790a01ff1a h1:lFbAQBSqRM2cpquaV7TjCTsnmrRGZbOfhZg/aOs7524=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241205100848-b0790a01ff1a/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241205102558-36e3ea825ca3 h1:fHcQ+MmsAt3jhDQaBEdYoQ0Kthako7MdRvLrekYdcMQ=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241205102558-36e3ea825ca3/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241206015638-6b15cf82851d h1:L/gXdFvjt966dFbM56fDSS+2vdkb/5hSZUxHvK+Vw4Q=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20241206015638-6b15cf82851d/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=

+ 2 - 8
http/handler/event/event_health.go

@@ -25,19 +25,13 @@ func CowDiseaseCreate(c *gin.Context) {
 		valid.Field(&req.DiseaseAt, valid.Required),
 		valid.Field(&req.DiseaseId, valid.Required),
 		valid.Field(&req.OperationId, valid.Required),
-		valid.Field(&req.PrescriptionDetail, valid.Required, valid.Each(valid.By(func(value interface{}) error {
-			item := value.(pasturePb.TreatmentDrugs)
-			return valid.ValidateStruct(&item,
-				valid.Field(&item.DrugsId, valid.Required),
-				valid.Field(&item.UseNum, valid.Required),
-			)
-		}))),
 	); err != nil {
 		apierr.AbortBadRequest(c, http.StatusBadRequest, err)
 		return
 	}
 
-	if err := middleware.BackendOperation(c).OpsService.CowDiseaseCreate(c, &req); err != nil {
+	source := c.GetHeader("Source")
+	if err := middleware.BackendOperation(c).OpsService.CowDiseaseCreate(c, &req, source); err != nil {
 		apierr.ClassifiedAbort(c, err)
 		return
 	}

+ 4 - 0
model/event_cow_disease.go

@@ -28,6 +28,7 @@ type EventCowDisease struct {
 	DiagnoseOperationId   int32                       `json:"diagnoseOperationId"`
 	DiagnoseOperationName string                      `json:"diagnoseOperationName"`
 	CurableAt             int64                       `json:"curableAt"`
+	Source                string                      `json:"source"`
 	CreatedAt             int64                       `json:"createdAt"`
 	UpdatedAt             int64                       `json:"updatedAt"`
 }
@@ -55,6 +56,9 @@ func NewEventCowDisease(cow *Cow, disease *Disease, req *pasturePb.EventCowDisea
 		MessageId:       int32(currUser.Id),
 		MessageName:     currUser.Name,
 		Remarks:         req.Remarks,
+		DiagnosedResult: pasturePb.IsShow_No,
+		Source:          SourceApp,
+		DiagnosedAt:     int64(req.DiseaseAt),
 	}
 }
 

+ 1 - 1
model/event_cow_treatment.go

@@ -57,7 +57,7 @@ type EventCowTreatmentSlice []*EventCowTreatment
 func (e EventCowTreatmentSlice) ToPB(eventCowDiseaseList []*EventCowDisease) []*pasturePb.EventCowTreatment {
 	res := make([]*pasturePb.EventCowTreatment, len(e))
 	for i, v := range e {
-		prescriptionDetail := make([]*pasturePb.TreatmentDrugs, 0)
+		prescriptionDetail := make([]*pasturePb.PrescriptionDrugsList, 0)
 		if v.PrescriptionDetail != "" {
 			err := json.Unmarshal([]byte(v.PrescriptionDetail), &prescriptionDetail)
 			if err != nil {

+ 4 - 4
model/event_immunization_plan.go

@@ -30,8 +30,8 @@ type EventImmunizationPlan struct {
 	UnitName      string                 `json:"unitName"`
 	Usage         int32                  `json:"usage"`
 	Remarks       string                 `json:"remarks"`
-	CreateAt      int64                  `json:"createAt"`
-	UpdateAt      int64                  `json:"updateAt"`
+	CreatedAt     int64                  `json:"createdAt"`
+	UpdatedAt     int64                  `json:"updatedAt"`
 }
 
 func (c *EventImmunizationPlan) TableName() string {
@@ -91,8 +91,8 @@ func (I EventImmunizationPlanSlice) ToPB() []*pasturePb.ImmunizationItems {
 			Unit:             v.Unit,
 			UnitName:         v.UnitName,
 			Usage:            v.Usage,
-			CreatedAt:        int32(v.CreateAt),
-			UpdatedAt:        int32(v.UpdateAt),
+			CreatedAt:        int32(v.CreatedAt),
+			UpdatedAt:        int32(v.UpdatedAt),
 		}
 	}
 	return res

+ 70 - 53
model/neck_active_habit.go

@@ -1,60 +1,65 @@
 package model
 
-import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+import (
+	"fmt"
+
+	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+)
 
 type NeckActiveHabit struct {
-	Id                       int64                 `json:"id"`
-	CowId                    int64                 `json:"cowId"`
-	NeckRingNumber           string                `json:"neckRingNumber"`
-	Lact                     int32                 `json:"lact"`
-	FrameId                  int32                 `json:"frameid"`
-	HeatDate                 string                `json:"heatDate"`
-	Rumina                   int32                 `json:"rumina"`
-	Intake                   int32                 `json:"intake"`
-	Inactive                 int32                 `json:"inactive"`
-	Gasp                     int32                 `json:"gasp"`
-	Other                    int32                 `json:"other"`
-	High                     int32                 `json:"high"`
-	Active                   int32                 `json:"active"`
-	Voltage                  int32                 `json:"voltage"`
-	Version                  int32                 `json:"version"`
-	FilterHigh               int32                 `json:"filterHigh"`
-	FilterRumina             int32                 `json:"filterRumina"`
-	FilterChew               int32                 `json:"filterChew"`
-	WeekHigh                 int32                 `json:"weekHigh"`
-	WeekAvgHighHabit         int32                 `json:"weekAvgHighHabit"`
-	WeekAvgRuminaHabit       int32                 `json:"WeekAvgRuminaHabit"`
-	WeekAvgIntakeHabit       int32                 `json:"weekAvgIntakeHabit"`
-	WeekAvgChewHabit         int32                 `json:"weekAvgChewHabit"`
-	WeekAvgInactiveHabit     int32                 `json:"weekAvgInactiveHabit"`
-	WeekAvgOtherHabit        int32                 `json:"weekAvgOtherHabit"`
-	ChangeHigh               int32                 `json:"changeHigh"`
-	ChangeRumina             int32                 `json:"changeRumina"`
-	ChangeChew               int32                 `json:"changeChew"`
-	ChangeAdjust             int32                 `json:"changeAdjust"`
-	ChangeFilter             int32                 `json:"changeFilter"`
-	RuminaFilter             int32                 `json:"ruminaFilter"`
-	ChewFilter               int32                 `json:"chewFilter"`
-	FilterCorrect            int32                 `json:"filterCorrect"`
-	SumRumina                int32                 `json:"sumRumina"`
-	SumIntake                int32                 `json:"sumIntake"`
-	SumInactive              int32                 `json:"sumInactive"`
-	SumAct                   int32                 `json:"sumAct"`
-	SumRuminaBeforeThreeDays int32                 `json:"sumRuminaBeforeThreeDays"`
-	SumIntakeBeforeThreeDays int32                 `json:"sumIntakeBeforeThreeDays"`
-	MinHigh                  int32                 `json:"minHigh"`
-	MaxHigh                  int32                 `json:"maxHigh"`
-	MinChew                  int32                 `json:"minChew"`
-	Score                    int32                 `json:"score"`
-	IsMaxTime                pasturePb.IsShow_Kind `json:"isMaxTime"`
-	ReceiveNumber            int32                 `json:"receiveNumber"`
-	RecodeCount              int32                 `json:"recodeCount"`
-	ActiveTime               string                `json:"activeTime"`
-	CreatedAt                int64                 `json:"createdAt"`
-	UpdatedAt                int64                 `json:"updatedAt"`
+	Id                      int64                 `json:"id"`
+	CowId                   int64                 `json:"cowId"`
+	NeckRingNumber          string                `json:"neckRingNumber"`
+	Lact                    int32                 `json:"lact"`
+	Frameid                 int32                 `json:"frameid"`
+	HeatDate                string                `json:"heatDate"`
+	Rumina                  int32                 `json:"rumina"`
+	Intake                  int32                 `json:"intake"`
+	Inactive                int32                 `json:"inactive"`
+	Gasp                    int32                 `json:"gasp"`
+	Other                   int32                 `json:"other"`
+	High                    int32                 `json:"high"`
+	Active                  int32                 `json:"active"`
+	Voltage                 int32                 `json:"voltage"`
+	Version                 int32                 `json:"version"`
+	FilterHigh              int32                 `json:"filterHigh"`
+	FilterRumina            int32                 `json:"filterRumina"`
+	FilterChew              int32                 `json:"filterChew"`
+	WeekHigh                int32                 `json:"weekHigh"`
+	WeekAvgHighHabit        int32                 `json:"weekAvgHighHabit"`
+	WeekAvgRuminaHabit      int32                 `json:"WeekAvgRuminaHabit"`
+	WeekAvgIntakeHabit      int32                 `json:"weekAvgIntakeHabit"`
+	WeekAvgChewHabit        int32                 `json:"weekAvgChewHabit"`
+	WeekAvgInactiveHabit    int32                 `json:"weekAvgInactiveHabit"`
+	WeekAvgOtherHabit       int32                 `json:"weekAvgOtherHabit"`
+	ChangeHigh              int32                 `json:"changeHigh"`
+	ChangeRumina            int32                 `json:"changeRumina"`
+	ChangeChew              int32                 `json:"changeChew"`
+	ChangeAdjust            int32                 `json:"changeAdjust"`
+	ChangeFilter            int32                 `json:"changeFilter"`
+	RuminaFilter            int32                 `json:"ruminaFilter"`
+	ChewFilter              int32                 `json:"chewFilter"`
+	FilterCorrect           int32                 `json:"filterCorrect"`
+	SumRumina               int32                 `json:"sumRumina"`
+	SumIntake               int32                 `json:"sumIntake"`
+	SumInactive             int32                 `json:"sumInactive"`
+	SumAct                  int32                 `json:"sumAct"`
+	SumRuminaBeforeThreeDay int32                 `json:"sumRuminaBeforeThreeDay"`
+	SumIntakeBeforeThreeDay int32                 `json:"sumIntakeBeforeThreeDay"`
+	MinHigh                 int32                 `json:"minHigh"`
+	MaxHigh                 int32                 `json:"maxHigh"`
+	MinChew                 int32                 `json:"minChew"`
+	Score                   int32                 `json:"score"`
+	IsMaxTime               pasturePb.IsShow_Kind `json:"isMaxTime"`
+	IsShow                  pasturePb.IsShow_Kind `json:"isShow"`
+	ReceiveNumber           int32                 `json:"receiveNumber"`
+	RecordCount             int32                 `json:"recordCount"`
+	ActiveTime              string                `json:"activeTime"`
+	CreatedAt               int64                 `json:"createdAt"`
+	UpdatedAt               int64                 `json:"updatedAt"`
 }
 
-func (c *NeckActiveHabit) TableName() string {
+func (n *NeckActiveHabit) TableName() string {
 	return "neck_active_habit"
 }
 
@@ -66,7 +71,7 @@ func NewNeckActiveHabit(frameId int32, heatDate, neckRingNumber string, cow *Cow
 		lact = cow.Lact
 	}
 	return &NeckActiveHabit{
-		FrameId:        frameId,
+		Frameid:        frameId,
 		HeatDate:       heatDate,
 		NeckRingNumber: neckRingNumber,
 		Lact:           lact,
@@ -78,6 +83,18 @@ func NewNeckActiveHabit(frameId int32, heatDate, neckRingNumber string, cow *Cow
 		Intake:         data.Intake,
 		Other:          data.Other,
 		Rumina:         data.Rumina,
-		IsMaxTime:      pasturePb.IsShow_Ok,
+		IsShow:         pasturePb.IsShow_No,
+		IsMaxTime:      pasturePb.IsShow_No,
+		ActiveTime:     fmt.Sprintf("%s %02d:00:00", heatDate, frameId),
 	}
 }
+
+func (n *NeckActiveHabit) MergeData(data *NeckActiveHabit) {
+	n.Rumina += data.Rumina
+	n.Inactive += data.Inactive
+	n.Active += data.Active
+	n.Intake += data.Intake
+	n.Other += data.Other
+	n.Gasp += data.Gasp
+	n.High += data.High
+}

+ 1 - 1
model/neck_ring_original.go

@@ -44,7 +44,7 @@ func (n *NeckRingOriginal) TableName() string {
 
 var (
 	AvgHours = int32(6)
-	JoinKey  = "-"
+	JoinKey  = "/"
 )
 
 func (n *NeckRingOriginal) IsAvgHours() {

+ 1 - 1
model/prescription_drugs.go

@@ -8,7 +8,7 @@ type PrescriptionDrugs struct {
 	DrugsId        int64                 `json:"drugs_id"`
 	DrugsName      string                `json:"drugs_name"`
 	UseDays        int32                 `json:"use_days"`
-	Dosages        int32                 `json:"dosages"`
+	Dosages        float32               `json:"dosages"`
 	Unit           pasturePb.Unit_Kind   `json:"unit"`
 	UnitName       string                `json:"unit_name"`
 	Specs          string                `json:"specs"`

+ 3 - 0
model/system_basic.go

@@ -12,6 +12,9 @@ const (
 
 	ValueTypeFixed = 1 // 固定值
 	ValueTypeRange = 2 // 范围值
+
+	SourcePC  = "PC"
+	SourceApp = "MINI"
 )
 
 var PregnantCheckNameKeyMap = map[string]string{

+ 22 - 0
model/system_configure.go

@@ -0,0 +1,22 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+const (
+	ActiveLowest = "active_lowest"
+	RuminaLowest = "rumina_lowest"
+)
+
+type SystemConfigure struct {
+	Id        int64                 `json:"id"`
+	Name      string                `json:"name"`
+	Value     string                `json:"value"`
+	Remarks   string                `json:"remarks"`
+	IsShow    pasturePb.IsShow_Kind `json:"is_show"`
+	CreatedAt int64                 `json:"createdAt"`
+	UpdatedAt int64                 `json:"updatedAt"`
+}
+
+func (s *SystemConfigure) TableName() string {
+	return "system_configure"
+}

+ 77 - 98
module/backend/event_health.go

@@ -15,7 +15,8 @@ import (
 )
 
 // CowDiseaseCreate 牛只发病提交
-func (s *StoreEntry) CowDiseaseCreate(ctx context.Context, req *pasturePb.EventCowDiseaseRequest) error {
+func (s *StoreEntry) CowDiseaseCreate(ctx context.Context, req *pasturePb.EventCowDiseaseRequest, source string) error {
+	// 牛只信息
 	cow, err := s.GetCowInfoByCowId(ctx, int64(req.CowId))
 	if err != nil {
 		return xerr.WithStack(err)
@@ -35,138 +36,116 @@ func (s *StoreEntry) CowDiseaseCreate(ctx context.Context, req *pasturePb.EventC
 	if err != nil {
 		return xerr.WithStack(err)
 	}
-	prescription := &model.Prescription{}
-	if req.PrescriptionId > 0 {
-		prescription, err = s.GetPrescriptionById(ctx, req.PrescriptionId)
-		if err != nil {
-			return xerr.WithStack(err)
-		}
-	}
 
+	newEventCowDisease := model.NewEventCowDisease(cow, disease, req, operationUser, currUser)
 	defer func() {
 		if req.PenId > 0 {
 			s.UpdateCowPenId(ctx, int64(req.CowId), int64(req.PenId))
 		}
-	}()
 
-	newEventCowDisease := model.NewEventCowDisease(cow, disease, req, operationUser, currUser)
-	if prescription.Id > 0 {
+		// 更新牛只健康状态
+		if newEventCowDisease.HealthStatus == pasturePb.HealthStatus_Disease || newEventCowDisease.HealthStatus == pasturePb.HealthStatus_Treatment {
+			s.DB.Model(new(model.Cow)).
+				Where("id = ?", req.CowId).
+				Updates(map[string]interface{}{
+					"health_status": pasturePb.HealthStatus_Disease,
+				})
+		}
+	}()
+	// PC端直接跳过诊断过程
+	if source == model.SourcePC {
+		newEventCowDisease.DiagnosedResult = pasturePb.IsShow_Ok
+		newEventCowDisease.DiagnoseOperationId = int32(operationUser.Id)
+		newEventCowDisease.DiagnoseOperationName = operationUser.Name
+		newEventCowDisease.Source = model.SourcePC
+		newEventCowDisease.DiagnoseId = req.DiseaseId
+		newEventCowDisease.DiagnoseName = disease.Name
+		newEventCowDisease.HealthStatus = pasturePb.HealthStatus_Disease
+	}
+
+	if req.PrescriptionId > 0 || len(req.PrescriptionDetail) > 0 {
 		newEventCowDisease.HealthStatus = pasturePb.HealthStatus_Treatment
 	}
 
 	var newEventCowTreatment *model.EventCowTreatment
 	var newCowTreatmentRequest *pasturePb.CowTreatmentRequest
-	unitMap := s.UnitMap()
+	var isCreatePrescription bool
 	diseaseTypeMap := s.DiseaseTypeMap()
-	if prescription.Id > 0 {
-		prescriptionDrugs, err := s.PrescriptionDrugsByPrescriptionId(ctx, prescription.Id)
-		if err != nil {
-			return xerr.WithStack(err)
-		}
-		prescriptionDetail := make([]*pasturePb.TreatmentDrugs, len(prescriptionDrugs))
-		for i, v := range prescriptionDrugs {
-			prescriptionDetail[i] = &pasturePb.TreatmentDrugs{
-				DrugsId:   int32(v.DrugsId),
-				DrugsName: v.DrugsName,
-				Unit:      v.Unit,
-				UnitName:  unitMap[v.Unit],
-				UseNum:    float32(v.Dosages),
-			}
-		}
+	prescription := &model.Prescription{}
+	if req.PrescriptionId > 0 || len(req.PrescriptionDetail) > 0 {
+		isCreatePrescription = true
 
-		newCowTreatmentRequest = &pasturePb.CowTreatmentRequest{
-			CowId:              req.CowId,
-			PrescriptionId:     prescription.Id,
-			DiseaseId:          req.DiseaseId,
-			DiseaseName:        disease.Name,
-			PrescriptionDetail: prescriptionDetail,
-			TreatmentResult:    pasturePb.TreatmentResult_GoOn,
-			Remarks:            req.Remarks,
-			TreatmentAt:        req.DiseaseAt,
-		}
-	} else {
-		if len(req.PrescriptionDetail) <= 0 {
-			return xerr.Custom("请填写治疗处方详情")
-		}
-		prescriptionDetail := make([]*pasturePb.TreatmentDrugs, len(req.PrescriptionDetail))
-		for i, v := range req.PrescriptionDetail {
-			if v.DrugsId <= 0 {
-				return xerr.Custom("请选择药方中的药品")
-			}
-			drugsData, err := s.GetDrugsById(ctx, int64(v.DrugsId))
+		if req.PrescriptionId > 0 {
+			prescription, err = s.GetPrescriptionById(ctx, req.PrescriptionId)
 			if err != nil {
 				return xerr.WithStack(err)
 			}
-			prescriptionDetail[i] = &pasturePb.TreatmentDrugs{
-				DrugsId:   v.DrugsId,
-				DrugsName: drugsData.Name,
-				Unit:      v.Unit,
-				UnitName:  unitMap[v.Unit],
-				UseNum:    float32(v.UseNum),
+
+			prescriptionDrugs, err := s.PrescriptionDrugsByPrescriptionId(ctx, prescription.Id)
+			if err != nil {
+				return xerr.WithStack(err)
 			}
-		}
-		req.PrescriptionDetail = prescriptionDetail
-		newCowTreatmentRequest = &pasturePb.CowTreatmentRequest{
-			CowId:              req.CowId,
-			PrescriptionId:     prescription.Id,
-			DiseaseId:          req.DiseaseId,
-			DiseaseName:        disease.Name,
-			PrescriptionDetail: req.PrescriptionDetail,
-			TreatmentResult:    pasturePb.TreatmentResult_GoOn,
-			Remarks:            req.Remarks,
-			TreatmentAt:        req.DiseaseAt,
+			req.PrescriptionDetail = model.PrescriptionDrugsSlice(prescriptionDrugs).ToPB()
 		}
 	}
 
-	newEventCowTreatment = model.NewEventCowTreatment(prescription, newCowTreatmentRequest, diseaseTypeMap, operationUser)
-	newEventCowDisease.DiagnosedAt = int64(req.DiseaseAt)
-
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		if err = tx.Model(new(model.EventCowDisease)).Create(newEventCowDisease).Error; err != nil {
 			return xerr.WithStack(err)
 		}
+		newEventCowTreatment.CowDiseaseId = newEventCowDisease.Id
 
-		// 创建治疗记录
-		if err = tx.Model(new(model.EventCowTreatment)).Create(newEventCowTreatment).Error; err != nil {
-			return xerr.WithStack(err)
+		// 已有的处方使用次数+1
+		if req.PrescriptionId > 0 {
+			if err = tx.Model(new(model.Prescription)).Where("id = ?", req.PrescriptionId).
+				Update("use_count", gorm.Expr("use_count + 1")).Error; err != nil {
+				return xerr.WithStack(err)
+			}
 		}
 
-		// 创建新的处方
-		if req.PrescriptionId <= 0 {
+		// 新的临时处方
+		if req.PrescriptionId <= 0 && len(req.PrescriptionDetail) > 0 {
 			newPrescriptionRequest := &pasturePb.PrescriptionRequest{
 				Name:                 fmt.Sprintf("%s-%s-%s", disease.Name, time.Now().Format("20060102"), operationUser.Name),
 				ApplicableDiseaseIds: []int32{req.DiseaseId},
+				IsShow:               pasturePb.IsShow_Ok,
 			}
-			newPrescription := model.NewPrescription(newPrescriptionRequest, disease.Name, 1, 0, 0, currUser)
-			if err = tx.Create(newPrescription).Error; err != nil {
+			newPrescription := model.NewPrescription(newPrescriptionRequest, fmt.Sprintf("%d", disease.Id), 1, 0, 0, currUser)
+			newPrescription.UseCount += 1
+			if err = tx.Model(new(model.Prescription)).Create(newPrescription).Error; err != nil {
 				return xerr.WithStack(err)
 			}
-			// 创建处方药品
-			drugsList := make([]*pasturePb.PrescriptionDrugsList, len(req.PrescriptionDetail))
-			for _, v := range req.PrescriptionDetail {
-				drugsList = append(drugsList, &pasturePb.PrescriptionDrugsList{
-					DrugsId:   v.DrugsId,
-					DrugsName: v.DrugsName,
-					Dosages:   int32(v.UseNum),
-					Unit:      v.Unit,
-					UnitName:  v.UnitName,
-					UseDays:   1,
-				})
-			}
-			newPrescriptionDrugs := model.NewPrescriptionDrugs(newPrescription.Id, drugsList)
-			if err = tx.Create(&newPrescriptionDrugs).Error; err != nil {
+			prescription = newPrescription
+
+			newPrescriptionDrugs := model.NewPrescriptionDrugs(prescription.Id, req.PrescriptionDetail)
+			if err = tx.Model(new(model.PrescriptionDrugs)).Create(newPrescriptionDrugs).Error; err != nil {
 				return xerr.WithStack(err)
 			}
-		}
 
-		if err = tx.Model(new(model.Cow)).
-			Where("id = ?", req.CowId).
-			Updates(map[string]interface{}{
-				"health_status": pasturePb.HealthStatus_Disease,
-			}).Error; err != nil {
-			return xerr.WithStack(err)
+			newEventCowTreatment.PrescriptionId = prescription.Id
+			newEventCowTreatment.PrescriptionName = prescription.Name
 		}
 
+		// 创建治疗记录
+		if isCreatePrescription {
+			newCowTreatmentRequest = &pasturePb.CowTreatmentRequest{
+				CowId:              req.CowId,
+				PrescriptionId:     prescription.Id,
+				DiseaseId:          req.DiseaseId,
+				DiseaseName:        disease.Name,
+				DiseaseType:        disease.DiseaseType,
+				PrescriptionDetail: req.PrescriptionDetail,
+				TreatmentResult:    pasturePb.TreatmentResult_GoOn,
+				Remarks:            req.Remarks,
+				TreatmentAt:        req.DiseaseAt,
+			}
+
+			newEventCowTreatment = model.NewEventCowTreatment(prescription, newCowTreatmentRequest, diseaseTypeMap, operationUser)
+			// 创建治疗记录
+			if err = tx.Model(new(model.EventCowTreatment)).Create(newEventCowTreatment).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+		}
 		return nil
 	}); err != nil {
 		return xerr.WithStack(err)
@@ -337,14 +316,14 @@ func (s *StoreEntry) CowDiseaseTreatment(ctx context.Context, req *pasturePb.Cow
 	}
 
 	unitMap := s.UnitMap()
-	prescriptionDetail := make([]*pasturePb.TreatmentDrugs, len(prescriptionDrugs))
+	prescriptionDetail := make([]*pasturePb.PrescriptionDrugsList, len(prescriptionDrugs))
 	for i, v := range prescriptionDrugs {
-		prescriptionDetail[i] = &pasturePb.TreatmentDrugs{
+		prescriptionDetail[i] = &pasturePb.PrescriptionDrugsList{
 			DrugsId:   int32(v.DrugsId),
 			DrugsName: v.DrugsName,
 			Unit:      v.Unit,
 			UnitName:  unitMap[v.Unit],
-			UseNum:    float32(v.Dosages),
+			Dosages:   v.Dosages,
 		}
 	}
 	req.PrescriptionDetail = prescriptionDetail

+ 1 - 1
module/backend/interface.go

@@ -186,7 +186,7 @@ type EventService interface {
 	WeightBatch(ctx context.Context, req *pasturePb.EventWeight) error
 
 	// CowDiseaseCreate 提交发病牛只
-	CowDiseaseCreate(ctx context.Context, req *pasturePb.EventCowDiseaseRequest) error
+	CowDiseaseCreate(ctx context.Context, req *pasturePb.EventCowDiseaseRequest, source string) error
 	// CowDiseaseDiagnose 诊断
 	CowDiseaseDiagnose(ctx context.Context, req *pasturePb.CowDiagnosedRequest) error
 	// CowDiseaseTreatment 治疗

+ 1 - 0
module/crontab/cow_cron.go

@@ -22,6 +22,7 @@ const (
 	SameTimePlan       = "SameTimePlan"
 	WorkOrderMaster    = "WorkOrderMaster"
 	SystemBasicCrontab = "SystemBasicCrontab"
+	NeckRingOriginal   = "NeckRingOriginal"
 )
 
 // GenerateAsynqWorkOrder 异步生成工作单

+ 103 - 16
module/crontab/neck_ring.go

@@ -2,7 +2,6 @@ package crontab
 
 import (
 	"fmt"
-	"kpt-pasture/config"
 	"kpt-pasture/model"
 	"math"
 
@@ -14,15 +13,23 @@ import (
 
 // NeckRingMergeData 把
 func (e *Entry) NeckRingMergeData() error {
-	cfg := config.Options()
-	limit := cfg.NeckRingLimit
+	// 先看看上次任务有没有执行结束,结束在执行下面的任务
+	if ok := e.IsExistCrontabLog(NeckRingOriginal); ok {
+		return nil
+	}
+
+	e.CreateCrontabLog(NeckRingOriginal)
+	defer func() {
+		e.DeleteCrontabLog(NeckRingOriginal)
+	}()
+
+	limit := e.Cfg.NeckRingLimit
 	if limit <= 0 {
 		limit = 10000
 	}
-
 	neckRingList := make([]*model.NeckRingOriginal, 0)
 	if err := e.DB.Model(new(model.NeckRingOriginal)).
-		Where("h1.is_show = ?", pasturePb.IsShow_No).
+		Where("is_show = ?", pasturePb.IsShow_No).
 		Limit(int(limit)).
 		Find(&neckRingList).Error; err != nil {
 		return xerr.WithStack(err)
@@ -38,7 +45,7 @@ func (e *Entry) NeckRingMergeData() error {
 	for _, v := range neckRingList {
 		neckRingIds = append(neckRingIds, v.Id)
 		xframeId := int(math.Floor(float64(v.FrameId)/10) * 2)
-		mapKey := fmt.Sprintf("%s%s%s%s%d", v.Imei, model.JoinKey, v.ActiveDate, model.JoinKey, xframeId) // 0001-2023-12-04-0 0001-2023-12-03-4
+		mapKey := fmt.Sprintf("%s%s%s%s%d", v.Imei, model.JoinKey, v.ActiveDate, model.JoinKey, xframeId) // 0001/2023-12-04/0 0001/2023-12-03/4
 		if _, ok := originalMapData[mapKey]; !ok {
 			originalMapData[mapKey] = new(model.NeckRingOriginalMerge)
 		}
@@ -47,14 +54,13 @@ func (e *Entry) NeckRingMergeData() error {
 	}
 
 	// 算平均值
-	sumAvgImei := make(map[string]*model.NeckRingOriginalMerge)
-	for key, _ := range originalMapData {
-		if _, ok := originalMapData[key]; !ok {
-			sumAvgImei[key] = new(model.NeckRingOriginalMerge)
-		}
-		sumAvgImei[key].SumAvg()
+	for _, v := range originalMapData {
+		v.SumAvg()
 	}
 
+	// 更新脖环牛只相关信息
+	newNeckActiveHabitList := model.NeckRingOriginalMap(originalMapData).ForMatData(e.GetCowInfoByImei)
+
 	if err := e.DB.Transaction(func(tx *gorm.DB) error {
 		// 更新已处理过的id
 		if len(neckRingIds) > 0 {
@@ -66,10 +72,22 @@ func (e *Entry) NeckRingMergeData() error {
 			}
 		}
 
-		// 插入新的数据,如果存在则合并更新
-		newNeckActiveHabitList := model.NeckRingOriginalMap(sumAvgImei).ForMatData(e.GetCowInfoByImei)
-		if len(newNeckActiveHabitList) > 0 {
-			if err := tx.Create(newNeckActiveHabitList).Error; err != nil {
+		for _, neckActiveHabit := range newNeckActiveHabitList {
+			// 新数据直接插入
+			if e.IsExistNeckActiveHabit(neckActiveHabit.NeckRingNumber, neckActiveHabit.Frameid) <= 0 {
+				if err := tx.Create(neckActiveHabit).Error; err != nil {
+					return xerr.WithStack(err)
+				}
+				continue
+			}
+
+			// 更新数据
+			historyNeckActiveHabit := e.GetNeckActiveHabit(neckActiveHabit.NeckRingNumber, neckActiveHabit.Frameid)
+			historyNeckActiveHabit.MergeData(neckActiveHabit)
+			if err := tx.Model(new(model.NeckActiveHabit)).
+				Select("rumina", "rumina", "intake", "gasp", "other", "high", "active").
+				Where("id = ?", historyNeckActiveHabit.Id).
+				Updates(historyNeckActiveHabit).Error; err != nil {
 				return xerr.WithStack(err)
 			}
 		}
@@ -79,3 +97,72 @@ func (e *Entry) NeckRingMergeData() error {
 	}
 	return nil
 }
+
+func (e *Entry) ActiveHabit() error {
+
+	// 上次任务未处理完的数据
+	minNeckActiveHabit := &model.NeckActiveHabit{}
+	if err := e.DB.Model(new(model.NeckActiveHabit)).
+		Where("is_show = ?", pasturePb.IsShow_No).
+		Order("id").Limit(1).First(minNeckActiveHabit).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+
+	// 更新牛只最新数据
+	if err := e.DB.Model(new(model.NeckActiveHabit)).
+		Where("is_max_time = ?", pasturePb.IsShow_Ok).
+		Update("is_max_time", pasturePb.IsShow_No).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+
+	sqlQuery := e.DB.Model(new(model.NeckActiveHabit)).
+		Select("Max(id) as id").
+		Where("id BETWEEN ? AND ?").
+		Where("change_filter > ?", -99).
+		Where("").Group("cow_id")
+
+	if err := e.DB.Model(new(model.NeckActiveHabit)).
+		Joins("JOIN (?) bb ON neck_active_habit.id = bb.id", sqlQuery).
+		Update("is_max_time", pasturePb.IsShow_Ok).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+
+	activeLowest := e.GetSystemConfigure(model.ActiveLowest)
+	ruminaLowest := e.GetSystemConfigure(model.RuminaLowest)
+	newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
+	if err := e.DB.Model(new(model.NeckActiveHabit)).
+		Where("is_show = ?", pasturePb.IsShow_No).
+		Where(e.DB.Where("change_filter = 0").Or("is_max_time = ?", pasturePb.IsShow_Ok)).
+		Where(e.DB.Where("high >= ?", activeLowest.Value).Or("rumina >= ?", ruminaLowest.Value)).
+		Order("cow_id,id").Find(&newNeckActiveHabitList).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+
+	var (
+		lastCowId    = int64(0)
+		filterValues = make(map[int64]*model.NeckActiveHabit)
+	)
+	// 活动量滤波
+	for _, v := range newNeckActiveHabitList {
+		if v.CowId != lastCowId {
+			lastCowId = v.CowId
+			filterValues[v.CowId] = &model.NeckActiveHabit{CowId: v.CowId}
+		}
+
+		prev := filterValues[v.CowId]
+		v.FilterHigh = int32(computeIfPositiveElse(float64(v.FilterHigh), float64(v.High), float64(prev.FilterHigh), 0.23, 0.77))
+		v.FilterRumina = int32(computeIfPositiveElse(float64(v.FilterRumina), float64(v.Rumina), float64(prev.FilterRumina), 0.33, 0.67))
+		v.FilterHigh = int32(computeIfPositiveElse(float64(v.FilterChew), float64(v.Rumina+v.Intake), float64(prev.FilterChew), 0.23, 0.77))
+		// 更新过滤值
+		filterValues[v.CowId] = v
+	}
+	return nil
+}
+
+// 辅助函数来计算过滤值
+func computeIfPositiveElse(filterValue, newValue, prevFilterValue float64, weightPrev, weightNew float64) float64 {
+	if filterValue > 0 {
+		return filterValue
+	}
+	return math.Ceil(weightPrev*prevFilterValue + weightNew*newValue)
+}

+ 24 - 12
module/crontab/other.go

@@ -27,18 +27,26 @@ func (e *Entry) IsExistCrontabLog(name string) bool {
 }
 
 func (e *Entry) CreateCrontabLog(name string) {
+	// 日志保留15天以内的
+	nowDay := time.Now()
+	defer func() {
+		if nowDay.Day()%15 == 0 {
+			beforeDay := nowDay.AddDate(0, 0, -15)
+			beforeDayFormat := beforeDay.Format(model.LayoutDate2)
+			e.DB.Model(&model.CronLog{}).
+				Where("date < ?", beforeDayFormat).
+				Where("name != ?", NeckRingOriginal).
+				Delete(&model.CronLog{})
+		}
+	}()
 	crontabLog := model.NewCronLog(name)
 	if err := e.DB.Model(&model.CronLog{}).Create(crontabLog).Error; err != nil {
 		zaplog.Error("CreateCrontabLog", zap.Any("err", err), zap.String("name", name))
 	}
+}
 
-	// 日志保留15天以内的
-	nowDay := time.Now()
-	beforeDay := nowDay.AddDate(0, 0, -15)
-	beforeDayFormat := beforeDay.Format(model.LayoutDate2)
-	if err := e.DB.Model(&model.CronLog{}).Where("date < ?", beforeDayFormat).Delete(&model.CronLog{}).Error; err != nil {
-		zaplog.Error("CreateCrontabLog", zap.Any("err", err), zap.String("name", name))
-	}
+func (e *Entry) DeleteCrontabLog(name string) {
+	e.DB.Model(&model.CronLog{}).Where("name = ?", name).Delete(&model.CronLog{})
 }
 
 // CreatedCalendar 创建当天工单日历记录
@@ -47,20 +55,24 @@ func (e *Entry) CreatedCalendar(calendarType pasturePb.CalendarType_Kind, count
 	newCalendar := model.NewCalendar(calendarTypeName, calendarType, count)
 
 	historyCalendar := &model.Calendar{}
+	historyCount := int64(0)
 	if err := e.DB.Model(&model.Calendar{}).Where("calendar_type = ?", calendarType).
-		Where("show_day = ?", time.Now().Format(model.LayoutDate2)).First(historyCalendar).Error; err != nil {
+		Where("show_day = ?", time.Now().Format(model.LayoutDate2)).Count(&historyCount).First(historyCalendar).Error; err != nil {
 		zaplog.Error("CreatedCalendar", zap.Any("err", err), zap.Any("historyCalendar", historyCalendar))
 	}
-	if historyCalendar.Id <= 0 {
+
+	if historyCount <= 0 {
 		if err := e.DB.Model(&model.Calendar{}).Create(newCalendar).Error; err != nil {
 			zaplog.Error("CreatedCalendar", zap.Any("err", err), zap.Any("workOrderCalendar", newCalendar))
 		}
 		return
 	}
 
-	if err := e.DB.Model(&model.Calendar{}).Where("id = ?", historyCalendar.Id).
-		Update("count", count).Error; err != nil {
-		zaplog.Error("CreatedCalendar", zap.Any("err", err), zap.Any("historyCalendar", historyCalendar))
+	if historyCount > 0 {
+		if err := e.DB.Model(&model.Calendar{}).Where("id = ?", historyCalendar.Id).
+			Update("count", count).Error; err != nil {
+			zaplog.Error("CreatedCalendar", zap.Any("err", err), zap.Any("historyCalendar", historyCalendar))
+		}
 	}
 }
 

+ 31 - 1
module/crontab/sql.go

@@ -22,7 +22,37 @@ func (e *Entry) GetPenMapList() (map[int32]*model.Pen, error) {
 
 func (e *Entry) GetCowInfoByImei(imei string) *model.Cow {
 	res := &model.Cow{}
-	if err := e.DB.Model(new(model.Cow)).Where("imei = ?", imei).First(res).Error; err != nil {
+	if err := e.DB.Model(new(model.Cow)).Where("neck_ring_number = ?", imei).First(res).Error; err != nil {
+		return nil
+	}
+	return res
+}
+
+func (e *Entry) IsExistNeckActiveHabit(neckRingNumber string, frameId int32) int64 {
+	count := int64(0)
+	if err := e.DB.Model(new(model.NeckActiveHabit)).
+		Where("neck_ring_number = ? and frameid = ?", neckRingNumber, frameId).Count(&count).Error; err != nil {
+		return 0
+	}
+	return count
+}
+
+func (e *Entry) GetNeckActiveHabit(neckRingNumber string, frameId int32) *model.NeckActiveHabit {
+	res := &model.NeckActiveHabit{}
+	if err := e.DB.Model(new(model.NeckActiveHabit)).
+		Where("neck_ring_number = ? and frameid = ?", neckRingNumber, frameId).
+		First(res).Error; err != nil {
+		return nil
+	}
+	return res
+}
+
+func (e *Entry) GetSystemConfigure(name string) *model.SystemConfigure {
+	res := &model.SystemConfigure{}
+	if err := e.DB.Model(new(model.SystemConfigure)).
+		Where("name = ?", name).
+		Where("is_show = ?", pasturePb.IsShow_Ok).
+		First(res).Error; err != nil {
 		return nil
 	}
 	return res

+ 71 - 0
module/crontab/work_cron_test.go

@@ -1,9 +1,80 @@
 package crontab
 
 import (
+	"encoding/json"
+	"fmt"
+	"kpt-pasture/model"
 	"testing"
 )
 
 func TestEntry_SameTimePlan(t *testing.T) {
+	neckActiveHabit := make([]*model.NeckActiveHabit, 0)
+	neckActiveHabit = append(neckActiveHabit, &model.NeckActiveHabit{
+		Id:           15408026,
+		CowId:        117,
+		High:         179,
+		FilterHigh:   0,
+		Rumina:       61,
+		FilterRumina: 0,
+		Intake:       0,
+		FilterChew:   59,
+	}, &model.NeckActiveHabit{
+		Id:           15408028,
+		CowId:        294,
+		High:         724,
+		FilterHigh:   0,
+		Rumina:       33,
+		FilterRumina: 0,
+		Intake:       18,
+		FilterChew:   45,
+	}, /*, &model.NeckActiveHabit{
+		Id:           15406800,
+		CowId:        297,
+		High:         944,
+		FilterHigh:   0,
+		Rumina:       24,
+		FilterRumina: 0,
+		Intake:       7,
+		FilterChew:   29,
+	}, &model.NeckActiveHabit{
+		Id:           15406801,
+		CowId:        299,
+		High:         615,
+		FilterHigh:   0,
+		Rumina:       37,
+		FilterRumina: 43,
+		Intake:       1,
+		FilterChew:   46,
+	}, &model.NeckActiveHabit{
+		Id:           15405632,
+		CowId:        315,
+		High:         1128,
+		FilterHigh:   0,
+		Rumina:       16,
+		FilterRumina: 18,
+		Intake:       37,
+		FilterChew:   45,
+	}*/)
 
+	var (
+		lastCowId    = int64(0)
+		filterValues = make(map[int64]*model.NeckActiveHabit)
+	)
+	// 活动量滤波
+	for _, v := range neckActiveHabit {
+		if v.CowId != lastCowId {
+			lastCowId = v.CowId
+			filterValues[v.CowId] = &model.NeckActiveHabit{CowId: v.CowId}
+		}
+
+		prev := filterValues[v.CowId]
+		v.FilterHigh = int32(computeIfPositiveElse(float64(v.FilterHigh), float64(v.High), float64(prev.FilterHigh), 0.23, 0.77))
+		v.FilterRumina = int32(computeIfPositiveElse(float64(v.FilterRumina), float64(v.Rumina), float64(prev.FilterRumina), 0.33, 0.67))
+		v.FilterHigh = int32(computeIfPositiveElse(float64(v.FilterChew), float64(v.Rumina+v.Intake), float64(prev.FilterChew), 0.23, 0.77))
+		// 更新过滤值
+		filterValues[v.CowId] = v
+	}
+
+	b, _ := json.Marshal(neckActiveHabit)
+	fmt.Println(string(b))
 }