فهرست منبع

system: user menu

Yi 1 هفته پیش
والد
کامیت
62002e0ddc
6فایلهای تغییر یافته به همراه315 افزوده شده و 121 حذف شده
  1. 11 32
      model/system_user.go
  2. 61 0
      model/system_user_depth_role.go
  3. 15 15
      module/backend/calendar.go
  4. 18 0
      module/backend/sql.go
  5. 195 74
      module/backend/system_service.go
  6. 15 0
      util/util_more.go

+ 11 - 32
model/system_user.go

@@ -34,12 +34,11 @@ func (s *SystemUser) TableName() string {
 	return "system_user"
 }
 
-func (s *SystemUser) UserUpdate(req *pasturePb.SearchUserRequest, deptIds, pastureIds string) {
+func (s *SystemUser) UserUpdate(req *pasturePb.SearchUserRequest, pastureIds string) {
 	s.Name = req.Name
 	s.NickName = req.NickName
 	s.Mobile = req.Mobile
 	s.Gender = req.Gender
-	s.DeptIds = deptIds
 	s.Remarks = req.Remarks
 	s.IsShow = req.IsShow
 	s.PastureIds = pastureIds
@@ -58,8 +57,6 @@ func NewSystemUser(req *pasturePb.SearchUserRequest, deptIds, pastureIds string,
 		Mobile:          req.Mobile,
 		Password:        req.Password,
 		Avatar:          "https://avatars.githubusercontent.com/u/9510375",
-		RoleIds:         "",
-		DeptIds:         deptIds,
 		IndicatorsKinds: fmt.Sprintf("%s,%s,%s,%s,%s,%s", AllCow, OutNumber, InputNumber, SalesVolume, FattenCattleNumber, AdultCow),
 		PastureIds:      pastureIds,
 		IsShow:          pasturePb.IsShow_Ok,
@@ -81,30 +78,6 @@ func (s *SystemUser) GetPastureIds() []int32 {
 	return res
 }
 
-func (s *SystemUser) GetRoleIds() []int32 {
-	res := make([]int32, 0)
-	if s.RoleIds != "" {
-		roleIds := strings.Split(s.RoleIds, ",")
-		for _, idStr := range roleIds {
-			id, _ := strconv.Atoi(idStr)
-			res = append(res, int32(id))
-		}
-	}
-	return res
-}
-
-func (s *SystemUser) GetDepthIds() []int32 {
-	res := make([]int32, 0)
-	if s.DeptIds != "" {
-		depthIds := strings.Split(s.DeptIds, ",")
-		for _, idStr := range depthIds {
-			id, _ := strconv.Atoi(idStr)
-			res = append(res, int32(id))
-		}
-	}
-	return res
-}
-
 type UserModel struct {
 	SystemUser *SystemUser
 	AppPasture *AppPastureList
@@ -112,7 +85,7 @@ type UserModel struct {
 
 type SystemUserSlice []*SystemUser
 
-func (s SystemUserSlice) ToPB(deptList []*SystemDept, roleList []*SystemRole, appPastureList []*AppPastureList) []*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
@@ -130,7 +103,10 @@ func (s SystemUserSlice) ToPB(deptList []*SystemDept, roleList []*SystemRole, ap
 	res := make([]*pasturePb.SearchUserRequest, len(s))
 	for i, v := range s {
 		userDepthName := make([]string, 0)
-		deptIds := v.GetDepthIds()
+		deptIds := make([]int32, 0)
+		if ud, ok := systemUserDepthRoleMap[v.Id]; ok {
+			deptIds = ud.GetDepthIds()
+		}
 		for _, d := range deptIds {
 			if de, ok := deptMap[d]; ok {
 				userDepthName = append(userDepthName, de.Name)
@@ -138,7 +114,10 @@ func (s SystemUserSlice) ToPB(deptList []*SystemDept, roleList []*SystemRole, ap
 		}
 
 		userRoleName := make([]string, 0)
-		roleIds := v.GetRoleIds()
+		roleIds := make([]int32, 0)
+		if rd, ok := systemUserDepthRoleMap[v.Id]; ok {
+			roleIds = rd.GetRoleIds()
+		}
 		for _, r := range roleIds {
 			if ro, ok := roleMap[r]; ok {
 				userRoleName = append(userRoleName, ro.Name)
@@ -171,7 +150,7 @@ func (s SystemUserSlice) ToPB(deptList []*SystemDept, roleList []*SystemRole, ap
 			DepthId:          deptIds,
 			DeptName:         userDepthName,
 			RoleList:         nil,
-			RoleId:           v.GetRoleIds(),
+			RoleId:           roleIds,
 			RoleName:         userRoleName,
 			PastureId:        v.GetPastureIds(),
 			PastureName:      pastureName,

+ 61 - 0
model/system_user_depth_role.go

@@ -0,0 +1,61 @@
+package model
+
+import (
+	"strconv"
+	"strings"
+)
+
+type SystemUserDepthRole struct {
+	Id        int64  `json:"id"`
+	UserId    int64  `json:"userId"`
+	PastureId int64  `json:"pastureId"`
+	DepthIds  string `json:"depthIds"`
+	RoleIds   string `json:"roleIds"`
+	CreatedAt int64  `json:"createdAt"`
+	UpdatedAt int64  `json:"updatedAt"`
+}
+
+func (s *SystemUserDepthRole) TableName() string {
+	return "system_user_depth_role"
+}
+
+func NewSystemUserDepthRole(pastureId, userId int64, depthIds, roleIds string) *SystemUserDepthRole {
+	return &SystemUserDepthRole{
+		UserId:    userId,
+		PastureId: pastureId,
+		DepthIds:  depthIds,
+		RoleIds:   roleIds,
+	}
+}
+
+func NewSystemUserDepthRoleList(userId int64, pastureDepth map[int64]string) []*SystemUserDepthRole {
+	res := make([]*SystemUserDepthRole, 0)
+	for pastureId, depthIds := range pastureDepth {
+		res = append(res, NewSystemUserDepthRole(pastureId, userId, depthIds, ""))
+	}
+	return res
+}
+
+func (s *SystemUserDepthRole) GetRoleIds() []int32 {
+	res := make([]int32, 0)
+	if s.RoleIds != "" {
+		roleIds := strings.Split(s.RoleIds, ",")
+		for _, idStr := range roleIds {
+			id, _ := strconv.Atoi(idStr)
+			res = append(res, int32(id))
+		}
+	}
+	return res
+}
+
+func (s *SystemUserDepthRole) GetDepthIds() []int32 {
+	res := make([]int32, 0)
+	if s.DepthIds != "" {
+		depthIds := strings.Split(s.DepthIds, ",")
+		for _, idStr := range depthIds {
+			id, _ := strconv.Atoi(idStr)
+			res = append(res, int32(id))
+		}
+	}
+	return res
+}

+ 15 - 15
module/backend/calendar.go

@@ -35,40 +35,40 @@ func (s *StoreEntry) CalendarToDoHistoryList(ctx context.Context, pastureId int6
 	if earNumber != "" {
 		whereSql += fmt.Sprintf(` AND ear_number = '%s' `, earNumber)
 	}
-	if penId > 0 {
-		whereSql += fmt.Sprintf(` AND b.pen_id = %d `, penId)
-	}
-
+	whereSql1 := fmt.Sprintf(` %s AND end_day >= %d `, whereSql, util.TimeParseLocalEndUnix(time.Now().Local().Format(model.LayoutDate2)))
 	if isStatus {
-		whereSql += ` AND a.status = 2 `
+		whereSql1 += ` AND status = 2 `
 	}
 
-	whereSql1 := fmt.Sprintf(`%s AND end_day >= %d `, whereSql, util.TimeParseLocalEndUnix(time.Now().Local().Format(model.LayoutDate2)))
 	calendarToDoList := make([]*pasturePb.CalendarToDoList, 0)
-	sql := `SELECT a.cow_id,b.pen_name,a.calendar_type_name,a.calendar_type_kind as calendar_type,DATE_FORMAT(FROM_UNIXTIME(a.plan_day), '%Y-%m-%d') AS plan_day,
-		DATE_FORMAT(FROM_UNIXTIME(a.end_day), '%Y-%m-%d') AS end_day,DATE_FORMAT(FROM_UNIXTIME(a.reality_day), '%Y-%m-%d') AS reality_day,a.remaining_days,b.lact,b.ear_number,a.status as is_finish,a.remarks
+	sql := `SELECT a.cow_id,b.pen_name,a.calendar_type_name,a.calendar_type_kind as calendar_type,
+		DATE_FORMAT(FROM_UNIXTIME(a.plan_day), '%Y-%m-%d') AS plan_day,
+		DATE_FORMAT(FROM_UNIXTIME(a.end_day), '%Y-%m-%d') AS end_day,
+		DATE_FORMAT(FROM_UNIXTIME(a.reality_day), '%Y-%m-%d') AS reality_day,
+		a.remaining_days,b.lact,b.ear_number,a.status as is_finish,a.remarks
 		FROM (
 			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'免疫' as calendar_type_name,1 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
 			FROM event_immunization_plan WHERE ` + whereSql1 + `
-			UNION ALL
+			  UNION ALL
 			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'同期' as calendar_type_name,2 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
 			FROM event_cow_same_time WHERE ` + whereSql1 + `
-			UNION ALL
+			  UNION ALL
 			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'孕检' as calendar_type_name,4 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
 			FROM event_pregnant_check WHERE ` + whereSql1 + `
-			UNION ALL
+			  UNION ALL
 			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'断奶' as calendar_type_name,6 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
 			FROM event_weaning WHERE ` + whereSql1 + `
-			UNION ALL
+			  UNION ALL
 			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'配种' as calendar_type_name,8 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
 			FROM event_mating WHERE ` + whereSql1 + `
-			UNION ALL
+			  UNION ALL
 			SELECT cow_id,plan_day,end_day,reality_day,status,remarks,'产犊' as calendar_type_name,9 as calendar_type_kind,TIMESTAMPDIFF(DAY, NOW(), FROM_UNIXTIME(end_day)) AS remaining_days 
 			FROM event_calving WHERE ` + whereSql1 + `
-			UNION ALL
+			  UNION ALL
 			SELECT cow_id,disease_at as plan_day,curable_at as end_day,curable_at as reality_day,health_status as status,remarks,'疾病' as calendar_type_name,7 as calendar_type_kind,0 AS remaining_days 
 			FROM event_cow_disease WHERE health_status IN (2,3) AND ` + whereSql + `
-		) as a JOIN cow b ON a.cow_id = b.id `
+		) as a 
+	JOIN cow b ON a.cow_id = b.id `
 
 	completeSql := fmt.Sprintf("%s ORDER BY a.plan_day DESC", sql)
 	if err := s.DB.Raw(completeSql).Find(&calendarToDoList).Error; err != nil {

+ 18 - 0
module/backend/sql.go

@@ -76,6 +76,24 @@ func (s *StoreEntry) GetCurrentSystemUser(ctx context.Context) (*model.SystemUse
 	return systemUser, nil
 }
 
+func (s *StoreEntry) GetSystemUserDepthRole(ctx context.Context, pastureId, userId int64) (*model.SystemUserDepthRole, error) {
+	systemUserDepthRole := &model.SystemUserDepthRole{}
+	if err := s.DB.Model(new(model.SystemUserDepthRole)).
+		Where("pasture_id = ?", pastureId).
+		Where("user_id = ?", userId).
+		First(&systemUserDepthRole).Error; err != nil {
+		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("当前用户未绑定角色数据,请重新绑定!")
+		} else {
+			return nil, xerr.Custom("用户信息有误")
+		}
+	}
+
+	return systemUserDepthRole, nil
+}
+
 func (s *StoreEntry) GetCurrentFarmInfo(ctx context.Context) (*model.AppPastureList, error) {
 	farmId := s.GetFarmId(ctx)
 	if farmId == "" {

+ 195 - 74
module/backend/system_service.go

@@ -49,19 +49,6 @@ func (s *StoreEntry) Login(ctx context.Context, req *pasturePb.SearchUserRequest
 		return nil, xerr.Custom("当前用户未配置相关牧场数据,请联系管理员!")
 	}
 
-	systemRoleList := make([]*model.SystemRole, 0)
-	if err := s.DB.Model(new(model.SystemRole)).
-		Where("is_show = ? and is_delete = ?", pasturePb.IsShow_Ok, pasturePb.IsShow_Ok).
-		Where("id IN ?", systemUser.GetRoleIds()).
-		Find(&systemRoleList).Error; err != nil {
-		zaplog.Error("Login", zap.Any("systemRole", err))
-	}
-
-	roleNameList := make([]string, 0)
-	for _, role := range systemRoleList {
-		roleNameList = append(roleNameList, role.Name)
-	}
-
 	jwtToken := jwt.NewJWTTokenGen(s.Cfg.AppName, s.Cfg.JwtTokenKeyConfig.PrivateKey)
 	token, err := jwtToken.GenerateToken(systemUser.Name, s.Cfg.JwtExpireTime)
 	if err != nil {
@@ -77,6 +64,24 @@ func (s *StoreEntry) Login(ctx context.Context, req *pasturePb.SearchUserRequest
 		return nil, xerr.Custom("牧场信息错误")
 	}
 
+	systemUserDepthRole, err := s.GetSystemUserDepthRole(ctx, farmList[0].Id, systemUser.Id)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	systemRoleList := make([]*model.SystemRole, 0)
+	if err = s.DB.Model(new(model.SystemRole)).
+		Where("is_show = ? and is_delete = ?", pasturePb.IsShow_Ok, pasturePb.IsShow_Ok).
+		Where("id IN ?", systemUserDepthRole.GetRoleIds()).
+		Find(&systemRoleList).Error; err != nil {
+		zaplog.Error("Login", zap.Any("systemRole", err))
+	}
+
+	roleNameList := make([]string, 0)
+	for _, role := range systemRoleList {
+		roleNameList = append(roleNameList, role.Name)
+	}
+
 	return &pasturePb.SystemUserResponse{
 		Code: http.StatusOK,
 		Msg:  "ok",
@@ -133,6 +138,24 @@ func (s *StoreEntry) SearchSystemUserList(ctx context.Context, req *pasturePb.Se
 		return nil, xerr.WithStack(err)
 	}
 
+	userIds := make([]int64, 0)
+	for _, v := range systemUserList {
+		userIds = append(userIds, v.Id)
+	}
+
+	systemUserDepthRoleList := make([]*model.SystemUserDepthRole, 0)
+	if err = s.DB.Model(new(model.SystemUserDepthRole)).
+		Where("user_id IN ?", userIds).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		Find(&systemUserDepthRoleList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	systemUserDepthRoleMap := make(map[int64]*model.SystemUserDepthRole)
+	for _, v := range systemUserDepthRoleList {
+		systemUserDepthRoleMap[v.UserId] = v
+	}
+
 	roleList, err := s.SearchSystemRoleListByIds(ctx, userModel.AppPasture.Id, []int64{})
 	if err != nil {
 		return nil, xerr.WithStack(err)
@@ -152,7 +175,7 @@ func (s *StoreEntry) SearchSystemUserList(ctx context.Context, req *pasturePb.Se
 		Code: http.StatusOK,
 		Msg:  "ok",
 		Data: &pasturePb.SearchUserData{
-			List:     model.SystemUserSlice(systemUserList).ToPB(deptList, roleList, appPastureList),
+			List:     model.SystemUserSlice(systemUserList).ToPB(deptList, roleList, appPastureList, systemUserDepthRoleMap),
 			Total:    int32(count),
 			PageSize: pagination.PageSize,
 			Page:     pagination.Page,
@@ -205,7 +228,8 @@ func (s *StoreEntry) SystemUserCreateOrUpdate(ctx context.Context, req *pastureP
 		return xerr.WithStack(err)
 	}
 
-	deptIds, pastureIds := "", ""
+	pastureIds, deptIds := "", ""
+	deptIdsMap := make(map[int64]string)
 	for _, pasture := range req.PastureDepthList {
 		appPasture, err := s.GetAppPastureListByFarmId(ctx, pasture.FarmId)
 		if err != nil {
@@ -223,6 +247,7 @@ func (s *StoreEntry) SystemUserCreateOrUpdate(ctx context.Context, req *pastureP
 
 		if len(deptIds) > 0 {
 			deptIds = strings.TrimSuffix(deptIds, ",")
+			deptIdsMap[appPasture.Id] = deptIds
 		}
 	}
 
@@ -234,14 +259,32 @@ func (s *StoreEntry) SystemUserCreateOrUpdate(ctx context.Context, req *pastureP
 			return xerr.WithStack(err)
 		}
 
-		systemUser.UserUpdate(req, deptIds, pastureIds)
-		if err = s.DB.Model(new(model.SystemUser)).
-			Select("name", "nick_name", "mobile", "gender", "dept_ids", "pasture_ids", "remarks", "is_show").
-			Where("id = ?", systemUser.Id).
-			Updates(systemUser).Error; err != nil {
+		systemUser.UserUpdate(req, pastureIds)
+		if err = s.DB.Transaction(func(tx *gorm.DB) error {
+			if err = tx.Model(new(model.SystemUser)).
+				Select("name", "nick_name", "mobile", "gender", "pasture_ids", "remarks", "is_show").
+				Where("id = ?", systemUser.Id).
+				Updates(systemUser).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+
+			// 删除重新创建新数据
+			if err = tx.Model(new(model.SystemUserDepthRole)).
+				Where("user_id = ?", systemUser.Id).
+				Delete(new(model.SystemUserDepthRole)).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+
+			newSystemUserDepthRoleList := model.NewSystemUserDepthRoleList(systemUser.Id, deptIdsMap)
+			if err = tx.Model(new(model.SystemUserDepthRole)).
+				Create(newSystemUserDepthRoleList).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+
+			return nil
+		}); err != nil {
 			return xerr.WithStack(err)
 		}
-
 	} else {
 		var count int64
 		if err = s.DB.Model(new(model.SystemUser)).
@@ -257,12 +300,24 @@ func (s *StoreEntry) SystemUserCreateOrUpdate(ctx context.Context, req *pastureP
 		}
 
 		newSystemUser := model.NewSystemUser(req, deptIds, pastureIds, req.PastureDepthList)
-		if err = s.DB.Model(new(model.SystemUser)).
-			Create(newSystemUser).Error; err != nil {
+		if err = s.DB.Transaction(func(tx *gorm.DB) error {
+			if err = tx.Model(new(model.SystemUser)).
+				Create(newSystemUser).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+
+			if len(deptIdsMap) > 0 {
+				newSystemUserDepthRoleList := model.NewSystemUserDepthRoleList(newSystemUser.Id, deptIdsMap)
+				if err = tx.Model(new(model.SystemUserDepthRole)).
+					Create(newSystemUserDepthRoleList).Error; err != nil {
+					return xerr.WithStack(err)
+				}
+			}
+			return nil
+		}); err != nil {
 			return xerr.WithStack(err)
 		}
 	}
-
 	return nil
 }
 
@@ -278,13 +333,14 @@ func (s *StoreEntry) GetSystemUserMenu(ctx context.Context) (*pasturePb.SystemUs
 		return nil, xerr.Custom("该用户数据不存在")
 	}
 
-	if len(systemUser.RoleIds) <= 0 {
-		return nil, xerr.Custom("该用户没有角色")
+	systemUserDepthRole, err := s.GetSystemUserDepthRole(ctx, userModel.AppPasture.Id, systemUser.Id)
+	if err != nil {
+		return nil, xerr.WithStack(err)
 	}
 
 	// 获取用户角色数据
 	systemRoleList := make([]*model.SystemRole, 0)
-	if err = s.DB.Where("id IN ?", systemUser.GetRoleIds()).
+	if err = s.DB.Where("id IN ?", systemUserDepthRole.GetRoleIds()).
 		Where("pasture_id = ?", userModel.AppPasture.Id).
 		Where("is_delete = ?", pasturePb.IsShow_Ok).
 		Where("is_show = ?", pasturePb.IsShow_Ok).
@@ -322,10 +378,17 @@ func (s *StoreEntry) GetSystemUserMenu(ctx context.Context) (*pasturePb.SystemUs
 	}
 
 	// 获取用户菜单
-	systemMenuList, err := s.GetMenusWithParents(ctx, menuIds)
+	systemMenuList, err := s.GetMenusWithParents(ctx, userModel.AppPasture.Id, menuIds)
 	if err != nil {
 		return nil, xerr.WithStack(err)
 	}
+
+	zaplog.Info("获取用户菜单权限",
+		zap.Any("user", systemUser),
+		zap.Any("menuIds", menuIds),
+		zap.Any("systemMenuList", systemMenuList),
+		zap.Any("data", model.SystemMenuSlice(systemMenuList).ToTree()),
+	)
 	// 获取菜单权限
 	return &pasturePb.SystemUserMenuTreeResponse{
 		Code: http.StatusOK,
@@ -354,8 +417,14 @@ func (s *StoreEntry) ResetPasswordSystemUser(ctx context.Context, req *pasturePb
 }
 
 func (s *StoreEntry) SystemUserRole(ctx context.Context, userId int64) (*pasturePb.SystemUserRoleResponse, error) {
+	userModel, err := s.GetUserModel(ctx)
+	if err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
 	systemUser := &model.SystemUser{Id: userId}
-	if err := s.DB.Model(new(model.SystemUser)).
+	if err = s.DB.Model(new(model.SystemUser)).
+		Where("is_delete = ?", pasturePb.IsShow_Ok).
 		First(systemUser).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
 			return nil, xerr.Custom("该用户不存在")
@@ -363,15 +432,26 @@ func (s *StoreEntry) SystemUserRole(ctx context.Context, userId int64) (*pasture
 		return nil, xerr.WithStack(err)
 	}
 
-	if systemUser.IsDelete == pasturePb.IsShow_No {
-		return nil, xerr.Custom("该用户已删除")
+	if systemUser.IsShow == pasturePb.IsShow_No {
+		return nil, xerr.Custom("该用户已禁用")
+	}
+
+	systemUserDepthRole := &model.SystemUserDepthRole{}
+	if err = s.DB.Model(new(model.SystemUserDepthRole)).
+		Where("user_id = ?", systemUser.Id).
+		Where("pasture_id = ?", userModel.AppPasture.Id).
+		First(systemUserDepthRole).Error; err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return nil, xerr.Custom("该用户没有角色")
+		}
+		return nil, xerr.WithStack(err)
 	}
 
 	return &pasturePb.SystemUserRoleResponse{
 		Code: http.StatusOK,
 		Msg:  "ok",
 		Data: &pasturePb.UserRoleData{
-			RoleIds: systemUser.GetRoleIds(),
+			RoleIds: systemUserDepthRole.GetRoleIds(),
 		},
 	}, nil
 }
@@ -421,70 +501,111 @@ func (s *StoreEntry) SystemUserRoleSave(ctx context.Context, req *pasturePb.Syst
 		roleIdsStr = strings.TrimRight(roleIdsStr, ",")
 	}
 
-	if err = s.DB.Model(systemUser).
-		Update("role_ids", roleIdsStr).Error; err != nil {
+	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).
+			Where("pasture_id = ?", userModel.AppPasture.Id).
+			Count(&systemUserDepthRoleCount).Error; err != nil {
+			return xerr.WithStack(err)
+		}
+
+		if systemUserDepthRoleCount > 0 {
+			if err = tx.Model(new(model.SystemUserDepthRole)).
+				Where("user_id = ?", systemUser.Id).
+				Where("pasture_id = ?", userModel.AppPasture.Id).
+				Update("role_ids", roleIdsStr).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+		} else {
+
+			newSystemUserDepthRole := model.NewSystemUserDepthRole(userModel.AppPasture.Id, systemUser.Id, "", roleIdsStr)
+			if err = tx.Model(new(model.SystemUserDepthRole)).
+				Create(newSystemUserDepthRole).Error; err != nil {
+				return xerr.WithStack(err)
+			}
+		}
+
+		return nil
+	}); err != nil {
 		return xerr.WithStack(err)
 	}
+
 	return nil
 }
 
-func (s *StoreEntry) GetMenusWithParents(ctx context.Context, menuIds []int64) ([]*model.SystemMenu, error) {
+func (s *StoreEntry) GetMenusWithParents(ctx context.Context, pastureId int64, menuIds []int64) ([]*model.SystemMenu, error) {
 	if len(menuIds) <= 0 {
 		return nil, xerr.Customf("菜单id不能为空")
 	}
-	// 用于存储所有需要查询的菜单ID(包括递归查询的父级ID)
-	allMenuIDs := make(map[int64]struct{})
-	// 用于存储已经处理过的菜单ID,避免重复处理
-	processedIDs := make(map[int64]struct{})
 
-	// 初始化待处理ID队列
-	queue := make([]int64, len(menuIds))
-	copy(queue, menuIds)
+	systemPastureMenuList := make([]*model.SystemPastureMenu, 0)
+	if err := s.DB.Model(new(model.SystemPastureMenu)).
+		Where("pasture_id = ?", pastureId).
+		Find(&systemPastureMenuList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
 
-	for len(queue) > 0 {
-		currentID := queue[0]
-		queue = queue[1:]
+	pastureMenuIds := make([]int64, 0)
+	for _, v := range systemPastureMenuList {
+		pastureMenuIds = append(pastureMenuIds, v.MenuId)
+	}
 
-		// 如果已经处理过,跳过
-		if _, exists := processedIDs[currentID]; exists {
-			continue
-		}
+	systemMenuList := make([]*model.SystemMenu, 0)
+	if err := s.DB.Model(new(model.SystemMenu)).
+		Where("id IN ?", pastureMenuIds).
+		Find(&systemMenuList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
 
-		// 标记为已处理
-		processedIDs[currentID] = struct{}{}
-		allMenuIDs[currentID] = struct{}{}
-
-		// 如果不是顶级菜单,查询其父级ID并加入队列
-		if currentID != 0 { // 0是顶级菜单的parent_id
-			var parentID int64
-			err := s.DB.Model(new(model.SystemMenu)).
-				Where("id = ? AND is_delete = 1", currentID).
-				Pluck("parent_id", &parentID).Error
-			if err != nil {
-				return nil, fmt.Errorf("failed to get parent ID for menu %d: %v", currentID, err)
+	systemMenuMap := make(map[int64]*model.SystemMenu)
+	for _, v := range systemMenuList {
+		systemMenuMap[v.Id] = v
+	}
+
+	userMenuList := make([]*model.SystemMenu, 0)
+	if err := s.DB.Model(new(model.SystemMenu)).
+		Where("id IN ?", menuIds).
+		Find(&userMenuList).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+
+	// 收集所有需要的菜单ID(包括各级父菜单ID)
+	processed := make(map[int64]struct{}) // 防止重复处理
+	for _, menu := range userMenuList {
+		currentID := menu.Id
+
+		// 向上追溯所有父级菜单
+		for currentID != 0 {
+			// 如果已经处理过,跳过
+			if _, exists := processed[currentID]; exists {
+				break
 			}
 
-			if parentID != 0 {
-				queue = append(queue, parentID)
+			// 添加到结果集
+			menuIds = append(menuIds, currentID)
+			processed[currentID] = struct{}{}
+
+			// 获取父菜单
+			parentMenu, ok := systemMenuMap[currentID]
+			if !ok || parentMenu.ParentId == 0 {
+				break
 			}
+			currentID = parentMenu.ParentId
 		}
 	}
 
-	// 将map中的ID转换为slice
-	var ids []int64
-	for id := range allMenuIDs {
-		ids = append(ids, id)
-	}
-
-	// 查询所有需要的菜单
-	systemMenuList := make([]*model.SystemMenu, 0)
+	// 去重
+	menuIds = util.DeduplicateInt64(menuIds)
+	allSystemMenuList := make([]*model.SystemMenu, 0)
 	if err := s.DB.Model(new(model.SystemMenu)).
-		Where("id IN (?) AND is_delete = 1", ids).
+		Where("id IN (?) AND is_delete = ?", menuIds, pasturePb.IsShow_Ok).
 		Order("parent_id ASC,id ASC").
 		Group("id").
-		Find(&systemMenuList).Error; err != nil {
+		Find(&allSystemMenuList).Error; err != nil {
 		return nil, fmt.Errorf("failed to query menus: %v", err)
 	}
 
-	return systemMenuList, nil
+	return allSystemMenuList, nil
 }

+ 15 - 0
util/util_more.go

@@ -153,3 +153,18 @@ func BooleanToIsShow(isShow bool) pasturePb.IsShow_Kind {
 	}
 	return showKind
 }
+
+// DeduplicateInt64 去重
+func DeduplicateInt64(slice []int64) []int64 {
+	seen := make(map[int64]struct{})
+	result := make([]int64, 0, len(slice))
+
+	for _, val := range slice {
+		if _, exists := seen[val]; !exists {
+			seen[val] = struct{}{}
+			result = append(result, val)
+		}
+	}
+
+	return result
+}