feat(接口定义): 接口支持自定义字段

--story=1009633 --user=王孝刚 接口定义支持自定义模板--添加自定义字段
https://www.tapd.cn/55049933/s/1244279
This commit is contained in:
wxg0103 2022-09-17 12:05:06 +08:00 committed by 刘瑞斌
parent d4c5099cca
commit 531f007e2f
56 changed files with 4183 additions and 889 deletions

View File

@ -1,9 +1,12 @@
package io.metersphere.api.dto.definition;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.dto.CustomFieldDao;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Setter
@Getter
public class ApiDefinitionResult extends ApiDefinitionWithBLOBs {
@ -35,4 +38,6 @@ public class ApiDefinitionResult extends ApiDefinitionWithBLOBs {
private Boolean versionEnable;
private boolean updated;
private List<CustomFieldDao> fields;
}

View File

@ -2,6 +2,7 @@ package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.definition.response.Response;
import io.metersphere.base.domain.Schedule;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Getter;
import lombok.Setter;
@ -86,4 +87,8 @@ public class SaveApiDefinitionRequest {
//是否新建
private Boolean newCreate;
//自定义字段
private List<CustomFieldResource> addFields;
private List<CustomFieldResource> editFields;
}

View File

@ -32,6 +32,7 @@ import io.metersphere.api.exec.api.ApiExecuteService;
import io.metersphere.api.exec.utils.ApiDefinitionExecResultUtil;
import io.metersphere.api.parse.ApiImportParser;
import io.metersphere.base.domain.*;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*;
import io.metersphere.commons.constants.*;
@ -42,10 +43,7 @@ import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.RelationshipEdgeRequest;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.dto.ProjectConfig;
import io.metersphere.dto.RelationshipEdgeDTO;
import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.dto.*;
import io.metersphere.i18n.Translator;
import io.metersphere.job.sechedule.SwaggerUrlImportJob;
import io.metersphere.log.utils.ReflexObjectUtil;
@ -172,6 +170,9 @@ public class ApiDefinitionService {
@Resource
private ApiScenarioReferenceIdMapper apiScenarioReferenceIdMapper;
@Resource
private CustomFieldApiService customFieldApiService;
private final ThreadLocal<Long> currentApiOrder = new ThreadLocal<>();
private final ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>();
private static final String COPY = "Copy";
@ -187,9 +188,19 @@ public class ApiDefinitionService {
} else {
buildProjectInfoWithoutProject(resList);
}
buildCustomField(resList);
return resList;
}
private void buildCustomField(List<ApiDefinitionResult> data) {
if (CollectionUtils.isEmpty(data)) {
return;
}
Map<String, List<CustomFieldDao>> fieldMap =
customFieldApiService.getMapByResourceIds(data.stream().map(ApiDefinitionResult::getId).collect(Collectors.toList()));
data.forEach(i -> i.setFields(fieldMap.get(i.getId())));
}
private void buildProjectInfoWithoutProject(List<ApiDefinitionResult> resList) {
resList.forEach(i -> {
Project project = projectMapper.selectByPrimaryKey(i.getProjectId());
@ -469,7 +480,10 @@ public class ApiDefinitionService {
esbApiParamService.deleteByResourceId(api.getId());
MockConfigService mockConfigService = CommonBeanFactory.getBean(MockConfigService.class);
mockConfigService.deleteMockConfigByApiId(api.getId());
relationshipEdgeService.delete(api.getId()); // 删除关系图
// 删除自定义字段关联关系
customFieldApiService.deleteByResourceId(api.getId());
// 删除关系图
relationshipEdgeService.delete(api.getId());
FileUtils.deleteBodyFiles(api.getId());
deleteFollows(api.getId());
});
@ -495,7 +509,10 @@ public class ApiDefinitionService {
// 删除附件关系
fileAssociationService.deleteByResourceIds(apiIds);
MockConfigService mockConfigService = CommonBeanFactory.getBean(MockConfigService.class);
relationshipEdgeService.delete(apiIds); // 删除关系图
// 删除自定义字段关联关系
customFieldApiService.deleteByResourceIds(apiIds);
// 删除关系图
relationshipEdgeService.delete(apiIds);
for (String apiId : apiIds) {
mockConfigService.deleteMockConfigByApiId(apiId);
deleteFollows(apiId);
@ -754,6 +771,9 @@ public class ApiDefinitionService {
// 存储附件关系
fileAssociationService.saveApi(test.getId(), request.getRequest(), FileAssociationType.API.name());
//保存自定义字段
customFieldApiService.editFields(test.getId(), request.getEditFields());
customFieldApiService.addFields(test.getId(), request.getAddFields());
return result;
}
@ -881,6 +901,13 @@ public class ApiDefinitionService {
// 存储附件关系
fileAssociationService.saveApi(test.getId(), request.getRequest(), FileAssociationType.API.name());
//保存自定义字段
List<CustomFieldResource> addFields = request.getAddFields();
if (CollectionUtils.isNotEmpty(addFields)) {
addFields.addAll(request.getEditFields());
customFieldApiService.addFields(request.getId(), addFields);
}
return getById(test.getId());
}

View File

@ -0,0 +1,19 @@
package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class ApiTemplate implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String name;
private String description;
private Boolean system;
private Boolean global;
private Long createTime;
private Long updateTime;
private String createUser;
private String projectId;
}

View File

@ -0,0 +1,790 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class ApiTemplateExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public ApiTemplateExample() {
oredCriteria = new ArrayList<Criteria>();
}
public String getOrderByClause() {
return orderByClause;
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public boolean isDistinct() {
return distinct;
}
public void setDistinct(boolean distinct) {
this.distinct = 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 andNameIsNull() {
addCriterion("`name` is null");
return (Criteria) this;
}
public Criteria andNameIsNotNull() {
addCriterion("`name` is not null");
return (Criteria) this;
}
public Criteria andNameEqualTo(String value) {
addCriterion("`name` =", value, "name");
return (Criteria) this;
}
public Criteria andNameNotEqualTo(String value) {
addCriterion("`name` <>", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThan(String value) {
addCriterion("`name` >", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThanOrEqualTo(String value) {
addCriterion("`name` >=", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThan(String value) {
addCriterion("`name` <", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThanOrEqualTo(String value) {
addCriterion("`name` <=", value, "name");
return (Criteria) this;
}
public Criteria andNameLike(String value) {
addCriterion("`name` like", value, "name");
return (Criteria) this;
}
public Criteria andNameNotLike(String value) {
addCriterion("`name` not like", value, "name");
return (Criteria) this;
}
public Criteria andNameIn(List<String> values) {
addCriterion("`name` in", values, "name");
return (Criteria) this;
}
public Criteria andNameNotIn(List<String> values) {
addCriterion("`name` not in", values, "name");
return (Criteria) this;
}
public Criteria andNameBetween(String value1, String value2) {
addCriterion("`name` between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andNameNotBetween(String value1, String value2) {
addCriterion("`name` not between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andDescriptionIsNull() {
addCriterion("description is null");
return (Criteria) this;
}
public Criteria andDescriptionIsNotNull() {
addCriterion("description is not null");
return (Criteria) this;
}
public Criteria andDescriptionEqualTo(String value) {
addCriterion("description =", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotEqualTo(String value) {
addCriterion("description <>", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionGreaterThan(String value) {
addCriterion("description >", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionGreaterThanOrEqualTo(String value) {
addCriterion("description >=", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionLessThan(String value) {
addCriterion("description <", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionLessThanOrEqualTo(String value) {
addCriterion("description <=", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionLike(String value) {
addCriterion("description like", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotLike(String value) {
addCriterion("description not like", value, "description");
return (Criteria) this;
}
public Criteria andDescriptionIn(List<String> values) {
addCriterion("description in", values, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotIn(List<String> values) {
addCriterion("description not in", values, "description");
return (Criteria) this;
}
public Criteria andDescriptionBetween(String value1, String value2) {
addCriterion("description between", value1, value2, "description");
return (Criteria) this;
}
public Criteria andDescriptionNotBetween(String value1, String value2) {
addCriterion("description not between", value1, value2, "description");
return (Criteria) this;
}
public Criteria andSystemIsNull() {
addCriterion("`system` is null");
return (Criteria) this;
}
public Criteria andSystemIsNotNull() {
addCriterion("`system` is not null");
return (Criteria) this;
}
public Criteria andSystemEqualTo(Boolean value) {
addCriterion("`system` =", value, "system");
return (Criteria) this;
}
public Criteria andSystemNotEqualTo(Boolean value) {
addCriterion("`system` <>", value, "system");
return (Criteria) this;
}
public Criteria andSystemGreaterThan(Boolean value) {
addCriterion("`system` >", value, "system");
return (Criteria) this;
}
public Criteria andSystemGreaterThanOrEqualTo(Boolean value) {
addCriterion("`system` >=", value, "system");
return (Criteria) this;
}
public Criteria andSystemLessThan(Boolean value) {
addCriterion("`system` <", value, "system");
return (Criteria) this;
}
public Criteria andSystemLessThanOrEqualTo(Boolean value) {
addCriterion("`system` <=", value, "system");
return (Criteria) this;
}
public Criteria andSystemIn(List<Boolean> values) {
addCriterion("`system` in", values, "system");
return (Criteria) this;
}
public Criteria andSystemNotIn(List<Boolean> values) {
addCriterion("`system` not in", values, "system");
return (Criteria) this;
}
public Criteria andSystemBetween(Boolean value1, Boolean value2) {
addCriterion("`system` between", value1, value2, "system");
return (Criteria) this;
}
public Criteria andSystemNotBetween(Boolean value1, Boolean value2) {
addCriterion("`system` not between", value1, value2, "system");
return (Criteria) this;
}
public Criteria andGlobalIsNull() {
addCriterion("`global` is null");
return (Criteria) this;
}
public Criteria andGlobalIsNotNull() {
addCriterion("`global` is not null");
return (Criteria) this;
}
public Criteria andGlobalEqualTo(Boolean value) {
addCriterion("`global` =", value, "global");
return (Criteria) this;
}
public Criteria andGlobalNotEqualTo(Boolean value) {
addCriterion("`global` <>", value, "global");
return (Criteria) this;
}
public Criteria andGlobalGreaterThan(Boolean value) {
addCriterion("`global` >", value, "global");
return (Criteria) this;
}
public Criteria andGlobalGreaterThanOrEqualTo(Boolean value) {
addCriterion("`global` >=", value, "global");
return (Criteria) this;
}
public Criteria andGlobalLessThan(Boolean value) {
addCriterion("`global` <", value, "global");
return (Criteria) this;
}
public Criteria andGlobalLessThanOrEqualTo(Boolean value) {
addCriterion("`global` <=", value, "global");
return (Criteria) this;
}
public Criteria andGlobalIn(List<Boolean> values) {
addCriterion("`global` in", values, "global");
return (Criteria) this;
}
public Criteria andGlobalNotIn(List<Boolean> values) {
addCriterion("`global` not in", values, "global");
return (Criteria) this;
}
public Criteria andGlobalBetween(Boolean value1, Boolean value2) {
addCriterion("`global` between", value1, value2, "global");
return (Criteria) this;
}
public Criteria andGlobalNotBetween(Boolean value1, Boolean value2) {
addCriterion("`global` not between", value1, value2, "global");
return (Criteria) this;
}
public Criteria andCreateTimeIsNull() {
addCriterion("create_time is null");
return (Criteria) this;
}
public Criteria andCreateTimeIsNotNull() {
addCriterion("create_time is not null");
return (Criteria) this;
}
public Criteria andCreateTimeEqualTo(Long value) {
addCriterion("create_time =", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotEqualTo(Long value) {
addCriterion("create_time <>", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThan(Long value) {
addCriterion("create_time >", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("create_time >=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThan(Long value) {
addCriterion("create_time <", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThanOrEqualTo(Long value) {
addCriterion("create_time <=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeIn(List<Long> values) {
addCriterion("create_time in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotIn(List<Long> values) {
addCriterion("create_time not in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeBetween(Long value1, Long value2) {
addCriterion("create_time between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotBetween(Long value1, Long value2) {
addCriterion("create_time not between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNull() {
addCriterion("update_time is null");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNotNull() {
addCriterion("update_time is not null");
return (Criteria) this;
}
public Criteria andUpdateTimeEqualTo(Long value) {
addCriterion("update_time =", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotEqualTo(Long value) {
addCriterion("update_time <>", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThan(Long value) {
addCriterion("update_time >", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("update_time >=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThan(Long value) {
addCriterion("update_time <", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThanOrEqualTo(Long value) {
addCriterion("update_time <=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIn(List<Long> values) {
addCriterion("update_time in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotIn(List<Long> values) {
addCriterion("update_time not in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeBetween(Long value1, Long value2) {
addCriterion("update_time between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotBetween(Long value1, Long value2) {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andCreateUserIsNull() {
addCriterion("create_user is null");
return (Criteria) this;
}
public Criteria andCreateUserIsNotNull() {
addCriterion("create_user is not null");
return (Criteria) this;
}
public Criteria andCreateUserEqualTo(String value) {
addCriterion("create_user =", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotEqualTo(String value) {
addCriterion("create_user <>", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserGreaterThan(String value) {
addCriterion("create_user >", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserGreaterThanOrEqualTo(String value) {
addCriterion("create_user >=", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLessThan(String value) {
addCriterion("create_user <", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLessThanOrEqualTo(String value) {
addCriterion("create_user <=", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLike(String value) {
addCriterion("create_user like", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotLike(String value) {
addCriterion("create_user not like", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserIn(List<String> values) {
addCriterion("create_user in", values, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotIn(List<String> values) {
addCriterion("create_user not in", values, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserBetween(String value1, String value2) {
addCriterion("create_user between", value1, value2, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotBetween(String value1, String value2) {
addCriterion("create_user not between", value1, value2, "createUser");
return (Criteria) this;
}
public Criteria andProjectIdIsNull() {
addCriterion("project_id is null");
return (Criteria) this;
}
public Criteria andProjectIdIsNotNull() {
addCriterion("project_id is not null");
return (Criteria) this;
}
public Criteria andProjectIdEqualTo(String value) {
addCriterion("project_id =", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("project_id <>", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThan(String value) {
addCriterion("project_id >", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("project_id >=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThan(String value) {
addCriterion("project_id <", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThanOrEqualTo(String value) {
addCriterion("project_id <=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLike(String value) {
addCriterion("project_id like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotLike(String value) {
addCriterion("project_id not like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdIn(List<String> values) {
addCriterion("project_id in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotIn(List<String> values) {
addCriterion("project_id not in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdBetween(String value1, String value2) {
addCriterion("project_id between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotBetween(String value1, String value2) {
addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this;
}
}
public 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;
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);
}
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;
}
}
}

View File

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

View File

@ -0,0 +1,410 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class CustomFieldApiExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public CustomFieldApiExample() {
oredCriteria = new ArrayList<Criteria>();
}
public String getOrderByClause() {
return orderByClause;
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public boolean isDistinct() {
return distinct;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andResourceIdIsNull() {
addCriterion("resource_id is null");
return (Criteria) this;
}
public Criteria andResourceIdIsNotNull() {
addCriterion("resource_id is not null");
return (Criteria) this;
}
public Criteria andResourceIdEqualTo(String value) {
addCriterion("resource_id =", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotEqualTo(String value) {
addCriterion("resource_id <>", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdGreaterThan(String value) {
addCriterion("resource_id >", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdGreaterThanOrEqualTo(String value) {
addCriterion("resource_id >=", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLessThan(String value) {
addCriterion("resource_id <", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLessThanOrEqualTo(String value) {
addCriterion("resource_id <=", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdLike(String value) {
addCriterion("resource_id like", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotLike(String value) {
addCriterion("resource_id not like", value, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdIn(List<String> values) {
addCriterion("resource_id in", values, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotIn(List<String> values) {
addCriterion("resource_id not in", values, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdBetween(String value1, String value2) {
addCriterion("resource_id between", value1, value2, "resourceId");
return (Criteria) this;
}
public Criteria andResourceIdNotBetween(String value1, String value2) {
addCriterion("resource_id not between", value1, value2, "resourceId");
return (Criteria) this;
}
public Criteria andFieldIdIsNull() {
addCriterion("field_id is null");
return (Criteria) this;
}
public Criteria andFieldIdIsNotNull() {
addCriterion("field_id is not null");
return (Criteria) this;
}
public Criteria andFieldIdEqualTo(String value) {
addCriterion("field_id =", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotEqualTo(String value) {
addCriterion("field_id <>", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdGreaterThan(String value) {
addCriterion("field_id >", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdGreaterThanOrEqualTo(String value) {
addCriterion("field_id >=", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdLessThan(String value) {
addCriterion("field_id <", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdLessThanOrEqualTo(String value) {
addCriterion("field_id <=", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdLike(String value) {
addCriterion("field_id like", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotLike(String value) {
addCriterion("field_id not like", value, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdIn(List<String> values) {
addCriterion("field_id in", values, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotIn(List<String> values) {
addCriterion("field_id not in", values, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdBetween(String value1, String value2) {
addCriterion("field_id between", value1, value2, "fieldId");
return (Criteria) this;
}
public Criteria andFieldIdNotBetween(String value1, String value2) {
addCriterion("field_id not between", value1, value2, "fieldId");
return (Criteria) this;
}
public Criteria andValueIsNull() {
addCriterion("`value` is null");
return (Criteria) this;
}
public Criteria andValueIsNotNull() {
addCriterion("`value` is not null");
return (Criteria) this;
}
public Criteria andValueEqualTo(String value) {
addCriterion("`value` =", value, "value");
return (Criteria) this;
}
public Criteria andValueNotEqualTo(String value) {
addCriterion("`value` <>", value, "value");
return (Criteria) this;
}
public Criteria andValueGreaterThan(String value) {
addCriterion("`value` >", value, "value");
return (Criteria) this;
}
public Criteria andValueGreaterThanOrEqualTo(String value) {
addCriterion("`value` >=", value, "value");
return (Criteria) this;
}
public Criteria andValueLessThan(String value) {
addCriterion("`value` <", value, "value");
return (Criteria) this;
}
public Criteria andValueLessThanOrEqualTo(String value) {
addCriterion("`value` <=", value, "value");
return (Criteria) this;
}
public Criteria andValueLike(String value) {
addCriterion("`value` like", value, "value");
return (Criteria) this;
}
public Criteria andValueNotLike(String value) {
addCriterion("`value` not like", value, "value");
return (Criteria) this;
}
public Criteria andValueIn(List<String> values) {
addCriterion("`value` in", values, "value");
return (Criteria) this;
}
public Criteria andValueNotIn(List<String> values) {
addCriterion("`value` not in", values, "value");
return (Criteria) this;
}
public Criteria andValueBetween(String value1, String value2) {
addCriterion("`value` between", value1, value2, "value");
return (Criteria) this;
}
public Criteria andValueNotBetween(String value1, String value2) {
addCriterion("`value` not between", value1, value2, "value");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
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);
}
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;
}
}
}

View File

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

View File

@ -41,6 +41,8 @@ public class Project implements Serializable {
private Boolean versionEnable;
private String apiTemplateId;
private String issueConfig;
private static final long serialVersionUID = 1L;

View File

@ -1323,6 +1323,76 @@ public class ProjectExample {
addCriterion("version_enable not between", value1, value2, "versionEnable");
return (Criteria) this;
}
public Criteria andApiTemplateIdIsNull() {
addCriterion("api_template_id is null");
return (Criteria) this;
}
public Criteria andApiTemplateIdIsNotNull() {
addCriterion("api_template_id is not null");
return (Criteria) this;
}
public Criteria andApiTemplateIdEqualTo(String value) {
addCriterion("api_template_id =", value, "apiTemplateId");
return (Criteria) this;
}
public Criteria andApiTemplateIdNotEqualTo(String value) {
addCriterion("api_template_id <>", value, "apiTemplateId");
return (Criteria) this;
}
public Criteria andApiTemplateIdGreaterThan(String value) {
addCriterion("api_template_id >", value, "apiTemplateId");
return (Criteria) this;
}
public Criteria andApiTemplateIdGreaterThanOrEqualTo(String value) {
addCriterion("api_template_id >=", value, "apiTemplateId");
return (Criteria) this;
}
public Criteria andApiTemplateIdLessThan(String value) {
addCriterion("api_template_id <", value, "apiTemplateId");
return (Criteria) this;
}
public Criteria andApiTemplateIdLessThanOrEqualTo(String value) {
addCriterion("api_template_id <=", value, "apiTemplateId");
return (Criteria) this;
}
public Criteria andApiTemplateIdLike(String value) {
addCriterion("api_template_id like", value, "apiTemplateId");
return (Criteria) this;
}
public Criteria andApiTemplateIdNotLike(String value) {
addCriterion("api_template_id not like", value, "apiTemplateId");
return (Criteria) this;
}
public Criteria andApiTemplateIdIn(List<String> values) {
addCriterion("api_template_id in", values, "apiTemplateId");
return (Criteria) this;
}
public Criteria andApiTemplateIdNotIn(List<String> values) {
addCriterion("api_template_id not in", values, "apiTemplateId");
return (Criteria) this;
}
public Criteria andApiTemplateIdBetween(String value1, String value2) {
addCriterion("api_template_id between", value1, value2, "apiTemplateId");
return (Criteria) this;
}
public Criteria andApiTemplateIdNotBetween(String value1, String value2) {
addCriterion("api_template_id not between", value1, value2, "apiTemplateId");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

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

View File

@ -0,0 +1,280 @@
<?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.ApiTemplateMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiTemplate">
<id column="id" jdbcType="VARCHAR" property="id"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="description" jdbcType="VARCHAR" property="description"/>
<result column="system" jdbcType="BIT" property="system"/>
<result column="global" jdbcType="BIT" property="global"/>
<result column="create_time" jdbcType="BIGINT" property="createTime"/>
<result column="update_time" jdbcType="BIGINT" property="updateTime"/>
<result column="create_user" jdbcType="VARCHAR" property="createUser"/>
<result column="project_id" jdbcType="VARCHAR" property="projectId"/>
</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
, `name`, description, `system`, `global`, create_time, update_time, create_user,
project_id
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ApiTemplateExample"
resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List"/>
from api_template
<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 api_template
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete
from api_template
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.ApiTemplateExample">
delete from api_template
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiTemplate">
insert into api_template (id, `name`, description,
`system`, `global`, create_time,
update_time, create_user, project_id)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR},
#{system,jdbcType=BIT}, #{global,jdbcType=BIT}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiTemplate">
insert into api_template
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="name != null">
`name`,
</if>
<if test="description != null">
description,
</if>
<if test="system != null">
`system`,
</if>
<if test="global != null">
`global`,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="createUser != null">
create_user,
</if>
<if test="projectId != null">
project_id,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="description != null">
#{description,jdbcType=VARCHAR},
</if>
<if test="system != null">
#{system,jdbcType=BIT},
</if>
<if test="global != null">
#{global,jdbcType=BIT},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="createUser != null">
#{createUser,jdbcType=VARCHAR},
</if>
<if test="projectId != null">
#{projectId,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ApiTemplateExample"
resultType="java.lang.Long">
select count(*) from api_template
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update api_template
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.description != null">
description = #{record.description,jdbcType=VARCHAR},
</if>
<if test="record.system != null">
`system` = #{record.system,jdbcType=BIT},
</if>
<if test="record.global != null">
`global` = #{record.global,jdbcType=BIT},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
<if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause"/>
</if>
</update>
<update id="updateByExample" parameterType="map">
update api_template
set id = #{record.id,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR},
`system` = #{record.system,jdbcType=BIT},
`global` = #{record.global,jdbcType=BIT},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
create_user = #{record.createUser,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause"/>
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiTemplate">
update api_template
<set>
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=VARCHAR},
</if>
<if test="system != null">
`system` = #{system,jdbcType=BIT},
</if>
<if test="global != null">
`global` = #{global,jdbcType=BIT},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="createUser != null">
create_user = #{createUser,jdbcType=VARCHAR},
</if>
<if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiTemplate">
update api_template
set `name` = #{name,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
`system` = #{system,jdbcType=BIT},
`global` = #{global,jdbcType=BIT},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
create_user = #{createUser,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

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

View File

@ -0,0 +1,242 @@
<?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.CustomFieldApiMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.CustomFieldApi">
<id column="resource_id" jdbcType="VARCHAR" property="resourceId"/>
<id column="field_id" jdbcType="VARCHAR" property="fieldId"/>
<result column="value" jdbcType="VARCHAR" property="value"/>
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.CustomFieldApi">
<result column="text_value" jdbcType="LONGVARCHAR" property="textValue"/>
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="("
separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="("
separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
resource_id
, field_id, `value`
</sql>
<sql id="Blob_Column_List">
text_value
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.CustomFieldApiExample"
resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List"/>
,
<include refid="Blob_Column_List"/>
from custom_field_api
<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.CustomFieldApiExample"
resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List"/>
from custom_field_api
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="io.metersphere.base.domain.CustomFieldApiKey"
resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List"/>
,
<include refid="Blob_Column_List"/>
from custom_field_api
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="io.metersphere.base.domain.CustomFieldApiKey">
delete
from custom_field_api
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.CustomFieldApiExample">
delete from custom_field_api
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.CustomFieldApi">
insert into custom_field_api (resource_id, field_id, `value`,
text_value)
values (#{resourceId,jdbcType=VARCHAR}, #{fieldId,jdbcType=VARCHAR}, #{value,jdbcType=VARCHAR},
#{textValue,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.CustomFieldApi">
insert into custom_field_api
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="resourceId != null">
resource_id,
</if>
<if test="fieldId != null">
field_id,
</if>
<if test="value != null">
`value`,
</if>
<if test="textValue != null">
text_value,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="resourceId != null">
#{resourceId,jdbcType=VARCHAR},
</if>
<if test="fieldId != null">
#{fieldId,jdbcType=VARCHAR},
</if>
<if test="value != null">
#{value,jdbcType=VARCHAR},
</if>
<if test="textValue != null">
#{textValue,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.CustomFieldApiExample"
resultType="java.lang.Long">
select count(*) from custom_field_api
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update custom_field_api
<set>
<if test="record.resourceId != null">
resource_id = #{record.resourceId,jdbcType=VARCHAR},
</if>
<if test="record.fieldId != null">
field_id = #{record.fieldId,jdbcType=VARCHAR},
</if>
<if test="record.value != null">
`value` = #{record.value,jdbcType=VARCHAR},
</if>
<if test="record.textValue != null">
text_value = #{record.textValue,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause"/>
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update custom_field_api
set resource_id = #{record.resourceId,jdbcType=VARCHAR},
field_id = #{record.fieldId,jdbcType=VARCHAR},
`value` = #{record.value,jdbcType=VARCHAR},
text_value = #{record.textValue,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause"/>
</if>
</update>
<update id="updateByExample" parameterType="map">
update custom_field_api
set resource_id = #{record.resourceId,jdbcType=VARCHAR},
field_id = #{record.fieldId,jdbcType=VARCHAR},
`value` = #{record.value,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause"/>
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.CustomFieldApi">
update custom_field_api
<set>
<if test="value != null">
`value` = #{value,jdbcType=VARCHAR},
</if>
<if test="textValue != null">
text_value = #{textValue,jdbcType=LONGVARCHAR},
</if>
</set>
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.CustomFieldApi">
update custom_field_api
set `value` = #{value,jdbcType=VARCHAR},
text_value = #{textValue,jdbcType=LONGVARCHAR}
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.CustomFieldApi">
update custom_field_api
set `value` = #{value,jdbcType=VARCHAR}
where resource_id = #{resourceId,jdbcType=VARCHAR}
and field_id = #{fieldId,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -20,6 +20,7 @@
<result column="platform" jdbcType="VARCHAR" property="platform" />
<result column="third_part_template" jdbcType="BIT" property="thirdPartTemplate" />
<result column="version_enable" jdbcType="BIT" property="versionEnable" />
<result column="api_template_id" jdbcType="VARCHAR" property="apiTemplateId"/>
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.Project">
<result column="issue_config" jdbcType="LONGVARCHAR" property="issueConfig" />
@ -83,9 +84,10 @@
</where>
</sql>
<sql id="Base_Column_List">
id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key,
id
, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key,
zentao_id, azure_devops_id, case_template_id, issue_template_id, create_user, system_id,
azure_filter_id, platform, third_part_template, version_enable
azure_filter_id, platform, third_part_template, version_enable, api_template_id
</sql>
<sql id="Blob_Column_List">
issue_config
@ -145,14 +147,15 @@
azure_devops_id, case_template_id, issue_template_id,
create_user, system_id, azure_filter_id,
platform, third_part_template, version_enable,
issue_config)
api_template_id, issue_config)
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{tapdId,jdbcType=VARCHAR}, #{jiraKey,jdbcType=VARCHAR}, #{zentaoId,jdbcType=VARCHAR},
#{azureDevopsId,jdbcType=VARCHAR}, #{caseTemplateId,jdbcType=VARCHAR}, #{issueTemplateId,jdbcType=VARCHAR},
#{azureDevopsId,jdbcType=VARCHAR}, #{caseTemplateId,jdbcType=VARCHAR},
#{issueTemplateId,jdbcType=VARCHAR},
#{createUser,jdbcType=VARCHAR}, #{systemId,jdbcType=VARCHAR}, #{azureFilterId,jdbcType=VARCHAR},
#{platform,jdbcType=VARCHAR}, #{thirdPartTemplate,jdbcType=BIT}, #{versionEnable,jdbcType=BIT},
#{issueConfig,jdbcType=LONGVARCHAR})
#{apiTemplateId,jdbcType=VARCHAR}, #{issueConfig,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.Project">
insert into project
@ -211,6 +214,9 @@
<if test="versionEnable != null">
version_enable,
</if>
<if test="apiTemplateId != null">
api_template_id,
</if>
<if test="issueConfig != null">
issue_config,
</if>
@ -270,6 +276,9 @@
<if test="versionEnable != null">
#{versionEnable,jdbcType=BIT},
</if>
<if test="apiTemplateId != null">
#{apiTemplateId,jdbcType=VARCHAR},
</if>
<if test="issueConfig != null">
#{issueConfig,jdbcType=LONGVARCHAR},
</if>
@ -338,6 +347,9 @@
<if test="record.versionEnable != null">
version_enable = #{record.versionEnable,jdbcType=BIT},
</if>
<if test="record.apiTemplateId != null">
api_template_id = #{record.apiTemplateId,jdbcType=VARCHAR},
</if>
<if test="record.issueConfig != null">
issue_config = #{record.issueConfig,jdbcType=LONGVARCHAR},
</if>
@ -366,6 +378,7 @@
platform = #{record.platform,jdbcType=VARCHAR},
third_part_template = #{record.thirdPartTemplate,jdbcType=BIT},
version_enable = #{record.versionEnable,jdbcType=BIT},
api_template_id = #{record.apiTemplateId,jdbcType=VARCHAR},
issue_config = #{record.issueConfig,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause"/>
@ -390,7 +403,8 @@
azure_filter_id = #{record.azureFilterId,jdbcType=VARCHAR},
platform = #{record.platform,jdbcType=VARCHAR},
third_part_template = #{record.thirdPartTemplate,jdbcType=BIT},
version_enable = #{record.versionEnable,jdbcType=BIT}
version_enable = #{record.versionEnable,jdbcType=BIT},
api_template_id = #{record.apiTemplateId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause"/>
</if>
@ -449,6 +463,9 @@
<if test="versionEnable != null">
version_enable = #{versionEnable,jdbcType=BIT},
</if>
<if test="apiTemplateId != null">
api_template_id = #{apiTemplateId,jdbcType=VARCHAR},
</if>
<if test="issueConfig != null">
issue_config = #{issueConfig,jdbcType=LONGVARCHAR},
</if>
@ -474,6 +491,7 @@
platform = #{platform,jdbcType=VARCHAR},
third_part_template = #{thirdPartTemplate,jdbcType=BIT},
version_enable = #{versionEnable,jdbcType=BIT},
api_template_id = #{apiTemplateId,jdbcType=VARCHAR},
issue_config = #{issueConfig,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
@ -495,7 +513,8 @@
azure_filter_id = #{azureFilterId,jdbcType=VARCHAR},
platform = #{platform,jdbcType=VARCHAR},
third_part_template = #{thirdPartTemplate,jdbcType=BIT},
version_enable = #{versionEnable,jdbcType=BIT}
version_enable = #{versionEnable,jdbcType=BIT},
api_template_id = #{apiTemplateId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -0,0 +1,12 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.ApiTemplate;
import io.metersphere.controller.request.BaseQueryRequest;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtApiTemplateMapper {
List<ApiTemplate> list(@Param("request") BaseQueryRequest request);
}

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="io.metersphere.base.mapper.ext.ExtApiTemplateMapper">
<select id="list" resultType="io.metersphere.base.domain.ApiTemplate">
select
<include refid="io.metersphere.base.mapper.ApiTemplateMapper.Base_Column_List"/>
from api_template tcft
<include refid="queryWhereCondition"/>
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
<sql id="queryWhereCondition">
<where>
<if test="request.name != null">
and tcft.name LIKE CONCAT('%', #{request.name}, '%')
</if>
<if test="request.workspaceId != null">
and (
tcft.workspace_id = #{request.workspaceId}
or (
tcft.global = 1 and
not exists (
select id
from api_template tcft_child
where tcft_child.name = tcft.name and tcft_child.global != 1 and tcft_child.workspace_id =
#{request.workspaceId}
)
)
)
</if>
<if test="request.projectId != null">
and (
tcft.project_id = #{request.projectId}
or (
tcft.global = 1 and
not exists (
select id
from api_template tcft_child
where tcft_child.name = tcft.name and tcft_child.global != 1 and tcft_child.project_id =
#{request.projectId}
)
)
)
</if>
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key == 'type'">
AND tcft.type IN
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
</choose>
</if>
</foreach>
</if>
</where>
</sql>
</mapper>

View File

@ -48,5 +48,7 @@ public interface ExtProjectMapper {
void updateUseDefaultCaseTemplateProject(@Param("originId") String originId, @Param("templateId") String templateId, @Param("projectId") String projectId);
void updateUseDefaultApiTemplateProject(@Param("originId") String originId, @Param("templateId") String templateId, @Param("projectId") String projectId);
List<String> getThirdPartProjectIds();
}

View File

@ -202,10 +202,17 @@
WHERE workspace_id = #{workspaceId}) AS a)
</update>
<update id="updateUseDefaultCaseTemplateProject">
update project set case_template_id = #{templateId}
update project
set case_template_id = #{templateId}
where (case_template_id = #{originId} or case_template_id is null or case_template_id = '')
and id = #{projectId}
</update>
<update id="updateUseDefaultApiTemplateProject">
update project
set api_template_id = #{templateId}
where (api_template_id = #{originId} or api_template_id is null or api_template_id = '')
and id = #{projectId}
</update>
<select id="selectProjectByResourceId" resultType="io.metersphere.base.domain.Project">
SELECT *
@ -258,8 +265,7 @@
UNION
SELECT project_id
FROM load_test_report
WHERE id = #{resourceId})
LIMIT 1
WHERE id = #{resourceId}) LIMIT 1
</select>
<select id="getProjectMemberSize" resultType="java.lang.Long">
SELECT count(distinct (`user`.id)) FROM user_group JOIN `user` ON user_group.user_id = `user`.id

View File

@ -11,6 +11,7 @@ public class OperLogModule {
public static final String WORKSPACE_TEMPLATE_SETTINGS_ISSUE = "WORKSPACE_TEMPLATE_SETTINGS_ISSUE";
public static final String WORKSPACE_SERVICE_INTEGRATION = "WORKSPACE_SERVICE_INTEGRATION";
public static final String WORKSPACE_TEMPLATE_SETTINGS_CASE = "WORKSPACE_TEMPLATE_SETTINGS_CASE";
public static final String WORKSPACE_TEMPLATE_SETTINGS_API = "WORKSPACE_TEMPLATE_SETTINGS_API";
public static final String WORKSPACE_MEMBER = "WORKSPACE_MEMBER";
public static final String API_AUTOMATION = "API_AUTOMATION";
public static final String API_AUTOMATION_SCHEDULE = "API_AUTOMATION_SCHEDULE";

View File

@ -203,6 +203,7 @@ public class PermissionConstants {
public static final String PROJECT_TEMPLATE_READ = "PROJECT_TEMPLATE:READ";
public static final String PROJECT_TEMPLATE_READ_CASE_TEMPLATE = "PROJECT_TEMPLATE:READ+CASE_TEMPLATE";
public static final String PROJECT_TEMPLATE_READ_ISSUE_TEMPLATE = "PROJECT_TEMPLATE:READ+ISSUE_TEMPLATE";
public static final String PROJECT_TEMPLATE_READ_API_TEMPLATE = "PROJECT_TEMPLATE:READ+API_TEMPLATE";
public static final String PROJECT_TEMPLATE_READ_CUSTOM = "PROJECT_TEMPLATE:READ+CUSTOM";
public static final String PROJECT_TEMPLATE_READ_REPORT_TEMPLATE = "PROJECT_TEMPLATE:READ+REPORT_TEMPLATE";
}

View File

@ -3,7 +3,7 @@ package io.metersphere.commons.constants;
public class TemplateConstants {
public enum FieldTemplateScene {
TEST_CASE, ISSUE
TEST_CASE, ISSUE, API
}
public enum TestCaseTemplateScene {

View File

@ -0,0 +1,60 @@
package io.metersphere.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.ApiTemplate;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.OperLogModule;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.controller.request.UpdateApiTemplateRequest;
import io.metersphere.dto.ApiTemplateDTO;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.service.ApiTemplateService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RequestMapping("project/field/template/api")
@RestController
public class ApiTemplateController {
@Resource
private ApiTemplateService apiTemplateService;
@PostMapping("/add")
@MsAuditLog(module = OperLogModule.WORKSPACE_TEMPLATE_SETTINGS_API, type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#request.id)", msClass = ApiTemplateService.class)
public void add(@RequestBody UpdateApiTemplateRequest request) {
apiTemplateService.add(request);
}
@PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<ApiTemplate>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody BaseQueryRequest request) {
Page<List<ApiTemplate>> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, apiTemplateService.list(request));
}
@GetMapping("/delete/{id}")
@MsAuditLog(module = OperLogModule.WORKSPACE_TEMPLATE_SETTINGS_API, type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#id)", msClass = ApiTemplateService.class)
public void delete(@PathVariable(value = "id") String id) {
apiTemplateService.delete(id);
}
@PostMapping("/update")
@MsAuditLog(module = OperLogModule.WORKSPACE_TEMPLATE_SETTINGS_API, type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id)", content = "#msClass.getLogDetails(#request.id)", msClass = ApiTemplateService.class)
public void update(@RequestBody UpdateApiTemplateRequest request) {
apiTemplateService.update(request);
}
@GetMapping({"/option/{projectId}", "/option"})
public List<ApiTemplate> list(@PathVariable(required = false) String projectId) {
return apiTemplateService.getOption(projectId);
}
@GetMapping("/get-template/relate/{projectId}")
public ApiTemplateDTO getTemplate(@PathVariable String projectId) {
return apiTemplateService.getTemplate(projectId);
}
}

View File

@ -0,0 +1,12 @@
package io.metersphere.controller.request;
import io.metersphere.base.domain.ApiTemplate;
import io.metersphere.base.domain.CustomFieldTemplate;
import lombok.Data;
import java.util.List;
@Data
public class UpdateApiTemplateRequest extends ApiTemplate {
List<CustomFieldTemplate> customFields;
}

View File

@ -0,0 +1,11 @@
package io.metersphere.dto;
import io.metersphere.base.domain.ApiTemplate;
import lombok.Data;
import java.util.List;
@Data
public class ApiTemplateDTO extends ApiTemplate {
List<CustomFieldDao> customFields;
}

View File

@ -0,0 +1,235 @@
package io.metersphere.service;
import com.alibaba.fastjson.JSON;
import io.metersphere.base.domain.ApiTemplate;
import io.metersphere.base.domain.ApiTemplateExample;
import io.metersphere.base.domain.CustomFieldTemplate;
import io.metersphere.base.domain.Project;
import io.metersphere.base.mapper.ApiTemplateMapper;
import io.metersphere.base.mapper.ext.ExtApiTemplateMapper;
import io.metersphere.commons.constants.TemplateConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.controller.request.UpdateApiTemplateRequest;
import io.metersphere.dto.ApiTemplateDTO;
import io.metersphere.dto.CustomFieldDao;
import io.metersphere.i18n.Translator;
import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.system.SystemReference;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiTemplateService extends TemplateBaseService {
@Resource
ExtApiTemplateMapper extApiTemplateMapper;
@Resource
ApiTemplateMapper apiTemplateMapper;
@Resource
CustomFieldTemplateService customFieldTemplateService;
@Resource
CustomFieldService customFieldService;
@Resource
ProjectService projectService;
public String add(UpdateApiTemplateRequest request) {
checkExist(request);
ApiTemplate apiTemplate = new ApiTemplate();
BeanUtils.copyBean(apiTemplate, request);
apiTemplate.setId(UUID.randomUUID().toString());
apiTemplate.setCreateTime(System.currentTimeMillis());
apiTemplate.setUpdateTime(System.currentTimeMillis());
apiTemplate.setGlobal(false);
apiTemplate.setCreateUser(SessionUtils.getUserId());
if (apiTemplate.getSystem() == null) {
apiTemplate.setSystem(false);
}
request.setId(apiTemplate.getId());
apiTemplateMapper.insert(apiTemplate);
customFieldTemplateService.create(request.getCustomFields(), apiTemplate.getId(),
TemplateConstants.FieldTemplateScene.API.name());
return apiTemplate.getId();
}
public List<ApiTemplate> list(BaseQueryRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
return extApiTemplateMapper.list(request);
}
public void delete(String id) {
checkTemplateUsed(id, projectService::getByApiTemplateId);
apiTemplateMapper.deleteByPrimaryKey(id);
customFieldTemplateService.deleteByTemplateId(id);
}
public void update(UpdateApiTemplateRequest request) {
if (BooleanUtils.isTrue(request.getGlobal())) {
String originId = request.getId();
// 如果是全局字段则创建对应工作空间字段
String id = add(request);
projectService.updateApiTemplate(originId, id, request.getProjectId());
} else {
checkExist(request);
customFieldTemplateService.deleteByTemplateId(request.getId());
ApiTemplate apiTemplate = new ApiTemplate();
BeanUtils.copyBean(apiTemplate, request);
apiTemplate.setUpdateTime(System.currentTimeMillis());
apiTemplateMapper.updateByPrimaryKeySelective(apiTemplate);
customFieldTemplateService.create(request.getCustomFields(), apiTemplate.getId(),
TemplateConstants.FieldTemplateScene.API.name());
}
}
/**
* 获取该工作空间的系统模板
* - 如果没有则创建该工作空间模板并关联默认的字段
* - 如果有则更新原来关联的 fieldId
*
* @param customField
*/
public void handleSystemFieldCreate(CustomFieldDao customField) {
ApiTemplateExample example = new ApiTemplateExample();
example.createCriteria()
.andGlobalEqualTo(true);
example.or(example.createCriteria()
.andProjectIdEqualTo(customField.getProjectId()));
List<ApiTemplate> apiTemplates = apiTemplateMapper.selectByExample(example);
Map<Boolean, List<ApiTemplate>> templatesMap = apiTemplates.stream()
.collect(Collectors.groupingBy(ApiTemplate::getGlobal));
// 获取全局模板
List<ApiTemplate> globalTemplates = templatesMap.get(true);
// 获取当前工作空间下模板
List<ApiTemplate> projectTemplates = templatesMap.get(false);
globalTemplates.forEach(global -> {
List<ApiTemplate> projectTemplate = null;
if (CollectionUtils.isNotEmpty(projectTemplates)) {
projectTemplate = projectTemplates.stream()
.filter(i -> i.getName().equals(global.getName()))
.collect(Collectors.toList());
}
// 如果没有项目级别的模板就创建
if (CollectionUtils.isEmpty(projectTemplate)) {
ApiTemplate template = new ApiTemplate();
BeanUtils.copyBean(template, global);
template.setId(UUID.randomUUID().toString());
template.setCreateTime(System.currentTimeMillis());
template.setUpdateTime(System.currentTimeMillis());
template.setCreateUser(SessionUtils.getUserId());
template.setGlobal(false);
template.setProjectId(customField.getProjectId());
apiTemplateMapper.insert(template);
projectService.updateApiTemplate(global.getId(), template.getId(), customField.getProjectId());
List<CustomFieldTemplate> customFieldTemplate =
customFieldTemplateService.getSystemFieldCreateTemplate(customField, global.getId());
customFieldTemplateService.create(customFieldTemplate, template.getId(),
TemplateConstants.FieldTemplateScene.API.name());
}
});
if (CollectionUtils.isNotEmpty(projectTemplates)) {
customFieldTemplateService.updateProjectTemplateGlobalField(customField,
projectTemplates.stream().map(ApiTemplate::getId).collect(Collectors.toList()));
}
}
private void checkExist(ApiTemplate apiTemplate) {
if (apiTemplate.getName() != null) {
ApiTemplateExample example = new ApiTemplateExample();
ApiTemplateExample.Criteria criteria = example.createCriteria();
criteria.andNameEqualTo(apiTemplate.getName())
.andProjectIdEqualTo(apiTemplate.getProjectId());
if (StringUtils.isNotBlank(apiTemplate.getId())) {
criteria.andIdNotEqualTo(apiTemplate.getId());
}
if (apiTemplateMapper.selectByExample(example).size() > 0) {
MSException.throwException(Translator.get("template_already") + apiTemplate.getName());
}
}
}
public ApiTemplate getDefaultTemplate(String projectId) {
ApiTemplateExample example = new ApiTemplateExample();
example.createCriteria()
.andProjectIdEqualTo(projectId)
.andSystemEqualTo(true);
List<ApiTemplate> apiTemplates = apiTemplateMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(apiTemplates)) {
return apiTemplates.get(0);
}
example.clear();
example.createCriteria()
.andGlobalEqualTo(true);
return apiTemplateMapper.selectByExample(example).get(0);
}
public List<ApiTemplate> getOption(String projectId) {
List<ApiTemplate> apiTemplates;
ApiTemplateExample example = new ApiTemplateExample();
if (StringUtils.isBlank(projectId)) {
example.createCriteria().andGlobalEqualTo(true)
.andSystemEqualTo(true);
return apiTemplateMapper.selectByExample(example);
}
example.createCriteria()
.andProjectIdEqualTo(projectId)
.andSystemNotEqualTo(true);
apiTemplates = apiTemplateMapper.selectByExample(example);
apiTemplates.add(getDefaultTemplate(projectId));
return apiTemplates;
}
public ApiTemplateDTO getTemplate(String projectId) {
Project project = projectService.getProjectById(projectId);
String apiTemplateId = project.getApiTemplateId();
ApiTemplate apiTemplate;
ApiTemplateDTO apiTemplateDao = new ApiTemplateDTO();
if (StringUtils.isNotBlank(apiTemplateId)) {
apiTemplate = apiTemplateMapper.selectByPrimaryKey(apiTemplateId);
if (apiTemplate == null) {
apiTemplate = getDefaultTemplate(projectId);
}
} else {
apiTemplate = getDefaultTemplate(projectId);
}
BeanUtils.copyBean(apiTemplateDao, apiTemplate);
List<CustomFieldDao> result = customFieldService.getCustomFieldByTemplateId(apiTemplate.getId());
apiTemplateDao.setCustomFields(result);
return apiTemplateDao;
}
public String getLogDetails(String id) {
ApiTemplate templateWithBLOBs = apiTemplateMapper.selectByPrimaryKey(id);
if (templateWithBLOBs != null) {
List<DetailColumn> columns = ReflexObjectUtil.getColumns(templateWithBLOBs, SystemReference.caseFieldColumns);
OperatingLogDetails details = new OperatingLogDetails(JSON.toJSONString(templateWithBLOBs.getId()), null, templateWithBLOBs.getName(), templateWithBLOBs.getCreateUser(), columns);
return JSON.toJSONString(details);
}
return null;
}
}

View File

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

View File

@ -152,9 +152,7 @@ public class CustomFieldResourceService {
long count = extCustomFieldResourceMapper.countFieldResource(tableName, resourceId, field.getFieldId());
field.setResourceId(resourceId);
if (count > 0) {
if (StringUtils.isNotBlank(field.getValue()) || StringUtils.isNotBlank(field.getTextValue())) {
extCustomFieldResourceMapper.updateByPrimaryKeySelective(tableName, field);
}
} else {
extCustomFieldResourceMapper.insert(tableName, field);
}
@ -309,7 +307,9 @@ public class CustomFieldResourceService {
fields.forEach(field -> {
try {
CustomField customField;
if (StringUtils.isBlank(field.getName())) { return; }
if (StringUtils.isBlank(field.getName())) {
return;
}
if (param.isEnableJiraSync()) {
if (StringUtils.isBlank(field.getId()) || field.getId().length() == 36) {
// 自定义字段中id为空或者是uuid的就不处理了
@ -344,6 +344,7 @@ public class CustomFieldResourceService {
/**
* 如果是jira勾选了自动获取模板
* 则创建对应的自定义字段并标记成 thirdPart true
*
* @param projectId
* @param field
* @param param

View File

@ -51,6 +51,10 @@ public class CustomFieldService {
@Resource
IssueTemplateService issueTemplateService;
@Lazy
@Resource
ApiTemplateService apiTemplateService;
@Lazy
@Resource
CustomFieldTemplateService customFieldTemplateService;
@ -111,6 +115,8 @@ public class CustomFieldService {
add(customFieldDao);
if (StringUtils.equals(customField.getScene(), TemplateConstants.FieldTemplateScene.TEST_CASE.name())) {
testCaseTemplateService.handleSystemFieldCreate(customFieldDao);
} else if (StringUtils.equals(customField.getScene(), TemplateConstants.FieldTemplateScene.API.name())) {
apiTemplateService.handleSystemFieldCreate(customFieldDao);
} else {
issueTemplateService.handleSystemFieldCreate(customFieldDao);
}

View File

@ -210,6 +210,7 @@ public class ProjectService {
}
}
public void addProjectVersion(Project project) {
ProjectVersion projectVersion = new ProjectVersion();
projectVersion.setId(UUID.randomUUID().toString());
@ -437,6 +438,11 @@ public class ProjectService {
extProjectMapper.updateUseDefaultCaseTemplateProject(originId, templateId, projectId);
}
//修改默认接口模版id
public void updateApiTemplate(String originId, String templateId, String projectId) {
extProjectMapper.updateUseDefaultApiTemplateProject(originId, templateId, projectId);
}
private void deleteLoadTestResourcesByProjectId(String projectId) {
LoadTestExample loadTestExample = new LoadTestExample();
loadTestExample.createCriteria().andProjectIdEqualTo(projectId);
@ -693,6 +699,13 @@ public class ProjectService {
return projectMapper.selectByExample(example);
}
public List<Project> getByApiTemplateId(String templateId) {
ProjectExample example = new ProjectExample();
example.createCriteria()
.andApiTemplateIdEqualTo(templateId);
return projectMapper.selectByExample(example);
}
public List<Project> getByIssueTemplateId(String templateId) {
ProjectExample example = new ProjectExample();
example.createCriteria()

@ -1 +1 @@
Subproject commit c6cd95f777577f8f1d478b13261021cc68d4079a
Subproject commit c13ef4c4f29e39de2b7de84d95a17e2e994e7b88

View File

@ -422,6 +422,11 @@
"name": "permission.project_template.issue_template",
"resourceId": "PROJECT_TEMPLATE"
},
{
"id": "PROJECT_TEMPLATE:READ+API_TEMPLATE",
"name": "permission.project_template.api_template",
"resourceId": "PROJECT_TEMPLATE"
},
{
"id": "PROJECT_TEMPLATE:READ+CUSTOM",
"name": "permission.project_template.custom",

View File

@ -1,7 +1,7 @@
<template>
<div>
<ms-container v-if="renderComponent">
<ms-aside-container>
<ms-aside-container v-show="isAsideHidden">
<ms-api-module
:show-operator="true"
:default-protocol="defaultProtocol"
@ -386,6 +386,7 @@ export default {
activeTab: "api",
currentVersion: null,
trashVersion: null,
isAsideHidden: true,
};
},
activated() {
@ -460,6 +461,9 @@ export default {
}
}
},
apiDefaultTab() {
this.isAsideHidden = (this.apiDefaultTab === 'default' || this.apiDefaultTab === 'trash');
}
},
created() {
let routeParamObj = this.$route.params.paramObj;

View File

@ -2,7 +2,8 @@
<div class="card-container">
<!-- HTTP 请求参数 -->
<ms-edit-complete-http-api @runTest="runTest" @saveApi="saveApi" @createRootModelInTree="createRootModelInTree"
<ms-edit-complete-http-api @createRootModelInTree="createRootModelInTree" @runTest="runTest"
@saveApi="saveApiValidate"
:request="request" :response="response" :project-id="projectId"
@mockConfig="mockConfig"
@changeTab="changeTab"
@ -11,20 +12,20 @@
v-if="currentProtocol === 'HTTP'" ref="httpApi"/>
<!-- TCP -->
<ms-edit-complete-tcp-api :request="request" @runTest="runTest" @createRootModelInTree="createRootModelInTree"
@saveApi="saveApi" :basisData="currentApi"
:basisData="currentApi" @saveApi="saveApiValidate"
@changeTab="changeTab"
@checkout="checkout"
:moduleOptions="moduleOptions" :syncTabs="syncTabs" v-if="currentProtocol === 'TCP'"
ref="tcpApi"/>
<!--DUBBO-->
<ms-edit-complete-dubbo-api :request="request" @runTest="runTest" @createRootModelInTree="createRootModelInTree"
@saveApi="saveApi" :basisData="currentApi"
:basisData="currentApi" @saveApi="saveApiValidate"
@checkout="checkout"
:moduleOptions="moduleOptions" :syncTabs="syncTabs" v-if="currentProtocol === 'DUBBO'"
ref="dubboApi"/>
<!--SQL-->
<ms-edit-complete-sql-api :request="request" @runTest="runTest" @createRootModelInTree="createRootModelInTree"
@saveApi="saveApi" :basisData="currentApi"
:basisData="currentApi" @saveApi="saveApiValidate"
@checkout="checkout"
:moduleOptions="moduleOptions" :syncTabs="syncTabs" v-if="currentProtocol === 'SQL'"
ref="sqlApi"/>
@ -38,7 +39,7 @@
import MsEditCompleteSqlApi from "./complete/EditCompleteSQLApi";
import {Body} from "../model/ApiTestModel";
import {getCurrentProjectID, getUUID, handleCtrlSEvent} from "@/common/js/utils";
import {getUUID, handleCtrlSEvent} from "@/common/js/utils";
import {createComponent, Request} from "./jmeter/components";
import Sampler from "./jmeter/components/sampler/sampler";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
@ -62,7 +63,8 @@
moduleOptions: {},
currentProtocol: String,
syncTabs: Array,
projectId: String
projectId: String,
validateTrue: String
},
watch: {
request: {
@ -275,7 +277,21 @@
this.sort(this.request.hashTree);
},
setParameter(data) {
data.name = this.currentApi.name;
data.moduleId = this.currentApi.moduleId;
data.userId = this.currentApi.userId;
data.status = this.currentApi.status;
if (this.currentApi.tags instanceof Array) {
data.tags = JSON.stringify(this.currentApi.tags);
}
data.description = this.currentApi.description;
},
saveApiValidate(data) {
this.$emit('validateBasic', data);
},
saveApi(data) {
this.setParameter(data);
this.setParameters(data);
let bodyFiles = this.getBodyUploadFiles(data);
data.requestId = data.request.id;
@ -305,6 +321,8 @@
this.$store.state.apiMap.set(this.currentApi.id, this.$store.state.apiStatus);
this.$store.state.apiStatus.set("responseChange", false);
this.$store.state.apiMap.set(this.currentApi.id, this.$store.state.apiStatus);
this.$store.state.apiStatus.set("fromChange", false);
this.$store.state.apiMap.set(this.currentApi.id, this.$store.state.apiStatus);
},
handleSave() {
if (this.$refs.httpApi) {

View File

@ -1,17 +1,34 @@
<template>
<el-card class="card-content" v-if="isShow && !loading">
<ms-container v-loading="loading" style="overflow: auto">
<ms-aside-container>
<api-base-info
ref="apiBaseInfo"
:api-template="apiTemplate"
:currentProtocol="currentProtocol"
:custom-field-form="customFieldForm"
:custom-field-rules="customFieldRules"
:form="currentApi"
:is-form-alive="isFormAlive"
:isloading="loading"
:maintainer-options="maintainerOptions"
:module-options="moduleOptions"
/>
</ms-aside-container>
<ms-main-container class="ms-scenario-main-container" style="overflow: hidden">
<el-button-group v-if="currentApi.id" style="z-index: 10; position: fixed;">
<el-button class="item" plain :class="{active: showApiList}" @click="changeTab('api')" size="small">
<el-button :class="{active: showApiList}" class="item" plain size="small" @click="changeTab('api')">
API
</el-button>
<el-button class="item" plain :class="{active: showTest}" @click="changeTab('test')" size="small">
<el-button :class="{active: showTest}" class="item" plain size="small" @click="changeTab('test')">
TEST
</el-button>
<el-button class="item" plain :class="{active: showTestCaseList}" @click="changeTab('testCase')" size="small">
<el-button :class="{active: showTestCaseList}" class="item" plain size="small" @click="changeTab('testCase')">
CASE
</el-button>
<el-button class="item" plain :class="{active: showMock}" @click="changeTab('mock')" size="small"
v-if="currentProtocol === 'HTTP' || currentProtocol === 'TCP'">
<el-button v-if="currentProtocol === 'HTTP' || currentProtocol === 'TCP'" :class="{active: showMock}"
class="item" plain size="small"
@click="changeTab('mock')">
MOCK
</el-button>
@ -23,87 +40,92 @@
<slot></slot>
<div v-if="showApiList">
<ms-api-config
:syncTabs="syncTabs" ref="apiConfig"
ref="apiConfig" :api-template="apiTemplate"
:current-api="currentApi"
:project-id="projectId"
:currentProtocol="currentProtocol"
:moduleOptions="moduleOptions"
:project-id="projectId"
:syncTabs="syncTabs"
:validateTrue.sync="validateTrue"
@changeTab="changeTab"
@checkout="checkout"
@createRootModel="createRootModel"
@runTest="runTest"
@saveApi="saveApi"
@checkout="checkout"
@changeTab="changeTab"
@createRootModel="createRootModel"
@validateBasic="validateBasic"
/>
</div>
<div v-else-if="showTest">
<ms-run-test-http-page
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
v-if="currentProtocol==='HTTP'"
ref="httpTestPage"
:api-data="currentApi"
:currentProtocol="currentProtocol"
:project-id="projectId"
:syncTabs="syncTabs"
@refresh="refresh"
@saveAsApi="editApi"
@saveAsCase="saveAsCase"
@refresh="refresh"
ref="httpTestPage"
v-if="currentProtocol==='HTTP'"
/>
<ms-run-test-tcp-page
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
v-if="currentProtocol==='TCP'"
ref="tcpTestPage"
:api-data="currentApi"
:currentProtocol="currentProtocol"
:project-id="projectId"
:syncTabs="syncTabs"
@refresh="refresh"
@saveAsApi="editApi"
@saveAsCase="saveAsCase"
@refresh="refresh"
ref="tcpTestPage"
v-if="currentProtocol==='TCP'"
/>
<ms-run-test-sql-page
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
v-if="currentProtocol==='SQL'"
:api-data="currentApi"
:currentProtocol="currentProtocol"
:project-id="projectId"
:syncTabs="syncTabs"
@refresh="refresh"
@saveAsApi="editApi"
@saveAsCase="saveAsCase"
@refresh="refresh"
v-if="currentProtocol==='SQL'"
/>
<ms-run-test-dubbo-page
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
v-if="currentProtocol==='DUBBO'"
:api-data="currentApi"
:currentProtocol="currentProtocol"
:project-id="projectId"
:syncTabs="syncTabs"
@refresh="refresh"
@saveAsApi="editApi"
@saveAsCase="saveAsCase"
@refresh="refresh"
v-if="currentProtocol==='DUBBO'"
/>
</div>
<div v-if="showMock && (currentProtocol === 'HTTP' || currentProtocol === 'TCP')">
<mock-tab :base-mock-config-data="baseMockConfigData" @redirectToTest="redirectToTest"
:version-name="currentApi.versionName"
:is-tcp="currentProtocol === 'TCP'"/>
<mock-tab :base-mock-config-data="baseMockConfigData" :form="currentApi"
:is-tcp="currentProtocol === 'TCP'"
:version-name="currentApi.versionName" @redirectToTest="redirectToTest"/>
</div>
<div v-if="showTestCaseList">
<!--测试用例列表-->
<api-case-simple-list
:apiDefinitionId="currentApi.id"
ref="trashCaseList"
:apiDefinition="currentApi"
:apiDefinitionId="currentApi.id"
:current-version="currentApi.versionId"
:trash-enable="false"
@changeSelectDataRangeAll="changeSelectDataRangeAll"
@handleCase="handleCase"
@refreshTable="refresh"
@showExecResult="showExecResult"
ref="trashCaseList"/>
@showExecResult="showExecResult"/>
</div>
<!-- 加载用例 -->
<ms-api-case-list
ref="caseList"
:createCase="createCase"
:currentApi="api"
@reLoadCase="reLoadCase"
ref="caseList"/>
@reLoadCase="reLoadCase"/>
</ms-main-container>
</ms-container>
</el-card>
</template>
@ -120,6 +142,12 @@ import MsApiCaseList from "./case/ApiCaseList";
import {getUUID} from "@/common/js/utils";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
import _ from 'lodash';
import MsContainer from "@/business/components/common/components/MsContainer";
import MsAsideContainer from "@/business/components/common/components/MsAsideContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
import ApiBaseInfo from "@/business/components/api/definition/components/complete/ApiBaseInfo";
import {getProjectMemberOption} from "@/network/user";
import {buildCustomFields, getApiFieldTemplate, parseCustomField} from "@/common/js/custom_field";
export default {
name: "EditCompleteContainer",
@ -132,7 +160,9 @@ export default {
MockTab,
TcpMockConfig,
ApiCaseSimpleList,
MsApiCaseList
MsApiCaseList,
MsContainer, MsAsideContainer, MsMainContainer,
ApiBaseInfo
},
data() {
return {
@ -143,8 +173,15 @@ export default {
showTestCaseList: false,
baseMockConfigData: {},
loading: false,
createCase: "",
createCase: '',
api: {},
maintainerOptions: [],
isFormAlive: true,
validateTrue: '',
apiTemplate: {},
customFieldRules: {},
customFieldForm: null,
currentValidateName: '',
};
},
props: {
@ -166,10 +203,17 @@ export default {
},
created() {
this.refreshButtonActiveClass(this.activeDom);
getApiFieldTemplate(this)
.then((template) => {
this.apiTemplate = template;
this.$store.commit('setApiTemplate', this.apiTemplate);
this.customFieldForm = parseCustomField(this.currentApi, this.apiTemplate, this.customFieldRules);
});
if (this.currentApi.id && (this.currentProtocol === "HTTP" || this.currentProtocol === "TCP")) {
this.mockSetting();
}
this.formatApi();
this.getMaintainerOptions();
},
watch: {
showMock() {
@ -189,6 +233,10 @@ export default {
reLoadCase() {
this.$refs.trashCaseList.initTable();
},
reloadForm() {
this.isFormAlive = false;
this.$nextTick(() => (this.isFormAlive = true));
},
sort(stepArray) {
if (stepArray) {
for (let i in stepArray) {
@ -198,9 +246,9 @@ export default {
if (stepArray[i] && stepArray[i].authManager && !stepArray[i].authManager.clazzName) {
stepArray[i].authManager.clazzName = TYPE_TO_C.get(stepArray[i].authManager.type);
}
if (stepArray[i].type === "Assertions" && !stepArray[i].document) {
if (stepArray[i].type === 'Assertions' && !stepArray[i].document) {
stepArray[i].document = {
type: "JSON",
type: 'JSON',
data: {xmlFollowAPI: false, jsonFollowAPI: false, json: [], xml: []}
};
}
@ -266,6 +314,31 @@ export default {
this.reload();
},
validateBasic(data) {
let baseInfoValidate = this.$refs.apiBaseInfo.validateForm();
if (!baseInfoValidate) {
return false;
}
let customValidate = this.$refs.apiBaseInfo.validateCustomForm();
if (!customValidate) {
let customFieldFormFields = this.$refs.apiBaseInfo.getCustomFields();
for (let i = 0; i < customFieldFormFields.length; i++) {
let customField = customFieldFormFields[i];
if (customField.validateState === 'error') {
if (this.currentValidateName) {
this.currentValidateName = this.currentValidateName + "," + customField.label
} else {
this.currentValidateName = customField.label
}
}
}
this.$warning(this.currentValidateName + this.$t('commons.cannot_be_null'));
this.currentValidateName = '';
return false;
}
buildCustomFields(this.currentApi, data, this.apiTemplate);
this.$refs.apiConfig.saveApi(data);
},
createRootModel() {
this.$emit("createRootModel");
},
@ -385,7 +458,12 @@ export default {
} else {
this.changeApi();
}
}
},
getMaintainerOptions() {
getProjectMemberOption(data => {
this.maintainerOptions = data;
});
},
}
};
</script>

View File

@ -0,0 +1,247 @@
<template>
<div v-loading="isloading">
<el-form ref="apiForm" :model="basicForm" :rules="rules" class="case-form" label-position="right"
label-width="100px"
size="small"
style="margin-left: 5px;margin-right: 5px">
<ms-form-divider :title="$t('test_track.plan_view.base_info')"/>
<!-- 基础信息 -->
<el-row>
<el-form-item v-if="currentProtocol !== 'TCP'" :label="$t('commons.name')" prop="name">
<el-input v-model="basicForm.name" class="ms-http-input" size="small"/>
</el-form-item>
<el-form-item v-else :label="$t('commons.name')" prop="name">
<el-input v-model="basicForm.name" class="ms-http-input" size="small">
<el-select slot="prepend" v-model="basicForm.method" size="mini" style="width: 80px">
<el-option v-for="item in methodTypes" :key="item.key" :label="item.value" :value="item.key"/>
</el-select>
</el-input>
</el-form-item>
</el-row>
<el-row>
<el-form-item :label="$t('api_test.definition.request.responsible')" prop="userId">
<el-select v-model="basicForm.userId"
:placeholder="$t('api_test.definition.request.responsible')" class="ms-http-select" filterable
size="small">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.name + ' (' + item.email + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-row>
<el-row>
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
<ms-select-tree ref="msTree" :data="moduleOptions" :defaultKey="basicForm.moduleId" :obj="moduleObj"
checkStrictly clearable size="small" @getValue="setModule"/>
</el-form-item>
</el-row>
<el-row>
<el-form-item :label="$t('commons.status')" prop="status">
<el-select v-model="basicForm.status" class="ms-http-select" size="small">
<el-option v-for="item in options" :key="item.id" :label="$t(item.label)" :value="item.id"/>
</el-select>
</el-form-item>
</el-row>
<el-row>
<el-form-item :label="$t('commons.tag')" prop="tag">
<ms-input-tag ref="tag" v-model="basicForm.tags" :currentScenario="basicForm"/>
</el-form-item>
</el-row>
<el-row>
<el-form-item :label="$t('commons.description')" prop="description">
<el-input v-model="basicForm.description"
:autosize="{ minRows: 1, maxRows: 10}"
:rows="1"
class="ms-http-textarea"
size="small" type="textarea"/>
</el-form-item>
</el-row>
<!-- 自定义字段 -->
<el-form v-if="isFormAlive" ref="customFieldForm" :model="customFieldForm" :rules="customFieldRules"
class="case-form" label-position="right" label-width="100px"
size="small">
<custom-filed-form-row :default-open="defaultOpen"
:disabled="readOnly"
:form="customFieldForm"
:issue-template="apiTemplate"/>
</el-form>
</el-form>
</div>
</template>
<script>
import MsFormDivider from "@/business/components/common/components/MsFormDivider";
import MsSelectTree from "@/business/components/common/select-tree/SelectTree";
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
import CustomFiledFormRow from "@/business/components/common/components/form/CustomFiledFormRow";
import {API_STATUS, REQ_METHOD} from "@/business/components/api/definition/model/JsonData";
import {hasLicense} from "@/common/js/utils";
export default {
name: "ApiBaseInfo",
components: {
MsFormDivider,
MsSelectTree,
MsInputTag,
CustomFiledFormRow,
},
data() {
let validateModuleId = (rule, value, callback) => {
if (this.basicForm.moduleId.length === 0 || !this.basicForm.moduleId) {
callback(this.$t('test_track.case.input_module'));
} else {
callback();
}
};
return {
rules: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 100, message: this.$t('test_track.length_less_than') + '100', trigger: 'blur'}
],
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
moduleId: [{required: true, validator: validateModuleId, trigger: 'change'}],
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
},
moduleObj: {
id: 'id',
label: 'name',
},
options: API_STATUS,
reqOptions: REQ_METHOD,
methodTypes: [
{
'key': "TCP",
'value': this.$t('api_test.request.tcp.general_format'),
}
],
basicForm: {},
}
},
props: {
form: Object,
isFormAlive: Boolean,
isloading: Boolean,
readOnly: Boolean,
customFieldForm: Object,
customFieldRules: Object,
apiTemplate: Object,
moduleOptions: Array,
defaultOpen: String,
maintainerOptions: Array,
currentProtocol: String
},
watch: {
'basicForm.name': {
handler(v, v1) {
if (v && v1 && v !== v1) {
this.apiMapStatus();
}
}
},
'basicForm.moduleId': {
handler(v, v1) {
if (v && v1 && v !== v1) {
this.apiMapStatus();
}
}
},
'basicForm.status': {
handler(v, v1) {
if (v && v1 && v !== v1) {
this.apiMapStatus();
}
}
},
'basicForm.follows': {
handler(v, v1) {
if (v && v1 && JSON.stringify(v) !== JSON.stringify(v1)) {
this.apiMapStatus();
}
}
},
'basicForm.description': {
handler(v, v1) {
if (v && v1 !== undefined && v !== v1) {
this.apiMapStatus();
}
}
},
'basicForm.tags': {
handler(v, v1) {
if (v && v1 && JSON.stringify(v) !== JSON.stringify(v1)) {
this.apiMapStatus();
}
}
},
customFieldForm: {
handler(v, v1) {
if (v && v1 && this.$store.state.apiMap && this.basicForm.id) {
this.apiMapStatus();
}
},
deep: true
}
},
methods: {
apiMapStatus() {
this.$store.state.apiStatus.set("fromChange", true);
if (this.basicForm.id) {
this.$store.state.apiMap.set(this.basicForm.id, this.$store.state.apiStatus);
}
},
setModule(id, data) {
this.basicForm.module = id;
this.basicForm.nodePath = data.path;
},
validateForm() {
let isValidate = true;
this.$refs['apiForm'].validate((valid) => {
if (!valid) {
isValidate = false;
}
});
return isValidate;
},
validateCustomForm() {
let isValidate = true;
this.$refs['customFieldForm'].validate((valid) => {
if (!valid) {
isValidate = false;
}
});
return isValidate;
},
getCustomFields() {
let caseFromFields = this.$refs['apiForm'].fields;
let customFields = this.$refs['customFieldForm'].fields;
Array.prototype.push.apply(caseFromFields, customFields);
return caseFromFields;
},
},
created() {
this.basicForm = this.form;
if (hasLicense()) {
if (this.methodTypes.length == 1) {
let esbMethodType = {};
esbMethodType.key = "ESB";
esbMethodType.value = "ESB";
this.methodTypes.push(esbMethodType);
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -29,16 +29,6 @@
</div>
</el-col>
</el-row>
<!-- 基础信息 -->
<p class="tip">{{ $t('test_track.plan_view.base_info') }} </p>
<br/>
<el-row>
<el-col>
<ms-basis-api @createRootModelInTree="createRootModelInTree" :moduleOptions="moduleOptions"
:basisData="basisData" ref="basicForm"
@callback="callback"/>
</el-col>
</el-row>
<!-- 请求参数 -->
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>

View File

@ -41,17 +41,8 @@
</el-dropdown>
</div>
<br/>
<ms-form-divider :title="$t('test_track.plan_view.base_info')"/>
<!-- 基础信息 -->
<div class="base-info">
<el-row>
<el-col :span="8">
<el-form-item :label="$t('commons.name')" prop="name">
<el-input class="ms-http-input" size="small" v-model="httpForm.name"/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item :label="$t('api_report.request')" prop="path">
<el-input :placeholder="$t('api_test.definition.request.path_info')" v-model="httpForm.path"
@ -63,70 +54,6 @@
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item :label="$t('api_test.definition.request.responsible')" prop="userId">
<el-select v-model="httpForm.userId"
:placeholder="$t('api_test.definition.request.responsible')" filterable size="small"
class="ms-http-select">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.name + ' (' + item.email + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="httpForm.moduleId" @getValue="setModule"
:obj="moduleObj" clearable checkStrictly ref="msTree"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('commons.status')" prop="status">
<el-select class="ms-http-select" size="small" v-model="httpForm.status">
<el-option v-for="item in options" :key="item.id" :label="$t(item.label)" :value="item.id"/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item :label="$t('commons.tag')" prop="tag">
<ms-input-tag :currentScenario="httpForm" ref="tag" v-model="httpForm.tags"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="httpForm.description"
type="textarea"
:autosize="{ minRows: 1, maxRows: 10}"
:rows="1" size="small"/>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- MOCK信息 -->
<ms-form-divider :title="$t('test_track.plan_view.mock_info')"/>
<div class="base-info mock-info">
<el-row>
<el-col :span="20">
Mock地址
<el-link :href="getUrlPrefix" target="_blank" style="color: black"
type="primary">{{ this.getUrlPrefix }}
</el-link>
</el-col>
<el-col :span="4">
<el-link @click="mockSetting" type="primary">Mock设置</el-link>
</el-col>
</el-row>
</div>
<!-- 请求参数 -->
@ -376,13 +303,6 @@ export default {
},
props: {moduleOptions: {}, request: {}, response: {}, basisData: {}, syncTabs: Array, projectId: String},
watch: {
'httpForm.name': {
handler(v, v1) {
if (v && v1 && v !== v1) {
this.apiMapStatus();
}
}
},
'httpForm.path': {
handler(v, v1) {
if (v && v1 && v !== v1) {
@ -390,49 +310,6 @@ export default {
}
}
},
'httpForm.userId': {
handler(v, v1) {
if (v && v1 && v !== v1) {
this.apiMapStatus();
}
}
},
'httpForm.moduleId': {
handler(v, v1) {
if (v && v1 && v !== v1) {
this.apiMapStatus();
}
}
},
'httpForm.status': {
handler(v, v1) {
if (v && v1 && v !== v1) {
this.apiMapStatus();
}
}
},
'httpForm.follows': {
handler(v, v1) {
if (v && v1 && JSON.stringify(v) !== JSON.stringify(v1)) {
this.apiMapStatus();
}
}
},
'httpForm.description': {
handler(v, v1) {
if (v && v1 !== undefined && v !== v1) {
this.apiMapStatus();
}
}
},
'httpForm.tags': {
handler(v, v1) {
this.count++;
if (v && v1 && JSON.stringify(v) !== JSON.stringify(v1) && this.count > 1) {
this.apiMapStatus();
}
}
},
syncTabs() {
if (this.basisData && this.syncTabs && this.syncTabs.includes(this.basisData.id)) {
//
@ -578,7 +455,6 @@ export default {
this.$refs['httpForm'].validate((valid) => {
if (valid) {
this.setParameter();
if (!this.httpForm.versionId) {
if (this.$refs.versionHistory && this.$refs.versionHistory.currentVersion) {
this.httpForm.versionId = this.$refs.versionHistory.currentVersion.id;

View File

@ -28,16 +28,6 @@
</div>
</el-col>
</el-row>
<!-- 基础信息 -->
<p class="tip">{{ $t('test_track.plan_view.base_info') }} </p>
<br/>
<el-row>
<el-col>
<ms-basis-api @createRootModelInTree="createRootModelInTree" :moduleOptions="moduleOptions"
:basisData="basisData" ref="basicForm"
@callback="callback"/>
</el-col>
</el-row>
<!-- 请求参数 -->
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>

View File

@ -28,35 +28,7 @@
</div>
</el-col>
</el-row>
<!-- 基础信息 -->
<p class="tip">{{ $t('test_track.plan_view.base_info') }} </p>
<br/>
<el-row>
<el-col>
<ms-tcp-basic-api :method-types="methodTypes" @createRootModelInTree="createRootModelInTree"
:moduleOptions="moduleOptions"
:basisData="basisData" ref="basicForm"
@changeApiProtocol="changeApiProtocol" @callback="callback"/>
</el-col>
</el-row>
<!-- MOCK信息 -->
<p class="tip">{{ $t('test_track.plan_view.mock_info') }} </p>
<div class="mock-info">
<el-row>
<el-col :span="20">
Mock地址
<el-link v-if="this.mockInfo !== '' " target="_blank" style="color: black"
type="primary">{{ this.mockInfo }}
</el-link>
<el-link v-else target="_blank" style="color: darkred"
type="primary">当前项目未开启Mock服务
</el-link>
</el-col>
<el-col :span="4">
<el-link @click="mockSetting" type="primary">Mock设置</el-link>
</el-col>
</el-row>
</div>
<!-- 请求参数 -->
<div v-if="apiProtocol=='TCP'">
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
@ -243,14 +215,7 @@ export default {
callback() {
this.validated = true;
},
validateApi() {
this.validated = false;
this.basisData.method = this.apiProtocol;
this.$refs['basicForm'].validate();
},
saveApi() {
this.validateApi();
if (this.validated) {
if (this.basisData.tags instanceof Array) {
this.basisData.tags = JSON.stringify(this.basisData.tags);
}
@ -277,11 +242,10 @@ export default {
this.$emit('saveApi', this.basisData);
this.$store.state.apiStatus.set("fromChange", false);
this.$store.state.apiMap.set(this.basisData.id, this.$store.state.apiStatus);
} else {
if (this.$refs.versionHistory) {
this.$refs.versionHistory.loading = false;
}
}
},
runTest() {
this.validateApi();

View File

@ -4,11 +4,20 @@
<div class="ms-opt-btn" v-if="versionEnable">
{{ $t('project.version.name') }}: {{ versionName }}
</div>
<el-input :placeholder="$t('commons.search_by_name')" class="search-input" size="small"
:clearable="true"
v-model="tableSearch"/>
<el-button type="primary" style="float: right;margin-right: 10px" icon="el-icon-plus" size="small"
v-permission="['PROJECT_API_DEFINITION:READ+EDIT_API']"
Mock地址
<el-link v-if="this.getUrlPrefix !== '' " :href="getUrlPrefix" style="color: black" target="_blank"
type="primary">
<span :style="{width: urlWidth}" class="ms-tab-name-width">{{ this.getUrlPrefix }}</span>
</el-link>
<el-link v-else style="color: darkred" target="_blank"
type="primary">当前项目未开启Mock服务
</el-link>
<el-input v-model="tableSearch" :clearable="true" :placeholder="$t('commons.search_by_name')"
class="search-input"
size="small"/>
<el-button v-permission="['PROJECT_API_DEFINITION:READ+EDIT_API']" icon="el-icon-plus" size="small"
style="float: right;margin-right: 10px"
type="primary"
@click="addApiMock">{{ $t('commons.add') }}
</el-button>
@ -101,6 +110,7 @@ export default {
type: Boolean,
default: false,
},
form: Object
},
data() {
return {
@ -134,22 +144,60 @@ export default {
}
],
versionEnable: false,
mockBaseUrl: "",
};
},
watch: {
baseMockConfigData() {
this.mockConfigData = this.baseMockConfigData;
}
},
},
created() {
this.mockConfigData = this.baseMockConfigData;
this.checkVersionEnable();
this.initMockEnvironment();
},
computed: {
getUrlPrefix() {
if (this.form.path == null) {
return this.mockBaseUrl;
} else {
let path = this.form.path;
let protocol = this.form.method;
if (protocol === 'GET' || protocol === 'DELETE') {
if (this.form.request != null && this.form.request.rest != null) {
let pathUrlArr = path.split("/");
let newPath = "";
pathUrlArr.forEach(item => {
if (item !== "") {
let pathItem = item;
if (item.indexOf("{") === 0 && item.indexOf("}") === (item.length - 1)) {
let paramItem = item.substr(1, item.length - 2);
for (let i = 0; i < this.form.request.rest.length; i++) {
let param = this.form.request.rest[i];
if (param.name === paramItem) {
pathItem = param.value;
}
}
}
newPath += "/" + pathItem;
}
});
if (newPath !== "") {
path = newPath;
}
}
}
return this.mockBaseUrl + path;
}
},
projectId() {
return getCurrentProjectID();
},
urlWidth() {
return document.documentElement.clientWidth - 900 + 'px';
}
},
methods: {
redirectToTest(row) {
@ -356,7 +404,26 @@ export default {
this.versionEnable = response.data;
});
}
},
initMockEnvironment() {
let protocol = document.location.protocol;
protocol = protocol.substring(0, protocol.indexOf(":"));
let url = "/api/definition/getMockEnvironment/";
this.$get(url + this.projectId, response => {
let mockEnvironment = response.data;
let httpConfig = JSON.parse(mockEnvironment.config);
if (httpConfig != null) {
httpConfig = httpConfig.httpConfig;
let httpType = httpConfig.defaultCondition;
let conditions = httpConfig.conditions;
conditions.forEach(condition => {
if (condition.type === httpType) {
this.mockBaseUrl = condition.protocol + "://" + condition.socket;
}
});
}
});
},
}
};
</script>
@ -373,4 +440,13 @@ export default {
margin-right: 10px;
margin-bottom: 10px;
}
.ms-tab-name-width {
display: inline-block;
overflow-x: hidden;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
max-width: 1030px;
}
</style>

View File

@ -2,7 +2,8 @@
<div>
<el-dialog :close-on-click-modal="false" :title="title" :visible.sync="createVisible" v-if="createVisible"
@close="handleClose">
<el-form v-loading="result.loading" :model="form" :rules="rules" ref="form" label-position="right" label-width="80px" size="small">
<el-form ref="form" v-loading="result.loading" :model="form" :rules="rules" label-position="right"
label-width="80px" size="small">
<el-form-item :label-width="labelWidth" :label="$t('commons.name')" prop="name">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
@ -17,7 +18,8 @@
</el-form-item>
<el-form-item :label-width="labelWidth" :label="$t('workspace.case_template_manage')" prop="caseTemplateId">
<template-select :data="form" scene="API_CASE" prop="caseTemplateId" ref="caseTemplate" :project-id="form.id"/>
<template-select ref="caseTemplate" :data="form" :project-id="form.id" prop="caseTemplateId"
scene="API_CASE"/>
</el-form-item>
<el-form-item :label-width="labelWidth"
@ -34,22 +36,36 @@
</el-form-item>
<el-form-item :label="$t('workspace.api_template_manage')" :label-width="labelWidth" prop="apiTemplateId">
<template-select ref="apiTemplate" :data="form" :project-id="form.id" prop="apiTemplateId"
scene="API"/>
</el-form-item>
<el-form-item :label-width="labelWidth" :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-width="labelWidth" :label="$t('project.tapd_id')" v-if="tapd">
<el-input v-model="form.tapdId" autocomplete="off"></el-input>
<el-button @click="check" type="primary" class="checkButton">{{ $t('test_track.issue.check_id_exist') }}</el-button>
<el-button class="checkButton" type="primary" @click="check">{{
$t('test_track.issue.check_id_exist')
}}
</el-button>
</el-form-item>
<project-jira-config :result="result" v-if="jira" :label-width="labelWidth" :form="form" ref="jiraConfig">
<template #checkBtn>
<el-button @click="check" type="primary" class="checkButton">{{ $t('test_track.issue.check_id_exist') }}</el-button>
<el-button class="checkButton" type="primary" @click="check">{{
$t('test_track.issue.check_id_exist')
}}
</el-button>
</template>
</project-jira-config>
<el-form-item :label-width="labelWidth" :label="$t('project.zentao_id')" v-if="zentao">
<el-input v-model="form.zentaoId" autocomplete="off"></el-input>
<el-button @click="check" type="primary" class="checkButton">{{ $t('test_track.issue.check_id_exist') }}</el-button>
<el-button class="checkButton" type="primary" @click="check">{{
$t('test_track.issue.check_id_exist')
}}
</el-button>
<ms-instructions-icon effect="light">
<template>
禅道流程产品-项目 | 产品-迭代 | 产品-冲刺 | 项目-迭代 | 项目-冲刺 <br/><br/>
@ -87,7 +103,8 @@ import {
getCurrentUser,
getCurrentUserId,
getCurrentWorkspaceId,
listenGoBack, operationConfirm,
listenGoBack,
operationConfirm,
removeGoBackListener
} from "@/common/js/utils";
@ -208,6 +225,9 @@ export default {
if (this.$refs.caseTemplate) {
this.$refs.caseTemplate.getTemplateOptions();
}
if (this.$refs.apiTemplate) {
this.$refs.apiTemplate.getTemplateOptions();
}
},
thirdPartTemplateChange(val) {
if (val)
@ -219,7 +239,10 @@ export default {
listenGoBack(this.handleClose);
if (row) {
this.title = this.$t('project.edit');
row.issueConfigObj = row.issueConfig ? JSON.parse(row.issueConfig) : {jiraIssueTypeId: null, jiraStoryTypeId: null};
row.issueConfigObj = row.issueConfig ? JSON.parse(row.issueConfig) : {
jiraIssueTypeId: null,
jiraStoryTypeId: null
};
//
if (!row.issueConfigObj.jiraIssueTypeId) {
row.issueConfigObj.jiraIssueTypeId = null;

View File

@ -0,0 +1,313 @@
<template>
<el-drawer
ref="drawer"
v-loading="result.loading"
:before-close="handleClose"
:modal="false"
:visible.sync="showDialog"
:with-header="false"
class="field-template-edit"
size="100%">
<template v-slot:default="scope">
<template-component-edit-header :template="form" @cancel="handleClose" @save="handleSave"/>
<el-main class="container">
<el-scrollbar>
<ms-form-divider :title="$t('test_track.plan_view.base_info')"/>
<el-form ref="form" :model="form" :rules="rules" label-position="right" label-width="80px" size="small">
<el-form-item :label="$t('table.template_name')" :label-width="labelWidth" prop="name">
<el-input v-model="form.name" :disabled="isSystem" autocomplete="off" maxlength="64"
show-word-limit></el-input>
</el-form-item>
<el-form-item :label="$t('commons.description')" :label-width="labelWidth" prop="description">
<el-input v-model="form.description" :autosize="{ minRows: 2, maxRows: 4}" maxlength="255"
show-word-limit type="textarea"></el-input>
</el-form-item>
<ms-form-divider :title="$t('custom_field.template_setting')"/>
<slot></slot>
<el-form-item :label="$t('table.base_fields')" :label-width="labelWidth" class="filed-list">
</el-form-item>
<el-form-item>
<el-row>
<el-col :span="6">
<el-form-item :label="$t('commons.name')">
<el-input :disabled="true" class="ms-http-input" size="small"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('test_track.module.module')">
<el-input :disabled="true" class="ms-http-input" size="small"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('commons.status')">
<el-input :disabled="true" class="ms-http-input" size="small"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-form-item :label="$t('api_test.definition.request.responsible')">
<el-input
:disabled="true"
class="ms-http-input"
filterable size="small" style="width: 100%"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('commons.tag')">
<el-input ref="tag" :disabled="true"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('commons.description')">
<el-input :autosize="{ minRows: 1, maxRows: 10}"
:disabled="true"
:rows="1"
class="ms-http-textarea" size="small" type="textarea"/>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('table.selected_custom_fields')" :label-width="labelWidth" class="filed-list">
<el-button type="primary" @click="relateField">{{ $t('custom_field.add_field') }}</el-button>
<el-button plain type="primary" @click="addField">{{
$t('custom_field.custom_field_setting')
}}
</el-button>
</el-form-item>
<el-form-item :label-width="labelWidth">
<custom-field-form-list
ref="customFieldFormList"
:custom-field-ids="form.customFieldIds"
:platform="form.platform"
:scene="scene"
:table-data="relateFields"
:template-contain-ids="templateContainIds"
/>
</el-form-item>
</el-form>
<custom-field-relate-list
ref="customFieldRelateList"
:scene="scene"
:template-contain-ids="templateContainIds"
:template-id="form.id"
@save="handleRelate"/>
<custom-field-edit ref="customFieldEdit" :label-width="labelWidth" :scene="scene"
@save="handleCustomFieldAdd"/>
</el-scrollbar>
</el-main>
</template>
</el-drawer>
</template>
<script>
import draggable from 'vuedraggable';
import TemplateComponentEditHeader
from "@/business/components/track/plan/view/comonents/report/TemplateComponentEditHeader";
import MsFormDivider from "@/business/components/common/components/MsFormDivider";
import CustomFieldFormList from "@/business/components/project/template/CustomFieldFormList";
import CustomFieldRelateList from "@/business/components/project/template/CustomFieldRelateList";
import {getCurrentProjectID, listenGoBack} from "@/common/js/utils";
import CustomFieldEdit from "@/business/components/project/template/CustomFieldEdit";
import {generateTableHeaderKey, getCustomFieldsKeys} from "@/common/js/tableUtils";
export default {
name: "FieldTemplateEdit",
components: {
CustomFieldEdit,
CustomFieldRelateList,
CustomFieldFormList,
MsFormDivider,
TemplateComponentEditHeader,
draggable,
},
data() {
return {
templateContainIds: new Set(),
relateFields: [],
showDialog: false,
form: {
name: "",
description: '',
customFieldIds: [],
},
labelWidth: '120px',
rules: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 64, message: this.$t('test_track.length_less_than') + '64', trigger: 'blur'}
],
type: [{required: true, trigger: 'change'}],
},
result: {},
url: '',
scene: 'API',
isSystem: false
};
},
methods: {
open() {
this.$nextTick(() => {
this.init();
this.getRelateFields();
this.showDialog = true;
});
},
openEdit(data, isCopy) {
if (data) {
Object.assign(this.form, data);
this.isSystem = this.form.system;
if (!(data.options instanceof Array)) {
this.form.options = data.options ? JSON.parse(data.options) : [];
}
if (isCopy) {
this.url = 'project/field/template/api/add';
} else {
this.url = 'project/field/template/api/update';
}
listenGoBack(() => {
this.showDialog = false;
});
} else {
this.form = {
id: "",
name: "",
description: '',
customFieldIds: [],
};
this.url = 'project/field/template/api/add';
}
this.open(data);
},
init() {
this.relateFields = [];
this.templateContainIds = new Set();
},
handleClose() {
this.showDialog = false;
},
handleRelate(data) {
this.templateContainIds.add(...data);
this.$refs.customFieldFormList.appendData(data);
},
handleSave() {
this.$refs.form.validate((valid) => {
if (valid) {
let param = {};
Object.assign(param, this.form);
param.options = JSON.stringify(this.form.options);
param.projectId = getCurrentProjectID();
let customFields = this.relateFields;
if (customFields) {
let keys = getCustomFieldsKeys(customFields);
customFields.forEach(item => {
if (!item.key) {
item.key = generateTableHeaderKey(keys, customFields);
}
item.defaultValue = JSON.stringify(item.defaultValue);
});
}
param.customFields = customFields;
this.result = this.$post(this.url, param, () => {
this.handleClose();
this.$success(this.$t('commons.save_success'));
this.$emit('refresh');
});
}
});
},
handleCustomFieldAdd(data) {
this.templateContainIds.add(data.id);
data.fieldId = data.id;
data.id = null;
data.options = JSON.parse(data.options);
if (data.type === 'checkbox') {
data.defaultValue = [];
}
this.relateFields.push(data);
},
relateField() {
this.$refs.customFieldRelateList.open();
},
addField() {
this.$refs.customFieldEdit.open(null, this.$t('custom_field.create'));
},
getRelateFields() {
let condition = {};
condition.templateId = this.form.id;
if (this.form.id) {
this.result = this.$post('custom/field/template/list',
condition, (response) => {
this.relateFields = response.data;
this.relateFields.forEach(item => {
if (item.options) {
item.options = JSON.parse(item.options);
}
if (item.defaultValue) {
item.defaultValue = JSON.parse(item.defaultValue);
} else if (item.type === 'checkbox') {
item.defaultValue = [];
}
this.templateContainIds.add(item.fieldId);
});
this.$refs.customFieldFormList.refreshTable();
});
} else {
this.appendDefaultFiled();
}
},
appendDefaultFiled() {
let condition = {
projectId: getCurrentProjectID(),
scene: this.scene
};
this.result = this.$post('custom/field/default', condition, (response) => {
let data = response.data;
data.forEach(item => {
if (item.id) {
this.templateContainIds.add(item.id);
}
item.fieldId = item.id;
item.id = null;
item.options = JSON.parse(item.options);
if (item.type === 'checkbox') {
item.defaultValue = [];
}
});
this.relateFields.push(...data);
});
}
}
};
</script>
<style scoped>
.container {
height: calc(100vh - 42px);
}
.filed-list {
margin-top: 30px;
}
.field-template-edit {
z-index: 1500 !important;
}
</style>

View File

@ -0,0 +1,196 @@
<template>
<el-card class="table-card">
<template v-slot:header>
<ms-table-header :condition.sync="condition" :create-tip="$t('custom_field.template_create')"
@create="handleCreate"
@search="initTableData"/>
</template>
<ms-table
ref="table"
v-loading="result.loading"
:condition="condition"
:data="tableData"
:enable-selection="false"
:operators="operators"
:page-size.sync="pageSize"
:screen-height="tableHeight"
:total="total"
@handlePageChange="initTableData"
@refresh="initTableData">
<ms-table-column
:fields="fields"
:label="$t('commons.name')"
prop="name">
<template v-slot="scope">
<span v-if="scope.row.system">{{ scope.row.name }}({{ $t('custom_field.default_template') }})</span>
<span v-else>{{ scope.row.name }}</span>
</template>
</ms-table-column>
<ms-table-column
:fields="fields"
:label="$t('custom_field.system_template')"
prop="system">
<template v-slot="scope">
<span v-if="scope.row.system">
{{ $t('commons.yes') }}
</span>
<span v-else>
{{ $t('commons.no') }}
</span>
</template>
</ms-table-column>
<ms-table-column
:fields="fields"
:label="$t('commons.description')"
prop="description">
</ms-table-column>
<ms-table-column
:fields="fields"
:label="$t('commons.create_time')"
prop="createTime"
sortable>
<template v-slot="scope">
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
</template>
</ms-table-column>
<ms-table-column
:fields="fields"
:label="$t('commons.update_time')"
prop="updateTime"
sortable>
<template v-slot="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</ms-table-column>
</ms-table>
<ms-table-pagination :change="initTableData" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
<api-field-template-edit ref="templateEdit" @refresh="initTableData"/>
<ms-delete-confirm ref="deleteConfirm" :title="$t('commons.template_delete')" @delete="_handleDelete"/>
</el-card>
</template>
<script>
import {CUSTOM_FIELD_LIST} from "@/common/js/default-table-header";
import {CASE_TYPE_OPTION} from "@/common/js/table-constants";
import {getCurrentProjectID} from "@/common/js/utils";
import MsTableHeader from "@/business/components/common/components/MsTableHeader";
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import MsTableButton from "@/business/components/common/components/MsTableButton";
import MsTableOperators from "@/business/components/common/components/MsTableOperators";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
import MsTable from "@/business/components/common/components/table/MsTable";
import ApiFieldTemplateEdit from "@/business/components/project/template/ApiFieldTemplateEdit";
import MsDeleteConfirm from "@/business/components/common/components/MsDeleteConfirm";
export default {
name: "ApiTemplateList",
components: {
MsTableHeader,
MsTablePagination,
MsTableButton,
MsTableOperators,
MsTableColumn,
MsTable,
MsDeleteConfirm,
ApiFieldTemplateEdit
},
data() {
return {
tableData: [],
condition: {},
total: 0,
pageSize: 10,
currentPage: 1,
result: {},
caseTypeMap: {
functional: this.$t('api_test.home_page.failed_case_list.table_value.case_type.functional')
},
operators: [
{
tip: this.$t('commons.edit'), icon: "el-icon-edit",
exec: this.handleEdit
}, {
tip: this.$t('commons.copy'), icon: "el-icon-copy-document", type: "success",
exec: this.handleCopy,
isDisable: this.systemDisable
}, {
tip: this.$t('commons.delete'), icon: "el-icon-delete", type: "danger",
exec: this.handleDelete,
isDisable: this.systemDisable
}
],
};
},
created() {
this.initTableData();
},
activated() {
this.initTableData();
},
computed: {
fields() {
return CUSTOM_FIELD_LIST;
},
caseTypeFilters() {
return new CASE_TYPE_OPTION();
},
tableHeight() {
return document.documentElement.clientHeight - 200;
}
},
methods: {
initTableData() {
this.condition.projectId = getCurrentProjectID();
this.result = this.$post('project/field/template/api/list/' + this.currentPage + '/' + this.pageSize,
this.condition, (response) => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
if (this.$refs.table) {
this.$refs.table.reloadTable();
}
});
},
handleEdit(data) {
this.$refs.templateEdit.openEdit(data);
},
handleCreate() {
this.$refs.templateEdit.openEdit();
},
handleCopy(data) {
let copyData = {};
Object.assign(copyData, data);
copyData.name = data.name + '_copy';
this.$refs.templateEdit.openEdit(copyData, true);
},
handleDelete(data) {
this.$refs.deleteConfirm.open(data);
},
_handleDelete(data) {
this.result = this.$get('project/field/template/api/delete/' + data.id, () => {
this.$success(this.$t('commons.delete_success'));
this.initTableData();
});
},
systemDisable(row) {
if (row.system) {
return true;
}
return false;
}
}
};
</script>
<style scoped>
</style>

View File

@ -52,6 +52,9 @@ export default {
if (this.scene === 'ISSUE') {
url = 'field/template/issue/option/';
}
if (this.scene === 'API') {
url = 'project/field/template/api/option/';
}
let projectId = this.projectId || '';
this.$get(url + projectId, (response) => {
this.templateOptions = response.data;

View File

@ -10,6 +10,9 @@
<el-tab-pane :label="$t('workspace.issue_template_manage')" name="issueTemplate" v-if="issueTemplateEnable">
<issues-template-list v-if="activeName === 'issueTemplate'"/>
</el-tab-pane>
<el-tab-pane v-if="apiTemplateEnable" :label="$t('workspace.api_template_manage')" name="apiTemplate">
<api-template-list v-if="activeName === 'apiTemplate'"/>
</el-tab-pane>
</el-tabs>
</el-card>
</template>
@ -19,16 +22,18 @@ import CustomFieldList from "@/business/components/project/template/CustomFieldL
import TestCaseTemplateList from "@/business/components/project/template/TestCaseTemplateList";
import IssuesTemplateList from "@/business/components/project/template/IssuesTemplateList";
import {hasPermissions} from "@/common/js/utils";
import ApiTemplateList from "@/business/components/project/template/ApiTemplateList";
export default {
name: "TemplateSetting",
components: {IssuesTemplateList, TestCaseTemplateList, CustomFieldList},
components: {IssuesTemplateList, TestCaseTemplateList, CustomFieldList, ApiTemplateList},
data() {
return {
activeName: 'field',
fieldEnable: false,
caseTemplateEnable: false,
issueTemplateEnable: false,
apiTemplateEnable: false
};
},
created() {
@ -37,6 +42,10 @@ export default {
methods: {
hasPermissions,
changeTab() {
if (hasPermissions('PROJECT_TEMPLATE:READ+API_TEMPLATE')) {
this.activeName = 'apiTemplate';
this.apiTemplateEnable = true;
}
// 1
if (hasPermissions('PROJECT_TEMPLATE:READ+ISSUE_TEMPLATE')) {
this.activeName = 'issueTemplate';
@ -54,6 +63,7 @@ export default {
this.activeName = 'field';
this.fieldEnable = true;
}
}
}
};

View File

@ -551,8 +551,8 @@ export default {
}
},
closeConfirm(targetName) {
this.activeName = 'default';
if (targetName === 'trash') {
this.activeName = 'default';
this.trashEnable = false;
} else {
this.closeTabWithSave(targetName);

View File

@ -358,7 +358,7 @@ export default {
},
deep: true
},
'testCaseTemplate.customFields': {
customFieldForm: {
handler(val) {
if (val && this.$store.state.testCaseMap && this.form.id) {
let change = this.$store.state.testCaseMap.get(this.form.id);

@ -1 +1 @@
Subproject commit 6c12de172275146ff2bd666ccc93a6f59b95b709
Subproject commit f1e15954ad9a2466bece422fc047e972caee85ce

View File

@ -154,6 +154,24 @@ export function getTemplate(baseUrl, vueObj) {
});
}
export function getApiFieldTemplate(vueObj) {
return new Promise((resolve) => {
let template = {};
let baseUrl = 'project/field/template/api/get-template/relate/';
vueObj.$get(baseUrl + vueObj.projectId, (response) => {
template = response.data;
if (template.customFields) {
template.customFields.forEach(item => {
if (item.options) {
item.options = JSON.parse(item.options);
}
});
}
resolve(template);
});
});
}
// 兼容旧字段
export function buildTestCaseOldFields(testCase) {
let oldFields = new Map();

View File

@ -55,6 +55,7 @@ export const UI_ELEMENT_LOCATION_TYPE_OPTION = [
export const CUSTOM_FIELD_SCENE_OPTION = [
{value: 'TEST_CASE', text: 'workspace.case_template_manage'},
{value: 'ISSUE', text: 'workspace.issue_template_manage'},
{value: 'API', text: 'workspace.api_template_manage'}
];
export function CASE_TYPE_OPTION() {
@ -91,7 +92,8 @@ export const FIELD_TYPE_MAP = {
export const SCENE_MAP = {
ISSUE: 'workspace.issue_template_manage',
TEST_CASE: 'workspace.case_template_manage',
PLAN: 'workstation.table_name.track_plan'
PLAN: 'workstation.table_name.track_plan',
API: 'workspace.api_template_manage'
};
export const SYSTEM_FIELD_NAME_MAP = {

View File

@ -622,6 +622,7 @@ export default {
template_manage: "Template Manage",
case_template_manage: "Case Template",
issue_template_manage: "Issue Template",
api_template_manage: "Api Template",
custom_filed: {
input: 'Input',
textarea: 'Textarea',
@ -2320,7 +2321,10 @@ export default {
table: {
header_display_field: 'Header display field',
fields_to_be_selected: 'Fields to be selected',
selected_fields: 'Selected fields'
selected_fields: 'Selected fields',
base_fields: 'Base fields',
template_name: 'Template name',
selected_custom_fields: 'Custom fields to be selected'
},
run_mode: {
title: "Mode",
@ -2536,6 +2540,7 @@ export default {
read: "READ",
case_template: "CASE TEMPLATE",
issue_template: "ISSUE TEMPLATE",
api_template: "API TEMPLATE",
custom: "CUSTOM FIELDS"
},
workspace_project_manager: {

View File

@ -629,6 +629,7 @@ export default {
template_manage: "模版管理",
case_template_manage: "用例模版",
issue_template_manage: "缺陷模版",
api_template_manage: "接口模版",
custom_filed: {
input: '输入框',
textarea: '文本框',
@ -2329,7 +2330,10 @@ export default {
table: {
header_display_field: '表头显示字段',
fields_to_be_selected: '待选字段',
selected_fields: '已选字段'
selected_fields: '已选字段',
base_fields: '基础字段',
template_name: '模版名称',
selected_custom_fields: '已选自定义字段'
},
run_mode: {
title: "模式",
@ -2545,6 +2549,7 @@ export default {
read: "查询",
case_template: "用例模版",
issue_template: "缺陷模版",
api_template: "接口模版",
custom: "自定义字段"
},
workspace_project_manager: {

View File

@ -625,6 +625,7 @@ export default {
template_manage: "模版管理",
case_template_manage: "用例模版",
issue_template_manage: "缺陷模版",
api_template_manage: "接口模版",
custom_filed: {
input: '輸入框',
textarea: '文本框',
@ -2325,7 +2326,10 @@ export default {
table: {
header_display_field: '表頭顯示字段',
fields_to_be_selected: '待選字段',
selected_fields: '已選字段'
selected_fields: '已選字段',
base_fields: '基礎字段',
template_name: '模版名稱',
selected_custom_fields: '已選自定義字段'
},
run_mode: {
title: "模式",
@ -2541,6 +2545,7 @@ export default {
read: "查詢",
case_template: "用例模版",
issue_template: "缺陷模版",
api_template: "接口模版",
custom: "自定義字段"
},
workspace_project_manager: {

View File

@ -29,3 +29,19 @@ export function getTestTemplate() {
export function updateCustomFieldTemplate(request) {
post('/custom/field/template/update', request);
}
export function getApiTemplate() {
return getTemplate('project/field/template/api/get-template/relate/');
}
export function getApiTemplate() {
return getTemplate('project/field/template/api/get-template/relate/');
}
export function getApiTemplate() {
return getTemplate('project/field/template/api/get-template/relate/');
}

View File

@ -17,6 +17,7 @@ const mutations = {
setIsTestCaseMinderChanged: (state, value) => state.isTestCaseMinderChanged = value,
setCurrentProjectIsCustomNum: (state, value) => state.currentProjectIsCustomNum = value,
setTestCaseTemplate: (state, value) => state.testCaseTemplate = value,
setApiTemplate: (state, value) => state.apiTemplate = value,
setCurTabId: (state, value) => state.curTabId = value,
setTestCaseDefaultValue: (state, value) => state.testCaseDefaultValue = value,
setSelectCommand: (state, value) => state.selectCommand = value,