Merge remote-tracking branch 'origin/master'

This commit is contained in:
q4speed 2020-08-14 13:35:34 +08:00
commit 2fb347bd85
57 changed files with 3647 additions and 704 deletions

View File

@ -79,6 +79,7 @@ public class APITestController {
return apiTestService.get(testId);
}
@PostMapping("/delete")
public void delete(@RequestBody DeleteAPITestRequest request) {
apiTestService.delete(request.getId());

View File

@ -1,8 +1,7 @@
package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable;
import lombok.Data;
@Data
public class Project implements Serializable {
@ -18,5 +17,9 @@ public class Project implements Serializable {
private Long updateTime;
private String tapdId;
private String jiraKey;
private static final long serialVersionUID = 1L;
}

View File

@ -245,72 +245,72 @@ public class ProjectExample {
}
public Criteria andNameIsNull() {
addCriterion("name is null");
addCriterion("`name` is null");
return (Criteria) this;
}
public Criteria andNameIsNotNull() {
addCriterion("name is not null");
addCriterion("`name` is not null");
return (Criteria) this;
}
public Criteria andNameEqualTo(String value) {
addCriterion("name =", value, "name");
addCriterion("`name` =", value, "name");
return (Criteria) this;
}
public Criteria andNameNotEqualTo(String value) {
addCriterion("name <>", value, "name");
addCriterion("`name` <>", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThan(String value) {
addCriterion("name >", value, "name");
addCriterion("`name` >", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThanOrEqualTo(String value) {
addCriterion("name >=", value, "name");
addCriterion("`name` >=", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThan(String value) {
addCriterion("name <", value, "name");
addCriterion("`name` <", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThanOrEqualTo(String value) {
addCriterion("name <=", value, "name");
addCriterion("`name` <=", value, "name");
return (Criteria) this;
}
public Criteria andNameLike(String value) {
addCriterion("name like", value, "name");
addCriterion("`name` like", value, "name");
return (Criteria) this;
}
public Criteria andNameNotLike(String value) {
addCriterion("name not like", value, "name");
addCriterion("`name` not like", value, "name");
return (Criteria) this;
}
public Criteria andNameIn(List<String> values) {
addCriterion("name in", values, "name");
addCriterion("`name` in", values, "name");
return (Criteria) this;
}
public Criteria andNameNotIn(List<String> values) {
addCriterion("name not in", values, "name");
addCriterion("`name` not in", values, "name");
return (Criteria) this;
}
public Criteria andNameBetween(String value1, String value2) {
addCriterion("name between", value1, value2, "name");
addCriterion("`name` between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andNameNotBetween(String value1, String value2) {
addCriterion("name not between", value1, value2, "name");
addCriterion("`name` not between", value1, value2, "name");
return (Criteria) this;
}
@ -503,6 +503,146 @@ public class ProjectExample {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andTapdIdIsNull() {
addCriterion("tapd_id is null");
return (Criteria) this;
}
public Criteria andTapdIdIsNotNull() {
addCriterion("tapd_id is not null");
return (Criteria) this;
}
public Criteria andTapdIdEqualTo(String value) {
addCriterion("tapd_id =", value, "tapdId");
return (Criteria) this;
}
public Criteria andTapdIdNotEqualTo(String value) {
addCriterion("tapd_id <>", value, "tapdId");
return (Criteria) this;
}
public Criteria andTapdIdGreaterThan(String value) {
addCriterion("tapd_id >", value, "tapdId");
return (Criteria) this;
}
public Criteria andTapdIdGreaterThanOrEqualTo(String value) {
addCriterion("tapd_id >=", value, "tapdId");
return (Criteria) this;
}
public Criteria andTapdIdLessThan(String value) {
addCriterion("tapd_id <", value, "tapdId");
return (Criteria) this;
}
public Criteria andTapdIdLessThanOrEqualTo(String value) {
addCriterion("tapd_id <=", value, "tapdId");
return (Criteria) this;
}
public Criteria andTapdIdLike(String value) {
addCriterion("tapd_id like", value, "tapdId");
return (Criteria) this;
}
public Criteria andTapdIdNotLike(String value) {
addCriterion("tapd_id not like", value, "tapdId");
return (Criteria) this;
}
public Criteria andTapdIdIn(List<String> values) {
addCriterion("tapd_id in", values, "tapdId");
return (Criteria) this;
}
public Criteria andTapdIdNotIn(List<String> values) {
addCriterion("tapd_id not in", values, "tapdId");
return (Criteria) this;
}
public Criteria andTapdIdBetween(String value1, String value2) {
addCriterion("tapd_id between", value1, value2, "tapdId");
return (Criteria) this;
}
public Criteria andTapdIdNotBetween(String value1, String value2) {
addCriterion("tapd_id not between", value1, value2, "tapdId");
return (Criteria) this;
}
public Criteria andJiraKeyIsNull() {
addCriterion("jira_key is null");
return (Criteria) this;
}
public Criteria andJiraKeyIsNotNull() {
addCriterion("jira_key is not null");
return (Criteria) this;
}
public Criteria andJiraKeyEqualTo(String value) {
addCriterion("jira_key =", value, "jiraKey");
return (Criteria) this;
}
public Criteria andJiraKeyNotEqualTo(String value) {
addCriterion("jira_key <>", value, "jiraKey");
return (Criteria) this;
}
public Criteria andJiraKeyGreaterThan(String value) {
addCriterion("jira_key >", value, "jiraKey");
return (Criteria) this;
}
public Criteria andJiraKeyGreaterThanOrEqualTo(String value) {
addCriterion("jira_key >=", value, "jiraKey");
return (Criteria) this;
}
public Criteria andJiraKeyLessThan(String value) {
addCriterion("jira_key <", value, "jiraKey");
return (Criteria) this;
}
public Criteria andJiraKeyLessThanOrEqualTo(String value) {
addCriterion("jira_key <=", value, "jiraKey");
return (Criteria) this;
}
public Criteria andJiraKeyLike(String value) {
addCriterion("jira_key like", value, "jiraKey");
return (Criteria) this;
}
public Criteria andJiraKeyNotLike(String value) {
addCriterion("jira_key not like", value, "jiraKey");
return (Criteria) this;
}
public Criteria andJiraKeyIn(List<String> values) {
addCriterion("jira_key in", values, "jiraKey");
return (Criteria) this;
}
public Criteria andJiraKeyNotIn(List<String> values) {
addCriterion("jira_key not in", values, "jiraKey");
return (Criteria) this;
}
public Criteria andJiraKeyBetween(String value1, String value2) {
addCriterion("jira_key between", value1, value2, "jiraKey");
return (Criteria) this;
}
public Criteria andJiraKeyNotBetween(String value1, String value2) {
addCriterion("jira_key not between", value1, value2, "jiraKey");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -0,0 +1,17 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class ServiceIntegration implements Serializable {
private String id;
private String organizationId;
private String platform;
private String configuration;
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 ServiceIntegrationExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public ServiceIntegrationExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andOrganizationIdIsNull() {
addCriterion("organization_id is null");
return (Criteria) this;
}
public Criteria andOrganizationIdIsNotNull() {
addCriterion("organization_id is not null");
return (Criteria) this;
}
public Criteria andOrganizationIdEqualTo(String value) {
addCriterion("organization_id =", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotEqualTo(String value) {
addCriterion("organization_id <>", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdGreaterThan(String value) {
addCriterion("organization_id >", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdGreaterThanOrEqualTo(String value) {
addCriterion("organization_id >=", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdLessThan(String value) {
addCriterion("organization_id <", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdLessThanOrEqualTo(String value) {
addCriterion("organization_id <=", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdLike(String value) {
addCriterion("organization_id like", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotLike(String value) {
addCriterion("organization_id not like", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdIn(List<String> values) {
addCriterion("organization_id in", values, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotIn(List<String> values) {
addCriterion("organization_id not in", values, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdBetween(String value1, String value2) {
addCriterion("organization_id between", value1, value2, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotBetween(String value1, String value2) {
addCriterion("organization_id not between", value1, value2, "organizationId");
return (Criteria) this;
}
public Criteria andPlatformIsNull() {
addCriterion("platform is null");
return (Criteria) this;
}
public Criteria andPlatformIsNotNull() {
addCriterion("platform is not null");
return (Criteria) this;
}
public Criteria andPlatformEqualTo(String value) {
addCriterion("platform =", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformNotEqualTo(String value) {
addCriterion("platform <>", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformGreaterThan(String value) {
addCriterion("platform >", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformGreaterThanOrEqualTo(String value) {
addCriterion("platform >=", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformLessThan(String value) {
addCriterion("platform <", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformLessThanOrEqualTo(String value) {
addCriterion("platform <=", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformLike(String value) {
addCriterion("platform like", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformNotLike(String value) {
addCriterion("platform not like", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformIn(List<String> values) {
addCriterion("platform in", values, "platform");
return (Criteria) this;
}
public Criteria andPlatformNotIn(List<String> values) {
addCriterion("platform not in", values, "platform");
return (Criteria) this;
}
public Criteria andPlatformBetween(String value1, String value2) {
addCriterion("platform between", value1, value2, "platform");
return (Criteria) this;
}
public Criteria andPlatformNotBetween(String value1, String value2) {
addCriterion("platform not between", value1, value2, "platform");
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,17 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class TestCaseIssues implements Serializable {
private String id;
private String testCaseId;
private String issuesId;
private String platform;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,480 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class TestCaseIssuesExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public TestCaseIssuesExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andTestCaseIdIsNull() {
addCriterion("test_case_id is null");
return (Criteria) this;
}
public Criteria andTestCaseIdIsNotNull() {
addCriterion("test_case_id is not null");
return (Criteria) this;
}
public Criteria andTestCaseIdEqualTo(String value) {
addCriterion("test_case_id =", value, "testCaseId");
return (Criteria) this;
}
public Criteria andTestCaseIdNotEqualTo(String value) {
addCriterion("test_case_id <>", value, "testCaseId");
return (Criteria) this;
}
public Criteria andTestCaseIdGreaterThan(String value) {
addCriterion("test_case_id >", value, "testCaseId");
return (Criteria) this;
}
public Criteria andTestCaseIdGreaterThanOrEqualTo(String value) {
addCriterion("test_case_id >=", value, "testCaseId");
return (Criteria) this;
}
public Criteria andTestCaseIdLessThan(String value) {
addCriterion("test_case_id <", value, "testCaseId");
return (Criteria) this;
}
public Criteria andTestCaseIdLessThanOrEqualTo(String value) {
addCriterion("test_case_id <=", value, "testCaseId");
return (Criteria) this;
}
public Criteria andTestCaseIdLike(String value) {
addCriterion("test_case_id like", value, "testCaseId");
return (Criteria) this;
}
public Criteria andTestCaseIdNotLike(String value) {
addCriterion("test_case_id not like", value, "testCaseId");
return (Criteria) this;
}
public Criteria andTestCaseIdIn(List<String> values) {
addCriterion("test_case_id in", values, "testCaseId");
return (Criteria) this;
}
public Criteria andTestCaseIdNotIn(List<String> values) {
addCriterion("test_case_id not in", values, "testCaseId");
return (Criteria) this;
}
public Criteria andTestCaseIdBetween(String value1, String value2) {
addCriterion("test_case_id between", value1, value2, "testCaseId");
return (Criteria) this;
}
public Criteria andTestCaseIdNotBetween(String value1, String value2) {
addCriterion("test_case_id not between", value1, value2, "testCaseId");
return (Criteria) this;
}
public Criteria andIssuesIdIsNull() {
addCriterion("issues_id is null");
return (Criteria) this;
}
public Criteria andIssuesIdIsNotNull() {
addCriterion("issues_id is not null");
return (Criteria) this;
}
public Criteria andIssuesIdEqualTo(String value) {
addCriterion("issues_id =", value, "issuesId");
return (Criteria) this;
}
public Criteria andIssuesIdNotEqualTo(String value) {
addCriterion("issues_id <>", value, "issuesId");
return (Criteria) this;
}
public Criteria andIssuesIdGreaterThan(String value) {
addCriterion("issues_id >", value, "issuesId");
return (Criteria) this;
}
public Criteria andIssuesIdGreaterThanOrEqualTo(String value) {
addCriterion("issues_id >=", value, "issuesId");
return (Criteria) this;
}
public Criteria andIssuesIdLessThan(String value) {
addCriterion("issues_id <", value, "issuesId");
return (Criteria) this;
}
public Criteria andIssuesIdLessThanOrEqualTo(String value) {
addCriterion("issues_id <=", value, "issuesId");
return (Criteria) this;
}
public Criteria andIssuesIdLike(String value) {
addCriterion("issues_id like", value, "issuesId");
return (Criteria) this;
}
public Criteria andIssuesIdNotLike(String value) {
addCriterion("issues_id not like", value, "issuesId");
return (Criteria) this;
}
public Criteria andIssuesIdIn(List<String> values) {
addCriterion("issues_id in", values, "issuesId");
return (Criteria) this;
}
public Criteria andIssuesIdNotIn(List<String> values) {
addCriterion("issues_id not in", values, "issuesId");
return (Criteria) this;
}
public Criteria andIssuesIdBetween(String value1, String value2) {
addCriterion("issues_id between", value1, value2, "issuesId");
return (Criteria) this;
}
public Criteria andIssuesIdNotBetween(String value1, String value2) {
addCriterion("issues_id not between", value1, value2, "issuesId");
return (Criteria) this;
}
public Criteria andPlatformIsNull() {
addCriterion("platform is null");
return (Criteria) this;
}
public Criteria andPlatformIsNotNull() {
addCriterion("platform is not null");
return (Criteria) this;
}
public Criteria andPlatformEqualTo(String value) {
addCriterion("platform =", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformNotEqualTo(String value) {
addCriterion("platform <>", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformGreaterThan(String value) {
addCriterion("platform >", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformGreaterThanOrEqualTo(String value) {
addCriterion("platform >=", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformLessThan(String value) {
addCriterion("platform <", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformLessThanOrEqualTo(String value) {
addCriterion("platform <=", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformLike(String value) {
addCriterion("platform like", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformNotLike(String value) {
addCriterion("platform not like", value, "platform");
return (Criteria) this;
}
public Criteria andPlatformIn(List<String> values) {
addCriterion("platform in", values, "platform");
return (Criteria) this;
}
public Criteria andPlatformNotIn(List<String> values) {
addCriterion("platform not in", values, "platform");
return (Criteria) this;
}
public Criteria andPlatformBetween(String value1, String value2) {
addCriterion("platform between", value1, value2, "platform");
return (Criteria) this;
}
public Criteria andPlatformNotBetween(String value1, String value2) {
addCriterion("platform not between", value1, value2, "platform");
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

@ -8,6 +8,8 @@
<result column="description" jdbcType="VARCHAR" property="description" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="tapd_id" jdbcType="VARCHAR" property="tapdId" />
<result column="jira_key" jdbcType="VARCHAR" property="jiraKey" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -68,7 +70,7 @@
</where>
</sql>
<sql id="Base_Column_List">
id, workspace_id, name, description, create_time, update_time
id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultMap="BaseResultMap">
select
@ -101,12 +103,12 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.Project">
insert into project (id, workspace_id, name,
description, create_time, update_time
)
insert into project (id, workspace_id, `name`,
description, create_time, update_time,
tapd_id, jira_key)
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}
)
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{tapdId,jdbcType=VARCHAR}, #{jiraKey,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.Project">
insert into project
@ -118,7 +120,7 @@
workspace_id,
</if>
<if test="name != null">
name,
`name`,
</if>
<if test="description != null">
description,
@ -129,6 +131,12 @@
<if test="updateTime != null">
update_time,
</if>
<if test="tapdId != null">
tapd_id,
</if>
<if test="jiraKey != null">
jira_key,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -149,6 +157,12 @@
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="tapdId != null">
#{tapdId,jdbcType=VARCHAR},
</if>
<if test="jiraKey != null">
#{jiraKey,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultType="java.lang.Long">
@ -167,7 +181,7 @@
workspace_id = #{record.workspaceId,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
name = #{record.name,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.description != null">
description = #{record.description,jdbcType=VARCHAR},
@ -178,6 +192,12 @@
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.tapdId != null">
tapd_id = #{record.tapdId,jdbcType=VARCHAR},
</if>
<if test="record.jiraKey != null">
jira_key = #{record.jiraKey,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -187,10 +207,12 @@
update project
set id = #{record.id,jdbcType=VARCHAR},
workspace_id = #{record.workspaceId,jdbcType=VARCHAR},
name = #{record.name,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}
update_time = #{record.updateTime,jdbcType=BIGINT},
tapd_id = #{record.tapdId,jdbcType=VARCHAR},
jira_key = #{record.jiraKey,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -202,7 +224,7 @@
workspace_id = #{workspaceId,jdbcType=VARCHAR},
</if>
<if test="name != null">
name = #{name,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=VARCHAR},
@ -213,16 +235,24 @@
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="tapdId != null">
tapd_id = #{tapdId,jdbcType=VARCHAR},
</if>
<if test="jiraKey != null">
jira_key = #{jiraKey,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.Project">
update project
set workspace_id = #{workspaceId,jdbcType=VARCHAR},
name = #{name,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}
update_time = #{updateTime,jdbcType=BIGINT},
tapd_id = #{tapdId,jdbcType=VARCHAR},
jira_key = #{jiraKey,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -0,0 +1,36 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.ServiceIntegration;
import io.metersphere.base.domain.ServiceIntegrationExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface ServiceIntegrationMapper {
long countByExample(ServiceIntegrationExample example);
int deleteByExample(ServiceIntegrationExample example);
int deleteByPrimaryKey(String id);
int insert(ServiceIntegration record);
int insertSelective(ServiceIntegration record);
List<ServiceIntegration> selectByExampleWithBLOBs(ServiceIntegrationExample example);
List<ServiceIntegration> selectByExample(ServiceIntegrationExample example);
ServiceIntegration selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") ServiceIntegration record, @Param("example") ServiceIntegrationExample example);
int updateByExampleWithBLOBs(@Param("record") ServiceIntegration record, @Param("example") ServiceIntegrationExample example);
int updateByExample(@Param("record") ServiceIntegration record, @Param("example") ServiceIntegrationExample example);
int updateByPrimaryKeySelective(ServiceIntegration record);
int updateByPrimaryKeyWithBLOBs(ServiceIntegration record);
int updateByPrimaryKey(ServiceIntegration 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.ServiceIntegrationMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.ServiceIntegration">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="organization_id" jdbcType="VARCHAR" property="organizationId" />
<result column="platform" jdbcType="VARCHAR" property="platform" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ServiceIntegration">
<result column="configuration" jdbcType="LONGVARCHAR" property="configuration" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, organization_id, platform
</sql>
<sql id="Blob_Column_List">
configuration
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.ServiceIntegrationExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from service_integration
<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.ServiceIntegrationExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from service_integration
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from service_integration
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from service_integration
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.ServiceIntegrationExample">
delete from service_integration
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ServiceIntegration">
insert into service_integration (id, organization_id, platform,
configuration)
values (#{id,jdbcType=VARCHAR}, #{organizationId,jdbcType=VARCHAR}, #{platform,jdbcType=VARCHAR},
#{configuration,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ServiceIntegration">
insert into service_integration
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="organizationId != null">
organization_id,
</if>
<if test="platform != null">
platform,
</if>
<if test="configuration != null">
configuration,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="organizationId != null">
#{organizationId,jdbcType=VARCHAR},
</if>
<if test="platform != null">
#{platform,jdbcType=VARCHAR},
</if>
<if test="configuration != null">
#{configuration,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ServiceIntegrationExample" resultType="java.lang.Long">
select count(*) from service_integration
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update service_integration
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.organizationId != null">
organization_id = #{record.organizationId,jdbcType=VARCHAR},
</if>
<if test="record.platform != null">
platform = #{record.platform,jdbcType=VARCHAR},
</if>
<if test="record.configuration != null">
configuration = #{record.configuration,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update service_integration
set id = #{record.id,jdbcType=VARCHAR},
organization_id = #{record.organizationId,jdbcType=VARCHAR},
platform = #{record.platform,jdbcType=VARCHAR},
configuration = #{record.configuration,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update service_integration
set id = #{record.id,jdbcType=VARCHAR},
organization_id = #{record.organizationId,jdbcType=VARCHAR},
platform = #{record.platform,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ServiceIntegration">
update service_integration
<set>
<if test="organizationId != null">
organization_id = #{organizationId,jdbcType=VARCHAR},
</if>
<if test="platform != null">
platform = #{platform,jdbcType=VARCHAR},
</if>
<if test="configuration != null">
configuration = #{configuration,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.ServiceIntegration">
update service_integration
set organization_id = #{organizationId,jdbcType=VARCHAR},
platform = #{platform,jdbcType=VARCHAR},
configuration = #{configuration,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ServiceIntegration">
update service_integration
set organization_id = #{organizationId,jdbcType=VARCHAR},
platform = #{platform,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

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

View File

@ -0,0 +1,196 @@
<?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.TestCaseIssuesMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.TestCaseIssues">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="test_case_id" jdbcType="VARCHAR" property="testCaseId" />
<result column="issues_id" jdbcType="VARCHAR" property="issuesId" />
<result column="platform" jdbcType="VARCHAR" property="platform" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, test_case_id, issues_id, platform
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestCaseIssuesExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from test_case_issues
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from test_case_issues
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from test_case_issues
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.TestCaseIssuesExample">
delete from test_case_issues
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestCaseIssues">
insert into test_case_issues (id, test_case_id, issues_id,
platform)
values (#{id,jdbcType=VARCHAR}, #{testCaseId,jdbcType=VARCHAR}, #{issuesId,jdbcType=VARCHAR},
#{platform,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestCaseIssues">
insert into test_case_issues
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="testCaseId != null">
test_case_id,
</if>
<if test="issuesId != null">
issues_id,
</if>
<if test="platform != null">
platform,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="testCaseId != null">
#{testCaseId,jdbcType=VARCHAR},
</if>
<if test="issuesId != null">
#{issuesId,jdbcType=VARCHAR},
</if>
<if test="platform != null">
#{platform,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestCaseIssuesExample" resultType="java.lang.Long">
select count(*) from test_case_issues
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update test_case_issues
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.testCaseId != null">
test_case_id = #{record.testCaseId,jdbcType=VARCHAR},
</if>
<if test="record.issuesId != null">
issues_id = #{record.issuesId,jdbcType=VARCHAR},
</if>
<if test="record.platform != null">
platform = #{record.platform,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update test_case_issues
set id = #{record.id,jdbcType=VARCHAR},
test_case_id = #{record.testCaseId,jdbcType=VARCHAR},
issues_id = #{record.issuesId,jdbcType=VARCHAR},
platform = #{record.platform,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.TestCaseIssues">
update test_case_issues
<set>
<if test="testCaseId != null">
test_case_id = #{testCaseId,jdbcType=VARCHAR},
</if>
<if test="issuesId != null">
issues_id = #{issuesId,jdbcType=VARCHAR},
</if>
<if test="platform != null">
platform = #{platform,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestCaseIssues">
update test_case_issues
set test_case_id = #{testCaseId,jdbcType=VARCHAR},
issues_id = #{issuesId,jdbcType=VARCHAR},
platform = #{platform,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -4,7 +4,7 @@
<select id="getProjectWithWorkspace" resultType="io.metersphere.dto.ProjectDTO">
select p.id, p.workspace_id, p.name, p.description, p.update_time,
p.create_time, w.id as workspaceId, w.name as workspaceName
p.create_time, w.id as workspaceId, w.name as workspaceName, p.tapd_id, p.jira_key
from project p
join workspace w on p.workspace_id = w.id
<where>

View File

@ -0,0 +1,5 @@
package io.metersphere.commons.constants;
public enum IssuesManagePlatform {
Tapd, Jira
}

View File

@ -0,0 +1,42 @@
package io.metersphere.commons.utils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
public class RestTemplateUtils {
private static RestTemplate restTemplate;
private static void getTemplate() {
restTemplate = (RestTemplate) CommonBeanFactory.getBean("restTemplate");
}
public static String get(String url, HttpHeaders httpHeaders) {
getTemplate();
try {
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(httpHeaders);
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
return responseEntity.getBody();
} catch (Exception e) {
throw new RuntimeException("调用接口失败", e);
}
}
public static String post(String url, Object paramMap, HttpHeaders httpHeaders) {
getTemplate();
try {
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>((MultiValueMap) paramMap, httpHeaders);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
return responseEntity.getBody();
} catch (Exception e) {
throw new RuntimeException("调用接口失败", e);
}
}
}

View File

@ -0,0 +1,38 @@
package io.metersphere.controller;
import io.metersphere.base.domain.ServiceIntegration;
import io.metersphere.controller.request.IntegrationRequest;
import io.metersphere.service.IntegrationService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RequestMapping("service/integration")
@RestController
public class ServiceIntegrationController {
@Resource
private IntegrationService integrationService;
@PostMapping("/save")
public ServiceIntegration save(@RequestBody ServiceIntegration service) {
return integrationService.save(service);
}
@PostMapping("/type")
public ServiceIntegration getByPlatform(@RequestBody IntegrationRequest request) {
return integrationService.get(request);
}
@PostMapping("/delete")
public void delete(@RequestBody IntegrationRequest request) {
integrationService.delete(request);
}
@GetMapping("/all/{orgId}")
public List<ServiceIntegration> getAll(@PathVariable String orgId) {
return integrationService.getAll(orgId);
}
}

View File

@ -1,36 +0,0 @@
package io.metersphere.controller;
import io.metersphere.base.domain.TestResource;
import io.metersphere.service.TestResourceService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RequestMapping("testresource")
@RestController
public class TestResourceController {
@Resource
private TestResourceService testResourceService;
@PostMapping("/add")
public TestResource addTestResource(@RequestBody TestResource testResource) {
return testResourceService.addTestResource(testResource);
}
@GetMapping("/list/{testResourcePoolId}")
public List<TestResource> getTestResourceList(@PathVariable(value = "testResourcePoolId") String testResourcePoolId) {
return testResourceService.getTestResourceList(testResourcePoolId);
}
@GetMapping("/delete/{testResourceId}")
public void deleteTestResource(@PathVariable(value = "testResourceId") String testResourceId) {
testResourceService.deleteTestResource(testResourceId);
}
@PostMapping("/update")
public void updateTestResource(@RequestBody TestResource testResource) {
testResourceService.updateTestResource(testResource);
}
}

View File

@ -0,0 +1,11 @@
package io.metersphere.controller.request;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class IntegrationRequest {
private String platform;
private String orgId;
}

View File

@ -14,5 +14,7 @@ public class ProjectDTO {
private String description;
private Long createTime;
private Long updateTime;
private String tapdId;
private String jiraKey;
}

View File

@ -0,0 +1,74 @@
package io.metersphere.service;
import io.metersphere.base.domain.ServiceIntegration;
import io.metersphere.base.domain.ServiceIntegrationExample;
import io.metersphere.base.mapper.ServiceIntegrationMapper;
import io.metersphere.controller.request.IntegrationRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Service
@Transactional(rollbackFor = Exception.class)
public class IntegrationService {
@Resource
private ServiceIntegrationMapper serviceIntegrationMapper;
public ServiceIntegration save(ServiceIntegration service) {
ServiceIntegrationExample example = new ServiceIntegrationExample();
example.createCriteria()
.andOrganizationIdEqualTo(service.getOrganizationId())
.andPlatformEqualTo(service.getPlatform());
List<ServiceIntegration> list = serviceIntegrationMapper.selectByExample(example);
if (!CollectionUtils.isEmpty(list)) {
serviceIntegrationMapper.updateByExampleSelective(service, example);
return list.get(0);
} else {
service.setId(UUID.randomUUID().toString());
serviceIntegrationMapper.insertSelective(service);
return service;
}
}
public ServiceIntegration get(IntegrationRequest request) {
String platform = request.getPlatform();
String orgId = request.getOrgId();
ServiceIntegrationExample example = new ServiceIntegrationExample();
ServiceIntegrationExample.Criteria criteria = example.createCriteria();
if (StringUtils.isNotBlank(platform)) {
criteria.andPlatformEqualTo(platform);
}
if (StringUtils.isNotBlank(orgId)) {
criteria.andOrganizationIdEqualTo(orgId);
}
List<ServiceIntegration> list = serviceIntegrationMapper.selectByExampleWithBLOBs(example);
return CollectionUtils.isEmpty(list) ? new ServiceIntegration() : list.get(0);
}
public void delete(IntegrationRequest request) {
String platform = request.getPlatform();
String orgId = request.getOrgId();
ServiceIntegrationExample example = new ServiceIntegrationExample();
example.createCriteria()
.andOrganizationIdEqualTo(orgId)
.andPlatformEqualTo(platform);
serviceIntegrationMapper.deleteByExample(example);
}
public List<ServiceIntegration> getAll(String orgId) {
ServiceIntegrationExample example = new ServiceIntegrationExample();
example.createCriteria().andOrganizationIdEqualTo(orgId);
List<ServiceIntegration> list = serviceIntegrationMapper.selectByExample(example);
return CollectionUtils.isEmpty(list) ? new ArrayList<>() : list;
}
}

View File

@ -0,0 +1,177 @@
package io.metersphere.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.TestCaseIssuesMapper;
import io.metersphere.commons.constants.IssuesManagePlatform;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.EncryptUtils;
import io.metersphere.commons.utils.RestTemplateUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.ResultHolder;
import io.metersphere.controller.request.IntegrationRequest;
import io.metersphere.track.dto.IssuesDTO;
import io.metersphere.track.request.testcase.IssuesRequest;
import io.metersphere.track.service.TestCaseService;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class IssuesService {
@Resource
private IntegrationService integrationService;
@Resource
private TestCaseIssuesMapper testCaseIssuesMapper;
@Resource
private ProjectService projectService;
@Resource
private TestCaseService testCaseService;
public void testAuth() {
String url = "https://api.tapd.cn/quickstart/testauth";
ResultHolder call = call(url);
System.out.println(call.getData());
}
public void addIssues(IssuesRequest issuesRequest) {
String url = "https://api.tapd.cn/bugs";
String testCaseId = issuesRequest.getTestCaseId();
String tapdId = getTapdProjectId(testCaseId);
if (StringUtils.isBlank(tapdId)) {
MSException.throwException("未关联Tapd 项目ID");
}
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
paramMap.add("title", issuesRequest.getTitle());
paramMap.add("workspace_id", tapdId);
paramMap.add("description", issuesRequest.getContent());
ResultHolder result = call(url, HttpMethod.POST, paramMap);
String listJson = JSON.toJSONString(result.getData());
JSONObject jsonObject = JSONObject.parseObject(listJson);
String issuesId = jsonObject.getObject("Bug", IssuesDTO.class).getId();
// 用例与第三方缺陷平台中的缺陷关联
TestCaseIssues issues = new TestCaseIssues();
issues.setId(UUID.randomUUID().toString());
issues.setIssuesId(issuesId);
issues.setTestCaseId(testCaseId);
testCaseIssuesMapper.insert(issues);
}
private ResultHolder call(String url) {
return call(url, HttpMethod.GET, null);
}
private ResultHolder call(String url, HttpMethod httpMethod, Object params) {
String responseJson;
String config = tapdConfig();
JSONObject object = JSON.parseObject(config);
if (object == null) {
MSException.throwException("tapd config is null");
}
String account = object.getString("account");
String password = object.getString("password");
HttpHeaders header = tapdAuth(account, password);
if (httpMethod.equals(HttpMethod.GET)) {
responseJson = RestTemplateUtils.get(url, header);
} else {
responseJson = RestTemplateUtils.post(url, params, header);
}
ResultHolder result = JSON.parseObject(responseJson, ResultHolder.class);
if (!result.isSuccess()) {
MSException.throwException(result.getMessage());
}
return JSON.parseObject(responseJson, ResultHolder.class);
}
private String tapdConfig() {
SessionUser user = SessionUtils.getUser();
String orgId = user.getLastOrganizationId();
IntegrationRequest request = new IntegrationRequest();
if (StringUtils.isBlank(orgId)) {
MSException.throwException("organization id is null");
}
request.setOrgId(orgId);
request.setPlatform(IssuesManagePlatform.Tapd.toString());
ServiceIntegration integration = integrationService.get(request);
return integration.getConfiguration();
}
private HttpHeaders tapdAuth(String apiUser, String password) {
String authKey = EncryptUtils.base64Encoding(apiUser + ":" + password);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + authKey);
return headers;
}
public IssuesDTO getTapdIssues(String projectId, String issuesId) {
String url = "https://api.tapd.cn/bugs?workspace_id=" + projectId + "&id=" + issuesId;
ResultHolder call = call(url);
String listJson = JSON.toJSONString(call.getData());
if (StringUtils.equals(Boolean.FALSE.toString(), listJson)) {
return new IssuesDTO();
}
JSONObject jsonObject = JSONObject.parseObject(listJson);
return jsonObject.getObject("Bug", IssuesDTO.class);
}
public List<IssuesDTO> getIssues(String caseId) {
List<IssuesDTO> list = new ArrayList<>();
String tapdId = getTapdProjectId(caseId);
TestCaseIssuesExample example = new TestCaseIssuesExample();
example.createCriteria().andTestCaseIdEqualTo(caseId);
List<TestCaseIssues> issues = testCaseIssuesMapper.selectByExample(example);
List<String> issuesIds = issues.stream().map(issue -> issue.getIssuesId()).collect(Collectors.toList());
issuesIds.forEach(issuesId -> {
IssuesDTO dto = getTapdIssues(tapdId, issuesId);
if (StringUtils.isBlank(dto.getId())) {
// 缺陷不存在解除用例和缺陷的关联
TestCaseIssuesExample issuesExample = new TestCaseIssuesExample();
issuesExample.createCriteria()
.andTestCaseIdEqualTo(caseId)
.andIssuesIdEqualTo(issuesId);
testCaseIssuesMapper.deleteByExample(issuesExample);
} else {
list.add(dto);
}
});
return list;
}
public String getTapdProjectId(String testCaseId) {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
Project project = projectService.getProjectById(testCase.getProjectId());
return project.getTapdId();
}
}

View File

@ -0,0 +1,27 @@
package io.metersphere.track.controller;
import io.metersphere.service.IssuesService;
import io.metersphere.track.dto.IssuesDTO;
import io.metersphere.track.request.testcase.IssuesRequest;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RequestMapping("issues")
@RestController
public class TestCaseIssuesController {
@Resource
private IssuesService issuesService;
@PostMapping("/add")
public void addIssues(@RequestBody IssuesRequest issuesRequest) {
issuesService.addIssues(issuesRequest);
}
@GetMapping("/get/{id}")
public List<IssuesDTO> getIssues(@PathVariable String id) {
return issuesService.getIssues(id);
}
}

View File

@ -0,0 +1,13 @@
package io.metersphere.track.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class IssuesDTO {
private String id;
private String title;
private String status;
private String description;
}

View File

@ -0,0 +1,13 @@
package io.metersphere.track.request.testcase;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class IssuesRequest {
private String title;
private String content;
private String projectId;
private String testCaseId;
}

View File

@ -0,0 +1,18 @@
create table service_integration
(
id varchar(50) not null,
organization_id varchar(50) not null,
platform varchar(50) not null,
configuration text not null,
constraint service_integration_pk
primary key (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
create table if not exists test_case_issues
(
id varchar(50) not null
primary key,
test_case_id varchar(50) not null,
issues_id varchar(100) not null,
platform varchar(50) not null
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -0,0 +1,2 @@
alter table project add tapd_id varchar(50) null;
alter table project add jira_key varchar(50) null;

View File

@ -66,7 +66,7 @@
<style scoped>
.el-table {
cursor:pointer;
cursor: pointer;
}
</style>

View File

@ -9,18 +9,25 @@
<span class="time">{{ report.createTime | timestampFormatDate }}</span>
</header>
<main v-if="this.isNotRunning">
<ms-metric-chart :content="content"/>
<el-tabs v-model="activeName">
<el-tab-pane :label="$t('api_report.total')" name="total">
<ms-scenario-results :scenarios="content.scenarios"/>
</el-tab-pane>
<el-tab-pane name="fail">
<template slot="label">
<span class="fail">{{ $t('api_report.fail') }}</span>
</template>
<ms-scenario-results :scenarios="fails"/>
</el-tab-pane>
</el-tabs>
<ms-metric-chart :content="content" :totalTime="totalTime"/>
<el-row :gutter="20">
<el-col :span="8">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane :label="$t('api_report.total')" name="total">
<ms-scenario-results :scenarios="content.scenarios" v-on:requestResult="requestResult"/>
</el-tab-pane>
<el-tab-pane name="fail">
<template slot="label">
<span class="fail">{{ $t('api_report.fail') }}</span>
</template>
<ms-scenario-results v-on:requestResult="requestResult" :scenarios="fails"/>
</el-tab-pane>
</el-tabs>
</el-col>
<el-col :span="16" style="margin-top: 40px;">
<ms-request-result-tail v-if="isRequestResult" :request="request" :scenario-name="scenarioName"/>
</el-col>
</el-row>
</main>
</section>
</el-card>
@ -30,131 +37,150 @@
<script>
import MsRequestResult from "./components/RequestResult";
import MsScenarioResult from "./components/ScenarioResult";
import MsMetricChart from "./components/MetricChart";
import MsScenarioResults from "./components/ScenarioResults";
import MsRequestResult from "./components/RequestResult";
import MsRequestResultTail from "./components/RequestResultTail";
import MsScenarioResult from "./components/ScenarioResult";
import MsMetricChart from "./components/MetricChart";
import MsScenarioResults from "./components/ScenarioResults";
import {Scenario} from "../test/model/ScenarioModel";
export default {
name: "MsApiReportView",
components: {MsScenarioResults, MsMetricChart, MsScenarioResult, MsRequestResult},
data() {
return {
activeName: "total",
content: {},
report: {},
loading: true,
fails: []
}
},
methods: {
init() {
this.loading = true;
this.report = {};
this.content = {};
this.fails = [];
export default {
name: "MsApiReportView",
components: {MsScenarioResults, MsRequestResultTail, MsMetricChart, MsScenarioResult, MsRequestResult},
data() {
return {
activeName: "total",
content: {},
report: {},
loading: true,
fails: [],
totalTime: "",
isRequestResult: false,
request: {},
scenarioName: null,
}
},
getReport() {
this.init();
if (this.reportId) {
let url = "/api/report/get/" + this.reportId;
this.$get(url, response => {
this.report = response.data || {};
if (response.data) {
if (this.isNotRunning) {
try {
this.content = JSON.parse(this.report.content);
} catch (e) {
console.log(this.report.content)
throw e;
methods: {
init() {
this.loading = true;
this.report = {};
this.content = {};
this.fails = [];
},
handleClick(tab, event) {
this.isRequestResult = false
},
getReport() {
this.init();
if (this.reportId) {
let url = "/api/report/get/" + this.reportId;
this.$get(url, response => {
this.report = response.data || {};
if (response.data) {
if (this.isNotRunning) {
try {
this.content = JSON.parse(this.report.content);
} catch (e) {
console.log(this.report.content)
throw e;
}
this.getFails();
this.loading = false;
} else {
setTimeout(this.getReport, 2000)
}
this.getFails();
this.loading = false;
} else {
setTimeout(this.getReport, 2000)
this.loading = false;
this.$error(this.$t('api_report.not_exist'));
}
} else {
this.loading = false;
this.$error(this.$t('api_report.not_exist'));
}
});
}
},
getFails() {
if (this.isNotRunning) {
this.fails = [];
this.content.scenarios.forEach((scenario) => {
this.totalTime = this.totalTime + scenario.responseTime
let failScenario = Object.assign({}, scenario);
if (scenario.error > 0) {
this.fails.push(failScenario);
failScenario.requestResults = [];
scenario.requestResults.forEach((request) => {
if (!request.success) {
let failRequest = Object.assign({}, request);
failScenario.requestResults.push(failRequest);
}
})
}
})
}
},
requestResult(requestResult) {
this.isRequestResult = false;
this.$nextTick(function () {
this.isRequestResult = true;
this.request = requestResult.request;
this.scenarioName = requestResult.scenarioName;
});
}
},
getFails() {
if (this.isNotRunning) {
this.fails = [];
this.content.scenarios.forEach((scenario) => {
let failScenario = Object.assign({}, scenario);
if (scenario.error > 0) {
this.fails.push(failScenario);
failScenario.requestResults = [];
scenario.requestResults.forEach((request) => {
if (!request.success) {
let failRequest = Object.assign({}, request);
failScenario.requestResults.push(failRequest);
}
})
}
})
watch: {
'$route': 'getReport',
},
created() {
this.getReport();
},
computed: {
reportId: function () {
return this.$route.params.reportId;
},
path() {
return "/api/test/edit?id=" + this.report.testId;
},
isNotRunning() {
return "Running" !== this.report.status;
}
}
},
watch: {
'$route': 'getReport',
},
created() {
this.getReport();
},
computed: {
reportId: function () {
return this.$route.params.reportId;
},
path() {
return "/api/test/edit?id=" + this.report.testId;
},
isNotRunning() {
return "Running" !== this.report.status;
}
}
}
</script>
<style>
.report-container .el-tabs__header {
margin-bottom: 1px;
}
.report-container .el-tabs__header {
margin-bottom: 1px;
}
</style>
<style scoped>
.report-container {
height: calc(100vh - 150px);
min-height: 600px;
overflow-y: auto;
}
.report-container {
height: calc(100vh - 150px);
min-height: 600px;
overflow-y: auto;
}
.report-header {
font-size: 15px;
}
.report-header {
font-size: 15px;
}
.report-header a {
text-decoration: none;
}
.report-header a {
text-decoration: none;
}
.report-header .time {
color: #909399;
margin-left: 10px;
}
.report-header .time {
color: #909399;
margin-left: 10px;
}
.report-container .fail {
color: #F56C6C;
}
.report-container .fail {
color: #F56C6C;
}
.report-container .is-active .fail {
color: inherit;
}
.report-container .is-active .fail {
color: inherit;
}
</style>

View File

@ -3,6 +3,12 @@
<el-row type="flex" align="middle">
<div style="width: 50%">
<el-row type="flex" justify="center" align="middle">
<el-row>
<div class="metric-time">
<div class="value" style="margin-right: 50px">{{time}}</div>
</div>
</el-row>
<chart id="chart" ref="chart" :options="options" :autoresize="true"></chart>
<el-row type="flex" justify="center" align="middle">
<i class="circle success"/>
@ -48,9 +54,37 @@
name: "MsMetricChart",
props: {
content: Object
content: Object,
totalTime: String
},
data() {
return {
hour:0,
minutes: 0,
seconds: 0,
time: 0
}
},
created() {
this.initTime()
},
methods: {
initTime() {
this.time=this.totalTime
this.seconds = Math.floor(this.time / 1000);
if (this.seconds > 60) {
this.minutes = Math.floor(this.time/60)
this.seconds=Math.floor(this.time%60)
this.time=this.minutes+"min"+this.seconds+"s"
}
if(this.minutes>60){
this.hour=Math.floor(this.minutes/60)
this.minutes = Math.floor(this.minutes%60)
this.time=this.hour+"hour"+this.minutes+"min"+this.seconds+"s"
}
this.time=this.seconds+"s"
},
},
computed: {
options() {
return {
@ -160,6 +194,12 @@
letter-spacing: -.5px;
}
.metric-time .value {
font-size: 25px;
font-weight: 400;
letter-spacing: -.5px;
}
.metric-box .name {
font-size: 16px;
letter-spacing: -.2px;

View File

@ -7,55 +7,14 @@
{{request.method}}
</div>
</el-col>
<el-col :span="12">
<el-col :span="20">
<div class="name">{{request.name}}</div>
<el-tooltip effect="dark" :content="request.url" placement="bottom" :open-delay="800">
<div class="url">{{request.url}}</div>
</el-tooltip>
</el-col>
<el-col :span="2">
<div class="time">
{{request.responseResult.responseTime}}
</div>
</el-col>
<el-col :span="2">
{{request.error}}
</el-col>
<el-col :span="2">
{{assertion}}
</el-col>
<el-col :span="2">
<el-tag size="mini" type="success" v-if="request.success">
{{$t('api_report.success')}}
</el-tag>
<el-tag size="mini" type="danger" v-else>
{{$t('api_report.fail')}}
</el-tag>
</el-col>
</el-row>
</div>
<el-collapse-transition>
<div v-show="isActive">
<el-tabs v-model="activeName" v-show="isActive" v-if="hasSub">
<el-tab-pane :label="$t('api_report.sub_result')" name="sub">
<ms-request-result class="sub-result" v-for="(sub, index) in request.subRequestResults"
:key="index" :request="sub"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_report.request_result')" name="result">
<ms-request-metric :request="request"/>
<ms-request-text :request="request"/>
<br>
<ms-response-text :response="request.responseResult"/>
</el-tab-pane>
</el-tabs>
<div v-else>
<ms-request-metric :request="request"/>
<ms-request-text :request="request"/>
<br>
<ms-response-text :response="request.responseResult"/>
</div>
</div>
</el-collapse-transition>
</div>
</template>
@ -69,30 +28,29 @@
name: "MsRequestResult",
components: {MsResponseText, MsRequestText, MsAssertionResults, MsRequestMetric},
props: {
request: Object
request: Object,
scenarioName: String
},
data() {
return {
isActive: false,
activeName: "sub",
}
return {}
},
methods: {
active() {
this.isActive = !this.isActive;
this.$emit("requestResult", {request: this.request, scenarioName: this.scenarioName});
}
},
computed: {
assertion() {
return this.request.passAssertions + " / " + this.request.totalAssertions;
},
hasSub() {
return this.request.subRequestResults.length > 0;
}
}
/* computed: {
assertion() {
return this.request.passAssertions + " / " + this.request.totalAssertions;
},
hasSub() {
return this.request.subRequestResults.length > 0;
}
}*/
}
</script>

View File

@ -0,0 +1,177 @@
<template>
<div class="request-result">
<div @click="active">
<el-row :gutter="10" type="flex" align="middle" class="info">
<el-col :span="16">
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}"/>
{{scenarioName}}
</el-col>
<el-col :span="2">
{{$t('api_report.response_time')}}
</el-col>
<el-col :span="2">
{{$t('api_report.error')}}
</el-col>
<el-col :span="2">
{{$t('api_report.assertions')}}
</el-col>
<el-col :span="2">
{{$t('api_report.result')}}
</el-col>
</el-row>
<el-row :gutter="10" type="flex" align="middle" class="info">
<el-col :span="4">
<div class="method">
{{request.method}}
</div>
</el-col>
<el-col :span="12">
<div class="name">{{request.name}}</div>
<el-tooltip effect="dark" :content="request.url" placement="bottom" :open-delay="800">
<div class="url">{{request.url}}</div>
</el-tooltip>
</el-col>
<el-col :span="2">
<div class="time">
{{request.responseResult.responseTime}}
</div>
</el-col>
<el-col :span="2">
{{request.error}}
</el-col>
<el-col :span="2">
{{assertion}}
</el-col>
<el-col :span="2">
<el-tag size="mini" type="success" v-if="request.success">
{{$t('api_report.success')}}
</el-tag>
<el-tag size="mini" type="danger" v-else>
{{$t('api_report.fail')}}
</el-tag>
</el-col>
</el-row>
</div>
<el-collapse-transition>
<div v-show="isActive">
<el-tabs v-model="activeName" v-show="isActive" v-if="hasSub">
<el-tab-pane :label="$t('api_report.sub_result')" name="sub">
<ms-request-result class="sub-result" v-for="(sub, index) in request.subRequestResults"
:key="index" :request="sub"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_report.request_result')" name="result">
<ms-request-metric :request="request"/>
<ms-request-text :request="request"/>
<br>
<ms-response-text :response="request.responseResult"/>
</el-tab-pane>
</el-tabs>
<div v-else>
<ms-request-metric :request="request"/>
<ms-request-text :request="request"/>
<br>
<ms-response-text :response="request.responseResult"/>
</div>
</div>
</el-collapse-transition>
</div>
</template>
<script>
import MsRequestMetric from "./RequestMetric";
import MsAssertionResults from "./AssertionResults";
import MsRequestText from "./RequestText";
import MsResponseText from "./ResponseText";
import MsRequestResult from "./RequestResult";
export default {
name: "MsRequestResultTail",
components: {MsResponseText, MsRequestText, MsAssertionResults, MsRequestMetric, MsRequestResult},
props: {
request: Object,
scenarioName: String
},
data() {
return {
isActive: true,
activeName: "sub",
}
},
methods: {
active() {
this.isActive = !this.isActive;
}
},
computed: {
assertion() {
return this.request.passAssertions + " / " + this.request.totalAssertions;
},
hasSub() {
return this.request.subRequestResults.length > 0;
}
}
}
</script>
<style scoped>
.request-result {
width: 100%;
min-height: 40px;
padding: 2px 0;
}
.request-result .info {
background-color: #F9F9F9;
margin-left: 20px;
cursor: pointer;
}
.request-result .method {
color: #1E90FF;
font-size: 14px;
font-weight: 500;
line-height: 40px;
padding-left: 5px;
}
.request-result .url {
color: #7f7f7f;
font-size: 12px;
font-weight: 400;
margin-top: 4px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
word-break: break-all;
}
.request-result .tab .el-tabs__header {
margin: 0;
}
.request-result .text {
height: 300px;
overflow-y: auto;
}
.sub-result .info {
background-color: #FFF;
}
.sub-result .method {
border-left: 5px solid #1E90FF;
padding-left: 20px;
}
.sub-result:last-child {
border-bottom: 1px solid #EBEEF5;
}
.request-result .icon.is-active {
transform: rotate(90deg);
}
</style>

View File

@ -30,7 +30,7 @@
data() {
return {
isActive: false,
isActive: true,
activeName: "body",
}
},

View File

@ -48,7 +48,7 @@
data() {
return {
isActive: false,
isActive: true,
activeName: "body",
modes: ['text', 'json', 'xml', 'html'],
mode: BODY_FORMAT.TEXT

View File

@ -6,28 +6,13 @@
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}"/>
{{scenario.name}}
</el-col>
<el-col :span="2">
{{scenario.responseTime}}
</el-col>
<el-col :span="2">
{{scenario.error}}
</el-col>
<el-col :span="2">
{{assertion}}
</el-col>
<el-col :span="2">
<el-tag size="mini" type="success" v-if="success">
{{$t('api_report.success')}}
</el-tag>
<el-tag size="mini" type="danger" v-else>
{{$t('api_report.fail')}}
</el-tag>
</el-col>
</el-row>
</div>
<el-collapse-transition>
<div v-show="isActive">
<ms-request-result v-for="(request, index) in scenario.requestResults" :key="index" :request="request"/>
<ms-request-result v-for="(request, index) in scenario.requestResults" :key="index" :request="request"
v-on:requestResult="requestResult"
:scenarioName="scenario.name"/>
</div>
</el-collapse-transition>
</div>
@ -54,6 +39,9 @@
methods: {
active() {
this.isActive = !this.isActive;
},
requestResult(requestResult) {
this.$emit("requestResult", requestResult);
}
},

View File

@ -5,21 +5,10 @@
<el-col :span="16">
{{$t('api_report.scenario_name')}}
</el-col>
<el-col :span="2">
{{$t('api_report.response_time')}}
</el-col>
<el-col :span="2">
{{$t('api_report.error')}}
</el-col>
<el-col :span="2">
{{$t('api_report.assertions')}}
</el-col>
<el-col :span="2">
{{$t('api_report.result')}}
</el-col>
</el-row>
</div>
<ms-scenario-result v-for="(scenario, index) in scenarios" :key="index" :scenario="scenario"/>
<ms-scenario-result v-for="(scenario, index) in scenarios" :key="index" :scenario="scenario"
v-on:requestResult="requestResult"/>
</el-card>
</template>
@ -32,9 +21,13 @@
components: {MsScenarioResult},
props: {
scenarios: Array,
scenarios: Array
},
methods: {
requestResult(requestResult) {
this.$emit("requestResult", requestResult);
}
}
}
</script>

View File

@ -5,10 +5,20 @@
<template v-slot:header>
<ms-table-header :is-tester-permission="true" :condition.sync="condition" @search="search"
:title="$t('commons.test')"
@create="create" :createTip="$t('load_test.create')"/>
@create="create" :createTip="$t('load_test.create')" :runTip="$t('load_test.run')"
:show-run="true"
@runTest="runTest"/>
</template>
<el-table border :data="tableData" class="adjust-table table-content" @sort-change="sort" @row-click="handleView"
@filter-change="filter">
<one-click-operation ref="OneClickOperation" :select-ids="selectIds" :select-names="selectNames"
:select-project-names="selectProjectNames"></one-click-operation>
<el-table border :data="tableData" class="adjust-table table-content" @sort-change="sort"
@row-click="handleView"
@filter-change="filter" @select-all="handleSelectAll" @select="selectionChange">
<el-table-column
type="selection"></el-table-column>
<el-table-column prop="name" :label="$t('commons.name')" width="250" show-overflow-tooltip>
</el-table-column>
<el-table-column prop="projectName" :label="$t('load_test.project_name')" width="200" show-overflow-tooltip/>
@ -46,6 +56,7 @@
</template>
<script>
import OneClickOperation from './OneClickOperation';
import MsTablePagination from "../../common/pagination/TablePagination";
import MsTableHeader from "../../common/components/MsTableHeader";
import MsTableOperator from "../../common/components/MsTableOperator";
@ -58,6 +69,7 @@
export default {
components: {
OneClickOperation,
MsTableOperators,
MsApiTestStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination, MsTableOperator
},
@ -74,6 +86,9 @@
pageSize: 5,
total: 0,
loading: false,
selectIds: new Set(),
selectNames: new Set(),
selectProjectNames: new Set(),
buttons: [
{
tip: this.$t('commons.edit'), icon: "el-icon-edit",
@ -105,16 +120,46 @@
create() {
this.$router.push('/api/test/create');
},
handleSelectAll(selection) {
if (selection.length > 0) {
this.tableData.forEach(item => {
this.selectIds.add(item.id);
this.selectProjectNames.add(item.projectName)
});
} else {
this.selectIds.clear()
this.selectProjectNames.clear()
}
},
selectionChange(selection, row) {
if (this.selectIds.has(row.id)) {
this.selectIds.delete(row.id);
this.selectProjectNames.delete(row.projectName)
} else {
this.selectIds.add(row.id);
this.selectProjectNames.add(row.projectName)
}
},
runTest() {
if (this.selectIds.size < 1) {
this.$warning(this.$t('test_track.plan_view.select_manipulate'));
} else {
this.$refs.OneClickOperation.openOneClickOperation();
}
},
search() {
if (this.projectId !== 'all') {
this.condition.projectId = this.projectId;
}
let url = "/api/list/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(url, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
this.tableData.forEach(item => {
this.selectNames.add(item.name)
})
});
},
handleSelectionChange(val) {

View File

@ -0,0 +1,152 @@
<template>
<el-dialog
:title="$t('load_test.run')"
:visible.sync="oneClickOperationVisible"
width="30%"
left
:destroy-on-close="true"
show-close
@closed="handleClose">
<el-form :model="ruleForm" label-position="right" label-width="120px" size="small" :rules="rule">
<el-form-item :label="$t('test_track.case.test_name')" prop="testName">
<el-input v-model="ruleForm.testName" autocomplete="off" clearable show-word-limit></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<ms-dialog-footer
@cancel="oneClickOperationVisible = false"
@confirm="checkedSaveAndRunTest"/>
</span>
</el-dialog>
</template>
<script>
import MsDialogFooter from '../../common/components/MsDialogFooter'
import {Test} from "./model/ScenarioModel";
import MsApiScenarioConfig from "./components/ApiScenarioConfig";
import MsApiReportStatus from "../report/ApiReportStatus";
import MsApiReportDialog from "./ApiReportDialog";
import {removeGoBackListener} from "../../../../common/js/utils";
export default {
name: "OneClickOperation",
components: {
MsApiReportDialog, MsApiReportStatus, MsApiScenarioConfig, MsDialogFooter
},
data() {
return {
oneClickOperationVisible: false,
test: null,
tests: [],
ruleForm: {},
rule: {
testName: [
{required: true, message: this.$t('api_test.input_name'), trigger: 'blur'},
],
}
};
},
props: {
selectIds: {
type: Set
},
selectNames: {
type: Set
},
selectProjectNames: {
type: Set
}
},
methods: {
openOneClickOperation() {
this.oneClickOperationVisible = true;
},
checkedSaveAndRunTest() {
if (this.selectNames.has(this.testName)) {
this.$warning(this.$t('load_test.already_exists'));
} else {
if (this.selectProjectNames.size > 1) {
this.$warning(this.$t('load_test.same_project_test'));
} else {
for (let x of this.selectIds) {
this.getTest(x)
}
}
}
},
getTest(id) {
this.result = this.$get("/api/get/" + id, response => {
if (response.data) {
let item = response.data;
this.tests.push(item);
let test = new Test({
projectId: item.projectId,
name: this.ruleForm.testName,
scenarioDefinition: JSON.parse(item.scenarioDefinition),
schedule: {},
});
this.test = this.test || test;
if (this.tests.length > 1) {
this.test.scenarioDefinition = this.test.scenarioDefinition.concat(test.scenarioDefinition);
}
if (this.tests.length === this.selectIds.size) {
this.tests = [];
this.saveRunTest();
this.oneClickOperationVisible = false;
}
}
});
},
saveRunTest() {
this.save(() => {
this.$success(this.$t('commons.save_success'));
this.runTest();
})
},
save(callback) {
let url = "/api/create";
this.result = this.$request(this.getOptions(url), () => {
this.create = false;
if (callback) callback();
});
},
runTest() {
this.result = this.$post("/api/run", {id: this.test.id, triggerMode: 'MANUAL'}, (response) => {
this.$success(this.$t('api_test.running'));
this.$router.push({
path: '/api/report/view/' + response.data
})
});
},
getOptions(url) {
let formData = new FormData();
let requestJson = JSON.stringify(this.test);
formData.append('request', new Blob([requestJson], {
type: "application/json"
}));
let jmx = this.test.toJMX();
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
formData.append("file", new File([blob], jmx.name));
return {
method: 'POST',
url: url,
data: formData,
headers: {
'Content-Type': undefined
}
};
},
handleClose() {
this.ruleForm = {}
},
}
}
</script>
<style scoped>
</style>

View File

@ -11,7 +11,7 @@
<ms-dropdown :default-command="body.format" v-if="body.type == 'Raw'" :commands="modes" @command="modeChange"/>
<ms-api-key-value :is-read-only="isReadOnly" :items="body.kvs" v-if="body.isKV()"/>
<ms-api-variable :is-read-only="isReadOnly" :items="body.kvs" v-if="body.isKV()"/>
<div class="body-raw" v-if="body.type == 'Raw'">
<ms-code-edit :mode="body.format" :read-only="isReadOnly" :data.sync="body.raw" :modes="modes" ref="codeEdit"/>
@ -21,24 +21,25 @@
</template>
<script>
import MsApiKeyValue from "./ApiKeyValue";
import {Body, BODY_FORMAT, BODY_TYPE} from "../model/ScenarioModel";
import MsCodeEdit from "../../../common/components/MsCodeEdit";
import MsDropdown from "../../../common/components/MsDropdown";
import MsApiKeyValue from "./ApiKeyValue";
import {Body, BODY_FORMAT, BODY_TYPE} from "../model/ScenarioModel";
import MsCodeEdit from "../../../common/components/MsCodeEdit";
import MsDropdown from "../../../common/components/MsDropdown";
import MsApiVariable from "@/business/components/api/test/components/ApiVariable";
export default {
name: "MsApiBody",
components: {MsDropdown, MsCodeEdit, MsApiKeyValue},
props: {
body: Body,
isReadOnly: {
type: Boolean,
default: false
}
},
export default {
name: "MsApiBody",
components: {MsApiVariable, MsDropdown, MsCodeEdit, MsApiKeyValue},
props: {
body: Body,
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
data() {
return {
type: BODY_TYPE,
modes: ['text', 'json', 'xml', 'html']
};

View File

@ -15,18 +15,8 @@
</el-col>
<el-col>
<el-autocomplete
:disabled="isReadOnly"
size="small"
class="input-with-autocomplete"
v-model="item.value"
:fetch-suggestions="funcSearch"
:placeholder="valueText"
value-key="name"
highlight-first-item
@select="change">
<i slot="suffix" class="el-input__icon el-icon-edit" style="cursor: pointer;" @click="advanced(item)"></i>
</el-autocomplete>
<el-input :disabled="isReadOnly" v-model="item.value" size="small" @change="change"
:placeholder="valueText" show-word-limit/>
</el-col>
<el-col class="kv-delete">
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"
@ -34,59 +24,11 @@
</el-col>
</el-row>
</div>
<el-dialog :title="$t('api_test.request.parameters_advance')"
:visible.sync="itemValueVisible"
class="advanced-item-value"
width="50%">
<el-form>
<el-form-item>
<el-input :autosize="{ minRows: 2, maxRows: 4}" type="textarea" :placeholder="valueText"
v-model="itemValue"/>
</el-form-item>
</el-form>
<div>
<el-row type="flex" align="middle">
<el-col :span="6">
<el-button size="small" type="primary" plain @click="saveAdvanced()">
{{ $t('commons.save') }}
</el-button>
<el-button size="small" type="success" plain @click="showPreview(itemValue)">
{{ $t('api_test.request.parameters_preview') }}
</el-button>
</el-col>
<el-col>
<div> {{ itemValuePreview }}</div>
</el-col>
</el-row>
</div>
<div class="format-tip">
<div>
<p>{{ $t('api_test.request.parameters_filter') }}
<el-tag size="mini" v-for="func in funcs" :key="func" @click="appendFunc(func)"
style="margin-left: 2px;cursor: pointer;">
<span>{{ func }}</span>
</el-tag>
</p>
</div>
<div>
<span>{{ $t('api_test.request.parameters_filter_desc') }}
<el-link href="http://mockjs.com/examples.html" target="_blank">http://mockjs.com/examples.html</el-link>
</span>
<p>{{ $t('api_test.request.parameters_filter_example') }}@string(10) | md5 | substr: 1, 3</p>
<p>{{ $t('api_test.request.parameters_filter_example') }}@integer(1, 5) | concat:_metersphere</p>
<p><strong>{{ $t('api_test.request.parameters_filter_tips') }}</strong></p>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import {KeyValue} from "../model/ScenarioModel";
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
import {calculate} from "@/business/components/api/test/model/ScenarioModel";
export default {
name: "MsApiKeyValue",
@ -103,16 +45,6 @@ export default {
suggestions: Array
},
data() {
return {
itemValueVisible: false,
itemValue: null,
funcs: ["md5", "sha1", "sha224", "sha256", "sha384", "sha512", "base64",
"unbase64", "substr", "concat", "lconcat", "lower", "upper", "length", "number"],
itemValuePreview: null
}
},
computed: {
keyText() {
return this.keyPlaceholder || this.$t("api_test.key");
@ -159,37 +91,6 @@ export default {
return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
};
},
funcSearch(queryString, cb) {
let funcs = MOCKJS_FUNC.concat(JMETER_FUNC);
let results = queryString ? funcs.filter(this.funcFilter(queryString)) : funcs;
// callback
cb(results);
},
funcFilter(queryString) {
return (func) => {
return (func.name.toLowerCase().indexOf(queryString.toLowerCase()) > -1);
};
},
showPreview(itemValue) {
this.itemValuePreview = calculate(itemValue);
},
appendFunc(func) {
if (this.itemValue) {
this.itemValue += " | " + func;
} else {
this.$warning(this.$t("api_test.request.parameters_preview_warning"));
}
},
advanced(item) {
this.currentItem = item;
this.itemValueVisible = true;
this.itemValue = item.value;
this.itemValuePreview = null;
},
saveAdvanced() {
this.currentItem.value = this.itemValue;
this.itemValueVisible = false;
}
},
created() {
if (this.items.length === 0) {
@ -215,19 +116,4 @@ export default {
.el-autocomplete {
width: 100%;
}
.advanced-item-value >>> .el-dialog__body {
padding: 15px 25px;
}
.format-tip {
background: #EDEDED;
}
.format-tip {
border: solid #E1E1E1 1px;
margin: 10px 0;
padding: 10px;
border-radius: 3px;
}
</style>

View File

@ -36,7 +36,8 @@
<el-main class="scenario-main">
<div class="scenario-form">
<ms-api-scenario-form :is-read-only="isReadOnly" :scenario="selected" :project-id="projectId" v-if="isScenario"/>
<ms-api-request-form :debug-report-id="debugReportId" @runDebug="runDebug" :is-read-only="isReadOnly" :request="selected" v-if="isRequest"/>
<ms-api-request-form :debug-report-id="debugReportId" @runDebug="runDebug" :is-read-only="isReadOnly"
:request="selected" :scenario="currentScenario" v-if="isRequest"/>
</div>
</el-main>
</el-container>
@ -44,25 +45,25 @@
<script>
import MsApiCollapseItem from "./collapse/ApiCollapseItem";
import MsApiCollapse from "./collapse/ApiCollapse";
import MsApiRequestConfig from "./request/ApiRequestConfig";
import MsApiRequestForm from "./request/ApiRequestForm";
import MsApiScenarioForm from "./ApiScenarioForm";
import {Scenario, Request} from "../model/ScenarioModel";
import draggable from 'vuedraggable';
import MsApiCollapseItem from "./collapse/ApiCollapseItem";
import MsApiCollapse from "./collapse/ApiCollapse";
import MsApiRequestConfig from "./request/ApiRequestConfig";
import MsApiRequestForm from "./request/ApiRequestForm";
import MsApiScenarioForm from "./ApiScenarioForm";
import {Request, Scenario} from "../model/ScenarioModel";
import draggable from 'vuedraggable';
export default {
name: "MsApiScenarioConfig",
export default {
name: "MsApiScenarioConfig",
components: {
MsApiRequestConfig,
MsApiScenarioForm,
MsApiRequestForm,
MsApiCollapse,
MsApiCollapseItem,
draggable
},
components: {
MsApiRequestConfig,
MsApiScenarioForm,
MsApiRequestForm,
MsApiCollapse,
MsApiCollapseItem,
draggable
},
props: {
scenarios: Array,

View File

@ -11,18 +11,18 @@
:label="environment.name + ': ' + environment.protocol + '://' + environment.socket"
:value="environment.id"/>
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{$t('api_test.environment.environment_config')}}
{{ $t('api_test.environment.environment_config') }}
</el-button>
<template v-slot:empty>
<div class="empty-environment">
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{$t('api_test.environment.environment_config')}}
{{ $t('api_test.environment.environment_config') }}
</el-button>
</div>
</template>
</el-select>
<el-form-item class="cookie-item">
<el-checkbox v-model="scenario.enableCookieShare">{{'共享 Cookie'}}</el-checkbox>
<el-checkbox v-model="scenario.enableCookieShare">{{ '共享 Cookie' }}</el-checkbox>
</el-form-item>
</el-form-item>
@ -33,6 +33,7 @@
</el-tab-pane>
<el-tab-pane :label="$t('api_test.scenario.headers')" name="headers">
<ms-api-key-value :is-read-only="isReadOnly" :items="scenario.headers" :suggestions="headerSuggestions"
:environment="scenario.environment"
:description="$t('api_test.scenario.kv_description')"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.scenario.dubbo')" name="dubbo">
@ -52,127 +53,127 @@
</template>
<script>
import MsApiKeyValue from "./ApiKeyValue";
import {Scenario} from "../model/ScenarioModel";
import MsApiScenarioVariables from "./ApiScenarioVariables";
import ApiEnvironmentConfig from "./ApiEnvironmentConfig";
import {REQUEST_HEADERS} from "@/common/js/constants";
import MsDubboRegistryCenter from "@/business/components/api/test/components/request/dubbo/RegistryCenter";
import MsDubboConfigCenter from "@/business/components/api/test/components/request/dubbo/ConfigCenter";
import MsDubboConsumerService from "@/business/components/api/test/components/request/dubbo/ConsumerAndService";
import MsApiKeyValue from "./ApiKeyValue";
import {Scenario} from "../model/ScenarioModel";
import MsApiScenarioVariables from "./ApiScenarioVariables";
import ApiEnvironmentConfig from "./ApiEnvironmentConfig";
import {REQUEST_HEADERS} from "@/common/js/constants";
import MsDubboRegistryCenter from "@/business/components/api/test/components/request/dubbo/RegistryCenter";
import MsDubboConfigCenter from "@/business/components/api/test/components/request/dubbo/ConfigCenter";
import MsDubboConsumerService from "@/business/components/api/test/components/request/dubbo/ConsumerAndService";
export default {
name: "MsApiScenarioForm",
components: {
MsDubboConsumerService,
MsDubboConfigCenter, MsDubboRegistryCenter, ApiEnvironmentConfig, MsApiScenarioVariables, MsApiKeyValue
},
props: {
scenario: Scenario,
projectId: String,
isReadOnly: {
type: Boolean,
default: false
}
},
created() {
export default {
name: "MsApiScenarioForm",
components: {
MsDubboConsumerService,
MsDubboConfigCenter, MsDubboRegistryCenter, ApiEnvironmentConfig, MsApiScenarioVariables, MsApiKeyValue
},
props: {
scenario: Scenario,
projectId: String,
isReadOnly: {
type: Boolean,
default: false
}
},
created() {
this.getEnvironments();
},
data() {
return {
result: {},
activeName: "parameters",
environments: [],
rules: {
name: [
{max: 100, message: this.$t('commons.input_limit', [1, 100]), trigger: 'blur'}
],
url: [
{max: 100, message: this.$t('commons.input_limit', [1, 100]), trigger: 'blur'}
]
},
headerSuggestions: REQUEST_HEADERS
}
},
watch: {
projectId() {
this.getEnvironments();
},
data() {
return {
result: {},
activeName: "parameters",
environments: [],
rules: {
name: [
{max: 100, message: this.$t('commons.input_limit', [1, 100]), trigger: 'blur'}
],
url: [
{max: 100, message: this.$t('commons.input_limit', [1, 100]), trigger: 'blur'}
]
},
headerSuggestions: REQUEST_HEADERS
}
},
watch: {
projectId() {
this.getEnvironments();
}
},
methods: {
getEnvironments() {
if (this.projectId) {
this.result = this.$get('/api/environment/list/' + this.projectId, response => {
this.environments = response.data;
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.scenario.environmentId) {
this.scenario.environment = this.environments[i];
hasEnvironment = true;
break;
}
}
},
methods: {
getEnvironments() {
if (this.projectId) {
this.result = this.$get('/api/environment/list/' + this.projectId, response => {
this.environments = response.data;
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.scenario.environmentId) {
this.scenario.environment = this.environments[i];
hasEnvironment = true;
break;
}
if (!hasEnvironment) {
this.scenario.environmentId = '';
this.scenario.environment = undefined;
}
});
} else {
this.scenario.environmentId = '';
this.scenario.environment = undefined;
}
},
environmentChange(value) {
for (let i in this.environments) {
if (this.environments[i].id === value) {
this.scenario.environment = this.environments[i];
break;
}
}
if (!value) {
this.scenario.environment = undefined;
this.scenario.requests.forEach(request => {
request.environment = undefined;
});
}
},
openEnvironmentConfig() {
if (!this.projectId) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.projectId);
},
environmentConfigClose() {
this.getEnvironments();
if (!hasEnvironment) {
this.scenario.environmentId = '';
this.scenario.environment = undefined;
}
});
} else {
this.scenario.environmentId = '';
this.scenario.environment = undefined;
}
},
environmentChange(value) {
for (let i in this.environments) {
if (this.environments[i].id === value) {
this.scenario.environment = this.environments[i];
break;
}
}
if (!value) {
this.scenario.environment = undefined;
this.scenario.requests.forEach(request => {
request.environment = undefined;
});
}
},
openEnvironmentConfig() {
if (!this.projectId) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.projectId);
},
environmentConfigClose() {
this.getEnvironments();
}
}
}
</script>
<style scoped>
.environment-select {
width: 100%;
}
.environment-select {
width: 100%;
}
.environment-button {
margin-left: 20px;
padding: 7px;
}
.environment-button {
margin-left: 20px;
padding: 7px;
}
.empty-environment {
padding: 10px 0;
}
.empty-environment {
padding: 10px 0;
}
.dubbo-config-title {
margin-bottom: 10px;
font-size: 15px;
font-weight: 600;
}
.dubbo-config-title {
margin-bottom: 10px;
font-size: 15px;
font-weight: 600;
}
.cookie-item {
margin-top: 15px;
}
.cookie-item {
margin-top: 15px;
}
</style>

View File

@ -0,0 +1,167 @@
<template>
<div>
<span class="kv-description" v-if="description">
{{ description }}
</span>
<div class="kv-row" v-for="(item, index) in parameters" :key="index">
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
<el-col>
<el-input v-if="!suggestions" :disabled="isReadOnly" v-model="item.name" size="small" maxlength="200"
@change="change"
:placeholder="keyText" show-word-limit/>
<el-autocomplete :disabled="isReadOnly" :maxlength="200" v-if="suggestions" v-model="item.name" size="small"
:fetch-suggestions="querySearch" @change="change" :placeholder="keyText"
show-word-limit/>
</el-col>
<el-col>
<el-autocomplete
:disabled="isReadOnly"
size="small"
class="input-with-autocomplete"
v-model="item.value"
:fetch-suggestions="funcSearch"
:placeholder="valueText"
value-key="name"
highlight-first-item
@select="change">
<i slot="suffix" class="el-input__icon el-icon-edit" style="cursor: pointer;" @click="advanced(item)"></i>
</el-autocomplete>
</el-col>
<el-col class="kv-delete">
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"
:disabled="isDisable(index) || isReadOnly"/>
</el-col>
</el-row>
</div>
<ms-api-variable-advance ref="variableAdvance" :environment="environment" :scenario="scenario" :request="request"
:current-item="currentItem"/>
</div>
</template>
<script>
import {HttpRequest, KeyValue, Scenario} from "../model/ScenarioModel";
import {MOCKJS_FUNC} from "@/common/js/constants";
import MsApiVariableAdvance from "@/business/components/api/test/components/ApiVariableAdvance";
export default {
name: "MsApiVariable",
components: {MsApiVariableAdvance},
props: {
keyPlaceholder: String,
valuePlaceholder: String,
description: String,
request: HttpRequest,
environment: Object,
scenario: Scenario,
isReadOnly: {
type: Boolean,
default: false
},
suggestions: Array
},
data() {
return {
currentItem: null,
parameters: [],
}
},
computed: {
keyText() {
return this.keyPlaceholder || this.$t("api_test.key");
},
valueText() {
return this.valuePlaceholder || this.$t("api_test.value");
}
},
methods: {
remove: function (index) {
this.parameters.splice(index, 1);
this.$emit('change', this.parameters);
},
change: function () {
let isNeedCreate = true;
let removeIndex = -1;
this.parameters.forEach((item, index) => {
if (!item.name && !item.value) {
//
if (index !== this.parameters.length - 1) {
removeIndex = index;
}
//
isNeedCreate = false;
}
});
if (isNeedCreate) {
this.parameters.push(new KeyValue());
}
this.$emit('change', this.parameters);
// TODO key
},
isDisable: function (index) {
return this.parameters.length - 1 === index;
},
querySearch(queryString, cb) {
let suggestions = this.suggestions;
let results = queryString ? suggestions.filter(this.createFilter(queryString)) : suggestions;
cb(results);
},
createFilter(queryString) {
return (restaurant) => {
return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
};
},
funcSearch(queryString, cb) {
let funcs = MOCKJS_FUNC;
let results = queryString ? funcs.filter(this.funcFilter(queryString)) : funcs;
// callback
cb(results);
},
funcFilter(queryString) {
return (func) => {
return (func.name.toLowerCase().indexOf(queryString.toLowerCase()) > -1);
};
},
advanced(item) {
this.$refs.variableAdvance.open();
this.currentItem = item;
this.itemValue = '';
this.mockVariableFuncs = [];
},
},
created() {
if (this.parameters.length === 0) {
this.parameters.push(new KeyValue());
}
}
}
</script>
<style scoped>
.kv-description {
font-size: 13px;
}
.kv-row {
margin-top: 10px;
}
.kv-delete {
width: 60px;
}
.el-autocomplete {
width: 100%;
}
.advanced-item-value >>> .el-dialog__body {
padding: 15px 25px;
}
.el-row {
margin-bottom: 5px;
}
</style>

View File

@ -0,0 +1,286 @@
<template>
<el-dialog :title="$t('api_test.request.parameters_advance')"
:visible.sync="itemValueVisible"
class="advanced-item-value"
width="70%">
<el-tabs tab-position="top" style="height: 50vh;" @tab-click="selectTab">
<el-tab-pane :label="$t('api_test.request.parameters_advance_mock')">
<el-row type="flex" :gutter="20">
<el-col :span="6" class="col-height">
<div>
<el-input size="small" v-model="filterText"
:placeholder="$t('api_test.request.parameters_mock_filter_tips')"/>
<el-tree class="filter-tree" ref="tree" :data="mockFuncs" :props="treeProps"
default-expand-all @node-click="selectVariable"
:filter-node-method="filterNode"></el-tree>
</div>
</el-col>
<el-col :span="6" v-for="(itemFunc, itemIndex) in mockVariableFuncs" :key="itemIndex">
<div v-for="(func, funcIndex) in funcs"
:key="`${itemIndex}-${funcIndex}`">
<el-row>
<el-col :span="12">
<el-radio size="mini" v-model="itemFunc.name" :label="func.name"
@change="methodChange(itemFunc, func)"/>
</el-col>
<el-col :span="12" v-if="itemFunc.name === func.name">
<div v-for="(p, pIndex) in itemFunc.params" :key="`${itemIndex}-${funcIndex}-${pIndex}`">
<el-input :placeholder="p.name" size="mini" v-model="p.value" @change="showPreview"/>
</div>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane label="变量">
<el-row>
<el-col :span="6" class="col-height">
<div v-if="environment">
<p>{{ $t('api_test.environment.environment') }}</p>
<el-tree :data="environmentParams" :props="treeProps" @node-click="selectVariable"></el-tree>
</div>
<div v-if="scenario">
<p>{{ $t('api_test.scenario.scenario') }}</p>
<el-tree :data="scenarioParams" :props="treeProps" @node-click="selectVariable"></el-tree>
</div>
<div v-if="preRequestParams">
<p>{{ $t('api_test.request.parameters_pre_request') }}</p>
<el-tree :data="preRequestParams" :props="treeProps" @node-click="selectVariable"></el-tree>
</div>
</el-col>
<el-col :span="6" v-for="(itemFunc, itemIndex) in jmeterVariableFuncs" :key="itemIndex" class="col-height">
<div>
<div v-for="(func, funcIndex) in jmeterFuncs"
:key="`${itemIndex}-${funcIndex}`">
<el-row>
<el-radio size="mini" v-model="itemFunc.name" :label="func.name"
@change="methodChange(itemFunc, func)"/>
</el-row>
</div>
</div>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
<el-form>
<el-form-item>
<el-input :placeholder="valueText" size="small"
v-model="itemValue"/>
</el-form-item>
</el-form>
<div style="padding-top: 10px;">
<el-row type="flex" align="middle">
<el-col :span="12">
<el-button size="small" type="primary" plain @click="saveAdvanced()">
{{ $t('commons.save') }}
</el-button>
<el-button size="small" type="info" plain @click="addFunc()" v-if="currentTab === 0">
{{ $t('api_test.request.parameters_advance_add_func') }}
</el-button>
<el-button size="small" type="success" plain @click="showPreview()" v-if="currentTab === 0">
{{ $t('api_test.request.parameters_preview') }}
</el-button>
</el-col>
<el-col>
<div> {{ itemValuePreview }}</div>
</el-col>
</el-row>
</div>
</el-dialog>
</template>
<script>
import {calculate, HttpRequest, Scenario} from "@/business/components/api/test/model/ScenarioModel";
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
export default {
name: "MsApiVariableAdvance",
props: {
request: HttpRequest,
environment: Object,
scenario: Scenario,
currentItem: Object,
},
data() {
return {
itemValueVisible: false,
filterText: '',
environmentParams: [],
scenarioParams: [],
preRequests: [],
preRequestParams: [],
treeProps: {children: 'children', label: 'name'},
currentTab: 0,
itemValue: null,
itemValuePreview: null,
funcs: [
{name: "md5"},
{name: "base64"},
{name: "unbase64"},
{
name: "substr",
params: [{name: "start"}, {name: "length"}]
},
{
name: "concat",
params: [{name: "suffix"}]
},
{name: "lconcat", params: [{name: "prefix"}]},
{name: "sha1"},
{name: "sha224"},
{name: "sha256"},
{name: "sha384"},
{name: "sha512"},
{name: "lower"},
{name: "upper"},
{name: "length"},
{name: "number"}
],
mockFuncs: MOCKJS_FUNC.map(f => {
return {name: f.name, value: f.name}
}),
jmeterFuncs: JMETER_FUNC,
mockVariableFuncs: [],
jmeterVariableFuncs: [],
}
},
computed: {
valueText() {
return this.valuePlaceholder || this.$t("api_test.value");
}
},
mounted() {
this.prepareData();
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
},
},
methods: {
open() {
this.itemValueVisible = true;
},
prepareData() {
if (this.request) {
this.parameters = this.request.parameters;
}
if (this.scenario) {
let variables = this.scenario.variables;
this.scenarioParams = [
{
name: this.scenario.name,
children: variables.filter(v => v.name).map(v => {
return {name: v.name, value: '${' + v.name + '}'}
}),
}
];
if (this.environment) {
let variables = JSON.parse(this.environment.variables);
this.environmentParams = [
{
name: this.environment.name,
children: variables.filter(v => v.name).map(v => {
return {name: v.name, value: '${' + v.name + '}'}
}),
}
];
}
let i = this.scenario.requests.indexOf(this.request);
this.preRequests = this.scenario.requests.slice(0, i);
this.preRequests.forEach(r => {
let js = r.extract.json.map(v => {
return {name: v.variable, value: v.value}
});
let xs = r.extract.xpath.map(v => {
return {name: v.variable, value: v.value}
});
let rx = r.extract.regex.map(v => {
return {name: v.variable, value: v.value}
});
let vs = [...js, ...xs, ...rx];
if (vs.length > 0) {
this.preRequestParams.push({name: r.name, children: vs});
}
});
}
},
filterNode(value, data) {
if (!value) return true;
return data.name.indexOf(value) !== -1;
},
selectVariable(node) {
this.itemValue = node.value;
},
selectTab(tab) {
this.currentTab = +tab.index;
this.itemValue = null;
this.itemValuePreview = null;
},
showPreview() {
//
if (!this.itemValue) {
return;
}
let index = this.itemValue.indexOf("|");
if (index > -1) {
this.itemValue = this.itemValue.substring(0, index).trim();
}
this.mockVariableFuncs.forEach(f => {
if (!f.name) {
return;
}
this.itemValue += "|" + f.name;
if (f.params) {
this.itemValue += ":" + f.params.map(p => p.value).join(",");
}
});
this.itemValuePreview = calculate(this.itemValue);
},
methodChange(itemFunc, func) {
let index = this.mockVariableFuncs.indexOf(itemFunc);
this.mockVariableFuncs = this.mockVariableFuncs.slice(0, index);
// deep copy
this.mockVariableFuncs.push(JSON.parse(JSON.stringify(func)));
this.showPreview();
},
addFunc() {
if (this.mockVariableFuncs.length > 4) {
this.$info(this.$t('api_test.request.parameters_advance_add_func_limit'));
return;
}
if (this.mockVariableFuncs.length > 0) {
let func = this.mockVariableFuncs[this.mockVariableFuncs.length - 1];
if (!func.name) {
this.$warning(this.$t('api_test.request.parameters_advance_add_func_error'));
return;
}
if (func.params) {
for (let j = 0; j < func.params.length; j++) {
if (!func.params[j].value) {
this.$warning(this.$t('api_test.request.parameters_advance_add_param_error'));
return;
}
}
}
}
this.mockVariableFuncs.push({name: '', params: []});
},
saveAdvanced() {
this.currentItem.value = this.itemValue;
this.itemValueVisible = false;
this.mockVariableFuncs = [];
}
}
}
</script>
<style scoped>
.col-height {
height: 40vh;
overflow: auto;
}
</style>

View File

@ -26,9 +26,10 @@
<el-form-item v-if="request.useEnvironment" :label="$t('api_test.request.address')" class="adjust-margin-bottom">
<el-tag class="environment-display">
<span class="environment-name">{{request.environment ? request.environment.name + ': ' : ''}}</span>
<span class="environment-url">{{displayUrl}}</span>
<span v-if="!displayUrl" class="environment-url-tip">{{$t('api_test.request.please_configure_environment_in_scenario')}}</span>
<span class="environment-name">{{ request.environment ? request.environment.name + ': ' : '' }}</span>
<span class="environment-url">{{ displayUrl }}</span>
<span v-if="!displayUrl"
class="environment-url-tip">{{ $t('api_test.request.please_configure_environment_in_scenario') }}</span>
</el-tag>
</el-form-item>
@ -39,17 +40,24 @@
</el-switch>
</el-form-item>
<el-button class="debug-button" size="small" type="primary" @click="runDebug">{{$t('load_test.save_and_run')}}</el-button>
<el-button class="debug-button" size="small" type="primary" @click="runDebug">{{ $t('load_test.save_and_run') }}
</el-button>
<el-tabs v-model="activeName">
<el-tab-pane :label="$t('api_test.request.parameters')" name="parameters">
<ms-api-body v-if="isNotGet" :is-read-only="isReadOnly" :body="request.body"/>
<ms-api-key-value v-else :is-read-only="isReadOnly" :items="request.parameters"
:description="$t('api_test.request.parameters_desc')"/>
<ms-api-variable :is-read-only="isReadOnly"
:request="request"
:environment="request.environment"
:scenario="scenario"
:extract="request.extract"
:description="$t('api_test.request.parameters_desc')"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.headers')" name="headers">
<ms-api-key-value :is-read-only="isReadOnly" :suggestions="headerSuggestions" :items="request.headers"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.body')" name="body" v-if="isNotGet">
<ms-api-body :is-read-only="isReadOnly" :body="request.body"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.assertions.label')" name="assertions">
<ms-api-assertions :is-read-only="isReadOnly" :assertions="request.assertions"/>
</el-tab-pane>
@ -64,134 +72,136 @@
import MsApiKeyValue from "../ApiKeyValue";
import MsApiBody from "../ApiBody";
import MsApiAssertions from "../assertion/ApiAssertions";
import {HttpRequest, KeyValue} from "../../model/ScenarioModel";
import {HttpRequest, KeyValue, Scenario} from "../../model/ScenarioModel";
import MsApiExtract from "../extract/ApiExtract";
import ApiRequestMethodSelect from "../collapse/ApiRequestMethodSelect";
import {REQUEST_HEADERS} from "@/common/js/constants";
import MsApiVariable from "@/business/components/api/test/components/ApiVariable";
export default {
name: "MsApiHttpRequestForm",
components: {ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiBody, MsApiKeyValue},
components: {MsApiVariable, ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiBody, MsApiKeyValue},
props: {
request: HttpRequest,
scenario: Scenario,
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
let validateURL = (rule, value, callback) => {
try {
new URL(this.addProtocol(this.request.url));
} catch (e) {
callback(this.$t('api_test.request.url_invalid'));
}
};
return {
activeName: "parameters",
rules: {
name: [
{max: 300, message: this.$t('commons.input_limit', [1, 300]), trigger: 'blur'}
],
url: [
{max: 500, required: true, message: this.$t('commons.input_limit', [1, 500]), trigger: 'blur'},
{validator: validateURL, trigger: 'blur'}
],
path: [
{max: 500, message: this.$t('commons.input_limit', [0, 500]), trigger: 'blur'},
]
},
headerSuggestions: REQUEST_HEADERS
data() {
let validateURL = (rule, value, callback) => {
try {
new URL(this.addProtocol(this.request.url));
} catch (e) {
callback(this.$t('api_test.request.url_invalid'));
}
};
return {
activeName: "parameters",
rules: {
name: [
{max: 300, message: this.$t('commons.input_limit', [1, 300]), trigger: 'blur'}
],
url: [
{max: 500, required: true, message: this.$t('commons.input_limit', [1, 500]), trigger: 'blur'},
{validator: validateURL, trigger: 'blur'}
],
path: [
{max: 500, message: this.$t('commons.input_limit', [0, 500]), trigger: 'blur'},
]
},
headerSuggestions: REQUEST_HEADERS
}
},
methods: {
urlChange() {
if (!this.request.url) return;
let url = this.getURL(this.addProtocol(this.request.url));
if (url) {
this.request.url = decodeURIComponent(url.origin + url.pathname);
}
},
methods: {
urlChange() {
if (!this.request.url) return;
let url = this.getURL(this.addProtocol(this.request.url));
if (url) {
this.request.url = decodeURIComponent(url.origin + url.pathname);
}
},
pathChange() {
if (!this.request.path) return;
let url = this.getURL(this.displayUrl);
let urlStr = url.origin + url.pathname;
let envUrl = this.request.environment.protocol + '://' + this.request.environment.socket;
this.request.path = decodeURIComponent(urlStr.substring(envUrl.length, urlStr.length));
},
getURL(urlStr) {
try {
let url = new URL(urlStr);
url.searchParams.forEach((value, key) => {
if (key && value) {
this.request.parameters.splice(0, 0, new KeyValue(key, value));
}
});
return url;
} catch (e) {
this.$error(this.$t('api_test.request.url_invalid'), 2000);
}
},
methodChange(value) {
if (value === 'GET' && this.activeName === 'body') {
this.activeName = 'parameters';
}
},
useEnvironmentChange(value) {
if (value && !this.request.environment) {
this.$error(this.$t('api_test.request.please_add_environment_to_scenario'), 2000);
this.request.useEnvironment = false;
}
this.$refs["request"].clearValidate();
},
addProtocol(url) {
if (url) {
if (!url.toLowerCase().startsWith("https") && !url.toLowerCase().startsWith("http")) {
return "https://" + url;
pathChange() {
if (!this.request.path) return;
let url = this.getURL(this.displayUrl);
let urlStr = url.origin + url.pathname;
let envUrl = this.request.environment.protocol + '://' + this.request.environment.socket;
this.request.path = decodeURIComponent(urlStr.substring(envUrl.length, urlStr.length));
},
getURL(urlStr) {
try {
let url = new URL(urlStr);
url.searchParams.forEach((value, key) => {
if (key && value) {
this.request.parameters.splice(0, 0, new KeyValue(key, value));
}
}
});
return url;
},
runDebug() {
this.$emit('runDebug');
} catch (e) {
this.$error(this.$t('api_test.request.url_invalid'), 2000);
}
},
computed: {
isNotGet() {
return this.request.method !== "GET";
},
displayUrl() {
return this.request.environment ? this.request.environment.protocol + '://' + this.request.environment.socket + (this.request.path ? this.request.path : '') : '';
methodChange(value) {
if (value === 'GET' && this.activeName === 'body') {
this.activeName = 'parameters';
}
},
useEnvironmentChange(value) {
if (value && !this.request.environment) {
this.$error(this.$t('api_test.request.please_add_environment_to_scenario'), 2000);
this.request.useEnvironment = false;
}
this.$refs["request"].clearValidate();
},
addProtocol(url) {
if (url) {
if (!url.toLowerCase().startsWith("https") && !url.toLowerCase().startsWith("http")) {
return "https://" + url;
}
}
return url;
},
runDebug() {
this.$emit('runDebug');
}
},
computed: {
isNotGet() {
return this.request.method !== "GET";
},
displayUrl() {
return this.request.environment ? this.request.environment.protocol + '://' + this.request.environment.socket + (this.request.path ? this.request.path : '') : '';
}
}
}
</script>
<style scoped>
.el-tag {
width: 100%;
height: 40px;
line-height: 40px;
}
.el-tag {
width: 100%;
height: 40px;
line-height: 40px;
}
.environment-display {
font-size: 14px;
}
.environment-display {
font-size: 14px;
}
.environment-name {
font-weight: bold;
font-style: italic;
}
.environment-name {
font-weight: bold;
font-style: italic;
}
.adjust-margin-bottom {
margin-bottom: 10px;
}
.adjust-margin-bottom {
margin-bottom: 10px;
}
.environment-url-tip {
color: #F56C6C;
}
.environment-url-tip {
color: #F56C6C;
}
</style>

View File

@ -1,27 +1,28 @@
<template>
<div class="request-form">
<component @runDebug="runDebug" :is="component" :is-read-only="isReadOnly" :request="request"/>
<component @runDebug="runDebug" :is="component" :is-read-only="isReadOnly" :request="request" :scenario="scenario"/>
<ms-scenario-results v-loading="debugReportLoading" v-if="isCompleted" :scenarios="isCompleted ? request.debugReport.scenarios : []"/>
</div>
</template>
<script>
import {Request, RequestFactory} from "../../model/ScenarioModel";
import MsApiHttpRequestForm from "./ApiHttpRequestForm";
import MsApiDubboRequestForm from "./ApiDubboRequestForm";
import MsScenarioResults from "../../../report/components/ScenarioResults";
import {Request, RequestFactory, Scenario} from "../../model/ScenarioModel";
import MsApiHttpRequestForm from "./ApiHttpRequestForm";
import MsApiDubboRequestForm from "./ApiDubboRequestForm";
import MsScenarioResults from "../../../report/components/ScenarioResults";
export default {
name: "MsApiRequestForm",
components: {MsScenarioResults, MsApiDubboRequestForm, MsApiHttpRequestForm},
props: {
request: Request,
isReadOnly: {
type: Boolean,
default: false
},
debugReportId: String
export default {
name: "MsApiRequestForm",
components: {MsScenarioResults, MsApiDubboRequestForm, MsApiHttpRequestForm},
props: {
scenario: Scenario,
request: Request,
isReadOnly: {
type: Boolean,
default: false
},
debugReportId: String
},
data() {
return {
reportId: "",

View File

@ -722,6 +722,8 @@ class JMXHttpRequest {
});
for (let i = 0; i < parameters.length; i++) {
let parameter = parameters[i];
// 非 GET 请求中出现了 url 参数
parameter.value = calculate(parameter.value);
path += (parameter.name + '=' + parameter.value);
if (i !== parameters.length - 1) {
path += '&';
@ -871,9 +873,6 @@ class JMXGenerator {
this.addEnvironments(environment.headers, scenario.headers)
}
let headers = this.filterKV(scenario.headers);
headers.forEach(h => {
h.value = calculate(h.value);
});
if (headers.length > 0) {
let name = scenario.name + " Headers"
threadGroup.put(new HeaderManager(name, headers));
@ -884,9 +883,6 @@ class JMXGenerator {
let name = request.name + " Headers";
this.addBodyFormat(request);
let headers = this.filterKV(request.headers);
headers.forEach(h => {
h.value = calculate(h.value);
});
if (headers.length > 0) {
httpSamplerProxy.put(new HeaderManager(name, headers));
}

View File

@ -1,5 +1,5 @@
<template>
<editor v-model="formatData" :lang="mode" @init="editorInit" theme="chrome"/>
<editor v-model="formatData" :lang="mode" @init="editorInit" theme="chrome"/>
</template>
<script>

View File

@ -5,9 +5,9 @@
</template>
<script>
export default {
name: "MsMainContainer"
}
export default {
name: "MsMainContainer"
}
</script>
<style scoped>

View File

@ -10,6 +10,10 @@
<span class="operate-button">
<ms-table-button :is-tester-permission="isTesterPermission" v-if="showCreate" icon="el-icon-circle-plus-outline"
:content="createTip" @click="create"/>
<ms-table-button :is-tester-permission="isTesterPermission" v-if="showRun" icon="el-icon-video-play"
type="primary"
:content="runTip" @click="runTest"/>
<slot name="button"></slot>
</span>
<span>
@ -40,6 +44,10 @@
type: Boolean,
default: true
},
showRun: {
type: Boolean,
default: false
},
condition: {
type: Object
},
@ -49,6 +57,11 @@
return this.$t('commons.create');
}
},
runTip: {
type: String,
},
isTesterPermission: {
type: Boolean,
default: false
@ -61,6 +74,9 @@
},
create() {
this.$emit('create');
},
runTest() {
this.$emit('runTest')
}
},
computed: {

View File

@ -15,6 +15,7 @@
changeRoute() {
//
this.$router.replace({path: this.index, query: {type: 'all'}});
window.location.reload();
}
}
}

View File

@ -56,6 +56,12 @@
<el-form-item :label="$t('commons.description')" prop="description">
<el-input :autosize="{ minRows: 2, maxRows: 4}" type="textarea" v-model="form.description"></el-input>
</el-form-item>
<el-form-item label="TAPD项目ID" v-if="tapd">
<el-input v-model="form.tapdId" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="JIRA项目key" v-if="jira">
<el-input v-model="form.jiraKey" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<template v-slot:footer>
<div class="dialog-footer">
@ -86,10 +92,12 @@
import MsDeleteConfirm from "../common/components/MsDeleteConfirm";
import MsTableOperatorButton from "../common/components/MsTableOperatorButton";
import ApiEnvironmentConfig from "../api/test/components/ApiEnvironmentConfig";
import TemplateComponent from "../track/plan/view/comonents/report/TemplateComponent/TemplateComponent";
export default {
name: "MsProject",
components: {
TemplateComponent,
ApiEnvironmentConfig,
MsTableOperatorButton,
MsDeleteConfirm,
@ -103,6 +111,8 @@
title: this.$t('project.create'),
condition: {},
items: [],
tapd: false,
jira: false,
form: {},
currentPage: 1,
pageSize: 5,
@ -171,6 +181,18 @@
this.createVisible = true;
listenGoBack(this.handleClose);
this.form = Object.assign({}, row);
if (this.baseUrl === 'track') {
this.$get("/service/integration/all/" + getCurrentUser().lastOrganizationId, response => {
let data = response.data;
let platforms = data.map(d => d.platform);
if (platforms.indexOf("Tapd") !== -1) {
this.tapd = true;
}
if (platforms.indexOf("Jira") !== -1) {
this.jira = true;
}
});
}
},
submit(formName) {
this.$refs[formName].validate((valid) => {

View File

@ -1,8 +1,8 @@
<template>
<el-card class="header-title">
<div>
<div v-loading="result.loading">
<div>{{$t('organization.select_defect_platform')}}</div>
<el-radio-group v-model="platform" style="margin-top: 10px">
<el-radio-group v-model="platform" style="margin-top: 10px" @change="change">
<el-radio v-for="(item, index) in platforms" :key="index" :label="item.value" size="small">
{{item.name}}
</el-radio>
@ -11,21 +11,26 @@
<div style="width: 500px">
<div style="margin-top: 20px;margin-bottom: 10px">{{$t('organization.basic_auth_info')}}</div>
<el-form :model="form" ref="form" label-width="100px" size="small">
<el-form :model="form" ref="form" label-width="100px" size="small" :disabled="show" :rules="rules">
<el-form-item :label="$t('organization.api_account')" prop="account">
<el-input v-model="form.account" :placeholder="$t('organization.input_api_account')"/>
</el-form-item>
<el-form-item :label="$t('organization.api_password')" prop="password">
<el-input v-model="form.password" auto-complete="new-password" :placeholder="$t('organization.input_api_password')" show-password/>
</el-form-item>
<el-form-item>
<el-button type="primary" size="small" @click="submit('form')" style="width: 400px">
{{$t('commons.save')}}
</el-button>
<el-input v-model="form.password" auto-complete="new-password"
:placeholder="$t('organization.input_api_password')" show-password/>
</el-form-item>
</el-form>
</div>
<div style="margin-left: 100px">
<el-button v-if="showEdit" size="small" @click="edit">{{$t('commons.edit')}}</el-button>
<el-button type="primary" v-if="showSave" size="small" @click="save('form')">{{$t('commons.save')}}</el-button>
<el-button v-if="showCancel" size="small" @click="cancelEdit">取消编辑</el-button>
<el-button type="info" size="small" @click="cancelIntegration('form')" :disabled="!show">
取消集成
</el-button>
</div>
<div class="defect-tip">
<div>{{$t('organization.use_tip')}}</div>
<div>
@ -33,27 +38,36 @@
</div>
<div>
2. {{$t('organization.use_tip_two')}}
<router-link to="/track/project/all" style="margin-left: 5px">{{$t('organization.link_the_project_now')}}</router-link>
<router-link to="/track/project/all" style="margin-left: 5px">{{$t('organization.link_the_project_now')}}
</router-link>
</div>
</div>
</el-card>
</template>
<script>
import {getCurrentUser} from "../../../../common/js/utils";
export default {
name: "DefectManagement",
data() {
return {
form: {},
result: {},
platform: '',
orgId: '',
show: true,
showEdit: true,
showSave: false,
showCancel: false,
platforms: [
{
name: 'TAPD',
value: 'tapd',
value: 'Tapd',
},
{
name: 'JIRA',
value: 'jira',
value: 'Jira',
}
],
rules: {
@ -62,9 +76,113 @@
},
}
},
created() {
this.init(this.platform);
},
methods: {
submit(form) {
init(platform) {
let param = {};
param.platform = platform;
param.orgId = getCurrentUser().lastOrganizationId;
this.result = this.$post("service/integration/type", param, response => {
let data = response.data;
this.platform = data.platform;
if (data.configuration) {
let config = JSON.parse(data.configuration);
this.$set(this.form, 'account', config.account);
this.$set(this.form, 'password', config.password);
} else {
this.clear();
}
})
},
edit() {
this.show = false;
this.showEdit = false;
this.showSave = true;
this.showCancel = true;
},
cancelEdit() {
this.showEdit = true;
this.showCancel = false;
this.showSave = false;
this.show = true;
this.init(this.platform);
},
cancelIntegration() {
if (this.form.account && this.form.password && this.platform) {
this.$alert("确认取消集成 " + this.platform + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let param = {};
param.orgId = getCurrentUser().lastOrganizationId;
param.platform = this.platform;
this.result = this.$post("service/integration/delete", param, () => {
this.$success("操作成功");
this.init('');
});
}
}
});
} else {
this.$warning("未集成该平台!");
}
},
save(form) {
if (!this.platform) {
this.$warning("请选择集成的平台!");
return;
}
let param = {};
let auth = {
account: this.form.account,
password: this.form.password
};
param.organizationId = getCurrentUser().lastOrganizationId;
param.platform = this.platform;
param.configuration = JSON.stringify(auth);
this.$refs[form].validate(valid => {
if (valid) {
this.result = this.$post("service/integration/save", param, () => {
this.show = true;
this.showEdit = true;
this.showSave = false;
this.showCancel = false;
this.init(this.platform);
this.$success(this.$t('commons.save_success'));
});
} else {
return false;
}
})
},
change(platform) {
this.show = true;
this.showEdit = true;
this.showCancel = false;
this.showSave = false;
let param = {};
param.orgId = getCurrentUser().lastOrganizationId;
param.platform = platform;
this.result = this.$post("service/integration/type", param, response => {
let data = response.data;
if (data.configuration) {
let config = JSON.parse(data.configuration);
this.$set(this.form, 'account', config.account);
this.$set(this.form, 'password', config.password);
} else {
this.clear();
}
})
},
clear() {
this.$set(this.form, 'account', '');
this.$set(this.form, 'password', '');
this.$nextTick(() => {
this.$refs.form.clearValidate();
});
}
}
}

View File

@ -172,21 +172,46 @@
</el-col>
</el-row>
<el-row v-if="testCase.issues">
<el-row>
<el-col :span="5" :offset="1">
<el-switch
:disabled="isReadOnly"
v-model="testCase.issues.hasIssues"
v-model="issuesSwitch"
@change="issuesChange"
:active-text="$t('test_track.plan_view.submit_issues')">
</el-switch>
<el-tooltip class="item" effect="dark"
content="在系统设置-组织-服务集成中集成缺陷管理平台可以自动提交缺陷到指定缺陷管理平台"
placement="right">
<i class="el-icon-info"/>
</el-tooltip>
</el-col>
</el-row>
<el-row v-if="testCase.issues && testCase.issues.hasIssues">
<el-row v-if="issuesSwitch">
<el-col :span="20" :offset="1" class="issues-edit">
<el-input
type="text"
placeholder="请输入标题"
v-model="testCase.issues.title"
maxlength="100"
show-word-limit
/>
<ckeditor :editor="editor" :disabled="isReadOnly" :config="editorConfig"
v-model="testCase.issues.content"/>
<el-button type="primary" size="small" @click="saveIssues">{{$t('commons.save')}}</el-button>
<el-button size="small" @click="issuesSwitch=false">{{$t('commons.cancel')}}</el-button>
</el-col>
</el-row>
<el-row>
<el-col :span="20" :offset="1" class="issues-edit">
<el-table border class="adjust-table" :data="issues" style="width: 100%">
<el-table-column prop="id" label="缺陷ID"/>
<el-table-column prop="title" label="缺陷标题"/>
<el-table-column prop="status" label="缺陷状态"/>
<el-table-column prop="description" label="缺陷描述" show-overflow-tooltip/>
</el-table>
</el-col>
</el-row>
@ -226,6 +251,7 @@
import PerformanceTestDetail from "./test/PerformanceTestDetail";
import PerformanceTestResult from "./test/PerformanceTestResult";
import {listenGoBack, removeGoBackListener} from "../../../../../../common/js/utils";
import {CURRENT_PROJECT} from "../../../../../../common/js/constants";
export default {
name: "TestPlanTestCaseEdit",
@ -242,7 +268,9 @@
showDialog: false,
testCase: {},
index: 0,
issuesSwitch: false,
testCases: [],
issues: [],
editor: ClassicEditor,
editorConfig: {
// 'increaseIndent','decreaseIndent'
@ -351,6 +379,7 @@
this.activeTab = 'detail';
listenGoBack(this.handleClose);
this.initData(testCase);
this.getIssues(testCase.caseId);
},
initTest() {
this.$nextTick(() => {
@ -403,18 +432,18 @@
}
},
issuesChange() {
if (this.testCase.issues.hasIssues) {
let desc = this.addPLabel('[' + this.$t('test_track.plan_view.operate_step') + ']');
let result = this.addPLabel('[' + this.$t('test_track.case.expected_results') + ']');
let executeResult = this.addPLabel('[' + this.$t('test_track.plan_view.actual_result') + ']');
this.testCase.steps.forEach(step => {
let stepPrefix = this.$t('test_track.plan_view.step') + step.num + ':';
desc += this.addPLabel(stepPrefix + (step.desc == undefined ? '' : step.desc));
result += this.addPLabel(stepPrefix + (step.result == undefined ? '' : step.result));
executeResult += this.addPLabel(stepPrefix + (step.executeResult == undefined ? '' : step.executeResult));
});
this.testCase.issues.content = desc + this.addPLabel('') + result + this.addPLabel('') + executeResult + this.addPLabel('');
}
// if (this.testCase.issues.hasIssues) {
// let desc = this.addPLabel('[' + this.$t('test_track.plan_view.operate_step') + ']');
// let result = this.addPLabel('[' + this.$t('test_track.case.expected_results') + ']');
// let executeResult = this.addPLabel('[' + this.$t('test_track.plan_view.actual_result') + ']');
// this.testCase.steps.forEach(step => {
// let stepPrefix = this.$t('test_track.plan_view.step') + step.num + ':';
// desc += this.addPLabel(stepPrefix + (step.desc == undefined ? '' : step.desc));
// result += this.addPLabel(stepPrefix + (step.result == undefined ? '' : step.result));
// executeResult += this.addPLabel(stepPrefix + (step.executeResult == undefined ? '' : step.executeResult));
// });
// this.testCase.issues.content = desc + this.addPLabel('') + result + this.addPLabel('') + executeResult + this.addPLabel('');
// }
},
addPLabel(str) {
return "<p>" + str + "</p>";
@ -429,6 +458,27 @@
}).length > 0;
}
},
saveIssues() {
if (!this.testCase.issues.title || !this.testCase.issues.content) {
this.$warning("标题和描述必填");
return;
}
let param = {};
param.title = this.testCase.issues.title;
param.content = this.testCase.issues.content;
param.testCaseId = this.testCase.caseId;
this.result = this.$post("/issues/add", param, () => {
this.$success(this.$t('commons.save_success'));
this.getIssues(param.testCaseId);
})
},
getIssues(caseId) {
this.result = this.$get("/issues/get/"+caseId,response => {
let data = response.data;
this.issues = data;
console.log(data);
})
}
}
}

View File

@ -73,7 +73,7 @@ export const funcFilters = {
lconcat: function (str, ...args) {
args.forEach(item => {
str = item + this._string;
str = item + str;
});
return str;
},

View File

@ -281,6 +281,8 @@ export default {
not_exist: "Test report does not exist",
},
load_test: {
same_project_test: 'Only tests within the same project can be run',
run: 'One click operation',
operating: 'Operating',
pressure_prediction_chart: 'Pressure Prediction Chart',
recent: 'Recent Tests',
@ -368,6 +370,7 @@ export default {
please_save_test: "Please Save Test First",
},
scenario: {
scenario: "Scenario",
dubbo: "Dubbo Config",
config: "Scenario Config",
input_name: "Please enter the scenario name",
@ -402,7 +405,13 @@ export default {
parameters_filter_tips: "Only support MockJs function result preview",
parameters_advance: "Advanced parameter settings",
parameters_preview: "Preview",
parameters_preview_warning: "Please enter the template first",
parameters_mock_filter_tips: "Please enter keywords to filter",
parameters_pre_request: "Pre-request extraction",
parameters_advance_mock: "Mock Data",
parameters_advance_add_func: "Add Function",
parameters_advance_add_func_limit: "Support up to 5 functions",
parameters_advance_add_func_error: "Please select function first",
parameters_advance_add_param_error: "Please enter function parameters",
parameters_desc: "Parameters will be appended to the URL e.g. https://fit2cloud.com?Name=Value&Name2=Value2",
headers: "Headers",
body: "Body",

View File

@ -281,6 +281,8 @@ export default {
not_exist: "测试报告不存在",
},
load_test: {
same_project_test: '只能运行同一项目内的测试',
already_exists: '测试名称不能重复',
operating: '操作',
recent: '最近的测试',
search_by_name: '根据名称搜索',
@ -333,6 +335,7 @@ export default {
custom_http_code: '自定义 HTTP 响应成功状态码',
separated_by_commas: '按逗号分隔',
create: '创建测试',
run: '一键运行',
select_resource_pool: '请选择资源池',
resource_pool_is_null: '资源池为空',
download_log_file: '下载完整日志文件',
@ -368,6 +371,7 @@ export default {
please_save_test: "请先保存测试",
},
scenario: {
scenario: "场景",
dubbo: "Dubbo配置",
config: "场景配置",
input_name: "请输入场景名称",
@ -404,7 +408,13 @@ export default {
parameters_filter_tips: "只支持 MockJs 函数结果预览",
parameters_advance: "高级参数设置",
parameters_preview: "预览",
parameters_preview_warning: "请先输入模版",
parameters_mock_filter_tips: "请输入关键字进行过滤",
parameters_pre_request: "前置请求提取",
parameters_advance_mock: "Mock 数据",
parameters_advance_add_func: "添加函数",
parameters_advance_add_func_limit: "最多支持5个函数",
parameters_advance_add_func_error: "请先选择函数",
parameters_advance_add_param_error: "请输入函数参数",
parameters_desc: "参数追加到URL例如https://fit2cloud.com/entries?key1=Value1&Key2=Value2",
headers: "请求头",
body: "请求内容",

View File

@ -280,6 +280,8 @@ export default {
not_exist: "測試報告不存在",
},
load_test: {
same_project_test: '只能運行同一項目內的測試',
run: '一鍵運行',
operating: '操作',
recent: '最近的測試',
search_by_name: '根據名稱搜索',
@ -367,6 +369,7 @@ export default {
please_save_test: "請先保存測試",
},
scenario: {
scenario: "場景",
dubbo: "Dubbo配寘",
creator: "創建人",
config: "場景配寘",
@ -402,7 +405,13 @@ export default {
parameters_filter_tips: "只支持MockJs函數結果預覽",
parameters_advance: "高級參數設置",
parameters_preview: "預覽",
parameters_preview_warning: "請先輸入模版",
parameters_mock_filter_tips: "請輸入關鍵字進行過濾",
parameters_pre_request: "前置請求提取",
parameters_advance_mock: "Mock 數據",
parameters_advance_add_func: "添加函數",
parameters_advance_add_func_limit: "最多支持5個函數",
parameters_advance_add_func_error: "請先選擇函數",
parameters_advance_add_param_error: "請輸入函數參數",
parameters_desc: "參數追加到URL,例如https://fit2cloud.com/entrieskey1=Value1&amp;Key2=Value2",
headers: "請求頭",
body: "請求內容",