feat(测试跟踪): 用例评审支持左侧模块树

--story=1014031 --user=宋昌昌 【测试计划】【用例评审】首页列表展示模块树 https://www.tapd.cn/55049933/s/1444816
This commit is contained in:
song-cc-rock 2023-12-18 17:17:04 +08:00 committed by 建国
parent 5b8ae932fb
commit 681eaebca0
70 changed files with 5336 additions and 137 deletions

View File

@ -27,7 +27,11 @@ public class TestCaseReview implements Serializable {
private String reviewPassRule;
private String nodeId;
private String nodePath;
private String description;
private static final long serialVersionUID = 1L;
}
}

View File

@ -843,6 +843,146 @@ public class TestCaseReviewExample {
addCriterion("review_pass_rule not between", value1, value2, "reviewPassRule");
return (Criteria) this;
}
public Criteria andNodeIdIsNull() {
addCriterion("node_id is null");
return (Criteria) this;
}
public Criteria andNodeIdIsNotNull() {
addCriterion("node_id is not null");
return (Criteria) this;
}
public Criteria andNodeIdEqualTo(String value) {
addCriterion("node_id =", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdNotEqualTo(String value) {
addCriterion("node_id <>", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdGreaterThan(String value) {
addCriterion("node_id >", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdGreaterThanOrEqualTo(String value) {
addCriterion("node_id >=", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdLessThan(String value) {
addCriterion("node_id <", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdLessThanOrEqualTo(String value) {
addCriterion("node_id <=", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdLike(String value) {
addCriterion("node_id like", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdNotLike(String value) {
addCriterion("node_id not like", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdIn(List<String> values) {
addCriterion("node_id in", values, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdNotIn(List<String> values) {
addCriterion("node_id not in", values, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdBetween(String value1, String value2) {
addCriterion("node_id between", value1, value2, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdNotBetween(String value1, String value2) {
addCriterion("node_id not between", value1, value2, "nodeId");
return (Criteria) this;
}
public Criteria andNodePathIsNull() {
addCriterion("node_path is null");
return (Criteria) this;
}
public Criteria andNodePathIsNotNull() {
addCriterion("node_path is not null");
return (Criteria) this;
}
public Criteria andNodePathEqualTo(String value) {
addCriterion("node_path =", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathNotEqualTo(String value) {
addCriterion("node_path <>", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathGreaterThan(String value) {
addCriterion("node_path >", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathGreaterThanOrEqualTo(String value) {
addCriterion("node_path >=", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathLessThan(String value) {
addCriterion("node_path <", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathLessThanOrEqualTo(String value) {
addCriterion("node_path <=", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathLike(String value) {
addCriterion("node_path like", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathNotLike(String value) {
addCriterion("node_path not like", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathIn(List<String> values) {
addCriterion("node_path in", values, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathNotIn(List<String> values) {
addCriterion("node_path not in", values, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathBetween(String value1, String value2) {
addCriterion("node_path between", value1, value2, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathNotBetween(String value1, String value2) {
addCriterion("node_path not between", value1, value2, "nodePath");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
@ -937,4 +1077,4 @@ public class TestCaseReviewExample {
this(condition, value, secondValue, null);
}
}
}
}

View File

@ -0,0 +1,27 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class TestCaseReviewNode implements Serializable {
private String id;
private String projectId;
private String name;
private String parentId;
private Integer level;
private Long createTime;
private Long updateTime;
private Double pos;
private String createUser;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,790 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class TestCaseReviewNodeExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public TestCaseReviewNodeExample() {
oredCriteria = new ArrayList<Criteria>();
}
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<Criteria> 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<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> 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 andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andProjectIdIsNull() {
addCriterion("project_id is null");
return (Criteria) this;
}
public Criteria andProjectIdIsNotNull() {
addCriterion("project_id is not null");
return (Criteria) this;
}
public Criteria andProjectIdEqualTo(String value) {
addCriterion("project_id =", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("project_id <>", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThan(String value) {
addCriterion("project_id >", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("project_id >=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThan(String value) {
addCriterion("project_id <", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThanOrEqualTo(String value) {
addCriterion("project_id <=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLike(String value) {
addCriterion("project_id like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotLike(String value) {
addCriterion("project_id not like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdIn(List<String> values) {
addCriterion("project_id in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotIn(List<String> values) {
addCriterion("project_id not in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdBetween(String value1, String value2) {
addCriterion("project_id between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotBetween(String value1, String value2) {
addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andNameIsNull() {
addCriterion("`name` is null");
return (Criteria) this;
}
public Criteria andNameIsNotNull() {
addCriterion("`name` is not null");
return (Criteria) this;
}
public Criteria andNameEqualTo(String value) {
addCriterion("`name` =", value, "name");
return (Criteria) this;
}
public Criteria andNameNotEqualTo(String value) {
addCriterion("`name` <>", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThan(String value) {
addCriterion("`name` >", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThanOrEqualTo(String value) {
addCriterion("`name` >=", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThan(String value) {
addCriterion("`name` <", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThanOrEqualTo(String value) {
addCriterion("`name` <=", value, "name");
return (Criteria) this;
}
public Criteria andNameLike(String value) {
addCriterion("`name` like", value, "name");
return (Criteria) this;
}
public Criteria andNameNotLike(String value) {
addCriterion("`name` not like", value, "name");
return (Criteria) this;
}
public Criteria andNameIn(List<String> values) {
addCriterion("`name` in", values, "name");
return (Criteria) this;
}
public Criteria andNameNotIn(List<String> values) {
addCriterion("`name` not in", values, "name");
return (Criteria) this;
}
public Criteria andNameBetween(String value1, String value2) {
addCriterion("`name` between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andNameNotBetween(String value1, String value2) {
addCriterion("`name` not between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andParentIdIsNull() {
addCriterion("parent_id is null");
return (Criteria) this;
}
public Criteria andParentIdIsNotNull() {
addCriterion("parent_id is not null");
return (Criteria) this;
}
public Criteria andParentIdEqualTo(String value) {
addCriterion("parent_id =", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotEqualTo(String value) {
addCriterion("parent_id <>", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdGreaterThan(String value) {
addCriterion("parent_id >", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdGreaterThanOrEqualTo(String value) {
addCriterion("parent_id >=", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdLessThan(String value) {
addCriterion("parent_id <", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdLessThanOrEqualTo(String value) {
addCriterion("parent_id <=", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdLike(String value) {
addCriterion("parent_id like", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotLike(String value) {
addCriterion("parent_id not like", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdIn(List<String> values) {
addCriterion("parent_id in", values, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotIn(List<String> values) {
addCriterion("parent_id not in", values, "parentId");
return (Criteria) this;
}
public Criteria andParentIdBetween(String value1, String value2) {
addCriterion("parent_id between", value1, value2, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotBetween(String value1, String value2) {
addCriterion("parent_id not between", value1, value2, "parentId");
return (Criteria) this;
}
public Criteria andLevelIsNull() {
addCriterion("`level` is null");
return (Criteria) this;
}
public Criteria andLevelIsNotNull() {
addCriterion("`level` is not null");
return (Criteria) this;
}
public Criteria andLevelEqualTo(Integer value) {
addCriterion("`level` =", value, "level");
return (Criteria) this;
}
public Criteria andLevelNotEqualTo(Integer value) {
addCriterion("`level` <>", value, "level");
return (Criteria) this;
}
public Criteria andLevelGreaterThan(Integer value) {
addCriterion("`level` >", value, "level");
return (Criteria) this;
}
public Criteria andLevelGreaterThanOrEqualTo(Integer value) {
addCriterion("`level` >=", value, "level");
return (Criteria) this;
}
public Criteria andLevelLessThan(Integer value) {
addCriterion("`level` <", value, "level");
return (Criteria) this;
}
public Criteria andLevelLessThanOrEqualTo(Integer value) {
addCriterion("`level` <=", value, "level");
return (Criteria) this;
}
public Criteria andLevelIn(List<Integer> values) {
addCriterion("`level` in", values, "level");
return (Criteria) this;
}
public Criteria andLevelNotIn(List<Integer> values) {
addCriterion("`level` not in", values, "level");
return (Criteria) this;
}
public Criteria andLevelBetween(Integer value1, Integer value2) {
addCriterion("`level` between", value1, value2, "level");
return (Criteria) this;
}
public Criteria andLevelNotBetween(Integer value1, Integer value2) {
addCriterion("`level` not between", value1, value2, "level");
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<Long> values) {
addCriterion("create_time in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotIn(List<Long> 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 Criteria andUpdateTimeIsNull() {
addCriterion("update_time is null");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNotNull() {
addCriterion("update_time is not null");
return (Criteria) this;
}
public Criteria andUpdateTimeEqualTo(Long value) {
addCriterion("update_time =", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotEqualTo(Long value) {
addCriterion("update_time <>", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThan(Long value) {
addCriterion("update_time >", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("update_time >=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThan(Long value) {
addCriterion("update_time <", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThanOrEqualTo(Long value) {
addCriterion("update_time <=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIn(List<Long> values) {
addCriterion("update_time in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotIn(List<Long> values) {
addCriterion("update_time not in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeBetween(Long value1, Long value2) {
addCriterion("update_time between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotBetween(Long value1, Long value2) {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andPosIsNull() {
addCriterion("pos is null");
return (Criteria) this;
}
public Criteria andPosIsNotNull() {
addCriterion("pos is not null");
return (Criteria) this;
}
public Criteria andPosEqualTo(Double value) {
addCriterion("pos =", value, "pos");
return (Criteria) this;
}
public Criteria andPosNotEqualTo(Double value) {
addCriterion("pos <>", value, "pos");
return (Criteria) this;
}
public Criteria andPosGreaterThan(Double value) {
addCriterion("pos >", value, "pos");
return (Criteria) this;
}
public Criteria andPosGreaterThanOrEqualTo(Double value) {
addCriterion("pos >=", value, "pos");
return (Criteria) this;
}
public Criteria andPosLessThan(Double value) {
addCriterion("pos <", value, "pos");
return (Criteria) this;
}
public Criteria andPosLessThanOrEqualTo(Double value) {
addCriterion("pos <=", value, "pos");
return (Criteria) this;
}
public Criteria andPosIn(List<Double> values) {
addCriterion("pos in", values, "pos");
return (Criteria) this;
}
public Criteria andPosNotIn(List<Double> values) {
addCriterion("pos not in", values, "pos");
return (Criteria) this;
}
public Criteria andPosBetween(Double value1, Double value2) {
addCriterion("pos between", value1, value2, "pos");
return (Criteria) this;
}
public Criteria andPosNotBetween(Double value1, Double value2) {
addCriterion("pos not between", value1, value2, "pos");
return (Criteria) this;
}
public Criteria andCreateUserIsNull() {
addCriterion("create_user is null");
return (Criteria) this;
}
public Criteria andCreateUserIsNotNull() {
addCriterion("create_user is not null");
return (Criteria) this;
}
public Criteria andCreateUserEqualTo(String value) {
addCriterion("create_user =", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotEqualTo(String value) {
addCriterion("create_user <>", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserGreaterThan(String value) {
addCriterion("create_user >", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserGreaterThanOrEqualTo(String value) {
addCriterion("create_user >=", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLessThan(String value) {
addCriterion("create_user <", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLessThanOrEqualTo(String value) {
addCriterion("create_user <=", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLike(String value) {
addCriterion("create_user like", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotLike(String value) {
addCriterion("create_user not like", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserIn(List<String> values) {
addCriterion("create_user in", values, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotIn(List<String> values) {
addCriterion("create_user not in", values, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserBetween(String value1, String value2) {
addCriterion("create_user between", value1, value2, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotBetween(String value1, String value2) {
addCriterion("create_user not between", value1, value2, "createUser");
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);
}
}
}

View File

@ -1,8 +1,7 @@
package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable;
import lombok.Data;
@Data
public class TestPlan implements Serializable {
@ -42,5 +41,9 @@ public class TestPlan implements Serializable {
private Boolean repeatCase;
private String nodeId;
private String nodePath;
private static final long serialVersionUID = 1L;
}

View File

@ -1273,6 +1273,146 @@ public class TestPlanExample {
addCriterion("repeat_case not between", value1, value2, "repeatCase");
return (Criteria) this;
}
public Criteria andNodeIdIsNull() {
addCriterion("node_id is null");
return (Criteria) this;
}
public Criteria andNodeIdIsNotNull() {
addCriterion("node_id is not null");
return (Criteria) this;
}
public Criteria andNodeIdEqualTo(String value) {
addCriterion("node_id =", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdNotEqualTo(String value) {
addCriterion("node_id <>", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdGreaterThan(String value) {
addCriterion("node_id >", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdGreaterThanOrEqualTo(String value) {
addCriterion("node_id >=", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdLessThan(String value) {
addCriterion("node_id <", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdLessThanOrEqualTo(String value) {
addCriterion("node_id <=", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdLike(String value) {
addCriterion("node_id like", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdNotLike(String value) {
addCriterion("node_id not like", value, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdIn(List<String> values) {
addCriterion("node_id in", values, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdNotIn(List<String> values) {
addCriterion("node_id not in", values, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdBetween(String value1, String value2) {
addCriterion("node_id between", value1, value2, "nodeId");
return (Criteria) this;
}
public Criteria andNodeIdNotBetween(String value1, String value2) {
addCriterion("node_id not between", value1, value2, "nodeId");
return (Criteria) this;
}
public Criteria andNodePathIsNull() {
addCriterion("node_path is null");
return (Criteria) this;
}
public Criteria andNodePathIsNotNull() {
addCriterion("node_path is not null");
return (Criteria) this;
}
public Criteria andNodePathEqualTo(String value) {
addCriterion("node_path =", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathNotEqualTo(String value) {
addCriterion("node_path <>", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathGreaterThan(String value) {
addCriterion("node_path >", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathGreaterThanOrEqualTo(String value) {
addCriterion("node_path >=", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathLessThan(String value) {
addCriterion("node_path <", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathLessThanOrEqualTo(String value) {
addCriterion("node_path <=", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathLike(String value) {
addCriterion("node_path like", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathNotLike(String value) {
addCriterion("node_path not like", value, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathIn(List<String> values) {
addCriterion("node_path in", values, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathNotIn(List<String> values) {
addCriterion("node_path not in", values, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathBetween(String value1, String value2) {
addCriterion("node_path between", value1, value2, "nodePath");
return (Criteria) this;
}
public Criteria andNodePathNotBetween(String value1, String value2) {
addCriterion("node_path not between", value1, value2, "nodePath");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -0,0 +1,27 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class TestPlanNode implements Serializable {
private String id;
private String projectId;
private String name;
private String parentId;
private Integer level;
private Long createTime;
private Long updateTime;
private Double pos;
private String createUser;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,790 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class TestPlanNodeExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public TestPlanNodeExample() {
oredCriteria = new ArrayList<Criteria>();
}
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<Criteria> 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<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> 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 andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andProjectIdIsNull() {
addCriterion("project_id is null");
return (Criteria) this;
}
public Criteria andProjectIdIsNotNull() {
addCriterion("project_id is not null");
return (Criteria) this;
}
public Criteria andProjectIdEqualTo(String value) {
addCriterion("project_id =", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("project_id <>", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThan(String value) {
addCriterion("project_id >", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("project_id >=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThan(String value) {
addCriterion("project_id <", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThanOrEqualTo(String value) {
addCriterion("project_id <=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLike(String value) {
addCriterion("project_id like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotLike(String value) {
addCriterion("project_id not like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdIn(List<String> values) {
addCriterion("project_id in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotIn(List<String> values) {
addCriterion("project_id not in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdBetween(String value1, String value2) {
addCriterion("project_id between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotBetween(String value1, String value2) {
addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andNameIsNull() {
addCriterion("`name` is null");
return (Criteria) this;
}
public Criteria andNameIsNotNull() {
addCriterion("`name` is not null");
return (Criteria) this;
}
public Criteria andNameEqualTo(String value) {
addCriterion("`name` =", value, "name");
return (Criteria) this;
}
public Criteria andNameNotEqualTo(String value) {
addCriterion("`name` <>", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThan(String value) {
addCriterion("`name` >", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThanOrEqualTo(String value) {
addCriterion("`name` >=", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThan(String value) {
addCriterion("`name` <", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThanOrEqualTo(String value) {
addCriterion("`name` <=", value, "name");
return (Criteria) this;
}
public Criteria andNameLike(String value) {
addCriterion("`name` like", value, "name");
return (Criteria) this;
}
public Criteria andNameNotLike(String value) {
addCriterion("`name` not like", value, "name");
return (Criteria) this;
}
public Criteria andNameIn(List<String> values) {
addCriterion("`name` in", values, "name");
return (Criteria) this;
}
public Criteria andNameNotIn(List<String> values) {
addCriterion("`name` not in", values, "name");
return (Criteria) this;
}
public Criteria andNameBetween(String value1, String value2) {
addCriterion("`name` between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andNameNotBetween(String value1, String value2) {
addCriterion("`name` not between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andParentIdIsNull() {
addCriterion("parent_id is null");
return (Criteria) this;
}
public Criteria andParentIdIsNotNull() {
addCriterion("parent_id is not null");
return (Criteria) this;
}
public Criteria andParentIdEqualTo(String value) {
addCriterion("parent_id =", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotEqualTo(String value) {
addCriterion("parent_id <>", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdGreaterThan(String value) {
addCriterion("parent_id >", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdGreaterThanOrEqualTo(String value) {
addCriterion("parent_id >=", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdLessThan(String value) {
addCriterion("parent_id <", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdLessThanOrEqualTo(String value) {
addCriterion("parent_id <=", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdLike(String value) {
addCriterion("parent_id like", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotLike(String value) {
addCriterion("parent_id not like", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdIn(List<String> values) {
addCriterion("parent_id in", values, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotIn(List<String> values) {
addCriterion("parent_id not in", values, "parentId");
return (Criteria) this;
}
public Criteria andParentIdBetween(String value1, String value2) {
addCriterion("parent_id between", value1, value2, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotBetween(String value1, String value2) {
addCriterion("parent_id not between", value1, value2, "parentId");
return (Criteria) this;
}
public Criteria andLevelIsNull() {
addCriterion("`level` is null");
return (Criteria) this;
}
public Criteria andLevelIsNotNull() {
addCriterion("`level` is not null");
return (Criteria) this;
}
public Criteria andLevelEqualTo(Integer value) {
addCriterion("`level` =", value, "level");
return (Criteria) this;
}
public Criteria andLevelNotEqualTo(Integer value) {
addCriterion("`level` <>", value, "level");
return (Criteria) this;
}
public Criteria andLevelGreaterThan(Integer value) {
addCriterion("`level` >", value, "level");
return (Criteria) this;
}
public Criteria andLevelGreaterThanOrEqualTo(Integer value) {
addCriterion("`level` >=", value, "level");
return (Criteria) this;
}
public Criteria andLevelLessThan(Integer value) {
addCriterion("`level` <", value, "level");
return (Criteria) this;
}
public Criteria andLevelLessThanOrEqualTo(Integer value) {
addCriterion("`level` <=", value, "level");
return (Criteria) this;
}
public Criteria andLevelIn(List<Integer> values) {
addCriterion("`level` in", values, "level");
return (Criteria) this;
}
public Criteria andLevelNotIn(List<Integer> values) {
addCriterion("`level` not in", values, "level");
return (Criteria) this;
}
public Criteria andLevelBetween(Integer value1, Integer value2) {
addCriterion("`level` between", value1, value2, "level");
return (Criteria) this;
}
public Criteria andLevelNotBetween(Integer value1, Integer value2) {
addCriterion("`level` not between", value1, value2, "level");
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<Long> values) {
addCriterion("create_time in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotIn(List<Long> 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 Criteria andUpdateTimeIsNull() {
addCriterion("update_time is null");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNotNull() {
addCriterion("update_time is not null");
return (Criteria) this;
}
public Criteria andUpdateTimeEqualTo(Long value) {
addCriterion("update_time =", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotEqualTo(Long value) {
addCriterion("update_time <>", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThan(Long value) {
addCriterion("update_time >", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("update_time >=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThan(Long value) {
addCriterion("update_time <", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThanOrEqualTo(Long value) {
addCriterion("update_time <=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIn(List<Long> values) {
addCriterion("update_time in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotIn(List<Long> values) {
addCriterion("update_time not in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeBetween(Long value1, Long value2) {
addCriterion("update_time between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotBetween(Long value1, Long value2) {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andPosIsNull() {
addCriterion("pos is null");
return (Criteria) this;
}
public Criteria andPosIsNotNull() {
addCriterion("pos is not null");
return (Criteria) this;
}
public Criteria andPosEqualTo(Double value) {
addCriterion("pos =", value, "pos");
return (Criteria) this;
}
public Criteria andPosNotEqualTo(Double value) {
addCriterion("pos <>", value, "pos");
return (Criteria) this;
}
public Criteria andPosGreaterThan(Double value) {
addCriterion("pos >", value, "pos");
return (Criteria) this;
}
public Criteria andPosGreaterThanOrEqualTo(Double value) {
addCriterion("pos >=", value, "pos");
return (Criteria) this;
}
public Criteria andPosLessThan(Double value) {
addCriterion("pos <", value, "pos");
return (Criteria) this;
}
public Criteria andPosLessThanOrEqualTo(Double value) {
addCriterion("pos <=", value, "pos");
return (Criteria) this;
}
public Criteria andPosIn(List<Double> values) {
addCriterion("pos in", values, "pos");
return (Criteria) this;
}
public Criteria andPosNotIn(List<Double> values) {
addCriterion("pos not in", values, "pos");
return (Criteria) this;
}
public Criteria andPosBetween(Double value1, Double value2) {
addCriterion("pos between", value1, value2, "pos");
return (Criteria) this;
}
public Criteria andPosNotBetween(Double value1, Double value2) {
addCriterion("pos not between", value1, value2, "pos");
return (Criteria) this;
}
public Criteria andCreateUserIsNull() {
addCriterion("create_user is null");
return (Criteria) this;
}
public Criteria andCreateUserIsNotNull() {
addCriterion("create_user is not null");
return (Criteria) this;
}
public Criteria andCreateUserEqualTo(String value) {
addCriterion("create_user =", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotEqualTo(String value) {
addCriterion("create_user <>", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserGreaterThan(String value) {
addCriterion("create_user >", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserGreaterThanOrEqualTo(String value) {
addCriterion("create_user >=", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLessThan(String value) {
addCriterion("create_user <", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLessThanOrEqualTo(String value) {
addCriterion("create_user <=", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLike(String value) {
addCriterion("create_user like", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotLike(String value) {
addCriterion("create_user not like", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserIn(List<String> values) {
addCriterion("create_user in", values, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotIn(List<String> values) {
addCriterion("create_user not in", values, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserBetween(String value1, String value2) {
addCriterion("create_user between", value1, value2, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotBetween(String value1, String value2) {
addCriterion("create_user not between", value1, value2, "createUser");
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);
}
}
}

View File

@ -1,11 +1,10 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.Serializable;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)

View File

@ -63,7 +63,8 @@
</javaClientGenerator>
<!--要生成的数据库表 -->
<table tableName="custom_field"/>
<table tableName="test_plan"/>
<table tableName="test_plan_node"/>
<!-- 要忽略的字段-->
<!-- <table tableName="test_case">

View File

@ -933,6 +933,18 @@ export const TEST_CASE_MODULE_TREE = _getModuleTree({
params: {} // 赋值时注意顺序
})
export const TEST_CASE_REVIEW_MODULE_TREE = _getModuleTree({
url: "/case/review/node/list",
type: "POST",
params: {} // 赋值时注意顺序
})
export const TEST_PLAN_MODULE_TREE = _getModuleTree({
url: "/plan/node/list",
type: "POST",
params: {} // 赋值时注意顺序
})
export const API_MODULE_TREE = _getModuleTree({
url: "/api/module/list",
type: "GET",
@ -993,10 +1005,10 @@ export const UI_CUSTOM_COMMAND_CONFIGS_TRASH = [NAME, CREATE_TIME, PROJECT_CREAT
// 测试跟踪-测试用例 列表
export const TEST_CASE_CONFIGS = [ID, NAME, TAGS, TEST_CASE_MODULE_TREE, CREATE_TIME, UPDATE_TIME, CREATOR, CASE_REVIEW_STATUS, FOLLOW_PEOPLE, CASE_DEMAND, TEST_CASE_STATUS, TEST_CASE_PRIORITY, TEST_CASE_MAINTAINER];
export const TEST_PLAN_CONFIGS = [NAME, UPDATE_TIME, CREATE_TIME, PRINCIPAL, TEST_PLAN_STATUS, STAGE, TAGS, FOLLOW_PEOPLE, ACTUAL_START_TIME, ACTUAL_END_TIME, PLAN_START_TIME, PLAN_END_TIME];
export const TEST_PLAN_CONFIGS = [NAME, UPDATE_TIME, CREATE_TIME, TEST_PLAN_MODULE_TREE, PRINCIPAL, TEST_PLAN_STATUS, STAGE, TAGS, FOLLOW_PEOPLE, ACTUAL_START_TIME, ACTUAL_END_TIME, PLAN_START_TIME, PLAN_END_TIME];
// 测试跟踪 测试评审列表
export const TEST_REVIEW = [NAME, CREATOR, TAGS, TEST_PLAN_STATUS, FOLLOW_PEOPLE, CREATE_TIME, UPDATE_TIME, END_TIME];
export const TEST_REVIEW = [NAME, CREATOR, TAGS, TEST_CASE_REVIEW_MODULE_TREE, TEST_PLAN_STATUS, FOLLOW_PEOPLE, CREATE_TIME, UPDATE_TIME, END_TIME];
export const TEST_REVIEW_CASE = [NAME, REVIEWER, MAINTAINER];
export const TEST_REVIEW_RELEVANCE_CASE_CONFIGS = [ID, NAME, TAGS, TEST_CASE_MODULE_TREE, CREATE_TIME, UPDATE_TIME, CREATOR, CASE_REVIEW_STATUS, FOLLOW_PEOPLE, CASE_DEMAND, TEST_CASE_STATUS, TEST_CASE_PRIORITY, TEST_CASE_MAINTAINER];

View File

@ -113,6 +113,7 @@ const message = {
"The debugging history only shows the last five pieces of data",
operating: "Operating",
input_limit: "Within {0} and {1} characters",
module_name_limit: "The module name length does not exceed 100 characters",
login: "Sign In",
welcome: "One-stop open source continuous testing platform",
theme_color: "Theme color",

View File

@ -139,6 +139,7 @@ export default {
batch_update_to: "Batch update to",
select_catalog: "Please select use case catalog",
batch_move_to: 'Move "{0}" {1} of Cases to',
resource_batch_move_to: 'Move "{0}" {1} of {2} to',
batch_copy_to: 'Copy "{0}" {1} of Cases to',
updated_attr_value: "The updated attribute value",
batch_operate: "Batch operation",

View File

@ -122,6 +122,7 @@ export default {
batch_update_to: "批量更新为",
select_catalog: "请选择用例目录",
batch_move_to: '将"{0}"等{1}个用例 移动到',
resource_batch_move_to: '将"{0}"等{1}条{2} 移动到',
batch_copy_to: '将"{0}"等{1}个用例 复制到',
updated_attr_value: "更新后属性值为",
batch_operate: "批量操作",

View File

@ -122,6 +122,7 @@ export default {
batch_update_to: "批量更新爲",
select_catalog: "請選擇用例目錄",
batch_move_to: '將"{0}"等{1}個用例 移動到',
resource_batch_move_to: '將"{0}"等{1}條{2} 移動到',
batch_copy_to: '將"{0}"等{1}個用例 複製到',
updated_attr_value: "更新後屬性值為",
batch_operate: "批量操作",

View File

@ -112,6 +112,7 @@ const message = {
prompt: "提示",
operating: "操作",
input_limit: "长度在 {0} 到 {1} 个字符",
module_name_limit: "模块长度不超过100个字符",
login: "登录",
welcome: "一站式开源持续测试平台",
theme_color: "主题色",

View File

@ -112,6 +112,7 @@ const message = {
prompt: "提示",
operating: "操作",
input_limit: "長度在 {0} 到 {1} 個字符",
module_name_limit: "模塊長度不超過100個字符",
login: "登錄",
welcome: "一站式開源持續測試平臺",
theme_color: "主題色",

View File

@ -26,7 +26,11 @@ public enum ProjectModuleDefaultNodeEnum {
/**
* UI元素库默认节点
*/
UI_ELEMENT_DEFAULT_NODE("未规划元素", "ui_element_module");
UI_ELEMENT_DEFAULT_NODE("未规划元素", "ui_element_module"),
/**
* 未规划模块(评审, 计划)
*/
DEFAULT_NODE("未规划模块", "node");
private String nodeName;
private String tableName;

View File

@ -2,9 +2,10 @@ package io.metersphere.base.mapper;
import io.metersphere.base.domain.TestCaseReview;
import io.metersphere.base.domain.TestCaseReviewExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface TestCaseReviewMapper {
long countByExample(TestCaseReviewExample example);
@ -33,4 +34,4 @@ public interface TestCaseReviewMapper {
int updateByPrimaryKeyWithBLOBs(TestCaseReview record);
int updateByPrimaryKey(TestCaseReview record);
}
}

View File

@ -13,6 +13,8 @@
<result column="tags" jdbcType="VARCHAR" property="tags" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
<result column="review_pass_rule" jdbcType="VARCHAR" property="reviewPassRule" />
<result column="node_id" jdbcType="VARCHAR" property="nodeId" />
<result column="node_path" jdbcType="VARCHAR" property="nodePath" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestCaseReview">
<result column="description" jdbcType="LONGVARCHAR" property="description" />
@ -76,8 +78,8 @@
</where>
</sql>
<sql id="Base_Column_List">
id, `name`, creator, `status`, create_time, update_time, end_time, project_id, tags,
create_user, review_pass_rule
id, `name`, creator, `status`, create_time, update_time, end_time, project_id, tags,
create_user, review_pass_rule, node_id, node_path
</sql>
<sql id="Blob_Column_List">
description
@ -113,7 +115,7 @@
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
@ -131,16 +133,16 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestCaseReview">
insert into test_case_review (id, `name`, creator,
`status`, create_time, update_time,
end_time, project_id, tags,
create_user, review_pass_rule, description
)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{creator,jdbcType=VARCHAR},
#{status,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{endTime,jdbcType=BIGINT}, #{projectId,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR},
#{createUser,jdbcType=VARCHAR}, #{reviewPassRule,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR}
)
insert into test_case_review (id, `name`, creator,
`status`, create_time, update_time,
end_time, project_id, tags,
create_user, review_pass_rule, node_id,
node_path, description)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{creator,jdbcType=VARCHAR},
#{status,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{endTime,jdbcType=BIGINT}, #{projectId,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR},
#{createUser,jdbcType=VARCHAR}, #{reviewPassRule,jdbcType=VARCHAR}, #{nodeId,jdbcType=VARCHAR},
#{nodePath,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestCaseReview">
insert into test_case_review
@ -178,6 +180,12 @@
<if test="reviewPassRule != null">
review_pass_rule,
</if>
<if test="nodeId != null">
node_id,
</if>
<if test="nodePath != null">
node_path,
</if>
<if test="description != null">
description,
</if>
@ -216,6 +224,12 @@
<if test="reviewPassRule != null">
#{reviewPassRule,jdbcType=VARCHAR},
</if>
<if test="nodeId != null">
#{nodeId,jdbcType=VARCHAR},
</if>
<if test="nodePath != null">
#{nodePath,jdbcType=VARCHAR},
</if>
<if test="description != null">
#{description,jdbcType=LONGVARCHAR},
</if>
@ -263,6 +277,12 @@
<if test="record.reviewPassRule != null">
review_pass_rule = #{record.reviewPassRule,jdbcType=VARCHAR},
</if>
<if test="record.nodeId != null">
node_id = #{record.nodeId,jdbcType=VARCHAR},
</if>
<if test="record.nodePath != null">
node_path = #{record.nodePath,jdbcType=VARCHAR},
</if>
<if test="record.description != null">
description = #{record.description,jdbcType=LONGVARCHAR},
</if>
@ -284,6 +304,8 @@
tags = #{record.tags,jdbcType=VARCHAR},
create_user = #{record.createUser,jdbcType=VARCHAR},
review_pass_rule = #{record.reviewPassRule,jdbcType=VARCHAR},
node_id = #{record.nodeId,jdbcType=VARCHAR},
node_path = #{record.nodePath,jdbcType=VARCHAR},
description = #{record.description,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -301,7 +323,9 @@
project_id = #{record.projectId,jdbcType=VARCHAR},
tags = #{record.tags,jdbcType=VARCHAR},
create_user = #{record.createUser,jdbcType=VARCHAR},
review_pass_rule = #{record.reviewPassRule,jdbcType=VARCHAR}
review_pass_rule = #{record.reviewPassRule,jdbcType=VARCHAR},
node_id = #{record.nodeId,jdbcType=VARCHAR},
node_path = #{record.nodePath,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -339,6 +363,12 @@
<if test="reviewPassRule != null">
review_pass_rule = #{reviewPassRule,jdbcType=VARCHAR},
</if>
<if test="nodeId != null">
node_id = #{nodeId,jdbcType=VARCHAR},
</if>
<if test="nodePath != null">
node_path = #{nodePath,jdbcType=VARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=LONGVARCHAR},
</if>
@ -357,6 +387,8 @@
tags = #{tags,jdbcType=VARCHAR},
create_user = #{createUser,jdbcType=VARCHAR},
review_pass_rule = #{reviewPassRule,jdbcType=VARCHAR},
node_id = #{nodeId,jdbcType=VARCHAR},
node_path = #{nodePath,jdbcType=VARCHAR},
description = #{description,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
@ -371,7 +403,9 @@
project_id = #{projectId,jdbcType=VARCHAR},
tags = #{tags,jdbcType=VARCHAR},
create_user = #{createUser,jdbcType=VARCHAR},
review_pass_rule = #{reviewPassRule,jdbcType=VARCHAR}
review_pass_rule = #{reviewPassRule,jdbcType=VARCHAR},
node_id = #{nodeId,jdbcType=VARCHAR},
node_path = #{nodePath,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>
</mapper>

View File

@ -0,0 +1,30 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.TestCaseReviewNode;
import io.metersphere.base.domain.TestCaseReviewNodeExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface TestCaseReviewNodeMapper {
long countByExample(TestCaseReviewNodeExample example);
int deleteByExample(TestCaseReviewNodeExample example);
int deleteByPrimaryKey(String id);
int insert(TestCaseReviewNode record);
int insertSelective(TestCaseReviewNode record);
List<TestCaseReviewNode> selectByExample(TestCaseReviewNodeExample example);
TestCaseReviewNode selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") TestCaseReviewNode record, @Param("example") TestCaseReviewNodeExample example);
int updateByExample(@Param("record") TestCaseReviewNode record, @Param("example") TestCaseReviewNodeExample example);
int updateByPrimaryKeySelective(TestCaseReviewNode record);
int updateByPrimaryKey(TestCaseReviewNode record);
}

View File

@ -0,0 +1,275 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.TestCaseReviewNodeMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.TestCaseReviewNode">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="parent_id" jdbcType="VARCHAR" property="parentId" />
<result column="level" jdbcType="INTEGER" property="level" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="pos" jdbcType="DOUBLE" property="pos" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, project_id, `name`, parent_id, `level`, create_time, update_time, pos, create_user
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestCaseReviewNodeExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from test_case_review_node
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from test_case_review_node
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from test_case_review_node
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.TestCaseReviewNodeExample">
delete from test_case_review_node
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestCaseReviewNode">
insert into test_case_review_node (id, project_id, `name`,
parent_id, `level`, create_time,
update_time, pos, create_user
)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{parentId,jdbcType=VARCHAR}, #{level,jdbcType=INTEGER}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{pos,jdbcType=DOUBLE}, #{createUser,jdbcType=VARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestCaseReviewNode">
insert into test_case_review_node
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="projectId != null">
project_id,
</if>
<if test="name != null">
`name`,
</if>
<if test="parentId != null">
parent_id,
</if>
<if test="level != null">
`level`,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="pos != null">
pos,
</if>
<if test="createUser != null">
create_user,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="projectId != null">
#{projectId,jdbcType=VARCHAR},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="parentId != null">
#{parentId,jdbcType=VARCHAR},
</if>
<if test="level != null">
#{level,jdbcType=INTEGER},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="pos != null">
#{pos,jdbcType=DOUBLE},
</if>
<if test="createUser != null">
#{createUser,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestCaseReviewNodeExample" resultType="java.lang.Long">
select count(*) from test_case_review_node
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update test_case_review_node
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.parentId != null">
parent_id = #{record.parentId,jdbcType=VARCHAR},
</if>
<if test="record.level != null">
`level` = #{record.level,jdbcType=INTEGER},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.pos != null">
pos = #{record.pos,jdbcType=DOUBLE},
</if>
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update test_case_review_node
set id = #{record.id,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
parent_id = #{record.parentId,jdbcType=VARCHAR},
`level` = #{record.level,jdbcType=INTEGER},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
pos = #{record.pos,jdbcType=DOUBLE},
create_user = #{record.createUser,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.TestCaseReviewNode">
update test_case_review_node
<set>
<if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR},
</if>
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
</if>
<if test="parentId != null">
parent_id = #{parentId,jdbcType=VARCHAR},
</if>
<if test="level != null">
`level` = #{level,jdbcType=INTEGER},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="pos != null">
pos = #{pos,jdbcType=DOUBLE},
</if>
<if test="createUser != null">
create_user = #{createUser,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestCaseReviewNode">
update test_case_review_node
set project_id = #{projectId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
parent_id = #{parentId,jdbcType=VARCHAR},
`level` = #{level,jdbcType=INTEGER},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
pos = #{pos,jdbcType=DOUBLE},
create_user = #{createUser,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -3,9 +3,10 @@ package io.metersphere.base.mapper;
import io.metersphere.base.domain.TestPlan;
import io.metersphere.base.domain.TestPlanExample;
import io.metersphere.base.domain.TestPlanWithBLOBs;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface TestPlanMapper {
long countByExample(TestPlanExample example);
@ -34,4 +35,4 @@ public interface TestPlanMapper {
int updateByPrimaryKeyWithBLOBs(TestPlanWithBLOBs record);
int updateByPrimaryKey(TestPlan record);
}
}

View File

@ -20,6 +20,8 @@
<result column="execution_times" jdbcType="INTEGER" property="executionTimes" />
<result column="automatic_status_update" jdbcType="BIT" property="automaticStatusUpdate" />
<result column="repeat_case" jdbcType="BIT" property="repeatCase" />
<result column="node_id" jdbcType="VARCHAR" property="nodeId" />
<result column="node_path" jdbcType="VARCHAR" property="nodePath" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestPlanWithBLOBs">
<result column="tags" jdbcType="LONGVARCHAR" property="tags" />
@ -86,9 +88,9 @@
</where>
</sql>
<sql id="Base_Column_List">
id, workspace_id, report_id, `name`, description, `status`, stage, create_time, update_time,
planned_start_time, planned_end_time, actual_start_time, actual_end_time, creator,
project_id, execution_times, automatic_status_update, repeat_case
id, workspace_id, report_id, `name`, description, `status`, stage, create_time, update_time,
planned_start_time, planned_end_time, actual_start_time, actual_end_time, creator,
project_id, execution_times, automatic_status_update, repeat_case, node_id, node_path
</sql>
<sql id="Blob_Column_List">
tags, report_summary, report_config, run_mode_config
@ -124,7 +126,7 @@
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
@ -142,22 +144,24 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestPlanWithBLOBs">
insert into test_plan (id, workspace_id, report_id,
`name`, description, `status`,
stage, create_time, update_time,
planned_start_time, planned_end_time, actual_start_time,
actual_end_time, creator, project_id,
execution_times, automatic_status_update, repeat_case,
tags, report_summary, report_config,
run_mode_config)
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
#{stage,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{plannedStartTime,jdbcType=BIGINT}, #{plannedEndTime,jdbcType=BIGINT}, #{actualStartTime,jdbcType=BIGINT},
#{actualEndTime,jdbcType=BIGINT}, #{creator,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR},
#{executionTimes,jdbcType=INTEGER}, #{automaticStatusUpdate,jdbcType=BIT}, #{repeatCase,jdbcType=BIT},
#{tags,jdbcType=LONGVARCHAR}, #{reportSummary,jdbcType=LONGVARCHAR}, #{reportConfig,jdbcType=LONGVARCHAR},
#{runModeConfig,jdbcType=LONGVARCHAR})
insert into test_plan (id, workspace_id, report_id,
`name`, description, `status`,
stage, create_time, update_time,
planned_start_time, planned_end_time, actual_start_time,
actual_end_time, creator, project_id,
execution_times, automatic_status_update, repeat_case,
node_id, node_path, tags,
report_summary, report_config, run_mode_config
)
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
#{stage,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{plannedStartTime,jdbcType=BIGINT}, #{plannedEndTime,jdbcType=BIGINT}, #{actualStartTime,jdbcType=BIGINT},
#{actualEndTime,jdbcType=BIGINT}, #{creator,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR},
#{executionTimes,jdbcType=INTEGER}, #{automaticStatusUpdate,jdbcType=BIT}, #{repeatCase,jdbcType=BIT},
#{nodeId,jdbcType=VARCHAR}, #{nodePath,jdbcType=VARCHAR}, #{tags,jdbcType=LONGVARCHAR},
#{reportSummary,jdbcType=LONGVARCHAR}, #{reportConfig,jdbcType=LONGVARCHAR}, #{runModeConfig,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanWithBLOBs">
insert into test_plan
@ -216,6 +220,12 @@
<if test="repeatCase != null">
repeat_case,
</if>
<if test="nodeId != null">
node_id,
</if>
<if test="nodePath != null">
node_path,
</if>
<if test="tags != null">
tags,
</if>
@ -284,6 +294,12 @@
<if test="repeatCase != null">
#{repeatCase,jdbcType=BIT},
</if>
<if test="nodeId != null">
#{nodeId,jdbcType=VARCHAR},
</if>
<if test="nodePath != null">
#{nodePath,jdbcType=VARCHAR},
</if>
<if test="tags != null">
#{tags,jdbcType=LONGVARCHAR},
</if>
@ -361,6 +377,12 @@
<if test="record.repeatCase != null">
repeat_case = #{record.repeatCase,jdbcType=BIT},
</if>
<if test="record.nodeId != null">
node_id = #{record.nodeId,jdbcType=VARCHAR},
</if>
<if test="record.nodePath != null">
node_path = #{record.nodePath,jdbcType=VARCHAR},
</if>
<if test="record.tags != null">
tags = #{record.tags,jdbcType=LONGVARCHAR},
</if>
@ -398,6 +420,8 @@
execution_times = #{record.executionTimes,jdbcType=INTEGER},
automatic_status_update = #{record.automaticStatusUpdate,jdbcType=BIT},
repeat_case = #{record.repeatCase,jdbcType=BIT},
node_id = #{record.nodeId,jdbcType=VARCHAR},
node_path = #{record.nodePath,jdbcType=VARCHAR},
tags = #{record.tags,jdbcType=LONGVARCHAR},
report_summary = #{record.reportSummary,jdbcType=LONGVARCHAR},
report_config = #{record.reportConfig,jdbcType=LONGVARCHAR},
@ -425,7 +449,9 @@
project_id = #{record.projectId,jdbcType=VARCHAR},
execution_times = #{record.executionTimes,jdbcType=INTEGER},
automatic_status_update = #{record.automaticStatusUpdate,jdbcType=BIT},
repeat_case = #{record.repeatCase,jdbcType=BIT}
repeat_case = #{record.repeatCase,jdbcType=BIT},
node_id = #{record.nodeId,jdbcType=VARCHAR},
node_path = #{record.nodePath,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -484,6 +510,12 @@
<if test="repeatCase != null">
repeat_case = #{repeatCase,jdbcType=BIT},
</if>
<if test="nodeId != null">
node_id = #{nodeId,jdbcType=VARCHAR},
</if>
<if test="nodePath != null">
node_path = #{nodePath,jdbcType=VARCHAR},
</if>
<if test="tags != null">
tags = #{tags,jdbcType=LONGVARCHAR},
</if>
@ -518,6 +550,8 @@
execution_times = #{executionTimes,jdbcType=INTEGER},
automatic_status_update = #{automaticStatusUpdate,jdbcType=BIT},
repeat_case = #{repeatCase,jdbcType=BIT},
node_id = #{nodeId,jdbcType=VARCHAR},
node_path = #{nodePath,jdbcType=VARCHAR},
tags = #{tags,jdbcType=LONGVARCHAR},
report_summary = #{reportSummary,jdbcType=LONGVARCHAR},
report_config = #{reportConfig,jdbcType=LONGVARCHAR},
@ -542,7 +576,9 @@
project_id = #{projectId,jdbcType=VARCHAR},
execution_times = #{executionTimes,jdbcType=INTEGER},
automatic_status_update = #{automaticStatusUpdate,jdbcType=BIT},
repeat_case = #{repeatCase,jdbcType=BIT}
repeat_case = #{repeatCase,jdbcType=BIT},
node_id = #{nodeId,jdbcType=VARCHAR},
node_path = #{nodePath,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>
</mapper>

View File

@ -0,0 +1,30 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.TestPlanNode;
import io.metersphere.base.domain.TestPlanNodeExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface TestPlanNodeMapper {
long countByExample(TestPlanNodeExample example);
int deleteByExample(TestPlanNodeExample example);
int deleteByPrimaryKey(String id);
int insert(TestPlanNode record);
int insertSelective(TestPlanNode record);
List<TestPlanNode> selectByExample(TestPlanNodeExample example);
TestPlanNode selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") TestPlanNode record, @Param("example") TestPlanNodeExample example);
int updateByExample(@Param("record") TestPlanNode record, @Param("example") TestPlanNodeExample example);
int updateByPrimaryKeySelective(TestPlanNode record);
int updateByPrimaryKey(TestPlanNode record);
}

View File

@ -0,0 +1,275 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.TestPlanNodeMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.TestPlanNode">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="parent_id" jdbcType="VARCHAR" property="parentId" />
<result column="level" jdbcType="INTEGER" property="level" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="pos" jdbcType="DOUBLE" property="pos" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, project_id, `name`, parent_id, `level`, create_time, update_time, pos, create_user
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestPlanNodeExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from test_plan_node
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from test_plan_node
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from test_plan_node
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.TestPlanNodeExample">
delete from test_plan_node
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestPlanNode">
insert into test_plan_node (id, project_id, `name`,
parent_id, `level`, create_time,
update_time, pos, create_user
)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{parentId,jdbcType=VARCHAR}, #{level,jdbcType=INTEGER}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{pos,jdbcType=DOUBLE}, #{createUser,jdbcType=VARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanNode">
insert into test_plan_node
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="projectId != null">
project_id,
</if>
<if test="name != null">
`name`,
</if>
<if test="parentId != null">
parent_id,
</if>
<if test="level != null">
`level`,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="pos != null">
pos,
</if>
<if test="createUser != null">
create_user,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="projectId != null">
#{projectId,jdbcType=VARCHAR},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="parentId != null">
#{parentId,jdbcType=VARCHAR},
</if>
<if test="level != null">
#{level,jdbcType=INTEGER},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="pos != null">
#{pos,jdbcType=DOUBLE},
</if>
<if test="createUser != null">
#{createUser,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestPlanNodeExample" resultType="java.lang.Long">
select count(*) from test_plan_node
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update test_plan_node
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.parentId != null">
parent_id = #{record.parentId,jdbcType=VARCHAR},
</if>
<if test="record.level != null">
`level` = #{record.level,jdbcType=INTEGER},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.pos != null">
pos = #{record.pos,jdbcType=DOUBLE},
</if>
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update test_plan_node
set id = #{record.id,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
parent_id = #{record.parentId,jdbcType=VARCHAR},
`level` = #{record.level,jdbcType=INTEGER},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
pos = #{record.pos,jdbcType=DOUBLE},
create_user = #{record.createUser,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.TestPlanNode">
update test_plan_node
<set>
<if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR},
</if>
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
</if>
<if test="parentId != null">
parent_id = #{parentId,jdbcType=VARCHAR},
</if>
<if test="level != null">
`level` = #{level,jdbcType=INTEGER},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="pos != null">
pos = #{pos,jdbcType=DOUBLE},
</if>
<if test="createUser != null">
create_user = #{createUser,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestPlanNode">
update test_plan_node
set project_id = #{projectId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
parent_id = #{parentId,jdbcType=VARCHAR},
`level` = #{level,jdbcType=INTEGER},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
pos = #{pos,jdbcType=DOUBLE},
create_user = #{createUser,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -2,10 +2,10 @@ package io.metersphere.base.mapper.ext;
import io.metersphere.dto.TestCaseReviewDTO;
import io.metersphere.dto.TestReviewDTOWithMetric;
import org.apache.ibatis.annotations.Param;
import io.metersphere.request.testreview.QueryTestReviewRequest;
import io.metersphere.request.testreview.QueryCaseReviewRequest;
import io.metersphere.request.testreview.QueryTestReviewRequest;
import io.metersphere.request.testreview.ReviewBatchMoveRequest;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
@ -28,4 +28,6 @@ public interface ExtTestCaseReviewMapper {
int checkIsHave(@Param("reviewId") String reviewId, @Param("projectIds") Set<String> projectIds);
String selectStatusById(@Param("id") String id);
void batchUpdateNode(@Param("request") ReviewBatchMoveRequest request);
}

View File

@ -8,8 +8,8 @@
test_case_review.tags,
test_case_review.create_time, test_case_review.update_time, test_case_review.end_time,
test_case_review.review_pass_rule,
test_case_review.description, user.name as creatorName, project.name as projectName, test_case_review.project_id
test_case_review.description, user.name as creatorName, project.name as projectName, test_case_review.project_id,
test_case_review.node_id, test_case_review.node_path
from test_case_review
join project on project.id = test_case_review.project_id
left join user on test_case_review.creator = user.id
@ -80,6 +80,12 @@
<property name="object" value="${condition}.creator"/>
</include>
</if>
<if test="${condition}.moduleIds != null">
and test_case_review.node_id
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.moduleIds"/>
</include>
</if>
</sql>
<sql id="queryWhereCondition">
@ -103,6 +109,18 @@
<if test="request.projectId != null">
and test_case_review.project_id = #{request.projectId}
</if>
<if test="request.nodeIds != null and request.nodeIds.size() > 0">
and test_case_review.node_id in
<foreach collection="request.nodeIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<if test="request.unSelectIds != null and request.unSelectIds.size > 0">
and test_case_review.id not in
<foreach collection="request.unSelectIds" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
<include refid="filter"/>
</where>
</sql>
@ -203,4 +221,12 @@
WHERE
id = #{id}
</select>
<update id="batchUpdateNode" parameterType="io.metersphere.request.testreview.ReviewBatchMoveRequest">
update test_case_review set node_id = #{request.nodeId}, node_path = #{request.nodePath}
where id in
<foreach collection="request.ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</update>
</mapper>

View File

@ -0,0 +1,18 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.dto.TestCaseReviewNodeDTO;
import io.metersphere.request.testreview.QueryCaseReviewRequest;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtTestCaseReviewNodeMapper {
List<TestCaseReviewNodeDTO> getCountNodes(@Param("request") QueryCaseReviewRequest request);
List<TestCaseReviewNodeDTO> getNodeTreeByProjectId(@Param("projectId") String projectId);
TestCaseReviewNodeDTO getNode(String id);
void updatePos(String id, Double pos);
}

View File

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestCaseReviewNodeMapper">
<select id="getCountNodes" resultType="io.metersphere.dto.TestCaseReviewNodeDTO">
select tcrn.id, count(*) as caseNum
from test_case_review
left join test_case_review_node tcrn on test_case_review.node_id = tcrn.id
left join project on tcrn.project_id = project.id
<include refid="queryWhereCondition"/>
group by tcrn.id
</select>
<select id="getNodeTreeByProjectId" resultType="io.metersphere.dto.TestCaseReviewNodeDTO">
select
id, project_id, `name`, parent_id, `level`, create_time, update_time, pos, create_user
from test_case_review_node tcrn
where tcrn.project_id = #{projectId}
order by pos
</select>
<select id="getNode" resultType="io.metersphere.dto.TestCaseReviewNodeDTO">
select
id, project_id, `name`, parent_id, `level`, create_time, update_time, pos, create_user
from test_case_review_node
where id = #{id}
</select>
<update id="updatePos">
update test_case_review_node set pos = #{pos} where id = #{id}
</update>
<sql id="combine">
<if test='${condition}.name != null and (${name} == null or ${name} == "")'>
and test_case_review.name
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test="${condition}.createTime != null">
and test_case_review.create_time
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<if test="${condition}.updateTime != null">
and test_case_review.update_time
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.updateTime"/>
</include>
</if>
<if test="${condition}.endTime != null">
and test_case_review.end_time
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.endTime"/>
</include>
</if>
<if test="${condition}.status != null">
and test_case_review.status
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.status"/>
</include>
</if>
<if test='${condition}.tags != null and ${objectKey}.operator == "not like"'>
and (test_case_review.tags is null or test_case_review.tags
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.tags"/>
</include>
)
</if>
<if test='${condition}.tags != null and ${objectKey}.operator == "like"'>
and test_case_review.tags
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.tags"/>
</include>
</if>
<if test="${condition}.followPeople != null">
and test_case_review.id in (
select review_id from test_case_review_follow where follow_id
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.followPeople"/>
</include>
)
</if>
<if test="${condition}.creator != null">
and test_case_review.create_user
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.creator"/>
</include>
</if>
<if test="${condition}.moduleIds != null">
and test_case_review.node_id
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.moduleIds"/>
</include>
</if>
</sql>
<sql id="queryWhereCondition">
<where>
<if test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
<property name="name" value="request.name"/>
<property name="objectKey" value="request.combine.tags"/>
</include>
</if>
<if test="request.name != null">
and test_case_review.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.reviewerId != null">
and test_case_review.id in (select test_case_review_test_case_users.review_id from test_case_review_test_case_users where test_case_review_test_case_users.user_id = #{request.reviewerId})
</if>
<if test="request.workspaceId != null">
AND project.workspace_id = #{request.workspaceId}
</if>
<if test="request.projectId != null">
and test_case_review.project_id = #{request.projectId}
</if>
<if test="request.nodeIds != null and request.nodeIds.size() > 0">
and test_case_review.node_id in
<foreach collection="request.nodeIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<include refid="filter"/>
</where>
</sql>
<sql id="filter">
<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=='stage'">
and test_case_review.stage in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</when>
<when test="key=='status'">
and test_case_review.status in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</when>
<when test="key=='creator_name'">
and test_case_review.creator in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</when>
</choose>
</if>
</foreach>
</if>
</sql>
</mapper>

View File

@ -5,6 +5,7 @@ import io.metersphere.dto.ParamsDTO;
import io.metersphere.dto.TestPlanDTOWithMetric;
import io.metersphere.plan.dto.TestPlanDTO;
import io.metersphere.plan.request.QueryTestPlanRequest;
import io.metersphere.plan.request.TestPlanBatchMoveRequest;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
@ -57,4 +58,6 @@ public interface ExtTestPlanMapper {
void updateStatusAndActStartTimeAndSetActEndTimeNullById(@Param("testPlanId") String testPlanId, @Param("actStartTime") long actStartTime, @Param("status") String status);
long countExecutingReportCount(String testPlanId);
void batchUpdateNode(@Param("request") TestPlanBatchMoveRequest request);
}

View File

@ -146,6 +146,12 @@
</include>
)
</if>
<if test="${condition}.moduleIds != null">
and test_plan.node_id
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.moduleIds"/>
</include>
</if>
</sql>
<select id="list" resultType="io.metersphere.dto.TestPlanDTOWithMetric"
@ -181,6 +187,18 @@
<if test="request.id != null">
AND test_plan.id = #{request.id}
</if>
<if test="request.nodeIds != null and request.nodeIds.size() > 0">
and test_plan.node_id in
<foreach collection="request.nodeIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<if test="request.unSelectIds != null and request.unSelectIds.size > 0">
and test_plan.id not in
<foreach collection="request.unSelectIds" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
<include refid="filter"/>
<if test="(request.filters == null or request.filters.size() == 0) and request.byFilter != true ">
and test_plan.status != 'Archived'
@ -472,4 +490,12 @@
WHERE test_plan_id = #{0}
AND status = 'RUNNING'
</select>
<update id="batchUpdateNode" parameterType="io.metersphere.plan.request.TestPlanBatchMoveRequest">
update test_plan set node_id = #{request.nodeId}, node_path = #{request.nodePath}
where id in
<foreach collection="request.ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</update>
</mapper>

View File

@ -0,0 +1,18 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.dto.TestPlanNodeDTO;
import io.metersphere.plan.request.QueryTestPlanRequest;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtTestPlanNodeMapper {
List<TestPlanNodeDTO> getCountNodes(@Param("request") QueryTestPlanRequest request);
List<TestPlanNodeDTO> getNodeTreeByProjectId(@Param("projectId") String projectId);
TestPlanNodeDTO getNode(String id);
void updatePos(String id, Double pos);
}

View File

@ -0,0 +1,271 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestPlanNodeMapper">
<select id="getCountNodes" resultType="io.metersphere.dto.TestPlanNodeDTO">
select tpn.id, count(*) as caseNum
from test_plan
left join test_plan_node tpn on test_plan.node_id = tpn.id
left join project on tpn.project_id = project.id
<include refid="queryWhereCondition"/>
group by tpn.id
</select>
<select id="getNodeTreeByProjectId" resultType="io.metersphere.dto.TestPlanNodeDTO">
select
id, project_id, `name`, parent_id, `level`, create_time, update_time, pos, create_user
from test_plan_node tpn
where tpn.project_id = #{projectId}
order by pos
</select>
<select id="getNode" resultType="io.metersphere.dto.TestPlanNodeDTO">
select
id, project_id, `name`, parent_id, `level`, create_time, update_time, pos, create_user
from test_plan_node
where id = #{id}
</select>
<update id="updatePos">
update test_plan_node set pos = #{pos} where id = #{id}
</update>
<resultMap id="BaseResultMap" type="io.metersphere.plan.dto.TestPlanDTO"
extends="io.metersphere.base.mapper.TestPlanMapper.BaseResultMap">
<result column="project_name" property="projectName" jdbcType="VARCHAR"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
</resultMap>
<sql id="condition">
<choose>
<when test='${object}.operator == "like"'>
like CONCAT('%', #{${object}.value},'%')
</when>
<when test='${object}.operator == "not like"'>
not like CONCAT('%', #{${object}.value},'%')
</when>
<when test='${object}.operator == "in"'>
in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "not in"'>
not in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "between"'>
between #{${object}.value[0]} and #{${object}.value[1]}
</when>
<when test='${object}.operator == "gt"'>
&gt; #{${object}.value}
</when>
<when test='${object}.operator == "lt"'>
&lt; #{${object}.value}
</when>
<when test='${object}.operator == "ge"'>
&gt;= #{${object}.value}
</when>
<when test='${object}.operator == "le"'>
&lt;= #{${object}.value}
</when>
<when test='${object}.operator == "current user"'>
= '${@io.metersphere.commons.utils.SessionUtils@getUserId()}'
</when>
<otherwise>
= #{${object}.value}
</otherwise>
</choose>
</sql>
<sql id="combine">
<if test='${condition}.name != null and (${name} == null or ${name} == "")'>
and test_plan.name
<include refid="condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test="${condition}.followPeople != null">
and test_plan.id in (
select test_plan_id from test_plan_follow where follow_id
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.followPeople"/>
</include>
)
</if>
<if test="${condition}.projectName != null">
and project.name
<include refid="condition">
<property name="object" value="${condition}.projectName"/>
</include>
</if>
<if test="${condition}.createTime != null">
and test_plan.create_time
<include refid="condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<if test="${condition}.actualStartTime != null">
and test_plan.actual_start_time
<include refid="condition">
<property name="object" value="${condition}.actualStartTime"/>
</include>
</if>
<if test="${condition}.actualEndTime != null">
and test_plan.actual_end_time
<include refid="condition">
<property name="object" value="${condition}.actualEndTime"/>
</include>
</if>
<if test="${condition}.planStartTime != null">
and test_plan.planned_start_time
<include refid="condition">
<property name="object" value="${condition}.planStartTime"/>
</include>
</if>
<if test="${condition}.planEndTime != null">
and test_plan.planned_end_time
<include refid="condition">
<property name="object" value="${condition}.planEndTime"/>
</include>
</if>
<if test="${condition}.status != null">
and test_plan.status
<include refid="condition">
<property name="object" value="${condition}.status"/>
</include>
</if>
<if test="${condition}.updateTime != null">
and test_plan.update_time
<include refid="condition">
<property name="object" value="${condition}.updateTime"/>
</include>
</if>
<if test="${condition}.stage != null">
and test_plan.stage
<include refid="condition">
<property name="object" value="${condition}.stage"/>
</include>
</if>
<if test="${condition}.creator != null">
and test_plan.creator
<include refid="condition">
<property name="object" value="${condition}.creator"/>
</include>
</if>
<if test='${condition}.tags != null and ${objectKey}.operator == "not like"'>
and (test_plan.tags is null or test_plan.tags
<include refid="condition">
<property name="object" value="${condition}.tags"/>
</include>
)
</if>
<if test='${condition}.tags != null and ${objectKey}.operator == "like"'>
and test_plan.tags
<include refid="condition">
<property name="object" value="${condition}.tags"/>
</include>
</if>
<if test="${condition}.principal != null">
and test_plan.id in (SELECT test_plan_id FROM test_plan_principal WHERE principal_id
<include refid="condition">
<property name="object" value="${condition}.principal"/>
</include>
)
</if>
</sql>
<sql id="queryWhereCondition">
<where>
<if test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
<property name="name" value="request.name"/>
<property name="objectKey" value="request.combine.tags"/>
</include>
</if>
<if test="request.name != null">
and test_plan.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.workspaceId != null">
AND test_plan.workspace_id = #{request.workspaceId}
</if>
<if test="request.projectId != null">
AND test_plan.project_id = #{request.projectId}
</if>
<if test="request.id != null">
AND test_plan.id = #{request.id}
</if>
<include refid="filter"/>
<if test="(request.filters == null or request.filters.size() == 0) and request.byFilter != true ">
and test_plan.status != 'Archived'
</if>
</where>
</sql>
<sql id="filter">
<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=='status'">
<choose>
<when test="request.executorOrPrincipal != null">
and (( test_plan_principal.principal_id =
'${@io.metersphere.commons.utils.SessionUtils@getUserId()}' and
test_plan.status in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
)
or
(test_plan_test_case.executor =
'${@io.metersphere.commons.utils.SessionUtils@getUserId()}' and
test_plan_test_case.status in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
))
and (test_plan.status is null or test_plan.status != 'Trash')
and (test_case.status is null or test_case.status != 'Trash')
</when>
<otherwise>
and test_plan.status in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</otherwise>
</choose>
</when>
<otherwise>
<choose>
<when test="key=='stage'">
and test_plan.stage in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</when>
<when test="key=='create_user'">
and test_plan.creator in
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.filterInWrapper"/>
</when>
<when test="key=='schedule_status'">
and
<foreach collection="values" item="value" separator="or" open="(" close=")">
<if test="value == 'OPEN'">
schedule.`enable` = 1
</if>
<if test="value == 'SHUT'">
schedule.`enable` = 0
</if>
<if test="value == 'NOTSET' ">
schedule.id is null
</if>
</foreach>
</when>
</choose>
and test_plan.status != 'Archived'
</otherwise>
</choose>
</if>
<if test="(values == null or values.size() == 0) and request.filters.get('status') == null">
and test_plan.status != 'Archived'
</if>
</foreach>
</if>
</sql>
</mapper>

View File

@ -12,19 +12,20 @@ import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.TestCaseReviewDTO;
import io.metersphere.dto.TestReviewDTOWithMetric;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.log.annotation.MsRequestLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.request.testreview.*;
import io.metersphere.service.*;
import io.metersphere.dto.TestCaseReviewDTO;
import io.metersphere.dto.TestReviewDTOWithMetric;
import io.metersphere.service.TestCaseReviewService;
import io.metersphere.service.TestReviewProjectService;
import io.metersphere.service.wapper.CheckPermissionService;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
import java.util.UUID;
@ -160,4 +161,10 @@ public class TestCaseReviewController {
public void editTestFollows(@RequestBody SaveTestCaseReviewRequest testCaseReview) {
testCaseReviewService.editCaseRevieweFollow(testCaseReview);
}
@PostMapping("/batch/move")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_PLAN_READ_EDIT})
public void batchMove(@RequestBody ReviewBatchMoveRequest request) {
testCaseReviewService.batchMove(request);
}
}

View File

@ -0,0 +1,71 @@
package io.metersphere.controller;
import io.metersphere.base.domain.TestCaseReviewNode;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.dto.TestCaseReviewNodeDTO;
import io.metersphere.request.testreview.DragReviewNodeRequest;
import io.metersphere.request.testreview.QueryCaseReviewRequest;
import io.metersphere.service.BaseCheckPermissionService;
import io.metersphere.service.TestCaseReviewNodeService;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
/**
* @author song-cc-rock
*/
@RestController
@RequestMapping("/case/review/node")
public class TestCaseReviewNodeController {
@Resource
private TestCaseReviewNodeService testCaseReviewNodeService;
@Resource
private BaseCheckPermissionService baseCheckPermissionService;
@PostMapping("/list/{projectId}")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_REVIEW_READ})
public List<TestCaseReviewNodeDTO> getNodeByCondition(@PathVariable String projectId, @RequestBody(required = false) QueryCaseReviewRequest request) {
// 高级搜索所属模块搜索时, 切换项目时需替换projectId为参数中切换项目
if (request != null && request.getProjectId() != null) {
projectId = request.getProjectId();
}
baseCheckPermissionService.checkProjectOwner(projectId);
return testCaseReviewNodeService.getNodeTreeByProjectId(projectId,
Optional.ofNullable(request).orElse(new QueryCaseReviewRequest()));
}
@PostMapping("/add")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_REVIEW_READ_EDIT})
public String addNode(@RequestBody TestCaseReviewNode node) {
return testCaseReviewNodeService.addNode(node);
}
@PostMapping("/edit")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_REVIEW_READ_EDIT})
public int editNode(@RequestBody TestCaseReviewNode node) {
return testCaseReviewNodeService.editNode(node);
}
@PostMapping("/delete")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_REVIEW_READ_DELETE})
public int deleteNode(@RequestBody List<String> nodeIds) {
return testCaseReviewNodeService.deleteNode(nodeIds);
}
@PostMapping("/drag")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_REVIEW_READ_EDIT})
public void dragNode(@RequestBody DragReviewNodeRequest node) {
testCaseReviewNodeService.dragNode(node);
}
@PostMapping("/pos")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_REVIEW_READ_EDIT})
public void treeSort(@RequestBody List<String> ids) {
testCaseReviewNodeService.sort(ids);
}
}

View File

@ -17,10 +17,7 @@ import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.plan.dto.TestCaseReportStatusResultDTO;
import io.metersphere.plan.dto.TestPlanDTO;
import io.metersphere.plan.dto.TestPlanReportDataStruct;
import io.metersphere.plan.request.AddTestPlanRequest;
import io.metersphere.plan.request.BatchOperateRequest;
import io.metersphere.plan.request.QueryTestPlanRequest;
import io.metersphere.plan.request.ScheduleInfoRequest;
import io.metersphere.plan.request.*;
import io.metersphere.plan.request.api.TestPlanRunRequest;
import io.metersphere.plan.request.function.PlanCaseRelevanceRequest;
import io.metersphere.plan.request.function.TestCaseRelevanceRequest;
@ -449,4 +446,10 @@ public class TestPlanController {
public void resetStatus(@PathVariable String planId) {
testPlanService.resetStatus(planId);
}
@PostMapping("/batch/move")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_PLAN_READ_EDIT})
public void batchMove(@RequestBody TestPlanBatchMoveRequest request) {
testPlanService.batchMove(request);
}
}

View File

@ -0,0 +1,71 @@
package io.metersphere.controller;
import io.metersphere.base.domain.TestPlanNode;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.dto.TestPlanNodeDTO;
import io.metersphere.plan.request.QueryTestPlanRequest;
import io.metersphere.request.testplan.DragPlanNodeRequest;
import io.metersphere.service.BaseCheckPermissionService;
import io.metersphere.service.TestPlanNodeService;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
/**
* @author song-cc-rock
*/
@RestController
@RequestMapping("/plan/node")
public class TestPlanNodeController {
@Resource
private TestPlanNodeService testPlanNodeService;
@Resource
private BaseCheckPermissionService baseCheckPermissionService;
@PostMapping("/list/{projectId}")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_CASE_READ})
public List<TestPlanNodeDTO> getNodeByCondition(@PathVariable String projectId, @RequestBody(required = false) QueryTestPlanRequest request) {
// 高级搜索所属模块搜索时, 切换项目时需替换projectId为参数中切换项目
if (request != null && request.getProjectId() != null) {
projectId = request.getProjectId();
}
baseCheckPermissionService.checkProjectOwner(projectId);
return testPlanNodeService.getNodeTreeByProjectId(projectId,
Optional.ofNullable(request).orElse(new QueryTestPlanRequest()));
}
@PostMapping("/add")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_PLAN_READ_EDIT})
public String addNode(@RequestBody TestPlanNode node) {
return testPlanNodeService.addNode(node);
}
@PostMapping("/edit")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_PLAN_READ_EDIT})
public int editNode(@RequestBody TestPlanNode node) {
return testPlanNodeService.editNode(node);
}
@PostMapping("/delete")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_PLAN_READ_DELETE})
public int deleteNode(@RequestBody List<String> nodeIds) {
return testPlanNodeService.deleteNode(nodeIds);
}
@PostMapping("/drag")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_PLAN_READ_EDIT})
public void dragNode(@RequestBody DragPlanNodeRequest node) {
testPlanNodeService.dragNode(node);
}
@PostMapping("/pos")
@RequiresPermissions(value = {PermissionConstants.PROJECT_TRACK_PLAN_READ_EDIT})
public void treeSort(@RequestBody List<String> ids) {
testPlanNodeService.sort(ids);
}
}

View File

@ -0,0 +1,7 @@
package io.metersphere.dto;
import lombok.Data;
@Data
public class TestCaseReviewNodeDTO extends TreeNodeDTO<TestCaseReviewNodeDTO> {
}

View File

@ -0,0 +1,7 @@
package io.metersphere.dto;
import lombok.Data;
@Data
public class TestPlanNodeDTO extends TreeNodeDTO<TestPlanNodeDTO> {
}

View File

@ -2,10 +2,11 @@ package io.metersphere.listener;
import io.metersphere.base.domain.Project;
import io.metersphere.base.mapper.ProjectMapper;
import io.metersphere.base.mapper.ext.ExtModuleNodeMapper;
import io.metersphere.commons.constants.KafkaTopicConstants;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.service.TestCaseNodeService;
import io.metersphere.service.TestCaseReviewNodeService;
import io.metersphere.service.TestPlanNodeService;
import jakarta.annotation.Resource;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.kafka.annotation.KafkaListener;
@ -15,18 +16,20 @@ import org.springframework.stereotype.Component;
public class ProjectCreatedListener {
public static final String CONSUME_ID = "test_track_project-created";
@Resource
private ExtModuleNodeMapper extModuleNodeMapper;
@Resource
private ProjectMapper projectMapper;
@Resource
private TestCaseNodeService testCaseNodeService;
@Resource
private TestCaseReviewNodeService testCaseReviewNodeService;
@Resource
private TestPlanNodeService testPlanNodeService;
@KafkaListener(id = CONSUME_ID, topics = KafkaTopicConstants.PROJECT_CREATED_TOPIC, groupId = "${spring.application.name}")
public void consume(ConsumerRecord<?, String> record) {
String projectId = record.value();
LogUtil.info("track service consume project_create message, project id: " + projectId);
this.initProjectDefaultNode(projectId);
initProjectDefaultNode(projectId);
}
private void initProjectDefaultNode(String projectId) {
@ -36,5 +39,9 @@ public class ProjectCreatedListener {
}
// 创建功能用例默认模块
testCaseNodeService.createDefaultNode(projectId);
// 创建评审默认模块
testCaseReviewNodeService.createDefaultNode(projectId);
// 创建计划默认模块
testPlanNodeService.createDefaultNode(projectId);
}
}

View File

@ -5,6 +5,7 @@ import io.metersphere.request.OrderRequest;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.util.List;
import java.util.Map;
@ -12,6 +13,9 @@ import java.util.Map;
@Setter
public class QueryTestPlanRequest extends TestPlan {
@Serial
private static final long serialVersionUID = -9022330526265056106L;
private boolean recent = false;
private List<String> planIds;
@ -43,4 +47,11 @@ public class QueryTestPlanRequest extends TestPlan {
private boolean byFilter;
private List<String> filterStatus;
/**
* @since 2.10.10 添加模块树条件, 批量移动条件
*/
private List<String> nodeIds;
private Boolean selectAll;
private List<String> unSelectIds;
}

View File

@ -0,0 +1,15 @@
package io.metersphere.plan.request;
import lombok.Data;
import java.util.List;
@Data
public class TestPlanBatchMoveRequest {
private List<String> ids;
private QueryTestPlanRequest condition;
private String projectId;
private String nodeId;
private String nodePath;
}

View File

@ -26,10 +26,7 @@ import io.metersphere.plan.constant.ApiReportStatus;
import io.metersphere.plan.dto.TestPlanDTO;
import io.metersphere.plan.dto.*;
import io.metersphere.plan.job.TestPlanTestJob;
import io.metersphere.plan.request.AddTestPlanRequest;
import io.metersphere.plan.request.BatchOperateRequest;
import io.metersphere.plan.request.QueryTestPlanRequest;
import io.metersphere.plan.request.ScheduleInfoRequest;
import io.metersphere.plan.request.*;
import io.metersphere.plan.request.api.ApiPlanReportRequest;
import io.metersphere.plan.request.api.RunScenarioRequest;
import io.metersphere.plan.request.api.SchedulePlanScenarioExecuteRequest;
@ -2308,6 +2305,17 @@ public class TestPlanService {
}
}
public void batchMove(TestPlanBatchMoveRequest request) {
if (request.getCondition().getSelectAll()) {
// 全选则重新设置MoveIds
request.getCondition().setProjectId(request.getProjectId());
List<TestPlanDTOWithMetric> movePlans = listTestPlan(request.getCondition());
List<String> ids = movePlans.stream().map(TestPlanDTOWithMetric::getId).collect(Collectors.toList());
request.setIds(ids);
}
extTestPlanMapper.batchUpdateNode(request);
}
public void deleteTestPlanBatch(BatchOperateRequest request) {
List<String> ids = request.getIds();
if (request.isSelectAll()) {

View File

@ -0,0 +1,21 @@
package io.metersphere.request.testplan;
import io.metersphere.base.domain.TestPlanNode;
import io.metersphere.dto.TestPlanNodeDTO;
import lombok.Data;
import java.io.Serial;
import java.util.List;
/**
* @author song-cc-rock
*/
@Data
public class DragPlanNodeRequest extends TestPlanNode {
@Serial
private static final long serialVersionUID = -2663513817971996721L;
private List<String> nodeIds;
private TestPlanNodeDTO nodeTree;
}

View File

@ -0,0 +1,21 @@
package io.metersphere.request.testreview;
import io.metersphere.base.domain.TestCaseReviewNode;
import io.metersphere.dto.TestCaseReviewNodeDTO;
import lombok.Data;
import java.io.Serial;
import java.util.List;
/**
* @author song-cc-rock
*/
@Data
public class DragReviewNodeRequest extends TestCaseReviewNode {
@Serial
private static final long serialVersionUID = -2663513817971996721L;
private List<String> nodeIds;
private TestCaseReviewNodeDTO nodeTree;
}

View File

@ -46,4 +46,10 @@ public class QueryCaseReviewRequest extends BaseQueryRequest {
private String status;
private Boolean isDel;
/**
* @since 2.10.10 添加模块树条件, 批量移动条件
*/
private Boolean selectAll;
private List<String> unSelectIds;
}

View File

@ -0,0 +1,15 @@
package io.metersphere.request.testreview;
import lombok.Data;
import java.util.List;
@Data
public class ReviewBatchMoveRequest {
private List<String> ids;
private QueryCaseReviewRequest condition;
private String projectId;
private String nodeId;
private String nodePath;
}

View File

@ -0,0 +1,303 @@
package io.metersphere.service;
import com.google.common.util.concurrent.AtomicDouble;
import io.metersphere.base.domain.TestCaseReviewExample;
import io.metersphere.base.domain.TestCaseReviewNode;
import io.metersphere.base.domain.TestCaseReviewNodeExample;
import io.metersphere.base.mapper.TestCaseReviewMapper;
import io.metersphere.base.mapper.TestCaseReviewNodeMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseReviewNodeMapper;
import io.metersphere.commons.constants.ProjectModuleDefaultNodeEnum;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.TestCaseReviewNodeDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.request.testreview.DragReviewNodeRequest;
import io.metersphere.request.testreview.QueryCaseReviewRequest;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author song-cc-rock
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class TestCaseReviewNodeService extends NodeTreeService<TestCaseReviewNodeDTO>{
@Resource
private RedissonClient redissonClient;
@Resource
private TestCaseReviewNodeMapper testCaseReviewNodeMapper;
@Resource
private ExtTestCaseReviewNodeMapper extTestCaseReviewNodeMapper;
@Resource
private TestCaseReviewMapper testCaseReviewMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
private static final String TEST_CASE_REVIEW_DEFAULT_NODE_CREATE_KEY = "TEST_CASE_REVIEW:DEFAULT_NODE:CREATE";
public TestCaseReviewNodeService() {
super(TestCaseReviewNodeDTO.class);
}
public List<TestCaseReviewNodeDTO> getNodeTreeByProjectId(String projectId, QueryCaseReviewRequest request) {
checkDefaultNode(projectId);
request.setNodeIds(null);
List<TestCaseReviewNodeDTO> countNodes = extTestCaseReviewNodeMapper.getCountNodes(request);
List<TestCaseReviewNodeDTO> testCaseNodes = extTestCaseReviewNodeMapper.getNodeTreeByProjectId(projectId);
return getNodeTrees(testCaseNodes, getCountMap(countNodes));
}
public String addNode(TestCaseReviewNode node) {
validateNode(node);
node.setCreateTime(System.currentTimeMillis());
node.setUpdateTime(System.currentTimeMillis());
if (StringUtils.isBlank(node.getId())) {
node.setId(UUID.randomUUID().toString());
}
node.setCreateUser(SessionUtils.getUserId());
double pos = getNextLevelPos(node.getProjectId(), node.getLevel(), node.getParentId());
node.setPos(pos);
testCaseReviewNodeMapper.insertSelective(node);
return node.getId();
}
public int editNode(TestCaseReviewNode request) {
request.setUpdateTime(System.currentTimeMillis());
return testCaseReviewNodeMapper.updateByPrimaryKeySelective(request);
}
public int deleteNode(List<String> nodeIds) {
if (CollectionUtils.isEmpty(nodeIds)) {
return 1;
}
// 删除所有节点下的评审
TestCaseReviewExample example = new TestCaseReviewExample();
example.createCriteria().andNodeIdIn(nodeIds);
testCaseReviewMapper.deleteByExample(example);
// 删除节点
TestCaseReviewNodeExample testCaseNodeExample = new TestCaseReviewNodeExample();
testCaseNodeExample.createCriteria().andIdIn(nodeIds);
return testCaseReviewNodeMapper.deleteByExample(testCaseNodeExample);
}
public void dragNode(DragReviewNodeRequest request) {
checkTestCaseNodeExist(request);
List<String> nodeIds = request.getNodeIds();
TestCaseReviewNodeDTO nodeTree = request.getNodeTree();
if (nodeTree == null) {
return;
}
List<TestCaseReviewNode> updateNodes = new ArrayList<>();
buildUpdateTestCase(nodeTree, updateNodes, "0", 1);
updateNodes = updateNodes.stream()
.filter(item -> nodeIds.contains(item.getId()))
.collect(Collectors.toList());
batchUpdateTestCaseNode(updateNodes);
}
@Override
public String insertNode(String nodeName, String pId, String projectId, Integer level, String path) {
TestCaseReviewNode reviewNode = new TestCaseReviewNode();
reviewNode.setName(nodeName.trim());
reviewNode.setParentId(pId);
reviewNode.setProjectId(projectId);
reviewNode.setCreateTime(System.currentTimeMillis());
reviewNode.setUpdateTime(System.currentTimeMillis());
reviewNode.setLevel(level);
reviewNode.setCreateUser(SessionUtils.getUserId());
reviewNode.setId(UUID.randomUUID().toString());
double pos = getNextLevelPos(projectId, level, pId);
reviewNode.setPos(pos);
testCaseReviewNodeMapper.insert(reviewNode);
return reviewNode.getId();
}
@Override
public TestCaseReviewNodeDTO getNode(String id) {
return extTestCaseReviewNodeMapper.getNode(id);
}
@Override
public void updatePos(String id, Double pos) {
extTestCaseReviewNodeMapper.updatePos(id, pos);
}
@Override
protected void refreshPos(String projectId, int level, String parentId) {
List<TestCaseReviewNode> nodes = getPos(projectId, level, parentId, "pos asc");
if (!CollectionUtils.isEmpty(nodes)) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestCaseReviewNodeMapper batchMapper = sqlSession.getMapper(TestCaseReviewNodeMapper.class);
AtomicDouble pos = new AtomicDouble(DEFAULT_POS);
nodes.forEach((node) -> {
node.setPos(pos.getAndAdd(DEFAULT_POS));
batchMapper.updateByPrimaryKey(node);
});
sqlSession.flushStatements();
if (sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
}
private void validateNode(TestCaseReviewNode node) {
checkTestCaseReviewNodeExist(node);
}
private void checkTestCaseReviewNodeExist(TestCaseReviewNode node) {
if (node.getName() != null) {
TestCaseReviewNodeExample example = new TestCaseReviewNodeExample();
TestCaseReviewNodeExample.Criteria criteria = example.createCriteria();
criteria.andNameEqualTo(node.getName())
.andProjectIdEqualTo(node.getProjectId());
if (StringUtils.isNotBlank(node.getParentId())) {
criteria.andParentIdEqualTo(node.getParentId());
} else {
criteria.andLevelEqualTo(node.getLevel());
}
if (StringUtils.isNotBlank(node.getId())) {
criteria.andIdNotEqualTo(node.getId());
}
if (!testCaseReviewNodeMapper.selectByExample(example).isEmpty()) {
MSException.throwException(Translator.get("test_case_module_already_exists"));
}
}
}
private double getNextLevelPos(String projectId, int level, String parentId) {
List<TestCaseReviewNode> list = getPos(projectId, level, parentId, "pos desc");
if (!CollectionUtils.isEmpty(list) && list.get(0) != null && list.get(0).getPos() != null) {
return list.get(0).getPos() + DEFAULT_POS;
} else {
return DEFAULT_POS;
}
}
private List<TestCaseReviewNode> getPos(String projectId, int level, String parentId, String order) {
TestCaseReviewNodeExample example = new TestCaseReviewNodeExample();
TestCaseReviewNodeExample.Criteria criteria = example.createCriteria();
criteria.andProjectIdEqualTo(projectId).andLevelEqualTo(level);
if (level != 1 && StringUtils.isNotBlank(parentId)) {
criteria.andParentIdEqualTo(parentId);
}
example.setOrderByClause(order);
return testCaseReviewNodeMapper.selectByExample(example);
}
private void checkTestCaseNodeExist(TestCaseReviewNode node) {
if (node.getName() != null) {
TestCaseReviewNodeExample example = new TestCaseReviewNodeExample();
TestCaseReviewNodeExample.Criteria criteria = example.createCriteria();
criteria.andNameEqualTo(node.getName())
.andProjectIdEqualTo(node.getProjectId());
if (StringUtils.isNotBlank(node.getParentId())) {
criteria.andParentIdEqualTo(node.getParentId());
} else {
criteria.andLevelEqualTo(node.getLevel());
}
if (StringUtils.isNotBlank(node.getId())) {
criteria.andIdNotEqualTo(node.getId());
}
if (!testCaseReviewNodeMapper.selectByExample(example).isEmpty()) {
MSException.throwException(Translator.get("test_case_module_already_exists"));
}
}
}
private void batchUpdateTestCaseNode(List<TestCaseReviewNode> updateNodes) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestCaseReviewNodeMapper batchMapper = sqlSession.getMapper(TestCaseReviewNodeMapper.class);
updateNodes.forEach(batchMapper::updateByPrimaryKeySelective);
sqlSession.flushStatements();
if (sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
private void buildUpdateTestCase(TestCaseReviewNodeDTO rootNode,
List<TestCaseReviewNode> updateNodes, String pId, int level) {
if (updateNodes != null) {
TestCaseReviewNode testCaseReviewNode = new TestCaseReviewNode();
testCaseReviewNode.setId(rootNode.getId());
testCaseReviewNode.setLevel(level);
testCaseReviewNode.setParentId(pId);
updateNodes.add(testCaseReviewNode);
}
List<TestCaseReviewNodeDTO> children = rootNode.getChildren();
if (!CollectionUtils.isEmpty(children)) {
for (TestCaseReviewNodeDTO child : children) {
buildUpdateTestCase(child, updateNodes, rootNode.getId(), level + 1);
}
}
}
public void checkDefaultNode(String projectId) {
TestCaseReviewNode defaultNode = getDefaultNode(projectId);
if (defaultNode == null) {
createDefaultNode(projectId);
}
}
public TestCaseReviewNode getDefaultNode(String projectId) {
TestCaseReviewNodeExample example = new TestCaseReviewNodeExample();
example.createCriteria().andProjectIdEqualTo(projectId).andNameEqualTo(ProjectModuleDefaultNodeEnum.DEFAULT_NODE.getNodeName()).andParentIdIsNull();
List<TestCaseReviewNode> defaultNodes = testCaseReviewNodeMapper.selectByExample(example);
if (CollectionUtils.isEmpty(defaultNodes)) {
return null;
} else {
return defaultNodes.get(0);
}
}
public void createDefaultNode(String projectId) {
// 加锁, 防止并发创建
RLock lock = redissonClient.getLock(TEST_CASE_REVIEW_DEFAULT_NODE_CREATE_KEY + ":" + projectId);
if (lock.tryLock()) {
try {
// 双重检查, 判断是否已经存在默认节点
if (getDefaultNode(projectId) != null) {
return;
}
// 创建默认节点, 只执行一次
TestCaseReviewNode defaultNode = new TestCaseReviewNode();
defaultNode.setId(UUID.randomUUID().toString());
defaultNode.setCreateUser(SessionUtils.getUserId());
defaultNode.setName(ProjectModuleDefaultNodeEnum.DEFAULT_NODE.getNodeName());
defaultNode.setPos(1.0);
defaultNode.setLevel(1);
defaultNode.setCreateTime(System.currentTimeMillis());
defaultNode.setUpdateTime(System.currentTimeMillis());
defaultNode.setProjectId(projectId);
testCaseReviewNodeMapper.insert(defaultNode);
} catch (Exception e) {
LogUtil.error(e);
} finally {
lock.unlock();
}
}
}
}

View File

@ -2,7 +2,6 @@ package io.metersphere.service;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.BaseProjectMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseReviewMapper;
import io.metersphere.base.mapper.ext.ExtTestReviewCaseMapper;
@ -67,8 +66,6 @@ public class TestCaseReviewService {
@Resource
ExtTestReviewCaseMapper extTestReviewCaseMapper;
@Resource
BaseProjectMapper baseProjectMapper;
@Resource
BaseUserService baseUserService;
@Resource
TestCaseMapper testCaseMapper;
@ -407,6 +404,17 @@ public class TestCaseReviewService {
}
public void batchMove(ReviewBatchMoveRequest request) {
if (request.getCondition().getSelectAll()) {
// 全选则重新设置MoveIds
request.getCondition().setProjectId(request.getProjectId());
List<TestCaseReviewDTO> moveReviews = listCaseReview(request.getCondition());
List<String> ids = moveReviews.stream().map(TestCaseReviewDTO::getId).collect(Collectors.toList());
request.setIds(ids);
}
extTestCaseReviewMapper.batchUpdateNode(request);
}
private void checkCaseReviewExist(TestCaseReview testCaseReview) {
if (testCaseReview.getName() != null) {
TestCaseReviewExample example = new TestCaseReviewExample();

View File

@ -0,0 +1,302 @@
package io.metersphere.service;
import com.google.common.util.concurrent.AtomicDouble;
import io.metersphere.base.domain.TestPlanExample;
import io.metersphere.base.domain.TestPlanNode;
import io.metersphere.base.domain.TestPlanNodeExample;
import io.metersphere.base.mapper.TestPlanMapper;
import io.metersphere.base.mapper.TestPlanNodeMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanNodeMapper;
import io.metersphere.commons.constants.ProjectModuleDefaultNodeEnum;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.TestPlanNodeDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.plan.request.QueryTestPlanRequest;
import io.metersphere.request.testplan.DragPlanNodeRequest;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author song-cc-rock
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanNodeService extends NodeTreeService<TestPlanNodeDTO>{
@Resource
private TestPlanNodeMapper testPlanNodeMapper;
@Resource
private ExtTestPlanNodeMapper extTestPlanNodeMapper;
@Resource
private TestPlanMapper testPlanMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private RedissonClient redissonClient;
private static final String TEST_PLAN_NODE_CREATE_KEY = "TEST_PLAN:DEFAULT_NODE:CREATE";
public TestPlanNodeService() {
super(TestPlanNodeDTO.class);
}
public List<TestPlanNodeDTO> getNodeTreeByProjectId(String projectId, QueryTestPlanRequest request) {
checkDefaultNode(projectId);
request.setNodeIds(null);
List<TestPlanNodeDTO> countNodes = extTestPlanNodeMapper.getCountNodes(request);
List<TestPlanNodeDTO> testCaseNodes = extTestPlanNodeMapper.getNodeTreeByProjectId(projectId);
return getNodeTrees(testCaseNodes, getCountMap(countNodes));
}
public String addNode(TestPlanNode node) {
validateNode(node);
node.setCreateTime(System.currentTimeMillis());
node.setUpdateTime(System.currentTimeMillis());
if (StringUtils.isBlank(node.getId())) {
node.setId(UUID.randomUUID().toString());
}
node.setCreateUser(SessionUtils.getUserId());
double pos = getNextLevelPos(node.getProjectId(), node.getLevel(), node.getParentId());
node.setPos(pos);
testPlanNodeMapper.insertSelective(node);
return node.getId();
}
public int editNode(TestPlanNode request) {
request.setUpdateTime(System.currentTimeMillis());
return testPlanNodeMapper.updateByPrimaryKeySelective(request);
}
public int deleteNode(List<String> nodeIds) {
if (CollectionUtils.isEmpty(nodeIds)) {
return 1;
}
// 删除所有节点下的计划
TestPlanExample example = new TestPlanExample();
example.createCriteria().andNodeIdIn(nodeIds);
testPlanMapper.deleteByExample(example);
// 删除节点
TestPlanNodeExample planNodeExample = new TestPlanNodeExample();
planNodeExample.createCriteria().andIdIn(nodeIds);
return testPlanNodeMapper.deleteByExample(planNodeExample);
}
public void dragNode(DragPlanNodeRequest request) {
checkTestCaseNodeExist(request);
List<String> nodeIds = request.getNodeIds();
TestPlanNodeDTO nodeTree = request.getNodeTree();
if (nodeTree == null) {
return;
}
List<TestPlanNode> updateNodes = new ArrayList<>();
buildUpdateTestCase(nodeTree, updateNodes, "0", 1);
updateNodes = updateNodes.stream()
.filter(item -> nodeIds.contains(item.getId()))
.collect(Collectors.toList());
batchUpdateTestCaseNode(updateNodes);
}
@Override
public String insertNode(String nodeName, String pId, String projectId, Integer level, String path) {
TestPlanNode planNode = new TestPlanNode();
planNode.setName(nodeName.trim());
planNode.setParentId(pId);
planNode.setProjectId(projectId);
planNode.setCreateTime(System.currentTimeMillis());
planNode.setUpdateTime(System.currentTimeMillis());
planNode.setLevel(level);
planNode.setCreateUser(SessionUtils.getUserId());
planNode.setId(UUID.randomUUID().toString());
double pos = getNextLevelPos(projectId, level, pId);
planNode.setPos(pos);
testPlanNodeMapper.insert(planNode);
return planNode.getId();
}
@Override
public TestPlanNodeDTO getNode(String id) {
return extTestPlanNodeMapper.getNode(id);
}
@Override
public void updatePos(String id, Double pos) {
extTestPlanNodeMapper.updatePos(id, pos);
}
@Override
protected void refreshPos(String projectId, int level, String parentId) {
List<TestPlanNode> nodes = getPos(projectId, level, parentId, "pos asc");
if (!CollectionUtils.isEmpty(nodes)) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestPlanNodeMapper batchMapper = sqlSession.getMapper(TestPlanNodeMapper.class);
AtomicDouble pos = new AtomicDouble(DEFAULT_POS);
nodes.forEach((node) -> {
node.setPos(pos.getAndAdd(DEFAULT_POS));
batchMapper.updateByPrimaryKey(node);
});
sqlSession.flushStatements();
if (sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
}
private void validateNode(TestPlanNode node) {
checkTestPlanNodeExist(node);
}
private void checkTestPlanNodeExist(TestPlanNode node) {
if (node.getName() != null) {
TestPlanNodeExample example = new TestPlanNodeExample();
TestPlanNodeExample.Criteria criteria = example.createCriteria();
criteria.andNameEqualTo(node.getName())
.andProjectIdEqualTo(node.getProjectId());
if (StringUtils.isNotBlank(node.getParentId())) {
criteria.andParentIdEqualTo(node.getParentId());
} else {
criteria.andLevelEqualTo(node.getLevel());
}
if (StringUtils.isNotBlank(node.getId())) {
criteria.andIdNotEqualTo(node.getId());
}
if (!testPlanNodeMapper.selectByExample(example).isEmpty()) {
MSException.throwException(Translator.get("test_case_module_already_exists"));
}
}
}
private double getNextLevelPos(String projectId, int level, String parentId) {
List<TestPlanNode> list = getPos(projectId, level, parentId, "pos desc");
if (!CollectionUtils.isEmpty(list) && list.get(0) != null && list.get(0).getPos() != null) {
return list.get(0).getPos() + DEFAULT_POS;
} else {
return DEFAULT_POS;
}
}
private List<TestPlanNode> getPos(String projectId, int level, String parentId, String order) {
TestPlanNodeExample example = new TestPlanNodeExample();
TestPlanNodeExample.Criteria criteria = example.createCriteria();
criteria.andProjectIdEqualTo(projectId).andLevelEqualTo(level);
if (level != 1 && StringUtils.isNotBlank(parentId)) {
criteria.andParentIdEqualTo(parentId);
}
example.setOrderByClause(order);
return testPlanNodeMapper.selectByExample(example);
}
private void checkTestCaseNodeExist(TestPlanNode node) {
if (node.getName() != null) {
TestPlanNodeExample example = new TestPlanNodeExample();
TestPlanNodeExample.Criteria criteria = example.createCriteria();
criteria.andNameEqualTo(node.getName())
.andProjectIdEqualTo(node.getProjectId());
if (StringUtils.isNotBlank(node.getParentId())) {
criteria.andParentIdEqualTo(node.getParentId());
} else {
criteria.andLevelEqualTo(node.getLevel());
}
if (StringUtils.isNotBlank(node.getId())) {
criteria.andIdNotEqualTo(node.getId());
}
if (!testPlanNodeMapper.selectByExample(example).isEmpty()) {
MSException.throwException(Translator.get("test_case_module_already_exists"));
}
}
}
private void batchUpdateTestCaseNode(List<TestPlanNode> updateNodes) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestPlanNodeMapper batchMapper = sqlSession.getMapper(TestPlanNodeMapper.class);
updateNodes.forEach(batchMapper::updateByPrimaryKeySelective);
sqlSession.flushStatements();
if (sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
private void buildUpdateTestCase(TestPlanNodeDTO rootNode,
List<TestPlanNode> updateNodes, String pId, int level) {
if (updateNodes != null) {
TestPlanNode testPlanNode = new TestPlanNode();
testPlanNode.setId(rootNode.getId());
testPlanNode.setLevel(level);
testPlanNode.setParentId(pId);
updateNodes.add(testPlanNode);
}
List<TestPlanNodeDTO> children = rootNode.getChildren();
if (!CollectionUtils.isEmpty(children)) {
for (TestPlanNodeDTO child : children) {
buildUpdateTestCase(child, updateNodes, rootNode.getId(), level + 1);
}
}
}
public void checkDefaultNode(String projectId) {
TestPlanNode defaultNode = getDefaultNode(projectId);
if (defaultNode == null) {
createDefaultNode(projectId);
}
}
public TestPlanNode getDefaultNode(String projectId) {
TestPlanNodeExample example = new TestPlanNodeExample();
example.createCriteria().andProjectIdEqualTo(projectId).andNameEqualTo(ProjectModuleDefaultNodeEnum.DEFAULT_NODE.getNodeName()).andParentIdIsNull();
List<TestPlanNode> defaultNodes = testPlanNodeMapper.selectByExample(example);
if (CollectionUtils.isEmpty(defaultNodes)) {
return null;
} else {
return defaultNodes.get(0);
}
}
public void createDefaultNode(String projectId) {
// 加锁, 防止并发创建
RLock lock = redissonClient.getLock(TEST_PLAN_NODE_CREATE_KEY + ":" + projectId);
if (lock.tryLock()) {
try {
// 双重检查, 判断是否已经存在默认节点
if (getDefaultNode(projectId) != null) {
return;
}
// 创建默认节点, 只执行一次
TestPlanNode defaultNode = new TestPlanNode();
defaultNode.setId(UUID.randomUUID().toString());
defaultNode.setCreateUser(SessionUtils.getUserId());
defaultNode.setName(ProjectModuleDefaultNodeEnum.DEFAULT_NODE.getNodeName());
defaultNode.setPos(1.0);
defaultNode.setLevel(1);
defaultNode.setCreateTime(System.currentTimeMillis());
defaultNode.setUpdateTime(System.currentTimeMillis());
defaultNode.setProjectId(projectId);
testPlanNodeMapper.insert(defaultNode);
} catch (Exception e) {
LogUtil.error(e);
} finally {
lock.unlock();
}
}
}
}

View File

@ -0,0 +1,25 @@
SET SESSION innodb_lock_wait_timeout = 7200;
-- 评审表添加模块相关字段
ALTER TABLE test_case_review ADD `node_id` varchar(50) NOT NULL COMMENT 'Node ID';
ALTER TABLE test_case_review ADD `node_path` varchar(999) NOT NULL COMMENT 'Node Path';
-- 评审模块表
CREATE TABLE IF NOT EXISTS test_case_review_node (
`id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Test case review node ID',
`project_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Project ID this node belongs to',
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Node name',
`parent_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'Parent node ID',
`level` int NULL DEFAULT 1 COMMENT 'Node level',
`create_time` bigint NOT NULL COMMENT 'Create timestamp',
`update_time` bigint NOT NULL COMMENT 'Update timestamp',
`pos` double NULL DEFAULT NULL,
`create_user` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `test_case_node_project_id_index`(`project_id`) USING BTREE,
INDEX `test_case_node_parent_id_index`(`parent_id`) USING BTREE,
INDEX `test_case_node_name_index`(`name`) USING BTREE,
INDEX `test_case_node_level_index`(`level`) USING BTREE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE utf8mb4_general_ci;
SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -0,0 +1,25 @@
SET SESSION innodb_lock_wait_timeout = 7200;
-- 测试计划表添加模块相关字段
ALTER TABLE test_plan ADD `node_id` varchar(50) NOT NULL COMMENT 'Node ID';
ALTER TABLE test_plan ADD `node_path` varchar(999) NOT NULL COMMENT 'Node Path';
-- 测试计划模块表
CREATE TABLE IF NOT EXISTS test_plan_node (
`id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Test case review node ID',
`project_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Project ID this node belongs to',
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Node name',
`parent_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'Parent node ID',
`level` int NULL DEFAULT 1 COMMENT 'Node level',
`create_time` bigint NOT NULL COMMENT 'Create timestamp',
`update_time` bigint NOT NULL COMMENT 'Update timestamp',
`pos` double NULL DEFAULT NULL,
`create_user` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `test_case_node_project_id_index`(`project_id`) USING BTREE,
INDEX `test_case_node_parent_id_index`(`parent_id`) USING BTREE,
INDEX `test_case_node_name_index`(`name`) USING BTREE,
INDEX `test_case_node_level_index`(`level`) USING BTREE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE utf8mb4_general_ci;
SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -0,0 +1,10 @@
SET SESSION innodb_lock_wait_timeout = 7200;
-- 1. 初始化所有项目的未规划评审模块
INSERT INTO test_case_review_node SELECT UUID(), id, '未规划模块', NULL, 1, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP(), 1, 'admin' FROM project;
-- 2. 将历史评审移入到未规划评审模块
UPDATE test_case_review tcr SET node_id = (SELECT IF(COUNT(id) > 0, id, '') FROM test_case_review_node WHERE project_id = tcr.project_id AND name = '未规划模块'),
node_path = '';
SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -0,0 +1,10 @@
SET SESSION innodb_lock_wait_timeout = 7200;
-- 1. 初始化所有项目的未规划计划模块
INSERT INTO test_plan_node SELECT UUID(), id, '未规划模块', NULL, 1, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP(), 1, 'admin' FROM project;
-- 2. 将历史计划移入到未规划计划模块
UPDATE test_plan tcr SET node_id = (SELECT IF(COUNT(id) > 0, id, '') FROM test_plan_node WHERE project_id = tcr.project_id AND name = '未规划模块'),
node_path = '';
SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -399,3 +399,7 @@ export function reportSocket(reportId) {
export function testPlanLoadCaseEditStatus(planId) {
return post(BASE_URL + `edit/status/${planId}`, new Promise(() => {}));
}
export function testPlanBatchMove(param) {
return post(BASE_URL + `batch/move`, param, new Promise(() => {}));
}

View File

@ -0,0 +1,27 @@
import {post} from "metersphere-frontend/src/plugins/request";
const BASE_URL = "/case/review/node/";
export function getTestCaseReviewNodes(projectId, param) {
return post(BASE_URL + "list/" + projectId, param);
}
export function testCaseReviewNodeAdd(param) {
return post(BASE_URL + 'add', param);
}
export function testCaseReviewNodeEdit(param) {
return post(BASE_URL + 'edit', param);
}
export function testCaseReviewNodeDelete(param) {
return post(BASE_URL + 'delete', param);
}
export function testCaseReviewNodeDrag(param) {
return post(BASE_URL + 'drag', param);
}
export function testCaseReviewNodePos(param) {
return post(BASE_URL + 'pos', param);
}

View File

@ -0,0 +1,27 @@
import {post} from "metersphere-frontend/src/plugins/request";
const BASE_URL = "/plan/node/";
export function getTestPlanNodes(projectId, param) {
return post(BASE_URL + "list/" + projectId, param);
}
export function testPlanNodeAdd(param) {
return post(BASE_URL + 'add', param);
}
export function testPlanNodeEdit(param) {
return post(BASE_URL + 'edit', param);
}
export function testPlanNodeDelete(param) {
return post(BASE_URL + 'delete', param);
}
export function testPlanNodeDrag(param) {
return post(BASE_URL + 'drag', param);
}
export function testPlanNodePos(param) {
return post(BASE_URL + 'pos', param);
}

View File

@ -1,4 +1,4 @@
import {post, get} from "metersphere-frontend/src/plugins/request";
import {get, post} from "metersphere-frontend/src/plugins/request";
import {buildPagePath} from "@/api/base-network";
const BASE_URL = '/test/case/review/';
@ -87,3 +87,7 @@ export function getTestCaseReviewsCasePage(currentPage, pageSize, param) {
export function getRelateTest(type, testCaseId) {
return get("/" + type + "/get/" + testCaseId);
}
export function batchMoveCaseReview(param) {
return post("/test/case/review/batch/move", param);
}

View File

@ -0,0 +1,225 @@
<template>
<div v-if="dialogVisible" class="batch-move" v-loading="result.loading">
<el-dialog
:visible.sync="dialogVisible"
:before-close="close"
:destroy-on-close="true"
width="40%"
append-to-body
:close-on-click-modal="false">
<el-tooltip :content="contentTitle" placement="top" width="width">
<span class="tooltipStyle" v-if="selectCount > 1">"{{ moveCaseTitle|ellipsis }}"{{selectCount}}{{moveType}} 移动到</span>
<span class="tooltipStyle" v-else>"{{ moveCaseTitle|ellipsis }}" 移动到</span>
</el-tooltip>
<el-input :placeholder="$t('test_track.module.search_by_name')" v-model="filterText" size="small" prefix-icon="el-icon-search"/>
<el-scrollbar style="margin-top: 12px; border: 1px solid #DEE0E3; border-radius: 4px;">
<div style="max-height: 336px; padding: 8px 16px 8px 16px;">
<el-tree
class="filter-tree node-tree"
:data="treeNodes"
node-key="id"
:filter-node-method="filterNode"
:expand-on-click-node="false"
highlight-current
style="overflow: auto"
@node-click="nodeClick"
ref="tree"
>
<template v-slot:default="{node}">
<span>
<span class="node-icon" style="position: relative; top: 3px">
<svg-icon :icon-class="node.isCurrent ? 'icon_folder_selected' : 'icon_folder'"/>
</span>
<span class="node-title">{{node.label}}</span>
</span>
</template>
</el-tree>
</div>
</el-scrollbar>
<template v-slot:footer>
<el-button @click="close" size="small">{{ $t('commons.cancel') }}</el-button>
<el-button v-prevent-re-click :type="!currentKey ? 'info' : 'primary'" @click="save"
@keydown.enter.native.prevent size="small" :disabled="!currentKey || btnDisable" style="margin-left: 12px">{{ $t('commons.confirm') }}</el-button>
</template>
</el-dialog>
</div>
</template>
<script>
import MsDialogFooter from "metersphere-frontend/src/components/MsDialogFooter";
export default {
name: "ReviewOrPlanBatchMove",
components: {
MsDialogFooter
},
data() {
return {
moveCaseTitle: '',
moveType: '',
treeNodes: [],
selectIds: [],
selectCount: 0,
selectNode: {},
dialogVisible: false,
currentKey: "",
moduleOptions: [],
filterText: "",
result: {},
contentTitle:"",
btnDisable: false
}
},
props: {
publicEnable: {
type: Boolean,
default: false,
},
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods: {
open(caseTitle, treeNodes, selectIds, selectCount, moduleOptions, moveType) {
this.moveCaseTitle = caseTitle;
this.dialogVisible = true;
this.treeNodes = treeNodes;
this.selectIds = selectIds;
this.selectCount = selectCount;
this.moduleOptions = moduleOptions;
this.moveType = moveType;
this.contentTitle = this.$t('test_track.case.resource_batch_move_to', [this.moveCaseTitle, this.selectCount, this.moveType])
},
save() {
this.btnDisable = true;
if (!this.currentKey) {
this.$warning(this.$t('test_track.case.input_module'), false);
this.btnDisable = false;
return;
}
let param = {};
param.nodeId = this.currentKey;
if (this.moduleOptions) {
this.moduleOptions.forEach(item => {
if (item.id === this.currentKey) {
param.nodePath = item.path;
}
});
}
param.ids = this.selectIds;
this.$emit('moveSave', param);
},
refresh() {
this.$emit("refresh");
},
close() {
this.filterText = "";
this.dialogVisible = false;
this.selectNode = {};
this.currentKey = "";
},
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
nodeClick() {
this.currentKey = this.$refs.tree.getCurrentKey();
}
},
filters: {
//使...
ellipsis(value) {
if (!value) {
return '';
}
if (value.length > 25) {
return value.slice(0, 25) + '...';
}
return value;
}
}
}
</script>
<style scoped>
.node-title {
width: 0;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 1 auto;
padding: 0 5px;
overflow: hidden;
}
:deep(.el-tree-node__expand-icon.el-icon-caret-right:before) {
color: #646A73;
font-size: 15px;
}
:deep(.is-leaf.el-tree-node__expand-icon.el-icon-caret-right:before) {
color: transparent;
}
:deep(.el-tree-node__content) {
width: auto;
height: 40px;
border-radius: 4px;
}
:deep(.el-tree-node__content:hover){
background-color: rgba(31, 35, 41, 0.1);
border-radius: 4px;
}
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
background-color: rgba(120, 56, 135, 0.1);
}
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content .node-title) {
color: #783887;
font-weight: 500;
}
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content .node-title:after) {
color: #783887;
font-weight: 500;
}
.svg-icon {
width: 1.2em;
height: 1.2em;
}
:deep(.el-button--small span) {
font-family: 'PingFang SC';
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 22px;
position: relative;
top: -5px;
}
.el-button--small {
min-width: 80px;
height: 32px;
border-radius: 4px;
}
.tooltipStyle{
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
white-space:nowrap;
width:100%;
height:34px;
display: inline-block;
title:content;
font-size: large;
}
</style>

View File

@ -0,0 +1,188 @@
<template>
<div>
<slot name="header"></slot>
<ms-node-tree
v-loading="loading"
:tree-nodes="treeNodes"
:type="'edit'"
:name-limit="100"
:delete-permission="['PROJECT_TRACK_REVIEW:READ+DELETE']"
:add-permission="['PROJECT_TRACK_REVIEW:READ+CREATE']"
:update-permission="['PROJECT_TRACK_REVIEW:READ+EDIT']"
default-label="未规划模块"
local-suffix="ui_module"
:hide-node-operator="hideNodeOperator"
@add="add"
@edit="edit"
@drag="drag"
@remove="remove"
@nodeSelectEvent="nodeChange"
@refresh="list"
@filter="filter"
ref="nodeTree">
<template v-slot:header>
<ms-search-bar
:show-operator="showOperator"
:condition="condition"/>
</template>
</ms-node-tree>
</div>
</template>
<script>
import MsNodeTree from "metersphere-frontend/src/components/new-ui/MsNodeTree";
import MsSearchBar from "metersphere-frontend/src/components/new-ui/MsSearchBar";
import {buildNodePath, buildTree} from "metersphere-frontend/src/model/NodeTree";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {
getTestCaseReviewNodes,
testCaseReviewNodeAdd,
testCaseReviewNodeDelete,
testCaseReviewNodeDrag,
testCaseReviewNodeEdit,
testCaseReviewNodePos
} from "@/api/test-case-review-node";
import {useStore} from "@/store";
export default {
name: "TestCaseReviewNodeTree",
components: {
MsSearchBar,
MsNodeTree,
},
data() {
return {
defaultProps: {
children: "children",
label: "label"
},
loading: false,
treeNodes: [],
condition: {
filterText: ""
},
currentNode: {}
};
},
props: {
type: {
type: String,
default: "view"
},
showOperator: Boolean,
reviewCondition: Object,
hideNodeOperator: {
type: Boolean,
default: false
},
},
watch: {
treeNodes() {
this.$emit('setTreeNodes', this.treeNodes);
},
'condition.filterText'() {
this.filter();
}
},
computed: {
projectId() {
return getCurrentProjectID();
}
},
methods: {
filter() {
this.$refs.nodeTree.filter(this.condition.filterText);
},
refresh() {
this.$emit("refreshTable");
},
list() {
if (this.projectId) {
this.loading = true;
getTestCaseReviewNodes(this.projectId, this.reviewCondition)
.then(r => {
this.loading = false;
this.treeNodes = r.data;
this.treeNodes.forEach(node => {
buildTree(node, {path: ''});
});
this.setModuleOptions();
if (this.$refs.nodeTree) {
this.$refs.nodeTree.filter(this.condition.filterText);
}
if (this.currentNode && this.currentNode.data) {
this.justSetCurrentKey();
} else {
this.$refs.nodeTree.setCurrentKey('root');
}
});
}
},
setModuleOptions() {
let moduleOptions = [];
this.treeNodes.forEach(node => {
buildNodePath(node, {path: ''}, moduleOptions);
});
useStore().testCaseReviewModuleOptions = moduleOptions;
},
nodeChange(node, nodeIds, pNodes) {
this.currentNode = node;
// , Tree
this.$emit("nodeSelectEvent", node, node.data.id === 'root' ? [] : nodeIds, pNodes);
},
justSetCurrentKey() {
if (this.$refs.nodeTree) {
this.$refs.nodeTree.justSetCurrentKey(this.currentNode.data.id)
}
},
increase(id) {
this.$refs.nodeTree.increase(id);
},
decrease(id) {
this.$refs.nodeTree.decrease(id);
},
edit(param) {
param.projectId = this.projectId;
testCaseReviewNodeEdit(param)
.then(() => {
this.list();
this.$emit("refreshTable");
});
},
add(param) {
if (param.length > 10) {
this.$error(this.$t('commons.delete_success'), false);
}
param.projectId = this.projectId;
testCaseReviewNodeAdd(param)
.then(() => {
this.$success(this.$t("test_track.module.success_create"), false);
this.list();
this.$emit("refreshTable");
}).catch(() => {
this.list();
this.$emit("refreshTable");
});
},
remove(nodeIds) {
testCaseReviewNodeDelete(nodeIds)
.then(() => {
this.list();
this.$emit("refreshTable");
this.$success(this.$t('commons.delete_success'), false);
});
},
drag(param, list) {
testCaseReviewNodeDrag(param)
.then(() => {
testCaseReviewNodePos(list)
this.list();
this.$emit("refreshTable");
}).catch(() => {
this.list();
this.$emit("refreshTable");
});
}
}
};
</script>

View File

@ -0,0 +1,188 @@
<template>
<div>
<slot name="header"></slot>
<ms-node-tree
v-loading="loading"
:tree-nodes="treeNodes"
:type="'edit'"
:name-limit="100"
:delete-permission="['PROJECT_TRACK_PLAN:READ+DELETE']"
:add-permission="['PROJECT_TRACK_PLAN:READ+CREATE']"
:update-permission="['PROJECT_TRACK_PLAN:READ+EDIT']"
default-label="未规划模块"
local-suffix="ui_module"
:hide-node-operator="hideNodeOperator"
@add="add"
@edit="edit"
@drag="drag"
@remove="remove"
@nodeSelectEvent="nodeChange"
@refresh="list"
@filter="filter"
ref="nodeTree">
<template v-slot:header>
<ms-search-bar
:show-operator="showOperator"
:condition="condition"/>
</template>
</ms-node-tree>
</div>
</template>
<script>
import MsNodeTree from "metersphere-frontend/src/components/new-ui/MsNodeTree";
import MsSearchBar from "metersphere-frontend/src/components/new-ui/MsSearchBar";
import {buildNodePath, buildTree} from "metersphere-frontend/src/model/NodeTree";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {
getTestPlanNodes,
testPlanNodeAdd,
testPlanNodeDelete,
testPlanNodeDrag,
testPlanNodeEdit,
testPlanNodePos
} from "@/api/test-plan-node";
import {useStore} from "@/store";
export default {
name: "TestPlanNodeTree",
components: {
MsSearchBar,
MsNodeTree,
},
data() {
return {
defaultProps: {
children: "children",
label: "label"
},
loading: false,
treeNodes: [],
condition: {
filterText: ""
},
currentNode: {}
};
},
props: {
type: {
type: String,
default: "view"
},
showOperator: Boolean,
planCondition: Object,
hideNodeOperator: {
type: Boolean,
default: false
},
},
watch: {
treeNodes() {
this.$emit('setTreeNodes', this.treeNodes);
},
'condition.filterText'() {
this.filter();
}
},
computed: {
projectId() {
return getCurrentProjectID();
}
},
methods: {
filter() {
this.$refs.nodeTree.filter(this.condition.filterText);
},
refresh() {
this.$emit("refreshTable");
},
list() {
if (this.projectId) {
this.loading = true;
getTestPlanNodes(this.projectId, this.planCondition)
.then(r => {
this.loading = false;
this.treeNodes = r.data;
this.treeNodes.forEach(node => {
buildTree(node, {path: ''});
});
this.setModuleOptions();
if (this.$refs.nodeTree) {
this.$refs.nodeTree.filter(this.condition.filterText);
}
if (this.currentNode && this.currentNode.data) {
this.justSetCurrentKey();
} else {
this.$refs.nodeTree.setCurrentKey('root');
}
});
}
},
setModuleOptions() {
let moduleOptions = [];
this.treeNodes.forEach(node => {
buildNodePath(node, {path: ''}, moduleOptions);
});
useStore().testPlanModuleOptions = moduleOptions;
},
nodeChange(node, nodeIds, pNodes) {
this.currentNode = node;
// , Tree
this.$emit("nodeSelectEvent", node, node.data.id === 'root' ? [] : nodeIds, pNodes);
},
justSetCurrentKey() {
if (this.$refs.nodeTree) {
this.$refs.nodeTree.justSetCurrentKey(this.currentNode.data.id)
}
},
increase(id) {
this.$refs.nodeTree.increase(id);
},
decrease(id) {
this.$refs.nodeTree.decrease(id);
},
edit(param) {
param.projectId = this.projectId;
testPlanNodeEdit(param)
.then(() => {
this.list();
this.$emit("refreshTable");
});
},
add(param) {
if (param.length > 10) {
this.$error(this.$t('commons.delete_success'), false);
}
param.projectId = this.projectId;
testPlanNodeAdd(param)
.then(() => {
this.$success(this.$t("test_track.module.success_create"), false);
this.list();
this.$emit("refreshTable");
}).catch(() => {
this.list();
this.$emit("refreshTable");
});
},
remove(nodeIds) {
testPlanNodeDelete(nodeIds)
.then(() => {
this.list();
this.$emit("refreshTable");
this.$success(this.$t('commons.delete_success'), false);
});
},
drag(param, list) {
testPlanNodeDrag(param)
.then(() => {
testPlanNodePos(list)
this.list();
this.$emit("refreshTable");
}).catch(() => {
this.list();
this.$emit("refreshTable");
});
}
}
};
</script>

View File

@ -1,32 +1,49 @@
<template>
<ms-container>
<ms-aside-container :enable-remember-width="true" max-width="600px" :enable-aside-hidden.sync="enableAsideHidden" class="plan-aside">
<test-plan-node-tree ref="planNodeTree" :plan-condition="condition" @setTreeNodes="setTreeNodes"
@nodeSelectEvent="handleCaseNodeSelect" @refreshTable="refreshTestPlanList"/>
</ms-aside-container>
<ms-main-container>
<test-plan-list
@openTestPlanEditDialog="openTestPlanEditDialog"
@testPlanEdit="openTestPlanEditDialog"
@refreshTree="refreshTreeByCondition"
@setCondition="setCondition"
:current-node="currentNode"
:current-select-nodes="currentSelectNodes"
:tree-nodes="treeNodes"
ref="testPlanList"/>
</ms-main-container>
<test-plan-edit ref="testPlanEditDialog" @refresh="refreshTestPlanList"/>
</ms-container>
</template>
<script>
import TestPlanNodeTree from "@/business/module/TestPlanNodeTree.vue";
import TestPlanList from './components/TestPlanList';
import TestPlanEdit from './components/TestPlanEdit';
import MsContainer from "metersphere-frontend/src/components/MsContainer";
import MsAsideContainer from "metersphere-frontend/src/components/MsAsideContainer";
import MsMainContainer from "metersphere-frontend/src/components/MsMainContainer";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import TestCaseReviewList from "@/business/review/components/TestCaseReviewList.vue";
export default {
name: "TestPlan",
components: {MsMainContainer, MsContainer, TestPlanList, TestPlanEdit},
components: {
TestCaseReviewList,
TestPlanNodeTree, MsMainContainer, MsAsideContainer, MsContainer, TestPlanList, TestPlanEdit},
data() {
return {};
return {
condition: {},
currentNode: null,
currentSelectNodes: [],
enableAsideHidden: true,
treeNodes: [],
};
},
computed: {
projectId() {
@ -48,20 +65,55 @@ export default {
}
this.openTestPlanEditDialog();
this.$router.push('/track/plan/all');
} else if (to.path.indexOf("/track/plan/all") >= 0) {
//
this.currentNode = null;
this.currentSelectNodes = [];
this.$refs.planNodeTree.currentNode = {};
}
}
},
methods: {
openTestPlanEditDialog(data) {
this.$refs.testPlanEditDialog.openTestPlanEditDialog(data);
setTreeNodes(data) {
this.treeNodes = data;
},
refreshTestPlanList() {
this.$refs.testPlanList.initTableData();
setCondition(data) {
this.condition = data;
},
openTestPlanEditDialog(data) {
this.$refs.testPlanEditDialog.openTestPlanEditDialog(data, this.currentNode);
},
refreshTestPlanList(nodeIds) {
this.$refs.testPlanList.condition = {};
this.$refs.testPlanList.initTableData(nodeIds ? nodeIds : this.currentSelectNodes);
},
refreshTreeByCondition() {
this.$refs.planNodeTree.list();
},
handleCaseNodeSelect(node, nodeIds, pNodes) {
this.currentNode = node;
this.currentSelectNodes = nodeIds;
this.$refs.testPlanList.initTableData(nodeIds);
}
}
};
</script>
<style scoped>
<style>
.plan-aside .hiddenBottom {
top: 300px!important;
}
.plan-aside .el-icon-arrow-left:before {
font-size: 17px;
}
.plan-aside .el-icon-arrow-right:before {
font-size: 17px;
}
.plan-aside .hiddenBottom i {
margin-left: -4px;
margin-top: 18px;
}
</style>

View File

@ -23,9 +23,20 @@
:size="itemSize" maxlength="128" show-word-limit/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('commons.tag')" :label-width="formLabelWidth" prop="tag">
<ms-input-tag :currentScenario="form" ref="tag" :size="itemSize"/>
<el-form-item prop="nodeId" :label="$t('test_track.case.module')" :label-width="formLabelWidth">
<ms-select-tree
class="plan-node-tree"
:disabled="false"
:data="treeNodes"
:obj="moduleObj"
:default-key="form.nodeId"
checkStrictly
@getValue="setModule"
size="small"
ref="moduleTree"
/>
</el-form-item>
</el-col>
</el-row>
@ -82,6 +93,14 @@
</el-row>
<!--end:xuxm增加自定义计划开始计划结束时间字段-->
<el-row type="flex" :gutter="20">
<el-col :span="12">
<el-form-item :label="$t('commons.tag')" :label-width="formLabelWidth" prop="tag">
<ms-input-tag :currentScenario="form" ref="tag" :size="itemSize"/>
</el-form-item>
</el-col>
</el-row>
<el-row type="flex" :gutter="20">
<el-col :span="12">
<el-form-item
@ -153,18 +172,19 @@
</template>
<script>
import MsSelectTree from "metersphere-frontend/src/components/select-tree/SelectTree";
import TestPlanStatusButton from "../common/TestPlanStatusButton";
import {getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token";
import {getCurrentProjectID, getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token";
import {listenGoBack, removeGoBackListener} from "metersphere-frontend/src/utils";
import MsInputTag from "metersphere-frontend/src/components/MsInputTag";
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
import {getPlanStageOption, testPlanAdd, testPlanEdit} from "@/api/remote/plan/test-plan";
import {getProjectMemberOption} from "@/business/utils/sdk-utils";
import {buildTree, getProjectMemberOption} from "@/business/utils/sdk-utils";
import {getTestPlanNodes} from "@/api/test-plan-node";
export default {
name: "TestPlanEdit",
components: {MsInstructionsIcon, TestPlanStatusButton, MsInputTag},
components: {MsInstructionsIcon, TestPlanStatusButton, MsInputTag, MsSelectTree},
data() {
return {
isStepTableAlive: true,
@ -181,13 +201,16 @@ export default {
plannedEndTime: '',
automaticStatusUpdate: false,
repeatCase: false,
follows: []
follows: [],
nodeId: '',
nodePath: ''
},
rules: {
name: [
{required: true, message: this.$t('test_track.plan.input_plan_name'), trigger: 'blur'},
{max: 128, message: this.$t('test_track.length_less_than') + '128', trigger: 'blur'}
],
nodeId: [{required: true, message: this.$t("api_test.environment.module_warning"), trigger: "change"}],
principals: [{required: true, message: this.$t('test_track.plan.input_plan_principal'), trigger: 'change'}],
stage: [{required: true, message: this.$t('test_track.plan.input_plan_stage'), trigger: 'change'}],
description: [{max: 200, message: this.$t('test_track.length_less_than') + '200', trigger: 'blur'}]
@ -195,7 +218,13 @@ export default {
formLabelWidth: "100px",
operationType: '',
principalOptions: [],
stageOption: []
stageOption: [],
defaultNode: null,
treeNodes: null,
moduleObj: {
id: "id",
label: "name",
}
};
},
created() {
@ -205,14 +234,67 @@ export default {
.then((r) => {
this.stageOption = r.data;
});
this.getNodeTrees();
},
computed: {
projectId() {
return getCurrentProjectID();
}
},
methods: {
getNodeTrees() {
getTestPlanNodes(this.projectId, {})
.then(r => {
let treeNodes = r.data;
treeNodes.forEach(node => {
buildTree(node, {path: ''});
});
this.treeNodes = treeNodes;
this.setDefaultModule();
});
},
setDefaultModule() {
if (this.defaultNode == null) {
this.setUnplannedModule(this.treeNodes);
} else {
this.form.nodeId = this.defaultNode.data.id;
let node = this.findTreeNode(this.treeNodes);
if (node) {
this.form.nodePath = node.path;
} else {
//
this.setUnplannedModule(this.treeNodes);
}
}
},
findTreeNode(nodeArray) {
for (let i = 0; i < nodeArray.length; i++) {
let node = nodeArray[i];
if (node.id === this.form.nodeId) {
return node;
} else {
if (node.children && node.children.length > 0) {
let findNode = this.findTreeNode(node.children);
if (findNode != null) {
return findNode;
}
}
}
}
},
setUnplannedModule(treeNodes) {
// ID
this.form.nodeId = treeNodes[0].id;
this.form.nodePath = treeNodes[0].path;
},
reload() {
this.isStepTableAlive = false;
this.$nextTick(() => (this.isStepTableAlive = true));
},
openTestPlanEditDialog(testPlan) {
openTestPlanEditDialog(testPlan, selectDefaultNode) {
this.resetForm();
this.defaultNode = selectDefaultNode;
this.getNodeTrees();
this.setPrincipalOptions();
this.operationType = 'add';
if (testPlan) {
@ -351,9 +433,17 @@ export default {
this.form.status = null;
this.form.plannedStartTime = null;
this.form.plannedEndTime = null;
this.form.nodeId = '';
this.form.nodePath = '';
return true;
});
}
},
setModule(id, data) {
if (data) {
this.form.nodeId = id;
this.form.nodePath = data.path;
}
}
}
}

View File

@ -209,6 +209,17 @@
>
</ms-table-column>
<ms-table-column
prop="nodePath"
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.case.module')"
min-width="150px">
<template v-slot:default="scope">
<span>{{ nodePathMap.get(scope.row.nodeId) }}</span>
</template>
</ms-table-column>
<ms-tags-column :field="item" :fields-width="fieldsWidth"/>
<ms-table-column
@ -462,6 +473,8 @@
<ms-dialog-footer @cancel="closeExecute" @confirm="handleRunBatch"/>
</template>
</el-dialog>
<review-or-plan-batch-move @refresh="refresh" @moveSave="moveSave" ref="testReviewBatchMove"/>
</el-card>
</template>
@ -496,6 +509,7 @@ import MsTaskCenter from "metersphere-frontend/src/components/task/TaskCenter";
import {
batchDeletePlan,
getPlanStageOption,
testPlanBatchMove,
testPlanCopy,
testPlanDelete,
testPlanEdit,
@ -507,7 +521,7 @@ import {
testPlanRun,
testPlanRunBatch,
testPlanRunSave,
testPlanUpdateScheduleEnable,
testPlanUpdateScheduleEnable
} from "@/api/remote/plan/test-plan";
import MsTableColumn from "metersphere-frontend/src/components/table/MsTableColumn";
import MsTable from "metersphere-frontend/src/components/table/MsTable";
@ -515,10 +529,14 @@ import MsTestPlanScheduleBatchSwitch from "@/business/plan/components/ScheduleBa
import MsTagsColumn from "metersphere-frontend/src/components/table/MsTagsColumn";
import {getProjectMemberUserFilter} from "@/api/user";
import TestPlanReportReview from "@/business/report/components/TestPlanReportReview";
import {mapState} from "pinia";
import {useStore} from "@/store";
import ReviewOrPlanBatchMove from "@/business/case/components/ReviewOrPlanBatchMove.vue";
export default {
name: "TestPlanList",
components: {
ReviewOrPlanBatchMove,
MsTagsColumn,
TestPlanReportReview,
MsTag,
@ -606,6 +624,11 @@ export default {
handleClick: this.handleBatchSwitch,
permissions: ["PROJECT_TRACK_PLAN:READ+SCHEDULE"],
},
{
name: this.$t('test_track.case.batch_move_case'),
handleClick: this.handleBatchMove,
permissions: ['PROJECT_TRACK_PLAN:READ+EDIT']
},
{
name: this.$t("api_test.automation.batch_execute"),
handleClick: this.handleBatchExecute,
@ -674,7 +697,48 @@ export default {
});
this.initTableData();
},
computed: {
...mapState(useStore, {
moduleOptions: 'testPlanModuleOptions',
}),
nodePathMap() {
let map = new Map();
if (this.moduleOptions) {
this.moduleOptions.forEach((item) => {
map.set(item.id, item.path);
});
}
return map;
}
},
props: {
treeNodes: {
type: Array
},
currentNode: {
type: Object
},
currentSelectNodes: {
type: Array
}
},
methods: {
moveSave(param) {
param.condition = this.condition;
param.projectId = this.projectId;
testPlanBatchMove(param)
.then(() => {
this.$refs.testReviewBatchMove.btnDisable = false;
this.$success(this.$t('commons.save_success'), false);
this.$refs.testReviewBatchMove.close();
this.refresh();
});
},
handleBatchMove() {
let batchSelectCount = this.$refs.testPlanLitTable.selectDataCounts;
let firstSelectRow = this.$refs.testPlanLitTable.selectRows.values().next().value;
this.$refs.testReviewBatchMove.open(firstSelectRow.name, this.treeNodes, this.$refs.testPlanLitTable.selectIds, batchSelectCount, this.moduleOptions, '计划');
},
setAdvSearchStageOption() {
let comp = this.condition.components.find((c) => c.key === "stage");
if (comp) {
@ -696,18 +760,25 @@ export default {
this.currentPage = 1;
this.initTableData();
},
initTableData() {
initTableData(nodeIds) {
this.cardLoading = true;
this.condition.nodeIds = [];
if (this.planId) {
this.condition.planId = this.planId;
}
if (this.selectNodeIds && this.selectNodeIds.length > 0) {
this.condition.nodeIds = this.selectNodeIds;
}
if (nodeIds && Array.isArray(nodeIds) && nodeIds.length > 0) {
this.condition.nodeIds = nodeIds;
}
if (!this.projectId) {
return;
}
this.condition.projectId = getCurrentProjectID();
this.cardLoading = true;
// ,
this.$emit('setCondition', this.condition);
this.$emit('refreshTree');
testPlanList(
{pageNum: this.currentPage, pageSize: this.pageSize},
this.condition
@ -826,7 +897,7 @@ export default {
refresh() {
this.$refs.testPlanLitTable.clear();
this.$refs.testPlanLitTable.isSelectDataAll(false);
this.initTableData();
this.initTableData(this.currentSelectNodes);
},
handleBatchDelete() {
this.$confirm(

View File

@ -1,21 +1,31 @@
<template>
<ms-container>
<ms-aside-container :enable-remember-width="true" max-width="600px" :enable-aside-hidden.sync="enableAsideHidden" class="review-aside">
<test-case-review-node-tree ref="reviewNodeTree" :review-condition="condition" @setTreeNodes="setTreeNodes"
@nodeSelectEvent="handleCaseNodeSelect" @refreshTable="refreshCaseReviewList"/>
</ms-aside-container>
<ms-main-container>
<test-case-review-list
@openCaseReviewEditDialog="openCaseReviewEditDialog"
@caseReviewEdit="openCaseReviewEditDialog"
@refreshTree="refreshTreeByCondition"
@setCondition="setCondition"
:tree-nodes="treeNodes"
:current-node="currentNode"
:current-select-nodes="currentSelectNodes"
ref="caseReviewList"/>
</ms-main-container>
<test-case-review-edit ref="caseReviewEditDialog" @refresh="refreshCaseReviewList"/>
</ms-container>
</template>
<script>
import TestCaseReviewNodeTree from "@/business/module/TestCaseReviewNodeTree";
import TestCaseReviewList from "./components/TestCaseReviewList";
import TestCaseReviewEdit from "./components/TestCaseReviewEdit";
import MsAsideContainer from "metersphere-frontend/src/components/MsAsideContainer";
import MsMainContainer from "metersphere-frontend/src/components/MsMainContainer";
import MsContainer from "metersphere-frontend/src/components/MsContainer";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
@ -26,11 +36,17 @@ export default {
MsMainContainer,
MsContainer,
TestCaseReviewList,
TestCaseReviewEdit
TestCaseReviewEdit,
MsAsideContainer,
TestCaseReviewNodeTree
},
data() {
return {
condition: {},
currentNode: null,
currentSelectNodes: [],
enableAsideHidden: true,
treeNodes: []
}
},
computed: {
@ -53,21 +69,55 @@ export default {
}
this.openCaseReviewEditDialog();
this.$router.push('/track/review/all');
} else if (to.path.indexOf("/track/review/all") >= 0) {
//
this.currentNode = null;
this.currentSelectNodes = [];
this.$refs.reviewNodeTree.currentNode = {};
}
}
},
methods: {
openCaseReviewEditDialog(data) {
this.$refs.caseReviewEditDialog.openCaseReviewEditDialog(data);
setTreeNodes(data) {
this.treeNodes = data;
},
refreshCaseReviewList() {
setCondition(data) {
this.condition = data;
},
openCaseReviewEditDialog(data) {
this.$refs.caseReviewEditDialog.openCaseReviewEditDialog(data, this.currentNode);
},
refreshCaseReviewList(nodeIds) {
this.$refs.caseReviewList.condition = {};
this.$refs.caseReviewList.initTableData();
this.$refs.caseReviewList.initTableData(nodeIds ? nodeIds : this.currentSelectNodes);
},
refreshTreeByCondition() {
this.$refs.reviewNodeTree.list();
},
handleCaseNodeSelect(node, nodeIds, pNodes) {
this.currentNode = node;
this.currentSelectNodes = nodeIds;
this.$refs.caseReviewList.initTableData(nodeIds);
}
}
}
</script>
<style scoped>
<style>
.review-aside .hiddenBottom {
top: 300px!important;
}
.review-aside .el-icon-arrow-left:before {
font-size: 17px;
}
.review-aside .el-icon-arrow-right:before {
font-size: 17px;
}
.review-aside .hiddenBottom i {
margin-left: -4px;
margin-top: 18px;
}
</style>

View File

@ -9,7 +9,6 @@
width="60%">
<el-form :model="form" :rules="rules" ref="reviewForm">
<el-row>
<el-col :span="10">
<el-form-item
@ -21,8 +20,18 @@
</el-form-item>
</el-col>
<el-col :span="12" :offset="1">
<el-form-item :label="$t('commons.tag')" :label-width="formLabelWidth" prop="tag">
<ms-input-tag :currentScenario="form" ref="tag" v-if="isStepTableAlive"/>
<el-form-item prop="nodeId" :label="$t('test_track.case.module')" :label-width="formLabelWidth">
<ms-select-tree
class="review-node-tree"
:disabled="false"
:data="treeNodes"
:obj="moduleObj"
:default-key="form.nodeId"
@getValue="setModule"
checkStrictly
size="small"
ref="moduleTree"
/>
</el-form-item>
</el-col>
</el-row>
@ -48,8 +57,6 @@
</div>
</el-form-item>
</el-col>
<el-col :span="12">
</el-col>
<el-col :span="12" :offset="1">
<el-form-item :label="$t('test_track.review.end_time')" :label-width="formLabelWidth" prop="endTime">
<el-date-picker @change="endTimeChange" type="datetime" :placeholder="$t('commons.select_date')"
@ -58,8 +65,8 @@
</el-col>
</el-row>
<el-row type="flex" justify="left" style="margin-top: 10px;">
<el-col :span="19">
<el-row style="margin-top: 10px;">
<el-col :span="10">
<el-form-item :label="$t('review.review_pass_rule')" :label-width="formLabelWidth" prop="reviewPassRule">
<el-select v-model="form.reviewPassRule" default-first-option>
<el-option
@ -78,6 +85,12 @@
</div>
</el-form-item>
</el-col>
<el-col :span="12" :offset="1">
<el-form-item :label="$t('commons.tag')" :label-width="formLabelWidth" prop="tag">
<ms-input-tag :currentScenario="form" ref="tag" v-if="isStepTableAlive" class="review-tag"/>
</el-form-item>
</el-col>
</el-row>
<el-row type="flex" justify="left" style="margin-top: 10px;">
@ -126,14 +139,17 @@ import TestPlanStatusButton from "../../plan/common/TestPlanStatusButton";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {listenGoBack, removeGoBackListener} from "metersphere-frontend/src/utils"
import MsInputTag from "metersphere-frontend/src/components/new-ui/MsInputTag";
import MsSelectTree from "metersphere-frontend/src/components/select-tree/SelectTree";
import i18n from "@/i18n";
import {getMaintainer} from "@/api/project";
import {saveOrUpdateTestCaseReview} from "@/api/test-review";
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
import {getTestCaseReviewNodes} from "@/api/test-case-review-node";
import {buildTree} from "@/business/utils/sdk-utils";
export default {
name: "TestCaseReviewEdit",
components: {MsInputTag, TestPlanStatusButton, MsInstructionsIcon},
components: {MsInputTag, TestPlanStatusButton, MsInstructionsIcon, MsSelectTree},
data() {
return {
isStepTableAlive: true,
@ -147,7 +163,9 @@ export default {
description: '',
endTime: '',
followIds: [],
reviewPassRule: 'SINGLE'
reviewPassRule: 'SINGLE',
nodeId: '',
nodePath: ''
},
dbProjectIds: [],
rules: {
@ -155,6 +173,7 @@ export default {
{required: true, message: this.$t('test_track.review.input_review_name'), trigger: 'blur'},
{max: 200, message: this.$t('test_track.length_less_than') + '200', trigger: 'blur'}
],
nodeId: [{required: true, message: this.$t("api_test.environment.module_warning"), trigger: "change"}],
userIds: [{required: true, message: this.$t('test_track.review.input_reviewer'), trigger: 'change'}],
stage: [{required: true, message: this.$t('test_track.plan.input_plan_stage'), trigger: 'change'}],
description: [{max: 200, message: this.$t('test_track.length_less_than') + '200', trigger: 'blur'}],
@ -164,6 +183,12 @@ export default {
formLabelWidth: "110px",
operationType: '',
reviewerOptions: [],
treeNodes: null,
moduleObj: {
id: "id",
label: "name",
},
defaultNode: null
};
},
computed: {
@ -174,13 +199,63 @@ export default {
return this.operationType === 'edit';
}
},
created() {
this.getNodeTrees();
},
methods: {
getNodeTrees() {
getTestCaseReviewNodes(this.projectId, {})
.then(r => {
let treeNodes = r.data;
treeNodes.forEach(node => {
buildTree(node, {path: ''});
});
this.treeNodes = treeNodes;
this.setDefaultModule();
});
},
setDefaultModule() {
if (this.defaultNode == null) {
this.setUnplannedModule(this.treeNodes);
} else {
this.form.nodeId = this.defaultNode.data.id;
let node = this.findTreeNode(this.treeNodes);
if (node) {
this.form.nodePath = node.path;
} else {
//
this.setUnplannedModule(this.treeNodes);
}
}
},
findTreeNode(nodeArray) {
for (let i = 0; i < nodeArray.length; i++) {
let node = nodeArray[i];
if (node.id === this.form.nodeId) {
return node;
} else {
if (node.children && node.children.length > 0) {
let findNode = this.findTreeNode(node.children);
if (findNode != null) {
return findNode;
}
}
}
}
},
setUnplannedModule(treeNodes) {
// ID
this.form.nodeId = treeNodes[0].id;
this.form.nodePath = treeNodes[0].path;
},
reload() {
this.isStepTableAlive = false;
this.$nextTick(() => (this.isStepTableAlive = true));
},
openCaseReviewEditDialog(caseReview) {
openCaseReviewEditDialog(caseReview, selectDefaultNode) {
this.resetForm();
this.defaultNode = selectDefaultNode;
this.getNodeTrees();
this.setReviewerOptions();
this.operationType = 'save';
if (caseReview) {
@ -286,6 +361,8 @@ export default {
this.form.projectIds = [];
this.form.userIds = [];
this.form.followIds = [];
this.form.nodeId = '';
this.form.nodePath = '';
return true;
});
}
@ -306,6 +383,12 @@ export default {
return false;
}
return true;
},
setModule(id, data) {
if (data) {
this.form.nodeId = id;
this.form.nodePath = data.path;
}
}
}
}
@ -316,5 +399,19 @@ export default {
font-size: 10px;
color: #909399;
}
.review-tag {
height: 40px!important;
}
</style>
<style>
.review-node-tree input.el-input__inner {
min-height: 40px;
}
.review-tag input.tag-input.el-input {
margin-top: 9px;
}
</style>

View File

@ -7,19 +7,20 @@
</template>
<ms-table
v-loading="loading"
operator-width="220px"
row-key="id"
:data="tableData"
:condition="condition"
:total="page.total"
:page-size.sync="page.pageSize"
:batch-operators="batchOperators"
:operators="operators"
:fields.sync="fields"
:screen-height="screenHeight"
:remember-order="true"
:field-key="tableHeaderKey"
:show-select-all="false"
:enable-selection="false"
ref="testCaseReviewTable"
@order="initTableData"
@filter="search"
@handleRowClick="intoReview">
@ -42,6 +43,17 @@
:label="$t('test_track.review.review_project')"
min-width="120px"/>
<ms-table-column
prop="nodePath"
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.case.module')"
min-width="150px">
<template v-slot:default="scope">
<span>{{ nodePathMap.get(scope.row.nodeId) }}</span>
</template>
</ms-table-column>
<ms-table-column
prop="creatorName"
:field="item"
@ -112,6 +124,7 @@
:total="page.total"/>
<ms-delete-confirm :title="$t('test_track.review.delete')" @delete="_handleDelete" ref="deleteConfirm"/>
<review-or-plan-batch-move @refresh="refresh" @moveSave="moveSave" ref="testCaseReviewBatchMove"/>
</el-card>
</template>
@ -145,17 +158,21 @@ import MsUpdateTimeColumn from "metersphere-frontend/src/components/table/MsUpda
import MsTableFollowOperator from "metersphere-frontend/src/components/table/MsTableFollowOperator";
import MsTagsColumn from "metersphere-frontend/src/components/table/MsTagsColumn";
import {
batchMoveCaseReview,
deleteTestCaseReview,
editTestCaseReviewFollows,
getTestCaseReviewFollow,
getTestCaseReviewProject,
getTestCaseReviewReviewer,
testReviewList
} from "@/api/test-review";
import {mapState} from "pinia";
import {useStore} from "@/store";
import ReviewOrPlanBatchMove from "@/business/case/components/ReviewOrPlanBatchMove.vue";
export default {
name: "TestCaseReviewList",
components: {
ReviewOrPlanBatchMove,
MsTagsColumn,
MsTableFollowOperator,
MsUpdateTimeColumn,
@ -175,6 +192,7 @@ export default {
},
data() {
return {
loading: false,
page: getPageInfo(),
type: TEST_CASE_REVIEW_LIST,
headerItems: Test_Case_Review,
@ -196,6 +214,13 @@ export default {
{text: this.$t('test_track.plan.plan_status_finished'), value: 'Finished'},
{text: this.$t('test_track.plan.plan_status_archived'), value: 'Archived'}
],
batchOperators: [
{
name: this.$t('test_track.case.batch_move_case'),
handleClick: this.handleBatchMove,
permissions: ['PROJECT_TRACK_REVIEW:READ+EDIT']
}
],
operators: [
{
tip: this.$t('commons.edit'),
@ -226,12 +251,57 @@ export default {
});
this.initTableData();
},
props: {
treeNodes: {
type: Array
},
currentNode: {
type: Object
},
currentSelectNodes: {
type: Array
}
},
computed: {
projectId() {
return getCurrentProjectID();
},
...mapState(useStore, {
moduleOptions: 'testCaseReviewModuleOptions',
}),
nodePathMap() {
let map = new Map();
if (this.moduleOptions) {
this.moduleOptions.forEach((item) => {
map.set(item.id, item.path);
});
}
return map;
}
},
methods: {
refresh() {
this.$refs.testCaseReviewTable.clear();
this.$refs.testCaseReviewTable.isSelectDataAll(false);
this.initTableData(this.currentSelectNodes);
},
moveSave(param) {
param.condition = this.condition;
param.projectId = this.projectId;
batchMoveCaseReview(param).then(() => {
this.$refs.testCaseReviewBatchMove.btnDisable = false;
this.$success(this.$t('commons.save_success'), false);
this.$refs.testCaseReviewBatchMove.close();
this.refresh();
}).catch(() => {
this.$refs.testCaseReviewBatchMove.btnDisable = false;
});
},
handleBatchMove() {
let batchSelectCount = this.$refs.testCaseReviewTable.selectDataCounts;
let firstSelectRow = this.$refs.testCaseReviewTable.selectRows.values().next().value;
this.$refs.testCaseReviewBatchMove.open(firstSelectRow.name, this.treeNodes, this.$refs.testCaseReviewTable.selectIds, batchSelectCount, this.moduleOptions, '评审');
},
currentUser: () => {
return getCurrentUser();
},
@ -239,12 +309,20 @@ export default {
const list = deepClone(this.tableLabel);
this.$refs.headerCustom.open(list);
},
initTableData() {
initTableData(nodeIds) {
this.loading = true;
this.condition.nodeIds = [];
this.condition.workspaceId = getCurrentWorkspaceId();
if (!this.projectId) {
return;
}
this.condition.projectId = this.projectId;
if (nodeIds && Array.isArray(nodeIds) && nodeIds.length > 0) {
this.condition.nodeIds = nodeIds;
}
// ,
this.$emit('setCondition', this.condition);
this.$emit('refreshTree');
testReviewList(this.page.currentPage, this.page.pageSize, this.condition)
.then((response) => {
let data = response.data;
@ -261,6 +339,7 @@ export default {
}
});
this.tableData = tableData;
this.loading = false;
for (let i = 0; i < this.tableData.length; i++) {
let param = {id: this.tableData[i].id};
getTestCaseReviewProject(param)
@ -299,7 +378,7 @@ export default {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
this.$emit('openCaseReviewEditDialog');
this.$emit('openCaseReviewEditDialog', null, this.currentNode);
},
handleEdit(caseReview) {
this.$emit('caseReviewEdit', caseReview);
@ -311,14 +390,14 @@ export default {
let reviewId = caseReview.id;
deleteTestCaseReview(reviewId)
.then(() => {
this.initTableData();
this.initTableData(this.currentSelectNodes);
this.$success(this.$t('commons.delete_success'));
})
},
search() {
//
this.page.currentPage = 1;
this.initTableData();
this.initTableData(this.currentSelectNodes);
},
saveFollow(row) {
let param = {};

View File

@ -25,12 +25,13 @@ const TRACK_HEADER = {
{id: 'stage', key: '4', label: 'test_track.plan.plan_stage'},
{id: 'testRate', key: '5', label: 'test_track.home.test_rate'},
{id: 'projectName', key: '6', label: 'test_track.plan.plan_project'},
{id: 'plannedStartTime', key: '7', label: 'test_track.plan.planned_start_time'},
{id: 'plannedEndTime', key: '8', label: 'test_track.plan.planned_end_time'},
{id: 'actualStartTime', key: '9', label: 'test_track.plan.actual_start_time'},
{id: 'actualEndTime', key: 'a', label: 'test_track.plan.actual_end_time'},
{id: 'tags', key: 'b', label: 'commons.tag'},
{id: 'scheduleStatus', key: 'c', label: 'commons.trigger_mode.schedule'},
{id: 'nodePath', key: '7', label: 'test_track.case.module'},
{id: 'plannedStartTime', key: '8', label: 'test_track.plan.planned_start_time'},
{id: 'plannedEndTime', key: '9', label: 'test_track.plan.planned_end_time'},
{id: 'actualStartTime', key: 'a', label: 'test_track.plan.actual_start_time'},
{id: 'actualEndTime', key: 'b', label: 'test_track.plan.actual_end_time'},
{id: 'tags', key: 'c', label: 'commons.tag'},
{id: 'scheduleStatus', key: 'd', label: 'commons.trigger_mode.schedule'},
{id: 'passRate', key: 'e', label: 'commons.pass_rate'},
{id: 'createUser', key: 'f', label: 'commons.create_user'},
{id: 'testPlanTestCaseCount', key: 'g', label: 'test_track.plan.test_plan_test_case_count'},
@ -145,11 +146,12 @@ const TRACK_HEADER = {
{id: 'name', key: '1', label: 'test_track.review.review_name'},
{id: 'reviewer', key: '2', label: 'test_track.review.reviewer'},
{id: 'projectName', key: '3', label: 'test_track.review.review_project'},
{id: 'creatorName', key: '4', label: 'test_track.review.creator'},
{id: 'status', key: '5', label: 'test_track.review.review_status'},
{id: 'createTime', key: '6', label: 'commons.create_time'},
{id: 'endTime', key: '7', label: 'test_track.review.end_time'},
{id: 'tags', key: '8', label: 'commons.tag'},
{id: 'nodePath', key: '4', label: 'test_track.case.module'},
{id: 'creatorName', key: '5', label: 'test_track.review.creator'},
{id: 'status', key: '6', label: 'test_track.review.review_status'},
{id: 'createTime', key: '7', label: 'commons.create_time'},
{id: 'endTime', key: '8', label: 'test_track.review.end_time'},
{id: 'tags', key: '9', label: 'commons.tag'},
// {id: 'testRate', key: '9', label: 'review.review_rate'},
{id: 'caseCount', key: 'a', label: 'api_test.definition.api_case_number'},
{id: 'passRate', key: 'b', label: 'commons.pass_rate'},

View File

@ -6,6 +6,8 @@ export default {
testCaseSelectNodeIds: [],
testCasePublicSelectNodeIds: [],
testCaseModuleOptions: [],
testCaseReviewModuleOptions: [],
testPlanModuleOptions: [],
testReviewSelectNode: {},
testReviewSelectNodeIds: [],
testPlanViewSelectNode: {},