feat(功能用例): 新增空白节点和模块组合的模块树接口 (#31294)

Co-authored-by: guoyuqi <xiaomeinvG@126.com>
This commit is contained in:
MeterSphere Bot 2024-06-05 16:08:15 +08:00 committed by GitHub
parent 1d6096265e
commit 22d5791c3b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 80 additions and 7 deletions

View File

@ -8,6 +8,7 @@ import io.metersphere.functional.request.FunctionalCasePlanMindRequest;
import io.metersphere.functional.request.FunctionalCaseReviewMindRequest; import io.metersphere.functional.request.FunctionalCaseReviewMindRequest;
import io.metersphere.functional.service.FunctionalCaseMinderService; import io.metersphere.functional.service.FunctionalCaseMinderService;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.security.CheckOwner; import io.metersphere.system.security.CheckOwner;
import io.metersphere.system.utils.SessionUtils; import io.metersphere.system.utils.SessionUtils;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@ -16,10 +17,7 @@ import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
@ -34,6 +32,14 @@ public class FunctionalCaseMinderController {
@Resource @Resource
private FunctionalCaseMinderService functionalCaseMinderService; private FunctionalCaseMinderService functionalCaseMinderService;
@GetMapping("/tree/{projectId}")
@Operation(summary = "用例管理-功能用例-脑图-获取空白节点和模块的组合树")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
@CheckOwner(resourceId = "#projectId", resourceType = "project")
public List<BaseTreeNode> getTree(@PathVariable String projectId) {
return functionalCaseMinderService.getTree(projectId);
}
@PostMapping("/list") @PostMapping("/list")
@Operation(summary = "用例管理-功能用例-脑图用例跟根据模块ID查询列表") @Operation(summary = "用例管理-功能用例-脑图用例跟根据模块ID查询列表")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_MINDER) @RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_MINDER)

View File

@ -7,6 +7,7 @@ import io.metersphere.functional.request.*;
import io.metersphere.project.dto.ModuleCountDTO; import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.request.AssociateOtherCaseRequest; import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest; import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -89,5 +90,5 @@ public interface ExtFunctionalCaseMapper {
List<FunctionalCaseMindDTO> getMinderTestPlanList(@Param("request") FunctionalCasePlanMindRequest request, @Param("deleted") boolean delete); List<FunctionalCaseMindDTO> getMinderTestPlanList(@Param("request") FunctionalCasePlanMindRequest request, @Param("deleted") boolean delete);
List<BaseTreeNode> selectBaseMindNodeByProjectId(@Param("projectId")String projectId);
} }

View File

@ -874,4 +874,11 @@
AND cf.internal= true AND cf.internal= true
</select> </select>
<select id="selectBaseMindNodeByProjectId" resultType="io.metersphere.system.dto.sdk.BaseTreeNode">
SELECT id, name, parent_id AS parentId, 'module' AS type
FROM mind_additional_node
WHERE project_id = #{projectId}
ORDER BY pos
</select>
</mapper> </mapper>

View File

@ -22,6 +22,7 @@ import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.CustomField; import io.metersphere.system.domain.CustomField;
import io.metersphere.system.domain.CustomFieldExample; import io.metersphere.system.domain.CustomFieldExample;
import io.metersphere.system.domain.User; import io.metersphere.system.domain.User;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.OptionDTO; import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.dto.sdk.TemplateCustomFieldDTO; import io.metersphere.system.dto.sdk.TemplateCustomFieldDTO;
import io.metersphere.system.dto.sdk.TemplateDTO; import io.metersphere.system.dto.sdk.TemplateDTO;
@ -1059,4 +1060,48 @@ public class FunctionalCaseMinderService {
} }
public List<BaseTreeNode> getTree(String projectId) {
List<BaseTreeNode> functionalModuleList = extFunctionalCaseModuleMapper.selectBaseByProjectId(projectId);
List<BaseTreeNode> baseTreeNodes = extFunctionalCaseMapper.selectBaseMindNodeByProjectId(projectId);
functionalModuleList.addAll(baseTreeNodes);
return buildTreeAndCountResource(functionalModuleList, true, Translator.get("functional_case.module.default.name"));
}
public List<BaseTreeNode> buildTreeAndCountResource(List<BaseTreeNode> traverseList, boolean haveVirtualRootNode, String virtualRootName) {
List<BaseTreeNode> baseTreeNodeList = new ArrayList<>();
if (haveVirtualRootNode) {
BaseTreeNode defaultNode = this.getDefaultModule(virtualRootName);
defaultNode.genModulePath(null);
baseTreeNodeList.add(defaultNode);
}
int lastSize = 0;
Map<String, BaseTreeNode> baseTreeNodeMap = new HashMap<>();
while (CollectionUtils.isNotEmpty(traverseList) && traverseList.size() != lastSize) {
lastSize = traverseList.size();
List<BaseTreeNode> notMatchedList = new ArrayList<>();
for (BaseTreeNode treeNode : traverseList) {
if (!baseTreeNodeMap.containsKey(treeNode.getParentId()) && !StringUtils.equalsIgnoreCase(treeNode.getParentId(), ModuleConstants.ROOT_NODE_PARENT_ID)) {
notMatchedList.add(treeNode);
continue;
}
BaseTreeNode node = new BaseTreeNode(treeNode.getId(), treeNode.getName(), treeNode.getType(), treeNode.getParentId());
node.genModulePath(baseTreeNodeMap.get(treeNode.getParentId()));
baseTreeNodeMap.put(treeNode.getId(), node);
if (StringUtils.equalsIgnoreCase(treeNode.getParentId(), ModuleConstants.ROOT_NODE_PARENT_ID)) {
baseTreeNodeList.add(node);
} else if (baseTreeNodeMap.containsKey(treeNode.getParentId())) {
baseTreeNodeMap.get(treeNode.getParentId()).addChild(node);
}
}
traverseList = notMatchedList;
}
return baseTreeNodeList;
}
public BaseTreeNode getDefaultModule(String name) {
//默认模块下不允许创建子模块 它本身也就是叶子节点
return new BaseTreeNode(ModuleConstants.DEFAULT_NODE_ID, name, ModuleConstants.NODE_TYPE_DEFAULT, ModuleConstants.ROOT_NODE_PARENT_ID);
}
} }

View File

@ -14,6 +14,7 @@ import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.base.BaseTest; import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder; import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -38,6 +39,9 @@ public class FunctionalCaseMinderControllerTest extends BaseTest {
public static final String FUNCTIONAL_CASE_EDIT_URL = "/functional/mind/case/edit"; public static final String FUNCTIONAL_CASE_EDIT_URL = "/functional/mind/case/edit";
public static final String FUNCTIONAL_CASE_NODE_MODULE_URL = "/functional/mind/case/tree/";
//评审 //评审
public static final String FUNCTIONAL_CASE_REVIEW_LIST_URL = "/functional/mind/case/review/list"; public static final String FUNCTIONAL_CASE_REVIEW_LIST_URL = "/functional/mind/case/review/list";
@ -258,9 +262,19 @@ public class FunctionalCaseMinderControllerTest extends BaseTest {
Assertions.assertTrue(CollectionUtils.isNotEmpty(functionalCases)); Assertions.assertTrue(CollectionUtils.isNotEmpty(functionalCases));
} }
@Test @Test
@Order(3) @Order(3)
public void testGetCaseModuleNodeList() throws Exception {
MvcResult mvcResultPage = this.requestGetWithOkAndReturn(FUNCTIONAL_CASE_NODE_MODULE_URL+"project-case-minder-test");
String contentAsString = mvcResultPage.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
List<BaseTreeNode> baseTreeNodes = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BaseTreeNode.class);
Assertions.assertNotNull(baseTreeNodes);
System.out.println(baseTreeNodes);
}
@Test
@Order(4)
public void testGetCaseReviewList() throws Exception { public void testGetCaseReviewList() throws Exception {
FunctionalCaseReviewMindRequest request = new FunctionalCaseReviewMindRequest(); FunctionalCaseReviewMindRequest request = new FunctionalCaseReviewMindRequest();
request.setProjectId("project-case-minder-test"); request.setProjectId("project-case-minder-test");
@ -287,7 +301,7 @@ public class FunctionalCaseMinderControllerTest extends BaseTest {
} }
@Test @Test
@Order(4) @Order(5)
public void testGetCasePlanList() throws Exception { public void testGetCasePlanList() throws Exception {
FunctionalCasePlanMindRequest request = new FunctionalCasePlanMindRequest(); FunctionalCasePlanMindRequest request = new FunctionalCasePlanMindRequest();
request.setProjectId("project-case-minder-test"); request.setProjectId("project-case-minder-test");