Kaynağa Gözat

i18n: update

Yi 5 gün önce
ebeveyn
işleme
9d8510318c

+ 2 - 1
Dockerfile

@@ -25,9 +25,10 @@ RUN rm -f /etc/localtime \
 && echo "Asia/Shanghai" > /etc/timezone
 
 COPY --from=0 /app/kpt-pasture/config/ /app/kpt-pasture/config/
+COPY --from=0 /app/kpt-pasture/locales/ /app/kpt-pasture/locales/
 COPY --from=0  /app/kpt-pasture/kptPasture /app/kpt-pasture/kptPasture
 
 EXPOSE 8090
-VOLUME ["/app/kpt-pasture/logger","/app/kpt-pasture/config","/app/kpt-pasture/files"]
+VOLUME ["/app/kpt-pasture/logger","/app/kpt-pasture/config","/app/kpt-pasture/files","/app/kpt-pasture/locales"]
 
 CMD ["/app/kpt-pasture/kptPasture","http"]

+ 6 - 6
http/middleware/i18n.go

@@ -101,16 +101,16 @@ func loadTranslations() error {
 
 // detectLanguage 检测客户端语言偏好
 func detectLanguage(r *http.Request) string {
-	/*// 1. 检查查询参数
-	if lang := r.URL.Query().Get("lang"); lang != "" {
+	// 1. 检查查询参数
+	if lang := r.URL.Query().Get("language"); lang != "" {
 		return normalizeLanguage(lang)
 	}
 
 	// 2. 检查 Cookie
-	if langCookie, err := r.Cookie("lang"); err == nil && langCookie.Value != "" {
+	if langCookie, err := r.Cookie("language"); err == nil && langCookie.Value != "" {
 		return normalizeLanguage(langCookie.Value)
 	}
-	*/
+
 	// 3. 检查 Accept-Language 头
 	if acceptLang := r.Header.Get("Accept-Language"); acceptLang != "" {
 		if langs := strings.Split(acceptLang, ","); len(langs) > 0 {
@@ -118,7 +118,7 @@ func detectLanguage(r *http.Request) string {
 		}
 	}
 	// 默认返回中文
-	return "zh"
+	return defaultLanguage.String()
 }
 
 // normalizeLanguage 规范化语言代码
@@ -134,5 +134,5 @@ func normalizeLanguage(lang string) string {
 	if supported[lang] {
 		return lang
 	}
-	return "zh" // 默认中文
+	return defaultLanguage.String()
 }

+ 1 - 1
http/route/system_api.go

@@ -17,7 +17,7 @@ func SystemAPI(opts ...func(engine *gin.Engine)) func(s *gin.Engine) {
 		s.NoRoute(handler.Handle404)
 		// Health Check
 		s.GET("/check", handler.Health)
-		s.POST("/api/v1/login", system.Login)
+		s.POST("/api/v1/login", middleware.I18N(), system.Login)
 		s.Static("/api/v1/files", "./files")
 
 		// system API 组  系统用户

+ 98 - 4
locales/en.json

@@ -1,6 +1,100 @@
 {
-  "auth": {
-    "unPasture": "The user has not configured relevant farm data. Please contact the administrator!",
-    "unLogin": "Please login first!"
-  }
+  "auth.unPasture": "The current user is not configured with relevant pasture data. Please contact the administrator!",
+  "auth.unLogin": "Please log in first!",
+  "auth.noUser": "User does not exist!",
+  "auth.reLogin": "Incorrect user login information. Please log out and log in again!",
+  "auth.userDelete": "The current user data has been deleted!",
+  "auth.userDisable": "The current user is disabled. Please contact the administrator!",
+  "auth.pregnancyDays": "Please configure the gestation days in the system settings basic parameters!",
+  "auth.noCow": "This cattle does not exist!",
+  "auth.errorCow": "Incorrect cattle information: {{.earNumber}}",
+  "auth.errorDateRange": "Incorrect date range",
+  "auth.wrongPassword": "Wrong password!",
+  "auth.noPermission": "No access permission!",
+  "auth.errorToken": "Invalid Token",
+  "auth.errorPasture": "Pasture information error!",
+  "auth.userNameExist": "User already exists!",
+  "auth.userRoleNotExist": "User role does not exist!",
+  "auth.noMenuPermission": "The user role has no menu permissions!",
+  "auth.menuIdNotEmpty": "Menu ID cannot be empty!",
+  "auth.checkOperation": "Please check the operator information!",
+  "auth.getOperationError": "Failed to get operator information!",
+  "dataWarning.notSupported": "This warning data is not currently supported!",
+  "dataWarning.selectData": "Please select warning data!",
+  "dataWarning.defaultDataNotExist": "Default warning data does not exist. Please contact the engineer!",
+  "dataWarning.defaultDataError": "Default warning data error. Please contact the engineer!",
+  "dataWarning.dataNotExist": "Warning data does not exist. Please contact the engineer!",
+  "dataWarning.dataError": "Warning data is incorrect. Please contact the engineer!",
+  "dataWarning.conditionGroupNotEmpty": "Condition group cannot be empty!",
+  "validate.startEndDateTime": "Start time cannot be later than end time!",
+  "validate.wrongCowSaleTime": "Cattle ID: {{.earNumber}}, sale time cannot be earlier than the cattle's birth time!",
+  "validate.dataError": "Data exception!",
+  "validate.immuneTime": "Cattle ID: {{.earNumber}}, immunization time cannot be earlier than the cattle's birth time!",
+  "validate.birthTime": "Cattle ID: {{.earNumber}}, calving time cannot be earlier than the cattle's birth time!",
+  "validate.lactationCount": "Calf information does not match the number of births",
+  "validate.noPregnancy": "This cow has not been bred!",
+  "validate.noMotherCow": "This cow information does not exist!",
+  "validate.noSameTimePlan": "Cattle ID: {{.earNumber}}, no synchronization plan today!",
+  "validate.matingTimeBirthTime": "Cattle ID: {{.earNumber}}, The breeding time cannot be earlier than the birth time of the cattle!",
+  "validate.matingTimeLastCalvingTime": "Cattle ID: {{.earNumber}}, The mating time cannot be earlier than the latest calving time of the cow!",
+  "validate.pregnantCheckMatingTime": "Cattle ID: {{.earNumber}}, The pregnancy test date must be later than the last mating date!",
+  "validate.dataLimit": "A maximum of 50 pieces of data can be submitted at once",
+  "validate.cowSex": "Cattle ID: {{.earNumber}},Not a cow!",
+  "validate.birthTimeEnterTime": "The birth time of cattle cannot exceed the entry time!",
+  "validate.matingTimeLastMatingTime": "Cattle ID: {{.earNumber}},mating date: {{.matingDate}},cannot be earlier than the last mating date: {{.lastMatingDate}}",
+  "validate.matingTimeLastAbortionTime": "Cattle ID: {{.earNumber}},mating date: {{.matingDate}},cannot be earlier than the last abortion date: {{.lastAbortionDate}}!",
+  "validate.matingDataError": "Cattle ID: {{.earNumber}},the latest mating data is abnormal!",
+  "validate.breedStatusError": "Cattle ID: {{.earNumber}},the current status is:{{.breedStatus}},cannot conduct breeding!",
+  "validate.cannotPregnantCheck": "Cattle ID: {{.earNumber}} Not participating in mating, unable to undergo pregnancy testing!",
+  "validate.notFoundPregnantCheckData": "No pregnancy test data was found for the {{.earNumber}} cow!",
+  "validate.notFoundMatingData": "No breeding data was found for the {{.earNumber}} cow!",
+  "validate.deathTime": "The death time of Cow {{.earNumber}} cannot be earlier than the birth time!",
+  "validate.deathTimeLastEvent": "Cattle: {{.earNumber}}, death time cannot be earlier than the last event time!",
+  "validate.unMatingDate": "Cattle: {{.earNumber}}, breeding time cannot be earlier than birth time!",
+  "validate.estrusDateBirthDate": "Cattle: {{.earNumber}}, estrus time cannot be less than birth time!",
+  "validate.estrusDateLastCalvingDate": "Cattle: {{.earNumber}}, estrus time cannot be less than the last calving time!",
+  "validate.estrusDataAlready": "The cow: {{.earNumber}}, has already submitted estrus data today!",
+  "validate.matingDataItemAlready": "The breeding list already has the data for this cow: {{.earNumber}}, and the breeding data has been submitted today!",
+  "validate.CowNotPregnant": "Cow: {{.earNumber}}, not pregnant!",
+  "validate.AbortionDateBirthDate": "Cattle: {{.earNumber}}, abortion time cannot be earlier than the cow's birth time!",
+  "analysis.wrongMethod": "Incorrect statistical method!",
+  "analysis.wrongLact": "Incorrect lactation interval symbol!",
+  "analysis.wrongDateRange": "Start time cannot be later than end time!",
+  "analysis.xAndY": "X-axis and Y-axis cannot be the same!",
+  "analysis.wrongXY": "Incorrect XY-axis data!",
+  "cow.earNumber": "Please select ear tag number!",
+  "cow.dataError": "Data error: {{.earNumber}}!",
+  "cow.inputCow": "Please enter cattle ID or collar number!",
+  "cow.noCow": "This cattle does not exist!",
+  "cow.errorCow": "Cattle information error: {{.earNumber}}!",
+  "cow.wrongCow": "Cattle ID: {{.earNumber}}, onset time cannot be earlier than the cattle's birth time!",
+  "cow.errorCowById": "Incorrect cattle information: {{.cowId}}!",
+  "cow.errorCowData": "Abnormal cattle data!",
+  "cow.cowNotExist": "This cattle: {{.earNumber}} does not exist!",
+  "cow.neckRingNumberBind": "This cattle: {{.earNumber}} has already been bound to collar: {{.neckRingNumber}}!",
+  "cow.selectCow": "Please select relevant cattle!",
+  "cow.errorData": "Abnormal cattle data!",
+  "cow.Exists": "The cow already exists!",
+  "health.cowExist": "This cattle already has this disease!",
+  "health.createPrescriptionFail": "Failed to create prescription!",
+  "health.treatmentTimeError": "Treatment time cannot be later than diagnosis time!",
+  "health.errorCowData": "Abnormal cattle data!",
+  "goods.selectNeckRing": "Please select collar data!",
+  "goods.neckRingAlreadyBind": "This collar: {{.neckRingNumber}} has already been bound to cattle: {{.earNumber}}",
+  "goods.neckRingNotBind": "This collar: {{.neckRingNumber}} is not bound to any cattle!",
+  "goods.selectOutGoods": "Please select goods for outbound!",
+  "goods.outGoodsNotExist": "This outbound order does not exist!",
+  "goods.outGoodsNotAllowEdit": "Not the applicant, no permission to modify this outbound order!",
+  "goods.outGoodsNotAllowDelete": "Not the applicant, no permission to delete this outbound order!",
+  "goods.outGoodsNotEdit": "This outbound order cannot be modified!",
+  "goods.goodsCount": "Please fill in the quantity of goods!",
+  "goods.unknownOutGoodsType": "Unknown outbound type!",
+  "goods.outGoodsAuditStatusError": "Outbound order audit status exception!",
+  "goods.outGoodsError": "Abnormal outbound order",
+  "goods.outGoodsNotDelete": "This outbound order cannot be deleted!",
+  "goods.dataNotExist": "This data: {{.id}} does not exist!",
+  "goods.frozenSemenNotExist": "The frozen semen information does not exist!",
+  "goods.frozenSemenNotEnough": "Insufficient quantity of frozen semen!",
+  "pasture.dealerNotExist": "This dealer information was not found!",
+  "pasture.dealerError": "Dealer data exception!"
 }

+ 99 - 5
locales/zh.json

@@ -1,6 +1,100 @@
 {
-  "auth": {
-    "unPasture": "当前用户未配置相关牧场数据,请联系管理员!",
-    "unLogin": "请先登录!"
-  }
-}
+  "auth.unPasture": "当前用户未配置相关牧场数据,请联系管理员!",
+  "auth.unLogin": "请先登录!",
+  "auth.noUser": "用户不存在!",
+  "auth.reLogin": "用户登录信息有误,请退出重新登录!",
+  "auth.userDelete": "当前用户数据已经删除!",
+  "auth.userDisable": "当前用户已禁用,请联系管理员!",
+  "auth.pregnancyDays": "请在系统设置基础参数配置妊娠天数!",
+  "auth.noCow": "该牛只不存在!",
+  "auth.errorCow": "错误的牛只信息: {{.earNumber}}",
+  "auth.errorDateRange":"错误的日期范围",
+  "auth.wrongPassword": "密码错误!",
+  "auth.noPermission": "无权限访问!",
+  "auth.errorToken": "无效的Token",
+  "auth.errorPasture": "牧场信息错误!",
+  "auth.userNameExist": "用户已存在!",
+  "auth.userRoleNotExist": "用户角色不存在!",
+  "auth.noMenuPermission": "用户角色没有菜单权限!",
+  "auth.menuIdNotEmpty": "菜单ID不能为空!",
+  "auth.checkOperation": "请检查操作人信息!",
+  "auth.getOperationError": "获取操作人员信息失败!",
+  "dataWarning.notSupported": "暂不支持该预警数据!",
+  "dataWarning.selectData": "请选择预警数据!",
+  "dataWarning.defaultDataNotExist": "默认预警数据不存在,请联系工程师!",
+  "dataWarning.defaultDataError": "默认预警数据错误,请联系工程师!",
+  "dataWarning.dataNotExist": "预警数据不存在,请联系工程师!",
+  "dataWarning.dataError": "预警数据有误,请联系工程师!",
+  "dataWarning.conditionGroupNotEmpty": "条件组不能为空!",
+  "validate.startEndDateTime": "开始时间不能大于结束时间!",
+  "validate.wrongCowSaleTime": "牛号: {{.earNumber}},销售时间不能早于牛只出生时间!",
+  "validate.dataError": "数据异常!",
+  "validate.immuneTime": "牛号: {{.earNumber}},免疫时间不能早于牛只出生时间!",
+  "validate.birthTime": "牛号: {{.earNumber}}, 产犊时间不能早于牛只出生时间!",
+  "validate.lactationCount": "犊牛信息与产子数不相符",
+  "validate.noPregnancy": "该母牛未配种!",
+  "validate.noMotherCow": "该母牛信息不存在!",
+  "validate.noSameTimePlan": "该牛号: {{.earNumber}}, 今日没有同期计划!",
+  "validate.matingTimeBirthTime": "牛号: {{.earNumber}}, 配种时间不能早于牛只出生时间!",
+  "validate.matingTimeLastCalvingTime": "牛号: {{.earNumber}}, 配种时间不能早于牛只最近产犊时间!",
+  "validate.pregnantCheckMatingTime": "牛号: {{.earNumber}}, 孕检日期必须大于最后一次配种日期!",
+  "validate.dataLimit": "一次性最多限制提交50条数据!",
+  "validate.cowSex": "牛只: {{.earNumber}},不是母牛!",
+  "validate.birthTimeEnterTime": "牛只出生时间不能大于入场时间!",
+  "validate.matingTimeLastMatingTime": "牛只: {{.earNumber}},配种时间: {{.matingDate}},不能小于上次配种时间: {{.lastMatingDate}}!",
+  "validate.matingTimeLastAbortionTime": "牛只: {{.earNumber}},配种时间: {{.matingDate}},不能小于上次流产时间: {{.lastAbortionDate}}!",
+  "validate.matingDataError": "牛只: {{.earNumber}},最近一次配种数据异常!",
+  "validate.breedStatusError": "牛只: {{.earNumber}},当前状态为:{{.breedStatus}},不能进行配种!",
+  "validate.cannotPregnantCheck": "牛只: {{.earNumber}} 未参加配种,不能进行孕检!",
+  "validate.notFoundPregnantCheckData": "未发现该牛只: %s 孕检数据!",
+  "validate.notFoundMatingData": "未发现该牛只: %s 配种数据!",
+  "validate.deathTime": "牛只: {{.earNumber}},死亡时间不能早于出生时间!",
+  "validate.deathTimeLastEvent": "牛只: {{.earNumber}},死亡时间不能早于上一次事件时间!",
+  "validate.unMatingDate": "牛只: {{.earNumber}},禁止配种时间不能小于出生时间!",
+  "validate.estrusDateBirthDate": "牛只: {{.earNumber}},发情时间不能小于出生时间!",
+  "validate.estrusDateLastCalvingDate": "牛只: {{.earNumber}},发情时间不能小于上次产犊时间!",
+  "validate.estrusDataAlready": "该牛只: {{.earNumber}},今天已经提交过发情数据!",
+  "validate.matingDataItemAlready": "配种清单已经有该牛只数据: {{.earNumber}},今天已经提交过配种数据!",
+  "validate.CowNotPregnant": "牛只: {{.earNumber}},不是怀孕状态!",
+  "validate.AbortionDateBirthDate": "牛只: {{.earNumber}},流产时间不能早于牛只出生时间!",
+  "analysis.wrongMethod": "错误的统计方式!",
+  "analysis.wrongLact": "错误的胎次区间符号!",
+  "analysis.wrongDateRange": "开始时间不能大于结束时间!",
+  "analysis.xAndY": "X轴和Y轴不能相同!",
+  "analysis.wrongXY": "错误的XY轴数据!",
+  "cow.earNumber": "请选择耳号!",
+  "cow.dataError": "数据错误: {{.earNumber}}!",
+  "cow.inputCow": "请输入牛号或项圈号!",
+  "cow.noCow": "该牛不存在!",
+  "cow.errorCow": "牛只信息错误: {{.earNumber}}!",
+  "cow.wrongCow": "牛号: {{.earNumber}},发病时间不能早于牛只出生时间!",
+  "cow.errorCowById": "错误的牛只信息: {{.cowId}}!",
+  "cow.errorCowData":"异常牛只数据!",
+  "cow.cowNotExist": "该牛只: {{.earNumber}} 不存在!",
+  "cow.neckRingNumberBind": "该牛只: {{.earNumber}},已经绑定脖环: {{.neckRingNumber}}!",
+  "cow.selectCow": "请选择相关牛只!",
+  "cow.errorData": "异常牛只数据!",
+  "cow.Exists": "该牛只已存在!",
+  "health.cowExist": "该牛已存在该疾病!",
+  "health.createPrescriptionFail": "创建处方失败!",
+  "health.treatmentTimeError": "治疗时间不能大于确诊时间!",
+  "health.errorCowData": "异常牛只数据!",
+  "goods.selectNeckRing": "请选择要脖环数据!",
+  "goods.neckRingAlreadyBind": "该脖环: {{.neckRingNumber}}已经绑定牛只: {{.earNumber}}",
+  "goods.neckRingNotBind": "该脖环: {{.neckRingNumber}},未绑定牛只!",
+  "goods.selectOutGoods": "请选择要出库商品!",
+  "goods.outGoodsNotExist": "该出库单不存在!",
+  "goods.outGoodsNotAllowEdit": "非申请人,无权修改该出库单!",
+  "goods.outGoodsNotAllowDelete": "非申请人,无权删除该出库单!",
+  "goods.outGoodsNotEdit": "该出库单不能修改!",
+  "goods.goodsCount": "请填写商品数量!",
+  "goods.unknownOutGoodsType": "未知的出库类型!",
+  "goods.outGoodsAuditStatusError": "出库单审核状态异常!",
+  "goods.outGoodsError": "异常出库单",
+  "goods.outGoodsNotDelete": "该出库单无法删除!",
+  "goods.dataNotExist": "该数据: {{.id}}不存在!",
+  "goods.frozenSemenNotExist": "该冻精信息不存在!",
+  "goods.frozenSemenNotEnough": "冻精数量不足!",
+  "pasture.dealerNotExist": "未找到该经销商信息!",
+  "pasture.dealerError": "经销商数据异常!"
+}

+ 7 - 2
model/data_waring.go

@@ -3,6 +3,8 @@ package model
 import (
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	"gitee.com/xuyiping_admin/pkg/xerr"
 
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
@@ -47,7 +49,7 @@ func DataWarningInitData(pastureId int64, dataWarningList []*pasturePb.ConfigOpt
 	return res
 }
 
-func (d *DataWarning) GetWarningColumn() (headers map[string]string, headerSort []string, err error) {
+func (d *DataWarning) GetWarningColumn(i18nTemplate *i18n.Localizer) (headers map[string]string, headerSort []string, err error) {
 	switch d.Kind {
 	case pasturePb.DataWarningType_Sale_Standard:
 		headers = map[string]string{
@@ -179,7 +181,10 @@ func (d *DataWarning) GetWarningColumn() (headers map[string]string, headerSort
 			"cowKindName",
 		}
 	default:
-		return nil, nil, xerr.Custom("暂不支持该预警数据")
+		message, _ := i18nTemplate.Localize(&i18n.LocalizeConfig{
+			MessageID: "dataWarning.notSupported",
+		})
+		return nil, nil, xerr.Custom(message)
 	}
 	return headers, headerSort, nil
 }

+ 6 - 1
model/system_user.go

@@ -87,7 +87,12 @@ type UserModel struct {
 
 type SystemUserSlice []*SystemUser
 
-func (s SystemUserSlice) ToPB(deptList []*SystemDept, roleList []*SystemRole, appPastureList []*AppPastureList, systemUserDepthRoleMap map[int64]*SystemUserDepthRole) []*pasturePb.SearchUserRequest {
+func (s SystemUserSlice) ToPB(
+	deptList []*SystemDept,
+	roleList []*SystemRole,
+	appPastureList []*AppPastureList,
+	systemUserDepthRoleMap map[int64]*SystemUserDepthRole,
+) []*pasturePb.SearchUserRequest {
 	deptMap := make(map[int32]*SystemDept)
 	for _, v := range deptList {
 		deptMap[int32(v.Id)] = v

+ 1 - 1
module/backend/analysis.go

@@ -16,7 +16,7 @@ import (
 func (s *StoreEntry) WeightScatterPlot(ctx context.Context, req *pasturePb.SearchGrowthCurvesRequest, pagination *pasturePb.PaginationModel) (*pasturePb.GrowthCurvesResponse, error) {
 	userModel, err := s.GetUserModel(ctx)
 	if err != nil {
-		return nil, xerr.Custom("当前用户信息错误,请退出重新登录")
+		return nil, xerr.WithStack(err)
 	}
 
 	// 查询数据

+ 78 - 41
module/backend/analysis_breed.go

@@ -7,6 +7,8 @@ import (
 	"kpt-pasture/util"
 	"net/http"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	"gitee.com/xuyiping_admin/pkg/xerr"
 )
@@ -21,7 +23,10 @@ func (s *StoreEntry) SingleFactorInfantSurvivalRateAnalysis(ctx context.Context,
 	startTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
 	endTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
 	if startTimeUnix == 0 || endTimeUnix == 0 || endTimeUnix <= startTimeUnix {
-		return nil, xerr.Custom("开始时间不能大于结束时间")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "validate.startEndDateTime",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 	list := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
 	chart := &pasturePb.SingleFactorPregnancyRateChart{
@@ -33,29 +38,32 @@ func (s *StoreEntry) SingleFactorInfantSurvivalRateAnalysis(ctx context.Context,
 	}
 	switch req.AnalysisMethod {
 	case pasturePb.SingleFactorAnalysisMethod_Cycle:
-		list, err = s.SingleFactorAnalysisMethodCycle(userModel.AppPasture.Id, req)
+		list, err = s.SingleFactorAnalysisMethodCycle(userModel, req)
 	case pasturePb.SingleFactorAnalysisMethod_Months:
-		list, err = s.SingleFactorAnalysisMethodMonths(userModel.AppPasture.Id, req)
+		list, err = s.SingleFactorAnalysisMethodMonths(userModel, req)
 	case pasturePb.SingleFactorAnalysisMethod_Mating_Times:
-		list, err = s.SingleFactorAnalysisMethodMatingTimes(userModel.AppPasture.Id, req)
+		list, err = s.SingleFactorAnalysisMethodMatingTimes(userModel, req)
 	case pasturePb.SingleFactorAnalysisMethod_Breeding_Method:
-		list, err = s.SingleFactorAnalysisMethodBreeding(userModel.AppPasture.Id, req)
+		list, err = s.SingleFactorAnalysisMethodBreeding(userModel, req)
 	case pasturePb.SingleFactorAnalysisMethod_Breeding_Company:
-		list, err = s.SingleFactorAnalysisMethodBreedingCompany(userModel.AppPasture.Id, req)
+		list, err = s.SingleFactorAnalysisMethodBreedingCompany(userModel, req)
 	case pasturePb.SingleFactorAnalysisMethod_Operation:
-		list, err = s.SingleFactorAnalysisMethodOperation(userModel.AppPasture.Id, req)
+		list, err = s.SingleFactorAnalysisMethodOperation(userModel, req)
 	case pasturePb.SingleFactorAnalysisMethod_Mating_Interval:
-		list, err = s.SingleFactorAnalysisMethodMatingInterval(userModel.AppPasture.Id, req)
+		list, err = s.SingleFactorAnalysisMethodMatingInterval(userModel, req)
 	case pasturePb.SingleFactorAnalysisMethod_Bull:
-		list, err = s.SingleFactorAnalysisMethodBull(userModel.AppPasture.Id, req)
+		list, err = s.SingleFactorAnalysisMethodBull(userModel, req)
 	case pasturePb.SingleFactorAnalysisMethod_Breeding_Cycle:
-		list, err = s.SingleFactorAnalysisMethodBreedingCycle(userModel.AppPasture.Id, req)
+		list, err = s.SingleFactorAnalysisMethodBreedingCycle(userModel, req)
 	case pasturePb.SingleFactorAnalysisMethod_Week:
-		list, err = s.SingleFactorAnalysisMethodWeek(userModel.AppPasture.Id, req)
+		list, err = s.SingleFactorAnalysisMethodWeek(userModel, req)
 	case pasturePb.SingleFactorAnalysisMethod_Lact:
-		list, err = s.SingleFactorAnalysisMethodLact(userModel.AppPasture.Id, req)
+		list, err = s.SingleFactorAnalysisMethodLact(userModel, req)
 	default:
-		return nil, xerr.Custom("错误的统计方式")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "analysis.wrongMethod",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	if err != nil {
@@ -108,7 +116,7 @@ func (s *StoreEntry) SingleFactorInfantSurvivalRateAnalysis(ctx context.Context,
 	}, nil
 }
 
-func (s *StoreEntry) SingleFactorAnalysisMethodCycle(pastureId int64, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+func (s *StoreEntry) SingleFactorAnalysisMethodCycle(userModel *model.UserModel, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
 	dateTimeRange, err := util.GetRangeDayByDays(req.StartDayTime, req.EndDayTime, req.Value)
 	if err != nil {
 		return nil, xerr.WithStack(err)
@@ -139,7 +147,7 @@ func (s *StoreEntry) SingleFactorAnalysisMethodCycle(pastureId int64, req *pastu
 		UNION ALL `, v[0], v[1], pasturePb.MatingResult_Pregnant, pasturePb.MatingResult_Empty, pasturePb.MatingResult_Abort,
 			pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
 			pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch,
-			pastureId, pasturePb.IsShow_Ok, startDayTimeUnix, endDayTimeUnix)
+			userModel.AppPasture.Id, pasturePb.IsShow_Ok, startDayTimeUnix, endDayTimeUnix)
 	}
 
 	if len(selectSql) > 0 {
@@ -153,11 +161,14 @@ func (s *StoreEntry) SingleFactorAnalysisMethodCycle(pastureId int64, req *pastu
 	return res, nil
 }
 
-func (s *StoreEntry) SingleFactorAnalysisMethodMonths(pastureId int64, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+func (s *StoreEntry) SingleFactorAnalysisMethodMonths(userModel *model.UserModel, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
 	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
 	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
 	if startDayTimeUnix == 0 || endDayTimeUnix == 0 || endDayTimeUnix <= startDayTimeUnix {
-		return nil, xerr.Custom("开始时间不能大于结束时间")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "validate.startEndDateTime",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
@@ -178,7 +189,7 @@ func (s *StoreEntry) SingleFactorAnalysisMethodMonths(pastureId int64, req *past
 			pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
 			pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch).
 		Where("status = ?", pasturePb.IsShow_Ok).
-		Where("pasture_id = ?", pastureId).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix)
 	if req.CowType > 0 {
 		pref.Where("cow_type = ?", req.CowType)
@@ -205,22 +216,27 @@ func (s *StoreEntry) SingleFactorAnalysisMethodMonths(pastureId int64, req *past
 		case pasturePb.CompareSymbol_Between:
 			pref.Where("lact BETWEEN ? AND ? ", req.LactIntervalStartValue, req.LactIntervalEndValue)
 		default:
-			return nil, xerr.Custom("错误的胎次区间符号")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "analysis.wrongLact",
+			})
+			return nil, xerr.Custom(messageId)
 		}
 	}
 
-	if err := pref.Group("months").Order("months").Find(&res).Error; err != nil {
+	if err := pref.Group("months").
+		Order("months").
+		Find(&res).Error; err != nil {
 		return nil, xerr.WithStack(err)
 	}
 	return res, nil
 }
 
-func (s *StoreEntry) SingleFactorAnalysisMethodMatingTimes(pastureId int64, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+func (s *StoreEntry) SingleFactorAnalysisMethodMatingTimes(userModel *model.UserModel, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
 	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
 	return res, nil
 }
 
-func (s *StoreEntry) SingleFactorAnalysisMethodBreeding(pastureId int64, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+func (s *StoreEntry) SingleFactorAnalysisMethodBreeding(userModel *model.UserModel, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
 	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
 	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
 	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
@@ -249,7 +265,7 @@ func (s *StoreEntry) SingleFactorAnalysisMethodBreeding(pastureId int64, req *pa
 			pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch, pasturePb.MatingResult_Pregnant,
 			pasturePb.MatingResult_Empty, pasturePb.MatingResult_Unknown, pasturePb.MatingResult_ReMatch,
 		).Where("status = ?", pasturePb.IsShow_Ok).
-		Where("pasture_id = ?", pastureId).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix).
 		Where("cow_type = ?", req.CowType).
 		Group("expose_estrus_type").
@@ -260,7 +276,7 @@ func (s *StoreEntry) SingleFactorAnalysisMethodBreeding(pastureId int64, req *pa
 	return res, nil
 }
 
-func (s *StoreEntry) SingleFactorAnalysisMethodBreedingCompany(pastureId int64, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+func (s *StoreEntry) SingleFactorAnalysisMethodBreedingCompany(userModel *model.UserModel, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
 	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
 	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
 	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
@@ -304,11 +320,14 @@ func (s *StoreEntry) SingleFactorAnalysisMethodBreedingCompany(pastureId int64,
 		case pasturePb.CompareSymbol_Between:
 			pref.Where("a.lact BETWEEN ? AND ? ", req.LactIntervalStartValue, req.LactIntervalEndValue)
 		default:
-			return nil, xerr.Custom("错误的胎次区间符号")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "analysis.wrongLact",
+			})
+			return nil, xerr.Custom(messageId)
 		}
 	}
 
-	if err := pref.Where("a.status = ?", pasturePb.IsShow_Ok).Where("pasture_id = ?", pastureId).
+	if err := pref.Where("a.status = ?", pasturePb.IsShow_Ok).Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("a.reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix).
 		Group("b.producer").
 		Find(&res).Error; err != nil {
@@ -318,7 +337,7 @@ func (s *StoreEntry) SingleFactorAnalysisMethodBreedingCompany(pastureId int64,
 	return res, nil
 }
 
-func (s *StoreEntry) SingleFactorAnalysisMethodOperation(pastureId int64, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+func (s *StoreEntry) SingleFactorAnalysisMethodOperation(userModel *model.UserModel, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
 	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
 	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
 	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
@@ -360,12 +379,15 @@ func (s *StoreEntry) SingleFactorAnalysisMethodOperation(pastureId int64, req *p
 		case pasturePb.CompareSymbol_Between:
 			pref.Where("lact BETWEEN ? AND ? ", req.LactIntervalStartValue, req.LactIntervalEndValue)
 		default:
-			return nil, xerr.Custom("错误的胎次区间符号")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "analysis.wrongLact",
+			})
+			return nil, xerr.Custom(messageId)
 		}
 	}
 
 	if err := pref.Where("status = ?", pasturePb.IsShow_Ok).
-		Where("pasture_id = ?", pastureId).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix).
 		Group("operation_id").
 		Find(&res).Error; err != nil {
@@ -375,12 +397,12 @@ func (s *StoreEntry) SingleFactorAnalysisMethodOperation(pastureId int64, req *p
 	return res, nil
 }
 
-func (s *StoreEntry) SingleFactorAnalysisMethodMatingInterval(pastureId int64, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+func (s *StoreEntry) SingleFactorAnalysisMethodMatingInterval(userModel *model.UserModel, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
 	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
 	return res, nil
 }
 
-func (s *StoreEntry) SingleFactorAnalysisMethodBull(pastureId int64, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+func (s *StoreEntry) SingleFactorAnalysisMethodBull(userModel *model.UserModel, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
 	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
 	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
 	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
@@ -423,7 +445,10 @@ func (s *StoreEntry) SingleFactorAnalysisMethodBull(pastureId int64, req *pastur
 		case pasturePb.CompareSymbol_Between:
 			pref.Where("lact BETWEEN ? AND ? ", req.LactIntervalStartValue, req.LactIntervalEndValue)
 		default:
-			return nil, xerr.Custom("错误的胎次区间符号")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "analysis.wrongLact",
+			})
+			return nil, xerr.Custom(messageId)
 		}
 	}
 
@@ -438,12 +463,12 @@ func (s *StoreEntry) SingleFactorAnalysisMethodBull(pastureId int64, req *pastur
 	return res, nil
 }
 
-func (s *StoreEntry) SingleFactorAnalysisMethodBreedingCycle(pastureId int64, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+func (s *StoreEntry) SingleFactorAnalysisMethodBreedingCycle(userModel *model.UserModel, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
 	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
 	return res, nil
 }
 
-func (s *StoreEntry) SingleFactorAnalysisMethodWeek(pastureId int64, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+func (s *StoreEntry) SingleFactorAnalysisMethodWeek(userModel *model.UserModel, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
 	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
 	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
 	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
@@ -496,12 +521,15 @@ func (s *StoreEntry) SingleFactorAnalysisMethodWeek(pastureId int64, req *pastur
 		case pasturePb.CompareSymbol_Between:
 			pref.Where("lact BETWEEN ? AND ? ", req.LactIntervalStartValue, req.LactIntervalEndValue)
 		default:
-			return nil, xerr.Custom("错误的胎次区间符号")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "analysis.wrongLact",
+			})
+			return nil, xerr.Custom(messageId)
 		}
 	}
 
 	if err := pref.Where("status = ?", pasturePb.IsShow_Ok).
-		Where("pasture_id = ?", pastureId).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix).
 		Group("statistic_method").
 		Find(&res).Error; err != nil {
@@ -511,7 +539,7 @@ func (s *StoreEntry) SingleFactorAnalysisMethodWeek(pastureId int64, req *pastur
 	return res, nil
 }
 
-func (s *StoreEntry) SingleFactorAnalysisMethodLact(pastureId int64, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
+func (s *StoreEntry) SingleFactorAnalysisMethodLact(userModel *model.UserModel, req *pasturePb.SingleFactorPregnancyRateRequest) ([]*pasturePb.SingleFactorPregnancyRateList, error) {
 	res := make([]*pasturePb.SingleFactorPregnancyRateList, 0)
 	startDayTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
 	endDayTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
@@ -538,7 +566,7 @@ func (s *StoreEntry) SingleFactorAnalysisMethodLact(pastureId int64, req *pastur
 	}
 
 	if err := pref.Where("status = ?", pasturePb.IsShow_Ok).
-		Where("pasture_id = ?", pastureId).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("reality_day BETWEEN ? AND ?", startDayTimeUnix, endDayTimeUnix).
 		Group("lact").
 		Find(&res).Error; err != nil {
@@ -556,15 +584,24 @@ func (s *StoreEntry) MultipleFactorAnalysis(ctx context.Context, req *pasturePb.
 	startTimeUnix := util.TimeParseLocalUnix(req.StartDayTime)
 	endTimeUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
 	if startTimeUnix == 0 || endTimeUnix == 0 || endTimeUnix <= startTimeUnix {
-		return nil, xerr.Custom("开始时间不能大于结束时间")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "analysis.wrongDateRange",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	if req.XAxle == req.YAxle {
-		return nil, xerr.Custom("X轴和Y轴不能相同")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "analysis.xAndY",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	if req.XAxle == 0 || req.YAxle == 0 {
-		return nil, xerr.Custom("错误的XY轴数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "analysis.wrongXY",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	pref := s.DB.Model(new(model.EventMating)).

+ 14 - 3
module/backend/analysis_more.go

@@ -9,6 +9,8 @@ import (
 	"sort"
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	"gitee.com/xuyiping_admin/pkg/xerr"
 
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
@@ -21,7 +23,10 @@ func (s *StoreEntry) PenBehavior(ctx context.Context, req *pasturePb.BarnBehavio
 	}
 
 	if req.StartAt == 0 || req.EndAt == 0 || req.EndAt < req.StartAt {
-		return nil, xerr.Customf("时间范围错误")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.errorDateRange",
+		})
+		return nil, xerr.Customf(messageId)
 	}
 	startTime := time.Unix(int64(req.StartAt), 0).Local().Format(model.LayoutDate2)
 	endTime := time.Unix(int64(req.EndAt), 0).Local().Format(model.LayoutDate2)
@@ -46,7 +51,10 @@ func (s *StoreEntry) PenBehaviorDaily(ctx context.Context, req *pasturePb.BarnMo
 		return nil, xerr.WithStack(err)
 	}
 	if req.StartAt == 0 || req.EndAt == 0 || req.EndAt < req.StartAt {
-		return nil, xerr.Customf("时间范围错误")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.errorDateRange",
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	startDate := time.Unix(int64(req.StartAt), 0).Local().Format(model.LayoutDate2)
@@ -106,7 +114,10 @@ func (s *StoreEntry) CowBehaviorDistribution(ctx context.Context, req *pasturePb
 
 	// 校验时间必须比当天时间小一天
 	if time.Now().Local().Format(model.LayoutDate2) == req.DateTime {
-		return nil, xerr.Customf("时间范围错误")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.errorDateRange",
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	milkDailList := make([]*model.MilkDaily, 0)

+ 26 - 15
module/backend/calendar.go

@@ -299,10 +299,12 @@ func (s *StoreEntry) ImmunisationCowList(ctx context.Context, req *pasturePb.Ite
 		Code: http.StatusOK,
 		Msg:  "ok",
 		Data: &pasturePb.ImmunizationItemsData{
-			Total:      int32(count),
-			Page:       pagination.Page,
-			PageSize:   pagination.PageSize,
-			HeaderSort: []string{"planDay", "planName", "penName", "dayAge", "earNumber", "planId"},
+			Total:    int32(count),
+			Page:     pagination.Page,
+			PageSize: pagination.PageSize,
+			HeaderSort: []string{
+				"planDay", "planName", "penName", "dayAge", "earNumber", "planId",
+			},
 			Header: map[string]string{
 				"earNumber": "耳标号",
 				"penName":   "栏舍",
@@ -365,9 +367,11 @@ func (s *StoreEntry) SameTimeCowList(ctx context.Context, req *pasturePb.ItemsRe
 			Total:    int32(count),
 			Page:     pagination.Page,
 			PageSize: pagination.PageSize,
-			HeaderSort: []string{"earNumber", "breedStatusName", "cowTypeName", "planDayAtFormat", "penName",
-				"lact", "calvingAge", "abortionAge", "dayAge", "status", "sameTimeTypeName", "matingTimes", "calvingAtFormat",
-				"abortionAtFormat", "sameTimeName"},
+			HeaderSort: []string{
+				"earNumber", "breedStatusName", "cowTypeName", "planDayAtFormat", "penName", "lact",
+				"calvingAge", "abortionAge", "dayAge", "status", "sameTimeTypeName", "matingTimes",
+				"calvingAtFormat", "abortionAtFormat", "sameTimeName",
+			},
 			Header: map[string]string{
 				"earNumber":        "耳标号",
 				"breedStatusName":  "繁殖状态",
@@ -457,8 +461,11 @@ func (s *StoreEntry) PregnancyCheckCowList(ctx context.Context, req *pasturePb.I
 			Total:    int32(count),
 			Page:     pagination.Page,
 			PageSize: pagination.PageSize,
-			HeaderSort: []string{"earNumber", "cowTypeName", "penName", "lact", "dayAge", "breedStatus", "planDay",
-				"checkTypeName", "status", "matingTimes", "calvingAtFormat", "matingAtFormat", "matingAge", "bullId", "pregnancyAge"},
+			HeaderSort: []string{
+				"earNumber", "cowTypeName", "penName", "lact", "dayAge", "breedStatus", "planDay",
+				"checkTypeName", "status", "matingTimes", "calvingAtFormat", "matingAtFormat",
+				"matingAge", "bullId", "pregnancyAge",
+			},
 			Header: map[string]string{
 				"earNumber":       "耳标号",
 				"cowTypeName":     "牛只类型",
@@ -514,10 +521,12 @@ func (s *StoreEntry) WeaningCowList(ctx context.Context, req *pasturePb.ItemsReq
 		Code: http.StatusOK,
 		Msg:  "ok",
 		Data: &pasturePb.WeaningItemsData{
-			Total:      int32(count),
-			Page:       pagination.Page,
-			PageSize:   pagination.PageSize,
-			HeaderSort: []string{"earNumber", "penName", "dayAge", "planDayFormat", "birthAtFormat", "currentWeight"},
+			Total:    int32(count),
+			Page:     pagination.Page,
+			PageSize: pagination.PageSize,
+			HeaderSort: []string{
+				"earNumber", "penName", "dayAge", "planDayFormat", "birthAtFormat", "currentWeight",
+			},
 			Header: map[string]string{
 				"earNumber":     "耳标号",
 				"penName":       "栏舍",
@@ -585,8 +594,10 @@ func (s *StoreEntry) MatingCowList(ctx context.Context, req *pasturePb.ItemsRequ
 			Total:    int32(count),
 			Page:     pagination.Page,
 			PageSize: pagination.PageSize,
-			HeaderSort: []string{"earNumber", "dayAge", "lact", "penName", "planDay", "breedStatusName",
-				"cowTypeName", "calvingAge", "abortionAge", "exposeEstrusTypeName", "lastCalvingAtFormat"},
+			HeaderSort: []string{
+				"earNumber", "dayAge", "lact", "penName", "planDay", "breedStatusName", "cowTypeName",
+				"calvingAge", "abortionAge", "exposeEstrusTypeName", "lastCalvingAtFormat",
+			},
 			Header: map[string]string{
 				"earNumber":            "耳标号",
 				"breedStatusName":      "繁殖状态",

+ 56 - 14
module/backend/cow.go

@@ -12,6 +12,8 @@ import (
 	"sync"
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	"gorm.io/gorm"
 
 	"gitee.com/xuyiping_admin/pkg/xerr"
@@ -26,7 +28,10 @@ func (s *StoreEntry) Detail(ctx context.Context, req *pasturePb.SearchEventReque
 	}
 
 	if req.EarNumber == "" && req.NeckRingNumber == "" {
-		return nil, xerr.Custom("请输入牛号或项圈号")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.inputCow",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	cowInfo := &model.Cow{}
@@ -43,7 +48,10 @@ func (s *StoreEntry) Detail(ctx context.Context, req *pasturePb.SearchEventReque
 
 	if err = pref.First(cowInfo).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return nil, xerr.Custom("该牛只未找到")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "cow.noCow",
+			})
+			return nil, xerr.Custom(messageId)
 		} else {
 			return nil, xerr.WithStack(err)
 		}
@@ -58,7 +66,10 @@ func (s *StoreEntry) Detail(ctx context.Context, req *pasturePb.SearchEventReque
 	purposeMap := s.PurposeMap()
 	systemBasic, err := s.GetSystemBasicByName(ctx, userModel.AppPasture.Id, model.PregnancyAge)
 	if err != nil {
-		return nil, xerr.Custom("请在基础参数配置妊娠天数")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.pregnancyDays",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	cowDetails := model.CowSlice([]*model.Cow{cowInfo}).ToPB(
@@ -66,7 +77,10 @@ func (s *StoreEntry) Detail(ctx context.Context, req *pasturePb.SearchEventReque
 		admissionStatusMap, healthStatusMap, purposeMap, systemBasic.MinValue,
 	)
 	if len(cowDetails) != 1 {
-		return nil, xerr.Custom("该牛只未找到")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.noCow",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	data := cowDetails[0]
@@ -85,7 +99,10 @@ func (s *StoreEntry) List(ctx context.Context, req *pasturePb.SearchEventRequest
 
 	systemBasic, err := s.GetSystemBasicByName(ctx, userModel.AppPasture.Id, model.PregnancyAge)
 	if err != nil {
-		return nil, xerr.Custom("请在基础参数配置妊娠天数")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.pregnancyDays",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	cowList := make([]*model.Cow, 0)
@@ -172,7 +189,11 @@ func (s *StoreEntry) EventList(ctx context.Context, req *pasturePb.SearchCowEven
 	eventCowLogList := make([]*model.EventCowLog, 0)
 	cowInfo, err := s.GetCowEventByEarNumber(ctx, userModel.AppPasture.Id, req.EarNumber)
 	if err != nil {
-		return nil, xerr.Customf("错误的牛只信息: %s", req.EarNumber)
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID:    "auth.errorCow",
+			TemplateData: map[string]interface{}{"earNumber": req.EarNumber},
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	eventCowLog := &model.EventCowLog{CowId: cowInfo.Id}
@@ -215,13 +236,17 @@ func (s *StoreEntry) BehaviorCurve(ctx context.Context, req *pasturePb.CowBehavi
 	}
 	cowInfo, err := s.GetCowEventByEarNumber(ctx, userModel.AppPasture.Id, req.EarNumber)
 	if err != nil {
-		return nil, xerr.Customf("错误的牛只信息: %d", req.CowId)
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID:    "auth.errorCow",
+			TemplateData: map[string]interface{}{"earNumber": req.EarNumber},
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	nowTime := time.Now().Local()
 	nowDayZero := util.TimeParseLocalUnix(nowTime.Format(model.LayoutDate2))
 	endDataTime := nowTime.Format(model.LayoutDate2)
-	startDataTime := nowTime.AddDate(0, 0, -30).Format(model.LayoutDate2)
+	startDataTime := nowTime.AddDate(0, 0, -50).Format(model.LayoutDate2)
 
 	dayRange, err := util.GetDaysBetween(startDataTime, endDataTime)
 	if err != nil {
@@ -229,7 +254,10 @@ func (s *StoreEntry) BehaviorCurve(ctx context.Context, req *pasturePb.CowBehavi
 	}
 
 	if len(dayRange) <= 0 {
-		return nil, xerr.Customf("错误的日期范围")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.errorDateRange",
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	// 行为曲线数据
@@ -500,7 +528,11 @@ func (s *StoreEntry) CowGrowthCurve(ctx context.Context, req *pasturePb.CowGrowt
 	}
 	cowInfo, err := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, req.EarNumber)
 	if err != nil {
-		return nil, xerr.Customf("错误的牛只信息: %s", req.EarNumber)
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID:    "auth.errorCow",
+			TemplateData: map[string]interface{}{"earNumber": req.EarNumber},
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	weightList := make([]*model.EventWeight, 0)
@@ -536,7 +568,11 @@ func (s *StoreEntry) CowLactCurve(ctx context.Context, req *pasturePb.CowLactCur
 	}
 	cowInfo, err := s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, int64(req.CowId))
 	if err != nil {
-		return nil, xerr.Customf("错误的牛只信息: %d", req.CowId)
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID:    "auth.errorCow",
+			TemplateData: map[string]interface{}{"earNumber": req.EarNumber},
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	cowLactList := make([]*model.CowLact, 0)
@@ -608,14 +644,20 @@ func (s *StoreEntry) BehaviorRate(ctx context.Context, req *pasturePb.CowBehavio
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}
-
 	cowInfo, err := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, req.EarNumber)
 	if err != nil {
-		return nil, xerr.Customf("错误的牛只信息: %s", req.EarNumber)
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID:    "auth.errorCow",
+			TemplateData: map[string]interface{}{"earNumber": req.EarNumber},
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	if req.EndAt <= 0 || req.StartAt <= 0 || req.EndAt < req.StartAt {
-		return nil, xerr.Customf("时间范围错误")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.errorDateRange",
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	t1 := time.Unix(int64(req.StartAt), 0).Local().Format(model.LayoutDate2)

+ 52 - 23
module/backend/dashboard.go

@@ -11,6 +11,8 @@ import (
 	"strings"
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	"gorm.io/gorm"
 
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
@@ -28,12 +30,18 @@ func (s *StoreEntry) DataWarningSet(ctx context.Context, req *pasturePb.IndexDat
 	pastureId := userModel.AppPasture.Id
 
 	if len(req.WarningDataSet) <= 0 {
-		return xerr.Custom("请选择预警数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "dataWarning.selectData",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	defaultDataWarning, _ := s.FindDataWarning(ctx, pastureId, model.DefaultUserId)
 	if len(defaultDataWarning) <= 0 {
-		return xerr.Custom("默认预警数据不存在,请联系管理员!")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "dataWarning.defaultDataNotExist",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	userDataWarningList, err := s.FindDataWarning(ctx, pastureId, userModel.SystemUser.Id)
@@ -42,9 +50,9 @@ func (s *StoreEntry) DataWarningSet(ctx context.Context, req *pasturePb.IndexDat
 	}
 
 	if len(userDataWarningList) <= 0 { // 新增
-		return s.addUserDataWarning(ctx, pastureId, userModel.SystemUser.Id, defaultDataWarning, req.WarningDataSet)
+		return s.addUserDataWarning(userModel, defaultDataWarning, req.WarningDataSet)
 	}
-	return s.updateUserDataWarning(ctx, pastureId, userModel.SystemUser.Id, userDataWarningList, req.WarningDataSet)
+	return s.updateUserDataWarning(userModel, userDataWarningList, req.WarningDataSet)
 }
 
 func (s *StoreEntry) DataWarningList(ctx context.Context) (*pasturePb.IndexDataWarningResponse, error) {
@@ -56,7 +64,10 @@ func (s *StoreEntry) DataWarningList(ctx context.Context) (*pasturePb.IndexDataW
 	pastureId := userModel.AppPasture.Id
 	defaultDataWarning, _ := s.FindDataWarning(ctx, pastureId, model.DefaultUserId)
 	if len(defaultDataWarning) <= 0 {
-		return nil, xerr.Custom("默认预警数据有误,请联系管理员!")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "dataWarning.defaultDataError",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	var isExist bool // 判断是否存在自己的设置的数据
@@ -79,17 +90,17 @@ func (s *StoreEntry) DataWarningList(ctx context.Context) (*pasturePb.IndexDataW
 
 	// 需要重新计算更新的warningId
 	if len(needUpdateWarningIds) > 0 {
-		s.UpdateWarningData(ctx, pastureId, needUpdateWarningIds)
+		s.UpdateWarningData(userModel, needUpdateWarningIds)
 	}
 
 	userDataWarningItems := make([]*model.DataWarningItems, 0)
 	// 计算过后重新获取数据
 	if isExist {
 		userDataWarning, _ = s.FindDataWarning(ctx, pastureId, model.DefaultUserId)
-		userDataWarningItems, _ = s.FindDataWarningItems(ctx, pastureId, model.DefaultUserId)
+		userDataWarningItems, _ = s.FindDataWarningItems(pastureId, model.DefaultUserId)
 	} else {
 		userDataWarning, _ = s.FindDataWarning(ctx, pastureId, userModel.SystemUser.Id)
-		userDataWarningItems, _ = s.FindDataWarningItems(ctx, pastureId, userModel.SystemUser.Id)
+		userDataWarningItems, _ = s.FindDataWarningItems(pastureId, userModel.SystemUser.Id)
 	}
 
 	return &pasturePb.IndexDataWarningResponse{
@@ -109,7 +120,10 @@ func (s *StoreEntry) DataWarningPop(ctx context.Context, req *pasturePb.WarningD
 	}
 
 	if req.Kind <= pasturePb.DataWarningType_Invalid {
-		return nil, xerr.Custom("请选择预警数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "dataWarning.selectData",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	pastureId := userModel.AppPasture.Id
@@ -128,11 +142,14 @@ func (s *StoreEntry) DataWarningPop(ctx context.Context, req *pasturePb.WarningD
 				return nil, xerr.WithStack(err)
 			}
 		} else {
-			return nil, xerr.Custom("预警数据不存在,请联系管理员!")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "dataWarning.dataNotExist",
+			})
+			return nil, xerr.Custom(messageId)
 		}
 	}
 
-	headers, headerSort, err := dataWaringItem.GetWarningColumn()
+	headers, headerSort, err := dataWaringItem.GetWarningColumn(userModel.LanguageContent)
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}
@@ -152,7 +169,7 @@ func (s *StoreEntry) DataWarningPop(ctx context.Context, req *pasturePb.WarningD
 		},
 	}
 
-	query, params, err := s.BuildQuery(dataWaringItem.Id)
+	query, params, err := s.BuildQuery(userModel, dataWaringItem.Id)
 	if err != nil {
 		zaplog.Error("UpdateWarningData", zap.Any("BuildQuery", err), zap.Any("warningId", dataWaringItem.Id))
 		return resp, nil
@@ -183,7 +200,10 @@ func (s *StoreEntry) DataWarningPop(ctx context.Context, req *pasturePb.WarningD
 	resp.Data.Total = int32(count)
 	systemBasic, err := s.GetSystemBasicByName(ctx, userModel.AppPasture.Id, model.PregnancyAge)
 	if err != nil {
-		return nil, xerr.Custom("请在基础参数配置妊娠天数")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.pregnancyDays",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 	resp.Data.DataList = model.CowSlice(cowList).ToPB(
 		cowTypeMap, breedStatusMap, cowKindMap,
@@ -204,7 +224,7 @@ func (s *StoreEntry) FindDataWarning(ctx context.Context, pastureId, userId int6
 	return dataWarningList, nil
 }
 
-func (s *StoreEntry) FindDataWarningItems(ctx context.Context, pastureId, userId int64) ([]*model.DataWarningItems, error) {
+func (s *StoreEntry) FindDataWarningItems(pastureId, userId int64) ([]*model.DataWarningItems, error) {
 	dataWarningItemsList := make([]*model.DataWarningItems, 0)
 	if err := s.DB.Model(new(model.DataWarningItems)).
 		Where("pasture_id = ?", pastureId).
@@ -215,7 +235,7 @@ func (s *StoreEntry) FindDataWarningItems(ctx context.Context, pastureId, userId
 	return dataWarningItemsList, nil
 }
 
-func (s *StoreEntry) FindDataWarningMap(ctx context.Context, pastureId, userId int64) (map[int64]*model.DataWarning, error) {
+/*func (s *StoreEntry) FindDataWarningMap(ctx context.Context, pastureId, userId int64) (map[int64]*model.DataWarning, error) {
 	dataWarning, err := s.FindDataWarning(ctx, pastureId, userId)
 	if err != nil {
 		return nil, xerr.Custom("默认预警数据有误,请联系管理员!")
@@ -239,15 +259,15 @@ func (s *StoreEntry) FindDataWarningItemsMap(ctx context.Context, userId int64)
 		dataWarningItemsMap[v.Id] = v
 	}
 	return dataWarningItemsMap, nil
-}
+}*/
 
 // UpdateWarningData 更新计算数据
-func (s *StoreEntry) UpdateWarningData(ctx context.Context, pastureId int64, needUpdateWarningIds []int64) {
+func (s *StoreEntry) UpdateWarningData(userModel *model.UserModel, needUpdateWarningIds []int64) {
 	if len(needUpdateWarningIds) <= 0 {
 		return
 	}
 	for _, warningId := range needUpdateWarningIds {
-		query, params, err := s.BuildQuery(warningId)
+		query, params, err := s.BuildQuery(userModel, warningId)
 		if err != nil {
 			zaplog.Error("UpdateWarningData", zap.Any("BuildQuery", err), zap.Any("warningId", warningId))
 		}
@@ -259,7 +279,7 @@ func (s *StoreEntry) UpdateWarningData(ctx context.Context, pastureId int64, nee
 
 		var count int64
 		if err = s.DB.Model(new(model.Cow)).
-			Where("pasture_id = ?", pastureId).
+			Where("pasture_id = ?", userModel.AppPasture.Id).
 			Where(query, params...).
 			Count(&count).Error; err != nil {
 			zaplog.Error("UpdateWarningData", zap.Any("err", err), zap.Any("query", query), zap.Any("params", params))
@@ -277,13 +297,16 @@ func (s *StoreEntry) UpdateWarningData(ctx context.Context, pastureId int64, nee
 }
 
 // 新增用户预警数据
-func (s *StoreEntry) addUserDataWarning(ctx context.Context, pastureId, userId int64, defaultDataWarning []*model.DataWarning, warningDataSet []*pasturePb.WarningDataSet) error {
+func (s *StoreEntry) addUserDataWarning(userModel *model.UserModel, defaultDataWarning []*model.DataWarning, warningDataSet []*pasturePb.WarningDataSet) error {
 	// 将默认预警数据按 Kind 映射
 	defaultDataWarningMap := make(map[pasturePb.DataWarningType_Kind]*model.DataWarning)
 	for _, v := range defaultDataWarning {
 		defaultDataWarningMap[v.Kind] = v
 	}
 
+	pastureId := userModel.AppPasture.Id
+	userId := userModel.SystemUser.Id
+
 	// 在事务中执行新增操作
 	return s.DB.Transaction(func(tx *gorm.DB) error {
 		addedKinds := make(map[pasturePb.DataWarningType_Kind]bool) // 记录已添加的 Kind
@@ -320,7 +343,7 @@ func (s *StoreEntry) addUserDataWarning(ctx context.Context, pastureId, userId i
 }
 
 // 更新用户预警数据
-func (s *StoreEntry) updateUserDataWarning(ctx context.Context, pastureId, userId int64, userDataWarningList []*model.DataWarning, warningDataSet []*pasturePb.WarningDataSet) error {
+func (s *StoreEntry) updateUserDataWarning(userModel *model.UserModel, userDataWarningList []*model.DataWarning, warningDataSet []*pasturePb.WarningDataSet) error {
 	// 将请求数据按 WarningId 和 Id 映射
 	warningIsShowMap := make(map[int32]*pasturePb.WarningDataSet)
 	warningItemDataMap := make(map[int32]*pasturePb.WarningDataSet)
@@ -329,14 +352,20 @@ func (s *StoreEntry) updateUserDataWarning(ctx context.Context, pastureId, userI
 		warningItemDataMap[set.Id] = set
 	}
 
+	pastureId := userModel.AppPasture.Id
+	userId := userModel.SystemUser.Id
+
 	// 获取用户预警项数据
-	userDataWarningItems, err := s.FindDataWarningItems(ctx, pastureId, userId)
+	userDataWarningItems, err := s.FindDataWarningItems(pastureId, userId)
 	if err != nil {
 		return xerr.WithStack(err)
 	}
 
 	if len(userDataWarningItems) == 0 {
-		return xerr.Custom("预警数据有误,请联系管理员!")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "dataWarning.dataError",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	// 在事务中执行更新操作

+ 8 - 3
module/backend/dashboard_more.go

@@ -10,6 +10,8 @@ import (
 	"strings"
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
 	"gitee.com/xuyiping_admin/pkg/xerr"
@@ -308,14 +310,17 @@ func (s *StoreEntry) OutNumber(ctx context.Context) (*pasturePb.OutNumberRespons
 
 	nowTime := time.Now().Local()
 	currentMonth := nowTime.Format(model.LayoutMonth)
-	startMonth := nowTime.AddDate(0, -5, 0).Format(model.LayoutMonth)
-
+	startTime := time.Date(nowTime.Year(), nowTime.Month(), 1, 0, 0, 0, 0, nowTime.Location())
+	startMonth := startTime.AddDate(0, -5, 0).Format(model.LayoutMonth)
 	monthRang, err := util.GetMonthsBetween(startMonth, currentMonth)
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}
 	if len(monthRang) != 6 {
-		return nil, xerr.Customf("错误的日期范围")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.errorDateRange",
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	startAt := util.TimeParseLocalUnix(fmt.Sprintf("%s-01", monthRang[0]))

+ 12 - 4
module/backend/data_warning.go

@@ -8,17 +8,23 @@ import (
 	"strings"
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	"gitee.com/xuyiping_admin/pkg/xerr"
 )
 
 func (s *StoreEntry) TestDataWaring(ctx context.Context, userId int64) error {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
 	dataWarningList := make([]*model.DataWarning, 0)
 	if err := s.DB.Model(new(model.DataWarning)).Where("user_id = ?", userId).Error; err != nil {
 		return xerr.WithStack(err)
 	}
 	for _, v := range dataWarningList {
-		a, params, err := s.BuildQuery(v.Id)
+		a, params, err := s.BuildQuery(userModel, v.Id)
 		if err != nil {
 			return xerr.WithStack(err)
 		}
@@ -107,8 +113,7 @@ func (s *StoreEntry) NeckRingOriginalAsync(ctx context.Context, pastureId int64,
 	return nil
 }
 
-func (s *StoreEntry) BuildQuery(warningId int64) (string, []interface{}, error) {
-
+func (s *StoreEntry) BuildQuery(userModel *model.UserModel, warningId int64) (string, []interface{}, error) {
 	conditionsMap := make(map[int32][]string)
 	params := make([]interface{}, 0)
 	res := make([]*model.DataWarningItems, 0)
@@ -125,7 +130,10 @@ func (s *StoreEntry) BuildQuery(warningId int64) (string, []interface{}, error)
 	}
 
 	if len(conditionsMap) == 0 {
-		return "", nil, xerr.Custom("条件组不能为空")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "dataWarning.conditionGroupNotEmpty",
+		})
+		return "", nil, xerr.Custom(messageId)
 	}
 
 	var sqlConditions []string

+ 1 - 1
module/backend/enum_map.go

@@ -328,7 +328,7 @@ func (s *StoreEntry) BarnTypeMap() map[pasturePb.PenType_Kind]string {
 		pasturePb.PenType_Lactation:        "成母牛舍",
 		pasturePb.PenType_Peripartum:       "围产牛舍",
 		pasturePb.PenType_Dry_Milking:      "干奶牛舍",
-		pasturePb.PenType_Sick_Cow:         "病牛舍",
+		pasturePb.PenType_Sick_Cow:         "病牛舍",
 		pasturePb.PenType_Out:              "淘汰牛舍",
 		pasturePb.PenType_Segregate:        "隔离牛舍",
 		pasturePb.PenType_Bull:             "公牛牛舍",

+ 1 - 1
module/backend/event_base.go

@@ -90,7 +90,7 @@ func (s *StoreEntry) CreateEnter(ctx context.Context, req *pasturePb.EventEnterR
 		return xerr.WithStack(err)
 	}
 
-	if err = s.EnterCheck(ctx, userModel.AppPasture.Id, req); err != nil {
+	if err = s.EnterCheck(userModel, req); err != nil {
 		return xerr.WithStack(err)
 	}
 

+ 41 - 10
module/backend/event_base_more.go

@@ -5,6 +5,8 @@ import (
 	"kpt-pasture/model"
 	"net/http"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 	"gitee.com/xuyiping_admin/pkg/xerr"
 	"gorm.io/gorm"
@@ -17,9 +19,12 @@ func (s *StoreEntry) DeathBatch(ctx context.Context, req *pasturePb.EventDeathBa
 	}
 
 	if len(req.Items) <= 0 {
-		return xerr.Custom("请选择相关牛只")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.selectCow",
+		})
+		return xerr.Custom(messageId)
 	}
-	newEventDeathList, err := s.DeathCheck(ctx, req, userModel)
+	newEventDeathList, err := s.DeathCheck(ctx, userModel, req)
 	if err != nil {
 		return xerr.WithStack(err)
 	}
@@ -133,7 +138,10 @@ func (s *StoreEntry) CowEarNumberUpdate(ctx context.Context, req *pasturePb.Even
 
 	cow, err := s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, int64(req.CowId))
 	if err != nil {
-		return xerr.Custom("未找到该牛只信息")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.noCow",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	cow.EventEarNumberUpdate(req.EarNumber)
@@ -158,7 +166,10 @@ func (s *StoreEntry) CowSaleCreate(ctx context.Context, req *pasturePb.EventCowS
 		return xerr.WithStack(err)
 	}
 	if len(cowList) != len(req.EarNumbers) {
-		return xerr.Custom("数据异常")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.errorData",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if len(cowList) <= 0 {
@@ -169,13 +180,19 @@ func (s *StoreEntry) CowSaleCreate(ctx context.Context, req *pasturePb.EventCowS
 	if err = s.DB.Model(new(model.SaleDealer)).
 		Where("id = ?", req.DealerId).
 		First(dealerInfo).Error; err != nil {
-		return xerr.Custom("经销商数据异常")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "pasture.dealerError",
+		})
+		return xerr.Custom(messageId)
 	}
 	req.DealerName = dealerInfo.Name
 
 	operationUser, err := s.GetSystemUserById(ctx, int64(req.OperationId))
 	if err != nil {
-		return xerr.Custom("获取操作人员信息失败")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.getOperationError",
+		})
+		return xerr.Custom(messageId)
 	}
 	req.OperationName = operationUser.Name
 
@@ -194,7 +211,11 @@ func (s *StoreEntry) CowSaleCreate(ctx context.Context, req *pasturePb.EventCowS
 	neckRingList := make([]*model.NeckRing, 0)
 	for _, cow := range cowList {
 		if cow.GetEventDayAge(int64(req.SaleAt)) < 0 {
-			return xerr.Customf("牛号: %s,销售时间不能早于牛只出生时间", cow.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID:    "validate.wrongCowSaleTime",
+				TemplateData: map[string]interface{}{"earNumber": cow.EarNumber},
+			})
+			return xerr.Customf(messageId)
 		}
 
 		var newEventCowLog *model.EventCowLog
@@ -409,7 +430,10 @@ func (s *StoreEntry) ImmunizationBatch(ctx context.Context, req *pasturePb.Immun
 	}
 
 	if len(req.EarNumbers) <= 0 {
-		return xerr.Custom("请选择相关牛只数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.selectCow",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if len(req.EarNumbers) > 50 {
@@ -426,7 +450,10 @@ func (s *StoreEntry) ImmunizationBatch(ctx context.Context, req *pasturePb.Immun
 	}
 
 	if len(eventImmunizationList) != len(req.EarNumbers) {
-		return xerr.Custom("数据异常")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "validate.dataError",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	drugsInfo := &model.Drugs{}
@@ -450,7 +477,11 @@ func (s *StoreEntry) ImmunizationBatch(ctx context.Context, req *pasturePb.Immun
 			}
 
 			if cowInfo.GetEventDayAge(int64(req.ImmunizationAt)) < 0 {
-				return xerr.Customf("牛号: %s,免疫时间不能早于牛只出生时间", cowInfo.EarNumber)
+				messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+					MessageID:    "validate.immuneTime",
+					TemplateData: map[string]interface{}{"earNumber": cowInfo.EarNumber},
+				})
+				return xerr.Customf(messageId)
 			}
 
 			// 更新数据

+ 39 - 8
module/backend/event_breed.go

@@ -9,6 +9,8 @@ import (
 	"strings"
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
 	"go.uber.org/zap"
 
@@ -79,24 +81,41 @@ func (s *StoreEntry) CalvingCreate(ctx context.Context, req *pasturePb.EventCalv
 	cow, err := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, req.EarNumber)
 	if err != nil {
 		zaplog.Error("CalvingCreate", zap.Any("cow_id", req.CowId), zap.Any("err", err))
-		return xerr.Custom("请选择相关牛只")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.selectCow",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if cow.GetEventDayAge(int64(req.CalvingAt)) < 0 {
-		return xerr.Custom("产犊时间不能早于牛只出生时间")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID:    "validate.birthTime",
+			TemplateData: map[string]interface{}{"earNumber": req.EarNumber},
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if len(req.CalfItemList) != int(req.ChildNumber) {
-		return xerr.Custom("犊牛信息与产子数不相符")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "validate.lactationCount",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if cow.IsPregnant != pasturePb.IsShow_Ok || cow.BreedStatus != pasturePb.BreedStatus_Pregnant {
-		return xerr.Custom("该母牛未配种")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "validate.noPregnancy",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	operationUser, err := s.GetSystemUserById(ctx, int64(req.OperationId))
 	if err != nil {
-		return xerr.Customf("获取操作人员信息失败: %s", err.Error())
+		zaplog.Error("CalvingCreate", zap.Any("req", req), zap.Any("err", err))
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.getOperationError",
+		})
+		return xerr.Customf(messageId)
 	}
 	req.OperationName = operationUser.Name
 
@@ -107,7 +126,10 @@ func (s *StoreEntry) CalvingCreate(ctx context.Context, req *pasturePb.EventCalv
 		Where("lact = ?", cow.Lact).
 		Where("status = ?", pasturePb.IsShow_No).
 		First(newEventCalving).Error; err != nil {
-		return xerr.Custom("该母牛信息不存在")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "validate.noMotherCow",
+		})
+		return xerr.Custom(messageId)
 	}
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		// 更新产犊事件表
@@ -235,7 +257,10 @@ func (s *StoreEntry) SameTimeBatch(ctx context.Context, req *pasturePb.EventSame
 
 	operationUser, err := s.GetSystemUserById(ctx, int64(req.OperationId))
 	if err != nil {
-		return xerr.Customf("异常数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.getOperationError",
+		})
+		return xerr.Customf(messageId)
 	}
 	req.OperationName = operationUser.Name
 
@@ -255,7 +280,13 @@ func (s *StoreEntry) SameTimeBatch(ctx context.Context, req *pasturePb.EventSame
 			return xerr.WithStack(err)
 		}
 		if time.Unix(eventCowSameTime.PlanDay, 0).Local().Format(model.LayoutDate2) != nowTime {
-			return xerr.Customf("该牛只不是今日计划: %s", eventCowSameTime.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.noSameTimePlan",
+				TemplateData: map[string]interface{}{
+					"earNumber": eventCowSameTime.EarNumber,
+				},
+			})
+			return xerr.Customf(messageId)
 		}
 		eventCowSameTimeList = append(eventCowSameTimeList, eventCowSameTime)
 	}

+ 2 - 2
module/backend/event_breed_more.go

@@ -69,7 +69,7 @@ func (s *StoreEntry) PregnantCheckCreateBatch(ctx context.Context, req *pastureP
 		return xerr.WithStack(err)
 	}
 
-	pregnantCheckBatchModelList, err := s.PregnantCheckDataCheck(ctx, userModel.AppPasture.Id, req)
+	pregnantCheckBatchModelList, err := s.PregnantCheckDataCheck(ctx, userModel, req)
 	if err != nil {
 		return xerr.WithStack(err)
 	}
@@ -339,7 +339,7 @@ func (s *StoreEntry) MatingBatch(ctx context.Context, req *pasturePb.EventMating
 		return xerr.WithStack(err)
 	}
 
-	eventMatingCheckModelList, err := s.MatingCreateCheck(ctx, userModel.AppPasture.Id, req)
+	eventMatingCheckModelList, err := s.MatingCreateCheck(ctx, userModel, req)
 	if err != nil {
 		return xerr.WithStack(err)
 	}

+ 292 - 86
module/backend/event_check.go

@@ -7,6 +7,8 @@ import (
 	"kpt-pasture/util"
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	"gorm.io/gorm"
 
 	"go.uber.org/zap"
@@ -43,43 +45,71 @@ type AbortionCheckBatchModel struct {
 	IsLact        pasturePb.IsShow_Kind
 }
 
-func (s *StoreEntry) EnterCheck(ctx context.Context, pastureId int64, req *pasturePb.EventEnterRequest) error {
+func (s *StoreEntry) EnterCheck(userModel *model.UserModel, req *pasturePb.EventEnterRequest) error {
 	var count int64
 	if err := s.DB.Model(new(model.Cow)).
 		Where("ear_number = ?", req.EarNumber).
-		Where("pasture_id = ?", pastureId).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Count(&count).Error; err != nil {
 		return xerr.WithStack(err)
 	}
 	if count > 0 {
-		return xerr.Custom("该牛只已存在")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.Exists",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if req.BirthAt > req.EnterAt {
-		return xerr.Custom("出生时间不能大于入场时间")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "validate.birthTimeEnterTime",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	return nil
 }
 
-func (s *StoreEntry) MatingCreateCheck(ctx context.Context, pastureId int64, req *pasturePb.EventMatingBatch) ([]*model.EventMatingCheckBatchModel, error) {
+func (s *StoreEntry) MatingCreateCheck(ctx context.Context, userModel *model.UserModel, req *pasturePb.EventMatingBatch) ([]*model.EventMatingCheckBatchModel, error) {
 	if len(req.Items) <= 0 {
-		return nil, xerr.Custom("请选择相关牛只")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.selectCow",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	if len(req.Items) > 50 {
-		return nil, xerr.Custom("最多只能选择50只牛只")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "validate.dataLimit",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 	eventMatingCheckBatchModelList := make([]*model.EventMatingCheckBatchModel, 0)
 
 	for _, v := range req.Items {
-		cowInfo, err := s.GetCowInfoByEarNumber(ctx, pastureId, v.EarNumber)
+		cowInfo, err := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, v.EarNumber)
 		if err != nil {
 			return nil, xerr.WithStack(err)
 		}
 
 		if cowInfo.GetEventDayAge(int64(v.MatingAt)) < 0 {
-			return nil, xerr.Customf("牛号:%s,配种时间不能早于牛只出生时间", cowInfo.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.matingTimeBirthTime",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
+		}
+
+		if int64(v.MatingAt) < cowInfo.LastCalvingAt {
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.matingTimeLastCalvingTime",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		operationUser, err := s.GetSystemUserById(ctx, int64(v.OperationId))
@@ -90,54 +120,83 @@ func (s *StoreEntry) MatingCreateCheck(ctx context.Context, pastureId int64, req
 		frozenSemen := &model.FrozenSemen{}
 		if err = s.DB.Where("bull_id = ?", v.FrozenSemenNumber).
 			First(frozenSemen).Error; err != nil {
-			return nil, xerr.Custom("未找到冻精信息")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "goods.frozenSemenNotExist",
+			})
+			return nil, xerr.Custom(messageId)
 		}
 
 		if frozenSemen.Quantity < v.FrozenSemenCount {
-			return nil, xerr.Custom("冻精数量不足")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "goods.frozenSemenNotEnough",
+			})
+			return nil, xerr.Custom(messageId)
 		}
 
 		if cowInfo.Sex != pasturePb.Genders_Female {
-			return nil, xerr.Customf("牛只: %d,不是母牛", cowInfo.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.cowSex",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if int64(v.MatingAt) < cowInfo.LastMatingAt {
-			return nil, xerr.Customf("牛只: %s,最近一次配种时间: %s,不能小于本次配种时间: %d",
-				cowInfo.EarNumber,
-				time.Unix(cowInfo.LastMatingAt, 0).Format(model.LayoutDate2),
-				time.Unix(int64(v.MatingAt), 0).Format(model.LayoutDate2),
-			)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.matingTimeLastMatingTime",
+				TemplateData: map[string]interface{}{
+					"earNumber":      cowInfo.EarNumber,
+					"matingTime":     time.Unix(int64(v.MatingAt), 0).Format(model.LayoutDate2),
+					"lastMatingTime": time.Unix(cowInfo.LastMatingAt, 0).Format(model.LayoutDate2),
+				},
+			})
+
+			return nil, xerr.Customf(messageId)
 		}
 
 		if int64(v.MatingAt) < cowInfo.LastPregnantCheckAt {
-			return nil, xerr.Customf("牛只: %s,最近一次孕检时间: %s,不能小于本次配种时间: %s",
-				cowInfo.EarNumber,
-				time.Unix(cowInfo.LastPregnantCheckAt, 0).Format(model.LayoutDate2),
-				time.Unix(int64(v.MatingAt), 0).Format(model.LayoutDate2),
-			)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.validate.pregnantCheckMatingTime",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if int64(v.MatingAt) < cowInfo.LastAbortionAt {
-			return nil, xerr.Customf("牛只: %s,最近一次流产时间: %d,不能小于本次配种时间: %d",
-				cowInfo.EarNumber,
-				cowInfo.LastAbortionAt,
-				v.MatingAt,
-			)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.matingTimeLastAbortionTime",
+				TemplateData: map[string]interface{}{
+					"earNumber":        cowInfo.EarNumber,
+					"lastAbortionDate": time.Unix(cowInfo.LastAbortionAt, 0).Format(model.LayoutDate2),
+					"matingDate":       time.Unix(int64(v.MatingAt), 0).Format(model.LayoutDate2),
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if int64(v.MatingAt) < cowInfo.BirthAt {
-			return nil, xerr.Customf("牛只: %s,出生时间: %d,不能小于本次配种时间: %d",
-				cowInfo.EarNumber,
-				time.Unix(cowInfo.BirthAt, 0).Format(model.LayoutDate2),
-				time.Unix(int64(v.MatingAt), 0).Format(model.LayoutDate2),
-			)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.matingTimeBirthTime",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if cowInfo.BreedStatus == pasturePb.BreedStatus_Pregnant || cowInfo.BreedStatus == pasturePb.BreedStatus_No_Mating {
-			return nil, xerr.Customf("牛只: %s,当前状态为: %s,不能进行配种",
-				cowInfo.EarNumber,
-				cowInfo.BreedStatus.String(),
-			)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.breedStatusError",
+				TemplateData: map[string]interface{}{
+					"earNumber":   cowInfo.EarNumber,
+					"breedStatus": cowInfo.BreedStatus.String(),
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 		eventMatingCheckBatchModelList = append(eventMatingCheckBatchModelList, &model.EventMatingCheckBatchModel{
 			Cow:              cowInfo,
@@ -153,45 +212,91 @@ func (s *StoreEntry) MatingCreateCheck(ctx context.Context, pastureId int64, req
 	return eventMatingCheckBatchModelList, nil
 }
 
-func (s *StoreEntry) PregnantCheckDataCheck(ctx context.Context, pastureId int64, req *pasturePb.EventPregnantCheckBatch) ([]*PregnantCheckBatchModel, error) {
+func (s *StoreEntry) PregnantCheckDataCheck(ctx context.Context, userModel *model.UserModel, req *pasturePb.EventPregnantCheckBatch) ([]*PregnantCheckBatchModel, error) {
 	if len(req.Items) <= 0 {
-		return nil, xerr.Custom("请选择相关牛只数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.selectCow",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	if len(req.Items) > 50 {
-		return nil, xerr.Custom("一次性最多限制提交50牛数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "validate.dataLimit",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	pregnantCheckBatchModelList := make([]*PregnantCheckBatchModel, 0)
 	cowInfo := &model.Cow{}
 	var err error
 	for _, item := range req.Items {
-		cowInfo, err = s.GetCowInfoByEarNumber(ctx, pastureId, item.EarNumber)
+		cowInfo, err = s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, item.EarNumber)
 		if err != nil {
 			return nil, xerr.WithStack(err)
 		}
 
 		if cowInfo.Sex != pasturePb.Genders_Female {
-			return nil, xerr.Customf("牛只: %d,不是母牛", cowInfo.Id)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.cowSex",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
+		}
+
+		if int64(item.PregnantCheckAt) > cowInfo.LastMatingAt {
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.pregnantCheckMatingTime",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if cowInfo.GetEventDayAge(int64(item.PregnantCheckAt)) < 0 {
-			return nil, xerr.Customf("牛号: %s,孕检时间不能早于牛只出生时间", cowInfo.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.pregnantCheckBirthTime",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		operationUser, err := s.GetSystemUserById(ctx, int64(item.OperationId))
 		if err != nil {
-			zaplog.Error("PregnantCheckDataCheck", zap.Any("id", item.OperationId), zap.Any("error", err.Error()))
-			return nil, xerr.Customf("获取操作人员信息失败")
+			zaplog.Error("PregnantCheckDataCheck",
+				zap.Any("id", item.OperationId),
+				zap.Any("error", err.Error()),
+			)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "auth.getOperationError",
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
-		// 过滤掉没有配种状态的牛只
-		if cowInfo.BreedStatus != pasturePb.BreedStatus_Breeding && cowInfo.BreedStatus != pasturePb.BreedStatus_Pregnant {
-			return nil, xerr.Customf("牛只: %s 未参加配种,不能进行孕检", cowInfo.EarNumber)
+		if cowInfo.LastMatingAt <= 0 {
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.matingDataError",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
-		if cowInfo.LastMatingAt <= 0 {
-			return nil, xerr.Customf("牛只: %s,最近一次配种数据异常", cowInfo.EarNumber)
+		// 过滤掉没有配种状态的牛只
+		if cowInfo.BreedStatus != pasturePb.BreedStatus_Breeding && cowInfo.BreedStatus != pasturePb.BreedStatus_Pregnant {
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.cannotPregnantCheck",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		itemEventPregnantCheck, err := s.FindEventPregnantCheckIsExIstByCowId(ctx, cowInfo)
@@ -200,16 +305,34 @@ func (s *StoreEntry) PregnantCheckDataCheck(ctx context.Context, pastureId int64
 		}
 
 		if itemEventPregnantCheck.Id <= 0 {
-			return nil, xerr.Customf("未发现该牛只: %s 孕检数据", cowInfo.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.notFoundPregnantCheckData",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
-		lastEventMating, err := s.FindLastEventMatingByCowId(ctx, pastureId, cowInfo.Id)
+		lastEventMating, err := s.FindLastEventMatingByCowId(ctx, userModel.AppPasture.Id, cowInfo.Id)
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return nil, xerr.Customf("未发现该牛只: %s 配种数据", cowInfo.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.notFoundMatingData",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if lastEventMating == nil || lastEventMating.Status == pasturePb.IsShow_No {
-			return nil, xerr.Customf("未发现该牛只: %s 配种数据", cowInfo.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.notFoundMatingData",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		pregnantCheckBatchModelList = append(pregnantCheckBatchModelList, &PregnantCheckBatchModel{
@@ -245,23 +368,43 @@ func (s *StoreEntry) EstrusCheckDataCheck(ctx context.Context, userModel *model.
 	for _, item := range req.Items {
 		cowInfo, err := s.GetCowInfoByEarNumber(ctx, pastureId, item.EarNumber)
 		if err != nil {
-			return nil, xerr.Custom("牛只信息不存在")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "cow.cowNotExist",
+				TemplateData: map[string]interface{}{
+					"earNumber": item.EarNumber,
+				},
+			})
+			return nil, xerr.Custom(messageId)
 		}
 
 		if cowInfo.Sex != pasturePb.Genders_Female {
-			return nil, xerr.Custom("该牛只不是母牛")
-		}
-
-		if item.EstrusAt <= 0 {
-			return nil, xerr.Custom("发情时间不能为空")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "cow.cowSex",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Custom(messageId)
 		}
 
 		if int64(item.EstrusAt) <= cowInfo.BirthAt {
-			return nil, xerr.Customf("牛号: %s,发情时间不能小于出生时间", cowInfo.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.estrusDateBirthDate",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if int64(item.EstrusAt) <= cowInfo.LastCalvingAt {
-			return nil, xerr.Custom("发情时间不能小于产犊时间")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.estrusDateLastCalvingDate",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Custom(messageId)
 		}
 
 		estrusAt := time.Unix(int64(item.EstrusAt), 0).Local().Format(model.LayoutDate2)
@@ -270,7 +413,13 @@ func (s *StoreEntry) EstrusCheckDataCheck(ctx context.Context, userModel *model.
 		isExists := s.FindEventEstrusByCowId(pastureId, cowInfo.Id, estrusLocalStartTime, estrusLocalEndTime)
 		// 如果存在,并且当天已经提交过则跳过
 		if isExists {
-			return nil, xerr.Customf("该牛只:%s,今天已经提交过发情数据", item.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.estrusDataAlready",
+				TemplateData: map[string]interface{}{
+					"earNumber": item.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		operationUser, _ := s.GetSystemUserById(ctx, int64(item.OperationId))
@@ -283,7 +432,13 @@ func (s *StoreEntry) EstrusCheckDataCheck(ctx context.Context, userModel *model.
 		if item.IsMating == pasturePb.IsShow_Ok {
 			isExists = s.FindEventMatingByCowId(pastureId, cowInfo.Id)
 			if isExists {
-				return nil, xerr.Customf("配种清单已经有该牛只数据 :%s,今天已经提交过配种数据", item.EarNumber)
+				messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+					MessageID: "validate.matingDataItemAlready",
+					TemplateData: map[string]interface{}{
+						"earNumber": item.EarNumber,
+					},
+				})
+				return nil, xerr.Customf(messageId)
 			}
 			newEventMating := model.NewEventMating(pastureId, cowInfo, time.Now().Local().Unix(), exposeEstrusType)
 			res.EventMatingList = append(res.EventMatingList, newEventMating)
@@ -301,10 +456,16 @@ func (s *StoreEntry) EstrusCheckDataCheck(ctx context.Context, userModel *model.
 
 func (s *StoreEntry) AbortionEventDataCheck(ctx context.Context, userModel *model.UserModel, items []*pasturePb.EventAbortionItem) ([]*AbortionCheckBatchModel, error) {
 	if len(items) <= 0 {
-		return nil, xerr.Custom("请选择相关数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.selectCow",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 	if len(items) > 50 {
-		return nil, xerr.Custom("一次性最多限制提交50牛数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "validate.dataLimit",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 	abortionCheckBatchModelList := make([]*AbortionCheckBatchModel, 0)
 	for _, item := range items {
@@ -314,19 +475,43 @@ func (s *StoreEntry) AbortionEventDataCheck(ctx context.Context, userModel *mode
 		}
 
 		if cow.Sex != pasturePb.Genders_Female {
-			return nil, xerr.Customf("牛只: %s,不是母牛", cow.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "cow.cowSex",
+				TemplateData: map[string]interface{}{
+					"earNumber": cow.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if cow.IsPregnant != pasturePb.IsShow_Ok {
-			return nil, xerr.Customf("牛只: %s,不是怀孕状态", cow.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.CowNotPregnant",
+				TemplateData: map[string]interface{}{
+					"earNumber": cow.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if cow.BreedStatus != pasturePb.BreedStatus_Pregnant {
-			return nil, xerr.Customf("牛只: %s,不是怀孕状态", cow.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.CowNotPregnant",
+				TemplateData: map[string]interface{}{
+					"earNumber": cow.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if cow.GetEventDayAge(int64(item.AbortionAt)) < 0 {
-			return nil, xerr.Customf("牛号: %s,流产时间不能早于牛只出生时间", cow.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.AbortionDateBirthDate",
+				TemplateData: map[string]interface{}{
+					"earNumber": item.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		operationUser, err := s.GetSystemUserById(ctx, int64(item.OperationId))
@@ -357,11 +542,23 @@ func (s *StoreEntry) ForbiddenMatingCheck(ctx context.Context, userModel *model.
 		}
 
 		if cowInfo.Sex != pasturePb.Genders_Female {
-			return nil, xerr.Customf("牛只: %s,不是母牛", cowInfo.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "cow.cowSex",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if v.ForbiddenMatingAt < int32(cowInfo.BirthAt) {
-			return nil, xerr.Customf("牛只: %s,禁止配种时间不能小于出生时间", cowInfo.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.unMatingDate",
+				TemplateData: map[string]interface{}{
+					"earNumber": cowInfo.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		operationUser, err := s.GetSystemUserById(ctx, int64(v.OperationId))
@@ -382,27 +579,33 @@ func (s *StoreEntry) ForbiddenMatingCheck(ctx context.Context, userModel *model.
 	return res, nil
 }
 
-func (s *StoreEntry) DeathCheck(ctx context.Context, req *pasturePb.EventDeathBatch, userModel *model.UserModel) ([]*model.EventDeathModel, error) {
+func (s *StoreEntry) DeathCheck(ctx context.Context, userModel *model.UserModel, req *pasturePb.EventDeathBatch) ([]*model.EventDeathModel, error) {
 	newEventDeathList := make([]*model.EventDeathModel, 0)
 	for _, item := range req.Items {
 		cow, err := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, item.EarNumber)
 		if err != nil {
-			zaplog.Error("DeathBatch", zap.Any("item", item), zap.Any("err", err))
-			return nil, xerr.Customf("获取牛只信息失败: %s", item.EarNumber)
+			return nil, xerr.WithStack(err)
 		}
 
 		if cow.BirthAt <= int64(item.DeathAt) {
-			return nil, xerr.Customf("牛只: %s,死亡时间不能早于出生时间", cow.EarNumber)
-		}
-
-		lastEventLog, err := s.GetEventCowLog(ctx, userModel.AppPasture.Id, cow.Id)
-		if err != nil {
-			zaplog.Error("DeathBatch", zap.Any("item", item), zap.Any("err", err))
-			return nil, xerr.Customf("获取牛只信息失败: %s", item.EarNumber)
-		}
-
-		if int64(item.DeathAt) < lastEventLog.EventAt {
-			return nil, xerr.Customf("牛只: %s,死亡时间不能早于上一次事件时间", cow.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.deathTime",
+				TemplateData: map[string]interface{}{
+					"earNumber": cow.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
+		}
+
+		lastEventLog, _ := s.GetEventCowLog(ctx, userModel.AppPasture.Id, cow.Id)
+		if lastEventLog != nil && int64(item.DeathAt) < lastEventLog.EventAt {
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "validate.deathTimeLastEvent",
+				TemplateData: map[string]interface{}{
+					"earNumber": cow.EarNumber,
+				},
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if name, ok := s.DeadReasonMap()[item.DeathReasonKind]; ok {
@@ -412,7 +615,10 @@ func (s *StoreEntry) DeathCheck(ctx context.Context, req *pasturePb.EventDeathBa
 		operationUser, err := s.GetSystemUserById(ctx, int64(item.OperationId))
 		if err != nil {
 			zaplog.Error("DeathBatch", zap.Any("item", item), zap.Any("err", err))
-			return nil, xerr.Customf("获取操作人员信息失败: %d", item.OperationId)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "auth.getOperationError",
+			})
+			return nil, xerr.Customf(messageId)
 		}
 
 		if name, ok := s.CowDeathDestinationMap()[item.DeathDestinationKind]; ok {

+ 53 - 12
module/backend/event_health.go

@@ -7,6 +7,8 @@ import (
 	"net/http"
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
 	"go.uber.org/zap"
 
@@ -87,16 +89,27 @@ func (s *StoreEntry) CowDiseaseCreate(ctx context.Context, req *pasturePb.EventC
 	// 牛只信息
 	cow, err := s.GetCowInfoByEarNumber(ctx, pastureId, req.EarNumber)
 	if err != nil {
-		return xerr.Customf("牛只信息错误: %d", req.CowId)
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID:    "cow.errorCow",
+			TemplateData: map[string]interface{}{"earNumber": req.EarNumber},
+		})
+		return xerr.Customf(messageId)
 	}
 
 	if cow.GetEventDayAge(int64(req.DiseaseAt)) < 0 {
-		return xerr.Customf("牛号: %s,发病时间不能早于牛只出生时间", cow.EarNumber)
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID:    "cow.wrongCow",
+			TemplateData: map[string]interface{}{"earNumber": req.EarNumber},
+		})
+		return xerr.Customf(messageId)
 	}
 
 	operationUser, err := s.GetSystemUserById(ctx, int64(req.OperationId))
 	if err != nil {
-		return xerr.Customf("请检查操作人信息")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.checkOperation",
+		})
+		return xerr.Customf(messageId)
 	}
 
 	disease, err := s.GetDiseaseById(ctx, pastureId, req.DiseaseId)
@@ -110,11 +123,17 @@ func (s *StoreEntry) CowDiseaseCreate(ctx context.Context, req *pasturePb.EventC
 		Where("disease_id = ?", disease.Id).
 		Where(s.DB.Where("health_status = ?", pasturePb.HealthStatus_Disease).Or("health_status = ?", pasturePb.HealthStatus_Treatment)).
 		Count(&alreadyCount).Error; err != nil {
-		return xerr.Customf("该牛只已存在该疾病")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "health.cowExist",
+		})
+		return xerr.Customf(messageId)
 	}
 
 	if alreadyCount > 0 {
-		return xerr.Customf("该牛只已存在该疾病")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "health.cowExist",
+		})
+		return xerr.Customf(messageId)
 	}
 
 	// 牛只疾病信息
@@ -170,7 +189,10 @@ func (s *StoreEntry) CowDiseaseCreate(ctx context.Context, req *pasturePb.EventC
 		if err = s.DB.Model(new(model.Prescription)).
 			Create(prescription).Error; err != nil {
 			zaplog.Error("CowDiseaseCreate", zap.Any("err", err), zap.Any("prescription", prescription))
-			return xerr.Customf("创建处方错误: %s", err.Error())
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "health.createPrescriptionFail",
+			})
+			return xerr.Customf(messageId)
 		}
 
 		newPrescriptionDrugs := model.NewPrescriptionDrugs(pastureId, prescription.Id, req.PrescriptionDetail)
@@ -273,7 +295,11 @@ func (s *StoreEntry) CowDiseaseDiagnose(ctx context.Context, req *pasturePb.CowD
 
 	cow, err := s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, int64(req.CowId))
 	if err != nil {
-		return xerr.Customf("错误的牛只信息: %d", req.CowId)
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID:    "cow.errorCowById",
+			TemplateData: map[string]interface{}{"cowId": req.CowId},
+		})
+		return xerr.Customf(messageId)
 	}
 
 	eventCowDisease := &model.EventCowDisease{}
@@ -284,11 +310,17 @@ func (s *StoreEntry) CowDiseaseDiagnose(ctx context.Context, req *pasturePb.CowD
 		Where("pasture_id = ?", userModel.AppPasture.Id).
 		First(eventCowDisease).Error; err != nil {
 		zaplog.Error("CowDiseaseDiagnose", zap.Any("req", req), zap.Any("userModel", userModel))
-		return xerr.Custom("异常牛只数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.errorCowData",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if eventCowDisease == nil || eventCowDisease.Id <= 0 {
-		return xerr.Custom("异常牛只数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "health.errorCowData",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if req.DiagnosedResult == pasturePb.IsShow_No {
@@ -360,7 +392,10 @@ func (s *StoreEntry) CowDiseaseTreatment(ctx context.Context, req *pasturePb.Cow
 	// 操作人信息
 	operationUser, err := s.GetSystemUserById(ctx, int64(req.OperationId))
 	if err != nil {
-		return xerr.Customf("操作人数据异常: %d", req.OperationId)
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.checkOperation",
+		})
+		return xerr.Customf(messageId)
 	}
 
 	// 处方信息
@@ -394,11 +429,17 @@ func (s *StoreEntry) CowDiseaseTreatment(ctx context.Context, req *pasturePb.Cow
 
 	if eventCowDisease.HealthStatus != pasturePb.HealthStatus_Disease &&
 		eventCowDisease.HealthStatus != pasturePb.HealthStatus_Treatment {
-		return xerr.Custom("异常牛只数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.errorCowData",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if eventCowDisease.DiagnosedAt < int64(req.TreatmentAt) {
-		return xerr.Custom("治疗时间不能大于确诊时间")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "health.treatmentTimeError",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	// 处方详情

+ 115 - 25
module/backend/goods.go

@@ -7,6 +7,8 @@ import (
 	"net/http"
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	"gorm.io/gorm"
 
 	"gitee.com/xuyiping_admin/pkg/xerr"
@@ -134,16 +136,24 @@ func (s *StoreEntry) NeckRingCreateOrUpdate(ctx context.Context, req *pasturePb.
 	}
 
 	if req.Items == nil || len(req.Items) == 0 {
-		return xerr.Custom("请选择要脖环数据")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "goods.selectNeckRing",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		for _, item := range req.Items {
 			number := ""
-
 			cowInfo, err := s.GetCowInfoByEarNumber(ctx, userModel.AppPasture.Id, item.EarNumber)
 			if err != nil {
-				return xerr.Customf("该牛: %s 不存在", item.EarNumber)
+				messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+					MessageID: "cow.cowNotExist",
+					TemplateData: map[string]interface{}{
+						"earNumber": item.EarNumber,
+					},
+				})
+				return xerr.Customf(messageId)
 			}
 
 			newNeckRingLog := model.NewNeckRingBindLog(userModel.AppPasture.Id, item.Number, cowInfo, userModel.SystemUser, "")
@@ -152,11 +162,25 @@ func (s *StoreEntry) NeckRingCreateOrUpdate(ctx context.Context, req *pasturePb.
 			switch req.Status {
 			case pasturePb.NeckRingOperationStatus_Bind: // 绑定
 				if ok && neckRing.IsBind == pasturePb.NeckRingIsBind_Bind {
-					return xerr.Customf("该脖环: %s已经绑定牛只: %s", item.Number, neckRing.EarNumber)
+					messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+						MessageID: "goods.neckRingAlreadyBind",
+						TemplateData: map[string]interface{}{
+							"neckRingNumber": item.Number,
+							"earNumber":      neckRing.EarNumber,
+						},
+					})
+					return xerr.Customf(messageId)
 				}
 
 				if cowInfo.NeckRingNumber != "" {
-					return xerr.Customf("该牛只: %s,已经绑定:%s", cowInfo.EarNumber, cowInfo.NeckRingNumber)
+					messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+						MessageID: "cow.neckRingNumberBind",
+						TemplateData: map[string]interface{}{
+							"neckRingNumber": cowInfo.NeckRingNumber,
+							"earNumber":      cowInfo.EarNumber,
+						},
+					})
+					return xerr.Customf(messageId)
 				}
 
 				newNeckRing := model.NewNeckRing(userModel.AppPasture.Id, item.Number, cowInfo, userModel.SystemUser)
@@ -169,7 +193,13 @@ func (s *StoreEntry) NeckRingCreateOrUpdate(ctx context.Context, req *pasturePb.
 				// 解绑
 			case pasturePb.NeckRingOperationStatus_UnBind:
 				if ok && neckRing.IsBind != pasturePb.NeckRingIsBind_Bind {
-					return xerr.Customf("该脖环: %s,未绑定牛只", item.Number)
+					messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+						MessageID: "goods.neckRingNotBind",
+						TemplateData: map[string]interface{}{
+							"neckRingNumber": item.Number,
+						},
+					})
+					return xerr.Customf(messageId)
 				}
 				if err = tx.Model(new(model.NeckRing)).
 					Where("id = ?", neckRing.Id).
@@ -186,7 +216,14 @@ func (s *StoreEntry) NeckRingCreateOrUpdate(ctx context.Context, req *pasturePb.
 				// 编辑
 			case pasturePb.NeckRingOperationStatus_Edit:
 				if cowInfo.NeckRingNumber != "" && item.Number != cowInfo.NeckRingNumber {
-					return xerr.Customf("该牛只: %s,已经绑定:%s", cowInfo.EarNumber, cowInfo.NeckRingNumber)
+					messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+						MessageID: "cow.neckRingNumberBind",
+						TemplateData: map[string]interface{}{
+							"neckRingNumber": cowInfo.NeckRingNumber,
+							"earNumber":      cowInfo.EarNumber,
+						},
+					})
+					return xerr.Customf(messageId)
 				}
 
 				if err = tx.Model(new(model.NeckRing)).
@@ -288,20 +325,32 @@ func (s *StoreEntry) OutboundApply(ctx context.Context, req *pasturePb.OutboundA
 	}
 
 	if len(req.Goods) <= 0 {
-		return xerr.Custom("请选择要出库商品")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "goods.selectOutGoods",
+		})
+		return xerr.Custom(messageId)
 	}
 	var outbound *model.Outbound
 	if req.Id > 0 {
 		outbound, err = s.GetOutboundById(ctx, userModel.AppPasture.Id, int64(req.Id))
 		if err != nil || outbound == nil || outbound.Id <= 0 {
-			return xerr.Customf("该出库单不存在")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "goods.outGoodsNotExist",
+			})
+			return xerr.Customf(messageId)
 		}
 		if userModel.SystemUser.Id != int64(outbound.ApplicantId) {
-			return xerr.Custom("非申请人,无权修改该出库单")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "goods.outGoodsNotAllowEdit",
+			})
+			return xerr.Custom(messageId)
 		}
 
 		if outbound.AuditStatus != pasturePb.AuditStatus_Pending {
-			return xerr.Custom("该出库单不能修改")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "goods.outGoodsNotEdit",
+			})
+			return xerr.Custom(messageId)
 		}
 	} else {
 		// 创建出库申请
@@ -312,10 +361,16 @@ func (s *StoreEntry) OutboundApply(ctx context.Context, req *pasturePb.OutboundA
 	case pasturePb.OutType_Drugs:
 		for _, v := range req.Goods {
 			if v.Quantity <= 0 {
-				return xerr.Custom("请填写商品数量")
+				messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+					MessageID: "goods.goodsCount",
+				})
+				return xerr.Custom(messageId)
 			}
 			if v.GoodsId <= 0 {
-				return xerr.Custom("请选择要出库商品")
+				messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+					MessageID: "goods.selectOutGoods",
+				})
+				return xerr.Custom(messageId)
 			}
 
 			newDrugs := &model.Drugs{}
@@ -339,10 +394,16 @@ func (s *StoreEntry) OutboundApply(ctx context.Context, req *pasturePb.OutboundA
 	case pasturePb.OutType_Medical_Equipment:
 		for _, v := range req.Goods {
 			if v.Quantity <= 0 {
-				return xerr.Custom("请填写商品数量")
+				messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+					MessageID: "goods.goodsCount",
+				})
+				return xerr.Custom(messageId)
 			}
 			if v.GoodsId <= 0 {
-				return xerr.Custom("请选择要出库商品")
+				messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+					MessageID: "goods.selectOutGoods",
+				})
+				return xerr.Custom(messageId)
 			}
 
 			newMedicalEquipment := &model.MedicalEquipment{}
@@ -364,10 +425,12 @@ func (s *StoreEntry) OutboundApply(ctx context.Context, req *pasturePb.OutboundA
 			})
 		}
 	default:
-		return xerr.Custom("未知的出库类型")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "goods.unknownOutGoodsType",
+		})
+		return xerr.Custom(messageId)
 	}
 	unitMap := s.UnitMap()
-
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
 		if req.Id > 0 {
 			if err = tx.Model(new(model.Outbound)).
@@ -467,15 +530,24 @@ func (s *StoreEntry) OutboundAudit(ctx context.Context, req *pasturePb.OutboundA
 	}
 
 	if outbound == nil {
-		return xerr.Custom("出库单不存在")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "goods.outGoodsNotExist",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if req.AuditStatus != pasturePb.AuditStatus_Pass && req.AuditStatus != pasturePb.AuditStatus_Reject && req.AuditStatus != pasturePb.AuditStatus_Cancel {
-		return xerr.Custom("审核状态异常")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "goods.outGoodsAuditStatusError",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if outbound.AuditStatus != pasturePb.AuditStatus_Pending {
-		return xerr.Custom("异常出库单")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "goods.outGoodsError",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	outboundDetails, err := s.GetOutboundDetailByOutboundId(ctx, outbound.Id)
@@ -484,7 +556,10 @@ func (s *StoreEntry) OutboundAudit(ctx context.Context, req *pasturePb.OutboundA
 	}
 
 	if len(outboundDetails) <= 0 {
-		return xerr.Custom("出库单商品不存在")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "goods.outGoodsNotExist",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
@@ -593,15 +668,24 @@ func (s *StoreEntry) OutboundDelete(ctx context.Context, id int64) error {
 	}
 
 	if outbound == nil {
-		return xerr.Custom("出库单不存在")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "goods.outGoodsNotExist",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if !(outbound.AuditStatus == pasturePb.AuditStatus_Pending || outbound.AuditStatus == pasturePb.AuditStatus_Cancel) {
-		return xerr.Custom("该出库单无法删除")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "goods.outGoodsNotDelete",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if userModel.SystemUser.Id != int64(outbound.ApplicantId) {
-		return xerr.Custom("非申请人,无权删除出库单")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "goods.outGoodsNotAllowDelete",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	outbound.Delete()
@@ -668,7 +752,13 @@ func (s *StoreEntry) FrozenSemenCreate(ctx context.Context, req *pasturePb.Searc
 			Where("pasture_id = ?", userModel.AppPasture.Id).
 			First(histData).
 			Error; err != nil {
-			return xerr.Customf("该数据不存在:%d", req.Id)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "goods.dataNotExist",
+				TemplateData: map[string]interface{}{
+					"id": req.Id,
+				},
+			})
+			return xerr.Customf(messageId)
 		}
 
 		histData.UpdateData(req)

+ 17 - 3
module/backend/neck_ring_warning.go

@@ -9,6 +9,8 @@ import (
 	"sort"
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	"go.uber.org/zap"
 	"gorm.io/gorm"
 
@@ -198,7 +200,10 @@ func (s *StoreEntry) NeckRingNoEstrusBatch(ctx context.Context, req *pasturePb.N
 		return xerr.WithStack(err)
 	}
 	if len(req.EarNumbers) <= 0 {
-		return xerr.Custom("请选择牛号")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.earNumber",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	nowTime := time.Now().Local()
@@ -233,7 +238,13 @@ func (s *StoreEntry) NeckRingNoEstrusBatch(ctx context.Context, req *pasturePb.N
 			Where("is_show = ?", pasturePb.IsShow_Ok).
 			First(neckRingEstrus).Error; err != nil {
 			zaplog.Error("NeckRingNoEstrusBatch", zap.Any("err", err), zap.Any("neckRingEstrusWarning", v))
-			return xerr.Customf("数据异常: %s", v.EarNumber)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "cow.dataError",
+				TemplateData: map[string]interface{}{
+					"earNumber": v.EarNumber,
+				},
+			})
+			return xerr.Customf(messageId)
 		}
 		neckRingEstrusIds = append(neckRingEstrusIds, neckRingEstrus.Id)
 	}
@@ -278,7 +289,10 @@ func (s *StoreEntry) NeckRingNoDiseaseBatch(ctx context.Context, req *pasturePb.
 		return xerr.WithStack(err)
 	}
 	if len(req.EarNumbers) <= 0 {
-		return xerr.Custom("请选择牛号")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "cow.earNumber",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	nowTime := time.Now().Local()

+ 6 - 1
module/backend/pasture.go

@@ -7,6 +7,8 @@ import (
 	"kpt-pasture/model"
 	"net/http"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	"gitee.com/xuyiping_admin/pkg/xerr"
 	"gorm.io/gorm"
 
@@ -491,7 +493,10 @@ func (s *StoreEntry) DeleteDealer(crx context.Context, id int64) error {
 		Where("id = ? and pasture_id = ?", id, userModel.AppPasture.Id).
 		First(saleDealer).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return xerr.Custom("未找到该经销商信息")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "pasture.dealerNotExist",
+			})
+			return xerr.Custom(messageId)
 		}
 		return xerr.WithStack(err)
 	}

+ 28 - 14
module/backend/sql.go

@@ -7,15 +7,13 @@ import (
 	"kpt-pasture/model"
 	"strings"
 
-	"github.com/nicksnyder/go-i18n/v2/i18n"
-
-	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
-	"go.uber.org/zap"
-
-	operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"
-
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
+	operationPb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/operation"
+	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
 	"gitee.com/xuyiping_admin/pkg/xerr"
+
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+	"go.uber.org/zap"
 	"gorm.io/gorm"
 )
 
@@ -69,6 +67,10 @@ func (s *StoreEntry) GetCurrentSystemUser(ctx context.Context) (*model.SystemUse
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}
+	userLanguage, err := s.GetCurrentUserLanguage(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
 	// 根据用户token获取用户数据
 	systemUser := &model.SystemUser{Name: userName}
 	if err = s.DB.Model(new(model.SystemUser)).
@@ -77,16 +79,28 @@ func (s *StoreEntry) GetCurrentSystemUser(ctx context.Context) (*model.SystemUse
 		zaplog.Error("GetCurrentSystemUser", zap.Any("err", err), zap.Any("userName", userName))
 
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return nil, xerr.Custom("当前登录用户数据不存在")
+			messageId, _ := userLanguage.Localize(&i18n.LocalizeConfig{
+				MessageID: "auth.noUser",
+			})
+			return nil, xerr.Custom(messageId)
 		} else {
-			return nil, xerr.Custom("用户登录信息有误,请退出重新登录")
+			messageId, _ := userLanguage.Localize(&i18n.LocalizeConfig{
+				MessageID: "auth.reLogin",
+			})
+			return nil, xerr.Custom(messageId)
 		}
 	}
 	if systemUser.IsDelete != pasturePb.IsShow_Ok {
-		return nil, xerr.Custom("当前用户数据已经删除")
+		messageId, _ := userLanguage.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.userDelete",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 	if systemUser.IsShow != pasturePb.IsShow_Ok {
-		return nil, xerr.Custom("当前用户已禁用")
+		messageId, _ := userLanguage.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.userDisable",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 	return systemUser, nil
 }
@@ -100,9 +114,9 @@ func (s *StoreEntry) GetSystemUserDepthRole(ctx context.Context, pastureId, user
 		zaplog.Error("GetSystemUserDepthRole", zap.Any("err", err), zap.Any("pastureId", pastureId), zap.Any("userId", userId))
 
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return nil, xerr.Custom("当前用户未绑定角色数据,请重新绑定")
+			return nil, xerr.Custom("当前用户未绑定角色数据,请重新绑定!")
 		} else {
-			return nil, xerr.Custom("用户信息有误")
+			return nil, xerr.Custom("用户信息有误!")
 		}
 	}
 
@@ -236,7 +250,7 @@ func (s *StoreEntry) GetCowInfoByEarNumber(ctx context.Context, pastureId int64,
 		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
 		First(cowInfo).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return nil, xerr.Customf("该牛只数据不存在: %s", earNumber)
+			return nil, xerr.Customf("The data for cow: %s does not exist!", earNumber)
 		} else {
 			return nil, xerr.WithStack(err)
 		}

+ 97 - 24
module/backend/system_service.go

@@ -10,6 +10,8 @@ import (
 	"strings"
 	"time"
 
+	"github.com/nicksnyder/go-i18n/v2/i18n"
+
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
 	"go.uber.org/zap"
 
@@ -28,31 +30,50 @@ const (
 
 // Login 用户登录
 func (s *StoreEntry) Login(ctx context.Context, req *pasturePb.SearchUserRequest) (*pasturePb.SystemUserResponse, error) {
+	language, err := s.GetCurrentUserLanguage(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
 	systemUser := &model.SystemUser{}
-	if err := s.DB.Model(new(model.SystemUser)).
+	if err = s.DB.Model(new(model.SystemUser)).
 		Where("name = ?", req.Name).
 		First(systemUser).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return nil, xerr.Customf("用户不存在: %s", req.Name)
+			messageId, _ := language.Localize(&i18n.LocalizeConfig{
+				MessageID: "auth.noUser",
+			})
+			return nil, xerr.Customf(messageId)
 		} else {
 			return nil, xerr.WithStack(err)
 		}
 	}
 
 	if systemUser.Password != req.Password {
-		return nil, xerr.Customf("密码错误,来自用户:%s", req.Name)
+		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.wrongPassword",
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	if systemUser.IsShow == pasturePb.IsShow_No {
-		return nil, xerr.Customf("该账号已被禁用,请联系管理员")
+		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.userDisable",
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	if systemUser.IsDelete == pasturePb.IsShow_No {
-		return nil, xerr.Customf("该账号已被删除,请联系管理员")
+		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.userDelete",
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	if len(systemUser.PastureIds) <= 0 {
-		return nil, xerr.Custom("当前用户未配置相关牧场数据,请联系管理员!")
+		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.unPasture",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	jwtToken := jwt.NewJWTTokenGen(s.Cfg.AppName, s.Cfg.JwtTokenKeyConfig.PrivateKey)
@@ -61,13 +82,19 @@ func (s *StoreEntry) Login(ctx context.Context, req *pasturePb.SearchUserRequest
 		return nil, xerr.WithStack(err)
 	}
 	if token == "" {
-		return nil, xerr.Custom("获取token错误")
+		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.errorToken",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	expires := time.Now().Local().Add(time.Duration(s.Cfg.JwtExpireTime) * time.Second).Format(util.LayoutTime)
 	farmList, err := s.FindPastureListByIds(ctx, systemUser.GetPastureIds())
 	if err != nil || len(farmList) == 0 {
-		return nil, xerr.Custom("牧场信息错误")
+		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.errorPasture",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	systemUserDepthRole, err := s.GetSystemUserDepthRole(ctx, farmList[0].Id, systemUser.Id)
@@ -198,7 +225,10 @@ func (s *StoreEntry) DeleteSystemUser(ctx context.Context, userId int64) error {
 	systemUser := &model.SystemUser{Id: userId}
 	if err = s.DB.Model(new(model.SystemUser)).First(systemUser).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return xerr.Custom("该用户不存在")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "auth.noUser",
+			})
+			return xerr.Custom(messageId)
 		}
 		return xerr.WithStack(err)
 	}
@@ -252,7 +282,7 @@ func (s *StoreEntry) IsShowSystemUser(ctx context.Context, userId int64) error {
 
 // SystemUserCreateOrUpdate 创建或者更新系统用户
 func (s *StoreEntry) SystemUserCreateOrUpdate(ctx context.Context, req *pasturePb.SearchUserRequest) error {
-	_, err := s.GetUserModel(ctx)
+	userModel, err := s.GetUserModel(ctx)
 	if err != nil {
 		return xerr.WithStack(err)
 	}
@@ -325,7 +355,10 @@ func (s *StoreEntry) SystemUserCreateOrUpdate(ctx context.Context, req *pastureP
 		}
 
 		if count > 0 {
-			return xerr.Customf("系统中该用户名称已经存在: %s_%s", req.Name, req.Mobile)
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "auth.userNameExist",
+			})
+			return xerr.Customf(messageId)
 		}
 
 		newSystemUser := model.NewSystemUser(req, pastureIds, req.PastureDepthList)
@@ -374,7 +407,10 @@ func (s *StoreEntry) GetSystemUserMenu(ctx context.Context) (*pasturePb.SystemUs
 	}
 
 	if len(systemRoleList) <= 0 {
-		return nil, xerr.Custom("该用户角色不存在")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.userRoleNotExist",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	systemRoleMenuList := make([]*model.SystemRoleMenu, 0)
@@ -385,7 +421,10 @@ func (s *StoreEntry) GetSystemUserMenu(ctx context.Context) (*pasturePb.SystemUs
 	}
 
 	if len(systemRoleMenuList) <= 0 {
-		return nil, xerr.Custom("该用户角色没有菜单权限")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.noMenuPermission",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	// 菜单Id
@@ -410,12 +449,19 @@ func (s *StoreEntry) GetSystemUserMenu(ctx context.Context) (*pasturePb.SystemUs
 
 // ResetPasswordSystemUser 重置系统用户密码
 func (s *StoreEntry) ResetPasswordSystemUser(ctx context.Context, req *pasturePb.ResetUserPasswordRequest) error {
+	language, err := s.GetCurrentUserLanguage(ctx)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
 	systemUser := &model.SystemUser{}
-	if err := s.DB.Model(new(model.SystemUser)).
+	if err = s.DB.Model(new(model.SystemUser)).
 		Where("id = ?", req.Id).
 		First(systemUser).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return xerr.Custom("该用户不存在")
+			messageId, _ := language.Localize(&i18n.LocalizeConfig{
+				MessageID: "auth.noUser",
+			})
+			return xerr.Custom(messageId)
 		}
 		return xerr.WithStack(err)
 	}
@@ -438,13 +484,19 @@ func (s *StoreEntry) SystemUserRole(ctx context.Context, userId int64) (*pasture
 		Where("is_delete = ?", pasturePb.IsShow_Ok).
 		First(systemUser).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return nil, xerr.Custom("该用户不存在")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "auth.noUser",
+			})
+			return nil, xerr.Custom(messageId)
 		}
 		return nil, xerr.WithStack(err)
 	}
 
 	if systemUser.IsShow == pasturePb.IsShow_No {
-		return nil, xerr.Custom("该用户已禁用")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.userDisable",
+		})
+		return nil, xerr.Custom(messageId)
 	}
 
 	systemUserDepthRole := &model.SystemUserDepthRole{}
@@ -453,7 +505,10 @@ func (s *StoreEntry) SystemUserRole(ctx context.Context, userId int64) (*pasture
 		Where("pasture_id = ?", userModel.AppPasture.Id).
 		First(systemUserDepthRole).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return nil, xerr.Custom("该用户没有角色")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "auth.userRoleNotExist",
+			})
+			return nil, xerr.Custom(messageId)
 		}
 		return nil, xerr.WithStack(err)
 	}
@@ -477,17 +532,26 @@ func (s *StoreEntry) SystemUserRoleSave(ctx context.Context, req *pasturePb.Syst
 	if err = s.DB.Model(new(model.SystemUser)).
 		First(systemUser).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return xerr.Custom("该用户不存在")
+			messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+				MessageID: "auth.noUser",
+			})
+			return xerr.Custom(messageId)
 		}
 		return xerr.WithStack(err)
 	}
 
 	if systemUser.IsDelete == pasturePb.IsShow_No {
-		return xerr.Custom("该用户已删除")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.userDelete",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	if systemUser.IsShow == pasturePb.IsShow_No {
-		return xerr.Custom("该用户已禁用")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.userDisable",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	systemRoleList := make([]*model.SystemRole, 0)
@@ -500,7 +564,10 @@ func (s *StoreEntry) SystemUserRoleSave(ctx context.Context, req *pasturePb.Syst
 	}
 
 	if len(systemRoleList) <= 0 {
-		return xerr.Custom("该用户没有角色")
+		messageId, _ := userModel.LanguageContent.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.userRoleNotExist",
+		})
+		return xerr.Custom(messageId)
 	}
 
 	roleIdsStr := ""
@@ -513,7 +580,6 @@ func (s *StoreEntry) SystemUserRoleSave(ctx context.Context, req *pasturePb.Syst
 	}
 
 	if err = s.DB.Transaction(func(tx *gorm.DB) error {
-
 		var systemUserDepthRoleCount int64
 		if err = tx.Model(new(model.SystemUserDepthRole)).
 			Where("user_id = ?", systemUser.Id).
@@ -548,7 +614,14 @@ func (s *StoreEntry) SystemUserRoleSave(ctx context.Context, req *pasturePb.Syst
 
 func (s *StoreEntry) GetMenusWithParents(ctx context.Context, pastureId int64, menuIds []int64) ([]*model.SystemMenu, error) {
 	if len(menuIds) <= 0 {
-		return nil, xerr.Customf("菜单id不能为空")
+		language, err := s.GetCurrentUserLanguage(ctx)
+		if err != nil {
+			return nil, xerr.Customf("菜单id不能为空")
+		}
+		messageId, _ := language.Localize(&i18n.LocalizeConfig{
+			MessageID: "auth.menuIdNotEmpty",
+		})
+		return nil, xerr.Customf(messageId)
 	}
 
 	menuIds = util.DeduplicateInt64(menuIds)

+ 6 - 31
util/util_test.go

@@ -1,9 +1,7 @@
 package util
 
 import (
-	"encoding/json"
 	"fmt"
-	"sort"
 	"strconv"
 	"strings"
 	"testing"
@@ -537,33 +535,10 @@ type WeeklyActiveModel struct {
 }
 
 func Test_demo(t *testing.T) {
-	nowTime := time.Now()
-	lastActiveTime := DateTimeParseLocalUnix2("2025-07-17 07:00:00")
-	sub := nowTime.Sub(lastActiveTime).Hours()
-
-	fmt.Println("sub:", sub)
-
-	weeklyActiveModelList := make([]*WeeklyActiveModel, 0)
-	weeklyActiveModelList = append(weeklyActiveModelList, &WeeklyActiveModel{
-		CowId:    1,
-		HeatDate: "2025-07-17 07:00:00",
-		Nb:       1,
-		High:     1,
-	}, &WeeklyActiveModel{
-		CowId:    2,
-		HeatDate: "2025-07-17 05:00:00",
-		Nb:       2,
-		High:     2,
-	}, &WeeklyActiveModel{
-		CowId:    3,
-		HeatDate: "2025-07-17 09:00:00",
-		Nb:       3,
-		High:     3,
-	})
-	sort.Slice(weeklyActiveModelList, func(i, j int) bool {
-		return weeklyActiveModelList[i].HeatDate < weeklyActiveModelList[j].HeatDate
-	})
-	b, _ := json.Marshal(weeklyActiveModelList)
-	fmt.Println(string(b))
-
+	nowTime := time.Now().Local()
+	currentMonth := nowTime.Format(LayoutMonth)
+	startTime := time.Date(nowTime.Year(), nowTime.Month(), 1, 0, 0, 0, 0, nowTime.Location())
+	startMonth := startTime.AddDate(0, -5, 0).Format(LayoutMonth)
+	monthRang, _ := GetMonthsBetween(startMonth, currentMonth)
+	fmt.Println("currentMonth:", currentMonth, "startMonth:", startMonth, "monthRang", monthRang)
 }