refactor(测试计划): 测试计划已关联功能用例模块树

This commit is contained in:
WangXu10 2024-06-21 10:03:42 +08:00 committed by Craftsman
parent 254cbfa019
commit 43440db470
5 changed files with 48 additions and 28 deletions

View File

@ -71,7 +71,7 @@ public class CaseReviewController {
@PostMapping("/copy")
@Operation(summary = "用例管理-用例评审-复制用例评审")
@Log(type = OperationLogType.COPY, expression = "#msClass.copyCaseReviewLog(#request)", msClass = CaseReviewLogService.class)
@Log(type = OperationLogType.ADD, expression = "#msClass.copyCaseReviewLog(#request)", msClass = CaseReviewLogService.class)
@SendNotice(taskType = NoticeConstants.TaskType.CASE_REVIEW_TASK, event = NoticeConstants.Event.CREATE, target = "#targetClass.getMainCaseReview(#request)", targetClass = CaseReviewNoticeService.class)
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_ADD)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")

View File

@ -22,7 +22,6 @@ public class TestPlanCaseRequest extends BasePageRequest implements Serializable
private String testPlanId;
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{functional_case.project_id.not_blank}")
private String projectId;
@Schema(description = "版本id")

View File

@ -135,8 +135,15 @@
<sql id="queryWhereCondition">
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and functional_case.module_id in
<foreach collection="request.moduleIds" item="moduleId" separator="," open="(" close=")">
#{moduleId}
<foreach collection="request.moduleIds" item="nodeId" separator="," open="(" close=")">
<choose>
<when test="nodeId.contains('_root')">
'root'
</when>
<otherwise>
#{nodeId}
</otherwise>
</choose>
</foreach>
</if>
<if test="request.keyword != null and request.keyword != ''">
@ -148,6 +155,9 @@
<if test="request.collectionId != null and request.collectionId != ''">
and test_plan_functional_case.test_plan_collection_id = #{request.collectionId}
</if>
<if test="request.projectId != null and request.projectId!=''">
and functional_case.project_id = #{request.projectId}
</if>
<include refid="filters">
<property name="filter" value="request.filter"/>
</include>
@ -451,7 +461,7 @@
LEFT JOIN test_plan_functional_case tpfc ON tpfc.functional_case_id = fc.id
LEFT JOIN project p ON fc.project_id = p.id
WHERE tpfc.test_plan_id = #{testPlanId}
AND fc.deleted = false AND fc.module_id = 'root'
AND fc.deleted = false
ORDER BY fc.pos
</select>
@ -465,14 +475,15 @@
</select>
<select id="countModuleIdByRequest" resultType="io.metersphere.functional.dto.FunctionalCaseModuleCountDTO">
SELECT functional_case.module_id AS moduleId, count(functional_case.id) AS dataCount, functional_case.project_id AS projectId, project.name AS projectName
SELECT CASE WHEN functional_case.module_id = 'root' THEN concat(functional_case.project_id, '_', functional_case.module_id) ElSE functional_case.module_id END AS moduleId,
count(functional_case.id) As dataCount, functional_case.project_id As projectId, project.name As projectName
FROM test_plan_functional_case
LEFT JOIN functional_case ON test_plan_functional_case.functional_case_id = functional_case.id
LEFT JOIN project ON functional_case.project_id = project.id
WHERE test_plan_functional_case.test_plan_id = #{request.testPlanId}
AND functional_case.deleted = #{deleted}
<include refid="queryWhereCondition"/>
GROUP BY module_id
GROUP BY moduleId
</select>
<select id="caseCount"

View File

@ -30,7 +30,6 @@ import io.metersphere.plan.dto.request.*;
import io.metersphere.plan.dto.response.*;
import io.metersphere.plan.mapper.*;
import io.metersphere.plugin.platform.dto.SelectOption;
import io.metersphere.project.domain.Project;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.MoveNodeSortDTO;
import io.metersphere.provider.BaseAssociateBugProvider;
@ -130,7 +129,7 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
@Override
public long copyResource(String originalTestPlanId, String newTestPlanId, Map<String, String> oldCollectionIdToNewCollectionId, String operator, long operatorTime) {
List<TestPlanFunctionalCase> copyList = new ArrayList<>();
String defaultCollectionId = extTestPlanCollectionMapper.selectDefaultCollectionId(newTestPlanId,CaseType.SCENARIO_CASE.getKey());
String defaultCollectionId = extTestPlanCollectionMapper.selectDefaultCollectionId(newTestPlanId, CaseType.SCENARIO_CASE.getKey());
extTestPlanFunctionalCaseMapper.selectByTestPlanIdAndNotDeleted(originalTestPlanId).forEach(originalCase -> {
TestPlanFunctionalCase newCase = new TestPlanFunctionalCase();
BeanUtils.copyBean(newCase, originalCase);
@ -323,27 +322,38 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
*/
private List<BaseTreeNode> getModuleTree(String testPlanId) {
List<BaseTreeNode> returnList = new ArrayList<>();
List<ProjectOptionDTO> rootIds = extTestPlanFunctionalCaseMapper.selectRootIdByTestPlanId(testPlanId);
Map<String, List<ProjectOptionDTO>> projectRootMap = rootIds.stream().collect(Collectors.groupingBy(ProjectOptionDTO::getName));
List<ProjectOptionDTO> moduleLists = extTestPlanFunctionalCaseMapper.selectRootIdByTestPlanId(testPlanId);
// 获取所有的项目id
List<String> projectIds = moduleLists.stream().map(ProjectOptionDTO::getName).distinct().toList();
// moduleLists中id=root的数据
List<ProjectOptionDTO> rootModuleList = moduleLists.stream().filter(item -> StringUtils.equals(item.getId(), ModuleConstants.DEFAULT_NODE_ID)).toList();
Map<String, List<ProjectOptionDTO>> projectRootMap = rootModuleList.stream().collect(Collectors.groupingBy(ProjectOptionDTO::getName));
List<FunctionalCaseModuleDTO> functionalModuleIds = extTestPlanFunctionalCaseMapper.selectBaseByProjectIdAndTestPlanId(testPlanId);
Map<String, List<FunctionalCaseModuleDTO>> projectModuleMap = functionalModuleIds.stream().collect(Collectors.groupingBy(FunctionalCaseModule::getProjectId));
if (MapUtils.isEmpty(projectModuleMap)) {
projectRootMap.forEach((projectId, projectOptionDTOList) -> {
BaseTreeNode projectNode = new BaseTreeNode(projectId, projectOptionDTOList.get(0).getProjectName(), Project.class.getName());
projectIds.forEach(projectId -> {
// 如果projectRootMap中没有projectId说明该项目没有根节点 不需要创
// projectModuleMap中没有projectId说明该项目没有模块 不需要创建
// 如果都有 需要创建完整的数结构
boolean needCreatRoot = MapUtils.isNotEmpty(projectRootMap) && projectRootMap.containsKey(projectId);
boolean needCreatModule = MapUtils.isNotEmpty(projectModuleMap) && projectModuleMap.containsKey(projectId);
// 项目名称是
String projectName = needCreatModule ? projectModuleMap.get(projectId).getFirst().getProjectName() : projectRootMap.get(projectId).getFirst().getProjectName();
// 构建项目那一层级
BaseTreeNode projectNode = new BaseTreeNode(projectId, projectName, "PROJECT");
returnList.add(projectNode);
BaseTreeNode defaultNode = functionalCaseModuleService.getDefaultModule(Translator.get("functional_case.module.default.name"));
projectNode.addChild(defaultNode);
});
return returnList;
List<BaseTreeNode> nodeByNodeIds = new ArrayList<>();
if (needCreatModule) {
List<String> projectModuleIds = projectModuleMap.get(projectId).stream().map(FunctionalCaseModuleDTO::getId).toList();
nodeByNodeIds = functionalCaseModuleService.getNodeByNodeIds(projectModuleIds);
}
projectModuleMap.forEach((projectId, moduleList) -> {
BaseTreeNode projectNode = new BaseTreeNode(projectId, moduleList.get(0).getProjectName(), Project.class.getName());
returnList.add(projectNode);
List<String> projectModuleIds = moduleList.stream().map(FunctionalCaseModule::getId).toList();
List<BaseTreeNode> nodeByNodeIds = functionalCaseModuleService.getNodeByNodeIds(projectModuleIds);
boolean haveVirtualRootNode = CollectionUtils.isEmpty(projectRootMap.get(projectId));
List<BaseTreeNode> baseTreeNodes = functionalCaseModuleService.buildTreeAndCountResource(nodeByNodeIds, !haveVirtualRootNode, Translator.get("functional_case.module.default.name"));
List<BaseTreeNode> baseTreeNodes = functionalCaseModuleService.buildTreeAndCountResource(nodeByNodeIds, needCreatRoot, Translator.get("functional_case.module.default.name"));
for (BaseTreeNode baseTreeNode : baseTreeNodes) {
if (StringUtils.equals(baseTreeNode.getId(), ModuleConstants.DEFAULT_NODE_ID)) {
// 默认拼项目id
baseTreeNode.setId(projectId + "_" + ModuleConstants.DEFAULT_NODE_ID);
}
projectNode.addChild(baseTreeNode);
}
});
@ -391,7 +401,7 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
request.setModuleIds(null);
List<FunctionalCaseModuleCountDTO> projectModuleCountDTOList = extTestPlanFunctionalCaseMapper.countModuleIdByRequest(request, false);
Map<String, List<FunctionalCaseModuleCountDTO>> projectCountMap = projectModuleCountDTOList.stream().collect(Collectors.groupingBy(FunctionalCaseModuleCountDTO::getProjectId));
Map<String, Long> projectModuleCountMap = new HashMap<>();
Map<String, Long> projectModuleCountMap = projectModuleCountDTOList.stream().collect(Collectors.groupingBy(FunctionalCaseModuleCountDTO::getModuleId, Collectors.summingLong(FunctionalCaseModuleCountDTO::getDataCount)));
projectCountMap.forEach((projectId, moduleCountDTOList) -> {
List<ModuleCountDTO> moduleCountDTOS = new ArrayList<>();
for (FunctionalCaseModuleCountDTO functionalCaseModuleCountDTO : moduleCountDTOList) {

View File

@ -27,7 +27,7 @@ VALUES
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES
('fc_1', 1, 't_1', '123', '100001', '111', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'TEST_FUNCTIONAL_MINDER_CASE_ID_7', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL),
('fc_2', 2, 't_1', '123', '100001', '222', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'TEST_FUNCTIONAL_MINDER_CASE_ID_7', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL),
('fc_2', 2, 'root', '123', '100001', '222', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'TEST_FUNCTIONAL_MINDER_CASE_ID_7', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL),
('fc_3', 3, 'root', '123', '100001', '333', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'TEST_FUNCTIONAL_MINDER_CASE_ID_7', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL),
('gyq_disassociate_fc_1', 4, 'root', 'gyq_disassociate', '100001', 'disassociate1', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'gyq_disassociate_fc_1', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL),
('gyq_disassociate_fc_2', 5, 'root', 'gyq_disassociate', '100001', 'disassociate2', 'UN_REVIEWED', NULL, 'TEXT', 55000, 'v3.0.0', 'gyq_disassociate_fc_2', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL),