|
|
@@ -919,178 +919,284 @@ public class AuthServiceImpl implements IAuthService {
|
|
|
|| Objects.equals(clientType, ClientTypeEnum.mobile.getValue());
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
* 根据角色ID字典配置控制APP模块权限。
|
|
|
* <p>
|
|
|
* 该方法主要用于在登录或刷新Token时,根据当前用户的角色配置,动态设置APP端需要展示的模块(如订单统计、销售统计、钱包、地址管理等)。
|
|
|
* 仅在APP端登录时生效,PC/H5端不展示这些特定模块配置。
|
|
|
+ * </p>
|
|
|
*
|
|
|
* @param loginRes 登录返回信息对象,用于设置模块显示状态及钱包子项
|
|
|
* @param loginBase 登录请求基础信息,用于判断客户端类型
|
|
|
*/
|
|
|
private void applyAppModulePermissionsByConfig(LoginResVo1 loginRes, LoginBase loginBase) {
|
|
|
- // 1. 初始化默认值:隐藏所有特定模块,清空钱包子项
|
|
|
- // 确保在未匹配到任何角色或配置异常时,前端不会错误展示敏感或无关模块
|
|
|
+ // 1. 参数非空校验:若登录结果或登录参数为空,直接返回,避免NPE
|
|
|
+ if (Objects.isNull(loginRes) || Objects.isNull(loginBase)) {
|
|
|
+ log.debug("登录返回对象或登录参数为空,跳过APP模块权限配置");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 初始化默认状态:默认隐藏所有APP工作台模块,遵循“最小权限原则”,避免无菜单权限时前端误展示。
|
|
|
loginRes.setShowOrderStatisticsModule(Boolean.FALSE);
|
|
|
loginRes.setShowSalesStatisticsModule(Boolean.FALSE);
|
|
|
loginRes.setShowWalletModule(Boolean.FALSE);
|
|
|
loginRes.setShowAddressModule(Boolean.FALSE);
|
|
|
loginRes.setWalletModuleItems(Collections.emptyList());
|
|
|
|
|
|
- // 2. 校验客户端类型:仅对APP端(iOS/Android/Mobile)进行模块权限控制
|
|
|
+ // 3. 客户端类型校验:仅对APP端(iOS/Android/Mobile)进行模块权限配置,PC/H5端直接返回
|
|
|
if (!isAppLogin(loginBase)) {
|
|
|
log.debug("非APP端登录,跳过APP模块权限配置。clientType: {}", loginBase.getClientType());
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 3. 加载当前角色的APP权限配置
|
|
|
- // 从字典表 app_role_permission 中读取角色ID对应的权限标识
|
|
|
+ // 4. 获取角色ID并加载对应的APP菜单配置
|
|
|
Long roleId = loginRes.getRoleId();
|
|
|
- AppRoleConfig appRoleConfig = loadAppRoleConfig(roleId);
|
|
|
- log.info("开始配置APP模块权限 - userId: {}, roleId: {}, config: {}", loginRes.getId(), roleId, appRoleConfig.roleTypes);
|
|
|
+ log.debug("开始加载APP模块权限配置,userId: {}, roleId: {}", loginRes.getId(), roleId);
|
|
|
+
|
|
|
+ // 通过远程服务查询该角色在APP端的菜单权限列表
|
|
|
+ List<AppTabBarMenuResDto> appMenus = loadAppRoleMenus(roleId);
|
|
|
|
|
|
- // 4. 匹配角色类型并设置相应的模块显示状态
|
|
|
- boolean isSeller = appRoleConfig.match(AppRoleType.SELLER); // 销售/供应商
|
|
|
- boolean isFinance = appRoleConfig.match(AppRoleType.FINANCE); // 财务
|
|
|
- boolean isPurchase = appRoleConfig.match(AppRoleType.PURCHASE); // 采购/买家
|
|
|
+ // 5. 逐项判断模块权限:
|
|
|
+ // 使用多关键字匹配(中文名、英文名、下划线格式、驼峰格式等),提高匹配的兼容性和健壮性。
|
|
|
+
|
|
|
+ // 5.1 订单统计模块:检查菜单中是否包含“展示订单统计”或相关标识(orderStatistics等),决定前端是否显示该模块
|
|
|
+ boolean hasOrderStatistics = hasAppModuleMenu(appMenus, "\u5c55\u793a\u8ba2\u5355\u7edf\u8ba1", "orderStatistics", "order-statistics", "order_statistics");
|
|
|
+ log.debug("订单统计模块权限判断结果: {}", hasOrderStatistics);
|
|
|
+
|
|
|
+ // 5.2 销售统计模块:检查菜单中是否包含“展示销售统计”或相关标识(salesStatistics等),决定前端是否显示该模块
|
|
|
+ boolean hasSalesStatistics = hasAppModuleMenu(appMenus, "\u5c55\u793a\u9500\u552e\u7edf\u8ba1", "salesStatistics", "sales-statistics", "sales_statistics");
|
|
|
+ log.debug("销售统计模块权限判断结果: {}", hasSalesStatistics);
|
|
|
+
|
|
|
+ // 5.3 钱包模块:检查菜单中是否包含“展示钱包”或相关标识(wallet),决定前端是否显·示钱包入口
|
|
|
+ boolean hasWallet = hasAppModuleMenu(appMenus, "\u5c55\u793a\u94b1\u5305", "wallet");
|
|
|
+ log.debug("钱包模块权限判断结果: {}", hasWallet);
|
|
|
+
|
|
|
+ // 5.4 地址管理模块:检查菜单中是否包含“展示地址”或相关标识(address),决定前端是否显示地址管理入口
|
|
|
+ boolean hasAddress = hasAppModuleMenu(appMenus, "\u5c55\u793a\u5730\u5740", "address");
|
|
|
+ log.debug("地址管理模块权限判断结果: {}", hasAddress);
|
|
|
|
|
|
- // 4.1 销售/供应商角色权限
|
|
|
- // 展示:订单统计、销售统计
|
|
|
- if (isSeller) {
|
|
|
- log.info("用户角色匹配[SELLER],开启订单统计与销售统计模块");
|
|
|
- loginRes.setShowOrderStatisticsModule(Boolean.TRUE);
|
|
|
- loginRes.setShowSalesStatisticsModule(Boolean.TRUE);
|
|
|
- return;
|
|
|
- }
|
|
|
+ // 5.5 钱包子项 - 待履约保证金:检查菜单中是否包含“展示待履约保证金”或相关标识,用于控制钱包内子项显示
|
|
|
+ boolean hasPendingPerformance = hasAppModuleMenu(appMenus, "\u5c55\u793a\u5f85\u5c65\u7ea6\u4fdd\u8bc1\u91d1", "PENDING_PERFORMANCE_BALANCE", "pendingPerformanceBalance", "pending-performance-balance");
|
|
|
+ log.debug("待履约保证金子项权限判断结果: {}", hasPendingPerformance);
|
|
|
|
|
|
- // 4.2 财务角色权限
|
|
|
- // 展示:订单统计、钱包模块
|
|
|
- // 钱包子项:待履约保证金(PENDING_PERFORMANCE_BALANCE)、待付运费(PENDING_FREIGHT)
|
|
|
- if (isFinance) {
|
|
|
- log.info("用户角色匹配[FINANCE],开启订单统计与钱包模块(待履约保证金、待付运费)");
|
|
|
- loginRes.setShowOrderStatisticsModule(Boolean.TRUE);
|
|
|
- loginRes.setShowWalletModule(Boolean.TRUE);
|
|
|
- loginRes.setWalletModuleItems(Arrays.asList("PENDING_PERFORMANCE_BALANCE", "PENDING_FREIGHT"));
|
|
|
- return;
|
|
|
+ // 5.6 钱包子项 - 预付余额:检查菜单中是否包含“展示预付余额”或相关标识,用于控制钱包内子项显示
|
|
|
+ boolean hasPrepayBalance = hasAppModuleMenu(appMenus, "\u5c55\u793a\u9884\u4ed8\u4f59\u989d", "PREPAY_BALANCE", "prepayBalance", "prepay-balance");
|
|
|
+ log.debug("预付余额子项权限判断结果: {}", hasPrepayBalance);
|
|
|
+
|
|
|
+ // 5.7 钱包子项 - 待付运费:检查菜单中是否包含“展示待付运费”或相关标识,用于控制钱包内子项显示
|
|
|
+ boolean hasPendingFreight = hasAppModuleMenu(appMenus, "\u5c55\u793a\u5f85\u4ed8\u8fd0\u8d39", "PENDING_FREIGHT", "pendingFreight", "pending-freight");
|
|
|
+ log.debug("待付运费子项权限判断结果: {}", hasPendingFreight);
|
|
|
+
|
|
|
+ // 6. 应用权限配置到返回对象
|
|
|
+ loginRes.setShowOrderStatisticsModule(hasOrderStatistics);
|
|
|
+ loginRes.setShowSalesStatisticsModule(hasSalesStatistics);
|
|
|
+ loginRes.setShowWalletModule(hasWallet);
|
|
|
+ loginRes.setShowAddressModule(hasAddress);
|
|
|
+
|
|
|
+ // 若拥有钱包模块权限,则进一步构建钱包内部的子项列表
|
|
|
+ if (hasWallet) {
|
|
|
+ List<String> walletItems = buildWalletModuleItems(hasPendingPerformance, hasPrepayBalance, hasPendingFreight);
|
|
|
+ loginRes.setWalletModuleItems(walletItems);
|
|
|
+ log.debug("钱包模块开启,子项配置: {}", walletItems);
|
|
|
}
|
|
|
|
|
|
- // 4.3 采购/买家角色权限
|
|
|
- // 展示:订单统计、钱包模块、地址管理模块
|
|
|
- // 钱包子项:预付余额(PREPAY_BALANCE)、待付运费(PENDING_FREIGHT)
|
|
|
- if (isPurchase) {
|
|
|
- log.info("用户角色匹配[PURCHASE],开启订单统计、钱包模块(预付余额、待付运费)及地址管理模块");
|
|
|
- loginRes.setShowOrderStatisticsModule(Boolean.TRUE);
|
|
|
- loginRes.setShowWalletModule(Boolean.TRUE);
|
|
|
- loginRes.setShowAddressModule(Boolean.TRUE);
|
|
|
- loginRes.setWalletModuleItems(Arrays.asList("PREPAY_BALANCE", "PENDING_FREIGHT"));
|
|
|
- } else {
|
|
|
- // 未匹配到上述特定角色,保持默认隐藏状态
|
|
|
- log.debug("用户角色未匹配SELLER/FINANCE/PURCHASE,保持模块默认隐藏状态");
|
|
|
+ // 7. 记录最终配置结果日志,便于后续排查权限问题
|
|
|
+ log.info("APP模块权限配置完成 - userId: {}, roleId: {}, orderStats: {}, salesStats: {}, wallet: {}, address: {}",
|
|
|
+ loginRes.getId(), roleId, hasOrderStatistics, hasSalesStatistics, hasWallet, hasAddress);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据菜单授权结果构建钱包模块子项。
|
|
|
+ *
|
|
|
+ * @param hasPendingPerformance 是否包含待履约保证金菜单
|
|
|
+ * @param hasPrepayBalance 是否包含预付余额菜单
|
|
|
+ * @param hasPendingFreight 是否包含待付运费菜单
|
|
|
+ * @return 钱包模块子项编码列表
|
|
|
+ */
|
|
|
+ List<String> buildWalletModuleItems(boolean hasPendingPerformance, boolean hasPrepayBalance, boolean hasPendingFreight) {
|
|
|
+ List<String> walletItems = new ArrayList<>();
|
|
|
+ if (hasPendingPerformance) {
|
|
|
+ walletItems.add("PENDING_PERFORMANCE_BALANCE");
|
|
|
}
|
|
|
+ if (hasPrepayBalance) {
|
|
|
+ walletItems.add("PREPAY_BALANCE");
|
|
|
+ }
|
|
|
+ if (hasPendingFreight || hasPendingPerformance || hasPrepayBalance) {
|
|
|
+ walletItems.add("PENDING_FREIGHT");
|
|
|
+ }
|
|
|
+ return walletItems;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 加载角色APP菜单。
|
|
|
+ *
|
|
|
+ * @param roleId 角色ID
|
|
|
+ * @return APP菜单列表
|
|
|
+ */
|
|
|
+ /**
|
|
|
+ * 加载指定角色的APP底部导航菜单配置。
|
|
|
+ * <p>
|
|
|
+ * 该方法通过远程服务查询角色对应的APP TabBar菜单权限,用于动态构建APP端底部导航栏。
|
|
|
+ * 若角色ID为空、查询结果为空或发生异常,均返回空列表,确保前端展示默认状态或不展示导航栏,避免影响登录流程。
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param roleId 角色ID,用于查询对应的APP底部导航配置
|
|
|
+ * @return APP底部导航菜单项列表,若无配置或查询失败则返回空列表
|
|
|
+ */
|
|
|
+ List<AppTabBarMenuResDto> loadAppRoleMenus(Long roleId) {
|
|
|
+ // 1. 参数校验:若角色ID为空,直接返回空列表,避免无效远程调用
|
|
|
+ if (Objects.isNull(roleId)) {
|
|
|
+ log.debug("角色ID为空,跳过APP角色菜单查询");
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 2. 记录开始查询日志,便于追踪性能和问题
|
|
|
+ log.debug("开始查询APP角色菜单,roleId: {}", roleId);
|
|
|
+
|
|
|
+ // 3. 远程调用系统服务,获取角色对应的APP底部导航菜单配置
|
|
|
+ List<AppTabBarMenuResDto> menus = remoteUserService.queryAppTabBarMenuByRoleId(roleId);
|
|
|
+
|
|
|
+ // 4. 结果校验:若返回结果为空或无数据,记录调试日志并返回空列表
|
|
|
+ if (org.apache.commons.collections4.CollectionUtils.isEmpty(menus)) {
|
|
|
+ log.debug("角色未配置APP底部导航菜单,roleId: {}", roleId);
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 记录成功查询日志,包含菜单数量信息
|
|
|
+ log.info("APP角色菜单查询成功,roleId: {}, 菜单数量: {}", roleId, menus.size());
|
|
|
+ return menus;
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 6. 异常处理:记录错误日志,防止因远程服务异常导致登录流程中断
|
|
|
+ // 返回空列表,前端可根据此情况展示默认导航或隐藏导航栏
|
|
|
+ log.error("查询APP角色菜单失败,roleId: {}", roleId, e);
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
- * 根据角色ID字典配置构建APP底部导航。
|
|
|
+ * 判断角色菜单中是否包含指定APP模块。
|
|
|
*
|
|
|
- * @param loginRes 登录返回信息,用于设置角色名称等上下文信息
|
|
|
- * @param loginBase 登录请求信息,用于判断客户端类型
|
|
|
- * @param roleName 当前角色名称,仅作为未配置字典时的兼容兜底(本方法主要依赖 roleId)
|
|
|
- * @param flag 预留参数,兼容原方法签名,暂未使用
|
|
|
- * @param entTypeNames 企业类型标识(1:供应商, 2:采购商, 3:4PL物流),用于区分特定管理员角色
|
|
|
- * @return APP底部导航配置列表,若非APP端登录或无匹配角色则返回空列表
|
|
|
+ * @param menus APP菜单列表
|
|
|
+ * @param keywords 模块关键字
|
|
|
+ * @return true-包含,false-不包含
|
|
|
*/
|
|
|
+ boolean hasAppModuleMenu(List<AppTabBarMenuResDto> menus, String... keywords) {
|
|
|
+ if (org.apache.commons.collections4.CollectionUtils.isEmpty(menus) || Objects.isNull(keywords)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return menus.stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .anyMatch(menu -> Arrays.stream(keywords)
|
|
|
+ .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
|
|
|
+ .anyMatch(keyword -> containsIgnoreCase(menu.getName(), keyword)
|
|
|
+ || containsIgnoreCase(menu.getPerms(), keyword)
|
|
|
+ || containsIgnoreCase(menu.getUrl(), keyword)));
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean containsIgnoreCase(String source, String keyword) {
|
|
|
+ return org.apache.commons.lang3.StringUtils.isNotBlank(source)
|
|
|
+ && org.apache.commons.lang3.StringUtils.containsIgnoreCase(source, keyword);
|
|
|
+ }
|
|
|
+
|
|
|
private List<LoginResVo1.TabBarItem> buildAppTabBarByConfig(LoginResVo1 loginRes, LoginBase loginBase,
|
|
|
String roleName, int flag, String entTypeNames) {
|
|
|
// 优先使用登录结果中的角色名称,若为空则使用传入的参数
|
|
|
+ if (Objects.isNull(loginRes)) {
|
|
|
+ log.debug("登录返回对象为空,跳过APP底部导航菜单查询");
|
|
|
+ return List.of();
|
|
|
+ }
|
|
|
roleName = org.apache.commons.lang3.StringUtils.defaultIfBlank(loginRes.getRoleName(), roleName);
|
|
|
|
|
|
// 记录关键上下文信息,便于排查角色匹配问题
|
|
|
log.info("构建APP TabBar - 角色ID:{},角色名称:{},企业类型:{}", loginRes.getRoleId(), roleName, entTypeNames);
|
|
|
|
|
|
// 非APP端登录(如PC、H5等)不展示底部导航
|
|
|
+ // 校验客户端类型:仅对APP端(iOS/Android/Mobile)构建底部导航,PC/H5端返回空列表
|
|
|
if (!isAppLogin(loginBase)) {
|
|
|
+ log.debug("非APP端登录(clientType: {}),跳过APP底部导航构建", loginBase.getClientType());
|
|
|
return List.of();
|
|
|
}
|
|
|
|
|
|
- // 加载基于字典配置的角色权限映射
|
|
|
- AppRoleConfig appRoleConfig = loadAppRoleConfig(loginRes.getRoleId());
|
|
|
-
|
|
|
- // 1. 采购员角色:直接返回买家导航
|
|
|
- if (appRoleConfig.match(AppRoleType.PURCHASE)) {
|
|
|
- return buildBuyerTabBar();
|
|
|
- }
|
|
|
+ Long roleId = loginRes.getRoleId();
|
|
|
+ log.info("开始构建APP底部导航 - userId: {}, roleId: {}", loginRes.getId(), roleId);
|
|
|
|
|
|
- // 2. 解析具体角色标识
|
|
|
- boolean isDoorKeeper = appRoleConfig.match(AppRoleType.DOOR_KEEPER); // 门卫
|
|
|
- boolean isForkliftDriver = appRoleConfig.match(AppRoleType.FORKLIFT_DRIVER); // 叉车司机
|
|
|
- boolean isBuyer = appRoleConfig.match(AppRoleType.BUYER); // 买家
|
|
|
- boolean isSeller = appRoleConfig.match(AppRoleType.SELLER); // 销售/供应商
|
|
|
- boolean isDriver = appRoleConfig.match(AppRoleType.DRIVER); // 司机
|
|
|
- boolean isLogistics = appRoleConfig.match(AppRoleType.LOGISTICS); // 物流人员
|
|
|
- boolean isFinance = appRoleConfig.match(AppRoleType.FINANCE); // 财务
|
|
|
-
|
|
|
- // 3. 解析特定企业管理员角色(需同时满足角色标识和企业类型)
|
|
|
- // 供应商管理员:角色匹配且企业类型为"1"
|
|
|
- boolean isSupplierAdmin = appRoleConfig.match(AppRoleType.SUPPLIER_ADMIN)
|
|
|
- && org.apache.commons.lang3.StringUtils.equals(entTypeNames, "1");
|
|
|
- // 物流商管理员:角色匹配且企业类型为"3"
|
|
|
- boolean isLogisticsAdmin = appRoleConfig.match(AppRoleType.LOGISTICS_ADMIN)
|
|
|
- && org.apache.commons.lang3.StringUtils.equals(entTypeNames, "3");
|
|
|
- // 采购商管理员:角色匹配且企业类型为"2"
|
|
|
- boolean isPurchaseAdmin = appRoleConfig.match(AppRoleType.PURCHASE_ADMIN)
|
|
|
- && org.apache.commons.lang3.StringUtils.equals(entTypeNames, "2");
|
|
|
-
|
|
|
- // 4. 按优先级匹配并返回对应的TabBar配置
|
|
|
- if (isDoorKeeper) {
|
|
|
- return buildDoorKeeperTabBar();
|
|
|
- }
|
|
|
- if (isForkliftDriver) {
|
|
|
- return buildForkliftDriverTabBar();
|
|
|
- }
|
|
|
- if (isBuyer) {
|
|
|
- return buildBuyerTabBar();
|
|
|
- }
|
|
|
- // 销售或财务共用卖家导航
|
|
|
- if (isSeller || isFinance) {
|
|
|
- return buildSellerTabBar();
|
|
|
- }
|
|
|
- if (isDriver) {
|
|
|
- return buildDefaultDriverTabBar();
|
|
|
- }
|
|
|
- if (isLogistics) {
|
|
|
- return buildLogisticsTabBar();
|
|
|
- }
|
|
|
+ // 从角色菜单权限加载APP底部导航,替代原有的硬编码字典配置,实现动态配置
|
|
|
+ List<LoginResVo1.TabBarItem> tabBarItems = buildAppTabBarByRoleMenus(roleId);
|
|
|
|
|
|
- // 5. 处理特定管理员角色,并修正显示的角色名称
|
|
|
- if (isSupplierAdmin) {
|
|
|
- loginRes.setRoleName("供应商管理员");
|
|
|
- return buildSupplierAdminTabBar();
|
|
|
- }
|
|
|
- if (isLogisticsAdmin) {
|
|
|
- loginRes.setRoleName("物流商管理员");
|
|
|
- return buildLogisticsAdminTabBar();
|
|
|
- }
|
|
|
- if (isPurchaseAdmin) {
|
|
|
- log.info("用户角色配置为采购管理员且企业属性为采购商,返回采购管理员TabBar");
|
|
|
- loginRes.setRoleName("采购商管理员");
|
|
|
- return buildPurchaseAdminTabBar();
|
|
|
- }
|
|
|
-
|
|
|
- // 未匹配到任何已知角色,返回空列表
|
|
|
- return List.of();
|
|
|
+ log.info("APP底部导航构建完成 - userId: {}, roleId: {}, 菜单数量: {}",
|
|
|
+ loginRes.getId(), roleId, tabBarItems != null ? tabBarItems.size() : 0);
|
|
|
+
|
|
|
+ return tabBarItems;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * 加载APP角色权限配置。
|
|
|
+ * 根据角色ID查询并构建APP底部导航栏菜单项。
|
|
|
* <p>
|
|
|
- * 该方法从系统字典服务中查询类型为 {@link DictTypeEnum#APP_ROLE_PERMISSION} 的字典项,
|
|
|
- * 并将其转换为 {@link AppRoleConfig} 对象,用于后续判断当前用户角色对应的APP端权限(如TabBar显示、模块可见性等)。
|
|
|
+ * 该方法通过远程服务获取指定角色配置的APP底部导航菜单数据,
|
|
|
+ * 并将其转换为前端所需的TabBarItem对象列表。
|
|
|
+ * 若角色ID为空、未配置菜单或查询异常,则返回空列表,确保前端展示默认状态或不展示底部导航。
|
|
|
* </p>
|
|
|
*
|
|
|
- * @param roleId 当前登录用户的角色ID
|
|
|
- * @return {@link AppRoleConfig} 包含该角色匹配的APP角色类型集合;若roleId为空或查询异常,则返回空配置
|
|
|
+ * @param roleId 角色ID,用于查询对应的APP底部导航配置
|
|
|
+ * @return APP底部导航菜单项列表,若无配置或查询失败则返回空列表
|
|
|
+ */
|
|
|
+ List<LoginResVo1.TabBarItem> buildAppTabBarByRoleMenus(Long roleId) {
|
|
|
+ // 1. 参数校验:若角色ID为空,直接返回空列表,避免无效远程调用
|
|
|
+ if (Objects.isNull(roleId)) {
|
|
|
+ log.debug("角色ID为空,跳过APP底部导航菜单查询");
|
|
|
+ return List.of();
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 2. 记录开始查询日志,便于追踪性能和问题
|
|
|
+ log.debug("开始查询APP底部导航菜单,roleId: {}", roleId);
|
|
|
+
|
|
|
+ // 3. 远程调用系统服务,获取角色对应的APP底部导航菜单配置
|
|
|
+ List<AppTabBarMenuResDto> menus = remoteUserService.queryAppTabBarMenuByRoleId(roleId);
|
|
|
+
|
|
|
+ // 4. 结果校验:若返回结果为空或无数据,记录调试日志并返回空列表
|
|
|
+ if (org.apache.commons.collections4.CollectionUtils.isEmpty(menus)) {
|
|
|
+ log.debug("角色未配置APP底部导航菜单,roleId: {}", roleId);
|
|
|
+ return List.of();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 数据转换:将DTO列表转换为前端所需的TabBarItem对象列表
|
|
|
+ // 过滤掉null对象,并对每个菜单项进行字段默认值处理(防止前端展示空白)
|
|
|
+ List<LoginResVo1.TabBarItem> tabBarItems = menus.stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .map(menu -> buildTabBarItem(
|
|
|
+ // 菜单名称,若为空则默认为空字符串
|
|
|
+ org.apache.commons.lang3.StringUtils.defaultString(menu.getName()),
|
|
|
+ // 选中图标路径,若为空则默认为空字符串
|
|
|
+ org.apache.commons.lang3.StringUtils.defaultString(menu.getIcon()),
|
|
|
+ // 未选中图标路径,若为空则默认为空字符串
|
|
|
+ org.apache.commons.lang3.StringUtils.defaultString(menu.getNotSelectedIconPath()),
|
|
|
+ // 页面路由地址,若为空则默认为空字符串
|
|
|
+ org.apache.commons.lang3.StringUtils.defaultString(menu.getUrl())))
|
|
|
+ .toList();
|
|
|
+
|
|
|
+ // 6. 记录成功构建日志,包含菜单数量信息
|
|
|
+ log.info("APP底部导航菜单构建成功,roleId: {}, 菜单数量: {}", roleId, tabBarItems.size());
|
|
|
+ return tabBarItems;
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 7. 异常处理:记录错误日志,防止因远程服务异常导致登录流程中断
|
|
|
+ // 返回空列表,前端可根据此情况展示默认导航或隐藏导航栏
|
|
|
+ log.error("查询APP底部导航菜单失败,roleId: {}", roleId, e);
|
|
|
+ return List.of();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加载APP模块权限角色配置。
|
|
|
+ *
|
|
|
+ * @param roleId 角色ID
|
|
|
+ * @return APP角色配置
|
|
|
*/
|
|
|
private AppRoleConfig loadAppRoleConfig(Long roleId) {
|
|
|
// 1. 参数校验:若角色ID为空,直接返回空配置,避免无效查询
|