From f1208474f771a1c233d7425c8ed13fbaa0d521ac Mon Sep 17 00:00:00 2001
From: baoshiwei <baoshiwei@shlanbao.cn>
Date: 星期三, 12 三月 2025 09:35:13 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/5.X' into 5.X

---
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java |  183 +++++++++++++++++++++++++++++++++++++++------
 1 files changed, 157 insertions(+), 26 deletions(-)

diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
index 47527da..0a2e485 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
@@ -1,5 +1,8 @@
 package org.dromara.system.service.impl;
 
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
@@ -8,8 +11,13 @@
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import org.dromara.common.core.constant.UserConstants;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.constant.SystemConstants;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.RoleService;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -27,7 +35,7 @@
 import org.dromara.system.mapper.SysRoleMenuMapper;
 import org.dromara.system.mapper.SysUserRoleMapper;
 import org.dromara.system.service.ISysRoleService;
-import lombok.RequiredArgsConstructor;
+import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -40,7 +48,7 @@
  */
 @RequiredArgsConstructor
 @Service
-public class SysRoleServiceImpl implements ISysRoleService {
+public class SysRoleServiceImpl implements ISysRoleService, RoleService {
 
     private final SysRoleMapper baseMapper;
     private final SysRoleMenuMapper roleMenuMapper;
@@ -67,14 +75,14 @@
     private Wrapper<SysRole> buildQueryWrapper(SysRoleBo bo) {
         Map<String, Object> params = bo.getParams();
         QueryWrapper<SysRole> wrapper = Wrappers.query();
-        wrapper.eq("r.del_flag", UserConstants.ROLE_NORMAL)
+        wrapper.eq("r.del_flag", SystemConstants.NORMAL)
             .eq(ObjectUtil.isNotNull(bo.getRoleId()), "r.role_id", bo.getRoleId())
             .like(StringUtils.isNotBlank(bo.getRoleName()), "r.role_name", bo.getRoleName())
             .eq(StringUtils.isNotBlank(bo.getStatus()), "r.status", bo.getStatus())
             .like(StringUtils.isNotBlank(bo.getRoleKey()), "r.role_key", bo.getRoleKey())
             .between(params.get("beginTime") != null && params.get("endTime") != null,
                 "r.create_time", params.get("beginTime"), params.get("endTime"))
-            .orderByAsc("r.role_sort").orderByAsc("r.create_time");;
+            .orderByAsc("r.role_sort").orderByAsc("r.create_time");
         return wrapper;
     }
 
@@ -86,14 +94,24 @@
      */
     @Override
     public List<SysRoleVo> selectRolesByUserId(Long userId) {
-        List<SysRoleVo> userRoles = baseMapper.selectRolePermissionByUserId(userId);
+        return baseMapper.selectRolesByUserId(userId);
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊鍒楄〃(鍖呭惈琚巿鏉冪姸鎬�)
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 瑙掕壊鍒楄〃
+     */
+    @Override
+    public List<SysRoleVo> selectRolesAuthByUserId(Long userId) {
+        List<SysRoleVo> userRoles = baseMapper.selectRolesByUserId(userId);
         List<SysRoleVo> roles = selectRoleAll();
+        // 浣跨敤HashSet鎻愰珮鏌ユ壘鏁堢巼
+        Set<Long> userRoleIds = StreamUtils.toSet(userRoles, SysRoleVo::getRoleId);
         for (SysRoleVo role : roles) {
-            for (SysRoleVo userRole : userRoles) {
-                if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) {
-                    role.setFlag(true);
-                    break;
-                }
+            if (userRoleIds.contains(role.getRoleId())) {
+                role.setFlag(true);
             }
         }
         return roles;
@@ -107,7 +125,7 @@
      */
     @Override
     public Set<String> selectRolePermissionByUserId(Long userId) {
-        List<SysRoleVo> perms = baseMapper.selectRolePermissionByUserId(userId);
+        List<SysRoleVo> perms = baseMapper.selectRolesByUserId(userId);
         Set<String> permsSet = new HashSet<>();
         for (SysRoleVo perm : perms) {
             if (ObjectUtil.isNotNull(perm)) {
@@ -135,7 +153,8 @@
      */
     @Override
     public List<Long> selectRoleListByUserId(Long userId) {
-        return baseMapper.selectRoleListByUserId(userId);
+        List<SysRoleVo> list = baseMapper.selectRolesByUserId(userId);
+        return StreamUtils.toList(list, SysRoleVo::getRoleId);
     }
 
     /**
@@ -147,6 +166,19 @@
     @Override
     public SysRoleVo selectRoleById(Long roleId) {
         return baseMapper.selectRoleById(roleId);
+    }
+
+    /**
+     * 閫氳繃瑙掕壊ID涓叉煡璇㈣鑹�
+     *
+     * @param roleIds 瑙掕壊ID涓�
+     * @return 瑙掕壊鍒楄〃淇℃伅
+     */
+    @Override
+    public List<SysRoleVo> selectRoleByIds(List<Long> roleIds) {
+        return baseMapper.selectRoleList(new QueryWrapper<SysRole>()
+            .eq("r.status", SystemConstants.NORMAL)
+            .in(CollUtil.isNotEmpty(roleIds), "r.role_id", roleIds));
     }
 
     /**
@@ -180,12 +212,30 @@
     /**
      * 鏍¢獙瑙掕壊鏄惁鍏佽鎿嶄綔
      *
-     * @param roleId 瑙掕壊ID
+     * @param role 瑙掕壊淇℃伅
      */
     @Override
-    public void checkRoleAllowed(Long roleId) {
-        if (ObjectUtil.isNotNull(roleId) && LoginHelper.isSuperAdmin(roleId)) {
+    public void checkRoleAllowed(SysRoleBo role) {
+        if (ObjectUtil.isNotNull(role.getRoleId()) && LoginHelper.isSuperAdmin(role.getRoleId())) {
             throw new ServiceException("涓嶅厑璁告搷浣滆秴绾х鐞嗗憳瑙掕壊");
+        }
+        String[] keys = new String[]{TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.TENANT_ADMIN_ROLE_KEY};
+        // 鏂板涓嶅厑璁镐娇鐢� 绠$悊鍛樻爣璇嗙
+        if (ObjectUtil.isNull(role.getRoleId())
+            && StringUtils.equalsAny(role.getRoleKey(), keys)) {
+            throw new ServiceException("涓嶅厑璁镐娇鐢ㄧ郴缁熷唴缃鐞嗗憳瑙掕壊鏍囪瘑绗�!");
+        }
+        // 淇敼涓嶅厑璁镐慨鏀� 绠$悊鍛樻爣璇嗙
+        if (ObjectUtil.isNotNull(role.getRoleId())) {
+            SysRole sysRole = baseMapper.selectById(role.getRoleId());
+            // 濡傛灉鏍囪瘑绗︿笉鐩哥瓑 鍒ゆ柇涓轰慨鏀逛簡绠$悊鍛樻爣璇嗙
+            if (!StringUtils.equals(sysRole.getRoleKey(), role.getRoleKey())) {
+                if (StringUtils.equalsAny(sysRole.getRoleKey(), keys)) {
+                    throw new ServiceException("涓嶅厑璁镐慨鏀圭郴缁熷唴缃鐞嗗憳瑙掕壊鏍囪瘑绗�!");
+                } else if (StringUtils.equalsAny(role.getRoleKey(), keys)) {
+                    throw new ServiceException("涓嶅厑璁镐娇鐢ㄧ郴缁熷唴缃鐞嗗憳瑙掕壊鏍囪瘑绗�!");
+                }
+            }
         }
     }
 
@@ -246,6 +296,10 @@
     @Transactional(rollbackFor = Exception.class)
     public int updateRole(SysRoleBo bo) {
         SysRole role = MapstructUtils.convert(bo, SysRole.class);
+
+        if (SystemConstants.DISABLE.equals(role.getStatus()) && this.countUserRoleByRoleId(role.getRoleId()) > 0) {
+            throw new ServiceException("瑙掕壊宸插垎閰嶏紝涓嶈兘绂佺敤!");
+        }
         // 淇敼瑙掕壊淇℃伅
         baseMapper.updateById(role);
         // 鍒犻櫎瑙掕壊涓庤彍鍗曞叧鑱�
@@ -262,6 +316,9 @@
      */
     @Override
     public int updateRoleStatus(Long roleId, String status) {
+        if (SystemConstants.DISABLE.equals(status) && this.countUserRoleByRoleId(roleId) > 0) {
+            throw new ServiceException("瑙掕壊宸插垎閰嶏紝涓嶈兘绂佺敤!");
+        }
         return baseMapper.update(null,
             new LambdaUpdateWrapper<SysRole>()
                 .set(SysRole::getStatus, status)
@@ -274,6 +331,7 @@
      * @param bo 瑙掕壊淇℃伅
      * @return 缁撴灉
      */
+    @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#bo.roleId")
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int authDataScope(SysRoleBo bo) {
@@ -294,7 +352,7 @@
     private int insertRoleMenu(SysRoleBo role) {
         int rows = 1;
         // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
-        List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();
+        List<SysRoleMenu> list = new ArrayList<>();
         for (Long menuId : role.getMenuIds()) {
             SysRoleMenu rm = new SysRoleMenu();
             rm.setRoleId(role.getRoleId());
@@ -315,7 +373,7 @@
     private int insertRoleDept(SysRoleBo role) {
         int rows = 1;
         // 鏂板瑙掕壊涓庨儴闂紙鏁版嵁鏉冮檺锛夌鐞�
-        List<SysRoleDept> list = new ArrayList<SysRoleDept>();
+        List<SysRoleDept> list = new ArrayList<>();
         for (Long deptId : role.getDeptIds()) {
             SysRoleDept rd = new SysRoleDept();
             rd.setRoleId(role.getRoleId());
@@ -334,6 +392,7 @@
      * @param roleId 瑙掕壊ID
      * @return 缁撴灉
      */
+    @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId")
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int deleteRoleById(Long roleId) {
@@ -350,15 +409,16 @@
      * @param roleIds 闇�瑕佸垹闄ょ殑瑙掕壊ID
      * @return 缁撴灉
      */
+    @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, allEntries = true)
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int deleteRoleByIds(Long[] roleIds) {
         for (Long roleId : roleIds) {
-            checkRoleAllowed(roleId);
-            checkRoleDataScope(roleId);
             SysRole role = baseMapper.selectById(roleId);
+            checkRoleAllowed(BeanUtil.toBean(role, SysRoleBo.class));
+            checkRoleDataScope(roleId);
             if (countUserRoleByRoleId(roleId) > 0) {
-                throw new ServiceException(String.format("%1$s宸插垎閰�,涓嶈兘鍒犻櫎", role.getRoleName()));
+                throw new ServiceException(String.format("%1$s宸插垎閰嶏紝涓嶈兘鍒犻櫎!", role.getRoleName()));
             }
         }
         List<Long> ids = Arrays.asList(roleIds);
@@ -366,7 +426,7 @@
         roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, ids));
         // 鍒犻櫎瑙掕壊涓庨儴闂ㄥ叧鑱�
         roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().in(SysRoleDept::getRoleId, ids));
-        return baseMapper.deleteBatchIds(ids);
+        return baseMapper.deleteByIds(ids);
     }
 
     /**
@@ -377,9 +437,13 @@
      */
     @Override
     public int deleteAuthUser(SysUserRole userRole) {
-        return userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
+        int rows = userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
             .eq(SysUserRole::getRoleId, userRole.getRoleId())
             .eq(SysUserRole::getUserId, userRole.getUserId()));
+        if (rows > 0) {
+            cleanOnlineUser(List.of(userRole.getUserId()));
+        }
+        return rows;
     }
 
     /**
@@ -391,9 +455,14 @@
      */
     @Override
     public int deleteAuthUsers(Long roleId, Long[] userIds) {
-        return userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
+        List<Long> ids = List.of(userIds);
+        int rows = userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
             .eq(SysUserRole::getRoleId, roleId)
-            .in(SysUserRole::getUserId, Arrays.asList(userIds)));
+            .in(SysUserRole::getUserId, ids));
+        if (rows > 0) {
+            cleanOnlineUser(ids);
+        }
+        return rows;
     }
 
     /**
@@ -407,7 +476,8 @@
     public int insertAuthUsers(Long roleId, Long[] userIds) {
         // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
         int rows = 1;
-        List<SysUserRole> list = StreamUtils.toList(List.of(userIds), userId -> {
+        List<Long> ids = List.of(userIds);
+        List<SysUserRole> list = StreamUtils.toList(ids, userId -> {
             SysUserRole ur = new SysUserRole();
             ur.setUserId(userId);
             ur.setRoleId(roleId);
@@ -416,6 +486,67 @@
         if (CollUtil.isNotEmpty(list)) {
             rows = userRoleMapper.insertBatch(list) ? list.size() : 0;
         }
+        if (rows > 0) {
+            cleanOnlineUser(ids);
+        }
         return rows;
     }
+
+    @Override
+    public void cleanOnlineUserByRole(Long roleId) {
+        // 濡傛灉瑙掕壊鏈粦瀹氱敤鎴� 鐩存帴杩斿洖
+        Long num = userRoleMapper.selectCount(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, roleId));
+        if (num == 0) {
+            return;
+        }
+        List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
+        if (CollUtil.isEmpty(keys)) {
+            return;
+        }
+        // 瑙掕壊鍏宠仈鐨勫湪绾跨敤鎴烽噺杩囧ぇ浼氬鑷磖edis闃诲鍗¢】 璋ㄦ厧鎿嶄綔
+        keys.parallelStream().forEach(key -> {
+            String token = StringUtils.substringAfterLast(key, ":");
+            // 濡傛灉宸茬粡杩囨湡鍒欒烦杩�
+            if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) {
+                return;
+            }
+            LoginUser loginUser = LoginHelper.getLoginUser(token);
+            if (ObjectUtil.isNull(loginUser) || CollUtil.isEmpty(loginUser.getRoles())) {
+                return;
+            }
+            if (loginUser.getRoles().stream().anyMatch(r -> r.getRoleId().equals(roleId))) {
+                try {
+                    StpUtil.logoutByTokenValue(token);
+                } catch (NotLoginException ignored) {
+                }
+            }
+        });
+    }
+
+    @Override
+    public void cleanOnlineUser(List<Long> userIds) {
+        List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
+        if (CollUtil.isEmpty(keys)) {
+            return;
+        }
+        // 瑙掕壊鍏宠仈鐨勫湪绾跨敤鎴烽噺杩囧ぇ浼氬鑷磖edis闃诲鍗¢】 璋ㄦ厧鎿嶄綔
+        keys.parallelStream().forEach(key -> {
+            String token = StringUtils.substringAfterLast(key, ":");
+            // 濡傛灉宸茬粡杩囨湡鍒欒烦杩�
+            if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) {
+                return;
+            }
+            LoginUser loginUser = LoginHelper.getLoginUser(token);
+            if (ObjectUtil.isNull(loginUser)) {
+                return;
+            }
+            if (userIds.contains(loginUser.getUserId())) {
+                try {
+                    StpUtil.logoutByTokenValue(token);
+                } catch (NotLoginException ignored) {
+                }
+            }
+        });
+    }
+
 }

--
Gitblit v1.9.3