fix(测试计划): 报告所属模块展示全路径

--bug=1041085 --user=宋昌昌 【测试计划】报告详情-功能用例明细-所属模块-hover未展示全路径 https://www.tapd.cn/55049933/s/1521841
This commit is contained in:
song-cc-rock 2024-05-28 14:56:49 +08:00 committed by Craftsman
parent 5bf0d63b01
commit f75e1bdf23
7 changed files with 108 additions and 9 deletions

View File

@ -0,0 +1,22 @@
package io.metersphere.plan.dto;
import lombok.Data;
@Data
public class TestPlanBaseModule {
/**
* 模块ID
*/
private String id;
/**
* 模块路径
*/
private String name;
/**
* 父级模块ID
*/
private String parentId;
}

View File

@ -3,6 +3,7 @@ package io.metersphere.plan.mapper;
import io.metersphere.plan.domain.TestPlanReportFunctionCase;
import io.metersphere.plan.dto.CaseStatusCountMap;
import io.metersphere.plan.dto.ReportDetailCasePageDTO;
import io.metersphere.plan.dto.TestPlanBaseModule;
import io.metersphere.plan.dto.request.TestPlanReportDetailPageRequest;
import io.metersphere.plugin.platform.dto.SelectOption;
import org.apache.ibatis.annotations.Param;
@ -18,6 +19,18 @@ public interface ExtTestPlanReportFunctionalCaseMapper {
*/
List<TestPlanReportFunctionCase> getPlanExecuteCases(@Param("id") String planId);
/**
* 获取项目下功能用例所属模块集合
* @param projectId 计划ID
* @return 模块集合
*/
List<TestPlanBaseModule> getPlanExecuteCaseModules(@Param("id") String projectId);
/**
* 获取用例等级
* @param caseIds 用例集合
* @return 等级集合
*/
List<SelectOption> getCasePriorityByIds(@Param("ids") List<String> caseIds);
/**

View File

@ -4,7 +4,7 @@
<select id="getPlanExecuteCases" resultType="io.metersphere.plan.domain.TestPlanReportFunctionCase">
select tpfc.id as testPlanFunctionCaseId, fc.id as functionCaseId, fc.num as functionCaseNum, fc.name as functionCaseName,
if(fc.module_id = 'root','未规划用例', fcm.name) as functionCaseModule, tpfc.execute_user as functionCaseExecuteUser,
if(fc.module_id = 'root','未规划用例', fc.module_id) as functionCaseModule, tpfc.execute_user as functionCaseExecuteUser,
count(brc.id) as functionCaseBugCount, ifnull(tpfc.last_exec_result, 'PENDING') as functionCaseExecuteResult
from test_plan_functional_case tpfc join functional_case fc on tpfc.functional_case_id = fc.id
left join functional_case_module fcm on fcm.id = fc.module_id
@ -13,6 +13,11 @@
group by tpfc.id
</select>
<select id="getPlanExecuteCaseModules" resultType="io.metersphere.plan.dto.TestPlanBaseModule">
select fcm.id, fcm.name, fcm.parent_id as parentId from functional_case_module fcm
where fcm.project_id = #{id}
</select>
<select id="getCasePriorityByIds" resultType="io.metersphere.plugin.platform.dto.SelectOption">
select distinct
fc.id as value,

View File

@ -3,15 +3,13 @@ package io.metersphere.plan.service;
import io.metersphere.bug.dto.response.BugDTO;
import io.metersphere.bug.service.BugCommonService;
import io.metersphere.plan.domain.*;
import io.metersphere.plan.dto.CaseStatusCountMap;
import io.metersphere.plan.dto.ReportDetailCasePageDTO;
import io.metersphere.plan.dto.TestPlanReportGenPreParam;
import io.metersphere.plan.dto.TestPlanReportPostParam;
import io.metersphere.plan.dto.*;
import io.metersphere.plan.dto.request.*;
import io.metersphere.plan.dto.response.TestPlanReportDetailResponse;
import io.metersphere.plan.dto.response.TestPlanReportPageResponse;
import io.metersphere.plan.enums.TestPlanReportAttachmentSourceType;
import io.metersphere.plan.mapper.*;
import io.metersphere.plan.utils.ModuleTreeUtils;
import io.metersphere.plan.utils.RateCalculateUtils;
import io.metersphere.plugin.platform.dto.SelectOption;
import io.metersphere.sdk.constants.*;
@ -244,12 +242,19 @@ public class TestPlanReportService {
// 功能用例
List<TestPlanReportFunctionCase> reportFunctionCases = extTestPlanReportFunctionalCaseMapper.getPlanExecuteCases(genParam.getTestPlanId());
if (CollectionUtils.isNotEmpty(reportFunctionCases)) {
// 模块树
List<TestPlanBaseModule> functionalModules = extTestPlanReportFunctionalCaseMapper.getPlanExecuteCaseModules(genParam.getProjectId());
Map<String, String> functionalModuleMap = new HashMap<>(functionalModules.size());
ModuleTreeUtils.genPathMap(functionalModules, functionalModuleMap, new ArrayList<>());
// 用例等级
List<String> ids = reportFunctionCases.stream().map(TestPlanReportFunctionCase::getFunctionCaseId).distinct().toList();
List<SelectOption> options = extTestPlanReportFunctionalCaseMapper.getCasePriorityByIds(ids);
Map<String, String> casePriorityMap = options.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText));
reportFunctionCases.forEach(reportFunctionalCase -> {
reportFunctionalCase.setId(IDGenerator.nextStr());
reportFunctionalCase.setTestPlanReportId(reportId);
reportFunctionalCase.setFunctionCaseModule(functionalModuleMap.getOrDefault(reportFunctionalCase.getFunctionCaseModule(),
ModuleTreeUtils.MODULE_PATH_PREFIX + reportFunctionalCase.getFunctionCaseModule()));
reportFunctionalCase.setFunctionCasePriority(casePriorityMap.get(reportFunctionalCase.getFunctionCaseId()));
});
// 插入计划功能用例关联数据 -> 报告内容

View File

@ -0,0 +1,47 @@
package io.metersphere.plan.utils;
import io.metersphere.plan.dto.TestPlanBaseModule;
import lombok.experimental.UtilityClass;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.Map;
/**
* 模块树解析相关的工具类
*/
@UtilityClass
public class ModuleTreeUtils {
public static final String MODULE_PATH_PREFIX = "/";
/**
* 解析并返回模块的全路径
* @param allNodes 模块集合
* @param nodePathMap 树节点路径集合
*/
public static void genPathMap(List<TestPlanBaseModule> allNodes, Map<String, String> nodePathMap, List<String> scanIds) {
if (MapUtils.isEmpty(nodePathMap)) {
// 根节点遍历
List<TestPlanBaseModule> rootNodes = allNodes.stream().filter(node ->
StringUtils.isBlank(node.getParentId()) || StringUtils.equals(node.getParentId(), "NONE")).toList();
rootNodes.forEach(node -> nodePathMap.put(node.getId(), MODULE_PATH_PREFIX + node.getName()));
// 下一级父节点
scanIds = rootNodes.stream().map(TestPlanBaseModule::getId).toList();
} else {
// 非根节点遍历
List<String> finalScanIds = scanIds;
List<TestPlanBaseModule> scanNodes = allNodes.stream().filter(node -> finalScanIds.contains(node.getParentId())).toList();
scanNodes.forEach(node -> nodePathMap.put(node.getId(), nodePathMap.getOrDefault(node.getParentId(), StringUtils.EMPTY) + MODULE_PATH_PREFIX + node.getName()));
// 下一级父节点
scanIds = scanNodes.stream().map(TestPlanBaseModule::getId).toList();
}
if (CollectionUtils.isEmpty(scanIds)) {
// 叶子节点不存在, 跳出
return;
}
genPathMap(allNodes, nodePathMap, scanIds);
}
}

View File

@ -1,11 +1,13 @@
package io.metersphere.plan.utils;
import lombok.experimental.UtilityClass;
import java.text.DecimalFormat;
/**
* 计划模块百分比计算工具类
*/
@UtilityClass
public class RateCalculateUtils {
public static final int MAX_BOUNDARY = 100;

View File

@ -15,7 +15,7 @@ INSERT INTO `test_plan_functional_case` (`id`, `test_plan_id`, `functional_case_
('plan_id_for_gen_report_case_5', 'plan_id_for_gen_report', 'f5_gen', CURRENT_TIMESTAMP, 'admin', 'admin', CURRENT_TIMESTAMP, 'FAKE_ERROR', 5);
-- 计划关联缺陷的测试数据
INSERT INTO `bug_relation_case`(`id`, `case_id`, `bug_id`, `case_type`, `test_plan_id`, `test_plan_case_id`, `create_user`, `create_time`, `update_time`) VALUES
INSERT INTO `bug_relation_case` (`id`, `case_id`, `bug_id`, `case_type`, `test_plan_id`, `test_plan_case_id`, `create_user`, `create_time`, `update_time`) VALUES
('test-plan-bug-relate-case-1', 'f1', 'test-plan-bug-for-gen', 'FUNCTIONAL', 'plan_id_for_gen_report', 'f1', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
-- 缺陷的测试数据
@ -23,5 +23,10 @@ INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_
('test-plan-bug-for-gen', 100000, 'default-bug-gen', 'oasis', 'admin', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '100001100001', 'bug-template-id', 'Local', 'new', '["default-tag"]', null, 0, 5000);
-- 用例的测试数据
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 ('f1_gen', 100001, 'TEST_MODULE_ID', '100001100001', '100001', 'functional_case_gen', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'v1.0.0', 'PENDING', b'0', b'0', b'1', 'admin', 'admin', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
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 ('f1_gen', 100001, 'TEST_MODULE_ID', '100001100001', '100001', 'functional_case_gen', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'v1.0.0', 'PENDING', b'0', b'0', b'1', 'admin', 'admin', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
INSERT INTO functional_case_module (id, project_id, name, parent_id, pos, create_user, create_time, update_user, update_time) VALUES
('TEST_MODULE_ID', '100001100001', 'test_module_gen_1', 'NONE', 0, 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP),
('TEST_MODULE_ID_1', '100001100001', 'test_module_gen_2', 'TEST_MODULE_ID', 0, 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP),
('TEST_MODULE_ID_2', '100001100001', 'test_module_gen_3', '', 0, 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP);