feat(测试跟踪): 功能用例关联用例弹窗模块树显示数量

--story=1011262 --user=宋昌昌 【Bug转需求】【测试跟踪】功能用例-编辑-关联测试用例-接口/场景/UI/性能用例-关联弹框-模块树和标题均未显示用例数量 https://www.tapd.cn/55049933/s/1359679
This commit is contained in:
song-cc-rock 2023-04-07 11:48:34 +08:00
parent 374c85f159
commit 60ed39d2f5
14 changed files with 178 additions and 71 deletions

View File

@ -48,6 +48,8 @@ public interface ExtApiDefinitionMapper {
List<ApiModuleDTO> moduleCountByCollection(@Param("request") ApiDefinitionRequest request);
List<ApiModuleDTO> moduleCaseCountByCollection(@Param("request") ApiDefinitionRequest request);
int checkOriginalStatusByIds(@Param("ids") List<String> ids);
List<String> getIdsOrderByUpdateTime(@Param("projectId") String projectId);

View File

@ -706,6 +706,72 @@
GROUP BY module_id
</select>
<select id="moduleCaseCountByCollection" resultType="io.metersphere.api.dto.definition.ApiModuleDTO">
select ad.module_id AS id, count(atc.id) AS caseNum
from api_test_case atc join api_definition ad on atc.api_definition_id = ad.id
where (atc.status is null or atc.status != 'Trash')
<if test="request.protocol != null and request.protocol!=''">
and ad.protocol = #{request.protocol}
</if>
<if test="request.projectId != null and request.projectId!=''">
and ad.project_id = #{request.projectId}
</if>
<if test="request.name != null and request.name!=''">
and (atc.name like CONCAT('%', #{request.name},'%')
or atc.tags like CONCAT('%', #{request.name},'%')
or atc.num like CONCAT('%', #{request.name},'%'))
</if>
<if test="request.notInIds != null and request.notInIds.size() > 0">
and atc.id not in
<foreach collection="request.notInIds" item="notInId" separator="," open="(" close=")">
#{notInId}
</foreach>
</if>
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and ad.module_id in
<foreach collection="request.moduleIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<if test="request.combine != null">
<include refid="relevanceApiCombine">
<property name="condition" value="request.combine"/>
<property name="name" value="request.name"/>
<property name="objectKey" value="request.combine.tags"/>
</include>
</if>
<include refid="relevanceApiVersionCondition">
<property name="versionTable" value="ad"/>
</include>
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key == 'priority'">
and atc.priority in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='status'">
and atc.status in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='version_id'">
and atc.version_id in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
</choose>
</if>
</foreach>
</if>
GROUP BY module_id
</select>
<sql id="filter">
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
@ -1215,4 +1281,57 @@
</where>
</sql>
<sql id="relevanceApiCombine">
<if test='${condition}.name != null and (${name} == null or ${name} == "")'>
and atc.name
<include refid="condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test="${condition}.updateTime != null">
and atc.update_time
<include refid="condition">
<property name="object" value="${condition}.updateTime"/>
</include>
</if>
<if test="${condition}.createTime != null">
and atc.create_time
<include refid="condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<if test="${condition}.priority != null">
and atc.priority
<include refid="condition">
<property name="object" value="${condition}.priority"/>
</include>
</if>
<if test="${condition}.status != null">
and atc.status
<include refid="condition">
<property name="object" value="${condition}.status"/>
</include>
</if>
<if test='${condition}.tags != null and ${objectKey}.operator == "like"'>
and atc.tags
<include refid="condition">
<property name="object" value="${condition}.tags"/>
</include>
</if>
<if test="${condition}.creator != null">
and atc.create_user_id
<include refid="condition">
<property name="object" value="${condition}.creator"/>
</include>
</if>
</sql>
<sql id="relevanceApiVersionCondition">
<if test="request.versionId != null">
and ${versionTable}.version_id = #{request.versionId}
</if>
<if test="request.versionId == null and request.id == null">
and ${versionTable}.latest = 1
</if>
</sql>
</mapper>

View File

@ -30,6 +30,13 @@ public class ApiModuleController {
return apiModuleService.getNodeTreeByProjectId(projectId, protocol, null);
}
@PostMapping("/relevance/list/{projectId}/{protocol}")
public List<ApiModuleDTO> getRelevanceNodeByProjectId(@PathVariable String projectId, @PathVariable String protocol, @RequestBody ApiDefinitionRequest request) {
String userId = SessionUtils.getUserId();
ApiDefinitionDefaultApiTypeUtil.addUserSelectApiType(userId, protocol);
return apiModuleService.getNodeTreeByCondition(projectId, protocol, null, request, true);
}
@GetMapping("/list/{projectId}/{protocol}/{versionId}")
public List<ApiModuleDTO> getNodeByProjectId(@PathVariable String projectId, @PathVariable String protocol,
@PathVariable String versionId) {
@ -42,7 +49,7 @@ public class ApiModuleController {
public List<ApiModuleDTO> searchNodeByProjectId(@PathVariable String projectId, @PathVariable String protocol, @RequestBody ApiDefinitionRequest request) {
String userId = SessionUtils.getUserId();
ApiDefinitionDefaultApiTypeUtil.addUserSelectApiType(userId, protocol);
return apiModuleService.getNodeTreeByCondition(projectId, protocol, null, request);
return apiModuleService.getNodeTreeByCondition(projectId, protocol, null, request, false);
}
@GetMapping("/trash/list/{projectId}/{protocol}/{versionId}")

View File

@ -142,10 +142,10 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
public List<ApiModuleDTO> getNodeTreeByProjectId(String projectId, String protocol, String versionId) {
ApiDefinitionRequest request = new ApiDefinitionRequest();
return getNodeTreeByCondition(projectId, protocol, versionId, request);
return getNodeTreeByCondition(projectId, protocol, versionId, request, false);
}
public List<ApiModuleDTO> getNodeTreeByCondition(String projectId, String protocol, String versionId, ApiDefinitionRequest request) {
public List<ApiModuleDTO> getNodeTreeByCondition(String projectId, String protocol, String versionId, ApiDefinitionRequest request, boolean isCaseRelevance) {
List<ApiModuleDTO> apiModules = getApiModulesByProjectAndPro(projectId, protocol);
LogUtil.info("当前API模块节点", apiModules.size());
@ -153,7 +153,7 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
request.setProtocol(protocol);
Map<String, List<String>> filters = new LinkedHashMap<>();
filters.put(ApiTestConstants.STATUS, ApiTestConstants.STATUS_ALL);
if (MapUtils.isEmpty(request.getFilters()) || !request.getFilters().containsKey(ApiTestConstants.STATUS)) {
if ((MapUtils.isEmpty(request.getFilters()) || !request.getFilters().containsKey(ApiTestConstants.STATUS)) && !isCaseRelevance) {
request.setFilters(filters);
}
request.setModuleIds(new ArrayList<>());
@ -161,7 +161,12 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
request.setVersionId(versionId);
}
apiDefinitionService.checkFilterHasCoverage(request);
List<ApiModuleDTO> countMNodes = extApiDefinitionMapper.moduleCountByCollection(request);
List<ApiModuleDTO> countMNodes;
if (isCaseRelevance) {
countMNodes = extApiDefinitionMapper.moduleCaseCountByCollection(request);
} else {
countMNodes = extApiDefinitionMapper.moduleCountByCollection(request);
}
return getNodeTrees(apiModules, getCountMap(countMNodes));
}

View File

@ -149,6 +149,10 @@ export function getModuleByUrl(url) {
return get('/environment/relate' + url);
}
export function getCaseRelateModuleByCondition(url, params) {
return post('/environment/relate' + url, params)
}
export function getCodeSnippetPages(goPage, pageSize, params) {
if (currentModuleName === 'project') {
return post(`/custom/func/list/${goPage}/${pageSize}`, params);

View File

@ -63,6 +63,11 @@ public class EnvironmentRelateController {
return microService.getForData(MicroServiceName.API_TEST, "/api/module/list/" + projectId + "/" + protocol);
}
@PostMapping("/api/module/relevance/list/{projectId}/{protocol}")
public Object getRelevanceNodeByProjectId(@PathVariable String projectId, @PathVariable String protocol, @RequestBody Object request) {
return microService.postForData(MicroServiceName.API_TEST, "/api/module/relevance/list/" + projectId + "/" + protocol, request);
}
@PostMapping("/custom/func/list/{goPage}/{pageSize}")
public Object query(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody Object request) {
return microService.postForData(MicroServiceName.PROJECT_MANAGEMENT, String.format("/custom/func/list/%s/%s", goPage, pageSize), request);

View File

@ -268,7 +268,10 @@ export default {
? this.contentObject.content.value
: this.contentObject.content.defaultValue;
if(!tempValue || Array.isArray(tempValue) && tempValue.length <= 0){
let customVal = this.model[this.contentObject.content.name];
let customVal;
if (this.model) {
customVal = this.model[this.contentObject.content.name];
}
if (customVal) {
this.isCustomNone = false;
tempValue = customVal;

View File

@ -55,7 +55,7 @@
import ApiModuleHeader from "metersphere-frontend/src/components/environment/snippet/ext/module/ApiModuleHeader";
import {buildTree} from "metersphere-frontend/src//model/NodeTree";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {getModuleByUrl, getUserDefaultApiType} from "metersphere-frontend/src/api/environment";
import {getModuleByUrl, getUserDefaultApiType, getCaseRelateModuleByCondition} from "metersphere-frontend/src/api/environment";
export default {
name: 'MsApiModule',
@ -111,7 +111,8 @@
default() {
return OPTIONS;
}
}
},
caseCondition: Object
},
computed: {
isPlanModel() {
@ -212,22 +213,18 @@
},
list(projectId) {
let url = undefined;
if (this.isPlanModel) {
url = '/api/module/list/plan/' + this.planId + '/' + this.condition.protocol;
} else if (this.isRelevanceModel) {
url = "/api/module/list/" + this.relevanceProjectId + "/" + this.condition.protocol +
(this.currentVersion ? '/' + this.currentVersion : '');
} else if (this.isTrashData) {
url = "/api/module/trash/list/" + (projectId ? projectId : this.projectId) + "/" + this.condition.protocol +
if (this.isRelevanceModel) {
url = "/api/module/relevance/list/" + this.relevanceProjectId + "/" + this.condition.protocol +
(this.currentVersion ? '/' + this.currentVersion : '');
} else {
url = "/api/module/list/" + (projectId ? projectId : this.projectId) + "/" + this.condition.protocol +
url = "/api/module/relevance/list/" + (projectId ? projectId : this.projectId) + "/" + this.condition.protocol +
(this.currentVersion ? '/' + this.currentVersion : '');
if (!this.projectId) {
return;
}
}
this.loading = getModuleByUrl(url).then(response => {
this.loading = getCaseRelateModuleByCondition(url, this.caseCondition).then(response => {
if (response.data) {
this.data = response.data;
this.data.forEach(node => {
@ -236,10 +233,7 @@
});
this.$emit('setModuleOptions', this.data);
this.$emit('setNodeTree', this.data);
this.$emit("nodeSelectEvent", null, []);
if (this.$refs.nodeTree) {
this.$refs.nodeTree.filter(this.condition.filterText);
}
this.setCurrentNode();
}
});
},
@ -262,47 +256,14 @@
} else {
this.$emit("nodeSelectEvent", node, nodeIds, pNodes);
}
this.nohupReloadTree(node.data.id);
this.setCurrentNode(node.data.id);
},
nohupReloadTree(selectNodeId) {
let url = undefined;
if (this.isPlanModel) {
url = '/api/module/list/plan/' + this.planId + '/' + this.condition.protocol;
} else if (this.isRelevanceModel) {
url = "/api/module/list/" + this.relevanceProjectId + "/" + this.condition.protocol +
(this.currentVersion ? '/' + this.currentVersion : '');
} else if (this.isTrashData) {
if (!this.projectId) {
return;
}
url = "/api/module/trash/list/" + this.projectId + "/" + this.condition.protocol +
(this.currentVersion ? '/' + this.currentVersion : '');
setCurrentNode(selectNodeId) {
if (selectNodeId) {
this.$refs.nodeTree.justSetCurrentKey(selectNodeId);
} else {
if (!this.projectId) {
return;
}
url = "/api/module/list/" + this.projectId + "/" + this.condition.protocol +
(this.currentVersion ? '/' + this.currentVersion : '');
this.$refs.nodeTree.justSetCurrentKey(this.currentModule.id);
}
getModuleByUrl(url).then(response => {
if (response.data) {
let treeData = response.data;
treeData.forEach(node => {
node.name = node.name === '未规划接口' ? this.$t('api_test.definition.unplanned_api') : node.name
buildTree(node, {path: ''});
});
this.data = treeData;
this.$nextTick(() => {
if (this.$refs.nodeTree) {
this.$refs.nodeTree.filter(this.condition.filterText);
if (selectNodeId) {
this.$refs.nodeTree.justSetCurrentKey(selectNodeId);
}
}
})
}
})
},
//---使
createRootModel() {

View File

@ -9,12 +9,12 @@
<template v-slot:aside>
<ms-api-module
:relevance-project-id="projectId"
:show-case-num="false"
@nodeSelectEvent="nodeChange"
@protocolChange="handleProtocolChange"
@refreshTable="refresh"
@setModuleOptions="setModuleOptions"
:is-read-only="true"
:case-condition="condition"
ref="nodeTree"
/>
</template>
@ -26,6 +26,7 @@
:not-in-ids="notInIds"
:versionEnable="versionEnable"
@selectCountChange="setSelectCounts"
@setCondition="setCondition"
ref="apiCaseList"
/>
</test-case-relevance-base>
@ -73,7 +74,6 @@ export default {
}
},
open() {
this.init();
this.$refs.baseRelevance.open();
if (this.$refs.apiCaseList) {
this.$refs.apiCaseList.clear();
@ -113,6 +113,10 @@ export default {
setSelectCounts(data) {
this.$refs.baseRelevance.selectCounts = data;
},
setCondition(data) {
this.condition = data;
this.$refs.nodeTree.list(this.projectId);
},
},
};
</script>

View File

@ -173,6 +173,7 @@ export default {
},
},
created: function () {
this.$emit('setCondition', this.condition);
this.initTable();
this.getVersionOptions();
},
@ -186,8 +187,8 @@ export default {
projectId() {
this.condition.versionId = null;
this.getVersionOptions();
this.initTable();
},
this.initTable(this.projectId);
}
},
computed: {
selectRows() {
@ -218,6 +219,7 @@ export default {
this.condition.protocol = this.currentProtocol;
}
this.condition.notInIds = this.notInIds; //
this.$emit('setCondition', this.condition);
getTestCaseRelevanceApiList(
this.currentPage,
this.pageSize,

View File

@ -9,7 +9,6 @@
<template v-slot:aside>
<ms-api-scenario-module
:relevance-project-id="projectId"
:show-case-num="false"
@nodeSelectEvent="nodeChange"
@refreshTable="refresh"
@setModuleOptions="setModuleOptions"

View File

@ -9,7 +9,6 @@
<template v-slot:aside>
<ui-scenario-module
:relevance-project-id="projectId"
:show-case-num="false"
@nodeSelectEvent="nodeChange"
@refreshTable="refresh"
@setModuleOptions="setModuleOptions"

View File

@ -70,7 +70,6 @@
<select-menu
:data="projects"
v-if="multipleProject"
width="155px"
:current-data="currentProject"
:title="$t('case.project') + ':'"
@dataChange="changeProject"

View File

@ -73,16 +73,14 @@ export default {
}
.select-menu :deep(.el-input__inner) {
border: none;
padding-left: 0px !important;
padding-left: 0 !important;
display: inline-block !important;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: px2rem(80);
}
.select-menu :deep(.el-select--small) {
width: px2rem(80) !important;
max-width: px2rem(200);
}
.select-menu :deep(.el-input__suffix-inner .el-select__caret::before) {
color: #646a73;
}