From ecc7f4bb02e5fd298794595f12678b4104f4a246 Mon Sep 17 00:00:00 2001 From: chenjianxing Date: Wed, 13 Oct 2021 10:47:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8A=9F=E8=83=BD=E7=94=A8=E4=BE=8B?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=89=8D=E5=90=8E=E7=BD=AE=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../base/domain/RelationshipEdge.java | 23 + .../base/domain/RelationshipEdgeExample.java | 680 ++++++++++++++++++ .../base/mapper/RelationshipEdgeMapper.java | 22 + .../base/mapper/RelationshipEdgeMapper.xml | 199 +++++ .../base/mapper/ext/ExtTestCaseMapper.java | 2 + .../base/mapper/ext/ExtTestCaseMapper.xml | 7 + .../RelationshipEdgeController.java | 27 + .../request/RelationshipEdgeRequest.java | 13 + .../metersphere/dto/RelationshipEdgeDTO.java | 13 + .../service/RelationshipEdgeService.java | 103 +++ .../track/controller/TestCaseController.java | 11 + .../testcase/QueryTestCaseRequest.java | 4 + .../track/service/TestCaseService.java | 38 +- .../db/migration/V97__v1.14_release.sql | 17 +- .../src/main/resources/generatorConfig.xml | 2 +- .../components/track/case/TestCase.vue | 6 +- .../RelationshipFunctionalRelevance.vue | 93 +++ .../track/case/components/TestCaseEdit.vue | 14 +- .../case/components/TestCaseEditOtherInfo.vue | 10 + .../track/case/components/TestCaseList.vue | 7 +- .../components/TestCaseRelationshipList.vue | 121 ++++ .../track/common/TestCaseNodeTree.vue | 5 +- .../track/plan/view/TestPlanView.vue | 3 +- .../plan/view/comonents/api/TestPlanApi.vue | 2 - .../comonents/base/TestCaseRelevanceBase.vue | 5 + ...lRelevance.vue => FunctionalRelevance.vue} | 111 +-- .../functional/TestPlanFunctional.vue | 9 +- .../TestPlanFunctionalRelevance.vue | 88 +++ .../review/view/components/TestReviewApi.vue | 2 - frontend/src/network/relationship-edge.js | 6 + frontend/src/network/testCase.js | 8 + frontend/src/store/index.js | 4 +- frontend/src/store/mutations.js | 1 + 33 files changed, 1549 insertions(+), 107 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/base/domain/RelationshipEdge.java create mode 100644 backend/src/main/java/io/metersphere/base/domain/RelationshipEdgeExample.java create mode 100644 backend/src/main/java/io/metersphere/base/mapper/RelationshipEdgeMapper.java create mode 100644 backend/src/main/java/io/metersphere/base/mapper/RelationshipEdgeMapper.xml create mode 100644 backend/src/main/java/io/metersphere/controller/RelationshipEdgeController.java create mode 100644 backend/src/main/java/io/metersphere/controller/request/RelationshipEdgeRequest.java create mode 100644 backend/src/main/java/io/metersphere/dto/RelationshipEdgeDTO.java create mode 100644 backend/src/main/java/io/metersphere/service/RelationshipEdgeService.java create mode 100644 frontend/src/business/components/track/case/components/RelationshipFunctionalRelevance.vue create mode 100644 frontend/src/business/components/track/case/components/TestCaseRelationshipList.vue rename frontend/src/business/components/track/plan/view/comonents/functional/{TestCaseFunctionalRelevance.vue => FunctionalRelevance.vue} (71%) create mode 100644 frontend/src/business/components/track/plan/view/comonents/functional/TestPlanFunctionalRelevance.vue create mode 100644 frontend/src/network/relationship-edge.js diff --git a/backend/src/main/java/io/metersphere/base/domain/RelationshipEdge.java b/backend/src/main/java/io/metersphere/base/domain/RelationshipEdge.java new file mode 100644 index 0000000000..dfdc4fff62 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/RelationshipEdge.java @@ -0,0 +1,23 @@ +package io.metersphere.base.domain; + +import java.io.Serializable; +import lombok.Data; + +@Data +public class RelationshipEdge implements Serializable { + private String sourceId; + + private String targetId; + + private String relationshipType; + + private String resourceType; + + private String graphId; + + private String creator; + + private Long createTime; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/RelationshipEdgeExample.java b/backend/src/main/java/io/metersphere/base/domain/RelationshipEdgeExample.java new file mode 100644 index 0000000000..2503e3caa7 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/RelationshipEdgeExample.java @@ -0,0 +1,680 @@ +package io.metersphere.base.domain; + +import java.util.ArrayList; +import java.util.List; + +public class RelationshipEdgeExample { + protected String orderByClause; + + protected boolean distinct; + + protected List oredCriteria; + + public RelationshipEdgeExample() { + oredCriteria = new ArrayList(); + } + + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; + } + + public String getOrderByClause() { + return orderByClause; + } + + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + + public boolean isDistinct() { + return distinct; + } + + public List getOredCriteria() { + return oredCriteria; + } + + public void or(Criteria criteria) { + oredCriteria.add(criteria); + } + + public Criteria or() { + Criteria criteria = createCriteriaInternal(); + oredCriteria.add(criteria); + return criteria; + } + + public Criteria createCriteria() { + Criteria criteria = createCriteriaInternal(); + if (oredCriteria.size() == 0) { + oredCriteria.add(criteria); + } + return criteria; + } + + protected Criteria createCriteriaInternal() { + Criteria criteria = new Criteria(); + return criteria; + } + + public void clear() { + oredCriteria.clear(); + orderByClause = null; + distinct = false; + } + + protected abstract static class GeneratedCriteria { + protected List criteria; + + protected GeneratedCriteria() { + super(); + criteria = new ArrayList(); + } + + public boolean isValid() { + return criteria.size() > 0; + } + + public List getAllCriteria() { + return criteria; + } + + public List getCriteria() { + return criteria; + } + + protected void addCriterion(String condition) { + if (condition == null) { + throw new RuntimeException("Value for condition cannot be null"); + } + criteria.add(new Criterion(condition)); + } + + protected void addCriterion(String condition, Object value, String property) { + if (value == null) { + throw new RuntimeException("Value for " + property + " cannot be null"); + } + criteria.add(new Criterion(condition, value)); + } + + protected void addCriterion(String condition, Object value1, Object value2, String property) { + if (value1 == null || value2 == null) { + throw new RuntimeException("Between values for " + property + " cannot be null"); + } + criteria.add(new Criterion(condition, value1, value2)); + } + + public Criteria andSourceIdIsNull() { + addCriterion("source_id is null"); + return (Criteria) this; + } + + public Criteria andSourceIdIsNotNull() { + addCriterion("source_id is not null"); + return (Criteria) this; + } + + public Criteria andSourceIdEqualTo(String value) { + addCriterion("source_id =", value, "sourceId"); + return (Criteria) this; + } + + public Criteria andSourceIdNotEqualTo(String value) { + addCriterion("source_id <>", value, "sourceId"); + return (Criteria) this; + } + + public Criteria andSourceIdGreaterThan(String value) { + addCriterion("source_id >", value, "sourceId"); + return (Criteria) this; + } + + public Criteria andSourceIdGreaterThanOrEqualTo(String value) { + addCriterion("source_id >=", value, "sourceId"); + return (Criteria) this; + } + + public Criteria andSourceIdLessThan(String value) { + addCriterion("source_id <", value, "sourceId"); + return (Criteria) this; + } + + public Criteria andSourceIdLessThanOrEqualTo(String value) { + addCriterion("source_id <=", value, "sourceId"); + return (Criteria) this; + } + + public Criteria andSourceIdLike(String value) { + addCriterion("source_id like", value, "sourceId"); + return (Criteria) this; + } + + public Criteria andSourceIdNotLike(String value) { + addCriterion("source_id not like", value, "sourceId"); + return (Criteria) this; + } + + public Criteria andSourceIdIn(List values) { + addCriterion("source_id in", values, "sourceId"); + return (Criteria) this; + } + + public Criteria andSourceIdNotIn(List values) { + addCriterion("source_id not in", values, "sourceId"); + return (Criteria) this; + } + + public Criteria andSourceIdBetween(String value1, String value2) { + addCriterion("source_id between", value1, value2, "sourceId"); + return (Criteria) this; + } + + public Criteria andSourceIdNotBetween(String value1, String value2) { + addCriterion("source_id not between", value1, value2, "sourceId"); + return (Criteria) this; + } + + public Criteria andTargetIdIsNull() { + addCriterion("target_id is null"); + return (Criteria) this; + } + + public Criteria andTargetIdIsNotNull() { + addCriterion("target_id is not null"); + return (Criteria) this; + } + + public Criteria andTargetIdEqualTo(String value) { + addCriterion("target_id =", value, "targetId"); + return (Criteria) this; + } + + public Criteria andTargetIdNotEqualTo(String value) { + addCriterion("target_id <>", value, "targetId"); + return (Criteria) this; + } + + public Criteria andTargetIdGreaterThan(String value) { + addCriterion("target_id >", value, "targetId"); + return (Criteria) this; + } + + public Criteria andTargetIdGreaterThanOrEqualTo(String value) { + addCriterion("target_id >=", value, "targetId"); + return (Criteria) this; + } + + public Criteria andTargetIdLessThan(String value) { + addCriterion("target_id <", value, "targetId"); + return (Criteria) this; + } + + public Criteria andTargetIdLessThanOrEqualTo(String value) { + addCriterion("target_id <=", value, "targetId"); + return (Criteria) this; + } + + public Criteria andTargetIdLike(String value) { + addCriterion("target_id like", value, "targetId"); + return (Criteria) this; + } + + public Criteria andTargetIdNotLike(String value) { + addCriterion("target_id not like", value, "targetId"); + return (Criteria) this; + } + + public Criteria andTargetIdIn(List values) { + addCriterion("target_id in", values, "targetId"); + return (Criteria) this; + } + + public Criteria andTargetIdNotIn(List values) { + addCriterion("target_id not in", values, "targetId"); + return (Criteria) this; + } + + public Criteria andTargetIdBetween(String value1, String value2) { + addCriterion("target_id between", value1, value2, "targetId"); + return (Criteria) this; + } + + public Criteria andTargetIdNotBetween(String value1, String value2) { + addCriterion("target_id not between", value1, value2, "targetId"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeIsNull() { + addCriterion("relationship_type is null"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeIsNotNull() { + addCriterion("relationship_type is not null"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeEqualTo(String value) { + addCriterion("relationship_type =", value, "relationshipType"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeNotEqualTo(String value) { + addCriterion("relationship_type <>", value, "relationshipType"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeGreaterThan(String value) { + addCriterion("relationship_type >", value, "relationshipType"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeGreaterThanOrEqualTo(String value) { + addCriterion("relationship_type >=", value, "relationshipType"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeLessThan(String value) { + addCriterion("relationship_type <", value, "relationshipType"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeLessThanOrEqualTo(String value) { + addCriterion("relationship_type <=", value, "relationshipType"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeLike(String value) { + addCriterion("relationship_type like", value, "relationshipType"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeNotLike(String value) { + addCriterion("relationship_type not like", value, "relationshipType"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeIn(List values) { + addCriterion("relationship_type in", values, "relationshipType"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeNotIn(List values) { + addCriterion("relationship_type not in", values, "relationshipType"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeBetween(String value1, String value2) { + addCriterion("relationship_type between", value1, value2, "relationshipType"); + return (Criteria) this; + } + + public Criteria andRelationshipTypeNotBetween(String value1, String value2) { + addCriterion("relationship_type not between", value1, value2, "relationshipType"); + return (Criteria) this; + } + + public Criteria andResourceTypeIsNull() { + addCriterion("resource_type is null"); + return (Criteria) this; + } + + public Criteria andResourceTypeIsNotNull() { + addCriterion("resource_type is not null"); + return (Criteria) this; + } + + public Criteria andResourceTypeEqualTo(String value) { + addCriterion("resource_type =", value, "resourceType"); + return (Criteria) this; + } + + public Criteria andResourceTypeNotEqualTo(String value) { + addCriterion("resource_type <>", value, "resourceType"); + return (Criteria) this; + } + + public Criteria andResourceTypeGreaterThan(String value) { + addCriterion("resource_type >", value, "resourceType"); + return (Criteria) this; + } + + public Criteria andResourceTypeGreaterThanOrEqualTo(String value) { + addCriterion("resource_type >=", value, "resourceType"); + return (Criteria) this; + } + + public Criteria andResourceTypeLessThan(String value) { + addCriterion("resource_type <", value, "resourceType"); + return (Criteria) this; + } + + public Criteria andResourceTypeLessThanOrEqualTo(String value) { + addCriterion("resource_type <=", value, "resourceType"); + return (Criteria) this; + } + + public Criteria andResourceTypeLike(String value) { + addCriterion("resource_type like", value, "resourceType"); + return (Criteria) this; + } + + public Criteria andResourceTypeNotLike(String value) { + addCriterion("resource_type not like", value, "resourceType"); + return (Criteria) this; + } + + public Criteria andResourceTypeIn(List values) { + addCriterion("resource_type in", values, "resourceType"); + return (Criteria) this; + } + + public Criteria andResourceTypeNotIn(List values) { + addCriterion("resource_type not in", values, "resourceType"); + return (Criteria) this; + } + + public Criteria andResourceTypeBetween(String value1, String value2) { + addCriterion("resource_type between", value1, value2, "resourceType"); + return (Criteria) this; + } + + public Criteria andResourceTypeNotBetween(String value1, String value2) { + addCriterion("resource_type not between", value1, value2, "resourceType"); + return (Criteria) this; + } + + public Criteria andGraphIdIsNull() { + addCriterion("graph_id is null"); + return (Criteria) this; + } + + public Criteria andGraphIdIsNotNull() { + addCriterion("graph_id is not null"); + return (Criteria) this; + } + + public Criteria andGraphIdEqualTo(String value) { + addCriterion("graph_id =", value, "graphId"); + return (Criteria) this; + } + + public Criteria andGraphIdNotEqualTo(String value) { + addCriterion("graph_id <>", value, "graphId"); + return (Criteria) this; + } + + public Criteria andGraphIdGreaterThan(String value) { + addCriterion("graph_id >", value, "graphId"); + return (Criteria) this; + } + + public Criteria andGraphIdGreaterThanOrEqualTo(String value) { + addCriterion("graph_id >=", value, "graphId"); + return (Criteria) this; + } + + public Criteria andGraphIdLessThan(String value) { + addCriterion("graph_id <", value, "graphId"); + return (Criteria) this; + } + + public Criteria andGraphIdLessThanOrEqualTo(String value) { + addCriterion("graph_id <=", value, "graphId"); + return (Criteria) this; + } + + public Criteria andGraphIdLike(String value) { + addCriterion("graph_id like", value, "graphId"); + return (Criteria) this; + } + + public Criteria andGraphIdNotLike(String value) { + addCriterion("graph_id not like", value, "graphId"); + return (Criteria) this; + } + + public Criteria andGraphIdIn(List values) { + addCriterion("graph_id in", values, "graphId"); + return (Criteria) this; + } + + public Criteria andGraphIdNotIn(List values) { + addCriterion("graph_id not in", values, "graphId"); + return (Criteria) this; + } + + public Criteria andGraphIdBetween(String value1, String value2) { + addCriterion("graph_id between", value1, value2, "graphId"); + return (Criteria) this; + } + + public Criteria andGraphIdNotBetween(String value1, String value2) { + addCriterion("graph_id not between", value1, value2, "graphId"); + return (Criteria) this; + } + + public Criteria andCreatorIsNull() { + addCriterion("creator is null"); + return (Criteria) this; + } + + public Criteria andCreatorIsNotNull() { + addCriterion("creator is not null"); + return (Criteria) this; + } + + public Criteria andCreatorEqualTo(String value) { + addCriterion("creator =", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorNotEqualTo(String value) { + addCriterion("creator <>", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorGreaterThan(String value) { + addCriterion("creator >", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorGreaterThanOrEqualTo(String value) { + addCriterion("creator >=", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorLessThan(String value) { + addCriterion("creator <", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorLessThanOrEqualTo(String value) { + addCriterion("creator <=", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorLike(String value) { + addCriterion("creator like", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorNotLike(String value) { + addCriterion("creator not like", value, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorIn(List values) { + addCriterion("creator in", values, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorNotIn(List values) { + addCriterion("creator not in", values, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorBetween(String value1, String value2) { + addCriterion("creator between", value1, value2, "creator"); + return (Criteria) this; + } + + public Criteria andCreatorNotBetween(String value1, String value2) { + addCriterion("creator not between", value1, value2, "creator"); + return (Criteria) this; + } + + public Criteria andCreateTimeIsNull() { + addCriterion("create_time is null"); + return (Criteria) this; + } + + public Criteria andCreateTimeIsNotNull() { + addCriterion("create_time is not null"); + return (Criteria) this; + } + + public Criteria andCreateTimeEqualTo(Long value) { + addCriterion("create_time =", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotEqualTo(Long value) { + addCriterion("create_time <>", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeGreaterThan(Long value) { + addCriterion("create_time >", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeGreaterThanOrEqualTo(Long value) { + addCriterion("create_time >=", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeLessThan(Long value) { + addCriterion("create_time <", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeLessThanOrEqualTo(Long value) { + addCriterion("create_time <=", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeIn(List values) { + addCriterion("create_time in", values, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotIn(List values) { + addCriterion("create_time not in", values, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeBetween(Long value1, Long value2) { + addCriterion("create_time between", value1, value2, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotBetween(Long value1, Long value2) { + addCriterion("create_time not between", value1, value2, "createTime"); + return (Criteria) this; + } + } + + public static class Criteria extends GeneratedCriteria { + + protected Criteria() { + super(); + } + } + + public static class Criterion { + private String condition; + + private Object value; + + private Object secondValue; + + private boolean noValue; + + private boolean singleValue; + + private boolean betweenValue; + + private boolean listValue; + + private String typeHandler; + + public String getCondition() { + return condition; + } + + public Object getValue() { + return value; + } + + public Object getSecondValue() { + return secondValue; + } + + public boolean isNoValue() { + return noValue; + } + + public boolean isSingleValue() { + return singleValue; + } + + public boolean isBetweenValue() { + return betweenValue; + } + + public boolean isListValue() { + return listValue; + } + + public String getTypeHandler() { + return typeHandler; + } + + protected Criterion(String condition) { + super(); + this.condition = condition; + this.typeHandler = null; + this.noValue = true; + } + + protected Criterion(String condition, Object value, String typeHandler) { + super(); + this.condition = condition; + this.value = value; + this.typeHandler = typeHandler; + if (value instanceof List) { + this.listValue = true; + } else { + this.singleValue = true; + } + } + + protected Criterion(String condition, Object value) { + this(condition, value, null); + } + + protected Criterion(String condition, Object value, Object secondValue, String typeHandler) { + super(); + this.condition = condition; + this.value = value; + this.secondValue = secondValue; + this.typeHandler = typeHandler; + this.betweenValue = true; + } + + protected Criterion(String condition, Object value, Object secondValue) { + this(condition, value, secondValue, null); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/RelationshipEdgeMapper.java b/backend/src/main/java/io/metersphere/base/mapper/RelationshipEdgeMapper.java new file mode 100644 index 0000000000..58b74c2d60 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/RelationshipEdgeMapper.java @@ -0,0 +1,22 @@ +package io.metersphere.base.mapper; + +import io.metersphere.base.domain.RelationshipEdge; +import io.metersphere.base.domain.RelationshipEdgeExample; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +public interface RelationshipEdgeMapper { + long countByExample(RelationshipEdgeExample example); + + int deleteByExample(RelationshipEdgeExample example); + + int insert(RelationshipEdge record); + + int insertSelective(RelationshipEdge record); + + List selectByExample(RelationshipEdgeExample example); + + int updateByExampleSelective(@Param("record") RelationshipEdge record, @Param("example") RelationshipEdgeExample example); + + int updateByExample(@Param("record") RelationshipEdge record, @Param("example") RelationshipEdgeExample example); +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/RelationshipEdgeMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/RelationshipEdgeMapper.xml new file mode 100644 index 0000000000..bfe4bf9a8c --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/RelationshipEdgeMapper.xml @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + + + + + + + + + source_id, target_id, relationship_type, resource_type, graph_id, creator, create_time + + + + delete from relationship_edge + + + + + + insert into relationship_edge (source_id, target_id, relationship_type, + resource_type, graph_id, creator, + create_time) + values (#{sourceId,jdbcType=VARCHAR}, #{targetId,jdbcType=VARCHAR}, #{relationshipType,jdbcType=VARCHAR}, + #{resourceType,jdbcType=VARCHAR}, #{graphId,jdbcType=VARCHAR}, #{creator,jdbcType=VARCHAR}, + #{createTime,jdbcType=BIGINT}) + + + insert into relationship_edge + + + source_id, + + + target_id, + + + relationship_type, + + + resource_type, + + + graph_id, + + + creator, + + + create_time, + + + + + #{sourceId,jdbcType=VARCHAR}, + + + #{targetId,jdbcType=VARCHAR}, + + + #{relationshipType,jdbcType=VARCHAR}, + + + #{resourceType,jdbcType=VARCHAR}, + + + #{graphId,jdbcType=VARCHAR}, + + + #{creator,jdbcType=VARCHAR}, + + + #{createTime,jdbcType=BIGINT}, + + + + + + update relationship_edge + + + source_id = #{record.sourceId,jdbcType=VARCHAR}, + + + target_id = #{record.targetId,jdbcType=VARCHAR}, + + + relationship_type = #{record.relationshipType,jdbcType=VARCHAR}, + + + resource_type = #{record.resourceType,jdbcType=VARCHAR}, + + + graph_id = #{record.graphId,jdbcType=VARCHAR}, + + + creator = #{record.creator,jdbcType=VARCHAR}, + + + create_time = #{record.createTime,jdbcType=BIGINT}, + + + + + + + + update relationship_edge + set source_id = #{record.sourceId,jdbcType=VARCHAR}, + target_id = #{record.targetId,jdbcType=VARCHAR}, + relationship_type = #{record.relationshipType,jdbcType=VARCHAR}, + resource_type = #{record.resourceType,jdbcType=VARCHAR}, + graph_id = #{record.graphId,jdbcType=VARCHAR}, + creator = #{record.creator,jdbcType=VARCHAR}, + create_time = #{record.createTime,jdbcType=BIGINT} + + + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java index 35815cc73f..9fcad44e18 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.java @@ -118,4 +118,6 @@ public interface ExtTestCaseMapper { Long getLastOrder(@Param("projectId")String projectId, @Param("baseOrder") Long baseOrder); Long getPreOrder(@Param("projectId")String projectId, @Param("baseOrder") Long baseOrder); + + List getTestCase(@Param("request") QueryTestCaseRequest request); } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml index ba4a2edee3..fd89e95ecf 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml @@ -551,6 +551,13 @@ order by `order` desc limit 1; + update test_case set original_status=status, diff --git a/backend/src/main/java/io/metersphere/controller/RelationshipEdgeController.java b/backend/src/main/java/io/metersphere/controller/RelationshipEdgeController.java new file mode 100644 index 0000000000..39757c983c --- /dev/null +++ b/backend/src/main/java/io/metersphere/controller/RelationshipEdgeController.java @@ -0,0 +1,27 @@ +package io.metersphere.controller; + + +import io.metersphere.controller.request.RelationshipEdgeRequest; +import io.metersphere.service.RelationshipEdgeService; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +@RequestMapping("relationship/edge") +@RestController +public class RelationshipEdgeController { + + @Resource + private RelationshipEdgeService relationshipEdgeService; + + @PostMapping("/save/batch") + public void add(@RequestBody RelationshipEdgeRequest request) { + relationshipEdgeService.saveBatch(request); + } + + @GetMapping("/delete") + public void delete(@PathVariable("sourceId") String sourceId, @PathVariable("targetId") String targetId) { + relationshipEdgeService.delete(sourceId, targetId); + } + +} diff --git a/backend/src/main/java/io/metersphere/controller/request/RelationshipEdgeRequest.java b/backend/src/main/java/io/metersphere/controller/request/RelationshipEdgeRequest.java new file mode 100644 index 0000000000..60cc63689e --- /dev/null +++ b/backend/src/main/java/io/metersphere/controller/request/RelationshipEdgeRequest.java @@ -0,0 +1,13 @@ +package io.metersphere.controller.request; + +import io.metersphere.base.domain.RelationshipEdge; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class RelationshipEdgeRequest extends RelationshipEdge { + private List targetIds; +} diff --git a/backend/src/main/java/io/metersphere/dto/RelationshipEdgeDTO.java b/backend/src/main/java/io/metersphere/dto/RelationshipEdgeDTO.java new file mode 100644 index 0000000000..0a90fc0a05 --- /dev/null +++ b/backend/src/main/java/io/metersphere/dto/RelationshipEdgeDTO.java @@ -0,0 +1,13 @@ +package io.metersphere.dto; + +import io.metersphere.base.domain.RelationshipEdge; +import lombok.Data; + +@Data +public class RelationshipEdgeDTO extends RelationshipEdge { + private String targetName; + private Integer targetNum; + private String targetCustomNum; + private String status; + private String creator; +} diff --git a/backend/src/main/java/io/metersphere/service/RelationshipEdgeService.java b/backend/src/main/java/io/metersphere/service/RelationshipEdgeService.java new file mode 100644 index 0000000000..52db8993ee --- /dev/null +++ b/backend/src/main/java/io/metersphere/service/RelationshipEdgeService.java @@ -0,0 +1,103 @@ +package io.metersphere.service; + + +import io.metersphere.base.domain.RelationshipEdge; +import io.metersphere.base.domain.RelationshipEdgeExample; +import io.metersphere.base.mapper.RelationshipEdgeMapper; +import io.metersphere.commons.utils.SessionUtils; +import io.metersphere.controller.request.RelationshipEdgeRequest; +import org.apache.commons.collections.CollectionUtils; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author jianxingChen + */ + +@Service +@Transactional(rollbackFor = Exception.class) +public class RelationshipEdgeService { + + @Resource + private RelationshipEdgeMapper relationshipEdgeMapper; + @Resource + private SqlSessionFactory sqlSessionFactory; + + + public void delete(String sourceId, String targetId) { + RelationshipEdgeExample example = new RelationshipEdgeExample(); + example.createCriteria() + .andSourceIdEqualTo(sourceId) + .andTargetIdEqualTo(targetId); + relationshipEdgeMapper.deleteByExample(example); + } + + public List getBySourceId(String sourceId) { + RelationshipEdgeExample example = new RelationshipEdgeExample(); + example.createCriteria() + .andSourceIdEqualTo(sourceId); + return relationshipEdgeMapper.selectByExample(example); + } + + public List getBySourceIdAndRelationType(String sourceId, String relationType) { + RelationshipEdgeExample example = new RelationshipEdgeExample(); + example.createCriteria() + .andSourceIdEqualTo(sourceId) + .andRelationshipTypeEqualTo(relationType); + return relationshipEdgeMapper.selectByExample(example); + } + + public void saveBatch(RelationshipEdgeRequest request) { + if (CollectionUtils.isEmpty(request.getTargetIds())) { + return; + } + + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + RelationshipEdgeMapper batchMapper = sqlSession.getMapper(RelationshipEdgeMapper.class); + String graphId = UUID.randomUUID().toString(); + + // 判断这些顶点是否已经和其他顶点连通 + // 连通的话,加到同一个图中,否则新建一个图,即 graphId + List graphNodes = new ArrayList<>(); + graphNodes.add(request.getSourceId()); + graphNodes.addAll(request.getTargetIds()); + RelationshipEdgeExample example = new RelationshipEdgeExample(); + example.createCriteria() + .andSourceIdIn(graphNodes) + .andRelationshipTypeEqualTo(request.getRelationshipType()); + example.or( + example.createCriteria() + .andTargetIdIn(graphNodes) + .andRelationshipTypeEqualTo(request.getRelationshipType()) + ); + List relationshipEdges = relationshipEdgeMapper.selectByExample(example); + if (CollectionUtils.isNotEmpty(relationshipEdges)) { + graphId = relationshipEdges.get(0).getGraphId(); + } + + // todo 检验是否有环 + + for (String targetId : request.getTargetIds()) { + RelationshipEdge edge = new RelationshipEdge(); + edge.setSourceId(request.getSourceId()); + edge.setTargetId(targetId); + edge.setGraphId(graphId); + edge.setRelationshipType(request.getRelationshipType()); + edge.setResourceType(request.getResourceType()); + edge.setCreator(SessionUtils.getUserId()); + edge.setCreateTime(System.currentTimeMillis()); + batchMapper.insert(edge); + } + + sqlSession.flushStatements(); + } + +} diff --git a/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java b/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java index e155338b1f..c77783ac2e 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java @@ -19,6 +19,7 @@ import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.ResetOrderRequest; import io.metersphere.dto.LoadTestDTO; +import io.metersphere.dto.RelationshipEdgeDTO; import io.metersphere.dto.TestCaseTestDao; import io.metersphere.excel.domain.ExcelResponse; import io.metersphere.log.annotation.MsAuditLog; @@ -99,6 +100,10 @@ public class TestCaseController { return testCaseService.listTestCaseIds(request); } + @GetMapping("/relationship/case/{id}/{relationshipType}") + public List getRelationshipCase(@PathVariable("id") String id, @PathVariable("relationshipType") String relationshipType) { + return testCaseService.getRelationshipCase(id, relationshipType); + } @GetMapping("recent/{count}") public List recentTestPlans(@PathVariable int count) { @@ -115,6 +120,12 @@ public class TestCaseController { return PageUtils.setPageInfo(page, testCaseService.getTestCaseRelateList(request)); } + @PostMapping("/relationship/relate/{goPage}/{pageSize}") + public Pager> getRelationshipRelateList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) { + Page page = PageHelper.startPage(goPage, pageSize, true); + return PageUtils.setPageInfo(page, testCaseService.getRelationshipRelateList(request)); + } + @PostMapping("/relate/issue/{goPage}/{pageSize}") public Pager> getTestCaseIssueRelateList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) { Page page = PageHelper.startPage(goPage, pageSize, true); diff --git a/backend/src/main/java/io/metersphere/track/request/testcase/QueryTestCaseRequest.java b/backend/src/main/java/io/metersphere/track/request/testcase/QueryTestCaseRequest.java index 37bf6fddb2..cde79d23ab 100644 --- a/backend/src/main/java/io/metersphere/track/request/testcase/QueryTestCaseRequest.java +++ b/backend/src/main/java/io/metersphere/track/request/testcase/QueryTestCaseRequest.java @@ -10,8 +10,12 @@ import java.util.List; @Setter public class QueryTestCaseRequest extends BaseQueryRequest { + private String id; + private String name; + private String relationshipType; + private List testCaseIds; private String planId; diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseService.java index 421dad94c5..83c9ea790c 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseService.java @@ -127,7 +127,7 @@ public class TestCaseService { @Resource private IssuesMapper issuesMapper; @Resource - private CustomFieldService customFieldService; + private RelationshipEdgeService relationshipEdgeService; @Resource @Lazy private ApiTestCaseService apiTestCaseService; @@ -1945,4 +1945,40 @@ public class TestCaseService { extTestCaseMapper::getLastOrder, testCaseMapper::updateByPrimaryKeySelective); } + + public List getRelationshipRelateList(QueryTestCaseRequest request) { + setDefaultOrder(request); + List relationshipEdges = relationshipEdgeService.getBySourceId(request.getId()); + List ids = relationshipEdges.stream().map(RelationshipEdge::getTargetId).collect(Collectors.toList()); + ids.add(request.getId()); + request.setTestCaseContainIds(ids); + return extTestCaseMapper.getTestCase(request); +// return extTestCaseMapper.getTestCaseByNotInPlan(request); + } + + public List getRelationshipCase(String id, String relationshipType) { + List relationshipEdges = relationshipEdgeService.getBySourceIdAndRelationType(id, relationshipType); + List targetIds = relationshipEdges.stream() + .map(RelationshipEdge::getTargetId) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(targetIds)) { + TestCaseExample example = new TestCaseExample(); + example.createCriteria().andIdIn(targetIds); + List testCaseList = testCaseMapper.selectByExample(example); + Map caseMap = testCaseList.stream().collect(Collectors.toMap(TestCase::getId, i -> i)); + List results = new ArrayList<>(); + for (RelationshipEdge relationshipEdge : relationshipEdges) { + RelationshipEdgeDTO relationshipEdgeDTO = new RelationshipEdgeDTO(); + BeanUtils.copyBean(relationshipEdgeDTO, relationshipEdge); + TestCase testCase = caseMap.get(relationshipEdge.getTargetId()); + relationshipEdgeDTO.setTargetName(testCase.getName()); + relationshipEdgeDTO.setCreator(testCase.getCreateUser()); + relationshipEdgeDTO.setTargetNum(testCase.getNum()); + relationshipEdgeDTO.setTargetCustomNum(testCase.getCustomNum()); + results.add(relationshipEdgeDTO); + } + return results; + } + return new ArrayList<>(); + } } diff --git a/backend/src/main/resources/db/migration/V97__v1.14_release.sql b/backend/src/main/resources/db/migration/V97__v1.14_release.sql index 2df84d39c2..6d63cb64f7 100644 --- a/backend/src/main/resources/db/migration/V97__v1.14_release.sql +++ b/backend/src/main/resources/db/migration/V97__v1.14_release.sql @@ -35,4 +35,19 @@ END DELIMITER ; CALL test_cursor(); -DROP PROCEDURE IF EXISTS test_cursor; \ No newline at end of file +DROP PROCEDURE IF EXISTS test_cursor; + + +create table if not exists relationship_edge ( + source_id varchar(50) not null comment '源节点的ID', + target_id varchar(50) not null comment '目标节点的ID', + relationship_type varchar(20) not null comment '关系的类型,前置后置或者依赖', + resource_type varchar(20) not null comment '是表示什么资源', + graph_id varchar(50) not null comment '所属关系图的ID', + creator varchar(50) not null comment '创建人', + create_time bigint(13) not null, + PRIMARY KEY (source_id, target_id) +) + ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE utf8mb4_general_ci; diff --git a/backend/src/main/resources/generatorConfig.xml b/backend/src/main/resources/generatorConfig.xml index 53b716a52a..38ff4aa1f3 100644 --- a/backend/src/main/resources/generatorConfig.xml +++ b/backend/src/main/resources/generatorConfig.xml @@ -78,7 +78,7 @@
--> -
+
diff --git a/frontend/src/business/components/track/case/TestCase.vue b/frontend/src/business/components/track/case/TestCase.vue index 301d94083f..71e82c9687 100644 --- a/frontend/src/business/components/track/case/TestCase.vue +++ b/frontend/src/business/components/track/case/TestCase.vue @@ -33,7 +33,6 @@ @refreshAll="refreshAll" @setCondition="setCondition" @decrease="decrease" - :custom-num="custom_num" ref="testCaseTrashList"> @@ -60,7 +59,6 @@ @refreshAll="refreshAll" @setCondition="setCondition" @decrease="decrease" - :custom-num="custom_num" ref="testCaseList"> @@ -165,7 +162,6 @@ export default { type: '', activeDom: 'left', tmpActiveDom: null, - custom_num: false }; }, mounted() { @@ -463,7 +459,7 @@ export default { this.$get("/project/get/" + this.projectId, result => { let data = result.data; if (data) { - this.custom_num = data.customNum; + this.$store.commit('setCurrentProjectIsCustomNum', data.customNum); } }); }, diff --git a/frontend/src/business/components/track/case/components/RelationshipFunctionalRelevance.vue b/frontend/src/business/components/track/case/components/RelationshipFunctionalRelevance.vue new file mode 100644 index 0000000000..c94889f21d --- /dev/null +++ b/frontend/src/business/components/track/case/components/RelationshipFunctionalRelevance.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/frontend/src/business/components/track/case/components/TestCaseEdit.vue b/frontend/src/business/components/track/case/components/TestCaseEdit.vue index 4369008c61..1a4aea7587 100644 --- a/frontend/src/business/components/track/case/components/TestCaseEdit.vue +++ b/frontend/src/business/components/track/case/components/TestCaseEdit.vue @@ -78,7 +78,7 @@ - + @@ -136,10 +136,9 @@ + + diff --git a/frontend/src/business/components/track/common/TestCaseNodeTree.vue b/frontend/src/business/components/track/common/TestCaseNodeTree.vue index 9f070bdf76..1e3424a054 100644 --- a/frontend/src/business/components/track/common/TestCaseNodeTree.vue +++ b/frontend/src/business/components/track/common/TestCaseNodeTree.vue @@ -50,6 +50,7 @@ import {buildTree} from "../../api/definition/model/NodeTree"; import {buildNodePath} from "@/business/components/api/definition/model/NodeTree"; import {getCurrentProjectID} from "@/common/js/utils"; import ModuleTrashButton from "@/business/components/api/definition/components/module/ModuleTrashButton"; +import {getTestCaseNodes} from "@/network/testCase"; export default { name: "TestCaseNodeTree", @@ -137,8 +138,8 @@ export default { }, list() { if (this.projectId) { - this.result = this.$get("/case/node/list/" + this.projectId, response => { - this.treeNodes = response.data; + this.result = getTestCaseNodes(this.projectId, data => { + this.treeNodes = data; this.treeNodes.forEach(node => { buildTree(node, {path: ''}); }); diff --git a/frontend/src/business/components/track/plan/view/TestPlanView.vue b/frontend/src/business/components/track/plan/view/TestPlanView.vue index cb0d815fe1..815eda48f2 100644 --- a/frontend/src/business/components/track/plan/view/TestPlanView.vue +++ b/frontend/src/business/components/track/plan/view/TestPlanView.vue @@ -35,7 +35,6 @@ import NodeTree from "../../common/NodeTree"; import TestPlanTestCaseList from "./comonents/functional/FunctionalTestCaseList"; -import TestCaseRelevance from "./comonents/functional/TestCaseFunctionalRelevance"; import SelectMenu from "../../common/SelectMenu"; import MsContainer from "../../../common/components/MsContainer"; import MsAsideContainer from "../../../common/components/MsAsideContainer"; @@ -55,7 +54,7 @@ export default { TestPlanFunctional, MsTestPlanHeaderBar, MsMainContainer, - MsAsideContainer, MsContainer, NodeTree, TestPlanTestCaseList, TestCaseRelevance, SelectMenu, TestPlanLoad + MsAsideContainer, MsContainer, NodeTree, TestPlanTestCaseList, SelectMenu, TestPlanLoad }, data() { return { diff --git a/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApi.vue b/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApi.vue index 4800a64f3f..cd7f421ad0 100644 --- a/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApi.vue +++ b/frontend/src/business/components/track/plan/view/comonents/api/TestPlanApi.vue @@ -84,7 +84,6 @@ + + diff --git a/frontend/src/business/components/track/review/view/components/TestReviewApi.vue b/frontend/src/business/components/track/review/view/components/TestReviewApi.vue index a65b73bf00..ce7d8f30f9 100644 --- a/frontend/src/business/components/track/review/view/components/TestReviewApi.vue +++ b/frontend/src/business/components/track/review/view/components/TestReviewApi.vue @@ -83,7 +83,6 @@ import MsTestPlanApiScenarioList from "@/business/components/track/plan/view/com import MsApiScenarioModule from "@/business/components/api/automation/scenario/ApiScenarioModule"; import ApiCaseSimpleList from "@/business/components/api/definition/components/list/ApiCaseSimpleList"; import TestPlanApiCaseList from "@/business/components/track/plan/view/comonents/api/TestPlanApiCaseList"; -import TestCaseRelevance from "@/business/components/track/plan/view/comonents/functional/TestCaseFunctionalRelevance"; import NodeTree from "@/business/components/track/common/NodeTree"; import MsApiModule from "../../../../api/definition/components/module/ApiModule" import TestReviewRelevanceApi from "@/business/components/track/review/view/components/TestReviewRelevanceApi"; @@ -100,7 +99,6 @@ export default { ApiCaseSimpleList, TestPlanApiCaseList, MsTestPlanCommonComponent, - TestCaseRelevance, NodeTree, MsApiModule, }, diff --git a/frontend/src/network/relationship-edge.js b/frontend/src/network/relationship-edge.js new file mode 100644 index 0000000000..6c2b808c8e --- /dev/null +++ b/frontend/src/network/relationship-edge.js @@ -0,0 +1,6 @@ +import {baseGet} from "@/network/base-network"; + +export function deleteRelationshipEdge(sourceId, targetId, callback) { + return baseGet('/relationship/edge/delete/' + sourceId + '/' + targetId, callback); +} + diff --git a/frontend/src/network/testCase.js b/frontend/src/network/testCase.js index a423a60819..df491414a0 100644 --- a/frontend/src/network/testCase.js +++ b/frontend/src/network/testCase.js @@ -63,3 +63,11 @@ export function editTestReviewTestCaseOrder(request, callback) { return basePost('/test/review/case/edit/order', request, callback); } +export function getTestCaseNodes(projectId, callback) { + return baseGet('/case/node/list/' + projectId, callback); +} + +export function getRelationshipCase(id, relationshipType, callback) { + return baseGet('/test/case/relationship/case/' + id + '/' + relationshipType, callback); +} + diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js index 9e5aa1baf0..efaf400f9c 100644 --- a/frontend/src/store/index.js +++ b/frontend/src/store/index.js @@ -26,7 +26,9 @@ const state = { selectStep: {}, currentApiCase: {}, pluginFiles: [], - isTestCaseMinderChanged: false + isTestCaseMinderChanged: false, + // 当前项目是否勾选自定义ID + currentProjectIsCustomNum: false } const store = new Vuex.Store({ diff --git a/frontend/src/store/mutations.js b/frontend/src/store/mutations.js index bf2011ae15..b40b3466b9 100644 --- a/frontend/src/store/mutations.js +++ b/frontend/src/store/mutations.js @@ -16,6 +16,7 @@ const mutations = { setTestReviewModuleOptions: (state, value) => state.testReviewModuleOptions = value, setTestPlanViewSelectNode: (state, value) => state.testPlanViewSelectNode = value, setIsTestCaseMinderChanged: (state, value) => state.isTestCaseMinderChanged = value, + setCurrentProjectIsCustomNum: (state, value) => state.currentProjectIsCustomNum = value, } export default mutations;