package backend import ( "context" "errors" "fmt" "kpt-tmr-group/model" "kpt-tmr-group/pkg/jwt" "kpt-tmr-group/pkg/logger/zaplog" "kpt-tmr-group/pkg/tool" "kpt-tmr-group/pkg/xerr" operationPb "kpt-tmr-group/proto/go/backend/operation" "net/http" "strconv" "strings" "go.uber.org/zap" "gorm.io/gorm" ) // Auth 用户登录 func (s *StoreEntry) Auth(ctx context.Context, auth *operationPb.UserAuthData) (*operationPb.SystemToken, error) { systemUser := &model.SystemUser{} if err := s.DB.Where("name = ?", auth.UserName).Find(systemUser).Error; err != nil { return nil, xerr.WithStack(err) } if systemUser.Password != auth.Password { return nil, xerr.Customf("密码错误,来自用户:%s", auth.UserName) } if systemUser.IsShow == operationPb.IsShow_NO { return nil, xerr.Customf("该账号已被禁用,请联系管理员") } token, err := jwt.GenerateToken(systemUser.Name, systemUser.Password) if err != nil { return nil, xerr.WithStack(err) } if token == "" { return nil, xerr.Custom("获取token错误") } return &operationPb.SystemToken{ Code: http.StatusOK, Msg: "ok", Data: &operationPb.TokenData{Token: token}, }, nil } // GetUserInfo 获取用户信息 func (s *StoreEntry) GetUserInfo(ctx context.Context, token string) (*operationPb.UserAuth, error) { systemUser := &model.SystemUser{} claims, err := jwt.ParseToken(token) if err != nil { return nil, xerr.WithStack(err) } if claims.Username == "" { return nil, xerr.Custom("token解析失败") } if err = s.DB.Where("name = ?", claims.Username).First(systemUser).Error; err != nil { return nil, xerr.WithStack(err) } systemRole := make([]*model.SystemRole, 0) pastureList := make([]*operationPb.UserPasture, 0) roleIdStr := strings.Split(systemUser.RoleIds, ",") if len(roleIdStr) > 0 { roleIds := make([]int, 0) for _, v := range roleIdStr { roleId, _ := strconv.Atoi(v) roleIds = append(roleIds, roleId) } if err = s.DB.Model(new(model.SystemGroupPasturePermissions)).Select("DISTINCT(group_pasture.id) AS did, group_pasture.id as id,group_pasture.name as name"). Where("system_group_pasture_permissions.role_id IN ?", roleIds).Where("system_group_pasture_permissions.is_show = ?", operationPb.IsShow_OK). Joins("right join group_pasture on system_group_pasture_permissions.pasture_id = group_pasture.id").Find(&pastureList).Debug().Error; err != nil { } if err = s.DB.Find(&systemRole, roleIds).Error; err != nil { return nil, xerr.WithStack(err) } } return systemUser.SystemUserFormat(systemRole, pastureList), nil } // CreateSystemUser 创建系统用户 func (s *StoreEntry) CreateSystemUser(ctx context.Context, req *operationPb.AddSystemUser) error { systemUsers := &model.SystemUser{ Name: req.Name, EmployeeName: req.EmployeeName, Phone: req.Phone, Password: tool.Md5String(model.InitManagerPassword), CreateUser: req.CreateUser, IsShow: operationPb.IsShow_OK, IsDelete: operationPb.IsShow_OK, } systemUsers.SystemUserRoleFormat(req) if err := s.DB.Create(systemUsers).Error; err != nil { return xerr.WithStack(err) } return nil } // SearchSystemUserList 查询系统用户 func (s *StoreEntry) SearchSystemUserList(ctx context.Context, req *operationPb.SearchUserRequest) (*operationPb.SearchUserResponse, error) { systemUserList := make([]*model.SystemUser, 0) var count int64 = 0 pref := s.DB.Model(new(model.SystemUser)).Where("is_delete = ?", operationPb.IsShow_OK) if req.Name != "" { pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%")) } if req.EmployeeName != "" { pref.Where("employee_name like ?", fmt.Sprintf("%s%s%s", "%", req.EmployeeName, "%")) } if req.IsShow > 0 { pref.Where("is_show = ?", req.IsShow) } if req.CreatedStartTime > 0 && req.CreatedEndTime > 0 && req.CreatedStartTime <= req.CreatedEndTime { pref.Where("created_at BETWEEN ? AND ?", req.CreatedStartTime, req.CreatedEndTime) } if err := pref.Order("id desc").Count(&count).Limit(int(req.Pagination.PageSize)).Offset(int(req.Pagination.PageOffset)). Find(&systemUserList).Debug().Error; err != nil { return nil, xerr.WithStack(err) } roleList, err := s.SearchSystemRoleListByIds(ctx, []int64{}) if err != nil { return nil, xerr.WithStack(err) } return &operationPb.SearchUserResponse{ Code: http.StatusOK, Msg: "ok", Data: &operationPb.SearchUserData{ Page: req.Pagination.Page, Total: int32(count), PageSize: req.Pagination.PageSize, List: model.SystemUserSlice(systemUserList).ToPB(roleList), }, }, nil } // EditSystemUser 编辑用户 func (s *StoreEntry) EditSystemUser(ctx context.Context, req *operationPb.AddSystemUser) error { systemUser := &model.SystemUser{Id: int64(req.Id)} if err := s.DB.First(systemUser).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return xerr.Custom("该数据不存在!") } return xerr.WithStack(err) } updateData := &model.SystemUser{ Name: req.Name, EmployeeName: req.EmployeeName, Phone: req.Phone, } updateData.SystemUserRoleFormat(req) if err := s.DB.Model(new(model.SystemUser)).Omit("is_show", "password", "is_delete", "create_user"). Where("id = ?", systemUser.Id). Updates(updateData).Error; err != nil { return xerr.WithStack(err) } return nil } // DeleteSystemUser 删除系统用户 func (s *StoreEntry) DeleteSystemUser(ctx context.Context, userId int64) error { systemUser := &model.SystemUser{ Id: userId, } if err := s.DB.First(systemUser).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return xerr.Custom("该用户不存在") } return xerr.WithStack(err) } if err := s.DB.Model(systemUser).Update("is_delete", operationPb.IsShow_NO).Error; err != nil { return xerr.WithStack(err) } return nil } // ResetPasswordSystemUser 重置系统用户密码 func (s *StoreEntry) ResetPasswordSystemUser(ctx context.Context, userId int64) error { systemUser := &model.SystemUser{ Id: userId, } if err := s.DB.First(systemUser).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return xerr.Custom("该用户不存在") } return xerr.WithStack(err) } if err := s.DB.Model(systemUser).Update("password", tool.Md5String(model.InitManagerPassword)).Error; err != nil { return xerr.WithStack(err) } return nil } // DetailsSystemUser 系统用户详情 func (s *StoreEntry) DetailsSystemUser(ctx context.Context, userId int64) (*operationPb.UserDetails, error) { systemUser := &model.SystemUser{ Id: userId, } if err := s.DB.First(systemUser).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, xerr.Custom("该用户不存在") } return nil, xerr.WithStack(err) } return &operationPb.UserDetails{ Code: http.StatusOK, Msg: "ok", Data: systemUser.ToPb(), }, nil } // IsShowSystemUser 用户是否启用 func (s *StoreEntry) IsShowSystemUser(ctx context.Context, req *operationPb.IsShowSystemUserRequest) error { systemUser := &model.SystemUser{ Id: int64(req.UserId), } if err := s.DB.First(systemUser).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return xerr.Custom("该用户不存在") } return xerr.WithStack(err) } if err := s.DB.Model(systemUser).Update("is_show", req.IsShow).Error; err != nil { return xerr.WithStack(err) } return nil } // GetSystemUserPermissions 返回系统用户相关菜单权限 func (s *StoreEntry) GetSystemUserPermissions(ctx context.Context, token string) (*operationPb.SystemUserMenuPermissions, error) { // 解析token claims, err := jwt.ParseToken(token) if err != nil { return nil, xerr.WithStack(err) } if err = claims.Valid(); err != nil { return nil, xerr.WithStack(err) } // 根据用户token获取用户数据 systemUser := &model.SystemUser{Name: claims.Username} if err = s.DB.Where("name = ?", claims.Username).First(systemUser).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, xerr.Custom("该用户数据不存在") } return nil, xerr.WithStack(err) } roleIds := systemUser.SystemUserRoleToSlice() // 获取用户角色数据 systemRoles := make([]*model.SystemRole, 0) if err = s.DB.Where("is_show = ?", operationPb.IsShow_OK).Find(&systemRoles, roleIds).Error; err != nil { return nil, xerr.WithStack(err) } systemAllPermissionsList := &SystemAllPermissionsList{ PastureList: make([]*model.SystemGroupPasturePermissions, 0), MenuList: make([]*model.SystemMenuPermissions, 0), MobileList: make([]*model.SystemMobilePermissions, 0), } for _, role := range systemRoles { item := s.GetSystemAllPermissionsList(ctx, role.Id) systemAllPermissionsList.PastureList = append(systemAllPermissionsList.PastureList, item.PastureList...) systemAllPermissionsList.MenuList = append(systemAllPermissionsList.MenuList, item.MenuList...) systemAllPermissionsList.MobileList = append(systemAllPermissionsList.MobileList, item.MobileList...) } systemAllPermissionsList.SystemUserMenuPermissionsUnDuplicate() groupPastureList, err := s.GetPastureList(ctx, systemAllPermissionsList.PastureList) if err != nil { return nil, xerr.WithStack(err) } menuList, err := s.GetMenuList(ctx, systemAllPermissionsList.MenuList) if err != nil { return nil, xerr.WithStack(err) } mobileList, err := s.GetMobileList(ctx, systemAllPermissionsList.MobileList) if err != nil { return nil, xerr.WithStack(err) } return s.SystemPermissionsFormatPb(groupPastureList, mobileList, menuList), nil } // CreateSystemRole 添加角色 func (s *StoreEntry) CreateSystemRole(ctx context.Context, req *operationPb.AddRoleRequest) error { if err := s.DB.Transaction(func(tx *gorm.DB) error { // 创建角色数据 role := model.NewSystemRole(req) if err := tx.Create(role).Error; err != nil { return xerr.WithStack(err) } // 创建角色菜单权限数据 if len(req.MenuId) > 0 { menuPermissions := model.NewSystemMenuPermissions(role.Id, req.MenuId) if err := tx.Create(menuPermissions).Error; err != nil { return xerr.WithStack(err) } } // 创建角色移动端权限数据 if len(req.MobileId) > 0 { mobilePermissions := model.NewSystemMobilePermissions(role.Id, req.MobileId) if err := tx.Create(mobilePermissions).Error; err != nil { return xerr.WithStack(err) } } // 创建角色牧场端权限数据 if len(req.PastureId) > 0 { pasturePermissions := model.NewSystemGroupPasturePermissions(role.Id, req.PastureId) if err := tx.Create(pasturePermissions).Error; err != nil { return xerr.WithStack(err) } } return nil }); err != nil { return xerr.WithStack(err) } return nil } // EditSystemRole 编辑角色 func (s *StoreEntry) EditSystemRole(ctx context.Context, req *operationPb.AddRoleRequest) error { role := &model.SystemRole{Id: int64(req.Id)} if err := s.DB.First(role).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return xerr.Custom("该数据不存在") } return xerr.WithStack(err) } if err := s.DB.Transaction(func(tx *gorm.DB) error { updateSystemRole := model.NewSystemRole(req) if err := tx.Omit("is_show"). Where("id = ?", role.Id). Updates(updateSystemRole).Error; err != nil { return xerr.WithStack(err) } // 更新牧场权限关系表 pastureIds := req.PastureId if err := tx.Model(new(model.SystemGroupPasturePermissions)). Where("role_id = ?", req.Id).Update("is_show", operationPb.IsShow_NO).Error; err != nil { return xerr.WithStack(err) } newSystemGroupPasturePermissions := model.NewSystemGroupPasturePermissions(int64(req.Id), pastureIds) if err := tx.Create(newSystemGroupPasturePermissions).Error; err != nil { return xerr.WithStack(err) } // 更新菜单权限关系表 menuIds := req.MenuId if err := tx.Model(new(model.SystemMenuPermissions)). Where("role_id = ?", req.Id).Update("is_show", operationPb.IsShow_NO).Error; err != nil { return xerr.WithStack(err) } newSystemMenuPermissions := model.NewSystemMenuPermissions(int64(req.Id), menuIds) if err := tx.Create(newSystemMenuPermissions).Error; err != nil { return xerr.WithStack(err) } // 更新移动端权限关系表 mobileIds := req.MobileId if err := tx.Model(new(model.SystemMobilePermissions)). Where("role_id = ?", req.Id).Update("is_show", operationPb.IsShow_NO).Error; err != nil { return xerr.WithStack(err) } newSystemMobilePermissions := model.NewSystemMobilePermissions(int64(req.Id), mobileIds) if err := tx.Create(newSystemMobilePermissions).Error; err != nil { return xerr.WithStack(err) } return nil }); err != nil { return xerr.WithStack(err) } return nil } // DeleteSystemRole 删除系统角色 func (s *StoreEntry) DeleteSystemRole(ctx context.Context, roleId int64) error { systemRole := &model.SystemRole{ Id: roleId, } if err := s.DB.First(systemRole).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return xerr.Custom("该数据不存在") } return xerr.WithStack(err) } if err := s.DB.Model(systemRole).Update("is_show", operationPb.IsShow_NO).Error; err != nil { return xerr.WithStack(err) } return nil } // SearchSystemRoleList 查询系统角色 func (s *StoreEntry) SearchSystemRoleList(ctx context.Context, req *operationPb.SearchRoleRequest) (*operationPb.SearchRoleResponse, error) { systemRoleList := make([]*model.SystemRole, 0) var count int64 = 0 pref := s.DB.Model(new(model.SystemRole)).Where("is_show = ?", operationPb.IsShow_OK) if req.Name != "" { pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%")) } if err := pref.Order("id desc").Count(&count).Limit(int(req.Pagination.PageSize)). Offset(int(req.Pagination.PageOffset)).Find(&systemRoleList).Error; err != nil { return nil, xerr.WithStack(err) } permissionsPastureMap := make(map[int64][]*model.GroupPasture, 0) permissionsMenuMap := make(map[int64][]*model.SystemMenu, 0) for _, role := range systemRoleList { groupPastureList := make([]*model.GroupPasture, 0) if err := s.DB.Table(new(model.GroupPasture).TableName()).Select(fmt.Sprintf("%s.*", new(model.GroupPasture).TableName())). Joins(fmt.Sprintf("left join %s on %s = %s and %s", new(model.SystemGroupPasturePermissions).TableName(), fmt.Sprintf("%s.pasture_id", new(model.SystemGroupPasturePermissions).TableName()), fmt.Sprintf("%s.id", new(model.GroupPasture).TableName()), fmt.Sprintf("%s.is_show = %d", new(model.SystemGroupPasturePermissions).TableName(), operationPb.IsShow_OK))). Where(fmt.Sprintf("%s.role_id = ?", new(model.SystemGroupPasturePermissions).TableName()), role.Id). Find(&groupPastureList).Error; err != nil { zaplog.Error("SearchSystemRoleList", zap.Any("SystemGroupPasturePermissions", err)) } permissionsPastureMap[role.Id] = groupPastureList systemMenuList := make([]*model.SystemMenu, 0) if err := s.DB.Table(new(model.SystemMenu).TableName()).Select(fmt.Sprintf("%s.*", new(model.SystemMenu).TableName())). Joins(fmt.Sprintf("left join %s on %s = %s and %s", new(model.SystemMenuPermissions).TableName(), fmt.Sprintf("%s.menu_id", new(model.SystemMenuPermissions).TableName()), fmt.Sprintf("%s.id", new(model.SystemMenu).TableName()), fmt.Sprintf("%s.is_show = %d", new(model.SystemMenuPermissions).TableName(), operationPb.IsShow_OK))). Where(fmt.Sprintf("%s.role_id = ?", new(model.SystemMenuPermissions).TableName()), role.Id).Where(fmt.Sprintf("%s.level = ?", new(model.SystemMenu).TableName()), model.Level2). Find(&systemMenuList).Error; err != nil { zaplog.Error("SearchSystemRoleList", zap.Any("SystemMenuPermissions", err)) } permissionsMenuMap[role.Id] = systemMenuList } return &operationPb.SearchRoleResponse{ Code: http.StatusOK, Msg: "ok", Data: &operationPb.SearchRoleData{ Page: req.Pagination.Page, Total: int32(count), PageSize: req.Pagination.PageSize, List: model.SystemRoleSlice(systemRoleList).ToPB(permissionsPastureMap, permissionsMenuMap), }, }, nil } // SearchSystemRoleListByIds 根据id查询角色列表 func (s *StoreEntry) SearchSystemRoleListByIds(ctx context.Context, ids []int64) ([]*model.SystemRole, error) { systemRoleList := make([]*model.SystemRole, 0) if err := s.DB.Model(new(model.SystemRole)).Where("is_show = ?", operationPb.IsShow_OK).Find(&systemRoleList, ids).Error; err != nil { return nil, xerr.WithStack(err) } return systemRoleList, nil } // GetRolePermissions 查询系统角色权限 func (s *StoreEntry) GetRolePermissions(ctx context.Context, roleId int64) (*operationPb.RolePermissionsList, error) { systemRole := &model.SystemRole{ Id: roleId, } if err := s.DB.First(systemRole).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, xerr.Custom("该数据不存在") } return nil, xerr.WithStack(err) } systemAllPermissionsList := &SystemAllPermissionsList{ PastureList: make([]*model.SystemGroupPasturePermissions, 0), MenuList: make([]*model.SystemMenuPermissions, 0), MobileList: make([]*model.SystemMobilePermissions, 0), } item := s.GetSystemAllPermissionsList(ctx, systemRole.Id) systemAllPermissionsList.PastureList = append(systemAllPermissionsList.PastureList, item.PastureList...) systemAllPermissionsList.MenuList = append(systemAllPermissionsList.MenuList, item.MenuList...) systemAllPermissionsList.MobileList = append(systemAllPermissionsList.MobileList, item.MobileList...) return s.AllPermissionsListToRolePermissions(systemAllPermissionsList), nil } // CreateSystemMenu 添加系统菜单权限 func (s *StoreEntry) CreateSystemMenu(ctx context.Context, req *operationPb.AddMenuRequest) error { systemMenu := model.NewSystemMenu(req) if err := s.DB.Create(systemMenu).Error; err != nil { return xerr.WithStack(err) } return nil } // EditSystemMenu 编辑系统菜单权限 func (s *StoreEntry) EditSystemMenu(ctx context.Context, req *operationPb.AddMenuRequest) error { systemMenu := &model.SystemMenu{Id: int64(req.Id)} if err := s.DB.First(systemMenu).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return xerr.Custom("该数据不存在!") } return xerr.WithStack(err) } updateData := &model.SystemMenu{ Name: req.Name, MenuType: req.MenuType, Title: req.Title, Path: req.Path, Component: req.Component, Icon: req.Icon, Sort: req.Sort, Redirect: req.Redirect, ParentId: int64(req.ParentId), } if err := s.DB.Model(new(model.SystemMenu)).Omit("is_show"). Where("id = ?", systemMenu.Id). Updates(updateData).Error; err != nil { return xerr.WithStack(err) } return nil } // IsShowSystemMenu 菜单是否启用 func (s *StoreEntry) IsShowSystemMenu(ctx context.Context, req *operationPb.IsShowSystemMenuRequest) error { systemMenu := &model.SystemMenu{Id: int64(req.MenuId)} if err := s.DB.First(systemMenu).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return xerr.Custom("该数据不存在") } return xerr.WithStack(err) } if err := s.DB.Model(systemMenu).Update("is_show", req.IsShow).Error; err != nil { return xerr.WithStack(err) } return nil } // SearchSystemMenuList 菜单列表查询 func (s *StoreEntry) SearchSystemMenuList(ctx context.Context, req *operationPb.SearchMenuRequest) (*operationPb.SearchMenuResponse, error) { systemMenuLevel1 := make([]*model.SystemMenu, 0) var count int64 = 0 pref := s.DB.Model(new(model.SystemMenu)).Where("is_delete = ? and level = ?", operationPb.IsShow_OK, model.Level1) if req.Name != "" { pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%")) } if err := pref.Order("sort desc").Count(&count).Limit(int(req.Pagination.PageSize)).Offset(int(req.Pagination.PageOffset)). Find(&systemMenuLevel1).Debug().Error; err != nil { return nil, xerr.WithStack(err) } systemMenuLevel1 = append(systemMenuLevel1, s.searchMenuLevel23ByLevel1(ctx, systemMenuLevel1)...) return &operationPb.SearchMenuResponse{ Code: http.StatusOK, Msg: "ok", Data: &operationPb.SearchMenuData{ Page: req.Pagination.Page, Total: int32(count), List: model.SystemMenuSlice(systemMenuLevel1).ToPB(), }, }, nil } // searchMenuLevel23ByLevel1 根据一级菜单返回对应二三级菜单 func (s *StoreEntry) searchMenuLevel23ByLevel1(ctx context.Context, res []*model.SystemMenu) []*model.SystemMenu { systemMenuLevel23 := make([]*model.SystemMenu, 0) if len(res) <= 0 { return systemMenuLevel23 } ids1 := make([]int64, 0) for _, v := range res { ids1 = append(ids1, v.Id) } if err := s.DB.Model(new(model.SystemMenu)).Where("is_delete = ? and level = ?", operationPb.IsShow_OK, model.Level2). Where("parent_id IN ?", ids1).Order("sort desc"). Find(&systemMenuLevel23).Error; err != nil { return systemMenuLevel23 } ids2 := make([]int64, 0) for _, v := range systemMenuLevel23 { ids2 = append(ids2, v.Id) } systemMenuLevel3 := make([]*model.SystemMenu, 0) if err := s.DB.Model(new(model.SystemMenu)).Where("is_delete = ? and level = ?", operationPb.IsShow_OK, model.Level3). Where("parent_id IN ?", ids2).Order("sort desc"). Find(&systemMenuLevel3).Error; err != nil { return systemMenuLevel23 } if len(systemMenuLevel3) > 0 { systemMenuLevel23 = append(systemMenuLevel23, systemMenuLevel3...) } return systemMenuLevel23 } // DeleteSystemMenu 删除系统菜单 func (s *StoreEntry) DeleteSystemMenu(ctx context.Context, menuId int64) error { systemMenu := &model.SystemMenu{Id: menuId} if err := s.DB.First(systemMenu).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return xerr.Custom("该数据不存在") } return xerr.WithStack(err) } if err := s.DB.Model(systemMenu).Update("is_delete", operationPb.IsShow_NO).Error; err != nil { return xerr.WithStack(err) } return nil } // SearchMobileList 查询移动端角色 func (s *StoreEntry) SearchMobileList(ctx context.Context, req *operationPb.SearchMobileRequest) (*operationPb.SearchMobileResponse, error) { systemMobile := make([]*model.SystemMobile, 0) var count int64 = 0 pref := s.DB.Model(new(model.SystemMobile)).Where("is_show = ?", operationPb.IsShow_OK) if req.Name != "" { pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%")) } if err := pref.Order("id desc").Count(&count).Limit(int(req.Pagination.PageSize)).Offset(int(req.Pagination.PageOffset)). Find(&systemMobile).Debug().Error; err != nil { return nil, xerr.WithStack(err) } return &operationPb.SearchMobileResponse{ Code: http.StatusOK, Msg: "ok", Data: &operationPb.SearchMobileData{ Page: req.Pagination.Page, Total: int32(count), PageSize: req.Pagination.PageSize, List: model.SystemMobileSlice(systemMobile).ToPB(), }, }, nil }