chenxiaofei 5 tuntia sitten
vanhempi
commit
c433720639

+ 33 - 6
sckw-auth/src/main/java/com/sckw/auth/service/impl/AuthServiceImpl.java

@@ -1174,6 +1174,10 @@ public class AuthServiceImpl implements IAuthService {
             log.debug("登录返回对象为空,跳过APP底部导航菜单查询");
             return List.of();
         }
+        if (!Objects.equals(loginBase.getClientType(), ClientTypeEnum.app.getValue())) {
+            log.info("非APP端登录,跳过APP底部导航菜单查询");
+            return List.of();
+        }
         roleName = org.apache.commons.lang3.StringUtils.defaultIfBlank(loginRes.getRoleName(), roleName);
         
         // 记录关键上下文信息,便于排查角色匹配问题
@@ -1190,7 +1194,7 @@ public class AuthServiceImpl implements IAuthService {
         log.info("开始构建APP底部导航 - userId: {}, roleId: {}", loginRes.getId(), roleId);
 
         // 从角色菜单权限加载APP底部导航,替代原有的硬编码字典配置,实现动态配置
-        List<LoginResVo1.TabBarItem> tabBarItems = buildAppTabBarByRoleMenus(roleId);
+        List<LoginResVo1.TabBarItem> tabBarItems = buildAppTabBarByRoleMenus(roleId, loginBase.getClientType());
         
         log.info("APP底部导航构建完成 - userId: {}, roleId: {}, 菜单数量: {}", 
                 loginRes.getId(), roleId, tabBarItems != null ? tabBarItems.size() : 0);
@@ -1207,10 +1211,11 @@ public class AuthServiceImpl implements IAuthService {
      * 若角色ID为空、未配置菜单或查询异常,则返回空列表,确保前端展示默认状态或不展示底部导航。
      * </p>
      *
-     * @param roleId 角色ID,用于查询对应的APP底部导航配置
+     * @param roleId     角色ID,用于查询对应的APP底部导航配置
+     * @param clientType 客户端类型
      * @return APP底部导航菜单项列表,若无配置或查询失败则返回空列表
      */
-    List<LoginResVo1.TabBarItem> buildAppTabBarByRoleMenus(Long roleId) {
+    List<LoginResVo1.TabBarItem> buildAppTabBarByRoleMenus(Long roleId, String clientType) {
         // 1. 参数校验:若角色ID为空,直接返回空列表,避免无效远程调用
         if (Objects.isNull(roleId)) {
             log.debug("角色ID为空,跳过APP底部导航菜单查询");
@@ -1219,10 +1224,11 @@ public class AuthServiceImpl implements IAuthService {
 
         try {
             // 2. 记录开始查询日志,便于追踪性能和问题
-            log.debug("开始查询APP底部导航菜单,roleId: {}", roleId);
+            log.debug("开始查询APP底部导航菜单,roleId: {}, clientType: {}", roleId, clientType);
 
             // 3. 远程调用系统服务,获取角色对应的APP底部导航菜单配置
             List<AppTabBarMenuResDto> menus = remoteUserService.queryAppTabBarMenuByRoleId(roleId);
+            menus = filterAppClientMenus(menus, clientType);
 
             // 4. 结果校验:若返回结果为空或无数据,记录调试日志并返回空列表
             if (org.apache.commons.collections4.CollectionUtils.isEmpty(menus)) {
@@ -1247,17 +1253,38 @@ public class AuthServiceImpl implements IAuthService {
                     .toList();
 
             // 6. 记录成功构建日志,包含菜单数量信息
-            log.info("APP底部导航菜单构建成功,roleId: {}, 菜单数量: {}", roleId, tabBarItems.size());
+            log.info("APP底部导航菜单构建成功,roleId: {}, clientType: {}, 菜单数量: {}", roleId, clientType, tabBarItems.size());
             return tabBarItems;
 
         } catch (Exception e) {
             // 7. 异常处理:记录错误日志,防止因远程服务异常导致登录流程中断
             // 返回空列表,前端可根据此情况展示默认导航或隐藏导航栏
-            log.error("查询APP底部导航菜单失败,roleId: {}", roleId, e);
+            log.error("查询APP底部导航菜单失败,roleId: {}, clientType: {}", roleId, clientType, e);
             return List.of();
         }
     }
 
+    /**
+     * APP端登录时仅保留APP终端菜单(kws_menu.client_type = 3)。
+     *
+     * @param menus      角色菜单列表
+     * @param clientType 前端传入的客户端类型
+     * @return 过滤后的菜单列表
+     */
+    static List<AppTabBarMenuResDto> filterAppClientMenus(List<AppTabBarMenuResDto> menus, String clientType) {
+        if (!Objects.equals(clientType, ClientTypeEnum.app.getValue())
+                || org.apache.commons.collections4.CollectionUtils.isEmpty(menus)) {
+            return menus;
+        }
+        List<AppTabBarMenuResDto> appMenus = menus.stream()
+                .filter(Objects::nonNull)
+                .filter(menu -> Objects.equals(menu.getClientType(), Global.NUMERICAL_THREE))
+                .toList();
+        log.debug("APP端菜单过滤完成,clientType: {}, 原数量: {}, 过滤后数量: {}",
+                clientType, menus.size(), appMenus.size());
+        return appMenus;
+    }
+
     /**
      * 加载APP模块权限角色配置。
      *

+ 44 - 2
sckw-auth/src/test/java/com/sckw/auth/service/impl/AuthServiceImplTest.java

@@ -3,6 +3,7 @@ package com.sckw.auth.service.impl;
 import com.sckw.auth.model.vo.req.LoginBase;
 import com.sckw.auth.model.vo.res.LoginResVo1;
 import com.sckw.system.api.model.dto.res.SysDictResDto;
+import com.sckw.core.model.constant.Global;
 import com.sckw.system.api.RemoteUserService;
 import com.sckw.system.api.model.dto.res.AppTabBarMenuResDto;
 import org.junit.Assert;
@@ -59,7 +60,7 @@ public class AuthServiceImplTest {
         setRemoteUserService(authService, buildRemoteUserServiceProxy());
 
         List<com.sckw.auth.model.vo.res.LoginResVo1.TabBarItem> tabBarItems =
-                authService.buildAppTabBarByRoleMenus(1001L);
+                authService.buildAppTabBarByRoleMenus(1001L, "app");
 
         Assert.assertEquals(1, tabBarItems.size());
         com.sckw.auth.model.vo.res.LoginResVo1.TabBarItem item = tabBarItems.get(0);
@@ -105,15 +106,55 @@ public class AuthServiceImplTest {
         homeMenu.setIcon("/static/icon/home-selected.png");
         homeMenu.setNotSelectedIconPath("/static/icon/home.png");
         homeMenu.setUrl("/pages/home/index");
+        homeMenu.setClientType(Global.NUMERICAL_THREE);
         setRemoteUserService(authService, buildRemoteUserServiceProxy(
                 homeMenu, buildOrderStatisticsMenu(), buildWalletMenu(), buildAddressMenu()));
 
-        List<LoginResVo1.TabBarItem> tabBarItems = authService.buildAppTabBarByRoleMenus(1001L);
+        List<LoginResVo1.TabBarItem> tabBarItems = authService.buildAppTabBarByRoleMenus(1001L, "app");
 
         Assert.assertEquals(1, tabBarItems.size());
         Assert.assertEquals("首页", tabBarItems.get(0).getText());
     }
 
+    /**
+     * 验证APP端登录时仅保留APP终端菜单,过滤PC等其他终端菜单。
+     */
+    @Test
+    public void filterAppClientMenusShouldKeepOnlyAppMenusWhenClientTypeIsApp() {
+        AppTabBarMenuResDto appMenu = new AppTabBarMenuResDto();
+        appMenu.setName("首页");
+        appMenu.setClientType(Global.NUMERICAL_THREE);
+
+        AppTabBarMenuResDto pcMenu = new AppTabBarMenuResDto();
+        pcMenu.setName("PC首页");
+        pcMenu.setClientType(Global.NUMERICAL_TWO);
+
+        List<AppTabBarMenuResDto> filtered = AuthServiceImpl.filterAppClientMenus(
+                Arrays.asList(appMenu, pcMenu), "app");
+
+        Assert.assertEquals(1, filtered.size());
+        Assert.assertEquals("首页", filtered.get(0).getName());
+    }
+
+    /**
+     * 验证非APP端客户端类型不做菜单终端过滤。
+     */
+    @Test
+    public void filterAppClientMenusShouldSkipWhenClientTypeIsNotApp() {
+        AppTabBarMenuResDto appMenu = new AppTabBarMenuResDto();
+        appMenu.setName("首页");
+        appMenu.setClientType(Global.NUMERICAL_THREE);
+
+        AppTabBarMenuResDto pcMenu = new AppTabBarMenuResDto();
+        pcMenu.setName("PC首页");
+        pcMenu.setClientType(Global.NUMERICAL_TWO);
+
+        List<AppTabBarMenuResDto> menus = Arrays.asList(appMenu, pcMenu);
+        List<AppTabBarMenuResDto> filtered = AuthServiceImpl.filterAppClientMenus(menus, "pc");
+
+        Assert.assertEquals(2, filtered.size());
+    }
+
     /**
      * 验证钱包、地址模块只由菜单结果控制,并按菜单子项返回钱包展示项。
      */
@@ -154,6 +195,7 @@ public class AuthServiceImplTest {
         menu.setIcon("/static/icon/home-selected.png");
         menu.setNotSelectedIconPath("/static/icon/home.png");
         menu.setUrl("/pages/home/index");
+        menu.setClientType(Global.NUMERICAL_THREE);
         return buildRemoteUserServiceProxy(menu);
     }
 

+ 5 - 0
sckw-modules-api/sckw-system-api/src/main/java/com/sckw/system/api/model/dto/res/AppTabBarMenuResDto.java

@@ -44,6 +44,11 @@ public class AppTabBarMenuResDto implements Serializable {
      */
     private String notSelectedIconPath;
 
+    /**
+     * 客户端类型
+     */
+    private Integer clientType;
+
     /**
      * 排序
      */

+ 37 - 24
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/operateService/KwcContractTradeService.java

@@ -322,7 +322,7 @@ public class KwcContractTradeService {
         KwcContractTrade kwcContractTrade = getKwcContractTrade(baseInfo, reqVo.getGoodsInfo(), reqVo.getRemark(), reqVo.getPid());
         long contactId = new IdWorker(1L).nextId();
         kwcContractTrade.setId(contactId);
-        kwcContractTrade.setAgentFlag(querySupplyAgentFlag(baseInfo.getProvideEntId()));
+        kwcContractTrade.setAgentFlag(querySupplyAgentFlag( baseInfo.getAgentEntId()));
         EntCacheResDto entCacheResDto = remoteSystemService.queryEntTreeById(LoginUserHolder.getEntId());
         if (Objects.nonNull(entCacheResDto) && StringUtils.isNotBlank(entCacheResDto.getEntTypes())) {
             if (org.apache.commons.lang3.StringUtils.equals(entCacheResDto.getEntTypes(), String.valueOf(EntTypeEnum.SUPPLIER.getCode()))) {
@@ -533,24 +533,31 @@ public class KwcContractTradeService {
     }
 
     /**
-     * 根据供应单位企业属性计算贸易合同代理标记。
+     * 计算贸易合同代理标记。
+     * <p>
+     * 已选择代理单位时,代理属性为是;
+     * 未选择代理单位时,根据供应单位企业属性是否包含代理属性判断。
+     * </p>
      *
-     * @param supplyEntId 供应单位ID
-     * @return 0-否,1-是
+     * @param agentEntId  代理单位ID
+     * @return 代理标识:1-是代理,0-非代理
+     * @throws BusinessException 当供应单位ID为空或查询远程服务异常时抛出
      */
+    private Integer querySupplyAgentFlag( Long agentEntId) {
+        if (Objects.nonNull(agentEntId)) {
+            log.debug("已选择代理单位,代理属性为是,agentEntId: {}", agentEntId);
+            return Global.YES;
+        }
+        return Global.NO;
+    }
+
     /**
-     * 查询供应单位是否具备代理属性。
-     * <p>
-     * 通过远程服务获取企业属性信息,判断该企业是否被标记为“供应单位代理”。
-     * 如果具备代理属性,返回 Global.YES (1),否则返回 Global.NO (0)。
-     * </p>
+     * 根据供应单位企业属性查询是否具备代理属性。
      *
      * @param supplyEntId 供应单位ID
      * @return 代理标识:1-是代理,0-非代理
-     * @throws BusinessException 当供应单位ID为空或查询远程服务异常时抛出
      */
-    private Integer querySupplyAgentFlag(Long supplyEntId) {
-        // 参数校验:供应单位ID不能为空
+    private Integer querySupplyEntAgentFlag(Long supplyEntId) {
         if (Objects.isNull(supplyEntId)) {
             log.warn("查询供应单位代理属性失败,原因:供应单位ID为空");
             throw new BusinessException("供应单位不能为空");
@@ -558,27 +565,33 @@ public class KwcContractTradeService {
 
         try {
             log.debug("开始查询供应单位代理属性,supplyEntId: {}", supplyEntId);
-
-            // 调用远程系统服务查询企业属性类型列表
             List<EntTypeResDto> entTypeList = remoteSystemService.queryEntTypeByIds(Collections.singleton(supplyEntId));
-
-            // 判断是否包含代理属性类型
-            boolean isAgent = hasSupplyAgentAttribute(entTypeList, supplyEntId);
-            Integer result = isAgent ? Global.YES : Global.NO;
-
+            Integer result = resolveSupplyAgentFlag(supplyEntId, null, entTypeList);
             log.debug("供应单位代理属性查询完成,supplyEntId: {}, 结果: {}", supplyEntId, result);
             return result;
-
         } catch (BusinessException e) {
-            // 业务异常直接抛出,避免重复包装
             throw e;
         } catch (Exception e) {
-            // 捕获其他异常(如网络超时、远程服务错误等),记录详细日志并抛出通用业务异常
             log.error("查询供应单位代理属性发生系统异常,supplyEntId: {}", supplyEntId, e);
             throw new BusinessException("查询供应单位代理属性失败");
         }
     }
 
+    /**
+     * 解析贸易合同代理标记。
+     *
+     * @param supplyEntId 供应单位ID
+     * @param agentEntId  代理单位ID
+     * @param entTypeList 企业属性集合
+     * @return 代理标识:1-是代理,0-非代理
+     */
+    static Integer resolveSupplyAgentFlag(Long supplyEntId, Long agentEntId, List<EntTypeResDto> entTypeList) {
+        if (Objects.nonNull(agentEntId)) {
+            return Global.YES;
+        }
+        return hasSupplyAgentAttribute(entTypeList, supplyEntId) ? Global.YES : Global.NO;
+    }
+
     /**
      * 判断指定供应单位是否具备代理属性。
      * <p>
@@ -940,7 +953,7 @@ public class KwcContractTradeService {
         kwcContractTrade.setSalesmanId(baseInfo.getSalesmanId());
         kwcContractTrade.setSalesmanPhone(baseInfo.getSalesmanPhone());
         kwcContractTrade.setDispatchWay(baseInfo.getDispatchWay());
-        kwcContractTrade.setAgentFlag(querySupplyAgentFlag(baseInfo.getProvideEntId()));
+        kwcContractTrade.setAgentFlag(querySupplyAgentFlag( baseInfo.getAgentEntId()));
         List<TradeGoodsInfoReqVo> goodsInfo = reqVo.getGoodsInfo();
         BigDecimal amountTotal = new BigDecimal(Global.NUMERICAL_ZERO);
         if (CollectionUtils.isNotEmpty(goodsInfo)) {
@@ -1480,7 +1493,7 @@ public class KwcContractTradeService {
         kwcContractTrade.setSalesmanId(baseInfo.getSalesmanId());
         kwcContractTrade.setSalesmanPhone(baseInfo.getSalesmanPhone());
         kwcContractTrade.setDispatchWay(baseInfo.getDispatchWay());
-        kwcContractTrade.setAgentFlag(querySupplyAgentFlag(baseInfo.getProvideEntId()));
+        kwcContractTrade.setAgentFlag(querySupplyAgentFlag(baseInfo.getAgentEntId()));
 
 
         BigDecimal amountTotal = new BigDecimal(Global.NUMERICAL_ZERO);

+ 41 - 0
sckw-modules/sckw-contract/src/test/java/com/sckw/contract/service/operateService/KwcContractTradeServiceTest.java

@@ -2,6 +2,7 @@ package com.sckw.contract.service.operateService;
 
 import com.sckw.contract.model.vo.req.TradeBaseInfoReqVo;
 import com.sckw.contract.service.KwcContractTradeUnitService;
+import com.sckw.core.model.constant.Global;
 import com.sckw.core.exception.SystemException;
 import com.sckw.system.api.model.dto.res.EntTypeResDto;
 import org.junit.Assert;
@@ -86,6 +87,46 @@ public class KwcContractTradeServiceTest {
         KwcContractTradeService.validateAgentUnitParam(null, "13800000000");
     }
 
+    /**
+     * 已选择代理单位时,代理属性为是。
+     */
+    @Test
+    public void resolveSupplyAgentFlagWhenAgentEntIdPresent() {
+        Integer result = KwcContractTradeService.resolveSupplyAgentFlag(1001L, 3001L, Collections.emptyList());
+
+        Assert.assertEquals(Global.YES, result.intValue());
+    }
+
+    /**
+     * 未选择代理单位时,根据供应单位企业属性判断是否具备代理属性。
+     */
+    @Test
+    public void resolveSupplyAgentFlagWhenAgentEntIdAbsentAndSupplyHasAgentType() {
+        EntTypeResDto agentType = new EntTypeResDto();
+        agentType.setEntId(1001L);
+        agentType.setType(4);
+
+        Integer result = KwcContractTradeService.resolveSupplyAgentFlag(1001L, null,
+                Collections.singletonList(agentType));
+
+        Assert.assertEquals(Global.YES, result.intValue());
+    }
+
+    /**
+     * 未选择代理单位且供应单位不具备代理属性时,代理属性为否。
+     */
+    @Test
+    public void resolveSupplyAgentFlagWhenAgentEntIdAbsentAndSupplyHasNoAgentType() {
+        EntTypeResDto supplierType = new EntTypeResDto();
+        supplierType.setEntId(1001L);
+        supplierType.setType(1);
+
+        Integer result = KwcContractTradeService.resolveSupplyAgentFlag(1001L, null,
+                Collections.singletonList(supplierType));
+
+        Assert.assertEquals(Global.NO, result.intValue());
+    }
+
     /**
      * 销售合同代理单位落库类型固定为3。
      */

+ 5 - 2
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/AbstractWaybillOrderHandler.java

@@ -113,7 +113,10 @@ public abstract class AbstractWaybillOrderHandler<T extends WaybillOrderProcessP
 
             log.info("{}处理完成", getProcessName());
             return handlerResult;
-        } finally {
+        } catch (Exception e) {
+            log.error("运单处理器异常!", e);
+            throw new BusinessPlatfromException(ErrorCodeEnum.SYSTEM_ERROR, e.getMessage());
+        }  finally {
             // 确保清理线程上下文,防止内存泄漏
             BusinessContext.clear();
         }
@@ -137,7 +140,7 @@ public abstract class AbstractWaybillOrderHandler<T extends WaybillOrderProcessP
         }
         // 过磅校验
         if (param instanceof WaybillOrderCmeIntoWeighParam) {
-            if (param.getWeighbridgeId() == null || param.getWeighbridgeName() == null || param.getWeighUrl() == null) {
+            if (param.getWeighbridgeId() == null || param.getWeighbridgeName() == null) {
                 throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "地磅信息不能为空");
             }
         }

+ 0 - 1
sql/2026/06/2026_06_11_app_tabbar_menu_permission.sql

@@ -14,5 +14,4 @@ INSERT INTO sckw_ng_system.kws_menu (id, client_type, parent_id, name, type, url
 INSERT INTO sckw_ng_system.kws_menu (id, client_type, parent_id, name, type, url, perms, icon, not_selected_icon_path, sort, level, custom, links, is_display, is_main, using_roles, remark, status, create_by, create_time, update_by, update_time, del_flag) VALUES (545583282163552256, 3, 0, '个人中心', 1, '/pages/myCenter/index', 'app:tabbar:my', '/static/tabbar/my_select.png', '/static/tabbar/my.png', 154, 1, 0, null, null, 0, '', null, 0, 156383116720607232, '2026-06-11 11:09:10', 156383116720607232, '2026-06-11 11:09:10', 0);
 INSERT INTO sckw_ng_system.kws_menu (id, client_type, parent_id, name, type, url, perms, icon, not_selected_icon_path, sort, level, custom, links, is_display, is_main, using_roles, remark, status, create_by, create_time, update_by, update_time, del_flag) VALUES (496654622425878528, 3, 0, '物流运单', 1, '/pages/logistics/waybill/index', 'app:tabbar:waybill', '/static/tabbar/waybill_select.png', '/static/tabbar/waybill.png', 146, 1, 0, null, null, 0, '', null, 0, 156383116720607232, '2026-01-27 10:44:09', 156383116720607232, '2026-06-11 11:08:00', 0);
 INSERT INTO sckw_ng_system.kws_menu (id, client_type, parent_id, name, type, url, perms, icon, not_selected_icon_path, sort, level, custom, links, is_display, is_main, using_roles, remark, status, create_by, create_time, update_by, update_time, del_flag) VALUES (496654536237125632, 3, 0, '物流订单', 1, '/pages/logistics/order/index', 'app:tabbar:logOrder', '/static/tabbar/logOrder_select.png', '/static/tabbar/logOrder.png', 145, 1, 0, null, null, 0, '', null, 0, 156383116720607232, '2026-01-27 10:43:48', 156383116720607232, '2026-06-11 11:07:21', 0);
-INSERT INTO sckw_ng_system.kws_menu (id, client_type, parent_id, name, type, url, perms, icon, not_selected_icon_path, sort, level, custom, links, is_display, is_main, using_roles, remark, status, create_by, create_time, update_by, update_time, del_flag) VALUES (496654386416586752, 3, 0, '商城商品', 1, '/pages/mall/index', 'app:tabbar:mall', '/static/tabbar/mall_select.png', '/static/tabbar/mall.png', 144, 1, 0, null, null, 0, '', null, 0, 156383116720607232, '2026-01-27 10:43:13', 156383116720607232, '2026-06-11 11:06:41', 0);
 INSERT INTO sckw_ng_system.kws_menu (id, client_type, parent_id, name, type, url, perms, icon, not_selected_icon_path, sort, level, custom, links, is_display, is_main, using_roles, remark, status, create_by, create_time, update_by, update_time, del_flag) VALUES (489392333326913536, 3, 0, '贸易订单', 1, '/pages/tradeOrder/index', 'app:tabbar:trade', '/static/tabbar/trade_select.png', '/static/tabbar/trade.png', 143, 1, 0, null, null, 0, '', null, 0, 156383116720607232, '2026-01-07 09:46:24', 156383116720607232, '2026-06-11 11:05:06', 0);