yanderong
2026-10-02 bca4733e4b0fcd9b6496e608304549a09f982463
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java
@@ -3,8 +3,10 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
@@ -71,6 +73,8 @@
   private static final String SERVICE_PROVIDER_ROLE_KEY = "service_provider";
   private static final String COMPANY_ROLE_NAME = "公司";
   private static final String COMPANY_ROLE_KEY = "company";
   private static final String COMPANY_ADMIN_ROLE_NAME = "公司管理员";
   private static final String COMPANY_ADMIN_ROLE_KEY = "company_admin";
   private static final String OWN_SITE_NAME = "自有电站";
   private static final String SYSTEM_ROLE_REMARK = "系统内置角色";
@@ -101,10 +105,15 @@
      ensureSystemRole(INDEPENDENT_PARTNER_ROLE_NAME, INDEPENDENT_PARTNER_ROLE_KEY, getIndependentPartnerMenuIds());
      ensureSystemRole(SITE_OWNER_ROLE_NAME, SITE_OWNER_ROLE_KEY, new HashSet<>());
      ensureSystemRole(SERVICE_PROVIDER_ROLE_NAME, SERVICE_PROVIDER_ROLE_KEY, new HashSet<>());
      ensureSystemRole(COMPANY_ROLE_NAME, COMPANY_ROLE_KEY, new HashSet<>());
      // 公司管理员角色:默认拥有车队管理、VIN码管理、卡片管理、白名单用户菜单,权限配置不可修改
      ensureSystemRole(COMPANY_ADMIN_ROLE_NAME, COMPANY_ADMIN_ROLE_KEY, getCompanyAdminMenuIds(), true);
   }
   private void ensureSystemRole(String roleName, String roleKey, Set<Long> menuIds) {
      ensureSystemRole(roleName, roleKey, menuIds, false);
   }
   private void ensureSystemRole(String roleName, String roleKey, Set<Long> menuIds, boolean repairMenus) {
      SysRole role = roleService.getOne(new LambdaQueryWrapper<SysRole>()
            .eq(SysRole::getRoleKey, roleKey)
            .eq(SysRole::getDelFlag, 0)
@@ -126,6 +135,9 @@
            role.setUpdateTime(new Date());
            roleService.updateById(role);
         }
         if (repairMenus) {
            repairRoleMenus(role.getRoleId(), menuIds);
         }
         return;
      }
@@ -140,6 +152,32 @@
      newRole.setCreateTime(new Date());
      newRole.setMenuIds(menuIds.toArray(new Long[0]));
      roleService.insertRole(newRole);
   }
   /**
    * 幂等补齐内置角色的菜单绑定(只补不删),保证公司管理员角色的默认菜单随版本补齐
    */
   private void repairRoleMenus(Long roleId, Set<Long> menuIds) {
      if (roleId == null || menuIds == null || menuIds.isEmpty()) {
         return;
      }
      List<Long> boundMenuIds = sysRoleMenuMapper.selectList(new LambdaQueryWrapper<SysRoleMenu>()
                  .eq(SysRoleMenu::getRoleId, roleId))
            .stream()
            .map(SysRoleMenu::getMenuId)
            .collect(Collectors.toList());
      List<SysRoleMenu> toInsert = menuIds.stream()
            .filter(menuId -> !boundMenuIds.contains(menuId))
            .map(menuId -> {
               SysRoleMenu roleMenu = new SysRoleMenu();
               roleMenu.setRoleId(roleId);
               roleMenu.setMenuId(menuId);
               return roleMenu;
            })
            .collect(Collectors.toList());
      if (!toInsert.isEmpty()) {
         sysRoleMenuMapper.batchRoleMenu(toInsert);
      }
   }
   private Set<Long> getIndependentPartnerMenuIds() {
@@ -172,6 +210,43 @@
      }
   }
   /**
    * 公司管理员默认菜单:车队管理、VIN码管理、卡片管理(不含刷卡充电订单/卡片收支明细)、白名单用户及其操作按钮
    */
   private Set<Long> getCompanyAdminMenuIds() {
      List<SysMenus> menus = menuMapper.getAll();
      Set<Long> menuIds = new HashSet<>();
      Map<Long, Long> parentMap = new HashMap<>();
      for (SysMenus menu : menus) {
         parentMap.put(menu.getMenuId(), menu.getParentId());
         String path = normalizeMenuPath(menu.getPath());
         String perms = menu.getPerms() == null ? "" : menu.getPerms();
         // 卡片模块排除收支明细子页(/chargingCardBalanceDetail 同以 /chargingCard 开头)
         if (path.startsWith("fleet") || perms.startsWith("/vinManagement")
               || (perms.startsWith("/chargingCard") && !perms.startsWith("/chargingCardBalanceDetail"))
               || perms.startsWith("/appUserWhitelist")) {
            menuIds.add(menu.getMenuId());
         }
      }
      // 白名单用户菜单挂在「用户管理」父级下,补齐祖先节点保证菜单树可以展示
      Set<Long> ancestorIds = new HashSet<>();
      for (Long menuId : new HashSet<>(menuIds)) {
         Long parentId = parentMap.get(menuId);
         while (parentId != null && parentId != 0L && !menuIds.contains(parentId) && ancestorIds.add(parentId)) {
            parentId = parentMap.get(parentId);
         }
      }
      menuIds.addAll(ancestorIds);
      return menuIds;
   }
   private String normalizeMenuPath(String path) {
      if (path == null) {
         return "";
      }
      return path.startsWith("/") ? path.substring(1) : path;
   }
   private boolean isIndependentPartnerRole(SysRole role) {
      return role != null && (INDEPENDENT_PARTNER_ROLE_KEY.equals(role.getRoleKey())
            || INDEPENDENT_PARTNER_ROLE_NAME.equals(role.getRoleName()));
@@ -190,8 +265,14 @@
            || COMPANY_ROLE_NAME.equals(role.getRoleName()));
   }
   private boolean isCompanyAdminBuiltinRole(SysRole role) {
      return role != null && (COMPANY_ADMIN_ROLE_KEY.equals(role.getRoleKey())
            || COMPANY_ADMIN_ROLE_NAME.equals(role.getRoleName()));
   }
   private boolean isSystemBuiltinRole(SysRole role) {
      return role != null && (role.isAdmin() || isPartnerBuiltinRole(role) || isCompanyBuiltinRole(role));
      return role != null && (role.isAdmin() || isPartnerBuiltinRole(role) || isCompanyBuiltinRole(role)
            || isCompanyAdminBuiltinRole(role));
   }
   private void fillRoleV2Info(SysRole role) {
@@ -350,6 +431,9 @@
      if (oldRole != null && oldRole.isAdmin()) {
         return AjaxResult.error("超级管理员角色不可编辑");
      }
      if (oldRole != null && isCompanyAdminBuiltinRole(oldRole)) {
         return AjaxResult.error("公司管理员角色不可编辑");
      }
      SysRole role = new SysRole();
      role.setRoleName(dto.getRoleName());
      SysRole one = roleService.getOne(new LambdaQueryWrapper<SysRole>().eq(SysRole::getRoleName, dto.getRoleName()));