|
@@ -0,0 +1,246 @@
|
|
|
|
|
+# /system/menu/treeselect 接口执行流程详解
|
|
|
|
|
+
|
|
|
|
|
+## 完整执行顺序
|
|
|
|
|
+
|
|
|
|
|
+### 1. 控制器层 - SysMenuController.treeselect()
|
|
|
|
|
+**位置**: `SysMenuController.java:84-89`
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+@SaCheckPermission("system:menu:query") // ← 步骤1: 权限校验
|
|
|
|
|
+@GetMapping("/treeselect")
|
|
|
|
|
+public R<List<Tree<Long>>> treeselect(SysMenuBo menu) {
|
|
|
|
|
+ // 步骤2: 查询菜单列表
|
|
|
|
|
+ List<SysMenuVo> menus = menuService.selectMenuList(menu, LoginHelper.getUserId());
|
|
|
|
|
+
|
|
|
|
|
+ // 步骤3: 构建树形结构
|
|
|
|
|
+ return R.ok(menuService.buildMenuTreeSelect(menus));
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**执行步骤**:
|
|
|
|
|
+1. **权限校验**: `@SaCheckPermission("system:menu:query")` - 检查用户是否有 `system:menu:query` 权限
|
|
|
|
|
+2. **获取用户ID**: `LoginHelper.getUserId()` - 从当前登录上下文获取用户ID
|
|
|
|
|
+3. **调用服务层**: `menuService.selectMenuList(menu, userId)`
|
|
|
|
|
+4. **构建树结构**: `menuService.buildMenuTreeSelect(menus)`
|
|
|
|
|
+5. **返回结果**: 包装成 `R<List<Tree<Long>>>` 返回
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 2. 服务层 - SysMenuServiceImpl.selectMenuList()
|
|
|
|
|
+**位置**: `SysMenuServiceImpl.java:73-93`
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+public List<SysMenuVo> selectMenuList(SysMenuBo menu, Long userId) {
|
|
|
|
|
+ List<SysMenuVo> menuList;
|
|
|
|
|
+ LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 步骤A: 权限过滤 ==========
|
|
|
|
|
+ if (!LoginHelper.isSuperAdmin(userId)) {
|
|
|
|
|
+ // 非超管用户,需要通过角色过滤菜单
|
|
|
|
|
+ wrapper.inSql(SysMenu::getMenuId, baseMapper.buildMenuByUserSql(userId));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 步骤B: 平台过滤 ==========
|
|
|
|
|
+ int platformId = menu.getPlatformId()==null? PlatformUtils.getId() : menu.getPlatformId();
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 步骤C: 构建查询条件并执行 ==========
|
|
|
|
|
+ menuList = baseMapper.selectVoList(
|
|
|
|
|
+ wrapper.like(StringUtils.isNotBlank(menu.getMenuName()), SysMenu::getMenuName, menu.getMenuName())
|
|
|
|
|
+ .eq(StringUtils.isNotBlank(menu.getVisible()), SysMenu::getVisible, menu.getVisible())
|
|
|
|
|
+ .eq(StringUtils.isNotBlank(menu.getStatus()), SysMenu::getStatus, menu.getStatus())
|
|
|
|
|
+ .eq(SysMenu::getPlatformId, platformId) // ← 关键:平台过滤
|
|
|
|
|
+ .eq(StringUtils.isNotBlank(menu.getMenuType()), SysMenu::getMenuType, menu.getMenuType())
|
|
|
|
|
+ .eq(ObjectUtil.isNotNull(menu.getParentId()), SysMenu::getParentId, menu.getParentId())
|
|
|
|
|
+ .orderByAsc(SysMenu::getParentId)
|
|
|
|
|
+ .orderByAsc(SysMenu::getOrderNum)
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ return menuList;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**详细执行流程**:
|
|
|
|
|
+
|
|
|
|
|
+#### 步骤A: 权限过滤(非超管用户)
|
|
|
|
|
+```java
|
|
|
|
|
+if (!LoginHelper.isSuperAdmin(userId)) {
|
|
|
|
|
+ wrapper.inSql(SysMenu::getMenuId, baseMapper.buildMenuByUserSql(userId));
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**生成的SQL子查询** (`buildMenuByUserSql`):
|
|
|
|
|
+```sql
|
|
|
|
|
+SELECT menu_id
|
|
|
|
|
+FROM sys_role_menu
|
|
|
|
|
+WHERE role_id IN (
|
|
|
|
|
+ SELECT sur.role_id
|
|
|
|
|
+ FROM sys_user_role sur
|
|
|
|
|
+ LEFT JOIN sys_role sr ON sr.role_id = sur.role_id
|
|
|
|
|
+ WHERE sur.user_id = ?
|
|
|
|
|
+ AND sr.status = '0'
|
|
|
|
|
+)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**作用**: 获取该用户所有角色分配的菜单ID列表
|
|
|
|
|
+
|
|
|
|
|
+#### 步骤B: 平台过滤
|
|
|
|
|
+```java
|
|
|
|
|
+int platformId = PlatformUtils.getId();
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**执行流程**:
|
|
|
|
|
+1. `PlatformUtils.getId()` 调用
|
|
|
|
|
+2. 从请求头获取 `PLATFORM_CODE`
|
|
|
|
|
+3. 根据 `PLATFORM_CODE` 转换为平台ID:
|
|
|
|
|
+ - `"PINGTAIDUAN"` → 0 (平台端)
|
|
|
|
|
+ - `"SHANGHUDUAN"` → 1 (商户端)
|
|
|
|
|
+
|
|
|
|
|
+#### 步骤C: 最终SQL查询
|
|
|
|
|
+
|
|
|
|
|
+**商户端用户的完整SQL**:
|
|
|
|
|
+```sql
|
|
|
|
|
+SELECT *
|
|
|
|
|
+FROM sys_menu
|
|
|
|
|
+WHERE menu_id IN (
|
|
|
|
|
+ -- 用户角色分配的菜单ID列表
|
|
|
|
|
+ SELECT menu_id FROM sys_role_menu WHERE role_id IN (...)
|
|
|
|
|
+)
|
|
|
|
|
+AND platform_id = 1 -- 商户端
|
|
|
|
|
+ORDER BY parent_id, order_num
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**关键点**: 这是一个 **AND 条件**,必须同时满足:
|
|
|
|
|
+- 菜单ID在用户角色分配的列表中
|
|
|
|
|
+- 菜单的 platform_id = 1
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 3. 数据层 - SysMenuMapper
|
|
|
|
|
+**位置**: `SysMenuMapper.java`
|
|
|
|
|
+
|
|
|
|
|
+使用 MyBatis-Plus 的 `LambdaQueryWrapper` 自动生成SQL并执行。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 4. 树结构构建 - buildMenuTreeSelect()
|
|
|
|
|
+**位置**: `SysMenuServiceImpl.java:250-265`
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+public List<Tree<Long>> buildMenuTreeSelect(List<SysMenuVo> menus) {
|
|
|
|
|
+ if (CollUtil.isEmpty(menus)) {
|
|
|
|
|
+ return CollUtil.newArrayList(); // ← 如果查询结果为空,返回空列表
|
|
|
|
|
+ }
|
|
|
|
|
+ return TreeBuildUtils.build(menus, (menu, tree) -> {
|
|
|
|
|
+ tree.setId(menu.getMenuId())
|
|
|
|
|
+ .setParentId(menu.getParentId())
|
|
|
|
|
+ .setName(menu.getMenuName())
|
|
|
|
|
+ .setWeight(menu.getOrderNum());
|
|
|
|
|
+ // ... 设置其他属性
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 为什么商户端查不到数据?
|
|
|
|
|
+
|
|
|
|
|
+### 问题定位
|
|
|
|
|
+
|
|
|
|
|
+根据执行流程,商户端查询的SQL实际上是:
|
|
|
|
|
+
|
|
|
|
|
+```sql
|
|
|
|
|
+SELECT *
|
|
|
|
|
+FROM sys_menu
|
|
|
|
|
+WHERE menu_id IN (
|
|
|
|
|
+ -- 步骤1: 获取用户角色分配的菜单
|
|
|
|
|
+ SELECT menu_id FROM sys_role_menu
|
|
|
|
|
+ WHERE role_id IN (
|
|
|
|
|
+ SELECT role_id FROM sys_user_role WHERE user_id = 2038434195944886273
|
|
|
|
|
+ )
|
|
|
|
|
+)
|
|
|
|
|
+AND platform_id = 1 -- 步骤2: 过滤商户端菜单
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 问题原因
|
|
|
|
|
+
|
|
|
|
|
+**两个条件的交集为空**:
|
|
|
|
|
+
|
|
|
|
|
+1. **步骤1结果**: 用户角色分配的菜单(假设有 100 条)
|
|
|
|
|
+ - 这些菜单的 `platform_id` 可能是 0、NULL 或其他值
|
|
|
|
|
+
|
|
|
|
|
+2. **步骤2过滤**: `platform_id = 1`
|
|
|
|
|
+ - 只保留商户端菜单
|
|
|
|
|
+
|
|
|
|
|
+3. **交集**: 如果步骤1的100条菜单中,没有一条的 `platform_id = 1`
|
|
|
|
|
+ - 最终结果为空
|
|
|
|
|
+
|
|
|
|
|
+### 验证方法
|
|
|
|
|
+
|
|
|
|
|
+执行以下SQL验证:
|
|
|
|
|
+
|
|
|
|
|
+```sql
|
|
|
|
|
+-- 查看用户角色分配的菜单的平台分布
|
|
|
|
|
+SELECT sm.platform_id, COUNT(*) as count
|
|
|
|
|
+FROM sys_user_role sur
|
|
|
|
|
+LEFT JOIN sys_role_menu srm ON sur.role_id = srm.role_id
|
|
|
|
|
+LEFT JOIN sys_menu sm ON srm.menu_id = sm.menu_id
|
|
|
|
|
+WHERE sur.user_id = 2038434195944886273
|
|
|
|
|
+GROUP BY sm.platform_id;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**如果结果显示**:
|
|
|
|
|
+- `platform_id = 0`: 100 条
|
|
|
|
|
+- `platform_id = 1`: 0 条
|
|
|
|
|
+
|
|
|
|
|
+**说明**: 用户角色分配的菜单都是平台端的,没有商户端的,所以查询结果为空。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 解决方案
|
|
|
|
|
+
|
|
|
|
|
+### 方案1: 修改菜单数据(推荐)
|
|
|
|
|
+
|
|
|
|
|
+将用户角色需要的菜单改为 `platform_id = 1`:
|
|
|
|
|
+
|
|
|
|
|
+```sql
|
|
|
|
|
+UPDATE sys_menu SET platform_id = 1
|
|
|
|
|
+WHERE menu_id IN (
|
|
|
|
|
+ SELECT menu_id FROM sys_role_menu
|
|
|
|
|
+ WHERE role_id IN (
|
|
|
|
|
+ SELECT role_id FROM sys_user_role
|
|
|
|
|
+ WHERE user_id = 2038434195944886273
|
|
|
|
|
+ )
|
|
|
|
|
+);
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 方案2: 重新分配角色菜单
|
|
|
|
|
+
|
|
|
|
|
+删除旧的菜单权限,分配新的 `platform_id = 1` 的菜单:
|
|
|
|
|
+
|
|
|
|
|
+```sql
|
|
|
|
|
+-- 1. 获取角色ID
|
|
|
|
|
+SELECT role_id FROM sys_user_role WHERE user_id = 2038434195944886273;
|
|
|
|
|
+
|
|
|
|
|
+-- 2. 删除旧权限
|
|
|
|
|
+DELETE FROM sys_role_menu WHERE role_id = ?;
|
|
|
|
|
+
|
|
|
|
|
+-- 3. 分配新权限
|
|
|
|
|
+INSERT INTO sys_role_menu (role_id, menu_id)
|
|
|
|
|
+SELECT ?, menu_id FROM sys_menu WHERE platform_id = 1;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 调试建议
|
|
|
|
|
+
|
|
|
|
|
+在以下位置添加日志:
|
|
|
|
|
+
|
|
|
|
|
+1. **SysMenuServiceImpl.java:82** - 查看 `platformId` 的值
|
|
|
|
|
+2. **SysMenuServiceImpl.java:92** - 查看 `menuList.size()`
|
|
|
|
|
+3. **PlatformUtils.java:8** - 查看请求头中的 `PLATFORM_CODE`
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+log.info("查询菜单 - userId={}, platformId={}, isSuperAdmin={}",
|
|
|
|
|
+ userId, platformId, LoginHelper.isSuperAdmin(userId));
|
|
|
|
|
+log.info("查询结果 - menuList.size()={}", menuList.size());
|
|
|
|
|
+```
|