Yi пре 3 дана
родитељ
комит
733e862f91

+ 43 - 18
README.md

@@ -6,13 +6,12 @@ kpt-pasture- 科湃腾牧场管理系统
 
 
 - Go >= 1.19
 - Go >= 1.19
 - MySQL >= 5.7
 - MySQL >= 5.7
-- Docker CE >= 19.03
-- Docker compose
+- Docker CE >= 26.1.3
+- Docker compose >= 2.27.0
 
 
 ## Develops
 ## Develops
 
 
 本地开始开发前,请先阅读 README 和 Makefile,标准使用流程:
 本地开始开发前,请先阅读 README 和 Makefile,标准使用流程:
-
 需要设置的环境变量:
 需要设置的环境变量:
 
 
 - export APP_ENVIRONMENT=test
 - export APP_ENVIRONMENT=test
@@ -39,18 +38,44 @@ lint:
 5. app_pasture_list
 5. app_pasture_list
 6. app_pasture_receiver
 6. app_pasture_receiver
 
 
-
-todo列表:
-- [x] module/crontab/crontab.go 中119行[Limit(100)] 待优化,case为产后日期类型待测试
-- [x] 后台添加配种数据时候,不知道该牛只是同期还是自然发情还是人工揭发?
-- [x] 青年牛转后备牛事件(到达主动停配期主动转?)
-- [x] 后备牛到达主动停配期后的牛只放在哪个模块(配种清单,发情清单)
-- [x] 发情清单和配种清单更新机制
-- [ ] 前后端部署架构【k8s,docker-compose,docker-swarm】namespace隔离,需要考虑的问题【1.一次性任务,2. 定时任务 3. 数据收集,4. 日志收集 5. 报警介入】
-- [x] 所有事件录入梳理【批量录入,excel导入,信息人员与操作人员统一规范】
-- [x] 药品优化成药品名称关联生产商
-- [x] 框架logrus日志优化【未按照指定天数的日志自动删除,待验证】
-- [x] 犊牛的牛只品种是根据母牛的品种来确定,还是根据公牛来确定?【目前是根据母牛品种来确定】
-
-脖环发情算法梳理:
-- [x] 处理异常上报数据(frameid > 12)
+## 项目文档:
+- cmd -容器启动命令参数入口
+- config -配置文件入口
+- dep -容器依赖注入模块
+- files -静态文件入口
+- http -http 相关
+    - debug -调试相关
+    - handler -路由处理
+    - middleware -中间件
+    - router -路由配置
+    - util -工具类
+    - server.go -服务启动入口
+- locales -国际化
+- migrator -数据库迁移
+- model -数据库模型
+- module -业务模块
+  - asynq -异步任务
+  - backend -后台管理
+  - crontab -定时任务
+  - mqtt -mqtt服务
+- service -服务层
+  - alert -报警服务
+  - excel -excel服务
+  - asyncsvc -异步服务
+  - httpclient -http客户端
+  - milk - 奶台服务
+  - mqtt -mqtt服务
+  - redis -redis服务
+  - sso -文件存储服务
+  - wechat -微信小程序服务
+- store -数据存储层
+- temp -临时文件
+- test -测试文件
+- util -工具类
+- .drone.yml 持续集成文件
+- .gitignore 忽略文件
+- docker-compose.yml 容器配置文件
+- Dockerfile 容器配置文件
+- Makefile 编译文件
+- README.md 项目描述文件
+- main.go 项目入口文件

+ 3 - 3
docker-compose.yml

@@ -12,7 +12,7 @@ services:
     environment:
     environment:
       - APP_ENVIRONMENT=production
       - APP_ENVIRONMENT=production
       - PASTURE_WORK_DIR=/app/kpt-pasture
       - PASTURE_WORK_DIR=/app/kpt-pasture
-    command: [ "/app/kpt-pasture/kptPasture","crontab" ]
+    command: [ "/app/kpt-pasture/kptPasture","crontab"]
   kpt-pasture-http:
   kpt-pasture-http:
     privileged: true
     privileged: true
     container_name: xdmy001_kpt_pasture_http
     container_name: xdmy001_kpt_pasture_http
@@ -28,7 +28,7 @@ services:
     environment:
     environment:
       - APP_ENVIRONMENT=production
       - APP_ENVIRONMENT=production
       - PASTURE_WORK_DIR=/app/kpt-pasture
       - PASTURE_WORK_DIR=/app/kpt-pasture
-    command: [ "/app/kpt-pasture/kptPasture","http" ]
+    command: [ "/app/kpt-pasture/kptPasture","http"]
   kpt-pasture-mqtt:
   kpt-pasture-mqtt:
     privileged: true
     privileged: true
     container_name: xdmy001_kpt_pasture_mqtt
     container_name: xdmy001_kpt_pasture_mqtt
@@ -41,4 +41,4 @@ services:
     environment:
     environment:
       - APP_ENVIRONMENT=production
       - APP_ENVIRONMENT=production
       - PASTURE_WORK_DIR=/app/kpt-pasture
       - PASTURE_WORK_DIR=/app/kpt-pasture
-    command: [ "/app/kpt-pasture/kptPasture","mqtt" ]
+    command: [ "/app/kpt-pasture/kptPasture","mqtt"]

+ 1 - 1
go.mod

@@ -3,7 +3,7 @@ module kpt-pasture
 go 1.17
 go 1.17
 
 
 require (
 require (
-	gitee.com/xuyiping_admin/go_proto v0.0.0-20250722095239-a27aeafbe6c7
+	gitee.com/xuyiping_admin/go_proto v0.0.0-20250731013344-bd687f491881
 	gitee.com/xuyiping_admin/pkg v0.0.0-20250613101634-36c36a2d27d0
 	gitee.com/xuyiping_admin/pkg v0.0.0-20250613101634-36c36a2d27d0
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/eclipse/paho.mqtt.golang v1.4.3
 	github.com/eclipse/paho.mqtt.golang v1.4.3

+ 4 - 0
go.sum

@@ -1325,6 +1325,10 @@ gitee.com/xuyiping_admin/go_proto v0.0.0-20250708055755-eca7bde9521e h1:6J5ou2Tg
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250708055755-eca7bde9521e/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250708055755-eca7bde9521e/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250722095239-a27aeafbe6c7 h1:hZaVxxS6ZR1oUDQQc1YQYMDuQKzkIZyRmv7ymfI9tv8=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250722095239-a27aeafbe6c7 h1:hZaVxxS6ZR1oUDQQc1YQYMDuQKzkIZyRmv7ymfI9tv8=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250722095239-a27aeafbe6c7/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/go_proto v0.0.0-20250722095239-a27aeafbe6c7/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250730095437-35f6be63af97 h1:hOXg1Ot2WaqXodqisOZWVmx9jWiDU81tk6HMfF8X62s=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250730095437-35f6be63af97/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250731013344-bd687f491881 h1:JCa0Y3NyPxe339VC3AnGu+eFyr2aXduuIypy8RXgwRw=
+gitee.com/xuyiping_admin/go_proto v0.0.0-20250731013344-bd687f491881/go.mod h1:BKrFW6YLDectlQcQk3FYKBeXvjEiodAKJ5rq7O/QiPE=
 gitee.com/xuyiping_admin/pkg v0.0.0-20250613101634-36c36a2d27d0 h1:ZCOqEAnGm6+DTAhACigzWKbwMKtleb8/7OzP2xfHG7g=
 gitee.com/xuyiping_admin/pkg v0.0.0-20250613101634-36c36a2d27d0 h1:ZCOqEAnGm6+DTAhACigzWKbwMKtleb8/7OzP2xfHG7g=
 gitee.com/xuyiping_admin/pkg v0.0.0-20250613101634-36c36a2d27d0/go.mod h1:8tF25X6pE9WkFCczlNAC0K2mrjwKvhhp02I7o0HtDxY=
 gitee.com/xuyiping_admin/pkg v0.0.0-20250613101634-36c36a2d27d0/go.mod h1:8tF25X6pE9WkFCczlNAC0K2mrjwKvhhp02I7o0HtDxY=
 github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=

+ 38 - 0
model/config_abortion_reasons.go

@@ -0,0 +1,38 @@
+package model
+
+import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+
+type ConfigAbortionReasons struct {
+	Id        int32                          `json:"id"`
+	PastureId int64                          `json:"pastureId"`
+	Kind      pasturePb.AbortionReasons_Kind `json:"kind"`
+	Zh        string                         `json:"zh"`
+	En        string                         `json:"en"`
+	Category  pasturePb.PastureCategory_Kind `json:"category"`
+	Remarks   string                         `json:"remarks"`
+	IsShow    pasturePb.IsShow_Kind          `json:"is_show"`
+	CreatedAt int64                          `json:"created_at"`
+	UpdatedAt int64                          `json:"updated_at"`
+}
+
+func (c *ConfigAbortionReasons) TableName() string {
+	return "config_abortion_reasons"
+}
+
+type ConfigAbortionReasonsSlice []*ConfigAbortionReasons
+
+func (c ConfigAbortionReasonsSlice) ToPB(lang string) []*pasturePb.ConfigOptionsList {
+	res := make([]*pasturePb.ConfigOptionsList, 0)
+	for _, v := range c {
+		label := v.Zh
+		if lang == "en" {
+			label = v.En
+		}
+		res = append(res, &pasturePb.ConfigOptionsList{
+			Value:    int32(v.Kind),
+			Label:    label,
+			Disabled: true,
+		})
+	}
+	return res
+}

+ 4 - 0
model/cow.go

@@ -48,6 +48,7 @@ type Cow struct {
 	BirthAt               int64                          `json:"birthAt"`               // 出生时间
 	BirthAt               int64                          `json:"birthAt"`               // 出生时间
 	AdmissionAt           int64                          `json:"admissionAt"`           // 入场时间
 	AdmissionAt           int64                          `json:"admissionAt"`           // 入场时间
 	DepartureAt           int64                          `json:"departureAt"`           // 离场时间
 	DepartureAt           int64                          `json:"departureAt"`           // 离场时间
+	WeaningWeight         int64                          `json:"weaningWeight"`         // 断奶体重
 	DeparturePrice        float32                        `json:"departurePrice"`        // 离场价格
 	DeparturePrice        float32                        `json:"departurePrice"`        // 离场价格
 	DepartureAvgWeight    int32                          `json:"departureAvgWeight"`    // 离场平均体重
 	DepartureAvgWeight    int32                          `json:"departureAvgWeight"`    // 离场平均体重
 	FirstMatingAt         int64                          `json:"firstMatingAt"`         // 首次配种时间
 	FirstMatingAt         int64                          `json:"firstMatingAt"`         // 首次配种时间
@@ -113,6 +114,7 @@ func (c *Cow) EventWeaningUpdate(weaningAt int64, penId int32, currentWeight int
 	c.WeaningAt = weaningAt
 	c.WeaningAt = weaningAt
 	c.CurrentWeight = currentWeight
 	c.CurrentWeight = currentWeight
 	c.LastWeightAt = weaningAt
 	c.LastWeightAt = weaningAt
+	c.WeaningWeight = currentWeight
 }
 }
 
 
 // EventPregnantCheckUpdate 孕检更新
 // EventPregnantCheckUpdate 孕检更新
@@ -565,6 +567,8 @@ func (c CowSlice) ToPB(
 			PurposeName:                 purposeName,
 			PurposeName:                 purposeName,
 			BatchNumber:                 v.BatchNumber,
 			BatchNumber:                 v.BatchNumber,
 			AdmissionWeight:             float32(v.AdmissionWeight / 1000),
 			AdmissionWeight:             float32(v.AdmissionWeight / 1000),
+			DepartureAvgWeight:          float32(v.DepartureAvgWeight / 1000),
+			WeaningWeight:               float32(v.WeaningWeight / 1000),
 		}
 		}
 	}
 	}
 	return res
 	return res

+ 1 - 0
model/system_user.go

@@ -83,6 +83,7 @@ type UserModel struct {
 	SystemUser      *SystemUser
 	SystemUser      *SystemUser
 	AppPasture      *AppPastureList
 	AppPasture      *AppPastureList
 	LanguageContent *i18n.Localizer
 	LanguageContent *i18n.Localizer
+	Language        string
 }
 }
 
 
 type SystemUserSlice []*SystemUser
 type SystemUserSlice []*SystemUser

+ 4 - 4
module/backend/config_data_base.go

@@ -11,7 +11,7 @@ func (s *StoreEntry) OutReasonEnumList(isAll string) []*pasturePb.ConfigOptionsL
 	if isAll == model.IsAllYes {
 	if isAll == model.IsAllYes {
 		configOptions = append(configOptions,
 		configOptions = append(configOptions,
 			&pasturePb.ConfigOptionsList{
 			&pasturePb.ConfigOptionsList{
-				Value:    int32(0),
+				Value:    int32(pasturePb.OutReasons_Invalid),
 				Label:    "全部",
 				Label:    "全部",
 				Disabled: true,
 				Disabled: true,
 			})
 			})
@@ -121,7 +121,7 @@ func (s *StoreEntry) DeathReasonEnumList(isAll string) []*pasturePb.ConfigOption
 	if isAll == model.IsAllYes {
 	if isAll == model.IsAllYes {
 		configOptions = append(configOptions,
 		configOptions = append(configOptions,
 			&pasturePb.ConfigOptionsList{
 			&pasturePb.ConfigOptionsList{
-				Value:    int32(0),
+				Value:    int32(pasturePb.DeathReason_Invalid),
 				Label:    "全部",
 				Label:    "全部",
 				Disabled: true,
 				Disabled: true,
 			})
 			})
@@ -199,7 +199,7 @@ func (s *StoreEntry) MatingResultEnumList(isAll string) []*pasturePb.ConfigOptio
 	if isAll == model.IsAllYes {
 	if isAll == model.IsAllYes {
 		configOptions = append(configOptions,
 		configOptions = append(configOptions,
 			&pasturePb.ConfigOptionsList{
 			&pasturePb.ConfigOptionsList{
-				Value:    int32(0),
+				Value:    int32(pasturePb.MatingResult_Invalid),
 				Label:    "全部",
 				Label:    "全部",
 				Disabled: true,
 				Disabled: true,
 			})
 			})
@@ -233,7 +233,7 @@ func (s *StoreEntry) EventCategoryEnumList(isAll string) []*pasturePb.ConfigOpti
 	if isAll == model.IsAllYes {
 	if isAll == model.IsAllYes {
 		configOptions = append(configOptions,
 		configOptions = append(configOptions,
 			&pasturePb.ConfigOptionsList{
 			&pasturePb.ConfigOptionsList{
-				Value:    int32(0),
+				Value:    int32(pasturePb.EventCategory_Invalid),
 				Label:    "全部",
 				Label:    "全部",
 				Disabled: true,
 				Disabled: true,
 			})
 			})

+ 18 - 1
module/backend/config_data_breed.go

@@ -328,6 +328,23 @@ func CalendarTypeEnumList(isAll string) []*pasturePb.ConfigOptionsList {
 }
 }
 
 
 func (s *StoreEntry) AbortionReasonsEnumList(isAll string) []*pasturePb.ConfigOptionsList {
 func (s *StoreEntry) AbortionReasonsEnumList(isAll string) []*pasturePb.ConfigOptionsList {
+	/*configAbortionReasonList := make([]*model.ConfigAbortionReasons, 0)
+	pref := s.DB.Model(new(model.ConfigAbortionReasons)).
+		Where("is_show =? ", pasturePb.IsShow_Ok).
+		Where("pasture_id =? ", userModel.AppPasture.Id)
+	if isAll == model.IsAllYes {
+		pref = pref.Where("kind >= ?", pasturePb.AbortionReasons_Invalid)
+	} else {
+		pref = pref.Where("kind > ?", pasturePb.AbortionReasons_Invalid)
+	}
+
+	if err := pref.Order("kind ASC").
+		Find(&configAbortionReasonList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	return model.ConfigAbortionReasonsSlice(configAbortionReasonList).ToPB(userModel.Language)*/
+
 	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
 	configOptions := make([]*pasturePb.ConfigOptionsList, 0)
 	if isAll == model.IsAllYes {
 	if isAll == model.IsAllYes {
 		configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
 		configOptions = append(configOptions, &pasturePb.ConfigOptionsList{
@@ -342,7 +359,7 @@ func (s *StoreEntry) AbortionReasonsEnumList(isAll string) []*pasturePb.ConfigOp
 		Disabled: true,
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
 	}, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.AbortionReasons_Malnutrition_Abortion),
 		Value:    int32(pasturePb.AbortionReasons_Malnutrition_Abortion),
-		Label:    "营养不良流产",
+		Label:    "营养不良流产",
 		Disabled: true,
 		Disabled: true,
 	}, &pasturePb.ConfigOptionsList{
 	}, &pasturePb.ConfigOptionsList{
 		Value:    int32(pasturePb.AbortionReasons_Mycotoxin_Abortion),
 		Value:    int32(pasturePb.AbortionReasons_Mycotoxin_Abortion),

+ 3 - 3
module/backend/cow.go

@@ -39,11 +39,11 @@ func (s *StoreEntry) Detail(ctx context.Context, req *pasturePb.SearchEventReque
 		Where("pasture_id = ?", userModel.AppPasture.Id)
 		Where("pasture_id = ?", userModel.AppPasture.Id)
 
 
 	if req.EarNumber != "" {
 	if req.EarNumber != "" {
-		pref.Where("ear_number = ?", req.EarNumber)
+		pref.Where("ear_number = ?", strings.TrimSpace(req.EarNumber))
 	}
 	}
 
 
 	if req.NeckRingNumber != "" {
 	if req.NeckRingNumber != "" {
-		pref.Where("neck_ring_number = ?", req.NeckRingNumber)
+		pref.Where("neck_ring_number = ?", strings.TrimSpace(req.NeckRingNumber))
 	}
 	}
 
 
 	if err = pref.First(cowInfo).Error; err != nil {
 	if err = pref.First(cowInfo).Error; err != nil {
@@ -325,7 +325,7 @@ func (s *StoreEntry) BehaviorCurve(ctx context.Context, req *pasturePb.CowBehavi
 	// 发情数据
 	// 发情数据
 	estrusList := make([]*model.NeckRingEstrus, 0)
 	estrusList := make([]*model.NeckRingEstrus, 0)
 	if err = s.DB.Model(new(model.NeckRingEstrus)).
 	if err = s.DB.Model(new(model.NeckRingEstrus)).
-		Select("id,active_level,active_time,is_peak").
+		Select("id,active_level,MAX(active_time) AS active_time,is_peak").
 		Where("cow_id = ?", cowInfo.Id).
 		Where("cow_id = ?", cowInfo.Id).
 		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("active_time BETWEEN ? AND ?", fmt.Sprintf("%s 00:00:00", startDataTime), fmt.Sprintf("%s 23:59:59", endDataTime)).
 		Where("active_time BETWEEN ? AND ?", fmt.Sprintf("%s 00:00:00", startDataTime), fmt.Sprintf("%s 23:59:59", endDataTime)).

+ 5 - 3
module/backend/event_breed_more.go

@@ -545,15 +545,17 @@ func (s *StoreEntry) WeaningBatch(ctx context.Context, req *pasturePb.EventWeani
 				item.Remarks, item.PenId, operation, userModel.SystemUser,
 				item.Remarks, item.PenId, operation, userModel.SystemUser,
 			)
 			)
 			if err = tx.Model(new(model.EventWeaning)).
 			if err = tx.Model(new(model.EventWeaning)).
-				Select("status", "reality_day", "operation_id", "operation_name", "message_id", "message_name", "remarks", "after_pen_id", "birth_weight", "birth_at").
-				Where("id = ?", eventWeaning.Id).
+				Select(
+					"status", "reality_day", "operation_id", "operation_name",
+					"message_id", "message_name", "remarks", "after_pen_id", "birth_weight", "birth_at",
+				).Where("id = ?", eventWeaning.Id).
 				Updates(eventWeaning).Error; err != nil {
 				Updates(eventWeaning).Error; err != nil {
 				return xerr.WithStack(err)
 				return xerr.WithStack(err)
 			}
 			}
 
 
 			cowInfo.EventWeaningUpdate(int64(item.WeaningAt), item.PenId, int64(item.Weight*1000))
 			cowInfo.EventWeaningUpdate(int64(item.WeaningAt), item.PenId, int64(item.Weight*1000))
 			if err = tx.Model(new(model.Cow)).
 			if err = tx.Model(new(model.Cow)).
-				Select("pen_id", "current_weight", "weaning_at", "last_weight_at").
+				Select("pen_id", "current_weight", "weaning_at", "last_weight_at", "weaning_weight").
 				Where("id = ?", cowInfo.Id).
 				Where("id = ?", cowInfo.Id).
 				Updates(cowInfo).Error; err != nil {
 				Updates(cowInfo).Error; err != nil {
 				return xerr.WithStack(err)
 				return xerr.WithStack(err)

+ 17 - 8
module/backend/sql.go

@@ -27,7 +27,7 @@ func (s *StoreEntry) GetUserModel(ctx context.Context) (*model.UserModel, error)
 		return nil, xerr.WithStack(err)
 		return nil, xerr.WithStack(err)
 	}
 	}
 
 
-	i18nTemplate, err := s.GetCurrentUserLanguage(ctx)
+	i18nTemplate, err := s.GetI18nTemplate(ctx)
 	if err != nil {
 	if err != nil {
 		return nil, xerr.WithStack(err)
 		return nil, xerr.WithStack(err)
 	}
 	}
@@ -67,7 +67,7 @@ func (s *StoreEntry) GetCurrentSystemUser(ctx context.Context) (*model.SystemUse
 	if err != nil {
 	if err != nil {
 		return nil, xerr.WithStack(err)
 		return nil, xerr.WithStack(err)
 	}
 	}
-	userLanguage, err := s.GetCurrentUserLanguage(ctx)
+	i18nTemplate, err := s.GetI18nTemplate(ctx)
 	if err != nil {
 	if err != nil {
 		return nil, xerr.WithStack(err)
 		return nil, xerr.WithStack(err)
 	}
 	}
@@ -79,25 +79,25 @@ func (s *StoreEntry) GetCurrentSystemUser(ctx context.Context) (*model.SystemUse
 		zaplog.Error("GetCurrentSystemUser", zap.Any("err", err), zap.Any("userName", userName))
 		zaplog.Error("GetCurrentSystemUser", zap.Any("err", err), zap.Any("userName", userName))
 
 
 		if errors.Is(err, gorm.ErrRecordNotFound) {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			messageId, _ := userLanguage.Localize(&i18n.LocalizeConfig{
+			messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 				MessageID: "auth.noUser",
 				MessageID: "auth.noUser",
 			})
 			})
 			return nil, xerr.Custom(messageId)
 			return nil, xerr.Custom(messageId)
 		} else {
 		} else {
-			messageId, _ := userLanguage.Localize(&i18n.LocalizeConfig{
+			messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 				MessageID: "auth.reLogin",
 				MessageID: "auth.reLogin",
 			})
 			})
 			return nil, xerr.Custom(messageId)
 			return nil, xerr.Custom(messageId)
 		}
 		}
 	}
 	}
 	if systemUser.IsDelete != pasturePb.IsShow_Ok {
 	if systemUser.IsDelete != pasturePb.IsShow_Ok {
-		messageId, _ := userLanguage.Localize(&i18n.LocalizeConfig{
+		messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 			MessageID: "auth.userDelete",
 			MessageID: "auth.userDelete",
 		})
 		})
 		return nil, xerr.Custom(messageId)
 		return nil, xerr.Custom(messageId)
 	}
 	}
 	if systemUser.IsShow != pasturePb.IsShow_Ok {
 	if systemUser.IsShow != pasturePb.IsShow_Ok {
-		messageId, _ := userLanguage.Localize(&i18n.LocalizeConfig{
+		messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 			MessageID: "auth.userDisable",
 			MessageID: "auth.userDisable",
 		})
 		})
 		return nil, xerr.Custom(messageId)
 		return nil, xerr.Custom(messageId)
@@ -149,8 +149,8 @@ func (s *StoreEntry) GetCurrentUserName(ctx context.Context) (string, error) {
 	}
 	}
 }
 }
 
 
-// GetCurrentUserLanguage 获取用户系统语言
-func (s *StoreEntry) GetCurrentUserLanguage(ctx context.Context) (*i18n.Localizer, error) {
+// GetI18nTemplate 获取用户多语言对应文件
+func (s *StoreEntry) GetI18nTemplate(ctx context.Context) (*i18n.Localizer, error) {
 	lg := ctx.Value(LanguageContent)
 	lg := ctx.Value(LanguageContent)
 	if lg == nil {
 	if lg == nil {
 		return nil, xerr.Customf("language error")
 		return nil, xerr.Customf("language error")
@@ -162,6 +162,15 @@ func (s *StoreEntry) GetCurrentUserLanguage(ctx context.Context) (*i18n.Localize
 	return lag, nil
 	return lag, nil
 }
 }
 
 
+// GetCurrentUserLanguage 获取用户语言标志
+func (s *StoreEntry) GetCurrentUserLanguage(ctx context.Context) string {
+	lg := ctx.Value(Language)
+	if lg != nil {
+		return lg.(string)
+	}
+	return "zh"
+}
+
 // GetFarmId 获取当前牧场Id
 // GetFarmId 获取当前牧场Id
 func (s *StoreEntry) GetFarmId(ctx context.Context) string {
 func (s *StoreEntry) GetFarmId(ctx context.Context) string {
 	farmId := ctx.Value(CurrentFarmId)
 	farmId := ctx.Value(CurrentFarmId)

+ 14 - 13
module/backend/system_service.go

@@ -26,11 +26,12 @@ const (
 	CurrentUserName = "userName"
 	CurrentUserName = "userName"
 	CurrentFarmId   = "FarmId"
 	CurrentFarmId   = "FarmId"
 	LanguageContent = "languageContent"
 	LanguageContent = "languageContent"
+	Language        = "language"
 )
 )
 
 
 // Login 用户登录
 // Login 用户登录
 func (s *StoreEntry) Login(ctx context.Context, req *pasturePb.SearchUserRequest) (*pasturePb.SystemUserResponse, error) {
 func (s *StoreEntry) Login(ctx context.Context, req *pasturePb.SearchUserRequest) (*pasturePb.SystemUserResponse, error) {
-	language, err := s.GetCurrentUserLanguage(ctx)
+	i18nTemplate, err := s.GetI18nTemplate(ctx)
 	if err != nil {
 	if err != nil {
 		return nil, xerr.WithStack(err)
 		return nil, xerr.WithStack(err)
 	}
 	}
@@ -39,7 +40,7 @@ func (s *StoreEntry) Login(ctx context.Context, req *pasturePb.SearchUserRequest
 		Where("name = ?", req.Name).
 		Where("name = ?", req.Name).
 		First(systemUser).Error; err != nil {
 		First(systemUser).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			messageId, _ := language.Localize(&i18n.LocalizeConfig{
+			messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 				MessageID: "auth.noUser",
 				MessageID: "auth.noUser",
 			})
 			})
 			return nil, xerr.Customf(messageId)
 			return nil, xerr.Customf(messageId)
@@ -49,28 +50,28 @@ func (s *StoreEntry) Login(ctx context.Context, req *pasturePb.SearchUserRequest
 	}
 	}
 
 
 	if systemUser.Password != req.Password {
 	if systemUser.Password != req.Password {
-		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+		messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 			MessageID: "auth.wrongPassword",
 			MessageID: "auth.wrongPassword",
 		})
 		})
 		return nil, xerr.Customf(messageId)
 		return nil, xerr.Customf(messageId)
 	}
 	}
 
 
 	if systemUser.IsShow == pasturePb.IsShow_No {
 	if systemUser.IsShow == pasturePb.IsShow_No {
-		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+		messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 			MessageID: "auth.userDisable",
 			MessageID: "auth.userDisable",
 		})
 		})
 		return nil, xerr.Customf(messageId)
 		return nil, xerr.Customf(messageId)
 	}
 	}
 
 
 	if systemUser.IsDelete == pasturePb.IsShow_No {
 	if systemUser.IsDelete == pasturePb.IsShow_No {
-		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+		messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 			MessageID: "auth.userDelete",
 			MessageID: "auth.userDelete",
 		})
 		})
 		return nil, xerr.Customf(messageId)
 		return nil, xerr.Customf(messageId)
 	}
 	}
 
 
 	if len(systemUser.PastureIds) <= 0 {
 	if len(systemUser.PastureIds) <= 0 {
-		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+		messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 			MessageID: "auth.unPasture",
 			MessageID: "auth.unPasture",
 		})
 		})
 		return nil, xerr.Custom(messageId)
 		return nil, xerr.Custom(messageId)
@@ -82,7 +83,7 @@ func (s *StoreEntry) Login(ctx context.Context, req *pasturePb.SearchUserRequest
 		return nil, xerr.WithStack(err)
 		return nil, xerr.WithStack(err)
 	}
 	}
 	if token == "" {
 	if token == "" {
-		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+		messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 			MessageID: "auth.errorToken",
 			MessageID: "auth.errorToken",
 		})
 		})
 		return nil, xerr.Custom(messageId)
 		return nil, xerr.Custom(messageId)
@@ -91,7 +92,7 @@ func (s *StoreEntry) Login(ctx context.Context, req *pasturePb.SearchUserRequest
 	expires := time.Now().Local().Add(time.Duration(s.Cfg.JwtExpireTime) * time.Second).Format(util.LayoutTime)
 	expires := time.Now().Local().Add(time.Duration(s.Cfg.JwtExpireTime) * time.Second).Format(util.LayoutTime)
 	farmList, err := s.FindPastureListByIds(ctx, systemUser.GetPastureIds())
 	farmList, err := s.FindPastureListByIds(ctx, systemUser.GetPastureIds())
 	if err != nil || len(farmList) == 0 {
 	if err != nil || len(farmList) == 0 {
-		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+		messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 			MessageID: "auth.errorPasture",
 			MessageID: "auth.errorPasture",
 		})
 		})
 		return nil, xerr.Custom(messageId)
 		return nil, xerr.Custom(messageId)
@@ -449,7 +450,7 @@ func (s *StoreEntry) GetSystemUserMenu(ctx context.Context) (*pasturePb.SystemUs
 
 
 // ResetPasswordSystemUser 重置系统用户密码
 // ResetPasswordSystemUser 重置系统用户密码
 func (s *StoreEntry) ResetPasswordSystemUser(ctx context.Context, req *pasturePb.ResetUserPasswordRequest) error {
 func (s *StoreEntry) ResetPasswordSystemUser(ctx context.Context, req *pasturePb.ResetUserPasswordRequest) error {
-	language, err := s.GetCurrentUserLanguage(ctx)
+	i18nTemplate, err := s.GetI18nTemplate(ctx)
 	if err != nil {
 	if err != nil {
 		return xerr.WithStack(err)
 		return xerr.WithStack(err)
 	}
 	}
@@ -458,7 +459,7 @@ func (s *StoreEntry) ResetPasswordSystemUser(ctx context.Context, req *pasturePb
 		Where("id = ?", req.Id).
 		Where("id = ?", req.Id).
 		First(systemUser).Error; err != nil {
 		First(systemUser).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			messageId, _ := language.Localize(&i18n.LocalizeConfig{
+			messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 				MessageID: "auth.noUser",
 				MessageID: "auth.noUser",
 			})
 			})
 			return xerr.Custom(messageId)
 			return xerr.Custom(messageId)
@@ -466,7 +467,7 @@ func (s *StoreEntry) ResetPasswordSystemUser(ctx context.Context, req *pasturePb
 		return xerr.WithStack(err)
 		return xerr.WithStack(err)
 	}
 	}
 
 
-	if err := s.DB.Model(systemUser).
+	if err = s.DB.Model(systemUser).
 		Update("password", req.Password).Error; err != nil {
 		Update("password", req.Password).Error; err != nil {
 		return xerr.WithStack(err)
 		return xerr.WithStack(err)
 	}
 	}
@@ -614,11 +615,11 @@ func (s *StoreEntry) SystemUserRoleSave(ctx context.Context, req *pasturePb.Syst
 
 
 func (s *StoreEntry) GetMenusWithParents(ctx context.Context, pastureId int64, menuIds []int64) ([]*model.SystemMenu, error) {
 func (s *StoreEntry) GetMenusWithParents(ctx context.Context, pastureId int64, menuIds []int64) ([]*model.SystemMenu, error) {
 	if len(menuIds) <= 0 {
 	if len(menuIds) <= 0 {
-		language, err := s.GetCurrentUserLanguage(ctx)
+		i18nTemplate, err := s.GetI18nTemplate(ctx)
 		if err != nil {
 		if err != nil {
 			return nil, xerr.Customf("菜单id不能为空")
 			return nil, xerr.Customf("菜单id不能为空")
 		}
 		}
-		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+		messageId, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
 			MessageID: "auth.menuIdNotEmpty",
 			MessageID: "auth.menuIdNotEmpty",
 		})
 		})
 		return nil, xerr.Customf(messageId)
 		return nil, xerr.Customf(messageId)