refactor: 代码规范 (#13625)

* refactor(测试跟踪): 自定义字段重构数据兼容性处理

* refactor(测试跟踪): 功能用例自定义字段改造

* refactor: 自定义字段移动至项目

* refactor: 高级搜索改造

* refactor: 统一高级搜索样式

* refactor: 修改操作列的文本显示

* refactor: 缺陷自定义字段处理

* refactor: 缺陷列表基础字段可搜索

* refactor: 缺陷支持通过自定义字段搜索

* refactor: flyway

* refactor: 代码规范

Co-authored-by: chenjianxing <jianxing.chen@fit2cloud.com>
Co-authored-by: shiziyuan9527 <yuhao.li@fit2cloud.com>
This commit is contained in:
MeterSphere Bot 2022-05-16 15:02:28 +08:00 committed by GitHub
parent 4949e5a3e2
commit 9e56ac53ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 3306 additions and 513 deletions

View File

@ -1,8 +1,7 @@
package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable;
import lombok.Data;
@Data
public class CustomField implements Serializable {
@ -28,7 +27,9 @@ public class CustomField implements Serializable {
private String projectId;
private Boolean thirdPart;
private String options;
private static final long serialVersionUID = 1L;
}
}

View File

@ -833,6 +833,66 @@ public class CustomFieldExample {
addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andThirdPartIsNull() {
addCriterion("third_part is null");
return (Criteria) this;
}
public Criteria andThirdPartIsNotNull() {
addCriterion("third_part is not null");
return (Criteria) this;
}
public Criteria andThirdPartEqualTo(Boolean value) {
addCriterion("third_part =", value, "thirdPart");
return (Criteria) this;
}
public Criteria andThirdPartNotEqualTo(Boolean value) {
addCriterion("third_part <>", value, "thirdPart");
return (Criteria) this;
}
public Criteria andThirdPartGreaterThan(Boolean value) {
addCriterion("third_part >", value, "thirdPart");
return (Criteria) this;
}
public Criteria andThirdPartGreaterThanOrEqualTo(Boolean value) {
addCriterion("third_part >=", value, "thirdPart");
return (Criteria) this;
}
public Criteria andThirdPartLessThan(Boolean value) {
addCriterion("third_part <", value, "thirdPart");
return (Criteria) this;
}
public Criteria andThirdPartLessThanOrEqualTo(Boolean value) {
addCriterion("third_part <=", value, "thirdPart");
return (Criteria) this;
}
public Criteria andThirdPartIn(List<Boolean> values) {
addCriterion("third_part in", values, "thirdPart");
return (Criteria) this;
}
public Criteria andThirdPartNotIn(List<Boolean> values) {
addCriterion("third_part not in", values, "thirdPart");
return (Criteria) this;
}
public Criteria andThirdPartBetween(Boolean value1, Boolean value2) {
addCriterion("third_part between", value1, value2, "thirdPart");
return (Criteria) this;
}
public Criteria andThirdPartNotBetween(Boolean value1, Boolean value2) {
addCriterion("third_part not between", value1, value2, "thirdPart");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
@ -927,4 +987,4 @@ public class CustomFieldExample {
this(condition, value, secondValue, null);
}
}
}
}

View File

@ -0,0 +1,17 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CustomFieldIssues extends CustomFieldIssuesKey implements Serializable {
private String value;
private String textValue;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,410 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class CustomFieldIssuesExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public CustomFieldIssuesExample() {
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 andResourceIdIsNull() {
addCriterion("resource_id is null");
return (Criteria) this;
}
public Criteria andResourceIdIsNotNull() {
addCriterion("resource_id is not null");
return (Criteria) this;
}
public Criteria andResourceIdEqualTo(String value) {
addCriterion("resource_id =", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotEqualTo(String value) {
addCriterion("resource_id <>", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdGreaterThan(String value) {
addCriterion("resource_id >", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdGreaterThanOrEqualTo(String value) {
addCriterion("resource_id >=", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLessThan(String value) {
addCriterion("resource_id <", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLessThanOrEqualTo(String value) {
addCriterion("resource_id <=", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLike(String value) {
addCriterion("resource_id like", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotLike(String value) {
addCriterion("resource_id not like", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdIn(List<String> values) {
addCriterion("resource_id in", values, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotIn(List<String> values) {
addCriterion("resource_id not in", values, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdBetween(String value1, String value2) {
addCriterion("resource_id between", value1, value2, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotBetween(String value1, String value2) {
addCriterion("resource_id not between", value1, value2, "resourceId");
return (Criteria) this;
}
public Criteria andFieldIdIsNull() {
addCriterion("field_id is null");
return (Criteria) this;
}
public Criteria andFieldIdIsNotNull() {
addCriterion("field_id is not null");
return (Criteria) this;
}
public Criteria andFieldIdEqualTo(String value) {
addCriterion("field_id =", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotEqualTo(String value) {
addCriterion("field_id <>", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdGreaterThan(String value) {
addCriterion("field_id >", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdGreaterThanOrEqualTo(String value) {
addCriterion("field_id >=", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdLessThan(String value) {
addCriterion("field_id <", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdLessThanOrEqualTo(String value) {
addCriterion("field_id <=", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdLike(String value) {
addCriterion("field_id like", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotLike(String value) {
addCriterion("field_id not like", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdIn(List<String> values) {
addCriterion("field_id in", values, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotIn(List<String> values) {
addCriterion("field_id not in", values, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdBetween(String value1, String value2) {
addCriterion("field_id between", value1, value2, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotBetween(String value1, String value2) {
addCriterion("field_id not between", value1, value2, "fieldId");
return (Criteria) this;
}
public Criteria andValueIsNull() {
addCriterion("`value` is null");
return (Criteria) this;
}
public Criteria andValueIsNotNull() {
addCriterion("`value` is not null");
return (Criteria) this;
}
public Criteria andValueEqualTo(String value) {
addCriterion("`value` =", value, "value");
return (Criteria) this;
}
public Criteria andValueNotEqualTo(String value) {
addCriterion("`value` <>", value, "value");
return (Criteria) this;
}
public Criteria andValueGreaterThan(String value) {
addCriterion("`value` >", value, "value");
return (Criteria) this;
}
public Criteria andValueGreaterThanOrEqualTo(String value) {
addCriterion("`value` >=", value, "value");
return (Criteria) this;
}
public Criteria andValueLessThan(String value) {
addCriterion("`value` <", value, "value");
return (Criteria) this;
}
public Criteria andValueLessThanOrEqualTo(String value) {
addCriterion("`value` <=", value, "value");
return (Criteria) this;
}
public Criteria andValueLike(String value) {
addCriterion("`value` like", value, "value");
return (Criteria) this;
}
public Criteria andValueNotLike(String value) {
addCriterion("`value` not like", value, "value");
return (Criteria) this;
}
public Criteria andValueIn(List<String> values) {
addCriterion("`value` in", values, "value");
return (Criteria) this;
}
public Criteria andValueNotIn(List<String> values) {
addCriterion("`value` not in", values, "value");
return (Criteria) this;
}
public Criteria andValueBetween(String value1, String value2) {
addCriterion("`value` between", value1, value2, "value");
return (Criteria) this;
}
public Criteria andValueNotBetween(String value1, String value2) {
addCriterion("`value` not between", value1, value2, "value");
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

@ -0,0 +1,13 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class CustomFieldIssuesKey implements Serializable {
private String resourceId;
private String fieldId;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,17 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CustomFieldTestCase extends CustomFieldTestCaseKey implements Serializable {
private String value;
private String textValue;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,410 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class CustomFieldTestCaseExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public CustomFieldTestCaseExample() {
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 andResourceIdIsNull() {
addCriterion("resource_id is null");
return (Criteria) this;
}
public Criteria andResourceIdIsNotNull() {
addCriterion("resource_id is not null");
return (Criteria) this;
}
public Criteria andResourceIdEqualTo(String value) {
addCriterion("resource_id =", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotEqualTo(String value) {
addCriterion("resource_id <>", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdGreaterThan(String value) {
addCriterion("resource_id >", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdGreaterThanOrEqualTo(String value) {
addCriterion("resource_id >=", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLessThan(String value) {
addCriterion("resource_id <", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLessThanOrEqualTo(String value) {
addCriterion("resource_id <=", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLike(String value) {
addCriterion("resource_id like", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotLike(String value) {
addCriterion("resource_id not like", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdIn(List<String> values) {
addCriterion("resource_id in", values, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotIn(List<String> values) {
addCriterion("resource_id not in", values, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdBetween(String value1, String value2) {
addCriterion("resource_id between", value1, value2, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotBetween(String value1, String value2) {
addCriterion("resource_id not between", value1, value2, "resourceId");
return (Criteria) this;
}
public Criteria andFieldIdIsNull() {
addCriterion("field_id is null");
return (Criteria) this;
}
public Criteria andFieldIdIsNotNull() {
addCriterion("field_id is not null");
return (Criteria) this;
}
public Criteria andFieldIdEqualTo(String value) {
addCriterion("field_id =", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotEqualTo(String value) {
addCriterion("field_id <>", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdGreaterThan(String value) {
addCriterion("field_id >", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdGreaterThanOrEqualTo(String value) {
addCriterion("field_id >=", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdLessThan(String value) {
addCriterion("field_id <", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdLessThanOrEqualTo(String value) {
addCriterion("field_id <=", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdLike(String value) {
addCriterion("field_id like", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotLike(String value) {
addCriterion("field_id not like", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdIn(List<String> values) {
addCriterion("field_id in", values, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotIn(List<String> values) {
addCriterion("field_id not in", values, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdBetween(String value1, String value2) {
addCriterion("field_id between", value1, value2, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotBetween(String value1, String value2) {
addCriterion("field_id not between", value1, value2, "fieldId");
return (Criteria) this;
}
public Criteria andValueIsNull() {
addCriterion("`value` is null");
return (Criteria) this;
}
public Criteria andValueIsNotNull() {
addCriterion("`value` is not null");
return (Criteria) this;
}
public Criteria andValueEqualTo(String value) {
addCriterion("`value` =", value, "value");
return (Criteria) this;
}
public Criteria andValueNotEqualTo(String value) {
addCriterion("`value` <>", value, "value");
return (Criteria) this;
}
public Criteria andValueGreaterThan(String value) {
addCriterion("`value` >", value, "value");
return (Criteria) this;
}
public Criteria andValueGreaterThanOrEqualTo(String value) {
addCriterion("`value` >=", value, "value");
return (Criteria) this;
}
public Criteria andValueLessThan(String value) {
addCriterion("`value` <", value, "value");
return (Criteria) this;
}
public Criteria andValueLessThanOrEqualTo(String value) {
addCriterion("`value` <=", value, "value");
return (Criteria) this;
}
public Criteria andValueLike(String value) {
addCriterion("`value` like", value, "value");
return (Criteria) this;
}
public Criteria andValueNotLike(String value) {
addCriterion("`value` not like", value, "value");
return (Criteria) this;
}
public Criteria andValueIn(List<String> values) {
addCriterion("`value` in", values, "value");
return (Criteria) this;
}
public Criteria andValueNotIn(List<String> values) {
addCriterion("`value` not in", values, "value");
return (Criteria) this;
}
public Criteria andValueBetween(String value1, String value2) {
addCriterion("`value` between", value1, value2, "value");
return (Criteria) this;
}
public Criteria andValueNotBetween(String value1, String value2) {
addCriterion("`value` not between", value1, value2, "value");
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

@ -0,0 +1,13 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class CustomFieldTestCaseKey implements Serializable {
private String resourceId;
private String fieldId;
private static final long serialVersionUID = 1L;
}

View File

@ -1,5 +1,6 @@
package io.metersphere.base.domain;
import io.metersphere.dto.CustomFieldDao;
import lombok.Getter;
import lombok.Setter;
@ -21,4 +22,5 @@ public class IssuesDao extends IssuesWithBLOBs {
private String zentaoAssigned;
private String refType;
private String refId;
private List<CustomFieldDao> fields;
}

View File

@ -0,0 +1,20 @@
package io.metersphere.base.domain.ext;
import io.metersphere.base.domain.CustomFieldTestCase;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.Serializable;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
/**
* 自定义字段关联表的统一操作类
* 字段跟 CustomFieldIssues CustomFieldTestCase 一样
* 考虑到表中数据量较大按类型拆分成多个表
*/
public class CustomFieldResource extends CustomFieldTestCase implements Serializable {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,11 @@
package io.metersphere.base.domain.ext;
import io.metersphere.base.domain.CustomFieldTestCaseKey;
import lombok.Data;
import java.io.Serializable;
@Data
public class CustomFieldResourceKey extends CustomFieldTestCaseKey implements Serializable {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,37 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.CustomFieldIssues;
import io.metersphere.base.domain.CustomFieldIssuesExample;
import io.metersphere.base.domain.CustomFieldIssuesKey;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface CustomFieldIssuesMapper {
long countByExample(CustomFieldIssuesExample example);
int deleteByExample(CustomFieldIssuesExample example);
int deleteByPrimaryKey(CustomFieldIssuesKey key);
int insert(CustomFieldIssues record);
int insertSelective(CustomFieldIssues record);
List<CustomFieldIssues> selectByExampleWithBLOBs(CustomFieldIssuesExample example);
List<CustomFieldIssues> selectByExample(CustomFieldIssuesExample example);
CustomFieldIssues selectByPrimaryKey(CustomFieldIssuesKey key);
int updateByExampleSelective(@Param("record") CustomFieldIssues record, @Param("example") CustomFieldIssuesExample example);
int updateByExampleWithBLOBs(@Param("record") CustomFieldIssues record, @Param("example") CustomFieldIssuesExample example);
int updateByExample(@Param("record") CustomFieldIssues record, @Param("example") CustomFieldIssuesExample example);
int updateByPrimaryKeySelective(CustomFieldIssues record);
int updateByPrimaryKeyWithBLOBs(CustomFieldIssues record);
int updateByPrimaryKey(CustomFieldIssues record);
}

View File

@ -0,0 +1,234 @@
<?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.CustomFieldIssuesMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.CustomFieldIssues">
<id column="resource_id" jdbcType="VARCHAR" property="resourceId" />
<id column="field_id" jdbcType="VARCHAR" property="fieldId" />
<result column="value" jdbcType="VARCHAR" property="value" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.CustomFieldIssues">
<result column="text_value" jdbcType="LONGVARCHAR" property="textValue" />
</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">
resource_id, field_id, `value`
</sql>
<sql id="Blob_Column_List">
text_value
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.CustomFieldIssuesExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from custom_field_issues
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.base.domain.CustomFieldIssuesExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from custom_field_issues
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="io.metersphere.base.domain.CustomFieldIssuesKey" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from custom_field_issues
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="io.metersphere.base.domain.CustomFieldIssuesKey">
delete from custom_field_issues
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.CustomFieldIssuesExample">
delete from custom_field_issues
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.CustomFieldIssues">
insert into custom_field_issues (resource_id, field_id, `value`,
text_value)
values (#{resourceId,jdbcType=VARCHAR}, #{fieldId,jdbcType=VARCHAR}, #{value,jdbcType=VARCHAR},
#{textValue,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.CustomFieldIssues">
insert into custom_field_issues
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="resourceId != null">
resource_id,
</if>
<if test="fieldId != null">
field_id,
</if>
<if test="value != null">
`value`,
</if>
<if test="textValue != null">
text_value,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="resourceId != null">
#{resourceId,jdbcType=VARCHAR},
</if>
<if test="fieldId != null">
#{fieldId,jdbcType=VARCHAR},
</if>
<if test="value != null">
#{value,jdbcType=VARCHAR},
</if>
<if test="textValue != null">
#{textValue,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.CustomFieldIssuesExample" resultType="java.lang.Long">
select count(*) from custom_field_issues
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update custom_field_issues
<set>
<if test="record.resourceId != null">
resource_id = #{record.resourceId,jdbcType=VARCHAR},
</if>
<if test="record.fieldId != null">
field_id = #{record.fieldId,jdbcType=VARCHAR},
</if>
<if test="record.value != null">
`value` = #{record.value,jdbcType=VARCHAR},
</if>
<if test="record.textValue != null">
text_value = #{record.textValue,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update custom_field_issues
set resource_id = #{record.resourceId,jdbcType=VARCHAR},
field_id = #{record.fieldId,jdbcType=VARCHAR},
`value` = #{record.value,jdbcType=VARCHAR},
text_value = #{record.textValue,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update custom_field_issues
set resource_id = #{record.resourceId,jdbcType=VARCHAR},
field_id = #{record.fieldId,jdbcType=VARCHAR},
`value` = #{record.value,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.CustomFieldIssues">
update custom_field_issues
<set>
<if test="value != null">
`value` = #{value,jdbcType=VARCHAR},
</if>
<if test="textValue != null">
text_value = #{textValue,jdbcType=LONGVARCHAR},
</if>
</set>
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.CustomFieldIssues">
update custom_field_issues
set `value` = #{value,jdbcType=VARCHAR},
text_value = #{textValue,jdbcType=LONGVARCHAR}
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.CustomFieldIssues">
update custom_field_issues
set `value` = #{value,jdbcType=VARCHAR}
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -13,6 +13,7 @@
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
<result column="third_part" jdbcType="BIT" property="thirdPart" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.CustomField">
<result column="options" jdbcType="LONGVARCHAR" property="options" />
@ -76,8 +77,8 @@
</where>
</sql>
<sql id="Base_Column_List">
id, `name`, scene, `type`, remark, `system`, `global`, create_time, update_time,
create_user, project_id
id, `name`, scene, `type`, remark, `system`, `global`, create_time, update_time,
create_user, project_id, third_part
</sql>
<sql id="Blob_Column_List">
`options`
@ -113,7 +114,7 @@
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
@ -132,13 +133,13 @@
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.CustomField">
INSERT INTO custom_field (id, `name`, scene,
`type`, remark, `system`, `global`,
create_time, update_time, create_user,
project_id, `options`)
`type`, remark, `system`, `global`,
create_time, update_time, create_user,
project_id, third_part, `options`)
VALUES (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{scene,jdbcType=VARCHAR},
#{type,jdbcType=VARCHAR}, #{remark,jdbcType=VARCHAR}, #{system,jdbcType=BIT}, #{global,jdbcType=BIT},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR},
#{projectId,jdbcType=VARCHAR}, #{options,jdbcType=LONGVARCHAR})
#{type,jdbcType=VARCHAR}, #{remark,jdbcType=VARCHAR}, #{system,jdbcType=BIT}, #{global,jdbcType=BIT},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR},
#{projectId,jdbcType=VARCHAR}, #{thirdPart,jdbcType=BIT}, #{options,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.CustomField">
insert into custom_field
@ -176,6 +177,9 @@
<if test="projectId != null">
project_id,
</if>
<if test="thirdPart != null">
third_part,
</if>
<if test="options != null">
`options`,
</if>
@ -214,6 +218,9 @@
<if test="projectId != null">
#{projectId,jdbcType=VARCHAR},
</if>
<if test="thirdPart != null">
#{thirdPart,jdbcType=BIT},
</if>
<if test="options != null">
#{options,jdbcType=LONGVARCHAR},
</if>
@ -258,6 +265,9 @@
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
<if test="record.thirdPart != null">
third_part = #{record.thirdPart,jdbcType=BIT},
</if>
<if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
@ -282,6 +292,7 @@
update_time = #{record.updateTime,jdbcType=BIGINT},
create_user = #{record.createUser,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR},
third_part = #{record.thirdPart,jdbcType=BIT},
`options` = #{record.options,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -300,6 +311,8 @@
update_time = #{record.updateTime,jdbcType=BIGINT},
create_user = #{record.createUser,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR}
create_user = #{record.createUser,jdbcType=VARCHAR},
third_part = #{record.thirdPart,jdbcType=BIT}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -334,6 +347,9 @@
<if test="createUser != null">
create_user = #{createUser,jdbcType=VARCHAR},
</if>
<if test="thirdPart != null">
third_part = #{thirdPart,jdbcType=BIT},
</if>
<if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR},
</if>
@ -355,12 +371,13 @@
update_time = #{updateTime,jdbcType=BIGINT},
create_user = #{createUser,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR},
third_part = #{thirdPart,jdbcType=BIT},
`options` = #{options,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.CustomField">
UPDATE custom_field
SET `name` = #{name,jdbcType=VARCHAR},
update custom_field
set `name` = #{name,jdbcType=VARCHAR},
scene = #{scene,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR},
remark = #{remark,jdbcType=VARCHAR},
@ -369,7 +386,8 @@
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
create_user = #{createUser,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR}
WHERE id = #{id,jdbcType=VARCHAR}
project_id = #{projectId,jdbcType=VARCHAR},
third_part = #{thirdPart,jdbcType=BIT}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>
</mapper>

View File

@ -0,0 +1,37 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.CustomFieldTestCase;
import io.metersphere.base.domain.CustomFieldTestCaseExample;
import io.metersphere.base.domain.CustomFieldTestCaseKey;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface CustomFieldTestCaseMapper {
long countByExample(CustomFieldTestCaseExample example);
int deleteByExample(CustomFieldTestCaseExample example);
int deleteByPrimaryKey(CustomFieldTestCaseKey key);
int insert(CustomFieldTestCase record);
int insertSelective(CustomFieldTestCase record);
List<CustomFieldTestCase> selectByExampleWithBLOBs(CustomFieldTestCaseExample example);
List<CustomFieldTestCase> selectByExample(CustomFieldTestCaseExample example);
CustomFieldTestCase selectByPrimaryKey(CustomFieldTestCaseKey key);
int updateByExampleSelective(@Param("record") CustomFieldTestCase record, @Param("example") CustomFieldTestCaseExample example);
int updateByExampleWithBLOBs(@Param("record") CustomFieldTestCase record, @Param("example") CustomFieldTestCaseExample example);
int updateByExample(@Param("record") CustomFieldTestCase record, @Param("example") CustomFieldTestCaseExample example);
int updateByPrimaryKeySelective(CustomFieldTestCase record);
int updateByPrimaryKeyWithBLOBs(CustomFieldTestCase record);
int updateByPrimaryKey(CustomFieldTestCase record);
}

View File

@ -0,0 +1,234 @@
<?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.CustomFieldTestCaseMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.CustomFieldTestCase">
<id column="resource_id" jdbcType="VARCHAR" property="resourceId" />
<id column="field_id" jdbcType="VARCHAR" property="fieldId" />
<result column="value" jdbcType="VARCHAR" property="value" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.CustomFieldTestCase">
<result column="text_value" jdbcType="LONGVARCHAR" property="textValue" />
</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">
resource_id, field_id, `value`
</sql>
<sql id="Blob_Column_List">
text_value
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.CustomFieldTestCaseExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from custom_field_test_case
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.base.domain.CustomFieldTestCaseExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from custom_field_test_case
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="io.metersphere.base.domain.CustomFieldTestCaseKey" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from custom_field_test_case
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="io.metersphere.base.domain.CustomFieldTestCaseKey">
delete from custom_field_test_case
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.CustomFieldTestCaseExample">
delete from custom_field_test_case
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.CustomFieldTestCase">
insert into custom_field_test_case (resource_id, field_id, `value`,
text_value)
values (#{resourceId,jdbcType=VARCHAR}, #{fieldId,jdbcType=VARCHAR}, #{value,jdbcType=VARCHAR},
#{textValue,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.CustomFieldTestCase">
insert into custom_field_test_case
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="resourceId != null">
resource_id,
</if>
<if test="fieldId != null">
field_id,
</if>
<if test="value != null">
`value`,
</if>
<if test="textValue != null">
text_value,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="resourceId != null">
#{resourceId,jdbcType=VARCHAR},
</if>
<if test="fieldId != null">
#{fieldId,jdbcType=VARCHAR},
</if>
<if test="value != null">
#{value,jdbcType=VARCHAR},
</if>
<if test="textValue != null">
#{textValue,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.CustomFieldTestCaseExample" resultType="java.lang.Long">
select count(*) from custom_field_test_case
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update custom_field_test_case
<set>
<if test="record.resourceId != null">
resource_id = #{record.resourceId,jdbcType=VARCHAR},
</if>
<if test="record.fieldId != null">
field_id = #{record.fieldId,jdbcType=VARCHAR},
</if>
<if test="record.value != null">
`value` = #{record.value,jdbcType=VARCHAR},
</if>
<if test="record.textValue != null">
text_value = #{record.textValue,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update custom_field_test_case
set resource_id = #{record.resourceId,jdbcType=VARCHAR},
field_id = #{record.fieldId,jdbcType=VARCHAR},
`value` = #{record.value,jdbcType=VARCHAR},
text_value = #{record.textValue,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update custom_field_test_case
set resource_id = #{record.resourceId,jdbcType=VARCHAR},
field_id = #{record.fieldId,jdbcType=VARCHAR},
`value` = #{record.value,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.CustomFieldTestCase">
update custom_field_test_case
<set>
<if test="value != null">
`value` = #{value,jdbcType=VARCHAR},
</if>
<if test="textValue != null">
text_value = #{textValue,jdbcType=LONGVARCHAR},
</if>
</set>
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.CustomFieldTestCase">
update custom_field_test_case
set `value` = #{value,jdbcType=VARCHAR},
text_value = #{textValue,jdbcType=LONGVARCHAR}
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.CustomFieldTestCase">
update custom_field_test_case
set `value` = #{value,jdbcType=VARCHAR}
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -0,0 +1,23 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.ext.CustomFieldResource;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtCustomFieldResourceMapper {
int insert(@Param("tableName") String tableName, @Param("record") CustomFieldResource record);
int updateByPrimaryKeySelective(@Param("tableName") String tableName, @Param("record") CustomFieldResource record);
void deleteByResourceId(@Param("tableName") String tableName, @Param("resourceId") String resourceId);
void deleteByResourceIds(@Param("tableName") String tableName, @Param("resourceIds") List<String> resourceIds);
List<CustomFieldResource> getByResourceId(@Param("tableName") String tableName, @Param("resourceId") String resourceId);
List<CustomFieldResource> getByResourceIds(@Param("tableName") String tableName, @Param("resourceIds") List<String> resourceIds);
long countFieldResource(@Param("tableName") String tableName, @Param("resourceId") String resourceId, @Param("fieldId") String field_id);
}

View File

@ -0,0 +1,57 @@
<?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.ExtCustomFieldResourceMapper">
<insert id="insert">
insert into ${tableName} (resource_id, field_id, `value`,
text_value)
values (#{record.resourceId,jdbcType=VARCHAR}, #{record.fieldId,jdbcType=VARCHAR}, #{record.value,jdbcType=VARCHAR},
#{record.textValue,jdbcType=LONGVARCHAR})
</insert>
<update id="updateByPrimaryKeySelective">
update ${tableName}
<set>
<if test="record.value != null">
`value` = #{record.value,jdbcType=VARCHAR},
</if>
<if test="record.textValue != null">
text_value = #{record.textValue,jdbcType=LONGVARCHAR},
</if>
</set>
where resource_id = #{record.resourceId,jdbcType=VARCHAR}
and field_id = #{record.fieldId,jdbcType=VARCHAR}
</update>
<delete id="deleteByResourceId">
delete from ${tableName}
where resource_id = #{resourceId}
</delete>
<delete id="deleteByResourceIds">
delete from ${tableName}
where resource_id in
<foreach collection="resourceIds" item="resourceId" separator="," open="(" close=")">
#{resourceId}
</foreach>
</delete>
<select id="getByResourceId" resultType="io.metersphere.base.domain.ext.CustomFieldResource">
select
<include refid="io.metersphere.base.mapper.CustomFieldTestCaseMapper.Base_Column_List" />
,
<include refid="io.metersphere.base.mapper.CustomFieldTestCaseMapper.Blob_Column_List" />
from ${tableName}
where resource_id = #{resourceId}
</select>
<select id="getByResourceIds" resultType="io.metersphere.base.domain.ext.CustomFieldResource">
select
<include refid="io.metersphere.base.mapper.CustomFieldTestCaseMapper.Base_Column_List" />
,
<include refid="io.metersphere.base.mapper.CustomFieldTestCaseMapper.Blob_Column_List" />
from ${tableName}
where resource_id in
<foreach collection="resourceIds" item="resourceId" separator="," open="(" close=")">
#{resourceId}
</foreach>
</select>
<select id="countFieldResource" resultType="java.lang.Long">
select count(1) from ${tableName} where resource_id = #{resourceId} and field_id = #{fieldId}
</select>
</mapper>

View File

@ -2,6 +2,7 @@ package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.Issues;
import io.metersphere.base.domain.IssuesDao;
import io.metersphere.track.dto.CustomFieldResourceCompatibleDTO;
import io.metersphere.track.dto.PlanReportIssueDTO;
import io.metersphere.track.request.testcase.IssuesRequest;
import org.apache.ibatis.annotations.Param;
@ -32,5 +33,7 @@ public interface ExtIssuesMapper {
int deleteIssues(@Param("issuesId") String issuesId, @Param("resourceId") String resourceId);
List<CustomFieldResourceCompatibleDTO> getForCompatibleCustomField(String projectId, int offset, int pageSize);
IssuesDao selectByPrimaryKey(String id);
}

View File

@ -112,6 +112,12 @@
#{value}
</foreach>
</select>
<select id="getForCompatibleCustomField" resultType="io.metersphere.track.dto.CustomFieldResourceCompatibleDTO">
select id, custom_fields
from issues
where project_id = #{projectId}
limit #{offset},#{pageSize}
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultType="io.metersphere.base.domain.IssuesDao">
select
<include refid="Issue_List_Column" />
@ -198,13 +204,24 @@
</where>
</sql>
<sql id="combine">
<if test='${condition}.name != null and (${name} == null or ${name} == "")'>
and issues.title
<include refid="condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
<if test="${condition}.creator != null">
and issues.creator
<include refid="condition">
<property name="object" value="${condition}.creator"/>
</include>
</if>
<if test="${condition}.platform != null">
and issues.platform
<include refid="condition">
<property name="object" value="${condition}.platform"/>
</include>
</if>
<if test="${condition}.followPeople != null">
and issues.id in (
select issue_id from issue_follow where follow_id
@ -213,6 +230,22 @@
</include>
)
</if>
<if test="${condition}.createTime != null">
and issues.create_time
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<if test="${condition}.customs != null and ${condition}.customs.size() > 0">
<foreach collection="${condition}.customs" item="custom" separator="" open="" close="">
and issues.id in (
select resource_id from custom_field_issues where field_id = #{custom.id}
and trim(both '"' from value)
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="custom"/>
</include>)
</foreach>
</if>
</sql>
<sql id="condition">
<choose>

View File

@ -23,6 +23,8 @@ public interface ExtProjectMapper {
List<String> getProjectIds();
List<Project> getProjectForCustomField(String workspaceId);
String getMaxSystemId();
@MapKey("id")

View File

@ -393,4 +393,7 @@
NULL)
</insert>
<select id="getProjectForCustomField" resultType="io.metersphere.base.domain.Project">
select id, platform, third_part_template from project where workspace_id = #{workspaceId}
</select>
</mapper>

View File

@ -4,6 +4,7 @@ import io.metersphere.base.domain.TestCase;
import io.metersphere.base.domain.TestCaseWithBLOBs;
import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.dto.RelationshipGraphData;
import io.metersphere.track.dto.CustomFieldResourceCompatibleDTO;
import io.metersphere.track.dto.TestCaseDTO;
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
@ -150,5 +151,7 @@ public interface ExtTestCaseMapper {
List<TestCaseDTO> getForNodeEdit(@Param("ids") List<String> ids);
List<CustomFieldResourceCompatibleDTO> getForCompatibleCustomField(String projectId, int offset, int pageSize);
List<Map<String, Object>> moduleExtraNodeCount(@Param("nodeIds") List<String> nodeIds);
}

View File

@ -78,6 +78,16 @@
<property name="object" value="${condition}.reviewStatus"/>
</include>
</if>
<if test="${condition}.customs != null and ${condition}.customs.size() > 0">
<foreach collection="${condition}.customs" item="custom" separator="" open="" close="">
and test_case.id in (
select resource_id from custom_field_test_case where field_id = #{custom.id}
and trim(both '"' from value)
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition">
<property name="object" value="custom"/>
</include>)
</foreach>
</if>
</sql>
<update id="updateTestCaseCustomNumByProjectId">
update test_case set custom_num = num where (custom_num is null or custom_num = '') and project_id = #{projectId}
@ -196,7 +206,7 @@
test_case.other_test_name, test_case.review_status, test_case.tags,
test_case.demand_id, test_case.demand_name, test_case.`status`,
test_case.custom_num, test_case.step_model, test_case.create_user,
test_case.custom_fields, test_case.ref_id
test_case.ref_id
</if>
from test_case
left join project_version on project_version.id = test_case.version_id
@ -971,6 +981,13 @@
</foreach>
</select>
<select id="getForCompatibleCustomField" resultType="io.metersphere.track.dto.CustomFieldResourceCompatibleDTO">
select id, custom_fields
from test_case
where project_id = #{projectId}
limit #{offset},#{pageSize}
</select>
<update id="addLatestVersion">
UPDATE test_case
INNER JOIN ((

View File

@ -12,4 +12,6 @@ public interface ExtWorkspaceMapper {
List<WorkspaceDTO> getWorkspaces(@Param("request") WorkspaceRequest request);
List<Workspace> getWorkspaceByUserId(@Param("userId")String userId);
List<String> getWorkspaceIds();
}

View File

@ -16,4 +16,7 @@
<select id="getWorkspaceByUserId" resultType="io.metersphere.base.domain.Workspace">
SELECT * from workspace where workspace.id in (SELECT user_group.source_id from user_group where user_group.user_id = #{userId})
</select>
</mapper>
<select id="getWorkspaceIds" resultType="java.lang.String">
select id from workspace;
</select>
</mapper>

View File

@ -46,6 +46,11 @@ public class CustomFieldController {
customFieldService.delete(id);
}
@GetMapping("/get/{id}")
public CustomField get(@PathVariable(value = "id") String id) {
return customFieldService.get(id);
}
@PostMapping("/update")
@MsAuditLog(module = OperLogModule.WORKSPACE_TEMPLATE_SETTINGS_FIELD, type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#customField.id)", content = "#msClass.getLogDetails(#customField.id)", msClass = CustomFieldService.class)
public void update(@RequestBody CustomField customField) {

View File

@ -0,0 +1,25 @@
package io.metersphere.controller.request.customfield;
import io.metersphere.base.domain.CustomField;
import io.metersphere.base.mapper.CustomFieldMapper;
import io.metersphere.base.mapper.ext.ExtCustomFieldResourceMapper;
import lombok.Getter;
import lombok.Setter;
import org.apache.ibatis.session.SqlSession;
import java.util.Map;
@Getter
@Setter
public class CustomFieldResourceRequest {
private String workspaceId;
private String projectId;
private Map<String, CustomField> wdFieldMap;
private Map<String, CustomField> globalFieldMap;
private Map<String, CustomField> jiraSyncFieldMap;
private String resourceType;
private SqlSession sqlSession;
private ExtCustomFieldResourceMapper batchMapper;
private CustomFieldMapper customFieldBatchMapper;
private boolean enableJiraSync;
}

View File

@ -11,6 +11,10 @@ public class CustomFieldDao extends CustomField {
private String defaultValue;
private String textValue;
private String value;
private String customData;
private String key;

View File

@ -0,0 +1,16 @@
package io.metersphere.dto;
import io.metersphere.base.domain.ext.CustomFieldResource;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.Serializable;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CustomFieldResourceDTO extends CustomFieldResource implements Serializable {
private String name;
private static final long serialVersionUID = 1L;
}

View File

@ -418,8 +418,9 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
}
data.setStatus(caseStatusValue);
String customFieldsJson = this.getCustomFieldsJson(data);
testCase.setCustomFields(customFieldsJson);
// todo 这里要获取模板的自定义字段再新建关联关系
// String customFieldsJson = this.getCustomFieldsJson(data);
// testCase.setCustomFields(customFieldsJson);
if (StringUtils.isNotBlank(data.getMaintainer())) {
testCase.setMaintainer(data.getMaintainer());
}
@ -471,8 +472,9 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
}
data.setStatus(caseStatusValue);
String customFieldsJson = this.getCustomFieldsJson(data);
testCase.setCustomFields(customFieldsJson);
// todo
// String customFieldsJson = this.getCustomFieldsJson(data);
// testCase.setCustomFields(customFieldsJson);
if (StringUtils.isNotBlank(data.getMaintainer())) {
testCase.setMaintainer(data.getMaintainer());
}

View File

@ -65,6 +65,8 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
private TestReviewTestCaseService testReviewTestCaseService;
@Resource
private MockConfigService mockConfigService;
@Resource
private CustomFieldResourceService customFieldResourceService;
@Value("${jmeter.home}")
private String jmeterHome;
@ -154,6 +156,7 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
initOnceOperate(testReviewTestCaseService::initOrderField, "init.sort.review.test.case");
initOnceOperate(apiDefinitionService::initDefaultModuleId, "init.default.module.id");
initOnceOperate(mockConfigService::initExpectNum, "init.mock.expectNum");
initOnceOperate(customFieldResourceService::compatibleData, "init.custom.field.resource");
initOnceOperate(jarConfigService::initJarPath, "init.jar.path");
}

View File

@ -0,0 +1,52 @@
package io.metersphere.service;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.dto.CustomFieldDao;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Map;
@Service
@Transactional(rollbackFor = Exception.class)
public class CustomFieldIssuesService extends CustomFieldResourceService {
private static final String TABLE_NAME = "custom_field_issues";
public void addFields(String resourceId, List<CustomFieldResource> addFields) {
super.addFields(TABLE_NAME, resourceId, addFields);
}
public void editFields(String resourceId, List<CustomFieldResource> editFields) {
super.editFields(TABLE_NAME, resourceId, editFields);
}
public void batchEditFields(String resourceId, List<CustomFieldResource> fields) {
super.batchEditFields(TABLE_NAME, resourceId, fields);
}
public int updateByPrimaryKeySelective(CustomFieldResource field) {
return super.updateByPrimaryKeySelective(TABLE_NAME, field);
}
public int insert(CustomFieldResource field) {
return super.insert(TABLE_NAME, field);
}
public void deleteByResourceId(String resourceId) {
super.deleteByResourceId(TABLE_NAME, resourceId);
}
public void deleteByResourceIds(List<String> resourceIds) {
super.deleteByResourceIds(TABLE_NAME, resourceIds);
}
public Map<String, List<CustomFieldDao>> getMapByResourceIds(List<String> resourceIds) {
return super.getMapByResourceIds(TABLE_NAME, resourceIds);
}
public List<CustomFieldResource> getByResourceId(String resourceId) {
return super.getByResourceId(TABLE_NAME, resourceId);
}
}

View File

@ -0,0 +1,350 @@
package io.metersphere.service;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.base.domain.CustomField;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.base.mapper.CustomFieldMapper;
import io.metersphere.base.mapper.ext.ExtBaseMapper;
import io.metersphere.base.mapper.ext.ExtCustomFieldResourceMapper;
import io.metersphere.base.mapper.ext.ExtIssuesMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.commons.constants.CustomFieldType;
import io.metersphere.commons.constants.IssuesManagePlatform;
import io.metersphere.commons.constants.TemplateConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.controller.request.customfield.CustomFieldResourceRequest;
import io.metersphere.dto.CustomFieldDao;
import io.metersphere.dto.CustomFieldItemDTO;
import io.metersphere.track.dto.CustomFieldResourceCompatibleDTO;
import org.apache.commons.collections.CollectionUtils;
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.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
@Service
@Transactional(rollbackFor = Exception.class)
public class CustomFieldResourceService {
@Resource
private SqlSessionFactory sqlSessionFactory;
@Lazy
@Resource
ProjectService projectService;
@Lazy
@Resource
WorkspaceService workspaceService;
@Resource
ExtTestCaseMapper extTestCaseMapper;
@Resource
ExtIssuesMapper extIssuesMapper;
@Resource
CustomFieldService customFieldService;
@Resource
ExtBaseMapper extBaseMapper;
@Resource
ExtCustomFieldResourceMapper extCustomFieldResourceMapper;
@Lazy
@Resource
SystemParameterService systemParameterService;
private int initCount = 0;
protected void addFields(String tableName, String resourceId, List<CustomFieldResource> addFields) {
if (CollectionUtils.isNotEmpty(addFields)) {
this.checkInit();
addFields.forEach(field -> {
createOrUpdateFields(tableName, resourceId, field);
});
}
}
protected void editFields(String tableName, String resourceId, List<CustomFieldResource> editFields) {
if (CollectionUtils.isNotEmpty(editFields)) {
this.checkInit();
editFields.forEach(field -> {
createOrUpdateFields(tableName, resourceId, field);
});
}
}
protected void batchEditFields(String tableName, String resourceId, List<CustomFieldResource> fields) {
if (CollectionUtils.isNotEmpty(fields)) {
this.checkInit();
SqlSession sqlSession = ServiceUtils.getBatchSqlSession();
ExtCustomFieldResourceMapper batchMapper = sqlSession.getMapper(ExtCustomFieldResourceMapper.class);
for (CustomFieldResource field : fields) {
long count = extCustomFieldResourceMapper.countFieldResource(tableName, resourceId, field.getFieldId());
if (count > 0) {
batchMapper.updateByPrimaryKeySelective(tableName, field);
} else {
batchMapper.insert(tableName, field);
}
}
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
}
private void createOrUpdateFields(String tableName, String resourceId, CustomFieldResource field) {
long count = extCustomFieldResourceMapper.countFieldResource(tableName, resourceId, field.getFieldId());
field.setResourceId(resourceId);
if (count > 0) {
extCustomFieldResourceMapper.updateByPrimaryKeySelective(tableName, field);
} else {
extCustomFieldResourceMapper.insert(tableName, field);
}
}
protected int updateByPrimaryKeySelective(String tableName, CustomFieldResource field) {
return extCustomFieldResourceMapper.updateByPrimaryKeySelective(tableName, field);
}
protected int insert(String tableName, CustomFieldResource field) {
return extCustomFieldResourceMapper.insert(tableName, field);
}
protected List<CustomFieldResource> getByResourceId(String tableName, String resourceId) {
return extCustomFieldResourceMapper.getByResourceId(tableName, resourceId);
}
protected List<CustomFieldResource> getByResourceIds(String tableName, List<String> resourceIds) {
if (CollectionUtils.isEmpty(resourceIds)) {
return new ArrayList<>();
}
return extCustomFieldResourceMapper.getByResourceIds(tableName, resourceIds);
}
protected Map<String, List<CustomFieldDao>> getMapByResourceIds(String tableName, List<String> resourceIds) {
if (CollectionUtils.isEmpty(resourceIds)) {
return new HashMap<>();
}
List<CustomFieldResource> customFieldResources = getByResourceIds(tableName, resourceIds);
Map<String, List<CustomFieldDao>> fieldMap = new HashMap<>();
customFieldResources.forEach(i -> {
List<CustomFieldDao> fields = fieldMap.get(i.getResourceId());
if (fields == null) {
fields = new ArrayList<>();
}
CustomFieldDao customFieldDao = new CustomFieldDao();
customFieldDao.setId(i.getFieldId());
customFieldDao.setValue(i.getValue());
customFieldDao.setTextValue(i.getTextValue());
fields.add(customFieldDao);
fieldMap.put(i.getResourceId(), fields);
});
return fieldMap;
}
protected void deleteByResourceId(String tableName, String resourceId) {
extCustomFieldResourceMapper.deleteByResourceId(tableName, resourceId);
}
protected void deleteByResourceIds(String tableName, List<String> resourceIds) {
extCustomFieldResourceMapper.deleteByResourceIds(tableName, resourceIds);
}
protected void checkInit() {
String value = systemParameterService.getValue("init.custom.field.resource");
if (StringUtils.isNotBlank(value) && value.equals("over")) {
return;
}
MSException.throwException("数据升级处理中,请稍后重试!");
}
/**
* 初始化数据
* 兼容旧数据
*/
public void compatibleData() {
LogUtil.info("init CustomFieldResourceService compatibleData start ===================");
List<String> projectIds = projectService.getProjectIds();
Map<String, CustomField> globalFieldMap = customFieldService.getGlobalNameMapByProjectId();
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ExtCustomFieldResourceMapper batchMapper = sqlSession.getMapper(ExtCustomFieldResourceMapper.class);
CustomFieldMapper customFieldBatchMapper = sqlSession.getMapper(CustomFieldMapper.class);
try {
CustomFieldResourceRequest param = new CustomFieldResourceRequest();
param.setGlobalFieldMap(globalFieldMap);
param.setSqlSession(sqlSession);
param.setBatchMapper(batchMapper);
param.setCustomFieldBatchMapper(customFieldBatchMapper);
projectIds.forEach(projectId -> {
param.setWdFieldMap(customFieldService.getNameMapByProjectId(projectId));
param.setJiraSyncFieldMap(new HashMap<>());
param.setProjectId(projectId);
compatibleTestCase(param);
Project project = projectService.getProjectById(projectId);
compatibleIssue(param, project);
});
sqlSession.flushStatements();
sqlSession.commit();
} catch (Exception e) {
LogUtil.error(e);
} finally {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
LogUtil.info("init CustomFieldResourceService compatibleData end ===================");
}
public void compatibleTestCase(CustomFieldResourceRequest param) {
param.setEnableJiraSync(false);
param.setResourceType(TemplateConstants.FieldTemplateScene.TEST_CASE.name());
this.compatibleCommon(param);
}
public void compatibleIssue( CustomFieldResourceRequest param, Project project) {
// 是否勾选了自动获取模板
boolean enableJiraSync = project.getPlatform().equals(IssuesManagePlatform.Jira.toString()) &&
(project.getThirdPartTemplate() == null ? false : project.getThirdPartTemplate() );
param.setEnableJiraSync(enableJiraSync);
param.setResourceType(TemplateConstants.FieldTemplateScene.ISSUE.name());
this.compatibleCommon(param);
}
/**
* 对旧数据做数据初始化
* 自定义字段不再存储在对应表的 customFields 字段
* 改为添加中间表
*/
protected void compatibleCommon(CustomFieldResourceRequest param) {
int pageNum = 1;
int pageSize = 1000;
List<CustomFieldResourceCompatibleDTO> list;
do {
if (param.getResourceType().equals(TemplateConstants.FieldTemplateScene.ISSUE.name())) {
list = extIssuesMapper.getForCompatibleCustomField(param.getProjectId(), (pageNum - 1) * pageSize, pageSize);
} else {
list = extTestCaseMapper.getForCompatibleCustomField(param.getProjectId(), (pageNum - 1) * pageSize, pageSize);
}
pageNum++;
if (CollectionUtils.isNotEmpty(list)) {
list.forEach(resource -> {
// 获取对应资源的自定义字段存入 CustomFieldResource
String customFields = resource.getCustomFields();
if (StringUtils.isNotBlank(customFields)) {
try {
List<CustomFieldItemDTO> fields = CustomFieldService.getCustomFields(customFields);
Set<String> fieldSet = new HashSet<>();
fields.forEach(field -> {
try {
CustomField customField;
if (StringUtils.isBlank(field.getName())) { return; }
if (param.isEnableJiraSync()) {
if (StringUtils.isBlank(field.getId()) || field.getId().length() == 36) {
// 自定义字段中id为空或者是uuid的就不处理了
return;
}
Map<String, CustomField> jiraSyncFieldMap = param.getJiraSyncFieldMap();
if (jiraSyncFieldMap.containsKey(field.getId())) {
customField = jiraSyncFieldMap.get(field.getId());
} else {
customField = createCustomField(param.getProjectId(), field, param);
param.getJiraSyncFieldMap().put(field.getId(), customField);
}
} else {
customField = Optional.ofNullable(param.getWdFieldMap().get(field.getName() + param.getResourceType()))
.orElse(param.getGlobalFieldMap().get(field.getName() + param.getResourceType()));
}
createCustomFieldResource(customField, fieldSet, resource, field, param);
} catch (Exception e) {
LogUtil.error(e);
}
});
} catch (Exception e) {
LogUtil.error(e);
}
}
});
}
} while (list.size() == pageSize);
}
/**
* 如果是jira勾选了自动获取模板
* 则创建对应的自定义字段并标记成 thirdPart true
* @param projectId
* @param field
* @param param
* @return
*/
private CustomField createCustomField(String projectId, CustomFieldItemDTO field, CustomFieldResourceRequest param) {
CustomField customField = new CustomField();
customField.setId(UUID.randomUUID().toString());
customField.setUpdateTime(System.currentTimeMillis());
customField.setCreateTime(System.currentTimeMillis());
customField.setGlobal(false);
customField.setSystem(false);
customField.setName(field.getId());
customField.setScene(TemplateConstants.FieldTemplateScene.ISSUE.name());
customField.setThirdPart(true);
customField.setType(field.getType());
customField.setProjectId(projectId);
CustomFieldMapper customFieldBatchMapper = param.getCustomFieldBatchMapper();
customFieldBatchMapper.insert(customField);
initCount++;
if (initCount > 1000) {
param.getSqlSession().flushStatements();
param.getSqlSession().commit();
initCount = 0;
}
return customField;
}
private void createCustomFieldResource(CustomField customField, Set<String> fieldSet, CustomFieldResourceCompatibleDTO resource,
CustomFieldItemDTO field, CustomFieldResourceRequest param) {
if (customField != null && field.getValue() != null) {
if (fieldSet.contains(customField.getId())) {
return;
}
String tableName;
if (param.getResourceType().equals(TemplateConstants.FieldTemplateScene.ISSUE.name())) {
tableName = "custom_field_issues";
} else {
tableName = "custom_field_test_case";
}
CustomFieldResource customFieldResource = new CustomFieldResource();
customFieldResource.setResourceId(resource.getId());
customFieldResource.setFieldId(customField.getId());
if (StringUtils.isNotBlank(customField.getType())
&& StringUtils.equalsAny(CustomFieldType.RICH_TEXT.getValue(), CustomFieldType.TEXTAREA.getValue())) {
customFieldResource.setTextValue(field.getValue().toString());
param.getBatchMapper().insert(tableName, customFieldResource);
} else {
if (field.getValue().toString().length() < 490) {
customFieldResource.setValue(JSONObject.toJSONString(field.getValue()));
param.getBatchMapper().insert(tableName, customFieldResource);
}
}
fieldSet.add(customField.getId());
initCount++;
if (initCount > 1000) {
param.getSqlSession().flushStatements();
param.getSqlSession().commit();
initCount = 0;
}
}
}
}

View File

@ -8,8 +8,11 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.CustomField;
import io.metersphere.base.domain.CustomFieldExample;
import io.metersphere.base.domain.CustomFieldTemplate;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.base.mapper.CustomFieldMapper;
import io.metersphere.base.mapper.CustomFieldTemplateMapper;
import io.metersphere.base.mapper.ext.ExtCustomFieldMapper;
import io.metersphere.commons.constants.CustomFieldType;
import io.metersphere.commons.constants.TemplateConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
@ -52,6 +55,8 @@ public class CustomFieldService {
@Lazy
@Resource
CustomFieldTemplateService customFieldTemplateService;
@Resource
private CustomFieldTemplateMapper customFieldTemplateMapper;
public String add(CustomField customField) {
checkExist(customField);
@ -59,6 +64,7 @@ public class CustomFieldService {
customField.setCreateTime(System.currentTimeMillis());
customField.setUpdateTime(System.currentTimeMillis());
customField.setGlobal(false);
customField.setThirdPart(false);
customField.setCreateUser(SessionUtils.getUserId());
customFieldMapper.insert(customField);
return customField.getId();
@ -91,6 +97,10 @@ public class CustomFieldService {
customFieldTemplateService.deleteByFieldId(id);
}
public CustomField get(String id) {
return customFieldMapper.selectByPrimaryKey(id);
}
public void update(CustomField customField) {
if (customField.getGlobal() != null && customField.getGlobal()) {
// 如果是全局字段则创建对应工作空间字段
@ -132,6 +142,7 @@ public class CustomFieldService {
CustomField customField = fieldMap.get(item.getFieldId());
BeanUtils.copyBean(customFieldDao, customField);
BeanUtils.copyBean(customFieldDao, item);
customFieldDao.setId(item.getFieldId());
result.add(customFieldDao);
});
}
@ -218,4 +229,98 @@ public class CustomFieldService {
}
return new ArrayList<>();
}
public List<CustomFieldResource> getCustomFieldResource(String customFieldsStr) {
List<CustomFieldResource> list = new ArrayList<>();
if (StringUtils.isNotBlank(customFieldsStr)) {
if (JSONObject.parse(customFieldsStr) instanceof JSONArray) {
List<CustomFieldItemDTO> fieldItems = JSONArray.parseArray(customFieldsStr, CustomFieldItemDTO.class);
for (CustomFieldItemDTO dto : fieldItems) {
// customFieldItemDTO里的id是模版ID
CustomFieldResource resource = new CustomFieldResource();
CustomFieldTemplate customFieldTemplate = customFieldTemplateMapper.selectByPrimaryKey(dto.getId());
if (customFieldTemplate == null) {
continue;
} else {
resource.setFieldId(customFieldTemplate.getFieldId());
}
if (StringUtils.isNotBlank(dto.getType())
&& StringUtils.equalsAny(CustomFieldType.RICH_TEXT.getValue(), CustomFieldType.TEXTAREA.getValue())) {
resource.setTextValue(dto.getValue().toString());
} else {
resource.setValue(JSONObject.toJSONString(dto.getValue()));
}
list.add(resource);
}
return list;
}
}
return new ArrayList<>();
}
public List<CustomFieldResource> getJiraCustomFieldResource(String customFieldsStr, String projectId) {
List<CustomFieldResource> list = new ArrayList<>();
if (StringUtils.isNotBlank(customFieldsStr)) {
if (JSONObject.parse(customFieldsStr) instanceof JSONArray) {
List<CustomFieldItemDTO> fieldItems = JSONArray.parseArray(customFieldsStr, CustomFieldItemDTO.class);
for (CustomFieldItemDTO dto : fieldItems) {
CustomFieldResource resource = new CustomFieldResource();
// customFieldItemDTO里的id是模版ID
CustomFieldTemplate customFieldTemplate = customFieldTemplateMapper.selectByPrimaryKey(dto.getId());
if (customFieldTemplate == null) {
CustomField customField = customFieldMapper.selectByPrimaryKey(dto.getId());
if (customField == null) {
CustomField field = new CustomField();
field.setId(dto.getId());
field.setUpdateTime(System.currentTimeMillis());
field.setCreateTime(System.currentTimeMillis());
field.setGlobal(false);
field.setSystem(false);
field.setName(dto.getName());
field.setScene(TemplateConstants.FieldTemplateScene.ISSUE.name());
field.setThirdPart(true);
field.setType(dto.getType());
field.setProjectId(projectId);
if (StringUtils.isNotBlank(SessionUtils.getUserId())) {
field.setCreateUser(SessionUtils.getUserId());
}
customFieldMapper.insert(field);
}
resource.setFieldId(dto.getId());
} else {
resource.setFieldId(customFieldTemplate.getFieldId());
}
if (StringUtils.isNotBlank(dto.getType())
&& StringUtils.equalsAny(CustomFieldType.RICH_TEXT.getValue(), CustomFieldType.TEXTAREA.getValue())) {
resource.setTextValue(dto.getValue().toString());
} else {
resource.setValue(JSONObject.toJSONString(dto.getValue()));
}
list.add(resource);
}
return list;
}
}
return new ArrayList<>();
}
public List<CustomField> getByProjectId(String projectId) {
CustomFieldExample example = new CustomFieldExample();
example.createCriteria().andProjectIdEqualTo(projectId);
return customFieldMapper.selectByExample(example);
}
public Map<String, CustomField> getNameMapByProjectId(String projectId) {
return this.getByProjectId(projectId)
.stream()
.collect(Collectors.toMap(i -> i.getName() + i.getScene(), i -> i, (val1, val2) -> val1));
}
public Map<String, CustomField> getGlobalNameMapByProjectId() {
CustomFieldExample example = new CustomFieldExample();
example.createCriteria().andGlobalEqualTo(true);
return customFieldMapper.selectByExample(example)
.stream()
.collect(Collectors.toMap(i -> i.getName() + i.getScene(), i -> i));
}
}

View File

@ -0,0 +1,48 @@
package io.metersphere.service;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.dto.CustomFieldDao;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Map;
@Service
@Transactional(rollbackFor = Exception.class)
public class CustomFieldTestCaseService extends CustomFieldResourceService {
private static final String TABLE_NAME = "custom_field_test_case";
public void addFields(String resourceId, List<CustomFieldResource> addFields) {
super.addFields(TABLE_NAME, resourceId, addFields);
}
public void editFields(String resourceId, List<CustomFieldResource> editFields) {
super.editFields(TABLE_NAME, resourceId, editFields);
}
public int updateByPrimaryKeySelective(CustomFieldResource field) {
return super.updateByPrimaryKeySelective(TABLE_NAME, field);
}
public int insert(CustomFieldResource field) {
return super.insert(TABLE_NAME, field);
}
public void deleteByResourceId(String resourceId) {
super.deleteByResourceId(TABLE_NAME, resourceId);
}
public void deleteByResourceIds(List<String> resourceIds) {
super.deleteByResourceIds(TABLE_NAME, resourceIds);
}
public Map<String, List<CustomFieldDao>> getMapByResourceIds(List<String> resourceIds) {
return super.getMapByResourceIds(TABLE_NAME, resourceIds);
}
public List<CustomFieldResource> getByResourceId(String resourceId) {
return super.getByResourceId(TABLE_NAME, resourceId);
}
}

View File

@ -759,6 +759,10 @@ public class ProjectService {
return extProjectMapper.getProjectIds();
}
public List<Project> getProjectForCustomField(String workspaceId) {
return extProjectMapper.getProjectForCustomField(workspaceId);
}
public Map<String, Project> queryNameByIds(List<String> ids) {
return extProjectMapper.queryNameByIds(ids);
}

View File

@ -329,4 +329,8 @@ public class WorkspaceService {
return resource;
}
public List<String> getWorkspaceIds() {
return extWorkspaceMapper.getWorkspaceIds();
}
}

View File

@ -122,7 +122,6 @@ public class TestCaseController {
@PostMapping("/relate/{goPage}/{pageSize}")
public Pager<List<TestCaseDTO>> getTestCaseRelateList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) {
// Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return testCaseService.getTestCaseRelateList(request, goPage, pageSize);
}
@ -177,7 +176,7 @@ public class TestCaseController {
}
@GetMapping("/get/{testCaseId}")
public TestCaseWithBLOBs getTestCase(@PathVariable String testCaseId) {
public TestCaseDTO getTestCase(@PathVariable String testCaseId) {
return testCaseService.getTestCase(testCaseId);
}

View File

@ -0,0 +1,9 @@
package io.metersphere.track.dto;
import lombok.Data;
@Data
public class CustomFieldResourceCompatibleDTO {
private String id;
private String customFields;
}

View File

@ -2,6 +2,7 @@ package io.metersphere.track.dto;
import io.metersphere.base.domain.IssuesDao;
import io.metersphere.base.domain.TestCaseWithBLOBs;
import io.metersphere.dto.CustomFieldDao;
import lombok.Getter;
import lombok.Setter;
@ -20,7 +21,7 @@ public class TestCaseDTO extends TestCaseWithBLOBs {
private String createName;
private String lastExecuteResult;
private String versionName;
private List<CustomFieldDao> fields;
private List<String> caseTags = new ArrayList<>();
private List<IssuesDao> issueList = new ArrayList<>();
}

View File

@ -70,7 +70,8 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
protected String userId;
protected String defaultCustomFields;
protected boolean isThirdPartTemplate;
protected CustomFieldIssuesService customFieldIssuesService;
protected CustomFieldService customFieldService;
public String getKey() {
return key;
@ -114,6 +115,8 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
this.extIssuesMapper = CommonBeanFactory.getBean(ExtIssuesMapper.class);
this.resourceService = CommonBeanFactory.getBean(ResourceService.class);
this.testCaseIssueService = CommonBeanFactory.getBean(TestCaseIssueService.class);
this.customFieldIssuesService = CommonBeanFactory.getBean(CustomFieldIssuesService.class);
this.customFieldService = CommonBeanFactory.getBean(CustomFieldService.class);
this.restTemplateIgnoreSSL = restTemplate;
}

View File

@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONObject;
import io.metersphere.base.domain.IssuesDao;
import io.metersphere.base.domain.IssuesWithBLOBs;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.commons.constants.CustomFieldType;
import io.metersphere.commons.constants.IssuesManagePlatform;
import io.metersphere.commons.constants.IssuesStatus;
@ -484,6 +485,10 @@ public class JiraPlatform extends AbstractIssuePlatform {
issues.forEach(item -> {
try {
getUpdateIssue(item, jiraClientV2.getIssues(item.getPlatformId()));
String customFields = item.getCustomFields();
// 把自定义字段存入新表
List<CustomFieldResource> customFieldResource = customFieldService.getJiraCustomFieldResource(customFields, project.getId());
customFieldIssuesService.addFields(item.getId(), customFieldResource);
issuesMapper.updateByPrimaryKeySelective(item);
} catch (HttpClientErrorException e) {
if (e.getRawStatusCode() == 404) {

View File

@ -213,6 +213,7 @@ public class TapdPlatform extends AbstractIssuePlatform {
IssuesWithBLOBs updateIssue = getUpdateIssue(issuesMapper.selectByPrimaryKey(id), bug, statusMap);
updateIssue.setId(id);
updateIssue.setCustomFields(syncIssueCustomField(updateIssue.getCustomFields(), bug));
customFieldIssuesService.addFields(id, customFieldService.getCustomFieldResource(updateIssue.getCustomFields()));
issuesMapper.updateByPrimaryKeySelective(updateIssue);
ids.remove(platformId);
});

View File

@ -4,13 +4,15 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import io.metersphere.base.domain.*;
import io.metersphere.base.domain.IssuesDao;
import io.metersphere.base.domain.IssuesExample;
import io.metersphere.base.domain.IssuesWithBLOBs;
import io.metersphere.base.domain.Project;
import io.metersphere.commons.constants.IssuesManagePlatform;
import io.metersphere.commons.constants.IssuesStatus;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.dto.UserDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.track.dto.DemandDTO;
import io.metersphere.track.issue.client.ZentaoClient;
import io.metersphere.track.issue.domain.PlatformUser;
@ -340,6 +342,7 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
IssuesWithBLOBs issue = issuesMapper.selectByPrimaryKey(item.getId());
JSONObject bug = zentaoClient.getBugById(item.getPlatformId());
issue = getUpdateIssues(issue, bug);
customFieldIssuesService.addFields(item.getId(), customFieldService.getCustomFieldResource(issue.getCustomFields()));
issue.setId(item.getId());
issuesMapper.updateByPrimaryKeySelective(issue);
});

View File

@ -1,7 +1,7 @@
package io.metersphere.track.request.testcase;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.TestCaseWithBLOBs;
import io.metersphere.base.domain.ext.CustomFieldResource;
import lombok.Getter;
import lombok.Setter;
@ -15,6 +15,8 @@ public class EditTestCaseRequest extends TestCaseWithBLOBs {
private List<String> follows;
private OtherInfoConfig otherInfoConfig;
private String oldDataId;
private List<CustomFieldResource> addFields;
private List<CustomFieldResource> editFields;
/**
* 复制测试用例后要进行复制的文件Id list
*/

View File

@ -1,6 +1,7 @@
package io.metersphere.track.request.testcase;
import io.metersphere.base.domain.IssuesWithBLOBs;
import io.metersphere.base.domain.ext.CustomFieldResource;
import lombok.Getter;
import lombok.Setter;
@ -13,6 +14,8 @@ public class IssuesUpdateRequest extends IssuesWithBLOBs {
private String workspaceId;
private List<String> tapdUsers;
private List<CustomFieldResource> addFields;
private List<CustomFieldResource> editFields;
/**
* zentao bug 处理人
*/

View File

@ -2,6 +2,7 @@ package io.metersphere.track.request.testcase;
import io.metersphere.base.domain.TestCaseWithBLOBs;
import io.metersphere.controller.request.OrderRequest;
import io.metersphere.dto.CustomFieldResourceDTO;
import lombok.Getter;
import lombok.Setter;
@ -13,7 +14,7 @@ public class TestCaseBatchRequest extends TestCaseWithBLOBs {
private List<String> ids;
private List<OrderRequest> orders;
private String projectId;
private CustomFiledRequest customField;
private CustomFieldResourceDTO customField;
private QueryTestCaseRequest condition;
private String customTemplateFieldId;

View File

@ -21,10 +21,7 @@ import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.track.TestPlanReference;
import io.metersphere.service.CustomFieldTemplateService;
import io.metersphere.service.IntegrationService;
import io.metersphere.service.IssueTemplateService;
import io.metersphere.service.ProjectService;
import io.metersphere.service.*;
import io.metersphere.track.dto.*;
import io.metersphere.track.issue.*;
import io.metersphere.track.issue.domain.PlatformUser;
@ -78,6 +75,10 @@ public class IssuesService {
private IssueFollowMapper issueFollowMapper;
@Resource
private TestPlanTestCaseMapper testPlanTestCaseMapper;
@Resource
private CustomFieldIssuesService customFieldIssuesService;
@Resource
private CustomFieldIssuesMapper customFieldIssuesMapper;
public void testAuth(String workspaceId, String platform) {
IssuesRequest issuesRequest = new IssuesRequest();
@ -99,6 +100,7 @@ public class IssuesService {
});
}
saveFollows(issuesRequest.getId(), issuesRequest.getFollows());
customFieldIssuesService.addFields(issuesRequest.getId(), issuesRequest.getAddFields());
return issues;
}
@ -109,6 +111,8 @@ public class IssuesService {
platformList.forEach(platform -> {
platform.updateIssue(issuesRequest);
});
customFieldIssuesService.editFields(issuesRequest.getId(), issuesRequest.getEditFields());
customFieldIssuesService.addFields(issuesRequest.getId(), issuesRequest.getAddFields());
// todo 缺陷更新事件
}
@ -178,15 +182,10 @@ public class IssuesService {
ZentaoPlatform zentaoPlatform = (ZentaoPlatform) IssueFactory.createPlatform(IssuesManagePlatform.Zentao.name(), issuesRequest);
zentaoPlatform.getZentaoAssignedAndBuilds(issuesWithBLOBs);
}
buildCustomField(issuesWithBLOBs);
return issuesWithBLOBs;
}
public String getPlatformsByCaseId(String caseId) {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(caseId);
Project project = projectService.getProjectById(testCase.getProjectId());
return getPlatform(project.getId());
}
public String getPlatform(String projectId) {
Project project = projectService.getProjectById(projectId);
return project.getPlatform();
@ -224,32 +223,6 @@ public class IssuesService {
return platforms;
}
private Project getProjectByCaseId(String testCaseId) {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
// testCase 不存在
if (testCase == null) {
return null;
}
return projectService.getProjectById(testCase.getProjectId());
}
private String getTapdProjectId(String testCaseId) {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
Project project = projectService.getProjectById(testCase.getProjectId());
return project.getTapdId();
}
private String getJiraProjectKey(String testCaseId) {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
Project project = projectService.getProjectById(testCase.getProjectId());
return project.getJiraKey();
}
private String getZentaoProjectId(String testCaseId) {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
Project project = projectService.getProjectById(testCase.getProjectId());
return project.getZentaoId();
}
/**
* 是否关联平台
@ -289,6 +262,7 @@ public class IssuesService {
testCaseIssueService.updateIssuesCount(i.getResourceId());
}
});
customFieldIssuesService.deleteByResourceId(id);
testCaseIssuesMapper.deleteByExample(example);
}
@ -374,9 +348,34 @@ public class IssuesService {
item.setCaseIds(new ArrayList<>(caseIdSet));
item.setCaseCount(caseIdSet.size());
});
buildCustomField(issues);
return issues;
}
private void buildCustomField(List<IssuesDao> data) {
if (CollectionUtils.isEmpty(data)) {
return;
}
Map<String, List<CustomFieldDao>> fieldMap =
customFieldIssuesService.getMapByResourceIds(data.stream().map(IssuesDao::getId).collect(Collectors.toList()));
data.forEach(i -> i.setFields(fieldMap.get(i.getId())));
}
private void buildCustomField(IssuesDao data) {
CustomFieldIssuesExample example = new CustomFieldIssuesExample();
example.createCriteria().andResourceIdEqualTo(data.getId());
List<CustomFieldIssues> customFieldTestCases = customFieldIssuesMapper.selectByExample(example);
List<CustomFieldDao> fields = new ArrayList<>();
customFieldTestCases.forEach(i -> {
CustomFieldDao customFieldDao = new CustomFieldDao();
customFieldDao.setId(i.getFieldId());
customFieldDao.setValue(i.getValue());
customFieldDao.setTextValue(i.getTextValue());
fields.add(customFieldDao);
});
data.setFields(fields);
}
private Map<String, String> getPlanMap(List<IssuesDao> issues) {
List<String> resourceIds = issues.stream().map(IssuesDao::getResourceId)
.filter(Objects::nonNull)

View File

@ -15,6 +15,7 @@ import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.api.service.ApiTestCaseService;
import io.metersphere.base.domain.*;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtIssuesMapper;
import io.metersphere.base.mapper.ext.ExtProjectVersionMapper;
@ -161,6 +162,10 @@ public class TestCaseService {
@Lazy
@Resource
private ProjectApplicationService projectApplicationService;
@Resource
private CustomFieldTestCaseMapper customFieldTestCaseMapper;
@Resource
private CustomFieldTestCaseService customFieldTestCaseService;
private ThreadLocal<Integer> importCreateNum = new ThreadLocal<>();
private ThreadLocal<Integer> beforeImportCreateNum = new ThreadLocal<>();
@ -212,6 +217,7 @@ public class TestCaseService {
testCaseMapper.insert(request);
saveFollows(request.getId(), request.getFollows());
customFieldTestCaseService.addFields(request.getId(), request.getAddFields());
return request;
}
@ -298,14 +304,12 @@ public class TestCaseService {
}
}
public List<TestCase> getTestCaseByNodeId(List<String> nodeIds) {
TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andNodeIdIn(nodeIds);
return testCaseMapper.selectByExample(testCaseExample);
}
public TestCaseWithBLOBs getTestCase(String testCaseId) {
return testCaseMapper.selectByPrimaryKey(testCaseId);
public TestCaseDTO getTestCase(String testCaseId) {
TestCaseWithBLOBs testCaseWithBLOBs = testCaseMapper.selectByPrimaryKey(testCaseId);
TestCaseDTO testCaseDTO = new TestCaseDTO();
BeanUtils.copyBean(testCaseDTO, testCaseWithBLOBs);
buildCustomField(testCaseDTO);
return testCaseDTO;
}
public TestCaseWithBLOBs editTestCase(EditTestCaseRequest testCase) {
@ -340,6 +344,9 @@ public class TestCaseService {
}
}
customFieldTestCaseService.editFields(testCase.getId(), testCase.getEditFields());
customFieldTestCaseService.addFields(testCase.getId(), testCase.getAddFields());
testCase.setLatest(null);
testCaseMapper.updateByPrimaryKeySelective(testCase);
@ -559,6 +566,7 @@ public class TestCaseService {
relateDelete(testCaseId);
relationshipEdgeService.delete(testCaseId); // 删除关系图
deleteFollows(testCaseId);
customFieldTestCaseService.deleteByResourceId(testCaseId); // 删除自定义字段关联关系
return testCaseMapper.deleteByPrimaryKey(testCaseId);
}
@ -616,10 +624,35 @@ public class TestCaseService {
} else {
buildProjectInfoWidthoutProject(list);
}
buildCustomField(list);
list = this.parseStatus(list);
return list;
}
private void buildCustomField(List<TestCaseDTO> data) {
if (CollectionUtils.isEmpty(data)) {
return;
}
Map<String, List<CustomFieldDao>> fieldMap =
customFieldTestCaseService.getMapByResourceIds(data.stream().map(TestCaseDTO::getId).collect(Collectors.toList()));
data.forEach(i -> i.setFields(fieldMap.get(i.getId())));
}
private void buildCustomField(TestCaseDTO data) {
CustomFieldTestCaseExample example = new CustomFieldTestCaseExample();
example.createCriteria().andResourceIdEqualTo(data.getId());
List<CustomFieldTestCase> customFieldTestCases = customFieldTestCaseMapper.selectByExample(example);
List<CustomFieldDao> fields = new ArrayList<>();
customFieldTestCases.forEach(i -> {
CustomFieldDao customFieldDao = new CustomFieldDao();
customFieldDao.setId(i.getFieldId());
customFieldDao.setValue(i.getValue());
customFieldDao.setTextValue(i.getTextValue());
fields.add(customFieldDao);
});
data.setFields(fields);
}
private void buildProjectInfoWidthoutProject(List<TestCaseDTO> resList) {
resList.forEach(i -> {
Project project = projectMapper.selectByPrimaryKey(i.getProjectId());
@ -1428,10 +1461,11 @@ public class TestCaseService {
StringBuilder result = new StringBuilder("");
Map<String, Map<String, String>> customSelectValueMap = new HashMap<>();
Map<String, String> customNameMap = new HashMap<>();
TestCaseTemplateService testCaseTemplateService = CommonBeanFactory.getBean(TestCaseTemplateService.class);
TestCaseTemplateDao testCaseTemplate = testCaseTemplateService.getTemplate(request.getProjectId());
List<CustomFieldDao> customFieldList = null;
List<CustomFieldDao> customFieldList;
if (testCaseTemplate == null) {
customFieldList = new ArrayList<>();
} else {
@ -1462,7 +1496,8 @@ public class TestCaseService {
} catch (Exception e) {
}
}
customSelectValueMap.put(dto.getName(), map);
customSelectValueMap.put(dto.getId(), map);
customNameMap.put(dto.getId(), dto.getName());
}
@ -1548,23 +1583,20 @@ public class TestCaseService {
}
data.setMaintainer(t.getMaintainer());
data.setStatus(t.getStatus());
String customFields = t.getCustomFields();
try {
JSONArray customFieldsArr = JSONArray.parseArray(customFields);
List<CustomFieldResource> fields = customFieldTestCaseService.getByResourceId(t.getId());
Map<String, String> map = new HashMap<>();
for (int index = 0; index < customFieldsArr.size(); index++) {
JSONObject obj = customFieldsArr.getJSONObject(index);
if (obj.containsKey("name") && obj.containsKey("value")) {
//进行key value对换
String name = obj.getString("name");
String value = obj.getString("value");
if (customSelectValueMap.containsKey(name)) {
if (customSelectValueMap.get(name).containsKey(value)) {
value = customSelectValueMap.get(name).get(value);
}
for (int index = 0; index < fields.size(); index++) {
CustomFieldResource field = fields.get(index);
//进行key value对换
String id = field.getFieldId();
String value = JSONObject.parse(field.getValue()).toString();
if (customSelectValueMap.containsKey(id)) {
if (customSelectValueMap.get(id).containsKey(value)) {
value = customSelectValueMap.get(id).get(value);
}
map.put(name, value);
}
map.put(customNameMap.get(id), value);
}
data.setCustomDatas(map);
} catch (Exception e) {
@ -1589,33 +1621,20 @@ public class TestCaseService {
if (request.getCustomField() != null) {
List<TestCaseWithBLOBs> testCases = extTestCaseMapper.getCustomFieldsByIds(ids);
testCases.forEach((testCase) -> {
String customFields = testCase.getCustomFields();
List<TestCaseBatchRequest.CustomFiledRequest> fields;
if (StringUtils.isBlank(customFields)) {
fields = new ArrayList<>();
CustomFieldResourceDTO customField = request.getCustomField();
if (StringUtils.equals(customField.getName(), "用例等级")) {
testCase.setPriority(JSONObject.parse(customField.getValue()).toString());
} else if (StringUtils.equals(request.getCustomField().getName(), "用例状态")) {
testCase.setStatus(JSONObject.parse(customField.getValue()).toString());
} else if (StringUtils.equals(customField.getName(), "责任人")) {
testCase.setMaintainer(JSONObject.parse(customField.getValue()).toString());
} else {
fields = JSONObject.parseArray(customFields, TestCaseBatchRequest.CustomFiledRequest.class);
}
boolean hasField = false;
for (TestCaseBatchRequest.CustomFiledRequest field : fields) {
if (StringUtils.equals(request.getCustomField().getName(), field.getName())) {
field.setValue(request.getCustomField().getValue());
hasField = true;
break;
customField.setResourceId(testCase.getId());
int row = customFieldTestCaseService.updateByPrimaryKeySelective(customField);
if (row < 1) {
customFieldTestCaseService.insert(customField);
}
}
if (!hasField) {
TestCaseBatchRequest.CustomFiledRequest customField = request.getCustomField();
customField.setId(request.getCustomTemplateFieldId());
customField.setName(request.getCustomField().getName());
customField.setValue(request.getCustomField().getValue());
fields.add(request.getCustomField());
}
if (StringUtils.equals(request.getCustomField().getName(), "用例等级")) {
testCase.setPriority((String) request.getCustomField().getValue());
}
testCase.setCustomFields(JSONObject.toJSONString(fields));
testCase.setUpdateTime(System.currentTimeMillis());
TestCaseExample example = new TestCaseExample();
example.createCriteria().andIdEqualTo(testCase.getId());
@ -1697,6 +1716,7 @@ public class TestCaseService {
deleteTestPlanTestCaseBath(request.getIds());
relationshipEdgeService.delete(request.getIds()); // 删除关系图
customFieldTestCaseService.deleteByResourceIds(request.getIds()); // 删除自定义字段
request.getIds().forEach(testCaseId -> { // todo 优化下效率
testCaseIssueService.delTestCaseIssues(testCaseId);
@ -1897,17 +1917,6 @@ public class TestCaseService {
List<TestCaseMinderEditRequest.TestCaseMinderEditItem> data = request.getData();
if (CollectionUtils.isNotEmpty(data)) {
List<String> editIds = data.stream()
.filter(TestCaseMinderEditRequest.TestCaseMinderEditItem::getIsEdit)
.map(TestCaseWithBLOBs::getId).collect(Collectors.toList());
Map<String, TestCaseWithBLOBs> testCaseMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(editIds)) {
TestCaseExample example = new TestCaseExample();
example.createCriteria().andIdIn(editIds);
List<TestCaseWithBLOBs> testCaseWithBLOBs = testCaseMapper.selectByExampleWithBLOBs(example);
testCaseMap = testCaseWithBLOBs.stream().collect(Collectors.toMap(TestCaseWithBLOBs::getId, t -> t));
}
for (TestCaseMinderEditRequest.TestCaseMinderEditItem item : data) {
if (StringUtils.isBlank(item.getNodeId()) || item.getNodeId().equals("root")) {
@ -1915,12 +1924,9 @@ public class TestCaseService {
}
item.setProjectId(request.getProjectId());
if (item.getIsEdit()) {
TestCaseWithBLOBs dbCase = testCaseMap.get(item.getId());
if (editCustomFieldsPriority(dbCase, item.getPriority())) {
item.setCustomFields(dbCase.getCustomFields());
}
EditTestCaseRequest editRequest = new EditTestCaseRequest();
BeanUtils.copyBean(editRequest, item);
editRequest.setCustomFields(null);
editTestCase(editRequest);
changeOrder(item, request.getProjectId());
} else {
@ -1949,29 +1955,6 @@ public class TestCaseService {
}
}
/**
* 脑图编辑之后修改用例等级同时修改自定义字段的用例等级
*
* @param dbCase
* @param priority
* @return
*/
private boolean editCustomFieldsPriority(TestCaseWithBLOBs dbCase, String priority) {
String customFields = dbCase.getCustomFields();
if (StringUtils.isNotBlank(customFields)) {
JSONArray fields = JSONObject.parseArray(customFields);
for (int i = 0; i < fields.size(); i++) {
JSONObject field = fields.getJSONObject(i);
if (field.getString("name").equals("用例等级")) {
field.put("value", priority);
dbCase.setCustomFields(JSONObject.toJSONString(fields));
return true;
}
}
}
return false;
}
public List<TestCase> getTestCaseByProjectId(String projectId) {
TestCaseExample example = new TestCaseExample();
example.createCriteria().andProjectIdEqualTo(projectId).andStatusNotEqualTo("Trash").andLatestEqualTo(true);

View File

@ -302,3 +302,7 @@ ALTER TABLE `api_scenario` ADD INDEX index_project_id ( `project_id`);
ALTER TABLE share_info ADD lang varchar(10) NULL;
UPDATE system_parameter SET param_value = 'http://local-selenium-grid:4444' WHERE param_key = 'base.selenium.docker.url';

View File

@ -3,9 +3,11 @@
<el-card class="table-card-nopadding" v-loading="result.loading">
<slot name="version"></slot>
<ms-table-search-bar :condition.sync="condition" @change="search" class="search-input"
:tip="$t('commons.search_by_id_name_tag')"/>
<ms-table-adv-search-bar :condition.sync="condition" @search="search" class="adv-search-bar"/>
<ms-search
:condition.sync="condition"
:base-search-tip="$t('commons.search_by_id_name_tag')"
@search="search">
</ms-search>
<ms-table
:data="tableData"
@ -330,6 +332,7 @@ import MsTableSearchBar from "@/business/components/common/components/MsTableSea
import MsTableAdvSearchBar from "@/business/components/common/components/search/MsTableAdvSearchBar";
import ListItemDeleteConfirm from "@/business/components/common/components/ListItemDeleteConfirm";
import {Message} from "element-ui";
import MsSearch from "@/business/components/common/components/search/MsSearch";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const relationshipGraphDrawer = requireComponent.keys().length > 0 ? requireComponent("./graph/RelationshipGraphDrawer.vue") : {};
@ -343,6 +346,7 @@ export default {
MsTable,
MsTableColumn,
HeaderLabelOperate,
MsSearch,
"relationshipGraphDrawer": relationshipGraphDrawer.default,
HeaderCustom: () => import("@/business/components/common/head/HeaderCustom"),
BatchMove: () => import("../../../track/case/components/BatchMove"),

View File

@ -10,12 +10,10 @@
<ms-environment-select :project-id="projectId" v-if="isTestPlan || isScript" :is-read-only="isReadOnly"
@setEnvironment="setEnvironment" ref="msEnvironmentSelect"/>
<el-input :placeholder="$t('commons.search_by_name_or_id')" @blur="initTable"
@keyup.enter.native="initTable" class="search-input" size="small" v-model="condition.name"/>
<ms-table-adv-search-bar :condition.sync="condition" class="adv-search-bar"
v-if="condition.components !== undefined && condition.components.length > 0"
@search="initTable"/>
<ms-search
:condition.sync="condition"
@search="initTable">
</ms-search>
<ms-table :data="tableData" :select-node-ids="selectNodeIds" :condition="condition" :page-size="pageSize"
:total="total" enableSelection
:screenHeight="screenHeight"
@ -110,6 +108,7 @@ import {_filter, _sort, buildBatchParam} from "@/common/js/tableUtils";
import MsTableAdvSearchBar from "@/business/components/common/components/search/MsTableAdvSearchBar";
import {TEST_PLAN_RELEVANCE_API_CASE_CONFIGS} from "@/business/components/common/components/search/search-components";
import {hasLicense} from "@/common/js/utils";
import MsSearch from "@/business/components/common/components/search/MsSearch";
export default {
name: "RelevanceCaseList",
@ -126,6 +125,7 @@ export default {
MsBatchEdit,
MsTable,
MsTableColumn,
MsSearch,
MsTableAdvSearchBar
},
data() {

View File

@ -1,10 +1,10 @@
<template>
<div>
<el-input :placeholder="$t('api_test.definition.request.select_case')" @blur="search"
@keyup.enter.native="search" class="search-input" size="small" v-model="condition.name"/>
<ms-table-adv-search-bar :condition.sync="condition" class="adv-search-bar"
v-if="condition.components !== undefined && condition.components.length > 0"
@search="search"/>
<ms-search
:base-search-tip="$t('api_test.definition.request.select_case')"
:condition.sync="condition"
@search="search">
</ms-search>
<version-select v-xpack :project-id="projectId" @changeVersion="changeVersion"
style="float: left"
class="search-input"/>
@ -95,6 +95,7 @@ import {ENV_TYPE} from "@/common/js/constants";
import {getCurrentProjectID, hasLicense} from "@/common/js/utils";
import MsTable from "@/business/components/common/components/table/MsTable";
import MsTag from "@/business/components/common/components/MsTag";
import MsSearch from "@/business/components/common/components/search/MsSearch";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./version/VersionSelect.vue") : {};
@ -111,6 +112,7 @@ export default {
MsTag,
MsApiReportDetail,
MsTableAdvSearchBar,
MsSearch,
'VersionSelect': VersionSelect.default,
},
props: {

View File

@ -1,11 +1,10 @@
<template>
<span>
<slot name="header"></slot>
<el-input :placeholder="$t('commons.search_by_name_or_id')" @blur="initTable" class="search-input" size="small"
@keyup.enter.native="initTable" v-model="condition.name"/>
<ms-table-adv-search-bar :condition.sync="condition" class="adv-search-bar"
v-if="condition.components !== undefined && condition.components.length > 0"
@search="initTable"/>
<ms-search
:condition.sync="condition"
@search="initTable">
</ms-search>
<ms-table :data="tableData" :select-node-ids="selectNodeIds" :condition="condition" :page-size="pageSize"
:total="total" enableSelection @selectCountChange="selectCountChange"
@ -119,6 +118,7 @@ import {getProtocolFilter} from "@/business/components/api/definition/api-defini
import {getProjectMember} from "@/network/user";
import TableSelectCountBar from "@/business/components/api/automation/scenario/api/TableSelectCountBar";
import {hasLicense} from "@/common/js/utils";
import MsSearch from "@/business/components/common/components/search/MsSearch";
export default {
name: "ApiTableList",
@ -135,7 +135,8 @@ export default {
MsBatchEdit,
MsTable,
MsTableColumn,
MsTableAdvSearchBar
MsTableAdvSearchBar,
MsSearch
},
data() {
return {

View File

@ -4,9 +4,11 @@
<div class="ms-opt-btn" v-if="apiDefinitionId && versionEnable">
{{ $t('project.version.name') }}: {{ apiDefinition.versionName }}
</div>
<el-input :placeholder="$t('commons.search_by_id_name_tag')" @change="search"
class="search-input" size="small"
v-model="condition.name"/>
<ms-search
:condition.sync="condition"
:base-search-tip="$t('commons.search_by_id_name_tag')"
@search="search">
</ms-search>
<el-button type="primary" style="float: right;margin-right: 10px" icon="el-icon-plus" size="small"
@click="addTestCase" v-if="apiDefinitionId">{{ $t('commons.add') }}
</el-button>
@ -222,8 +224,6 @@
<ms-set-environment ref="setEnvironment" :testCase="clickRow" @createPerformance="createPerformance"/>
<!--查看引用-->
<ms-reference-view ref="viewRef"/>
<!--高级搜索-->
<ms-table-adv-search-bar :condition.sync="condition" :showLink="false" ref="searchBar" @search="initTable"/>
<ms-task-center ref="taskCenter" :show-menu="false"/>
@ -285,6 +285,7 @@ import MsRequestResultTail from "../../../../api/definition/components/response/
import {editApiTestCaseOrder} from "@/network/api";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
import i18n from "@/i18n/i18n";
import MsSearch from "@/business/components/common/components/search/MsSearch";
export default {
name: "ApiCaseSimpleList",
@ -311,6 +312,7 @@ export default {
MsTableColumn,
MsRequestResultTail,
MsApiCaseRunModeWithEnv,
MsSearch,
PlanStatusTableItem: () => import("../../../../track/common/tableItems/plan/PlanStatusTableItem"),
MsTaskCenter: () => import("@/business/components/task/TaskCenter"),
},

View File

@ -1,12 +1,12 @@
<template>
<span>
<span>
<el-input :placeholder="$t('commons.search_by_id_name_tag_path')" @blur="search" class="search-input" size="small"
@keyup.enter.native="enterSearch"
v-model="condition.name" ref="inputVal"/>
<el-link type="primary" @click="open" style="float: right;margin-top: 5px;padding-right: 10px">
{{ $t('commons.adv_search.title') }}
</el-link>
<ms-search
:condition.sync="condition"
:base-search-tip="$t('commons.search_by_id_name_tag_path')"
:base-search-width="260"
@search="search">
</ms-search>
<ms-table
:data="tableData" :select-node-ids="selectNodeIds" :condition="condition" :page-size="pageSize"
@ -248,6 +248,7 @@ import {editApiDefinitionOrder} from "@/network/api";
import {getProtocolFilter} from "@/business/components/api/definition/api-definition";
import {getGraphByCondition} from "@/network/graph";
import ListItemDeleteConfirm from "@/business/components/common/components/ListItemDeleteConfirm";
import MsSearch from "@/business/components/common/components/search/MsSearch";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const relationshipGraphDrawer = requireComponent.keys().length > 0 ? requireComponent("./graph/RelationshipGraphDrawer.vue") : {};
@ -275,6 +276,7 @@ export default {
MsTableAdvSearchBar,
MsTable,
MsTableColumn,
MsSearch,
"relationshipGraphDrawer": relationshipGraphDrawer.default,
},
data() {

View File

@ -23,8 +23,12 @@
</span>
<span>
<slot name="searchBarBefore"></slot>
<ms-table-search-bar :condition.sync="condition" @change="search" class="search-bar" :tip="tip" v-if="haveSearch"/>
<ms-table-adv-search-bar :condition.sync="condition" @search="search" v-if="isCombine" ref="searchBar"/>
<ms-search
:base-search-tip="tip"
:condition.sync="condition"
:show-base-search="haveSearch"
@search="search">
</ms-search>
</span>
</el-row>
</div>
@ -36,13 +40,14 @@
import MsTableButton from './MsTableButton';
import MsTableAdvSearchBar from "./search/MsTableAdvSearchBar";
import {getCurrentProjectID} from "@/common/js/utils";
import MsSearch from "@/business/components/common/components/search/MsSearch";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./version/VersionSelect.vue") : {};
export default {
name: "MsTableHeader",
components: {MsTableAdvSearchBar, MsTableSearchBar, MsTableButton,'VersionSelect': VersionSelect.default},
components: {MsTableAdvSearchBar, MsTableSearchBar, MsTableButton,'VersionSelect': VersionSelect.default, MsSearch},
data() {
return {
version:this.currentVersion

View File

@ -0,0 +1,77 @@
<template>
<div style="float: right;">
<ms-table-search-bar
v-if="showBaseSearch"
:condition.sync="condition"
:style="{width: baseSearchWidth + 'px'}"
:tip="baseSearchTip"
@change="search"/>
<ms-table-adv-search-bar
:show-link="showAdvSearchLink"
:condition.sync="condition"
@search="search"
class="ms-adv-search"
ref="advSearch"/>
</div>
</template>
<script>
import MsTableSearchBar from "@/business/components/common/components/MsTableSearchBar";
import MsTableAdvSearchBar from "@/business/components/common/components/search/MsTableAdvSearchBar";
export default {
name: "MsSearch",
components: {
MsTableSearchBar,
MsTableAdvSearchBar
},
props: {
condition: {
type: Object,
default() {
return {};
}
},
baseSearchTip: {
type: String,
default() {
return this.$t('commons.search_by_name_or_id');
}
},
showBaseSearch: {
type: Boolean,
default() {
return true;
}
},
baseSearchWidth: {
type: Number,
default() {
return 240;
}
}
},
computed: {
showAdvSearchLink() {
return this.condition.components !== undefined && this.condition.components.length > 0;
},
},
methods: {
search() {
this.$emit("search");
},
resetAdvSearch() {
if (this.$refs.advSearch) {
this.$refs.advSearch.reset();
}
}
}
}
</script>
<style scoped>
.ms-adv-search {
margin-left: 5px;
margin-right: 5px;
}
</style>

View File

@ -1,18 +1,27 @@
<template>
<span class="adv-search-bar">
<el-link type="primary" @click="open" v-if="showLink">{{$t('commons.adv_search.title')}}</el-link>
<el-dialog :title="$t('commons.adv_search.combine')" :visible.sync="visible" custom-class="adv-dialog"
:append-to-body="true">
<div>
<div class="search-items">
<component class="search-item" v-for="(component, index) in config.components" :key="index"
:is="component.name" :component="component"/>
<el-link type="primary" @click="open" v-if="showLink">{{ $t('commons.adv_search.title') }}</el-link>
<el-dialog :title="$t('commons.adv_search.title')" :visible.sync="visible"
custom-class="adv-dialog" :append-to-body="true">
<div class="search-items">
<div class="search-item" v-for="(component) in optional.components" :key="component.key">
<el-row>
<el-col :span="22">
<component :is="component.name" :component="component" :components.sync="config.components"
@updateKey="changeSearchItemKey" :custom="condition.custom"/>
</el-col>
<el-col :span="2">
<i class="el-icon-close delete-icon" @click="remove(component)"></i>
</el-col>
</el-row>
</div>
<el-link type="primary" icon="el-icon-plus" v-if="showAddFilterLink"
class="add-filter-link" @click="addFilter">添加筛选条件</el-link>
</div>
<template v-slot:footer>
<div class="dialog-footer">
<el-button @click="reset">{{$t('commons.adv_search.reset')}}</el-button>
<el-button type="primary" @click="search">{{$t('commons.adv_search.search')}}</el-button>
<el-button @click="reset">{{ $t('commons.adv_search.reset') }}</el-button>
<el-button type="primary" @click="search">{{ $t('commons.adv_search.search') }}</el-button>
</div>
</template>
</el-dialog>
@ -20,137 +29,265 @@
</template>
<script>
import components from "./search-components";
import {cloneDeep} from "lodash";
import components from "./search-components";
import {cloneDeep, slice, concat} from "lodash";
import {_findByKey, _findIndexByKey} from "@/business/components/common/components/search/custom-component";
export default {
components: {...components},
name: "MsTableAdvSearchBar",
props: {
condition: Object,
showLink: {
type: Boolean,
default: true,
}
export default {
components: {...components},
name: "MsTableAdvSearchBar",
props: {
condition: Object,
showLink: {
type: Boolean,
default: true,
},
data() {
return {
visible: false,
config: this.init()
showItemSize: {
type: Number,
default() {
return 4; //
}
},
methods: {
init() {
let config = cloneDeep(this.condition);
config.components.forEach(component => {
let operator = component.operator.value;
component.operator.value = operator === undefined ? component.operator.options[0].value : operator;
})
}
},
data() {
return {
visible: false,
config: {
components: []
},
optional: {
components: []
},
showAddFilterLink: true,
nullFilterKey: '',
isInit: false,
}
},
methods: {
doInit(handleCustom) {
let config = cloneDeep(this.condition);
config.components.forEach(component => {
let operator = component.operator.value;
component.operator.value = operator === undefined ? component.operator.options[0].value : operator;
})
if (!handleCustom) {
return config;
},
search() {
let condition = {}
this.config.components.forEach(component => {
let operator = component.operator.value;
let value = component.value;
if (Array.isArray(value)) {
if (value.length > 0) {
condition[component.key] = {
operator: operator,
value: value
}
}
} else {
if (value !== undefined && value !== null && value !== "") {
condition[component.key] = {
operator: operator,
value: value
}
}
}
if (this.condition.custom) {
let components = [];
this.systemFiled = config.components.filter(co => co.custom === undefined || false);
this.customFiled = config.components.filter(co => co.custom === true);
//
this.$set(components, 0, {label: "系统字段", child: this.systemFiled});
this.$set(components, 1, {label: "自定义字段", child: this.customFiled});
this.$set(config, "components", components);
}
return config;
},
search() {
let condition = {}
this.optional.components.forEach(component => {
let value = component.value;
if (Array.isArray(value)) {
if (value.length > 0) {
this.setCondition(condition, component);
}
});
} else {
if (value !== undefined && value !== null && value !== "") {
this.setCondition(condition, component);
}
}
});
// name
if (this.condition.name) this.condition.name = undefined;
//
this.condition.combine = condition;
this.$emit('update:condition', this.condition);
this.$emit('search', condition);
this.visible = false;
},
reset() {
let source = this.condition.components;
this.config.components.forEach((component, index) => {
if (component.operator.value !== undefined) {
let operator = source[index].operator.value;
component.operator.value = operator === undefined ? component.operator.options[0].value : operator;
}
if (component.value !== undefined) {
component.value = source[index].value;
}
})
this.condition.combine = undefined;
this.$emit('update:condition', this.condition);
this.$emit('search');
},
open() {
this.visible = true;
// name
if (this.condition.name) this.condition.name = undefined;
//
this.condition.combine = condition;
this.$emit('update:condition', this.condition);
this.$emit('search', condition);
this.visible = false;
},
setCondition(condition, component) {
if (!component.custom) {
condition[component.key] = {
operator: component.operator.value,
value: component.value
};
} else {
if (!condition.customs) {
condition['customs'] = [];
}
condition['customs'].push({
id: component.key,
operator: component.operator.value,
value: component.value
});
}
},
reset() {
let source = this.condition.components;
this.optional.components.forEach((component, index) => {
if (component.operator.value !== undefined) {
let operator = _findByKey(source, component.key).operator.value;
component.operator.value = operator === undefined ? component.operator.options[0].value : operator;
}
if (component.value !== undefined) {
component.value = source[index].value;
}
})
this.condition.combine = undefined;
this.$emit('update:condition', this.condition);
this.$emit('search');
},
init() {
this.config = this.doInit(true);
this.optional = this.doInit();
if (this.optional.components.length && this.optional.components.length <= this.showItemSize) {
this.showAddFilterLink = false;
}
//
this.optional.components = slice(this.optional.components, 0, this.showItemSize);
const all = concat(this.config.components[0].child, this.config.components[1].child);
let allComponent = this.condition.custom ? all : this.config.components;
for (let component of allComponent) {
let co = _findByKey(this.optional.components, component.key);
co ? this.$set(co, 'disable', true) : this.$set(component, 'disable', false);
}
},
open() {
this.visible = true;
if (!this.isInit) {
this.isInit = true;
this.init();
}
},
addFilter() {
const index = _findIndexByKey(this.optional.components, this.nullFilterKey);
if (index > -1) {
this.$warning("有为空的查询条件,请先选择!")
return;
}
let data = {
key: this.nullFilterKey,
name: 'MsTableSearchInput',
label: '',
operator: {
options: []
},
disable: false
};
this.optional.components.push(data);
},
remove(component) {
this.showAddFilterLink = true;
if (!this.condition.custom) {
this.enableOptional(component, this.config.components);
} else {
//
const components = concat(this.config.components[0].child, this.config.components[1].child);
this.enableOptional(component, components);
}
let index = _findIndexByKey(this.optional.components, component.key);
if (index !== -1) {
this.optional.components.splice(index, 1);
}
},
enableOptional(component, components) {
let data = _findByKey(components, component.key);
if (data) {
this.$set(data, 'disable', false);
}
},
//
changeSearchItemKey(newData, oldData) {
let key = oldData ? oldData.key : this.nullFilterKey;
const index = _findIndexByKey(this.optional.components, key);
this.optional.components.splice(index, 1, newData);
this.showAddFilterLink = false;
let components = [];
if (!this.condition.custom) {
components = this.config.components;
} else {
components = concat(this.config.components[0].child, this.config.components[1].child);
}
for (let op of components) {
if (op.disable !== undefined && op.disable === false) {
this.showAddFilterLink = true;
break;
}
}
}
}
}
</script>
<style>
@media only screen and (min-width: 1870px) {
.el-dialog.adv-dialog {
width: 70%;
}
@media only screen and (min-width: 1870px) {
.el-dialog.adv-dialog {
width: 70%;
}
}
@media only screen and (min-width: 1650px) and (max-width: 1869px) {
.el-dialog.adv-dialog {
width: 80%;
}
@media only screen and (min-width: 1650px) and (max-width: 1869px) {
.el-dialog.adv-dialog {
width: 80%;
}
}
@media only screen and (min-width: 1470px) and (max-width: 1649px) {
.el-dialog.adv-dialog {
width: 90%;
}
@media only screen and (min-width: 1470px) and (max-width: 1649px) {
.el-dialog.adv-dialog {
width: 90%;
}
}
@media only screen and (max-width: 1469px) {
.el-dialog.adv-dialog {
width: 70%;
min-width: 695px;
}
@media only screen and (max-width: 1469px) {
.el-dialog.adv-dialog {
width: 70%;
min-width: 695px;
}
}
</style>
<style scoped>
.dialog-footer {
text-align: center;
}
.dialog-footer {
text-align: center;
}
.search-items {
.search-items {
width: 100%;
}
@media only screen and (max-width: 1469px) {
.search-item {
width: 100%;
}
}
@media only screen and (max-width: 1469px) {
.search-item {
width: 100%;
}
}
@media only screen and (min-width: 1470px) {
.search-item {
width: 50%;
}
}
@media only screen and (min-width: 1470px) {
.search-item {
display: inline-block;
margin-top: 10px;
width: 50%;
}
}
.search-item {
display: inline-block;
margin-top: 10px;
}
.delete-icon {
font-size: 17px;
margin-top: 8px;
}
.delete-icon:hover {
cursor: pointer;
}
.add-filter-link {
position: absolute;
left: 25px;
bottom: 50px;
}
</style>

View File

@ -1,6 +1,32 @@
<template>
<div>
<div class="search-label">{{$t(component.label)}}</div>
<el-select class="search-label" v-model="selectKey" v-if="!custom"
filterable placeholder="请选择" size="small">
<el-option
v-for="item in components"
:disabled="item.disable !== undefined ? item.disable : true"
:key="item.key"
:label="$t(item.label)"
:value="item.key">
<span style="float: left">{{ $t(item.label) }}</span>
</el-option>
</el-select>
<el-select class="search-label" v-model="selectKey" v-else
filterable placeholder="请选择" size="small">
<el-option-group
v-for="group in components"
:key="group.key"
:label="$t(group.label)">
<el-option
v-for="item in group.child"
:key="item.key"
:label="$t(item.label)"
:disabled="item.disable !== undefined ? item.disable : true"
:value="item.key">
<span style="float: left">{{ $t(item.label) }}</span>
</el-option>
</el-option-group>
</el-select>
<el-select class="search-operator" v-model="component.operator.value" :placeholder="$t('commons.please_select')"
size="small"
@ -15,53 +41,88 @@
</template>
<script>
export default {
name: "MsTableSearchComponent",
props: ['component'],
data() {
return {
operators: this.component.operator.options || [],
import {concat} from "lodash";
import {_findByKey} from "@/business/components/common/components/search/custom-component";
export default {
name: "MsTableSearchComponent",
props: ['component', 'components', 'custom'],
data() {
return {
operators: this.component.operator.options || [],
selectKey: this.component.key
}
},
watch: {
selectKey(newVal, oldVal) {
this.componentTypeChange(newVal, oldVal);
}
},
methods: {
componentTypeChange(newVal, oldVal) {
let components = undefined;
if (!this.custom) {
components = this.enableOrDisableOptional(newVal, oldVal, this.components)
} else {
const array = concat(this.components[0].child, this.components[1].child);
components = this.enableOrDisableOptional(newVal, oldVal, array);
}
this.$emit("update:components", this.components);
this.$emit("updateKey", ...components);
},
methods: {
change(value) {
if (this.component.operator.change) {
this.component.operator.change(this.component, value)
enableOrDisableOptional(newVal, oldVal, options) {
//
const oldComponent = _findByKey(options, oldVal);
if (oldVal) {
if (oldComponent) {
this.$set(oldComponent, 'disable', false);
}
this.$emit('change', value);
},
input(value) {
this.$emit('input', value);
}
const newComponent = _findByKey(options, newVal);
if (newVal || newComponent) {
this.$set(newComponent, 'disable', true);
}
return [newComponent, oldComponent];
},
computed: {
showContent() {
if (this.component.isShow) {
return this.component.isShow(this.component.operator.value);
}
return true;
change(value) {
if (this.component.operator.change) {
this.component.operator.change(this.component, value)
}
this.$emit('change', value);
},
input(value) {
this.$emit('input', value);
}
},
computed: {
showContent() {
if (this.component.isShow) {
return this.component.isShow(this.component.operator.value);
}
return true;
}
}
}
</script>
<style scoped>
.search-label {
display: inline-block;
width: 120px;
box-sizing: border-box;
padding-left: 5px;
}
.search-label {
display: inline-block;
width: 125px;
box-sizing: border-box;
padding-left: 5px;
margin-right: 8px;
}
.search-operator {
display: inline-block;
width: 120px;
}
.search-operator {
display: inline-block;
width: 125px;
}
.search-content {
display: inline-block;
padding: 0 5px 0 10px;
width: calc(100% - 240px);
box-sizing: border-box;
}
.search-content {
display: inline-block;
padding: 0 5px 0 8px;
width: calc(100% - 260px);
box-sizing: border-box;
}
</style>

View File

@ -1,10 +1,12 @@
<template>
<ms-table-search-component v-model="component.operator.value" :component="component">
<ms-table-search-component v-model="component.operator.value" :component="component" v-bind="$attrs"
v-on="$listeners">
<template v-slot="scope">
<el-date-picker
v-model="scope.component.value" v-bind="scope.component.props"
:placeholder="$t('commons.date.select_date')" size="small"
:type="type" :key="type" value-format="timestamp"
class="ms-el-date-picker"
:range-separator="$t('commons.date.range_separator')"
:start-placeholder="$t('commons.date.start_date')"
:end-placeholder="$t('commons.date.end_date')">
@ -15,38 +17,42 @@
</template>
<script>
import MsTableSearchComponent from "./MsTableSearchComponet";
import {OPERATORS} from "./search-components"
import MsTableSearchComponent from "./MsTableSearchComponet";
import {OPERATORS} from "./search-components"
export default {
name: "MsTableSearchDatePicker",
components: {MsTableSearchComponent},
props: ['component'],
methods: {
change(value) {
if (value === OPERATORS.BETWEEN.value) {
if (!Array.isArray(this.component.value)) {
this.component.value = [];
}
} else {
if (Array.isArray(this.component.value)) {
this.component.value = "";
}
export default {
name: "MsTableSearchDatePicker",
components: {MsTableSearchComponent},
props: ['component'],
inheritAttrs: false,
methods: {
change(value) {
if (value === OPERATORS.BETWEEN.value) {
if (!Array.isArray(this.component.value)) {
this.component.value = [];
}
}
},
computed: {
type() {
if (this.component.operator.value === OPERATORS.BETWEEN.value) {
return "daterange";
} else {
return "date";
} else {
if (Array.isArray(this.component.value)) {
this.component.value = "";
}
}
}
},
computed: {
type() {
if (this.component.operator.value === OPERATORS.BETWEEN.value) {
return "daterange";
} else {
return "date";
}
}
}
}
</script>
<style scoped>
.ms-el-date-picker >>> .el-date-editor, .el-range-editor.el-input__inner,
.el-date-editor--daterange {
width: 100%;
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<ms-table-search-component v-model="component.operator.value" :component="component" @change="change">
<ms-table-search-component v-model="component.operator.value" :component="component" @change="change" v-bind="$attrs" v-on="$listeners">
<template v-slot="scope">
<el-date-picker v-model="scope.component.value" v-bind="scope.component.props"
:placeholder="$t('commons.date.select_date_time')" size="small"
@ -22,6 +22,7 @@
name: "MsTableSearchDateTimePicker",
components: {MsTableSearchComponent},
props: ['component'],
inheritAttrs: false,
methods: {
change(value) {
if (value === OPERATORS.BETWEEN.value) {

View File

@ -1,5 +1,5 @@
<template>
<ms-table-search-component v-model="component.operator.value" :component="component">
<ms-table-search-component v-model="component.operator.value" :component="component" v-bind="$attrs" v-on="$listeners">
<template v-slot="scope">
<el-input v-model="scope.component.value" v-bind="props"
:placeholder="$t('commons.input_content')" size="small"/>
@ -13,6 +13,7 @@
export default {
name: "MsTableSearchInput",
components: {MsTableSearchComponent},
inheritAttrs: false,
props: ['component'],
data() {
return {

View File

@ -1,5 +1,5 @@
<template>
<ms-table-search-component v-model="component.operator.value" :component="component">
<ms-table-search-component v-model="component.operator.value" :component="component" v-bind="$attrs" v-on="$listeners">
<template v-slot="scope">
<el-select v-model="scope.component.value" :placeholder="$t('commons.please_select')" size="small"
filterable v-bind="scope.component.props" class="search-select">
@ -16,6 +16,7 @@
name: "MsTableSearchSelect",
components: {MsTableSearchComponent},
props: ['component'],
inheritAttrs: false,
data() {
return {
options: !(this.component.options instanceof Array) ? [] : this.component.options || []

View File

@ -0,0 +1,127 @@
import {OPERATORS} from "@/business/components/common/components/search/search-components";
export function getAdvSearchCustomField(componentArr, fields) {
const components = [];
for (let field of fields) {
let index = componentArr.findIndex(a => a.key === field.id);
if (index > -1) {
continue;
}
const componentType = getComponentName(field.type);
let component = {
key: field.id,
name: componentType,
label: field.name,
operator: getComponentOperator(componentType, field.type, false), // 自定义字段可以异步获取选项?
options: getComponentOptions(field),
custom: true,
}
// 作为搜索条件时,可以多选
if (componentType === 'MsTableSearchSelect') {
component['props'] = {
multiple: true
}
}
components.push(component);
}
return components;
}
function getComponentOptions(field) {
const fieldOptions = field.options ? field.options : [];
let type = field.type;
let options = [];
if (fieldOptions.length === 0 && field.type !== 'member' && field.type !== 'multipleMember') {
return options;
}
if (type === 'member' || type === 'multipleMember') {
options = { // 异步获取候选项
url: "/user/list",
labelKey: "name",
valueKey: "id",
showLabel: option => {
return option.label + "(" + option.value + ")";
}
}
}
for (let option of fieldOptions) {
let temp = {
value: option.value,
label: option.text
}
options.push(temp);
}
return options;
}
function getComponentName(type) {
switch (type) {
case 'input':
case 'textarea':
case 'richText':
return 'MsTableSearchInput';
case 'select':
case 'multipleSelect':
case 'radio':
case 'checkbox':
case 'member':
case 'multipleMember':
return 'MsTableSearchSelect';
case 'date':
return 'MsTableSearchDatePicker';
case 'datetime':
return 'MsTableSearchDateTimePicker';
case 'int':
case 'float':
case 'multipleInput':
return 'MsTableSearchInput'; // todo 创建对应组件
default:
return 'MsTableSearchInput';
}
}
function getComponentOperator(componentType, fieldType, async) {
let operator = {};
switch (componentType) {
case 'MsTableSearchInput':
operator = { // 运算符设置
value: OPERATORS.LIKE.value, // 如果未设置value初始值则value初始值为options[0]
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE] // 运算符候选项
}
break;
case 'MsTableSearchSelect':
if (async || fieldType === 'member' || fieldType === 'multipleMember') {
operator = {
options: [OPERATORS.IN, OPERATORS.NOT_IN, OPERATORS.CURRENT_USER],
//todo
change: function (component, value) { // 运算符change事件
if (value === OPERATORS.CURRENT_USER.value) {
component.value = value;
}
}
}
} else {
operator = {
options: [OPERATORS.IN, OPERATORS.NOT_IN]
}
}
break;
case 'MsTableSearchDatePicker':
case 'MsTableSearchDateTimePicker':
operator = {
options: [OPERATORS.BETWEEN, OPERATORS.GT, OPERATORS.GE, OPERATORS.LT, OPERATORS.LE, OPERATORS.EQ]
}
break;
}
return operator;
}
export function _findByKey(components, key) {
return components.find(co => co.key === key);
}
export function _findIndexByKey(components, key) {
return components.findIndex(co => co.key === key);
}

View File

@ -572,6 +572,25 @@ export const PLAN_CASE_STATUS = {
}
}
export const PLATFORM = {
key: "platform",
name: 'MsTableSearchSelect',
label: "所属平台",
operator: {
options: [OPERATORS.IN, OPERATORS.NOT_IN]
},
options: [
{label: "Tapd", value: "Tapd"},
{label: "Jira", value: "Jira"},
{label: "Zentao", value: "Zentao"},
{label: "Local", value: "Local"},
],
props: {
multiple: true
}
}
export const TEST_CONFIGS = [NAME, UPDATE_TIME, CREATE_TIME, STATUS, CREATOR];
export const PROJECT_CONFIGS = [NAME, UPDATE_TIME, CREATE_TIME, CREATOR];
@ -608,3 +627,10 @@ export const TEST_PLAN_RELEVANCE_LOAD_CASE= [NAME, STATUS, CREATE_TIME, UPDATE_T
export const TEST_CASE_RELEVANCE_API_CASE_CONFIGS = [NAME, API_CASE_PRIORITY, API_TAGS, CREATOR];
export const TEST_CASE_RELEVANCE_API_SCENARIO_CONFIGS = [NAME, API_CASE_PRIORITY, API_TAGS, CREATOR];
export const TEST_CASE_RELEVANCE_LOAD_CASE= [NAME, STATUS, CREATE_TIME, UPDATE_TIME, CREATOR];
// 测试跟踪-缺陷管理-缺陷列表
export const TEST_TRACK_ISSUE_LIST = [NAME, PLATFORM, CREATE_TIME, CREATOR];
// 测试跟踪-测试用例-关联缺陷
export const TEST_CASE_RELEVANCE_ISSUE_LIST = [NAME, PLATFORM, CREATE_TIME, CREATOR];

View File

@ -17,11 +17,11 @@ export const Test_Case_Review = [
{id: 'name', label: i18n.t('test_track.review.review_name')},
{id: 'reviewer', label: i18n.t('test_track.review.reviewer')},
{id: 'projectName', label: i18n.t('test_track.review.review_project')},
{id: 'creatorName', label: i18n.t('test_track.review.review_creator')},
{id: 'creatorName', label: i18n.t('test_track.review.creator')},
{id: 'status', label: i18n.t('test_track.review.review_status')},
{id: 'createTime', label: i18n.t('commons.create_time')},
{id: 'endTime', label: i18n.t('test_track.review.end_time')},
{id: 'tags', label: '标签'},
{id: 'tags', label: i18n.t('commons.tag')},
]
//测试计划-测试用例
export const Test_Plan_List = [

View File

@ -5,7 +5,11 @@
:destroy-on-close="true"
width="60%" :visible.sync="loadApiAutomationVisible"
:modal="true">
<ms-table-search-bar :condition.sync="condition" @change="search" class="search-bar" :tip="$t('commons.search_by_id_name_tag')" />
<ms-search
:base-search-tip="$t('commons.search_by_id_name_tag')"
:condition.sync="condition"
@search="search">
</ms-search>
<el-table v-loading="projectLoadingResult.loading" class="basic-config"
:data="apiScenarios"
@select-all="handleSelectAll"
@ -49,12 +53,12 @@ import MsTablePagination from "@/business/components/common/pagination/TablePagi
import {getCurrentProjectID} from "@/common/js/utils";
import MsTag from "@/business/components/common/components/MsTag";
import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup";
import {API_SCENARIO_CONFIGS} from "@/business/components/common/components/search/search-components";
import MsTableSearchBar from "@/business/components/common/components/MsTableSearchBar";
import MsSearch from "@/business/components/common/components/search/MsSearch";
export default {
name: "ExistScenarios",
components: {MsTag, MsTablePagination, MsDialogFooter,MsTableSearchBar},
components: {MsTag, MsTablePagination, MsDialogFooter,MsTableSearchBar, MsSearch},
props: {
fileList: Array,
tableData: Array,
@ -71,7 +75,6 @@ export default {
apiScenarios: [],
selectIds: new Set,
condition: {
components: API_SCENARIO_CONFIGS,
projectId: getCurrentProjectID(),
filters: {status: ["Prepare", "Underway", "Completed"]}
},

View File

@ -50,6 +50,7 @@
</ms-tab-button>
</el-tab-pane>
<el-tab-pane name="public" v-if="publicEnable" :label="$t('project.case_public')">
<div style="height: 6px;"></div>
<test-case-list
:checkRedirectID="checkRedirectID"
:isRedirectEdit="isRedirectEdit"

View File

@ -169,7 +169,7 @@ export default {
// custom template field id
let id = val.slice(6);
this.fieldType = "custom";
this.$get("/custom/field/template/" + id, res => {
this.$get("/custom/field/get/" + id, res => {
this.customField = res ? res.data : {};
this.customField.options = JSON.parse(this.customField.options);
if (this.customField.type === 'checkbox' || this.customField.type === 'multipleMember') {

View File

@ -5,8 +5,10 @@
:title="$t('test_track.case.relate_issue')"
@confirm="save"
ref="relevanceDialog">
<el-input :placeholder="$t('commons.search_by_name_or_id')" @change="getIssues" class="search-input" size="small"
v-model="page.condition.name"/>
<ms-search
:base-search-tip="$t('commons.search_by_name_or_id')"
:condition.sync="page.condition"
@search="getIssues"/>
<ms-table
v-loading="page.result.loading"
:data="page.data"
@ -80,12 +82,18 @@ import {ISSUE_STATUS_MAP} from "@/common/js/table-constants";
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import {getPageInfo} from "@/common/js/tableUtils";
import {getCurrentProjectID} from "@/common/js/utils";
import {
TEST_CASE_RELEVANCE_ISSUE_LIST
} from "@/business/components/common/components/search/search-components";
import MsSearch from "@/business/components/common/components/search/MsSearch";
export default {
name: "IssueRelateList",
components: {MsTablePagination, IssueDescriptionTableItem, MsTableColumn, MsTable, MsEditDialog},
components: {MsTablePagination, IssueDescriptionTableItem, MsTableColumn, MsTable, MsEditDialog, MsSearch},
data() {
return {
page: getPageInfo(),
page: getPageInfo({
components: TEST_CASE_RELEVANCE_ISSUE_LIST
}),
visible: false,
isThirdPart: false
}

View File

@ -582,8 +582,6 @@ export default {
this.setFormData(testCase);
this.setTestCaseExtInfo(testCase);
this.getSelectOptions();
//
this.customFieldForm = parseCustomField(this.form, this.testCaseTemplate, this.customFieldRules, buildTestCaseOldFields(this.form));
this.reload();
this.$nextTick(() => {
this.showInputTag = true;
@ -592,6 +590,7 @@ export default {
this.getTestCase(testCase.id);
}
} else {
// add
if (this.selectNode.data) {
this.form.module = this.selectNode.data.id;
} else {
@ -666,9 +665,29 @@ export default {
//
this.customFieldForm = parseCustomField(this.form, this.testCaseTemplate, this.customFieldRules, testCase ? buildTestCaseOldFields(this.form) : null);
this.setDefaultValue();
this.resetSystemField();
//
this.reloadForm();
},
resetSystemField() {
if (this.operationType === 'add') {
return;
}
//
this.from;
this.customFieldForm['用例等级'] = this.form.priority;
this.customFieldForm['责任人'] = this.form.maintainer;
this.customFieldForm['用例状态'] = this.form.status;
this.testCaseTemplate.customFields.forEach(field => {
if (field.name === '用例等级') {
field.defaultValue = this.form.priority;
} else if (field.name === '责任人') {
field.defaultValue = this.form.maintainer;
} else if (field.name === '用例状态') {
field.defaultValue = this.form.status;
}
});
},
setTestCaseExtInfo(testCase) {
this.testCase = {};
if (testCase) {
@ -762,21 +781,18 @@ export default {
return param;
},
parseOldFields(param) {
let customFieldsStr = param.customFields;
if (customFieldsStr) {
let customFields = JSON.parse(customFieldsStr);
customFields.forEach(item => {
if (item.name === '用例等级') {
param.priority = item.value;
}
if (item.name === '责任人') {
param.maintainer = item.value;
}
if (item.name === '用例状态') {
param.status = item.value;
}
});
}
let customFields = this.testCaseTemplate.customFields;
customFields.forEach(item => {
if (item.name === '用例等级') {
param.priority = item.defaultValue;
}
if (item.name === '责任人') {
param.maintainer = item.defaultValue;
}
if (item.name === '用例状态') {
param.status = item.defaultValue;
}
});
},
getOption(param) {
let formData = new FormData();

View File

@ -1,12 +1,10 @@
<template>
<span>
<el-input :placeholder="$t('commons.search_by_name_or_id')" @change="initTableData" class="search-input"
size="small"
v-model="condition.name" ref="inputVal"/>
<el-link type="primary" @click="open" style="float: right;margin-top: 5px;padding-right: 10px">
{{ $t('commons.adv_search.title') }}
</el-link>
<ms-search
:condition.sync="condition"
@search="search">
</ms-search>
<ms-table
v-loading="page.result.loading"
@ -223,8 +221,6 @@
<relationship-graph-drawer :graph-data="graphData" ref="relationshipGraph"/>
<!--高级搜索-->
<ms-table-adv-search-bar :condition.sync="condition" :showLink="false" ref="searchBar" @search="search"/>
<!-- 删除接口提示 -->
<list-item-delete-confirm ref="apiDeleteConfirm" @handleDelete="_handleDeleteVersion"/>
</span>
@ -262,7 +258,7 @@ import {
getLastTableSortField,
getPageInfo,
getTableHeaderWithCustomFields,
initCondition,
initCondition, parseCustomFilesForList,
} from "@/common/js/tableUtils";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import PlanStatusTableItem from "@/business/components/track/common/tableItems/plan/PlanStatusTableItem";
@ -285,6 +281,8 @@ import {editTestCaseOrder} from "@/network/testCase";
import {getGraphByCondition} from "@/network/graph";
import MsTableAdvSearchBar from "@/business/components/common/components/search/MsTableAdvSearchBar";
import ListItemDeleteConfirm from "@/business/components/common/components/ListItemDeleteConfirm";
import {getAdvSearchCustomField} from "@/business/components/common/components/search/custom-component";
import MsSearch from "@/business/components/common/components/search/MsSearch";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const relationshipGraphDrawer = requireComponent.keys().length > 0 ? requireComponent("./graph/RelationshipGraphDrawer.vue") : {};
@ -292,6 +290,7 @@ const relationshipGraphDrawer = requireComponent.keys().length > 0 ? requireComp
export default {
name: "TestCaseList",
components: {
MsSearch,
ListItemDeleteConfirm,
MsTableAdvSearchBar,
TestCasePreview,
@ -332,7 +331,8 @@ export default {
isMoveBatch: true,
condition: {
components: TEST_CASE_CONFIGS,
filters: {}
filters: {},
custom: true,
},
versionFilters: [],
graphData: {},
@ -631,6 +631,9 @@ export default {
let template = data[1];
this.testCaseTemplate = template;
this.fields = getTableHeaderWithCustomFields('TRACK_TEST_CASE', this.testCaseTemplate.customFields);
// todo
let comp = getAdvSearchCustomField(this.condition.components, this.testCaseTemplate.customFields);
this.condition.components.push(...comp);
this.setTestCaseDefaultValue(template);
this.typeArr = [];
getCustomFieldBatchEditOption(template.customFields, this.typeArr, this.valueArr, this.members);
@ -658,18 +661,14 @@ export default {
},
getCustomFieldValue(row, field) {
let value = getCustomFieldValue(row, field, this.members);
if (!value) {
if (field.name === '用例等级') {
return row.priority;
}
if (field.name === '责任人') {
return row.maintainer;
}
if (field.name === '用例状态') {
return row.status;
}
if (field.name === '用例等级') {
return row.priority;
} else if (field.name === '责任人') {
return row.maintainer;
} else if (field.name === '用例状态') {
return row.status;
}
return value;
return value ? value : '';
},
getCustomFieldFilter(field) {
if (field.name === '用例等级') {
@ -726,9 +725,6 @@ export default {
}
this.getData();
},
open() {
this.$refs.searchBar.open();
},
getData() {
this.getSelectDataRange();
this.condition.selectThisWeedData = false;
@ -781,11 +777,7 @@ export default {
let data = response.data;
this.page.total = data.itemCount;
this.page.data = data.listObject;
this.page.data.forEach(item => {
if (item.customFields) {
item.customFields = JSON.parse(item.customFields);
}
});
parseCustomFilesForList(this.page.data);
parseTag(this.page.data);
});
this.$emit("getTrashList");
@ -1058,10 +1050,14 @@ export default {
param.customTemplateFieldId = form.type.slice(6);
param.condition = this.condition;
param.customField = {
id: form.customField.id,
fieldId: form.customField.id,
name: form.customField.name,
value: form.customField.defaultValue
};
if (form.customField.type && (form.customField.type === 'richText' || form.customField.type === 'textarea')) {
param.customField.textValue = form.customField.defaultValue;
} else {
param.customField.value = JSON.stringify(form.customField.defaultValue ? form.customField.defaultValue : '');
}
this.$post('/test/case/batch/edit', param, () => {
this.$success(this.$t('commons.save_success'));
this.refresh();

View File

@ -1,11 +1,9 @@
<template>
<div>
<el-input :placeholder="$t('commons.search_by_name_or_id')" @blur="initTable"
@keyup.enter.native="initTable" class="search-input" size="small" v-model="condition.name"/>
<ms-table-adv-search-bar :condition.sync="condition" class="adv-search-bar"
v-if="condition.components !== undefined && condition.components.length > 0"
@search="initTable"/>
<ms-search
:condition.sync="condition"
@search="initTable">
</ms-search>
<version-select v-xpack :project-id="projectId" @changeVersion="changeVersion" margin-right="20"
class="search-input"/>
@ -75,6 +73,7 @@ import {TEST_CASE_RELEVANCE_API_CASE_CONFIGS} from "@/business/components/common
import MsTableAdvSearchBar from "@/business/components/common/components/search/MsTableAdvSearchBar";
import MsTag from "@/business/components/common/components/MsTag";
import {getCurrentProjectID, hasLicense} from "@/common/js/utils";
import MsSearch from "@/business/components/common/components/search/MsSearch";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./version/VersionSelect.vue") : {};
@ -87,6 +86,7 @@ export default {
MsTableColumn,
MsTableAdvSearchBar,
MsTag,
MsSearch,
'VersionSelect': VersionSelect.default,
},
data() {

View File

@ -1,11 +1,10 @@
<template>
<div>
<el-input :placeholder="$t('commons.search_by_name_or_id')" @blur="initTable"
@keyup.enter.native="initTable" class="search-input" size="small" v-model="condition.name"/>
<ms-table-adv-search-bar :condition.sync="condition" class="adv-search-bar"
v-if="condition.components !== undefined && condition.components.length > 0"
@search="initTable"/>
<ms-search
:condition.sync="condition"
@search="initTable">
</ms-search>
<version-select v-xpack :project-id="projectId" @changeVersion="changeVersion" margin-right="20"
class="search-input"/>
@ -83,6 +82,7 @@ import {TEST_CASE_RELEVANCE_LOAD_CASE} from "@/business/components/common/compon
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./version/VersionSelect.vue") : {};
import {hasLicense, getCurrentProjectID} from "@/common/js/utils";
import MsSearch from "@/business/components/common/components/search/MsSearch";
export default {
name: "TestCaseRelateLoadList",
@ -92,6 +92,7 @@ export default {
MsTable,
MsTableColumn,
MsTableAdvSearchBar,
MsSearch,
'VersionSelect': VersionSelect.default,
},
data() {

View File

@ -1,11 +1,10 @@
<template>
<div>
<el-input :placeholder="$t('commons.search_by_name_or_id')" @blur="initTable"
@keyup.enter.native="initTable" class="search-input" size="small" v-model="condition.name"/>
<ms-table-adv-search-bar :condition.sync="condition" class="adv-search-bar"
v-if="condition.components !== undefined && condition.components.length > 0"
@search="initTable"/>
<ms-search
:condition.sync="condition"
@search="initTable">
</ms-search>
<version-select v-xpack :project-id="projectId" @changeVersion="changeVersion" margin-left="-100"
class="search-input"/>
@ -86,6 +85,7 @@ import MsTableAdvSearchBar from "@/business/components/common/components/search/
import MsTag from "@/business/components/common/components/MsTag";
import {TEST_CASE_RELEVANCE_API_CASE_CONFIGS} from "@/business/components/common/components/search/search-components";
import {hasLicense, getCurrentProjectID} from "@/common/js/utils";
import MsSearch from "@/business/components/common/components/search/MsSearch";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./version/VersionSelect.vue") : {};
@ -99,6 +99,7 @@ export default {
MsTableColumn,
MsTableAdvSearchBar,
MsTag,
MsSearch,
'VersionSelect': VersionSelect.default,
},
data() {

View File

@ -179,6 +179,8 @@ import MsMainContainer from "@/business/components/common/components/MsMainConta
import {getCurrentProjectID, getCurrentWorkspaceId} from "@/common/js/utils";
import {getProjectMember} from "@/network/user";
import {LOCAL} from "@/common/js/constants";
import {TEST_TRACK_ISSUE_LIST} from "@/business/components/common/components/search/search-components";
import {getAdvSearchCustomField} from "@/business/components/common/components/search/custom-component";
export default {
name: "IssueList",
@ -192,7 +194,10 @@ export default {
},
data() {
return {
page: getPageInfo(),
page: getPageInfo({
components: TEST_TRACK_ISSUE_LIST,
custom: true,
}),
fields: [],
tableHeaderKey:"ISSUE_LIST",
fieldsWidth: getCustomTableWidth('ISSUE_LIST'),
@ -284,6 +289,10 @@ export default {
let removeField = {id: 'platformStatus', name: 'platformStatus', remove: true};
this.issueTemplate.customFields.push(removeField);
}
//
this.page.condition.components = this.page.condition.components.filter(item => item.custom !== true);
let comp = getAdvSearchCustomField(this.page.condition.components, this.issueTemplate.customFields);
this.page.condition.components.push(...comp);
if (this.$refs.table) this.$refs.table.reloadTable();
},
getIssues() {

View File

@ -39,7 +39,7 @@
<el-table-column
v-if="item.id=='creatorName'"
prop="creatorName"
:label="$t('test_track.review.review_creator')"
:label="$t('test_track.review.creator')"
show-overflow-tooltip
:key="index"
>

View File

@ -16,13 +16,10 @@ function setDefaultValue(item, value) {
*/
export function parseCustomField(data, template, rules, oldFields) {
let hasOldData = false;
if (!data.customFields) {
if (!data.fields) {
// 旧数据
hasOldData = true;
data.customFields = {};
}
if (!(data.customFields instanceof Object) && !(data.customFields instanceof Array)) {
data.customFields = JSON.parse(data.customFields);
data.fields = [];
}
let customFieldForm = {};
@ -56,29 +53,25 @@ export function parseCustomField(data, template, rules, oldFields) {
}
// 将保存的值赋值给template
if (data.customFields instanceof Array) {
for (let i = 0; i < data.customFields.length; i++) {
let customField = data.customFields[i];
if (customField.name === item.name) {
if (customField.type === 'multipleSelect') {
if (typeof (customField.value) === 'string' || customField.value instanceof String) {
try {
customField.value = JSON.parse(customField.value);
} catch (e) {
console.log("JSON parse custom field value error.");
}
}
if (data.fields instanceof Array) {
for (let i = 0; i < data.fields.length; i++) {
let customField = data.fields[i];
if (customField.id === item.id) {
try {
setDefaultValue(item, customField.value);
item.isEdit = true;
} catch (e) {
console.log("JSON parse custom field value error.");
}
setDefaultValue(item, customField.value);
break;
}
}
} else if (data.customFields instanceof Object) {
} else if (data.fields instanceof Object) { // todo
// 兼容旧的存储方式
for (const key in data.customFields) {
for (const key in data.fields) {
if (item.name === key) {
if (data.customFields[key]) {
setDefaultValue(item, JSON.parse(data.customFields[key]));
if (data.fields[key]) {
setDefaultValue(item, JSON.parse(data.fields[key]));
}
}
}
@ -93,46 +86,26 @@ export function parseCustomField(data, template, rules, oldFields) {
// 将template的属性值设置给customFields
export function buildCustomFields(data, param, template) {
if (template.customFields) {
if (!(data.customFields instanceof Array)) {
data.customFields = [];
if (!(data.fields instanceof Array)) {
data.fields = [];
}
let customFields = data.customFields;
// 去重操作
if (customFields) {
let nameSet = new Set();
for(let i = customFields.length - 1; i >= 0; i--){
let name = customFields[i].name;
if(nameSet.has(name)){
customFields.splice(i,1);
}
nameSet.add(name);
}
}
let addFields = [];
let editFields = [];
template.customFields.forEach(item => {
let hasField = false;
for (const index in customFields) {
if (customFields[index].name === item.name) {
hasField = true;
customFields[index].name = item.name;
customFields[index].value = item.defaultValue;
customFields[index].type = item.type;
break;
}
}
if (!hasField) {
let customField = {
id: item.id,
name: item.name,
value: item.defaultValue,
type: item.type,
customData: item.customData,
};
customFields.push(customField);
let customField = {
fieldId: item.id,
value: JSON.stringify(item.defaultValue),
};
if (item.isEdit) {
editFields.push(customField);
} else {
addFields.push(customField);
}
});
param.customFields = JSON.stringify(customFields);
param.addFields = addFields;
param.editFields = editFields;
}
}

View File

@ -104,7 +104,7 @@ export let CUSTOM_TABLE_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.review_creator'},
{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'},

View File

@ -438,10 +438,10 @@ export function saveCustomTableWidth(key, fieldKey, colWith) {
* @returns {VueI18n.TranslateResult|*}
*/
export function getCustomFieldValue(row, field, members) {
if (row.customFields) {
for (let i = 0; i < row.customFields.length; i++) {
let item = row.customFields[i];
if (item.name === field.name) {
if (row.fields) {
for (let i = 0; i < row.fields.length; i++) {
let item = row.fields[i];
if (item.id === field.id) {
if (!item.value) return '';
if (field.type === 'member') {
for (let j = 0; j < members.length; j++) {
@ -517,6 +517,8 @@ export function getCustomFieldValue(row, field, members) {
return val;
} else if (field.type === 'datetime') {
return timestampFormatDate(item.value);
} else if (['richText', 'textarea'].indexOf(field.type) > -1) {
return item.textValue;
}
return item.value;
}
@ -536,7 +538,7 @@ export function getCustomFieldBatchEditOption(customFields, typeArr, valueArr, m
customFields.forEach(item => {
if (item.options) {
typeArr.push({
id: item.name,
id: item.id,
name: item.name,
uuid: item.id,
custom: "custom" + item.id
@ -563,6 +565,24 @@ export function getCustomFieldBatchEditOption(customFields, typeArr, valueArr, m
});
}
export function parseCustomFilesForList(data) {
data.forEach(item => {
if (item.fields) {
item.fields.forEach(i => {
parseCustomFilesForItem(i);
});
}
});
}
export function parseCustomFilesForItem(data) {
if (data.value) {
data.value = JSON.parse(data.value);
}
if (data.textValue) {
// data.textValue = data.textValue;
}
}
// 多个监听共享变量
// 否则切换 pageSize 等刷新操作会导致部分行的回调函数中 data 数据不一致

View File

@ -1202,7 +1202,7 @@ export default {
api_definition_path: "API路径",
api_case_path: "用例路径",
api_principal: "责任人",
api_last_time: "最后更新时间",
api_last_time: "更新时间",
api_case_number: "用例数",
api_case_status: "用例状态",
api_case_passing_rate: "用例通过率",
@ -1379,7 +1379,7 @@ export default {
creator: "创建人",
update_time: "最后更新时间",
step: "步骤数",
last_result: "最后结果",
last_result: "执行结果",
last_result_id: '最后结果ID',
passing_rate: "通过率",
success: "通过",
@ -2133,14 +2133,14 @@ export default {
related_tip: "关联项目后可以添加关联项目下的测试用例到测试计划列表",
plan_stage: "测试阶段",
follow_people: "关注人",
plan_status: "当前状态",
plan_status: "状态",
smoke_test: "冒烟测试",
functional_test: "功能测试",
regression_test: "回归测试",
integration_testing: "集成测试",
system_test: "系统测试",
version_validation: "版本验证",
plan_principal: "责人",
plan_principal: "人",
input_plan_name: "请输入测试计划名称",
input_plan_principal: "请选择负责人",
input_plan_project: "请选择所属项目",
@ -2208,7 +2208,7 @@ export default {
related_tip: "关联项目后可以添加关联项目下的测试用例到评审列表",
review_creator: "发起人",
review_follow_people: "关注人",
review_status: "当前状态",
review_status: "状态",
end_time: "截止时间",
delete: "删除评审",
input_review_name: "请输入评审名称",

View File

@ -1,5 +1,5 @@
import {post, get} from "@/common/js/ajax";
import {getPageDate} from "@/common/js/tableUtils";
import {getPageDate, parseCustomFilesForList} from "@/common/js/tableUtils";
import {getCurrentProjectID, hasLicense} from "@/common/js/utils";
import {baseGet, basePost} from "@/network/base-network";
import {getCurrentProject} from "@/network/project";
@ -20,7 +20,8 @@ export function buildIssues(page) {
export function getIssues(page) {
return post('issues/list/' + page.currentPage + '/' + page.pageSize, page.condition, (response) => {
getPageDate(response, page);
buildIssues(page);
parseCustomFilesForList(page.data);
// buildIssues(page);
});
}