refactor: 关系图若干优化

This commit is contained in:
chenjianxing 2021-10-21 21:02:11 +08:00 committed by jianxing
parent e18937a423
commit 411ac0d079
31 changed files with 291 additions and 71 deletions

View File

@ -23,7 +23,6 @@ import org.springframework.scheduling.annotation.EnableScheduling;
JmeterProperties.class
})
@EnableScheduling
//@PropertySource(value = {"file:c:\\opt\\metersphere\\conf\\metersphere.properties"}, encoding = "UTF-8", ignoreResourceNotFound = true)
@PropertySource(value = {"file:/opt/metersphere/conf/metersphere.properties"}, encoding = "UTF-8", ignoreResourceNotFound = true)
public class Application {
public static void main(String[] args) {

View File

@ -315,6 +315,11 @@ public class ApiDefinitionController {
return apiDefinitionService.getRelationshipApi(id, relationshipType);
}
@GetMapping("/relationship/count/{id}/")
public int getRelationshipApi(@PathVariable("id") String id) {
return apiDefinitionService.getRelationshipCount(id);
}
@PostMapping("/relationship/relate/{goPage}/{pageSize}")
public Pager< List<ApiDefinitionResult>> getRelationshipRelateList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiDefinitionRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);

View File

@ -1607,16 +1607,21 @@ public class ApiDefinitionService {
return extApiDefinitionMapper.countQuotedApiByProjectId(projectId);
}
public int getRelationshipCount(String id) {
return relationshipEdgeService.getRelationshipCount(id, extApiDefinitionMapper::countByIds);
}
public List<RelationshipEdgeDTO> getRelationshipApi(String id, String relationshipType) {
List<RelationshipEdge> relationshipEdges = relationshipEdgeService.getRelationshipEdgeByType(id, relationshipType);
List<String> ids = relationshipEdgeService.getRelationIdsByType(relationshipType, relationshipEdges);
if (CollectionUtils.isNotEmpty(ids)) {
ApiDefinitionExample example = new ApiDefinitionExample();
example.createCriteria().andIdIn(ids);
example.createCriteria().andIdIn(ids).andStatusNotEqualTo("Trash");
List<ApiDefinition> apiDefinitions = apiDefinitionMapper.selectByExample(example);
Map<String, ApiDefinition> apiMap = apiDefinitions.stream().collect(Collectors.toMap(ApiDefinition::getId, i -> i));
List<RelationshipEdgeDTO> results = new ArrayList<>();
buildUserInfo(apiDefinitions);
for (RelationshipEdge relationshipEdge : relationshipEdges) {
RelationshipEdgeDTO relationshipEdgeDTO = new RelationshipEdgeDTO();
BeanUtils.copyBean(relationshipEdgeDTO, relationshipEdge);
@ -1627,8 +1632,9 @@ public class ApiDefinitionService {
apiDefinition = apiMap.get(relationshipEdge.getSourceId());
}
relationshipEdgeDTO.setTargetName(apiDefinition.getName());
relationshipEdgeDTO.setCreator(apiDefinition.getCreateUser());
relationshipEdgeDTO.setCreator(apiDefinition.getUserId());
relationshipEdgeDTO.setTargetNum(apiDefinition.getNum());
relationshipEdgeDTO.setStatus(apiDefinition.getStatus());
results.add(relationshipEdgeDTO);
}
return results;
@ -1636,6 +1642,21 @@ public class ApiDefinitionService {
return new ArrayList<>();
}
public void buildUserInfo(List<? extends ApiDefinition> apis) {
List<String> userIds = new ArrayList();
userIds.addAll(apis.stream().map(ApiDefinition::getCreateUser).collect(Collectors.toList()));
userIds.addAll(apis.stream().map(ApiDefinition::getDeleteUserId).collect(Collectors.toList()));
userIds.addAll(apis.stream().map(ApiDefinition::getUserId).collect(Collectors.toList()));
if (!org.apache.commons.collections.CollectionUtils.isEmpty(userIds)) {
Map<String, String> userMap = ServiceUtils.getUserNameMap(userIds);
apis.forEach(caseResult -> {
caseResult.setCreateUser(userMap.get(caseResult.getCreateUser()));
caseResult.setDeleteUserId(userMap.get(caseResult.getDeleteUserId()));
caseResult.setUserId(userMap.get(caseResult.getUserId()));
});
}
}
public List<ApiDefinitionResult> getRelationshipRelateList(ApiDefinitionRequest request) {
request = this.initRequest(request, true, true);
List<String> relationshipIds = relationshipEdgeService.getRelationshipIds(request.getId());

View File

@ -76,4 +76,6 @@ public interface ExtApiDefinitionMapper {
long countQuotedApiByProjectId(String projectId);
List<RelationshipGraphData.Node> getForGraph(@Param("ids") Set<String> ids);
int countByIds(@Param("ids") List<String> ids);
}

View File

@ -720,5 +720,13 @@
where t3.api_definition_id = #{apiDefinitionId}
and t3.`status`!='Trash'
</select>
<select id="countByIds" resultType="java.lang.Integer">
select count(id) from api_definition
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
and api_definition.status != 'Trash';
</select>
</mapper>

View File

@ -123,4 +123,6 @@ public interface ExtTestCaseMapper {
List<TestCase> getTestCase(@Param("request") QueryTestCaseRequest request);
List<RelationshipGraphData.Node> getTestCaseForGraph(@Param("ids") Set<String> ids);
int countByIds(@Param("ids") List<String> ids);
}

View File

@ -574,6 +574,15 @@
</foreach>
and (test_case.status != 'Trash' or test_case.status is NULL);
</select>
<select id="countByIds" resultType="java.lang.Integer">
select count(id)
from test_case
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
and (test_case.status != 'Trash' or test_case.status is NULL);
</select>
<update id="deleteToGc">
update test_case set original_status=status,

View File

@ -1,6 +1,8 @@
package io.metersphere.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.CustomField;
@ -13,6 +15,7 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.QueryCustomFieldRequest;
import io.metersphere.dto.CustomFieldDao;
import io.metersphere.dto.CustomFieldItemDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn;
@ -205,4 +208,13 @@ public class CustomFieldService {
}
return null;
}
public static List<CustomFieldItemDTO> getCustomFields(String customFieldsStr) {
if (StringUtils.isNotBlank(customFieldsStr)) {
if (JSONObject.parse(customFieldsStr) instanceof JSONArray) {
return JSONArray.parseArray(customFieldsStr, CustomFieldItemDTO.class);
}
}
return new ArrayList<>();
}
}

View File

@ -18,6 +18,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
@ -97,6 +98,17 @@ public class RelationshipEdgeService {
return relationshipEdgeMapper.selectByExample(example);
}
public List<RelationshipEdge> getBySourceIdOrTargetId(String id) {
RelationshipEdgeExample example = new RelationshipEdgeExample();
example.createCriteria()
.andSourceIdEqualTo(id);
example.or(
example.createCriteria()
.andTargetIdEqualTo(id)
);
return relationshipEdgeMapper.selectByExample(example);
}
/**
* 保存新的边
* 校验是否存在环
@ -128,11 +140,16 @@ public class RelationshipEdgeService {
});
}
// 判断是否有环, 两个方向都搜索一遍
if (directedCycle(request.getId(), relationshipEdges, new HashSet<>(), true) ||
directedCycle(request.getId(), relationshipEdges, new HashSet<>(), false)) {
HashSet<String> nodeIds = new HashSet<>();
nodeIds.addAll(relationshipEdges.stream().map(RelationshipEdge::getSourceId).collect(Collectors.toSet()));
nodeIds.addAll(relationshipEdges.stream().map(RelationshipEdge::getTargetId).collect(Collectors.toSet()));
// 判断是否有环
HashSet<String> visitedSet = new HashSet<>();
nodeIds.forEach(nodeId -> {
if (!visitedSet.contains(nodeId) && directedCycle(nodeId, relationshipEdges, new HashSet<>(), visitedSet)) {
MSException.throwException("关联后存在循环依赖,请检查依赖关系");
};
});
relationshipEdges.forEach(item -> {
if (addEdgesIds.contains(item.getSourceId() + item.getTargetId())) {
@ -186,11 +203,11 @@ public class RelationshipEdgeService {
* 给定一点深度搜索该连通图中是否存在环
* @param id
* @param edges
* @param markSet
* @param isForwardDirection
* @param markSet 标记该路径上经过的节点
* @param visitedSet 标记访问过的节点
* @return
*/
public boolean directedCycle(String id, List<RelationshipEdge> edges, Set<String> markSet, Boolean isForwardDirection) {
public boolean directedCycle(String id, List<RelationshipEdge> edges, Set<String> markSet, Set<String> visitedSet) {
if (markSet.contains(id)) {
// 如果已经访问过该节点则说明存在环
@ -198,23 +215,19 @@ public class RelationshipEdgeService {
}
markSet.add(id);
visitedSet.add(id);
ArrayList<String> nextLevelNodes = new ArrayList();
for (RelationshipEdge relationshipEdge : edges) {
if (isForwardDirection) {// 正向则搜索 sourceId 是当前节点的边
if (id.equals(relationshipEdge.getSourceId())) {
nextLevelNodes.add(relationshipEdge.getTargetId());
}
} else {
if (id.equals(relationshipEdge.getTargetId())) {
nextLevelNodes.add(relationshipEdge.getSourceId());
}
}
}
for (String nextNode : nextLevelNodes) {
if (directedCycle(nextNode, edges, markSet, isForwardDirection)) {
if (directedCycle(nextNode, edges, markSet, visitedSet)) {
return true;
};
}
}
// 关键递归完这一条路径要把这个标记去掉否则会误判为有环
@ -225,17 +238,24 @@ public class RelationshipEdgeService {
}
/**
* 给定一个节点获取跟他关联的所有节点的id
* 给定一个节点获取直接关联的节点的id
* @param nodeId
* @return
*/
public List<String> getRelationshipIds(String nodeId) {
List<RelationshipEdge> sourceRelationshipEdges = getBySourceId(nodeId);
List<RelationshipEdge> targetRelationshipEdges = getByTargetId(nodeId);
List<RelationshipEdge> sourceRelationshipEdges = getBySourceIdOrTargetId(nodeId);
List<String> ids = sourceRelationshipEdges.stream().map(RelationshipEdge::getTargetId).collect(Collectors.toList());
ids.addAll(targetRelationshipEdges.stream().map(RelationshipEdge::getSourceId).collect(Collectors.toList()));
ids.addAll(sourceRelationshipEdges.stream().map(RelationshipEdge::getSourceId).collect(Collectors.toList()));
ids.add(nodeId);
return ids;
}
public int getRelationshipCount(String id, Function<List<String>, Integer> countByIdsFunc) {
List<String> ids = getRelationshipIds(id);
ids = ids.stream().filter(i -> !i.equals(id)).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(ids)) {
return countByIdsFunc.apply(ids);
}
return 0;
}
}

View File

@ -105,6 +105,11 @@ public class TestCaseController {
return testCaseService.getRelationshipCase(id, relationshipType);
}
@GetMapping("/relationship/case/count/{id}")
public int getRelationshipCase(@PathVariable("id") String id) {
return testCaseService.getRelationshipCount(id);
}
@GetMapping("recent/{count}")
public List<TestCase> recentTestPlans(@PathVariable int count) {
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();

View File

@ -1,6 +1,5 @@
package io.metersphere.track.issue;
import com.alibaba.fastjson.JSONArray;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.IssuesMapper;
import io.metersphere.base.mapper.ProjectMapper;
@ -11,10 +10,7 @@ import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.IntegrationRequest;
import io.metersphere.dto.CustomFieldItemDTO;
import io.metersphere.dto.UserDTO;
import io.metersphere.service.IntegrationService;
import io.metersphere.service.ProjectService;
import io.metersphere.service.ResourceService;
import io.metersphere.service.UserService;
import io.metersphere.service.*;
import io.metersphere.track.request.testcase.IssuesRequest;
import io.metersphere.track.request.testcase.IssuesUpdateRequest;
import io.metersphere.track.service.TestCaseIssueService;
@ -218,13 +214,6 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
}
}
protected List<CustomFieldItemDTO> getCustomFields(String customFieldsStr) {
if (StringUtils.isNotBlank(customFieldsStr)) {
return JSONArray.parseArray(customFieldsStr, CustomFieldItemDTO.class);
}
return new ArrayList<>();
}
/**
* 将html格式的缺陷描述转成ms平台的格式
*
@ -347,7 +336,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
}
protected void addCustomFields(IssuesUpdateRequest issuesRequest, MultiValueMap<String, Object> paramMap) {
List<CustomFieldItemDTO> customFields = getCustomFields(issuesRequest.getCustomFields());
List<CustomFieldItemDTO> customFields = CustomFieldService.getCustomFields(issuesRequest.getCustomFields());
customFields.forEach(item -> {
if (StringUtils.isNotBlank(item.getCustomData())) {
paramMap.add(item.getCustomData(), item.getValue());

View File

@ -11,6 +11,7 @@ import io.metersphere.commons.utils.EncryptUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.dto.CustomFieldItemDTO;
import io.metersphere.dto.UserDTO;
import io.metersphere.service.CustomFieldService;
import io.metersphere.track.dto.DemandDTO;
import io.metersphere.track.issue.client.JiraClientV2;
import io.metersphere.track.issue.domain.Jira.JiraAddIssueResponse;
@ -109,7 +110,7 @@ public class JiraPlatform extends AbstractIssuePlatform {
}
public String parseIssueCustomField(String customFieldsStr, JiraIssue jiraIssue) {
List<CustomFieldItemDTO> customFields = getCustomFields(customFieldsStr);
List<CustomFieldItemDTO> customFields = CustomFieldService.getCustomFields(customFieldsStr);
JSONObject fields = jiraIssue.getFields();
customFields.forEach(item -> {
@ -286,7 +287,7 @@ public class JiraPlatform extends AbstractIssuePlatform {
JSONObject addJiraIssueParam = new JSONObject();
addJiraIssueParam.put("fields", fields);
List<CustomFieldItemDTO> customFields = getCustomFields(issuesRequest.getCustomFields());
List<CustomFieldItemDTO> customFields = CustomFieldService.getCustomFields(issuesRequest.getCustomFields());
jiraClientV2.setConfig(config);
customFields.forEach(item -> {

View File

@ -15,7 +15,6 @@ import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.ResultHolder;
import io.metersphere.dto.CustomFieldItemDTO;
import io.metersphere.dto.UserDTO;
import io.metersphere.service.SystemParameterService;
import io.metersphere.track.dto.DemandDTO;

View File

@ -10,6 +10,7 @@ import io.metersphere.api.dto.automation.ApiScenarioDTO;
import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.api.service.ApiTestCaseService;
import io.metersphere.base.domain.*;
@ -1973,8 +1974,9 @@ public class TestCaseService {
if (CollectionUtils.isNotEmpty(ids)) {
TestCaseExample example = new TestCaseExample();
example.createCriteria().andIdIn(ids);
List<TestCase> testCaseList = testCaseMapper.selectByExample(example);
example.createCriteria().andIdIn(ids).andStatusNotEqualTo("Trash");
List<TestCaseWithBLOBs> testCaseList = testCaseMapper.selectByExampleWithBLOBs(example);
buildUserInfo(testCaseList);
Map<String, TestCase> caseMap = testCaseList.stream().collect(Collectors.toMap(TestCase::getId, i -> i));
List<RelationshipEdgeDTO> results = new ArrayList<>();
for (RelationshipEdge relationshipEdge : relationshipEdges) {
@ -1990,10 +1992,30 @@ public class TestCaseService {
relationshipEdgeDTO.setCreator(testCase.getCreateUser());
relationshipEdgeDTO.setTargetNum(testCase.getNum());
relationshipEdgeDTO.setTargetCustomNum(testCase.getCustomNum());
relationshipEdgeDTO.setStatus(testCase.getStatus());
results.add(relationshipEdgeDTO);
}
return results;
}
return new ArrayList<>();
}
public void buildUserInfo(List<? extends TestCase> testCases) {
List<String> userIds = new ArrayList();
userIds.addAll(testCases.stream().map(TestCase::getCreateUser).collect(Collectors.toList()));
userIds.addAll(testCases.stream().map(TestCase::getDeleteUserId).collect(Collectors.toList()));
userIds.addAll(testCases.stream().map(TestCase::getMaintainer).collect(Collectors.toList()));
if (!org.apache.commons.collections.CollectionUtils.isEmpty(userIds)) {
Map<String, String> userMap = ServiceUtils.getUserNameMap(userIds);
testCases.forEach(caseResult -> {
caseResult.setCreateUser(userMap.get(caseResult.getCreateUser()));
caseResult.setDeleteUserId(userMap.get(caseResult.getDeleteUserId()));
caseResult.setMaintainer(userMap.get(caseResult.getMaintainer()));
});
}
}
public int getRelationshipCount(String id) {
return relationshipEdgeService.getRelationshipCount(id, extTestCaseMapper::countByIds);
}
}

@ -1 +1 @@
Subproject commit 6aff490dd3321a760e2a519c0cb6aa6c90850f3f
Subproject commit a86e39275aae2a3e2e8aae705da5a4dddbd0089d

View File

@ -9,7 +9,10 @@
<form-rich-text-item class="remark-item" :disabled="readOnly && !hasPermissions" :data="api" prop="remark" label-width="0"/>
</el-tab-pane>
<el-tab-pane :label="$t('commons.relationship.name')" name="dependencies" class="pane">
<dependencies-list :read-only="readOnly" :resource-id="api.id" resource-type="API" ref="dependencies"/>
<template v-slot:label>
<tab-pane-count :title="$t('commons.relationship.name')" :count="relationshipCount"/>
</template>
<dependencies-list @setCount="setCount" :read-only="readOnly" :resource-id="api.id" resource-type="API" ref="dependencies"/>
</el-tab-pane>
</el-tabs>
</el-collapse-transition>
@ -24,13 +27,16 @@ import ApiInfoContainer from "@/business/components/api/definition/components/co
import DependenciesList from "@/business/components/common/components/graph/DependenciesList";
import FormRichTextItem from "@/business/components/track/case/components/FormRichTextItem";
import {hasPermissions} from "@/common/js/utils";
import TabPaneCount from "@/business/components/track/plan/view/comonents/report/detail/component/TabPaneCount";
import {getRelationshipCountApi} from "@/network/api";
export default {
name: "ApiOtherInfo",
components: {FormRichTextItem, DependenciesList, ApiInfoContainer, MsFormDivider},
components: {TabPaneCount, FormRichTextItem, DependenciesList, ApiInfoContainer, MsFormDivider},
props: ['api','readOnly'],
data() {
return {
activeName: 'remark'
activeName: 'remark',
relationshipCount: 0
}
},
computed: {
@ -43,8 +49,18 @@ export default {
if (this.activeName === 'dependencies') {
this.$refs.dependencies.open();
}
}
},
},
mounted() {
getRelationshipCountApi(this.api.id, (data) => {
this.relationshipCount = data;
});
},
methods: {
setCount(count) {
this.relationshipCount = count;
},
}
}
</script>

View File

@ -26,6 +26,17 @@
min-width="120">
</ms-table-column>
<ms-table-column
prop="status"
min-width="120px"
:label="$t('api_test.definition.api_status')">
<template v-slot:default="scope">
<span class="el-dropdown-link">
<api-status :value="scope.row.status"/>
</span>
</template>
</ms-table-column>
</ms-table>
<api-relationship-relevance
@ -46,9 +57,12 @@ import RelationshipFunctionalRelevance
import {getRelationshipApi} from "@/network/api";
import ApiRelationshipRelevance
from "@/business/components/api/definition/components/complete/ApiRelationshipRelevance";
import ApiStatus from "@/business/components/api/definition/components/list/ApiStatus";
export default {
name: "ApiRelationshipList",
components: {ApiRelationshipRelevance, RelationshipFunctionalRelevance, MsTableSearchBar, MsTableColumn, MsTable},
components: {
ApiStatus,
ApiRelationshipRelevance, RelationshipFunctionalRelevance, MsTableSearchBar, MsTableColumn, MsTable},
data() {
return {
result: {},
@ -74,6 +88,7 @@ export default {
getTableData() {
getRelationshipApi(this.apiDefinitionId, this.relationshipType, (data) => {
this.data = data;
this.$emit('setCount', data.length);
});
},
openRelevance() {

View File

@ -1,11 +1,23 @@
<template>
<div class="dependencies-container">
<el-main v-xpack>
<i class="el-icon-view" @click="openGraph"></i>
</el-main>
<relationship-list :read-only="readOnly" :title="$t('commons.relationship.pre')" relationship-type="PRE" :resource-id="resourceId" :resource-type="resourceType" ref="preRelationshipList"/>
<relationship-list :read-only="readOnly" :title="$t('commons.relationship.post')" relationship-type="POST" :resource-id="resourceId" :resource-type="resourceType" ref="postRelationshipList"/>
<el-tooltip v-xpack class="item" effect="dark" :content="$t('commons.relationship.graph')" placement="left">
<font-awesome-icon class="graph-icon" :icon="['fas', 'sitemap']" size="lg" @click="openGraph"/>
</el-tooltip>
<relationship-list
class="pre-list"
:read-only="readOnly" :title="resourceType === 'TEST_CASE' ? $t('commons.relationship.pre_case') : $t('commons.relationship.pre_api')"
relationship-type="PRE" :resource-id="resourceId"
@setCount="setPreCount"
:resource-type="resourceType" ref="preRelationshipList"/>
<relationship-list
class="post-list"
:read-only="readOnly"
:title="resourceType === 'TEST_CASE' ? $t('commons.relationship.post_case') : $t('commons.relationship.post_api')"
relationship-type="POST" :resource-id="resourceId"
@setCount="setPostCount"
:resource-type="resourceType" ref="postRelationshipList"/>
<relationship-graph-drawer v-permission :graph-data="graphData" ref="relationshipGraph"/>
@ -26,7 +38,9 @@ export default {
],
data() {
return {
graphData: {}
graphData: {},
preCount: 0,
postCount: 0,
}
},
methods: {
@ -39,13 +53,26 @@ export default {
this.graphData = data;
this.$refs.relationshipGraph.open();
});
}
},
setPreCount(count) {
this.preCount = count;
this.$emit('setCount', this.preCount + this.postCount);
},
setPostCount(count) {
this.postCount = count;
this.$emit('setCount', this.preCount + this.postCount);
},
}
}
</script>
<style scoped>
.dependencies-container .el-main {
.post-list {
margin-top: 20px;
}
.graph-icon {
float: right;
margin-right: 20px;
}
</style>

View File

@ -9,6 +9,7 @@
:case-id="resourceId"
:read-only="readOnly"
:relationship-type="relationshipType"
@setCount="setCount"
@deleteRelationship="handleDelete"
ref="testCaseRelationshipList"/>
@ -17,6 +18,7 @@
:read-only="readOnly"
:api-definition-id="resourceId"
:relationship-type="relationshipType"
@setCount="setCount"
@deleteRelationship="handleDelete"
ref="testCaseRelationshipList"/>
@ -66,6 +68,9 @@ export default {
this.$success(this.$t('commons.delete_success'));
});
},
setCount(count) {
this.$emit('setCount', count);
}
}
}
</script>

View File

@ -337,6 +337,7 @@
getTestTemplate()
.then((template) => {
this.testCaseTemplate = template;
this.$store.commit('setTestCaseTemplate', this.testCaseTemplate);
initAddFuc();
});
if (this.selectNode && this.selectNode.data && !this.form.id) {
@ -461,6 +462,7 @@
getTemplate('field/template/case/get/relate/', this)
.then((template) => {
this.testCaseTemplate = template;
this.$store.commit('setTestCaseTemplate', this.testCaseTemplate);
initFuc(testCase);
});
},

View File

@ -40,7 +40,10 @@
</el-tab-pane>
<el-tab-pane :label="$t('commons.relationship.name')" name="relationship">
<dependencies-list :read-only="readOnly" :resource-id="caseId" resource-type="TEST_CASE" ref="relationship"/>
<template v-slot:label>
<tab-pane-count :title="$t('commons.relationship.name')" :count="relationshipCount"/>
</template>
<dependencies-list @setCount="setRelationshipCount" :read-only="readOnly" :resource-id="caseId" resource-type="TEST_CASE" ref="relationship"/>
</el-tab-pane>
<el-tab-pane :label="$t('test_track.case.attachment')" name="attachment">
@ -83,10 +86,13 @@ import TestCaseIssueRelate from "@/business/components/track/case/components/Tes
import FormRichTextItem from "@/business/components/track/case/components/FormRichTextItem";
import TestCaseTestRelate from "@/business/components/track/case/components/TestCaseTestRelate";
import DependenciesList from "@/business/components/common/components/graph/DependenciesList";
import TabPaneCount from "@/business/components/track/plan/view/comonents/report/detail/component/TabPaneCount";
import {getRelationshipCountCase} from "@/network/testCase";
export default {
name: "TestCaseEditOtherInfo",
components: {
TabPaneCount,
DependenciesList,
TestCaseTestRelate,
FormRichTextItem, TestCaseIssueRelate, TestCaseAttachment, MsRichText, TestCaseRichText},
@ -99,6 +105,7 @@ export default {
fileList: [],
tableData: [],
demandOptions: [],
relationshipCount: 0,
//sysList:this.sysList,//
props: {
multiple: true,
@ -123,12 +130,20 @@ export default {
} else if (this.tabActiveName === 'attachment') {
this.getFileMetaData();
}
},
caseId() {
getRelationshipCountCase(this.caseId, (data) => {
this.relationshipCount = data;
});
}
},
methods: {
updateRemark(text) {
this.form.remark = text;
},
setRelationshipCount(count) {
this.relationshipCount = count;
},
reset() {
this.tabActiveName = "remark";
},

View File

@ -33,6 +33,15 @@
min-width="120">
</ms-table-column>
<ms-table-column
prop="status"
min-width="100px"
:label="$t('api_test.definition.api_case_status')">
<template slot-scope="{row}">
{{$t(statusMap.get(row.status))}}
</template>
</ms-table-column>
</ms-table>
<relationship-functional-relevance
@ -68,6 +77,7 @@ export default {
],
condition: {},
options: [],
statusMap: new Map,
value: ''
}
},
@ -78,6 +88,14 @@ export default {
},
computed: {
isCustomNum() {
let template = this.$store.state.testCaseTemplate;
template.customFields.forEach(item => {
if (item.name === '用例状态') {
for (let i = 0; i < item.options.length; i++) {
this.statusMap.set(item.options[i].value, item.options[i].text);
}
}
});
return this.$store.state.currentProjectIsCustomNum;
},
},
@ -85,6 +103,7 @@ export default {
getTableData() {
getRelationshipCase(this.caseId, this.relationshipType, (data) => {
this.data = data;
this.$emit('setCount', data.length);
});
},
openRelevance() {

View File

@ -1,7 +1,7 @@
<template>
<span>
<span>{{title}}</span>
<span class="el-step__icon is-text ms-api-col ms-header" v-if="count > 0">
<span class="el-step__icon is-text ms-api-col ms-header" :class="{'fix-color': fixColor}" v-if="count > 0">
<span class="el-step__icon-inner">{{count}}</span>
</span>
</span>
@ -10,7 +10,7 @@
<script>
export default {
name: "TabPaneCount",
props: ['title', 'count']
props: ['title', 'count', 'fixColor']
}
</script>
@ -24,4 +24,14 @@ export default {
/*border-radius: 42%;*/
/*margin-left: 4px;*/
}
.fix-color {
background: #783887;
color: white;
/*color: #783887;*/
/*height: 20px;*/
/*border: 0px !important;*/
border-radius: 42%;
margin-left: 4px;
}
</style>

@ -1 +1 @@
Subproject commit a6da67c67e912b419efda9a2cdd2546dcac48075
Subproject commit ffab6a94b62dd5a8324b2e226b05ea3f6243f169

View File

@ -189,13 +189,14 @@ export default {
generate_test_data: "Generate test data",
relationship: {
name: 'Dependencies',
pre: 'Prepositional Object',
post: 'Postposition Object',
pre_case: 'Prepositional Case',
post_case: 'Postposition Case',
pre_api: 'Prepositional API',
post_api: 'Postposition API',
graph: 'Dependencies Graph',
selected: 'Selected Node',
direct: 'Direct Link',
indirect: 'Indirect Link',
},
project_setting: "Project Setting",
table: {

View File

@ -189,9 +189,11 @@ export default {
run_fail: "执行失败",
relationship: {
name: '依赖关系',
pre: '前置对象',
post: '后置置对象',
graph: '依赖图',
pre_case: '前置用例',
post_case: '后置用例',
pre_api: '前置接口',
post_api: '后置接口',
graph: '依赖关系图',
selected: '选中节点',
direct: '直接关联',
indirect: '间接关联',

View File

@ -189,9 +189,11 @@ export default {
run_fail: "執行失敗",
relationship: {
name: '依賴關系',
pre: '前置對象',
post: '後置置對象',
graph: '依賴圖',
pre_case: '前置用例',
post_case: '後置用例',
pre_api: '前置接口',
post_api: '後置接口',
graph: '依賴關系圖',
selected: '選中節點',
direct: '直接關聯',
indirect: '間接關聯',

View File

@ -35,3 +35,7 @@ export function editApiTestCaseOrder(request, callback) {
export function getRelationshipApi(id, relationshipType, callback) {
return baseGet('/api/definition/relationship/' + id + '/' + relationshipType, callback);
}
export function getRelationshipCountApi(id, callback) {
return baseGet('/api/definition/relationship/count/' + id + '/', callback);
}

View File

@ -70,3 +70,7 @@ export function getTestCaseNodes(projectId, callback) {
export function getRelationshipCase(id, relationshipType, callback) {
return baseGet('/test/case/relationship/case/' + id + '/' + relationshipType, callback);
}
export function getRelationshipCountCase(id, callback) {
return baseGet('/test/case/relationship/case/count/' + id + '/', callback);
}

View File

@ -28,7 +28,8 @@ const state = {
pluginFiles: [],
isTestCaseMinderChanged: false,
// 当前项目是否勾选自定义ID
currentProjectIsCustomNum: false
currentProjectIsCustomNum: false,
testCaseTemplate: {},
}
const store = new Vuex.Store({

View File

@ -17,6 +17,9 @@ const mutations = {
setTestPlanViewSelectNode: (state, value) => state.testPlanViewSelectNode = value,
setIsTestCaseMinderChanged: (state, value) => state.isTestCaseMinderChanged = value,
setCurrentProjectIsCustomNum: (state, value) => state.currentProjectIsCustomNum = value,
setTestCaseTemplate: (state, value) => {
state.testCaseTemplate = value
},
}
export default mutations;