Browse Source

虚拟单位重组功能开发

dev-V1.0.1
庄锐波 6 months ago
parent
commit
13a74c60ed
  1. 107
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/common/util/DataFilterUtil.java
  2. 4
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/helper/DataFilterHelper.java
  3. 16
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeVirtualUnitMapper.java
  4. 11
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeVirtualUnitService.java
  5. 14
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeVirtualUnitServiceImpl.java
  6. 15
      zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeVirtualUnitMapper.xml
  7. 288
      zdxt-web-server/zdxt-admin-web-server/src/test/java/org/dromara/test/DataFilterUtilTest.java

107
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/common/util/DataFilterUtil.java

@ -0,0 +1,107 @@
package com.zdxt.enforcementcode.common.util;
import cn.hutool.core.util.StrUtil;
import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo;
import com.zdxt.enforcementcode.service.IEfcodeVirtualUnitService;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.dromara.common.core.utils.SpringUtils;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DataFilterUtil {
// ======================== 区(ShenZhen_Areas)(2) 的子节点常量 ========================
/** 区 */
public static final String SHENZHEN_AREAS = "ShenZhen_Areas";
/** 光明区 */
public static final String AREA_GUANG_MING_QU = "Area_GuangMingQu";
/** 南山区 */
public static final String AREA_NAN_SHAN_QU = "Area_NanShanQu";
/** 坪山区 */
public static final String AREA_PING_SHAN_QU = "Area_PingsHanQu";
/** 大鹏新区 */
public static final String AREA_DA_PENG_XIN_QU = "Area_DapengXinQu";
/** 宝安区 */
public static final String AREA_BAO_AN_QU = "Area_BaoAnQu";
/** 深汕特别合作区 */
public static final String AREA_SHEN_SHAN_TE_BIE_HE_ZUO_QU = "Area_ShenShanTeBieHeZuoQu";
/** 盐田区 */
public static final String AREA_YAN_TIAN_QU = "Area_YanTianQu";
/** 福田区 */
public static final String AREA_FU_TIAN_QU = "Area_FuTianQu";
/** 罗湖区 */
public static final String AREA_LUO_HU_QU = "Area_LuoHuQu";
/** 龙华区 */
public static final String AREA_LONG_HUA_QU = "Area_LongHuaQu";
/** 龙岗区 */
public static final String AREA_LONG_GANG_QU = "Area_LongGangQu";
/** 深圳市直 */
public static final String ShenZhen_ShiZhi = "ShenZhen_ShiZhi";
// ======================== 公开方法 ========================
/**
* 获取指定节点下所有子孙级符合条件的部门ID (sys_dept_id)
*
* @param virId 起始节点的虚拟单位ID
* @param includeSearch 是否包含查询节点 (virIncludeSearch = "是")
* @param includeStatistics 是否包含统计节点 (virIncludeStatistics = "是")
* @param includeBusiness 是否包含业务节点 (virShowAtBusiness = "是")
* @return 符合条件的后代节点的 sys_dept_id 列表(已去重,排除空值)
*/
public static List<String> getDescendantDeptIds(String virId,
boolean includeSearch,
boolean includeStatistics,
boolean includeBusiness) {
if (StrUtil.isBlank(virId)) {
return Collections.emptyList();
}
IEfcodeVirtualUnitService service = SpringUtils.getBean(IEfcodeVirtualUnitService.class);
return service.queryDescendants(virId, includeSearch, includeStatistics, includeBusiness)
.stream()
.map(EfcodeVirtualUnitVo::getSysDeptId)
.filter(StrUtil::isNotBlank)
.distinct()
.collect(Collectors.toList());
}
/**
* 获取指定节点下所有子孙级符合条件的虚拟单位ID (vir_id)
*
* @param virId 起始节点的虚拟单位ID
* @param includeSearch 是否包含查询节点 (virIncludeSearch = "是")
* @param includeStatistics 是否包含统计节点 (virIncludeStatistics = "是")
* @param includeBusiness 是否包含业务节点 (virShowAtBusiness = "是")
* @return 符合条件的后代节点的 vir_id 列表(已去重,排除空值)
*/
public static List<String> getDescendantVirIds(String virId,
boolean includeSearch,
boolean includeStatistics,
boolean includeBusiness) {
if (StrUtil.isBlank(virId)) {
return Collections.emptyList();
}
IEfcodeVirtualUnitService service = SpringUtils.getBean(IEfcodeVirtualUnitService.class);
return service.queryDescendants(virId, includeSearch, includeStatistics, includeBusiness)
.stream()
.map(EfcodeVirtualUnitVo::getVirId)
.filter(StrUtil::isNotBlank)
.distinct()
.collect(Collectors.toList());
}
}

4
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/helper/DataFilterHelper.java

@ -1,4 +0,0 @@
package com.zdxt.enforcementcode.helper;
public class DataFilterHelper {
}

16
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeVirtualUnitMapper.java

@ -9,6 +9,8 @@ import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/** /**
* 虚拟单位树Mapper接口 * 虚拟单位树Mapper接口
* *
@ -30,4 +32,18 @@ public interface EfcodeVirtualUnitMapper extends BaseMapperPlus<EfcodeVirtualUni
@Param("sysDeptId") String sysDeptId, @Param("sysDeptId") String sysDeptId,
@Param("keyword") String keyword, @Param("keyword") String keyword,
@Param("globalSearch") boolean globalSearch); @Param("globalSearch") boolean globalSearch);
/**
* 查询指定节点的子孙级虚拟单位(按查询/统计/业务条件过滤)
*
* @param virId 起始节点的虚拟单位ID
* @param includeSearch 是否包含查询节点
* @param includeStatistics 是否包含统计节点
* @param includeBusiness 是否包含业务节点
* @return 符合条件的后代节点列表
*/
List<EfcodeVirtualUnitVo> selectDescendants(@Param("virId") String virId,
@Param("includeSearch") boolean includeSearch,
@Param("includeStatistics") boolean includeStatistics,
@Param("includeBusiness") boolean includeBusiness);
} }

11
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeVirtualUnitService.java

@ -75,6 +75,17 @@ public interface IEfcodeVirtualUnitService {
*/ */
List<EfcodeVirtualUnitVo> queryTreeList(); List<EfcodeVirtualUnitVo> queryTreeList();
/**
* 查询指定节点的子孙级虚拟单位(按查询/统计/业务条件在SQL层过滤)
*
* @param virId 起始节点的虚拟单位ID
* @param includeSearch 是否包含查询节点
* @param includeStatistics 是否包含统计节点
* @param includeBusiness 是否包含业务节点
* @return 符合条件的后代节点列表
*/
List<EfcodeVirtualUnitVo> queryDescendants(String virId, boolean includeSearch, boolean includeStatistics, boolean includeBusiness);
/** /**
* 查询业务可见的虚拟单位树列表(vir_show_at_business='1') * 查询业务可见的虚拟单位树列表(vir_show_at_business='1')
* *

14
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeVirtualUnitServiceImpl.java

@ -222,7 +222,7 @@ public class EfcodeVirtualUnitServiceImpl implements IEfcodeVirtualUnitService {
} }
/** /**
* 查询业务可见的虚拟单位树列表(vir_show_at_business='1') * 查询业务可见的虚拟单位树列表(vir_show_at_business='是')
*/ */
@Override @Override
public List<EfcodeVirtualUnitVo> queryBusinessTreeList() { public List<EfcodeVirtualUnitVo> queryBusinessTreeList() {
@ -233,6 +233,18 @@ public class EfcodeVirtualUnitServiceImpl implements IEfcodeVirtualUnitService {
return baseMapper.selectVoList(lqw); return baseMapper.selectVoList(lqw);
} }
/**
* 查询指定节点的子孙级虚拟单位(按查询/统计/业务条件在SQL层过滤)
* SQL实现参见 EfcodeVirtualUnitMapper.xml#selectDescendants
*/
@Override
public List<EfcodeVirtualUnitVo> queryDescendants(String virId, boolean includeSearch, boolean includeStatistics, boolean includeBusiness) {
if (StringUtils.isBlank(virId)) {
return List.of();
}
return baseMapper.selectDescendants(virId, includeSearch, includeStatistics, includeBusiness);
}
/** /**
* 根据虚拟单位的sysDeptId分页查询关联人员列表 * 根据虚拟单位的sysDeptId分页查询关联人员列表
* SQL实现参见 EfcodeVirtualUnitMapper.xml#selectUnitUsers * SQL实现参见 EfcodeVirtualUnitMapper.xml#selectUnitUsers

15
zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeVirtualUnitMapper.xml

@ -40,4 +40,19 @@
</if> </if>
ORDER BY u.dept_id ASC, u.user_id ASC ORDER BY u.dept_id ASC, u.user_id ASC
</select> </select>
<!-- 查询指定节点的子孙级(按查询/统计/业务条件过滤) -->
<select id="selectDescendants" resultType="com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo">
SELECT vir_id, sys_dept_id
FROM efcode_virtual_unit
WHERE FIND_IN_SET(#{virId}, vir_ancestors)
AND vir_id != #{virId}
<if test="includeSearch or includeStatistics or includeBusiness">
AND (
1=0
<if test="includeSearch"> OR vir_include_search = '是'</if>
<if test="includeStatistics"> OR vir_include_statistics = '是'</if>
<if test="includeBusiness"> OR vir_show_at_business = '是'</if>
)
</if>
</select>
</mapper> </mapper>

288
zdxt-web-server/zdxt-admin-web-server/src/test/java/org/dromara/test/DataFilterUtilTest.java

@ -0,0 +1,288 @@
package org.dromara.test;
import cn.dev33.satoken.context.mock.SaTokenContextMockUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import com.zdxt.enforcementcode.common.util.DataFilterUtil;
import org.dromara.ZdxtAdminApplication;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.satoken.utils.LoginHelper;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.HashSet;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* DataFilterUtil 单元测试
*/
@SpringBootTest(classes = ZdxtAdminApplication.class)
@ActiveProfiles({"dev", "dev-cust-zrb"})
@AutoConfigureMockMvc
@DisplayName("DataFilterUtil 单元测试")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DataFilterUtilTest {
private static final String TEST_CLIENT_ID = "e5cd7e4891bf95d1d19206ce24a7b32e";
private static final String TENANT_ID = "000000";
@BeforeEach
public void setUp() {
SaTokenContextMockUtil.setMockContext();
MockHttpServletRequest mockRequest = new MockHttpServletRequest();
mockRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest));
LoginUser loginUser = new LoginUser();
loginUser.setUserId(1L);
loginUser.setUserType("sys_user");
loginUser.setTenantId(TENANT_ID);
loginUser.setUsername("test_admin");
loginUser.setNickname("测试管理员");
loginUser.setDeptId("103");
loginUser.setDeptName("测试部门");
loginUser.setRolePermission(new HashSet<>());
loginUser.setMenuPermission(new HashSet<>());
SaLoginParameter param = new SaLoginParameter();
param.setExtra(LoginHelper.CLIENT_KEY, TEST_CLIENT_ID);
LoginHelper.login(loginUser, param);
}
@AfterEach
public void tearDown() {
try {
StpUtil.logout();
} catch (Exception ignored) {
}
RequestContextHolder.resetRequestAttributes();
SaTokenContextMockUtil.clearContext();
}
// ======================== 常量验证 ========================
@Test
@Order(1)
@DisplayName("验证区域常量值")
public void testConstants() {
assertEquals("ShenZhen_Areas", DataFilterUtil.SHENZHEN_AREAS);
assertEquals("Area_GuangMingQu", DataFilterUtil.AREA_GUANG_MING_QU);
assertEquals("Area_NanShanQu", DataFilterUtil.AREA_NAN_SHAN_QU);
assertEquals("Area_PingsHanQu", DataFilterUtil.AREA_PING_SHAN_QU);
assertEquals("Area_DapengXinQu", DataFilterUtil.AREA_DA_PENG_XIN_QU);
assertEquals("Area_BaoAnQu", DataFilterUtil.AREA_BAO_AN_QU);
assertEquals("Area_ShenShanTeBieHeZuoQu", DataFilterUtil.AREA_SHEN_SHAN_TE_BIE_HE_ZUO_QU);
assertEquals("Area_YanTianQu", DataFilterUtil.AREA_YAN_TIAN_QU);
assertEquals("Area_FuTianQu", DataFilterUtil.AREA_FU_TIAN_QU);
assertEquals("Area_LuoHuQu", DataFilterUtil.AREA_LUO_HU_QU);
assertEquals("Area_LongHuaQu", DataFilterUtil.AREA_LONG_HUA_QU);
assertEquals("Area_LongGangQu", DataFilterUtil.AREA_LONG_GANG_QU);
assertEquals("ShenZhen_ShiZhi", DataFilterUtil.ShenZhen_ShiZhi);
}
// ======================== getDescendantDeptIds 测试 ========================
@Test
@Order(2)
@DisplayName("getDescendantDeptIds - 空virId返回空列表")
public void testGetDescendantDeptIds_blankVirId() {
List<String> result1 = DataFilterUtil.getDescendantDeptIds(null, true, true, true);
assertNotNull(result1);
assertTrue(result1.isEmpty(), "null virId 应返回空列表");
List<String> result2 = DataFilterUtil.getDescendantDeptIds("", true, true, true);
assertNotNull(result2);
assertTrue(result2.isEmpty(), "空字符串 virId 应返回空列表");
List<String> result3 = DataFilterUtil.getDescendantDeptIds(" ", true, true, true);
assertNotNull(result3);
assertTrue(result3.isEmpty(), "空白字符串 virId 应返回空列表");
}
@Test
@Order(3)
@DisplayName("getDescendantDeptIds - 查询深圳各区子节点的部门ID")
public void testGetDescendantDeptIds_shenzhenAreas() {
List<String> deptIds = DataFilterUtil.getDescendantDeptIds(
DataFilterUtil.SHENZHEN_AREAS, true, true, true);
assertNotNull(deptIds);
System.out.println("SHENZHEN_AREAS 子孙部门ID数量: " + deptIds.size());
deptIds.forEach(id -> {
assertNotNull(id);
assertFalse(id.isBlank(), "部门ID不应为空白字符串");
});
assertFalse(deptIds.isEmpty(), "深圳各区下应存在子孙部门");
assertEquals(deptIds.size(), deptIds.stream().distinct().count(), "部门ID不应有重复");
}
@Test
@Order(4)
@DisplayName("getDescendantDeptIds - 查询光明区子节点的部门ID")
public void testGetDescendantDeptIds_guangMingQu() {
List<String> deptIds = DataFilterUtil.getDescendantDeptIds(
DataFilterUtil.AREA_GUANG_MING_QU, true, true, true);
assertNotNull(deptIds);
System.out.println("光明区子孙部门ID数量: " + deptIds.size());
deptIds.forEach(id -> assertFalse(id.isBlank(), "部门ID不应为空白"));
}
@Test
@Order(5)
@DisplayName("getDescendantDeptIds - 查询市直子节点的部门ID")
public void testGetDescendantDeptIds_shiZhi() {
List<String> deptIds = DataFilterUtil.getDescendantDeptIds(
DataFilterUtil.ShenZhen_ShiZhi, true, true, true);
assertNotNull(deptIds);
System.out.println("市直子孙部门ID数量: " + deptIds.size());
deptIds.forEach(id -> assertFalse(id.isBlank(), "部门ID不应为空白"));
}
@Test
@Order(6)
@DisplayName("getDescendantDeptIds - 不存在的virId返回空列表")
public void testGetDescendantDeptIds_nonExistentVirId() {
List<String> deptIds = DataFilterUtil.getDescendantDeptIds(
"NON_EXISTENT_VIR_ID_12345", true, true, true);
assertNotNull(deptIds);
assertTrue(deptIds.isEmpty(), "不存在的virId应返回空列表");
}
@Test
@Order(7)
@DisplayName("getDescendantDeptIds - 不同过滤条件组合测试")
public void testGetDescendantDeptIds_filterCombinations() {
String virId = DataFilterUtil.SHENZHEN_AREAS;
List<String> allTrue = DataFilterUtil.getDescendantDeptIds(virId, true, true, true);
List<String> noSearch = DataFilterUtil.getDescendantDeptIds(virId, false, true, true);
List<String> noStatistics = DataFilterUtil.getDescendantDeptIds(virId, true, false, true);
List<String> noBusiness = DataFilterUtil.getDescendantDeptIds(virId, true, true, false);
List<String> allFalse = DataFilterUtil.getDescendantDeptIds(virId, false, false, false);
assertNotNull(allTrue);
assertNotNull(noSearch);
assertNotNull(noStatistics);
assertNotNull(noBusiness);
assertNotNull(allFalse);
System.out.println("全部包含: " + allTrue.size());
System.out.println("不包含查询节点: " + noSearch.size());
System.out.println("不包含统计节点: " + noStatistics.size());
System.out.println("不包含业务节点: " + noBusiness.size());
System.out.println("全部不包含: " + allFalse.size());
}
// ======================== getDescendantVirIds 测试 ========================
@Test
@Order(8)
@DisplayName("getDescendantVirIds - 空virId返回空列表")
public void testGetDescendantVirIds_blankVirId() {
List<String> result1 = DataFilterUtil.getDescendantVirIds(null, true, true, true);
assertNotNull(result1);
assertTrue(result1.isEmpty(), "null virId 应返回空列表");
List<String> result2 = DataFilterUtil.getDescendantVirIds("", true, true, true);
assertNotNull(result2);
assertTrue(result2.isEmpty(), "空字符串 virId 应返回空列表");
List<String> result3 = DataFilterUtil.getDescendantVirIds(" ", true, true, true);
assertNotNull(result3);
assertTrue(result3.isEmpty(), "空白字符串 virId 应返回空列表");
}
@Test
@Order(9)
@DisplayName("getDescendantVirIds - 查询深圳各区子节点的虚拟单位ID")
public void testGetDescendantVirIds_shenzhenAreas() {
List<String> virIds = DataFilterUtil.getDescendantVirIds(
DataFilterUtil.SHENZHEN_AREAS, true, true, true);
assertNotNull(virIds);
System.out.println("SHENZHEN_AREAS 子孙虚拟单位ID数量: " + virIds.size());
virIds.forEach(id -> {
assertNotNull(id);
assertFalse(id.isBlank(), "虚拟单位ID不应为空白字符串");
});
assertFalse(virIds.isEmpty(), "深圳各区下应存在子孙虚拟单位");
assertEquals(virIds.size(), virIds.stream().distinct().count(), "虚拟单位ID不应有重复");
}
@Test
@Order(10)
@DisplayName("getDescendantVirIds - 查询市直子节点的虚拟单位ID")
public void testGetDescendantVirIds_shiZhi() {
List<String> virIds = DataFilterUtil.getDescendantVirIds(
DataFilterUtil.ShenZhen_ShiZhi, true, true, true);
assertNotNull(virIds);
System.out.println("市直子孙虚拟单位ID数量: " + virIds.size());
virIds.forEach(id -> assertFalse(id.isBlank(), "虚拟单位ID不应为空白"));
}
@Test
@Order(11)
@DisplayName("getDescendantVirIds - 不存在的virId返回空列表")
public void testGetDescendantVirIds_nonExistentVirId() {
List<String> virIds = DataFilterUtil.getDescendantVirIds(
"NON_EXISTENT_VIR_ID_12345", true, true, true);
assertNotNull(virIds);
assertTrue(virIds.isEmpty(), "不存在的virId应返回空列表");
}
@Test
@Order(12)
@DisplayName("getDescendantDeptIds - 遍历所有区域常量查询子孙部门")
public void testGetDescendantDeptIds_allAreaConstants() {
String[] areaConstants = {
DataFilterUtil.AREA_GUANG_MING_QU,
DataFilterUtil.AREA_NAN_SHAN_QU,
DataFilterUtil.AREA_PING_SHAN_QU,
DataFilterUtil.AREA_DA_PENG_XIN_QU,
DataFilterUtil.AREA_BAO_AN_QU,
DataFilterUtil.AREA_SHEN_SHAN_TE_BIE_HE_ZUO_QU,
DataFilterUtil.AREA_YAN_TIAN_QU,
DataFilterUtil.AREA_FU_TIAN_QU,
DataFilterUtil.AREA_LUO_HU_QU,
DataFilterUtil.AREA_LONG_HUA_QU,
DataFilterUtil.AREA_LONG_GANG_QU,
};
for (String area : areaConstants) {
List<String> deptIds = DataFilterUtil.getDescendantDeptIds(area, true, true, true);
assertNotNull(deptIds, area + " 查询不应返回null");
System.out.println(area + " 子孙部门ID数量: " + deptIds.size());
}
}
@Test
@Order(13)
@DisplayName("getDescendantVirIds - 不同过滤条件组合测试")
public void testGetDescendantVirIds_filterCombinations() {
String virId = DataFilterUtil.SHENZHEN_AREAS;
List<String> allTrue = DataFilterUtil.getDescendantVirIds(virId, true, true, true);
List<String> noSearch = DataFilterUtil.getDescendantVirIds(virId, false, true, true);
List<String> noStatistics = DataFilterUtil.getDescendantVirIds(virId, true, false, true);
List<String> noBusiness = DataFilterUtil.getDescendantVirIds(virId, true, true, false);
List<String> allFalse = DataFilterUtil.getDescendantVirIds(virId, false, false, false);
assertNotNull(allTrue);
assertNotNull(noSearch);
assertNotNull(noStatistics);
assertNotNull(noBusiness);
assertNotNull(allFalse);
System.out.println("VirIds 全部包含: " + allTrue.size());
System.out.println("VirIds 不包含查询节点: " + noSearch.size());
System.out.println("VirIds 不包含统计节点: " + noStatistics.size());
System.out.println("VirIds 不包含业务节点: " + noBusiness.size());
System.out.println("VirIds 全部不包含: " + allFalse.size());
}
}
Loading…
Cancel
Save