Browse Source

work: calendar update

Yi 4 days ago
parent
commit
2e586e10c3

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250325071609-113a7f4c6da5
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250326061245-9a4fbec39fb6
 	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

+ 10 - 0
go.sum

@@ -86,6 +86,16 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250325011618-727f0797ea27 h1:DruuERLr
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250325011618-727f0797ea27/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250325071609-113a7f4c6da5 h1:gOfJObe2DLEfFjO+8+atJ2mLWAo6HAkOnYQIFW4P7tk=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250325071609-113a7f4c6da5/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250325093632-db9c4586260e h1:d5OaTPXG1JP/2k11WBgj/pggSMrBYYT67R9pD/Z9la4=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250325093632-db9c4586260e/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250326020249-4550f6f60bbe h1:gR2DdJByndC/DBKOIV0c6yA6PiPkMaL9BSRREGdl/tw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250326020249-4550f6f60bbe/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250326020740-d3d1bc9a851f h1:vQm+DMaNM40JJAkx/KUgfBbDYZxrLv4dAUbqS8k7Y68=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250326020740-d3d1bc9a851f/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250326060130-a292235a6f1a h1:GMMirOkHyFlcj8l5DgPWc5CR2qFDg/nWU+iNi2kL9Aw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250326060130-a292235a6f1a/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250326061245-9a4fbec39fb6 h1:mfOzWgdB2NIgdunlgKAQGuZWGYidEJizQRHu2T4HXR4=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250326061245-9a4fbec39fb6/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=

+ 3 - 3
http/handler/event/event_breed.go

@@ -381,14 +381,14 @@ func WeaningCreateBatch(c *gin.Context) {
 	}
 
 	if err := valid.ValidateStruct(&req,
-		valid.Field(&req.WeaningAt, valid.Required),
-		valid.Field(&req.OperationId, valid.Required),
-		valid.Field(&req.PenId, valid.Required),
 		valid.Field(&req.Items, valid.Required, valid.Each(valid.By(func(value interface{}) error {
 			item := value.(pasturePb.WeaningItem)
 			return valid.ValidateStruct(&item,
 				valid.Field(&item.EarNumber, valid.Required),
 				valid.Field(&item.Weight, valid.Required),
+				valid.Field(&item.WeaningAt, valid.Required),
+				valid.Field(&item.OperationId, valid.Required),
+				valid.Field(&item.PenId, valid.Required),
 			)
 		}))),
 	); err != nil {

+ 1 - 1
http/handler/work/calendar.go

@@ -80,7 +80,7 @@ func CalendarToDoList(c *gin.Context) {
 		apierr.ClassifiedAbort(c, err)
 		return
 	}
-	c.JSON(http.StatusOK, res)
+	ginutil.JSONResp(c, res)
 }
 
 func ImmunizationItems(c *gin.Context) {

+ 16 - 45
http/middleware/log.go

@@ -2,12 +2,9 @@ package middleware
 
 import (
 	"bytes"
-	"io"
 	"io/ioutil"
 	"net/http"
-	"runtime"
 	"runtime/debug"
-	"strings"
 	"time"
 
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
@@ -20,15 +17,6 @@ type responseBodyWriter struct {
 	body *bytes.Buffer
 }
 
-type stackErr struct {
-	Err   error
-	Stack string
-}
-
-func (s *stackErr) Error() string {
-	return s.Err.Error()
-}
-
 func (r responseBodyWriter) Write(b []byte) (int, error) {
 	r.body.Write(b)
 	return r.ResponseWriter.Write(b)
@@ -75,40 +63,23 @@ func GinRecovery(stack bool) gin.HandlerFunc {
 	return func(c *gin.Context) {
 		defer func() {
 			if err := recover(); err != nil {
-				defer func() {
-					if err = recover(); err != nil {
-						body, _ := ioutil.ReadAll(c.Request.Body)
-
-						// 获取 panic 发生的位置
-						pc, file, line, ok := runtime.Caller(2)
-						funcName := ""
-						if ok {
-							fn := runtime.FuncForPC(pc).Name()
-							// 去除包路径,只保留函数名
-							/*funcName = filepath.Base(fn)
-							file = filepath.Base(file)*/
-							parts := strings.Split(fn, "/")
-							if len(parts) > 0 {
-								lastPart := parts[len(parts)-1]
-								parts = strings.Split(lastPart, ".")
-								if len(parts) > 0 {
-									funcName = parts[len(parts)-1]
-								}
-							}
-							file = strings.TrimPrefix(file, c.Request.Context().Value(gin.ContextKey).(string)+"/") // 尝试去除项目路径前缀(可选)
-						}
-						zaplog.Error("cors",
-							zap.Any("recover", err),
-							zap.Any("url", c.Request.URL),
-							zap.Any("file", file),
-							zap.Any("line", line),
-							zap.Any("func", funcName),
-							zap.Any("request", string(body)),
-						)
-						c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
-					}
-				}()
+				body, _ := ioutil.ReadAll(c.Request.Body)
+				// 获取 panic 发生的位置
+				var stackTrace []byte
+				if stack {
+					// 获取调用栈
+					stackTrace = debug.Stack()
+				}
+				zaplog.Error("panic",
+					zap.Any("recover", err),
+					zap.Any("url", c.Request.URL),
+					zap.Any("stackTrace", string(stackTrace)),
+					zap.Any("request", string(body)),
+					zap.String("x-request-id", c.GetHeader("X-Request-ID")),
+				)
 				c.AbortWithStatus(http.StatusInternalServerError)
+				c.Abort()
+				return
 			}
 		}()
 		c.Next()

+ 1 - 1
http/route/root.go

@@ -13,12 +13,12 @@ func Root(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		for _, opt := range opts {
 			opt(s)
 		}
+		s.Use(middleware.GinRecovery(true))
 		s.Use(
 			middleware.CORS(),
 			middleware.Pagination(),
 			requestid.New(),
 			gzip.Gzip(gzip.DefaultCompression),
-			middleware.GinRecovery(true),
 		)
 	}
 }

+ 1 - 1
http/route/system_api.go

@@ -62,6 +62,6 @@ func SystemAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 func authRouteGroup(s *gin.Engine, relativePath string) *gin.RouterGroup {
 	group := s.Group(relativePath)
 	// 中间件鉴权
-	group.Use(middleware.RequireAdmin(), middleware.CORS(), middleware.GinLogger())
+	group.Use(middleware.RequireAdmin(), middleware.GinLogger())
 	return group
 }

+ 1 - 0
model/calendar.go

@@ -86,5 +86,6 @@ func (c CalendarSlice) ToPB() []*pasturePb.Calendar {
 
 type TodayCompletedData struct {
 	Count            int32
+	CalendarTypeKind pasturePb.CalendarType_Kind
 	CalendarTypeName string
 }

+ 1 - 0
model/cow.go

@@ -405,6 +405,7 @@ func NewEnterCow(pastureId int64, req *pasturePb.EventEnterRequest, penMap map[i
 		BirthWeight:         int64(req.Weight * 1000),
 		LastWeightAt:        int64(req.EstrusAt),
 		CurrentWeight:       int64(req.Weight * 1000),
+		LastDryMilkAt:       int64(req.DryMilkAt),
 	}
 }
 

+ 3 - 3
model/event_dry_milk.go

@@ -17,7 +17,7 @@ type EventDryMilk struct {
 	PlanDay       int64                 `json:"planDay"`
 	RealityDay    int64                 `json:"realityDay"`
 	EndDay        int64                 `json:"endDay"`
-	IsShow        pasturePb.IsShow_Kind `json:"isShow"`
+	Status        pasturePb.IsShow_Kind `json:"status"`
 	Remarks       string                `json:"remarks"`
 	OperationId   int64                 `json:"operationId"`
 	OperationName string                `json:"operationName"`
@@ -35,7 +35,7 @@ func (e *EventDryMilk) EventDryMilkUpdate(cow *Cow, dryMilkAt int64, pen *Pen, o
 	e.Lact = cow.Lact
 	e.RealityDay = dryMilkAt
 	e.Remarks = remarks
-	e.IsShow = pasturePb.IsShow_Ok
+	e.Status = pasturePb.IsShow_Ok
 	e.OperationId = operation.Id
 	e.OperationName = operation.Name
 	e.MessageId = message.Id
@@ -52,7 +52,7 @@ func NewEventDryMilk(pastureId int64, cow *Cow, startDay, endDay string) *EventD
 		Lact:      cow.Lact,
 		PlanDay:   util.TimeParseLocalUnix(startDay),
 		EndDay:    util.TimeParseLocalUnix(endDay),
-		IsShow:    pasturePb.IsShow_No,
+		Status:    pasturePb.IsShow_No,
 	}
 }
 

+ 33 - 20
module/backend/calendar.go

@@ -18,23 +18,29 @@ func (s *StoreEntry) CalendarToDoList(ctx context.Context, req *pasturePb.Calend
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}
-	whereSql := fmt.Sprintf(" AND pasture_id = %d AND end_day <= %d ", userModel.AppPasture.Id, util.TimeParseLocalEndUnix(time.Now().Format(model.LayoutDate2)))
+	whereSql := ""
+	if req.EarNumber != "" {
+		whereSql += fmt.Sprintf(` AND ear_number = '%s' `, req.EarNumber)
+	}
+	whereSql += fmt.Sprintf(" AND pasture_id = %d AND end_day <= %d ", userModel.AppPasture.Id, util.TimeParseLocalEndUnix(time.Now().Format(model.LayoutDate2)))
 
 	calendarToDoList := make([]*pasturePb.CalendarToDoList, 0)
-	sql := `SELECT a.cow_id,b.pen_name,a.calendar_type_name,DATE_FORMAT(FROM_UNIXTIME(a.plan_day), '%Y-%m-%d') AS plan_day,a.remaining_days,b.lact,b.ear_number FROM (
-		SELECT cow_id,plan_day,'免疫' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_immunization_plan WHERE status = 2` + whereSql + `
+	sql := `SELECT a.cow_id,b.pen_name,a.calendar_type_name,a.calendar_type_kind as calendar_type,DATE_FORMAT(FROM_UNIXTIME(a.plan_day), '%Y-%m-%d') AS plan_day,a.remaining_days,b.lact,b.ear_number FROM (
+		SELECT cow_id,plan_day,'免疫' as calendar_type_name,1 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_immunization_plan WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,plan_day,'同期' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_cow_same_time WHERE status = 2` + whereSql + `
+		SELECT cow_id,plan_day,'同期' as calendar_type_name,2 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_cow_same_time WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,plan_day,'孕检' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_pregnant_check WHERE status = 2` + whereSql + `
+		SELECT cow_id,plan_day,'孕检' as calendar_type_name,4 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_pregnant_check WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,plan_day,'断奶' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_weaning WHERE status = 2` + whereSql + `
+		SELECT cow_id,plan_day,'断奶' as calendar_type_name,6 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_weaning WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,plan_day,'配种' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_mating WHERE status = 2` + whereSql + `
+		SELECT cow_id,plan_day,'配种' as calendar_type_name,8 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_mating WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,plan_day,'产犊' as calendar_type_name,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_calving WHERE status = 2` + whereSql + `
+		SELECT cow_id,plan_day,'产犊' as calendar_type_name,9 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_calving WHERE status = 2` + whereSql + `
 		UNION ALL
-		SELECT cow_id,disease_at as plan_day,'疾病' as calendar_type_name,0 AS remaining_days FROM event_cow_disease WHERE diagnosed_result IN (2,3) AND pasture_id = ` + fmt.Sprintf("%d", userModel.AppPasture.Id) + `
+		SELECT cow_id,plan_day,'干奶' as calendar_type_name,9 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days FROM event_dry_milk WHERE status = 2` + whereSql + `
+		UNION ALL
+		SELECT cow_id,disease_at as plan_day,'疾病' as calendar_type_name,7 as calendar_type_kind,0 AS remaining_days FROM event_cow_disease WHERE diagnosed_result IN (2,3) AND pasture_id = ` + fmt.Sprintf("%d", userModel.AppPasture.Id) + `
 	) as a JOIN cow b ON a.cow_id = b.id WHERE 1 = 1 `
 
 	completeSql := fmt.Sprintf("%s ORDER BY a.plan_day DESC", sql)
@@ -43,30 +49,37 @@ func (s *StoreEntry) CalendarToDoList(ctx context.Context, req *pasturePb.Calend
 	}
 
 	nowTime := time.Now().Format(model.LayoutDate2)
-	todayCompletedSql := `SELECT a.count as count,a.calendar_type_name as calendar_type_name FROM (
-		SELECT count('cow_id') as count,'免疫' as calendar_type_name FROM event_immunization_plan WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
+	todayCompletedSql := `SELECT a.count as count,a.calendar_type_name as calendar_type_name,a.calendar_type_kind as calendar_type_kind FROM (
+		SELECT count('cow_id') as count,'免疫' as calendar_type_name,1 as calendar_type_kind FROM event_immunization_plan WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
+		UNION ALL
+		SELECT count('cow_id') as count,'同期' as calendar_type_name,2 as calendar_type_kind FROM event_cow_same_time WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
 		UNION ALL
-		SELECT count('cow_id') as count,'同期' as calendar_type_name FROM event_cow_same_time WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
+		SELECT count('cow_id') as count,'孕检' as calendar_type_name,4 as calendar_type_kind FROM event_pregnant_check WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
 		UNION ALL
-		SELECT count('cow_id') as count,'孕检' as calendar_type_name FROM event_pregnant_check WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
+		SELECT count('cow_id') as count,'断奶' as calendar_type_name,6 as calendar_type_kind FROM event_weaning WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
 		UNION ALL
-		SELECT count('cow_id') as count,'断奶' as calendar_type_name FROM event_weaning WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
+		SELECT count('cow_id') as count,'配种' as calendar_type_name,8 as calendar_type_kind FROM event_mating WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
 		UNION ALL
-		SELECT count('cow_id') as count,'配种' as calendar_type_name FROM event_mating WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
+		SELECT count('cow_id') as count,'产犊' as calendar_type_name,9 as calendar_type_kind FROM event_calving WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
 		UNION ALL
-		SELECT count('cow_id') as count,'产犊' as calendar_type_name FROM event_calving WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?
+		SELECT count('cow_id') as count,'干奶' as calendar_type_name,10 as calendar_type_kind FROM event_dry_milk WHERE status = 1 AND DATE_FORMAT(FROM_UNIXTIME(reality_day), '%Y-%m-%d') = ?		
 		UNION ALL
-		SELECT count('cow_id') as count,'疾病' as calendar_type_name FROM event_cow_disease WHERE diagnosed_result = 4 AND DATE_FORMAT(FROM_UNIXTIME(curable_at), '%Y-%m-%d') = ?
+		SELECT count('cow_id') as count,'疾病' as calendar_type_name,7 as calendar_type_kind FROM event_cow_disease WHERE diagnosed_result = 4 AND DATE_FORMAT(FROM_UNIXTIME(curable_at), '%Y-%m-%d') = ?
 	) as a `
 
 	toDayCompletedList := make([]*model.TodayCompletedData, 0)
-	if err = s.DB.Raw(todayCompletedSql, nowTime, nowTime, nowTime, nowTime, nowTime, nowTime, nowTime).Find(&toDayCompletedList).Error; err != nil {
+	if err = s.DB.Raw(todayCompletedSql, nowTime, nowTime, nowTime, nowTime, nowTime, nowTime, nowTime, nowTime).
+		Find(&toDayCompletedList).Error; err != nil {
 		return nil, xerr.WithStack(err)
 	}
 
-	toDayCompletedCountMap := make(map[string]int32)
+	toDayCompletedCountMap := make(map[pasturePb.CalendarType_Kind]*pasturePb.ProgressList)
 	for _, v := range toDayCompletedList {
-		toDayCompletedCountMap[v.CalendarTypeName] = v.Count
+		toDayCompletedCountMap[v.CalendarTypeKind] = &pasturePb.ProgressList{
+			CalendarTypeKind: v.CalendarTypeKind,
+			CalendarName:     v.CalendarTypeName,
+			CompletedCount:   v.Count,
+		}
 	}
 
 	list, total := Paginate(calendarToDoList, req, pagination)

+ 17 - 15
module/backend/calendar_more.go

@@ -261,27 +261,29 @@ func Paginate(slice []*pasturePb.CalendarToDoList, req *pasturePb.CalendarToDoRe
 	return newSlice[start:end], total
 }
 
-func ProgressList(dataList []*pasturePb.CalendarToDoList, toDayCompletedCountMap map[string]int32) map[string]*pasturePb.ProgressList {
+func ProgressList(dataList []*pasturePb.CalendarToDoList, toDayCompletedCountMap map[pasturePb.CalendarType_Kind]*pasturePb.ProgressList) map[string]*pasturePb.ProgressList {
 	res := make(map[string]*pasturePb.ProgressList)
-	for cn, cc := range toDayCompletedCountMap {
-		res[cn] = &pasturePb.ProgressList{
-			CalendarName:   cn,
-			CompletedCount: cc,
-		}
+	dMap := map[pasturePb.CalendarType_Kind][]*pasturePb.CalendarToDoList{}
 
-		for _, d := range dataList {
-			calendarName := CalendarTypeMap()[d.CalendarType]
-			if calendarName != cn {
-				continue
+	for _, v := range dataList {
+		dMap[v.CalendarType] = append(dMap[v.CalendarType], v)
+	}
+
+	for kind, cc := range toDayCompletedCountMap {
+		if res[cc.CalendarName] == nil {
+			res[cc.CalendarName] = &pasturePb.ProgressList{
+				CalendarTypeKind: kind,
+				CalendarName:     cc.CalendarName,
+				Color:            model.CalendarTypeColorMap[kind],
+				CompletedCount:   cc.CompletedCount,
+				IncompleteTotal:  int32(len(dMap[kind])),
 			}
-			res[cn].CalendarTypeKind = d.CalendarType
-			res[cn].IncompleteTotal += 1
 		}
 
-		if res[cn].IncompleteTotal > 0 && res[cn].CompletedCount > 0 {
-			res[cn].Progress = strconv.FormatFloat(float64(res[cn].CompletedCount)/float64(res[cn].IncompleteTotal)*100, 'f', 2, 64)
+		if res[cc.CalendarName].IncompleteTotal > 0 && res[cc.CalendarName].CompletedCount > 0 {
+			res[cc.CalendarName].Progress = strconv.FormatFloat(float64(res[cc.CalendarName].CompletedCount)/float64(res[cc.CalendarName].IncompleteTotal)*100, 'f', 2, 64)
 		} else {
-			res[cn].Progress = "0%"
+			res[cc.CalendarName].Progress = "0%"
 		}
 	}
 

+ 28 - 31
module/backend/event_breed_more.go

@@ -479,42 +479,39 @@ func (s *StoreEntry) WeaningBatch(ctx context.Context, req *pasturePb.EventWeani
 	if len(req.Items) <= 0 {
 		return nil
 	}
-	cowIds := make([]int64, 0)
-	cowWeightMap := make(map[int64]float64)
-	for _, item := range req.Items {
-		cowIds = append(cowIds, int64(item.CowId))
-		cowWeightMap[int64(item.CowId)] = float64(item.Weight)
+	if len(req.Items) > 50 {
+		return xerr.Custom("最多只能添加50条数据")
 	}
 
-	eventWeaningList := make([]*model.EventWeaning, 0)
-	if err = s.DB.Model(new(model.EventWeaning)).
-		Where("cow_id IN ?", cowIds).
-		Where("status = ?", pasturePb.IsShow_No).
-		Find(&eventWeaningList).Error; err != nil {
-		return xerr.WithStack(err)
-	}
+	if err = s.DB.Transaction(func(tx *gorm.DB) error {
+		for _, item := range req.Items {
+			cowInfo, err := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, item.EarNumber)
+			if err != nil {
+				return xerr.WithStack(err)
+			}
 
-	operation, err := s.GetSystemUserById(ctx, int64(req.OperationId))
-	if err != nil {
-		return xerr.WithStack(err)
-	}
-	req.OperationName = operation.Name
+			eventWeaning := &model.EventWeaning{}
+			if err = s.DB.Model(new(model.EventWeaning)).
+				Where("ear_number = ?", item.EarNumber).
+				Where("status = ?", pasturePb.IsShow_No).
+				First(&eventWeaning).Error; err != nil {
+				return xerr.WithStack(err)
+			}
 
-	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-		cowInfo := &model.Cow{}
-		for _, eventWeaning := range eventWeaningList {
-			eventWeaning.EventUpdate(int64(req.WeaningAt), int32(cowWeightMap[cowInfo.Id]*1000), req.Remarks, req.PenId, operation, userModel.SystemUser)
+			operation, err := s.GetSystemUserById(ctx, int64(item.OperationId))
+			if err != nil {
+				return xerr.WithStack(err)
+			}
+
+			eventWeaning.EventUpdate(int64(item.WeaningAt), int32(item.Weight*1000), item.Remarks, item.PenId, operation, userModel.SystemUser)
 			if err = tx.Model(new(model.EventWeaning)).
 				Select("status", "reality_day", "operation_id", "operation_name", "message_id", "message_name", "remarks", "after_pen_id").
 				Where("id = ?", eventWeaning.Id).
 				Updates(eventWeaning).Error; err != nil {
 				return xerr.WithStack(err)
 			}
-			cowInfo, err = s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, eventWeaning.CowId)
-			if err != nil {
-				return xerr.WithStack(err)
-			}
-			cowInfo.EventWeaningUpdate(int64(req.WeaningAt), req.PenId, int64(cowWeightMap[cowInfo.Id]*1000))
+
+			cowInfo.EventWeaningUpdate(int64(item.WeaningAt), item.PenId, int64(item.Weight*1000))
 			if err = tx.Model(new(model.Cow)).
 				Select("pen_id", "current_weight", "weaning_at", "last_weight_at").
 				Where("id = ?", cowInfo.Id).
@@ -523,11 +520,11 @@ func (s *StoreEntry) WeaningBatch(ctx context.Context, req *pasturePb.EventWeani
 			}
 			// 创建牛只的体重记录
 			eventWeight := &pasturePb.EventWeight{
-				WeightAt:      req.WeaningAt,
-				OperationId:   req.OperationId,
-				OperationName: req.OperationName,
-				Remarks:       req.Remarks,
-				Weight:        float32(cowWeightMap[cowInfo.Id]),
+				WeightAt:      item.WeaningAt,
+				OperationId:   int32(operation.Id),
+				OperationName: operation.Name,
+				Remarks:       item.Remarks,
+				Weight:        item.Weight,
 				Height:        0,
 			}
 			newEventWeight := model.NewEventWeight(userModel.AppPasture.Id, cowInfo, userModel.SystemUser, eventWeight)

+ 2 - 7
module/backend/event_cow_log.go

@@ -151,17 +151,12 @@ func (s *StoreEntry) SubmitEventLog(ctx context.Context, pastureId int64, cow *m
 		operationUser.Id = data.OperationId
 		operationUser.Name = data.OperationName
 	case pasturePb.EventType_Weaning:
-		data := req.(*pasturePb.EventWeaningBatch)
+		data := req.(*pasturePb.WeaningItem)
 		eventAt = int64(data.WeaningAt)
 		operationUser.Id = int64(data.OperationId)
 		operationUser.Name = data.OperationName
 		remarks = data.Remarks
-		for _, v := range data.Items {
-			if int64(v.CowId) == cow.Id {
-				desc = fmt.Sprintf("具体体重: %s", strconv.FormatFloat(float64(v.Weight), 'f', 2, 64))
-				break
-			}
-		}
+		desc = fmt.Sprintf("具体体重: %s", strconv.FormatFloat(float64(data.Weight), 'f', 2, 64))
 	case pasturePb.EventType_Sale:
 		data := req.(*pasturePb.EventCowSale)
 		eventAt = int64(data.SaleAt)

+ 1 - 1
module/backend/neck_ring_warning.go

@@ -47,7 +47,7 @@ func (s *StoreEntry) EstrusOrAbortionCowList(ctx context.Context, req *pasturePb
 			Joins(fmt.Sprintf("JOIN %s AS b on a.cow_id = b.id", new(model.Cow).TableName())).
 			Where("b.last_mating_at < UNIX_TIMESTAMP(a.date_time)").
 			Where("b.admission_status = ?", pasturePb.AdmissionStatus_Admission).
-			Where("b.is_not_mating = ?", pasturePb.IsShow_No).
+			Where("b.is_forbidden_mating = ?", pasturePb.IsShow_No).
 			Where("a.level >= ?", pasturePb.EstrusLevel_Low).
 			Where("a.pasture_id = ?", userModel.AppPasture.Id).
 			Where("a.date_time BETWEEN ? AND ?", startTime, entTime).