# /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());
```
