Переглянути джерело

Merge remote-tracking branch 'origin/dev_20260131' into dev_20260131

donglang 1 місяць тому
батько
коміт
4512719c3f

+ 15 - 0
sckw-auth/src/main/java/com/sckw/auth/model/vo/res/LoginResVo1.java

@@ -165,6 +165,21 @@ public class LoginResVo1 implements Serializable {
      */
     private List<TabBarItem> tabBar;
 
+    @Schema(description = "是否展示订单统计模块")
+    private Boolean showOrderStatisticsModule;
+
+    @Schema(description = "是否展示销售统计模块")
+    private Boolean showSalesStatisticsModule;
+
+    @Schema(description = "是否展示钱包模块")
+    private Boolean showWalletModule;
+
+    @Schema(description = "是否展示地址模块")
+    private Boolean showAddressModule;
+
+    @Schema(description = "钱包模块展示项")
+    private List<String> walletModuleItems;
+
     @Data
     public static class TabBarItem implements Serializable {
         @Serial

+ 54 - 0
sckw-auth/src/main/java/com/sckw/auth/service/impl/AuthServiceImpl.java

@@ -172,6 +172,7 @@ public class AuthServiceImpl implements IAuthService {
         if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(tabBar)) {
             loginRes.setTabBar(tabBar);
         }
+        applyAppModulePermissions(loginRes, loginBase, null);
         loginRes.setRefreshToken(refreshToken);
         return HttpResult.ok(loginRes);
     }
@@ -265,6 +266,7 @@ public class AuthServiceImpl implements IAuthService {
         if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(tabBar)) {
             loginRes.setTabBar(tabBar);
         }
+        applyAppModulePermissions(loginRes, loginBase, user.getRoleName());
         if (user.getSystemType().equals(SystemTypeEnum.MANAGE.getCode())) {
             loginRes.setValid(true);
         } else {
@@ -354,6 +356,7 @@ public class AuthServiceImpl implements IAuthService {
         if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(tabBar)) {
             loginRes.setTabBar(tabBar);
         }
+        applyAppModulePermissions(loginRes, loginBase, user.getRoleName());
         if (user.getSystemType().equals(SystemTypeEnum.MANAGE.getCode())) {
             loginRes.setValid(true);
         } else {
@@ -517,6 +520,9 @@ public class AuthServiceImpl implements IAuthService {
         loginRes.setToken(token);
         loginRes.setDeptId(user.getDeptId());
         loginRes.setRoleId(user.getRoleId());
+        LoginBase loginBase = new LoginBase();
+        loginBase.setClientType(clientType);
+        applyAppModulePermissions(loginRes, loginBase, user.getRoleName());
         if (user.getSystemType().equals(SystemTypeEnum.MANAGE.getCode())) {
             loginRes.setValid(true);
         } else {
@@ -855,6 +861,7 @@ public class AuthServiceImpl implements IAuthService {
         if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(tabBar)) {
             loginRes.setTabBar(tabBar);
         }
+        applyAppModulePermissions(loginRes, loginBase, null);
         return loginRes;
     }
     
@@ -891,6 +898,7 @@ public class AuthServiceImpl implements IAuthService {
         if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(tabBar)) {
             loginRes.setTabBar(tabBar);
         }
+        applyAppModulePermissions(loginRes, loginBase, user.getRoleName());
         if (user.getSystemType().equals(SystemTypeEnum.MANAGE.getCode())) {
             loginRes.setValid(true);
         } else {
@@ -907,10 +915,56 @@ public class AuthServiceImpl implements IAuthService {
                 || Objects.equals(clientType, ClientTypeEnum.mobile.getValue());
     }
 
+    private void applyAppModulePermissions(LoginResVo1 loginRes, LoginBase loginBase, String roleName) {
+        loginRes.setShowOrderStatisticsModule(Boolean.FALSE);
+        loginRes.setShowSalesStatisticsModule(Boolean.FALSE);
+        loginRes.setShowWalletModule(Boolean.FALSE);
+        loginRes.setShowAddressModule(Boolean.FALSE);
+        loginRes.setWalletModuleItems(Collections.emptyList());
+        if (!isAppLogin(loginBase) || StringUtils.isBlank(roleName)) {
+            return;
+        }
+        boolean isSeller = containsAnyRole(roleName, "销售");
+        boolean isFinance = containsAnyRole(roleName, "财务");
+        boolean isPurchase = containsAnyRole(roleName, "采购", "买家");
+        if (isSeller) {
+            loginRes.setShowOrderStatisticsModule(Boolean.TRUE);
+            loginRes.setShowSalesStatisticsModule(Boolean.TRUE);
+            return;
+        }
+        if (isFinance) {
+            loginRes.setShowOrderStatisticsModule(Boolean.TRUE);
+            loginRes.setShowWalletModule(Boolean.TRUE);
+            loginRes.setWalletModuleItems(Arrays.asList("PENDING_PERFORMANCE_BALANCE", "PENDING_FREIGHT"));
+            return;
+        }
+        if (isPurchase) {
+            loginRes.setShowOrderStatisticsModule(Boolean.TRUE);
+            loginRes.setShowWalletModule(Boolean.TRUE);
+            loginRes.setShowAddressModule(Boolean.TRUE);
+            loginRes.setWalletModuleItems(Arrays.asList("PREPAY_BALANCE", "PENDING_FREIGHT"));
+        }
+    }
+
+    private boolean containsAnyRole(String roleName, String... roleKeywords) {
+        if (StringUtils.isBlank(roleName) || roleKeywords == null) {
+            return false;
+        }
+        for (String roleKeyword : roleKeywords) {
+            if (StringUtils.isNotBlank(roleKeyword) && roleName.contains(roleKeyword)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private List<LoginResVo1.TabBarItem> buildAppTabBar(LoginBase loginBase, String roleName,int flag) {
         if (!isAppLogin(loginBase)) {
             return List.of();
         }
+        if (containsAnyRole(roleName, "采购")) {
+            return buildBuyerTabBar();
+        }
         boolean isDoorKeeper = StringUtils.isNotBlank(roleName) && roleName.contains("门卫");
         boolean isForkliftDriver = StringUtils.isNotBlank(roleName) && roleName.contains("铲车司机");
         boolean isBuyer = StringUtils.isNotBlank(roleName) && roleName.contains("买家");

+ 9 - 0
sckw-modules/sckw-system/src/main/java/com/sckw/system/controller/KwsMenuController.java

@@ -49,6 +49,15 @@ public class KwsMenuController {
         return HttpResult.ok(kwsMenuService.findTree(reqVo));
     }
 
+    /**
+     * App 端查询菜单/按钮权限;permQueryType=3 时返回菜单并在每条记录下挂 buttons
+     */
+    @PostMapping("/appMenuOrButtonPerms")
+    @Operation(summary = "App 菜单/按钮权限列表(支持菜单下挂按钮)")
+    public HttpResult appMenuOrButtonPerms(@RequestBody @Valid AppMenuPermQueryReqVo reqVo) {
+        return HttpResult.ok(kwsMenuService.queryAppMenuOrButtonPerms(reqVo));
+    }
+
     @PostMapping("/list")
     @Operation(summary = "导航首页统计")
     public HttpResult list(@RequestBody @Valid FindMenuTreeReqVo reqVo) {

+ 2 - 0
sckw-modules/sckw-system/src/main/java/com/sckw/system/dao/KwsMenuDao.java

@@ -71,6 +71,8 @@ public interface KwsMenuDao {
      */
     List<KwsMenuResVo> findList(FindMenuTreePojo params);
 
+    List<KwsMenuResVo> findList1(FindMenuTreePojo params);
+
     /**
      * @param kwsMenuParam 实体
      * @return KwsMenu

+ 1 - 0
sckw-modules/sckw-system/src/main/java/com/sckw/system/dao/KwsMenuMappingDao.java

@@ -40,6 +40,7 @@ public interface KwsMenuMappingDao {
      * @date: 2023/9/5
      */
     List<KwsMenuMapping> selectByMenuIds(@Param(value = "idList") List<Long> idList);
+    List<KwsMenuMapping> selectByMappingIds(@Param(value = "idList") List<Long> idList);
 
     /**
      * @param kwsMenuMapping 实体

+ 12 - 0
sckw-modules/sckw-system/src/main/java/com/sckw/system/dao/KwsMenuMpMapper.java

@@ -0,0 +1,12 @@
+package com.sckw.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.sckw.system.model.KwsMenu;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 菜单表 MyBatis-Plus 查询(与 {@link KwsMenuDao} 传统 XML 并存,仅用于 Lambda 条件查询)
+ */
+@Mapper
+public interface KwsMenuMpMapper extends BaseMapper<KwsMenu> {
+}

+ 12 - 0
sckw-modules/sckw-system/src/main/java/com/sckw/system/dao/KwsMenuRightsMpMapper.java

@@ -0,0 +1,12 @@
+package com.sckw.system.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.sckw.system.model.KwsMenuRights;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 菜单权限表 MyBatis-Plus 查询(与 {@link KwsMenuRightsDao} 传统 XML 并存)
+ */
+@Mapper
+public interface KwsMenuRightsMpMapper extends BaseMapper<KwsMenuRights> {
+}

+ 46 - 0
sckw-modules/sckw-system/src/main/java/com/sckw/system/model/vo/req/AppMenuPermQueryReqVo.java

@@ -0,0 +1,46 @@
+package com.sckw.system.model.vo.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * App 端查询菜单或按钮权限入参
+ * <p>
+ * permQueryType:1-仅菜单(目录+菜单),2-仅按钮,3-菜单且每项下带出该菜单下的按钮权限
+ */
+@Data
+public class AppMenuPermQueryReqVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 查询类型:1 仅菜单,2 仅按钮,3 菜单并带出下属按钮
+     */
+    public static final int PERM_QUERY_MENU = 1;
+    public static final int PERM_QUERY_BUTTON = 2;
+    public static final int PERM_QUERY_MENU_WITH_BUTTONS = 3;
+
+    @NotBlank(message = "客户端类型不能为空")
+    @Schema(description = "终端类型:3-企业APP 等,与菜单 client_type 一致")
+    private String clientType;
+
+    /**
+     * 与 {@link FindMenuTreeReqVo#getUserId()} 一致:企业 APP 传参用户 id 时走对应权限链路
+     */
+    @Schema(description = "用户 id,APP 与 findMenuTree 一致时可传")
+    private Long userId;
+
+    @NotNull(message = "权限查询类型不能为空")
+    @Min(1)
+    @Max(3)
+    @Schema(description = "1-仅菜单(目录+菜单),2-仅按钮,3-菜单且每项携带 buttons 按钮列表")
+    private Integer permQueryType;
+}

+ 95 - 0
sckw-modules/sckw-system/src/main/java/com/sckw/system/model/vo/res/AppMenuPermItemResVo.java

@@ -0,0 +1,95 @@
+package com.sckw.system.model.vo.res;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * App 菜单/按钮权限项:字段与菜单表对齐,序列化时对空值统一为默认非 null,便于前端直接使用。
+ */
+@Data
+public class AppMenuPermItemResVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "菜单主键")
+    private Long id;
+
+    @Schema(description = "父级菜单 id,无父级时为 0")
+    private Long parentId;
+
+    @Schema(description = "终端类型:1运营端、2企业PC、3企业APP、4司机端")
+    private Integer clientType;
+
+    @Schema(description = "权限标识")
+    private String perms;
+
+    @Schema(description = "名称")
+    private String name;
+
+    @Schema(description = "类型:0目录/1菜单/2按钮")
+    private Integer type;
+
+    @Schema(description = "前端路由或页面路径")
+    private String url;
+
+    @Schema(description = "按钮对应后端接口地址")
+    private String links;
+
+    @Schema(description = "菜单图标")
+    private String icon;
+
+    @Schema(description = "排序")
+    private Integer sort;
+
+    @Schema(description = "层级")
+    private Integer level;
+
+    @Schema(description = "是否定制:0否 1是")
+    private Integer custom;
+
+    @Schema(description = "是否默认展示")
+    private Integer isDisplay;
+
+    @Schema(description = "菜单开放类型:0普通 1超管 2非普通用户")
+    private Integer isMain;
+
+    @Schema(description = "适用企业类型(多值拼接)")
+    private String usingRoles;
+
+    @Schema(description = "备注")
+    private String remark;
+
+    @Schema(description = "状态:0正常 1锁定")
+    private Integer status;
+
+    @Schema(description = "创建人")
+    private Long createBy;
+
+    @Schema(description = "创建时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createTime;
+
+    @Schema(description = "更新人")
+    private Long updateBy;
+
+    @Schema(description = "更新时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updateTime;
+
+    @Schema(description = "删除标识:0正常")
+    private Integer delFlag;
+
+    /**
+     * 菜单+按钮查询时为下属按钮列表;仅菜单/仅按钮查询时为无元素的列表,避免 null。
+     */
+    @Schema(description = "下属按钮权限;非菜单+按钮模式为空列表")
+    private List<AppMenuPermItemResVo> buttons = new ArrayList<>();
+}

+ 7 - 5
sckw-modules/sckw-system/src/main/java/com/sckw/system/service/KwsEnterpriseService.java

@@ -1685,13 +1685,15 @@ public class KwsEnterpriseService {
     public List<EntInfo> queryEnterpriseByPageType(EnterprisePageQueryReqVo req) {
         log.info("查询企业信息请求参数:{}", JSON.toJSONString(req));
 
-        List<KwsEntType> entTypes = kwsEntTypeRepository.queryByType(req.getEnterpriseType());
-        if (CollectionUtils.isEmpty(entTypes)) {
+        Long loginEntId = LoginUserHolder.getEntId();
+        if (Objects.isNull(loginEntId)) {
             return Collections.emptyList();
         }
 
-        Set<Long> entIds = entTypes.stream().map(KwsEntType::getEntId).collect(Collectors.toSet());
-        if (CollectionUtils.isEmpty(entIds)) {
+        List<KwsEntType> entTypes = kwsEntTypeDao.findListByEntId(loginEntId);
+        boolean matchEnterpriseType = CollectionUtils.isNotEmpty(entTypes)
+                && entTypes.stream().anyMatch(item -> Objects.equals(item.getType(), req.getEnterpriseType()));
+        if (!matchEnterpriseType) {
             return Collections.emptyList();
         }
 
@@ -1699,7 +1701,7 @@ public class KwsEnterpriseService {
                 .eq(BaseModel::getDelFlag, Global.UN_DELETED)
                 .eq(BaseModel::getStatus, Global.NO)
                 .eq(KwsEnterprise::getApproval, ApprovalEnum.OK.getCode())
-                .in(KwsEnterprise::getId, entIds)
+                .eq(KwsEnterprise::getId, loginEntId)
                 .like(StringUtils.isNotBlank(req.getEntName()), KwsEnterprise::getFirmName, req.getEntName())
                 .orderByAsc(KwsEnterprise::getFirmName));
         if (CollectionUtils.isEmpty(enterprises)) {

+ 357 - 13
sckw-modules/sckw-system/src/main/java/com/sckw/system/service/KwsMenuService.java

@@ -3,6 +3,8 @@ package com.sckw.system.service;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.sckw.contract.api.RemoteContractService;
 import com.sckw.core.exception.SystemException;
 import com.sckw.core.model.constant.Global;
@@ -48,6 +50,12 @@ public class KwsMenuService {
     @Autowired
     KwsMenuDao kwsMenuDao;
 
+    @Autowired
+    private KwsMenuMpMapper kwsMenuMpMapper;
+
+    @Autowired
+    private KwsMenuRightsMpMapper kwsMenuRightsMpMapper;
+
     @Autowired
     KwsMenuRightsDao kwsMenuRightsDao;
 
@@ -278,14 +286,336 @@ public class KwsMenuService {
      * @author: czh
      * @date: 2023/7/7
      */
+
+    /**
+     * 查询 App 端菜单或按钮权限列表。
+     * <p>
+     * 核心逻辑:
+     * 1. 解析客户端类型和权限查询类型。
+     * 2. 填充查询条件对象(包括系统类型、角色ID、企业类型等)。
+     * 3. 判断是否绕过权限校验(运营端主账号拥有所有权限)。
+     * 4. 根据是否绕过权限,执行不同的菜单查询策略。
+     * 5. 如果是企业用户且使用 App 端,应用菜单映射逻辑(App 菜单映射到 PC 菜单)。
+     * 6. 对结果进行排序(先按层级,再按序号)。
+     * 7. 如果请求包含按钮信息,则组装菜单及其子按钮;否则直接返回菜单列表。
+     *
+     * @param reqVo 查询请求参数,包含客户端类型、用户ID、权限查询类型等
+     * @return 菜单或按钮权限项列表
+     */
+    public List<AppMenuPermItemResVo> queryAppMenuOrButtonPerms(AppMenuPermQueryReqVo reqVo) {
+        // 解析客户端类型,去除空格并转为整数
+        int clientType = Integer.parseInt(reqVo.getClientType().trim());
+        // 获取权限查询类型(如:仅菜单、仅按钮、菜单+按钮)
+        int permQueryType = reqVo.getPermQueryType();
+
+        // 构建查询条件对象
+        FindMenuTreePojo pojo = new FindMenuTreePojo();
+        pojo.setClientType(clientType);
+        // 填充用户相关的查询条件(如角色ID、企业类型、系统类型等)
+        extracted(reqVo.getUserId(), reqVo.getClientType(), pojo);
+
+        // 判断是否绕过权限校验:运营端系统类型且为主账号时,无需校验具体权限
+        boolean bypassRights = Objects.equals(LoginUserHolder.getSystemType(), SystemTypeEnum.MANAGE.getCode())
+                && Objects.equals(LoginUserHolder.getIsMain(), Global.YES);
+
+        // 根据是否绕过权限,选择查询策略
+        List<KwsMenu> menus = bypassRights
+                ? selectMenusByMpWithoutRights(clientType, permQueryType, pojo) // 无权限限制查询
+                : selectMenusByMpWithRights(clientType, permQueryType, pojo);   // 有权限限制查询
+
+
+        // 对菜单列表进行排序:先按层级(level)升序,再按序号(sort)升序,null 值排在最后
+//        menus.sort(Comparator.comparing(KwsMenu::getLevel, Comparator.nullsLast(Integer::compareTo))
+//                .thenComparing(KwsMenu::getSort, Comparator.nullsLast(Integer::compareTo)));
+
+        // 如果查询类型为“菜单带按钮”,则组装菜单及其嵌套的按钮列表
+        if (permQueryType == AppMenuPermQueryReqVo.PERM_QUERY_MENU_WITH_BUTTONS) {
+            return assembleMenusWithNestedButtons(menus, pojo);
+        }
+        return menus.stream().map(this::toAppMenuPermItemResVo).toList();
+    }
+
+    /**
+     * 将菜单实体转为权限 VO,并对所有字段做空值默认填充,保证返回 JSON 中字段均有明确取值。
+     */
+    private AppMenuPermItemResVo toAppMenuPermItemResVo(KwsMenu source) {
+        AppMenuPermItemResVo v = new AppMenuPermItemResVo();
+        if (source != null) {
+            BeanUtils.copyProperties(source, v);
+        }
+        //fillAppMenuPermVoDefaults(v);
+        return v;
+    }
+
+    private void fillAppMenuPermVoDefaults(AppMenuPermItemResVo v) {
+        if (v.getId() == null) {
+            v.setId(0L);
+        }
+        if (v.getParentId() == null) {
+            v.setParentId(0L);
+        }
+        if (v.getClientType() == null) {
+            v.setClientType(0);
+        }
+        if (v.getPerms() == null) {
+            v.setPerms("");
+        }
+        if (v.getName() == null) {
+            v.setName("");
+        }
+        if (v.getType() == null) {
+            v.setType(0);
+        }
+        if (v.getUrl() == null) {
+            v.setUrl("");
+        }
+        if (v.getLinks() == null) {
+            v.setLinks("");
+        }
+        if (v.getIcon() == null) {
+            v.setIcon("");
+        }
+        if (v.getSort() == null) {
+            v.setSort(0);
+        }
+        if (v.getLevel() == null) {
+            v.setLevel(0);
+        }
+        if (v.getCustom() == null) {
+            v.setCustom(0);
+        }
+        if (v.getIsDisplay() == null) {
+            v.setIsDisplay(0);
+        }
+        if (v.getIsMain() == null) {
+            v.setIsMain(0);
+        }
+        if (v.getUsingRoles() == null) {
+            v.setUsingRoles("");
+        }
+        if (v.getRemark() == null) {
+            v.setRemark("");
+        }
+        if (v.getStatus() == null) {
+            v.setStatus(0);
+        }
+        if (v.getCreateBy() == null) {
+            v.setCreateBy(0L);
+        }
+        if (v.getUpdateBy() == null) {
+            v.setUpdateBy(0L);
+        }
+        if (v.getCreateTime() == null) {
+            v.setCreateTime(new Date(0));
+        }
+        if (v.getUpdateTime() == null) {
+            v.setUpdateTime(new Date(0));
+        }
+        if (v.getDelFlag() == null) {
+            v.setDelFlag(0);
+        }
+        if (v.getButtons() == null) {
+            v.setButtons(new ArrayList<>());
+        }
+    }
+
+    /**
+     * 在已确定的菜单(目录+菜单)集合上,用 MyBatis-Plus 批量查询 parent 在其 id 集合下的按钮并挂到每条菜单下。
+     * <p>
+     * 步骤:
+     * 1. 提取所有菜单的 ID 作为父 ID 集合。
+     * 2. 批量查询这些父 ID 下的所有按钮类型的菜单。
+     * 3. 将按钮按父 ID 分组。
+     * 4. 遍历菜单列表,为每个菜单设置其对应的子按钮列表。
+     *
+     * @param menus 菜单列表(不含按钮)
+     * @param pojo  查询条件对象,用于过滤按钮的企业类型权限
+     * @return 组装好子按钮的菜单权限项列表
+     */
+    private List<AppMenuPermItemResVo> assembleMenusWithNestedButtons(List<KwsMenu> menus, FindMenuTreePojo pojo) {
+        // 如果菜单列表为空,直接返回空列表
+        if (CollectionUtils.isEmpty(menus)) {
+            return Collections.emptyList();
+        }
+        // 提取所有菜单的 ID,作为查询子按钮的父 ID 条件
+        List<Long> parentIds = menus.stream().map(KwsMenu::getId).toList();
+        // 获取客户端类型,确保查询的按钮与菜单属于同一客户端
+        Integer btnClientType = menus.get(0).getClientType();
+
+        // 构建按钮查询条件
+        LambdaQueryWrapper<KwsMenu> bw = Wrappers.lambdaQuery(KwsMenu.class)
+                .eq(KwsMenu::getDelFlag, Global.NO) // 未删除
+                .eq(KwsMenu::getType, MenuTypeEnum.BUTTON.getCode()) // 仅限按钮类型
+                .eq(KwsMenu::getClientType, btnClientType) // 匹配客户端类型
+                .in(KwsMenu::getParentId, parentIds); // 父 ID 在菜单 ID 集合中
+        // 追加企业类型过滤,确保按钮也符合当前用户的企业类型权限
+        appendUsingRolesFilter(bw, pojo.getEntTypeList());
+        // 按序号升序排列
+        bw.orderByAsc(KwsMenu::getSort);
+
+        // 执行查询,获取所有相关按钮
+        List<KwsMenu> buttonRows = kwsMenuMpMapper.selectList(bw);
+        // 将按钮按父 ID 分组,使用 LinkedHashMap 保持插入顺序
+        Map<Long, List<KwsMenu>> buttonsByParent = buttonRows.stream()
+                .collect(Collectors.groupingBy(KwsMenu::getParentId, LinkedHashMap::new, Collectors.toList()));
+
+        List<AppMenuPermItemResVo> result = new ArrayList<>(menus.size());
+        for (KwsMenu m : menus) {
+            AppMenuPermItemResVo vo = toAppMenuPermItemResVo(m);
+            List<KwsMenu> children = buttonsByParent.getOrDefault(m.getId(), Collections.emptyList());
+            List<AppMenuPermItemResVo> btnVos = new ArrayList<>(children.size());
+            for (KwsMenu c : children) {
+                btnVos.add(toAppMenuPermItemResVo(c));
+            }
+            vo.setButtons(btnVos);
+            result.add(vo);
+        }
+        return result;
+    }
+
+    /**
+     * 无需权限校验的菜单查询(通常用于运营端主账号)。
+     * <p>
+     * 直接根据客户端类型、权限查询类型和企业类型过滤菜单,不关联菜单权限表。
+     *
+     * @param clientType    客户端类型
+     * @param permQueryType 权限查询类型(菜单或按钮)
+     * @param pojo          查询条件对象,包含企业类型列表
+     * @return 菜单列表
+     */
+    private List<KwsMenu> selectMenusByMpWithoutRights(int clientType, int permQueryType, FindMenuTreePojo pojo) {
+        // 构建基础查询条件:未删除且匹配客户端类型
+        LambdaQueryWrapper<KwsMenu> mw = Wrappers.lambdaQuery(KwsMenu.class)
+                .eq(KwsMenu::getDelFlag, Global.NO)
+                .eq(KwsMenu::getClientType, clientType);
+        
+        // 追加权限查询类型过滤(区分查询菜单/目录还是按钮)
+        appendPermQueryType(mw, permQueryType);
+        // 追加企业类型过滤(基于 using_roles 字段模糊匹配)
+        appendUsingRolesFilter(mw, pojo.getEntTypeList());
+        
+        // 执行查询并返回结果
+        return kwsMenuMpMapper.selectList(mw);
+    }
+
+    /**
+     * 需要权限校验的菜单查询。
+     * <p>
+     * 首先从菜单权限表(kws_menu_rights)中查询当前用户/企业有权限的菜单ID集合,
+     * 然后根据这些ID查询具体的菜单信息,并附加其他过滤条件。
+     *
+     * @param clientType    客户端类型
+     * @param permQueryType 权限查询类型
+     * @param pojo          查询条件对象,包含角色ID、企业ID、企业类型列表
+     * @return 菜单列表
+     */
+    private List<KwsMenu> selectMenusByMpWithRights(int clientType, int permQueryType, FindMenuTreePojo pojo) {
+        // 构建菜单权限查询条件
+        LambdaQueryWrapper<KwsMenuRights> rw = Wrappers.lambdaQuery(KwsMenuRights.class)
+                .eq(KwsMenuRights::getDelFlag, Global.NO) // 未删除
+                .select(KwsMenuRights::getMenuId); // 只查询菜单ID字段,优化性能
+        
+        // 如果有角色ID限制,则加入 in 条件
+        if (CollectionUtils.isNotEmpty(pojo.getRoleIds())) {
+            rw.in(KwsMenuRights::getRoleId, pojo.getRoleIds());
+        }
+        // 如果有企业ID限制,则加入 eq 条件
+        if (pojo.getEntId() != null) {
+            rw.eq(KwsMenuRights::getEntId, pojo.getEntId());
+        }
+        
+        // 执行查询,获取有权限的菜单ID行记录
+        List<KwsMenuRights> rightsRows = kwsMenuRightsMpMapper.selectList(rw);
+        
+        // 提取菜单ID集合,去重
+        Set<Long> menuIds = rightsRows.stream()
+                .map(KwsMenuRights::getMenuId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+        
+        // 如果没有权限ID,直接返回空列表
+        if (menuIds.isEmpty()) {
+            return Collections.emptyList();
+        }
+        
+        // 构建菜单查询条件
+        LambdaQueryWrapper<KwsMenu> mw = Wrappers.lambdaQuery(KwsMenu.class)
+                .eq(KwsMenu::getDelFlag, Global.NO) // 未删除
+                .eq(KwsMenu::getClientType, clientType) // 匹配客户端类型
+                .in(KwsMenu::getId, menuIds); // 限制在有权重的菜单ID范围内
+        
+        // 追加权限查询类型过滤
+        appendPermQueryType(mw, permQueryType);
+        // 追加企业类型过滤
+        appendUsingRolesFilter(mw, pojo.getEntTypeList());
+        
+        return kwsMenuMpMapper.selectList(mw);
+    }
+
+    /**
+     * 根据权限查询类型,向查询条件中追加菜单类型过滤。
+     * <p>
+     * 如果查询类型为按钮,则只查询按钮类型;
+     * 否则查询目录类型(type=0 或 type=DIRECTORY)。
+     *
+     * @param mw            菜单查询包装器
+     * @param permQueryType 权限查询类型常量
+     */
+    private void appendPermQueryType(LambdaQueryWrapper<KwsMenu> mw, int permQueryType) {
+        if (permQueryType == AppMenuPermQueryReqVo.PERM_QUERY_BUTTON) {
+            // 仅查询按钮类型
+            mw.eq(KwsMenu::getType, MenuTypeEnum.BUTTON.getCode());
+        } else {
+            // 查询目录或菜单类型(排除按钮)
+            // 注意:这里兼容了 type=0 的历史数据或特定定义
+            mw.and(w -> w.eq(KwsMenu::getType, 0).or().eq(KwsMenu::getType, MenuTypeEnum.DIRECTORY.getCode()));
+        }
+    }
+
+    /**
+     * 向查询条件中追加企业类型(using_roles)的模糊匹配过滤。
+     * <p>
+     * 多个企业类型之间使用 OR 连接,即只要 matching 其中一个类型即可。
+     * SQL 示例: AND (using_roles LIKE '%type1%' OR using_roles LIKE '%type2%')
+     *
+     * @param mw           菜单查询包装器
+     * @param entTypeList  企业类型列表
+     */
+    private void appendUsingRolesFilter(LambdaQueryWrapper<KwsMenu> mw, List<String> entTypeList) {
+        // 如果企业类型列表为空,不进行过滤
+        if (CollectionUtils.isEmpty(entTypeList)) {
+            return;
+        }
+        // 构建 (like A or like B or ...) 的条件组
+        mw.and(w -> {
+            for (int i = 0; i < entTypeList.size(); i++) {
+                String t = entTypeList.get(i);
+                if (i == 0) {
+                    // 第一个条件直接使用 like
+                    w.like(KwsMenu::getUsingRoles, t);
+                } else {
+                    // 后续条件使用 or like
+                    w.or().like(KwsMenu::getUsingRoles, t);
+                }
+            }
+        });
+    }
+
+
+
     public List<FindMenuTreeResVo> findTree(FindMenuTreeReqVo reqVo) {
         FindMenuTreePojo findMenuTreePojo = new FindMenuTreePojo();
         BeanUtils.copyProperties(reqVo, findMenuTreePojo);
 
         //填充用户参数
         extracted(reqVo.getUserId(), reqVo.getClientType(), findMenuTreePojo);
-
-        List<KwsMenuResVo> menuList = kwsMenuDao.findList(findMenuTreePojo);
+        List<KwsMenuResVo> menuList = new ArrayList<>();
+        if (Objects.equals(LoginUserHolder.getSystemType(), SystemTypeEnum.COMPANY.getCode()) && org.apache.commons.lang3.StringUtils.equals(reqVo.getClientType(), String.valueOf(Global.NUMERICAL_THREE))) {
+            menuList = kwsMenuDao.findList1(findMenuTreePojo);
+        }else {
+            menuList = kwsMenuDao.findList(findMenuTreePojo);
+        }
+       // List<KwsMenuResVo> menuList = kwsMenuDao.findList(findMenuTreePojo);
         if (CollectionUtils.isEmpty(menuList)) {
             return Collections.emptyList();
         }
@@ -294,17 +624,18 @@ public class KwsMenuService {
         List<KwsMenuResVo> finalList = new ArrayList<>();
         if (SystemTypeEnum.COMPANY.getCode().equals(LoginUserHolder.getSystemType()) &&
                 ClientTypeEnum.app.getValue().equals(LoginUserHolder.getClientType())) {
-            List<KwsMenuMapping> kwsMenuMappings = kwsMenuMappingDao.selectByMenuIds(menuList.stream().map(KwsMenuResVo::getId).toList());
-            if (CollectionUtils.isEmpty(kwsMenuMappings)) {
-                return Collections.emptyList();
-            }
-
-            List<Long> mapIds = kwsMenuMappings.stream().map(KwsMenuMapping::getMappingId).toList();
-            List<KwsMenu> kwsMenus = kwsMenuDao.selectByKeys(mapIds);
-            if (CollectionUtils.isEmpty(kwsMenus)) {
-                return Collections.emptyList();
-            }
-            finalList = BeanUtils.copyToList(kwsMenus, KwsMenuResVo.class);
+//            List<KwsMenuMapping> kwsMenuMappings = kwsMenuMappingDao.selectByMenuIds(menuList.stream().map(KwsMenuResVo::getId).toList());
+//            if (CollectionUtils.isEmpty(kwsMenuMappings)) {
+//                return Collections.emptyList();
+//            }
+//
+//            List<Long> mapIds = kwsMenuMappings.stream().map(KwsMenuMapping::getMappingId).toList();
+//            List<KwsMenu> kwsMenus = kwsMenuDao.selectByKeys(mapIds);
+//            if (CollectionUtils.isEmpty(kwsMenus)) {
+//                return Collections.emptyList();
+//            }
+            finalList = menuList;
+          //  finalList = BeanUtils.copyToList(kwsMenus, KwsMenuResVo.class);
         } else {
             finalList = menuList;
         }
@@ -349,7 +680,20 @@ public class KwsMenuService {
         }
         //pc端和app权限不做过滤,
         // 根据用户id查询角色id
+        if (Objects.equals(LoginUserHolder.getSystemType(), SystemTypeEnum.COMPANY.getCode()) && org.apache.commons.lang3.StringUtils.equals(clientType, String.valueOf(Global.NUMERICAL_THREE)) && Objects.equals(LoginUserHolder.getIsMain(), Global.YES)) {
+            return;
+        }
+
         if (Objects.equals(LoginUserHolder.getSystemType(), SystemTypeEnum.COMPANY.getCode()) && org.apache.commons.lang3.StringUtils.equals(clientType, String.valueOf(Global.NUMERICAL_THREE))) {
+            if (Objects.isNull(userId)) {
+                userId = LoginUserHolder.getUserId();
+            }
+            KwsUser kwsUser = kwsUserDao.selectByKey(userId);
+            if (Objects.isNull(kwsUser)) {
+                throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.ACCOUNT_NOT_EXISTS);
+            }
+            //改为单一角色切换形式,获取当前激活的角色。
+            findMenuTreePojo.setRoleIds(Collections.singletonList(LoginUserHolder.getCurrentRoleId()));
             return;
         }
         //特殊处理,后面会做菜单关联

+ 33 - 1
sckw-modules/sckw-system/src/main/resources/mapper/KwsMenuDao.xml

@@ -299,7 +299,39 @@
     </if>
     ORDER BY sm.level, sm.sort
   </select>
-
+  <select id="findList1" resultType="com.sckw.system.model.vo.res.KwsMenuResVo"
+          parameterType="com.sckw.system.model.pojo.FindMenuTreePojo" >
+    select distinct
+    <include refid="Base_Column_List" />
+    from kws_menu sm
+    left join kws_menu_rights smr on sm.id = smr.menu_id
+    where sm.del_flag = 0 and  smr.del_flag = 0
+    <if test="clientType != null">
+      and sm.client_type = #{clientType}
+    </if>
+    <if test="name != null and name != ''">
+      and sm.name = #{name, jdbcType=VARCHAR}
+    </if>
+    <if test="entTypeList != null and entTypeList.size() > 0">
+      and
+      <foreach collection="entTypeList" item="item" open="(" close=")" separator=" or ">
+        using_roles like concat('%', #{item}, '%')
+      </foreach>
+    </if>
+    <if test="entId != null">
+      and smr.ent_id = #{entId}
+    </if>
+    <if test="roleIds != null and roleIds.size() > 0">
+      and smr.role_id in
+      <foreach collection="roleIds" separator="," open="(" close=")" item="item">
+        #{item}
+      </foreach>
+    </if>
+    <if test="type != null">
+      and sm.type = #{type}
+    </if>
+    ORDER BY sm.level, sm.sort
+  </select>
   <select id="selectByKeys" resultType="com.sckw.system.model.KwsMenu">
     select
     <include refid="Base_Column_List" />

+ 8 - 0
sckw-modules/sckw-system/src/main/resources/mapper/KwsMenuMappingDao.xml

@@ -56,4 +56,12 @@
         and a.del_flag = 0
     </select>
 
+    <select id="selectByMappingIds" resultType="com.sckw.system.model.KwsMenuMapping">
+        select a.* from kws_menu_mapping a where a.mapping_id in
+        <foreach collection="idList" item="item" open="(" close=")" separator=",">
+            #{item}
+        </foreach>
+        and a.del_flag = 0
+    </select>
+
 </mapper>