Merge remote-tracking branch 'origin/master'
# Conflicts: # frontend/src/business/components/api/definition/components/list/ApiCaseSimpleList.vue # frontend/src/business/components/api/definition/components/list/ApiList.vue
This commit is contained in:
commit
252f5f3c10
|
@ -385,6 +385,12 @@
|
|||
<artifactId>kubernetes-client</artifactId>
|
||||
<version>4.13.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.fge</groupId>
|
||||
<artifactId>json-schema-validator</artifactId>
|
||||
<version>2.2.6</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -11,6 +11,7 @@ import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
|||
import io.metersphere.api.service.ApiDefinitionService;
|
||||
import io.metersphere.base.domain.ApiDefinition;
|
||||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.commons.json.JSONSchemaGenerator;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
import io.metersphere.commons.utils.Pager;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
|
@ -158,4 +159,10 @@ public class ApiDefinitionController {
|
|||
public void testPlanRelevance(@RequestBody ApiCaseRelevanceRequest request) {
|
||||
apiDefinitionService.testPlanRelevance(request);
|
||||
}
|
||||
|
||||
@PostMapping("/preview")
|
||||
public String preview(@RequestBody String jsonSchema) {
|
||||
return JSONSchemaGenerator.getJson(jsonSchema);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
package io.metersphere.api.dto.definition;
|
||||
|
||||
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
|
||||
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
|
||||
import io.metersphere.controller.request.OrderRequest;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -32,6 +29,10 @@ public class ApiTestBatchRequest extends ApiTestCaseWithBLOBs {
|
|||
|
||||
private String name;
|
||||
|
||||
private String method;
|
||||
|
||||
private String path;
|
||||
|
||||
private List<String> moduleIds;
|
||||
|
||||
private List<String> unSelectIds;
|
||||
|
@ -39,13 +40,4 @@ public class ApiTestBatchRequest extends ApiTestCaseWithBLOBs {
|
|||
private String protocol;
|
||||
|
||||
private String status;
|
||||
|
||||
public void cleanSelectParam() {
|
||||
filters = new HashMap<>();
|
||||
name = null;
|
||||
moduleIds = new ArrayList<>();
|
||||
protocol = null;
|
||||
status = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.metersphere.api.dto.scenario.request.BodyFile;
|
||||
import io.metersphere.commons.json.JSONSchemaGenerator;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
|
||||
|
@ -17,6 +18,7 @@ public class Body {
|
|||
private String format;
|
||||
private List<KeyValue> kvs;
|
||||
private List<KeyValue> binary;
|
||||
private Object jsonSchema;
|
||||
|
||||
public final static String KV = "KeyValue";
|
||||
public final static String FORM_DATA = "Form Data";
|
||||
|
@ -54,6 +56,10 @@ public class Body {
|
|||
} else {
|
||||
if (!this.isJson()) {
|
||||
sampler.setPostBodyRaw(true);
|
||||
} else {
|
||||
if (StringUtils.isNotEmpty(this.format) && this.format.equals("JSON-SCHEMA") && this.getJsonSchema() != null) {
|
||||
this.raw = JSONSchemaGenerator.getJson(com.alibaba.fastjson.JSON.toJSONString(this.getJsonSchema()));
|
||||
}
|
||||
}
|
||||
KeyValue keyValue = new KeyValue("", this.getRaw());
|
||||
keyValue.setEnable(true);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.jmeter;
|
||||
|
||||
import io.metersphere.api.dto.scenario.request.RequestType;
|
||||
import io.metersphere.api.service.*;
|
||||
import io.metersphere.base.domain.ApiScenarioReport;
|
||||
import io.metersphere.base.domain.ApiTestReport;
|
||||
|
@ -323,7 +324,10 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
if (responseAssertionResult.isPass()) {
|
||||
requestResult.addPassAssertions();
|
||||
}
|
||||
responseResult.getAssertions().add(responseAssertionResult);
|
||||
//xpath 提取错误会添加断言错误
|
||||
if (!responseAssertionResult.getMessage().contains("The required item type of the first operand of")) {
|
||||
responseResult.getAssertions().add(responseAssertionResult);
|
||||
}
|
||||
}
|
||||
responseResult.setConsole(getConsole());
|
||||
|
||||
|
@ -336,7 +340,11 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
String start = "RPC Protocol: ";
|
||||
String end = "://";
|
||||
if (StringUtils.contains(body, start)) {
|
||||
return StringUtils.substringBetween(body, start, end).toUpperCase();
|
||||
String protocol = StringUtils.substringBetween(body, start, end);
|
||||
if (StringUtils.isNotEmpty(protocol)) {
|
||||
return protocol.toUpperCase();
|
||||
}
|
||||
return RequestType.DUBBO;
|
||||
} else {
|
||||
// Http Method
|
||||
String method = StringUtils.substringBefore(body, " ");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.jmeter;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample;
|
||||
import org.apache.jmeter.extractor.JSR223PostProcessor;
|
||||
import org.apache.jmeter.extractor.RegexExtractor;
|
||||
|
@ -30,12 +31,29 @@ public class JMeterVars {
|
|||
* @param vars
|
||||
* @param extract
|
||||
*/
|
||||
public static void addVars(Integer testId, JMeterVariables vars, String extract) {
|
||||
public static void addVars(Integer testId, JMeterVariables vars, String extract) {
|
||||
JMeterVariables vs = new JMeterVariables();
|
||||
|
||||
if (!StringUtils.isEmpty(extract) && vars != null) {
|
||||
List<String> extracts = Arrays.asList(extract.split(";"));
|
||||
Optional.ofNullable(extracts).orElse(new ArrayList<>()).forEach(item -> {
|
||||
|
||||
String nrKey = item + "_matchNr";
|
||||
Object nr = vars.get(nrKey);
|
||||
if (nr != null) {
|
||||
int nrv = 0;
|
||||
try {
|
||||
nrv = Integer.valueOf(String.valueOf(nr));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
if (nrv > 0) {
|
||||
List<Object> data = new ArrayList<>();
|
||||
for (int i = 1; i < nrv + 1; i++) {
|
||||
data.add(vars.get(item + "_" + i));
|
||||
}
|
||||
String array = JSON.toJSONString(data);
|
||||
vars.put(item, array);
|
||||
}
|
||||
}
|
||||
vs.put(item, vars.get(item) == null ? "" : vars.get(item));
|
||||
});
|
||||
vs.remove("TESTSTART.MS"); // 标示变量移除
|
||||
|
|
|
@ -97,8 +97,10 @@ public class Swagger2Parser extends ApiImportAbstractParser {
|
|||
String name = "";
|
||||
if (StringUtils.isNotBlank(operation.getSummary())) {
|
||||
name = operation.getSummary();
|
||||
} else {
|
||||
} else if (StringUtils.isNotBlank(operation.getOperationId())) {
|
||||
name = operation.getOperationId();
|
||||
} else {
|
||||
name = path;
|
||||
}
|
||||
return buildApiDefinition(id, name, path, method);
|
||||
}
|
||||
|
@ -275,6 +277,11 @@ public class Swagger2Parser extends ApiImportAbstractParser {
|
|||
} else if (value instanceof RefProperty) {
|
||||
RefProperty refProperty = (RefProperty) value;
|
||||
String simpleRef = refProperty.getSimpleRef();
|
||||
if (refSet.contains(simpleRef)) {
|
||||
//避免嵌套死循环
|
||||
jsonObject.put(key, new JSONArray());
|
||||
return;
|
||||
}
|
||||
refSet.add(simpleRef);
|
||||
Model model = definitions.get(simpleRef);
|
||||
jsonObject.put(key, getBodyParameters(model.getProperties(), refSet));
|
||||
|
|
|
@ -129,8 +129,10 @@ public class Swagger3Parser extends ApiImportAbstractParser {
|
|||
String name = "";
|
||||
if (StringUtils.isNotBlank(operation.getSummary())) {
|
||||
name = operation.getSummary();
|
||||
} else {
|
||||
} else if (StringUtils.isNotBlank(operation.getOperationId())) {
|
||||
name = operation.getOperationId();
|
||||
} else {
|
||||
name = path;
|
||||
}
|
||||
return buildApiDefinition(id, name, path, method);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import io.metersphere.base.mapper.ext.ExtTestPlanScenarioCaseMapper;
|
|||
import io.metersphere.commons.constants.*;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.DateUtils;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.commons.utils.ServiceUtils;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.i18n.Translator;
|
||||
|
@ -323,8 +324,12 @@ public class ApiAutomationService {
|
|||
boolean isFirst = true;
|
||||
for (ApiScenarioWithBLOBs item : apiScenarios) {
|
||||
if (item.getStepTotal() == 0) {
|
||||
MSException.throwException(item.getName() + "," + Translator.get("automation_exec_info"));
|
||||
break;
|
||||
// 只有一个场景且没有测试步骤,则提示
|
||||
if (apiScenarios.size() == 1) {
|
||||
MSException.throwException((item.getName() + "," + Translator.get("automation_exec_info")));
|
||||
}
|
||||
LogUtil.warn(item.getName() + "," + Translator.get("automation_exec_info"));
|
||||
continue;
|
||||
}
|
||||
MsThreadGroup group = new MsThreadGroup();
|
||||
group.setLabel(item.getName());
|
||||
|
@ -342,14 +347,12 @@ public class ApiAutomationService {
|
|||
// 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取
|
||||
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
|
||||
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
|
||||
new TypeReference<LinkedList<MsTestElement>>() {
|
||||
});
|
||||
new TypeReference<LinkedList<MsTestElement>>() {});
|
||||
scenario.setHashTree(elements);
|
||||
}
|
||||
if (StringUtils.isNotEmpty(element.getString("variables"))) {
|
||||
LinkedList<KeyValue> variables = mapper.readValue(element.getString("variables"),
|
||||
new TypeReference<LinkedList<KeyValue>>() {
|
||||
});
|
||||
new TypeReference<LinkedList<KeyValue>>() {});
|
||||
scenario.setVariables(variables);
|
||||
}
|
||||
group.setEnableCookieShare(scenario.isEnableCookieShare());
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.service;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
|
@ -11,6 +12,8 @@ import io.metersphere.api.dto.definition.request.MsTestElement;
|
|||
import io.metersphere.api.dto.definition.request.MsTestPlan;
|
||||
import io.metersphere.api.dto.definition.request.MsThreadGroup;
|
||||
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
||||
import io.metersphere.api.dto.scenario.request.RequestType;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.ApiDefinitionMapper;
|
||||
|
@ -380,13 +383,33 @@ public class ApiTestCaseService {
|
|||
if (request.isSelectAllDate()) {
|
||||
ids = this.getAllApiCaseIdsByFontedSelect(request.getFilters(), request.getModuleIds(), request.getName(), request.getProjectId(), request.getProtocol(), request.getUnSelectIds(), request.getStatus());
|
||||
}
|
||||
request.cleanSelectParam();
|
||||
ApiTestCaseExample apiDefinitionExample = new ApiTestCaseExample();
|
||||
apiDefinitionExample.createCriteria().andIdIn(ids);
|
||||
ApiTestCaseWithBLOBs apiDefinitionWithBLOBs = new ApiTestCaseWithBLOBs();
|
||||
BeanUtils.copyBean(apiDefinitionWithBLOBs, request);
|
||||
apiDefinitionWithBLOBs.setUpdateTime(System.currentTimeMillis());
|
||||
apiTestCaseMapper.updateByExampleSelective(apiDefinitionWithBLOBs, apiDefinitionExample);
|
||||
if (StringUtils.isNotEmpty(request.getPriority())) {
|
||||
ApiTestCaseWithBLOBs apiDefinitionWithBLOBs = new ApiTestCaseWithBLOBs();
|
||||
apiDefinitionWithBLOBs.setPriority(request.getPriority());
|
||||
apiDefinitionWithBLOBs.setUpdateTime(System.currentTimeMillis());
|
||||
apiTestCaseMapper.updateByExampleSelective(apiDefinitionWithBLOBs, apiDefinitionExample);
|
||||
}
|
||||
if ((StringUtils.isNotEmpty(request.getMethod()) || StringUtils.isNotEmpty(request.getPath())) && request.getProtocol().equals(RequestType.HTTP)) {
|
||||
List<ApiTestCaseWithBLOBs> bloBs = apiTestCaseMapper.selectByExampleWithBLOBs(apiDefinitionExample);
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
ApiTestCaseMapper batchMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
|
||||
bloBs.forEach(apiTestCase -> {
|
||||
MsHTTPSamplerProxy req = JSON.parseObject(apiTestCase.getRequest(), MsHTTPSamplerProxy.class);
|
||||
if (StringUtils.isNotEmpty(request.getMethod())) {
|
||||
req.setMethod(request.getMethod());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(request.getPath())) {
|
||||
req.setPath(request.getPath());
|
||||
}
|
||||
String requestStr = JSON.toJSONString(req);
|
||||
apiTestCase.setRequest(requestStr);
|
||||
batchMapper.updateByPrimaryKeySelective(apiTestCase);
|
||||
});
|
||||
sqlSession.flushStatements();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private List<String> getAllApiCaseIdsByFontedSelect(Map<String, List<String>> filters, List<String> moduleIds, String name, String projectId, String protocol, List<String> unSelectIds, String status) {
|
||||
|
|
|
@ -310,20 +310,9 @@
|
|||
</select>
|
||||
|
||||
<select id="listRelevance" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult">
|
||||
select api_definition.id, api_definition.project_id, api_definition.num,
|
||||
api_definition.name,api_definition.protocol,api_definition.path,api_definition.module_id,api_definition.module_path,api_definition.method,
|
||||
api_definition.description,api_definition.request,api_definition.response,api_definition.environment_id,
|
||||
api_definition.status, api_definition.user_id, api_definition.create_time, api_definition.update_time
|
||||
select
|
||||
<include refid="io.metersphere.base.mapper.ApiDefinitionMapper.Base_Column_List"/>
|
||||
from api_definition
|
||||
inner join
|
||||
api_test_case c
|
||||
on c.api_definition_id = api_definition.id
|
||||
and not exists (
|
||||
select id
|
||||
from test_plan_api_case t
|
||||
where t.api_case_id = c.id
|
||||
and t.test_plan_id = #{request.planId}
|
||||
)
|
||||
<where>
|
||||
<if test="request.combine != null">
|
||||
<include refid="combine">
|
||||
|
@ -359,6 +348,17 @@
|
|||
#{value}
|
||||
</foreach>
|
||||
</if>
|
||||
and exists (
|
||||
select id
|
||||
from api_test_case c
|
||||
where c.api_definition_id = api_definition.id
|
||||
and not exists (
|
||||
select id
|
||||
from test_plan_api_case t
|
||||
where t.api_case_id = c.id
|
||||
and t.test_plan_id = #{request.planId}
|
||||
)
|
||||
)
|
||||
</where>
|
||||
<if test="request.orders != null and request.orders.size() > 0">
|
||||
order by
|
||||
|
|
|
@ -15,4 +15,6 @@ public interface ExtTestPlanApiCaseMapper {
|
|||
List<String> getExecResultByPlanId(String planId);
|
||||
|
||||
List<String> getIdsByPlanId(String planId);
|
||||
|
||||
List<String> getNotRelevanceCaseIds(@Param("planId")String planId, @Param("relevanceProjectIds")List<String> relevanceProjectIds);
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
<select id="list" resultType="io.metersphere.api.dto.definition.TestPlanApiCaseDTO">
|
||||
select
|
||||
t.id, t.environment_id, t.create_time, t.update_time,
|
||||
c.id as case_id, c.project_id, c.name, c.api_definition_id, c.priority, c.description, c.create_user_id, c.update_user_id,
|
||||
c.id as case_id, c.project_id, c.name, c.api_definition_id, c.priority, c.description, c.create_user_id, c.update_user_id, c.num,
|
||||
a.module_id, a.path, a.protocol, t.status execResult
|
||||
from
|
||||
test_plan_api_case t
|
||||
|
@ -90,17 +90,31 @@
|
|||
</foreach>
|
||||
</if>
|
||||
</select>
|
||||
<select id="getExecResultByPlanId" resultType="java.lang.String">
|
||||
select status
|
||||
from
|
||||
test_plan_api_case
|
||||
where test_plan_id = #{planId}
|
||||
</select>
|
||||
<select id="getExecResultByPlanId" resultType="java.lang.String">
|
||||
select status
|
||||
from
|
||||
test_plan_api_case
|
||||
where test_plan_id = #{planId}
|
||||
</select>
|
||||
|
||||
<select id="getIdsByPlanId" resultType="java.lang.String">
|
||||
select id from
|
||||
from test_plan_api_case
|
||||
where id = #{planId}
|
||||
</select>
|
||||
<select id="getIdsByPlanId" resultType="java.lang.String">
|
||||
select id
|
||||
from test_plan_api_case
|
||||
where id = #{planId}
|
||||
</select>
|
||||
|
||||
<select id="getNotRelevanceCaseIds" resultType="java.lang.String">
|
||||
select t.id
|
||||
from test_plan_api_case t
|
||||
inner join api_test_case c
|
||||
on c.id = t.api_case_id
|
||||
<if test="relevanceProjectIds != null and relevanceProjectIds.size() > 0">
|
||||
and c.project_id not in
|
||||
<foreach collection="relevanceProjectIds" item="projectId" separator="," open="(" close=")">
|
||||
#{projectId}
|
||||
</foreach>
|
||||
</if>
|
||||
where t.test_plan_id = #{planId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -21,4 +21,6 @@ public interface ExtTestPlanScenarioCaseMapper {
|
|||
List<String> getExecResultByPlanId(String planId);
|
||||
|
||||
List<String> getIdsByPlanId(String planId);
|
||||
|
||||
List<String> getNotRelevanceCaseIds(String planId, List<String> relevanceProjectIds);
|
||||
}
|
|
@ -92,4 +92,18 @@
|
|||
where test_plan_id = #{planId}
|
||||
</select>
|
||||
|
||||
<select id="getNotRelevanceCaseIds" resultType="java.lang.String">
|
||||
select t.id
|
||||
from test_plan_api_scenario t
|
||||
inner join api_scenario c
|
||||
on c.id = t.api_scenario_id
|
||||
<if test="relevanceProjectIds != null and relevanceProjectIds.size() > 0">
|
||||
and c.project_id not in
|
||||
<foreach collection="relevanceProjectIds" item="projectId" separator="," open="(" close=")">
|
||||
#{projectId}
|
||||
</foreach>
|
||||
</if>
|
||||
where t.test_plan_id = #{planId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -88,28 +88,22 @@ public interface ParamConstants {
|
|||
}
|
||||
}
|
||||
|
||||
enum MAIL {
|
||||
SERVER("smtp.server", 1),
|
||||
PORT("smtp.port", 2),
|
||||
ACCOUNT("smtp.account", 3),
|
||||
PASSWORD("smtp.password", 4),
|
||||
SSL("smtp.ssl", 5),
|
||||
TLS("smtp.tls", 6),
|
||||
ANON("smtp.anon", 7);
|
||||
enum MAIL implements ParamConstants{
|
||||
SERVER("smtp.host"),
|
||||
PORT("smtp.port"),
|
||||
ACCOUNT("smtp.account"),
|
||||
PASSWORD("smtp.password"),
|
||||
SSL("smtp.ssl"),
|
||||
TLS("smtp.tls"),
|
||||
RECIPIENTS("smtp.recipient");
|
||||
|
||||
private String key;
|
||||
private Integer value;
|
||||
private String value;
|
||||
|
||||
private MAIL(String key, Integer value) {
|
||||
this.key = key;
|
||||
private MAIL(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,310 @@
|
|||
package io.metersphere.commons.json;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.github.fge.jackson.JsonLoader;
|
||||
import com.github.fge.jsonschema.cfg.ValidationConfiguration;
|
||||
import com.github.fge.jsonschema.core.report.ProcessingReport;
|
||||
import com.github.fge.jsonschema.processors.syntax.SyntaxValidator;
|
||||
import com.google.gson.*;
|
||||
import io.metersphere.commons.utils.ScriptEngineUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class JSONSchemaGenerator {
|
||||
|
||||
private static void generator(String json, JSONObject obj) {
|
||||
analyzeSchema(json, obj);
|
||||
}
|
||||
|
||||
private static void analyzeSchema(String json, JSONObject rootObj) {
|
||||
// Let's start with the root element of the file
|
||||
JsonObject rootElement = null;
|
||||
try {
|
||||
JsonParser jsonParser = new JsonParser();
|
||||
JsonElement inputElement = jsonParser.parse(json);
|
||||
rootElement = inputElement.getAsJsonObject();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
analyzeRootSchemaElement(rootElement, rootObj);
|
||||
}
|
||||
|
||||
private static void analyzeRootSchemaElement(JsonObject rootElement, JSONObject rootObj) {
|
||||
if (rootElement.has("type") || rootElement.has("allOf")) {
|
||||
analyzeObject(rootElement, rootObj);
|
||||
}
|
||||
|
||||
if (rootElement.has("definitions")) {
|
||||
// Section 9 in json-validation
|
||||
analyzeDefinitions(rootElement);
|
||||
}
|
||||
}
|
||||
|
||||
private static void analyzeObject(JsonObject object, JSONObject rootObj) {
|
||||
// Creating the concept
|
||||
|
||||
if (object.has("title")) {
|
||||
// 暂不处理,后续使用时再加
|
||||
String title = object.get("title").getAsString();
|
||||
}
|
||||
|
||||
if (object.has("description")) {
|
||||
// 暂不处理,后续使用时再加
|
||||
String description = object.get("description").getAsString();
|
||||
}
|
||||
|
||||
if (object.has("allOf")) {
|
||||
JsonArray allOfArray = object.get("allOf").getAsJsonArray();
|
||||
for (JsonElement allOfElement : allOfArray) {
|
||||
JsonObject allOfElementObj = allOfElement.getAsJsonObject();
|
||||
if (allOfElementObj.has("$ref")) {
|
||||
// 暂不处理,后续使用时再加
|
||||
String ref = allOfElementObj.get("$ref").getAsString();
|
||||
} else if (allOfElementObj.has("properties")) {
|
||||
// Properties elements will become the attributes/references of the element
|
||||
JsonObject propertiesObj = allOfElementObj.get("properties").getAsJsonObject();
|
||||
for (Entry<String, JsonElement> entry : propertiesObj.entrySet()) {
|
||||
String propertyKey = entry.getKey();
|
||||
JsonObject propertyObj = propertiesObj.get(propertyKey).getAsJsonObject();
|
||||
analyzeProperty(rootObj, propertyKey, propertyObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (object.has("oneOf")) {
|
||||
// 暂不处理,后续使用时再加
|
||||
} else if (object.has("properties")) {
|
||||
JsonObject propertiesObj = object.get("properties").getAsJsonObject();
|
||||
for (Entry<String, JsonElement> entry : propertiesObj.entrySet()) {
|
||||
String propertyKey = entry.getKey();
|
||||
JsonObject propertyObj = propertiesObj.get(propertyKey).getAsJsonObject();
|
||||
analyzeProperty(rootObj, propertyKey, propertyObj);
|
||||
}
|
||||
} else if (object.has("type") && !object.get("type").getAsString().equals("object")) {
|
||||
analyzeProperty(rootObj, object.getAsString(), object);
|
||||
}
|
||||
|
||||
if (object.has("required")) {
|
||||
// 必选项暂不处理,后续使用时再加
|
||||
}
|
||||
}
|
||||
|
||||
private static void analyzeProperty(JSONObject concept, String propertyName, JsonObject object) {
|
||||
if (object.has("type")) {
|
||||
String propertyObjType = null;
|
||||
if (object.get("type") instanceof JsonPrimitive) {
|
||||
propertyObjType = object.get("type").getAsString();
|
||||
} else if (object.get("type") instanceof JsonArray) {
|
||||
JsonArray typeArray = (JsonArray) object.get("type").getAsJsonArray();
|
||||
propertyObjType = typeArray.get(0).getAsString();
|
||||
if (typeArray.size() > 1) {
|
||||
if (typeArray.get(1).getAsString().equals("null")) {
|
||||
// 暂不处理,后续使用时再加
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (object.has("enum")) {
|
||||
concept.put(propertyName, analyzeEnumProperty(object));
|
||||
} else if (propertyObjType.equals("string")) {
|
||||
// 先设置空值
|
||||
concept.put(propertyName, null);
|
||||
if (object.has("format")) {
|
||||
String propertyFormat = object.get("format").getAsString();
|
||||
if (propertyFormat.equals("date-time")) {
|
||||
|
||||
}
|
||||
}
|
||||
if (object.has("default")) {
|
||||
concept.put(propertyName, object.get("default"));
|
||||
}
|
||||
if (object.has("mock") && object.get("mock").getAsJsonObject() != null && StringUtils.isNotEmpty(object.get("mock").getAsJsonObject().get("mock").getAsString()) && StringUtils.isNotEmpty(object.get("mock").getAsJsonObject().get("mock").getAsString())) {
|
||||
String value = ScriptEngineUtils.calculate(object.get("mock").getAsJsonObject().get("mock").getAsString());
|
||||
concept.put(propertyName, value);
|
||||
}
|
||||
if (object.has("maxLength")) {
|
||||
|
||||
}
|
||||
// Section 6.3.1 in json-schema-validation. Resolved as OCL
|
||||
|
||||
if (object.has("minLength")) {
|
||||
|
||||
}
|
||||
// Section 6.3.2 in json-schema-validation. Resolved as OCL
|
||||
|
||||
if (object.has("pattern")) {
|
||||
// Section 6.3.3 in json-schema-validation. Resolved as OCL, possible?
|
||||
// TODO 6.3.3 in json-schema-validation
|
||||
}
|
||||
|
||||
} else if (propertyObjType.equals("integer") || propertyObjType.equals("number")) {
|
||||
// 先设置空值
|
||||
concept.put(propertyName, 0);
|
||||
if (object.has("default")) {
|
||||
concept.put(propertyName, object.get("default"));
|
||||
}
|
||||
if (object.has("mock") && object.get("mock").getAsJsonObject() != null && StringUtils.isNotEmpty(object.get("mock").getAsJsonObject().get("mock").getAsString())) {
|
||||
String value = ScriptEngineUtils.calculate(object.get("mock").getAsJsonObject().get("mock").toString());
|
||||
concept.put(propertyName, value);
|
||||
}
|
||||
if (object.has("multipleOf")) {
|
||||
|
||||
}
|
||||
// Section 6.2.1 in json-schema-validation. Resolved as OCL
|
||||
|
||||
if (object.has("maximum")) {
|
||||
|
||||
}
|
||||
// Section 6.2.2 in json-schema-validation. Resolved as OCL
|
||||
|
||||
if (object.has("exclusiveMaximum")) {
|
||||
|
||||
}
|
||||
// Section 6.2.3 in json-schema-validation. Resolved as OCL
|
||||
|
||||
if (object.has("minimum")) {
|
||||
|
||||
}
|
||||
// Section 6.2.4 in json-schema-validation. Resolved as OCL
|
||||
|
||||
if (object.has("exclusiveMinimum")) {
|
||||
|
||||
}
|
||||
// Section 6.2.5 in json-schema-validation. Resolved as OCL
|
||||
|
||||
} else if (propertyObjType.equals("boolean")) {
|
||||
// 先设置空值
|
||||
concept.put(propertyName, false);
|
||||
if (object.has("default")) {
|
||||
concept.put(propertyName, object.get("default"));
|
||||
}
|
||||
if (object.has("mock") && object.get("mock").getAsJsonObject() != null && StringUtils.isNotEmpty(object.get("mock").getAsJsonObject().get("mock").getAsString())) {
|
||||
String value = ScriptEngineUtils.calculate(object.get("mock").getAsJsonObject().get("mock").toString());
|
||||
concept.put(propertyName, value);
|
||||
}
|
||||
} else if (propertyObjType.equals("array")) {
|
||||
// 先设置空值
|
||||
List<Object> array = new LinkedList<>();
|
||||
|
||||
JsonObject itemsObject = null;
|
||||
if (object.has("items") && object.get("items").isJsonArray()) {
|
||||
itemsObject = object.get("items").getAsJsonArray().get(0).getAsJsonObject();
|
||||
} else {
|
||||
itemsObject = object.get("items").getAsJsonObject();
|
||||
}
|
||||
|
||||
if (object.has("items")) {
|
||||
if (itemsObject.has("enum")) {
|
||||
array.add(analyzeEnumProperty(object));
|
||||
} else if (itemsObject.has("type") && itemsObject.get("type").getAsString().equals("string")) {
|
||||
if (object.has("default")) {
|
||||
array.add(object.get("default"));
|
||||
} else if (object.has("mock") && object.get("mock").getAsJsonObject() != null && StringUtils.isNotEmpty(object.get("mock").getAsJsonObject().get("mock").getAsString())) {
|
||||
String value = ScriptEngineUtils.calculate(object.get("mock").getAsJsonObject().get("mock").toString());
|
||||
array.add(object.get(value));
|
||||
} else {
|
||||
array.add(null);
|
||||
}
|
||||
} else if (itemsObject.has("type") && itemsObject.get("type").getAsString().equals("number")) {
|
||||
if (object.has("default")) {
|
||||
array.add(object.get("default"));
|
||||
} else if (object.has("mock") && object.get("mock").getAsJsonObject() != null && StringUtils.isNotEmpty(object.get("mock").getAsJsonObject().get("mock").getAsString())) {
|
||||
String value = ScriptEngineUtils.calculate(object.get("mock").getAsJsonObject().get("mock").toString());
|
||||
array.add(object.get(value));
|
||||
} else {
|
||||
array.add(0);
|
||||
}
|
||||
} else if (itemsObject.has("oneOf")) {
|
||||
|
||||
} else if (itemsObject.has("anyOf")) {
|
||||
|
||||
} else if (itemsObject.has("allOf")) {
|
||||
// TODO
|
||||
} else if (itemsObject.has("properties")) {
|
||||
JSONObject propertyConcept = new JSONObject();
|
||||
JsonObject propertiesObj = itemsObject.get("properties").getAsJsonObject();
|
||||
for (Entry<String, JsonElement> entry : propertiesObj.entrySet()) {
|
||||
String propertyKey = entry.getKey();
|
||||
JsonObject propertyObj = propertiesObj.get(propertyKey).getAsJsonObject();
|
||||
analyzeProperty(propertyConcept, propertyKey, propertyObj);
|
||||
}
|
||||
array.add(propertyConcept);
|
||||
|
||||
} else if (itemsObject.has("$ref")) {
|
||||
analyzeRef(concept, propertyName, itemsObject);
|
||||
}
|
||||
} else if (object.has("items") && object.get("items").isJsonArray()) {
|
||||
JsonArray itemsObjectArray = object.get("items").getAsJsonArray();
|
||||
array.add(itemsObjectArray);
|
||||
}
|
||||
|
||||
concept.put(propertyName, array);
|
||||
|
||||
} else if (propertyObjType.equals("object")) {
|
||||
JSONObject obj = new JSONObject();
|
||||
concept.put(propertyName, obj);
|
||||
analyzeObject(object, obj);
|
||||
}
|
||||
} else if (object.has("$ref")) {
|
||||
analyzeRef(concept, propertyName, object);
|
||||
} else if (object.has("oneOf")) {
|
||||
// Section 6.7.3 in json-schema-validation
|
||||
|
||||
} else if (object.has("anyOf")) {
|
||||
// Section 6.7.2 in json-schema-validation
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Object> analyzeEnumProperty(JsonObject object) {
|
||||
JsonArray enumValues = object.get("enum").getAsJsonArray();
|
||||
List<Object> list = new LinkedList<>();
|
||||
for (JsonElement enumValueElem : enumValues) {
|
||||
String enumValue = enumValueElem.getAsString();
|
||||
list.add(enumValue);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static void analyzeRef(JSONObject concept, String propertyName, JsonObject object) {
|
||||
String ref = object.get("$ref").getAsString();
|
||||
}
|
||||
|
||||
private static void analyzeDefinitions(JsonObject object) {
|
||||
JsonObject definitionsObj = object.get("definitions").getAsJsonObject();
|
||||
for (Entry<String, JsonElement> entry : definitionsObj.entrySet()) {
|
||||
String definitionKey = entry.getKey();
|
||||
JsonObject definitionObj = definitionsObj.get(definitionKey).getAsJsonObject();
|
||||
JSONObject obj = new JSONObject();
|
||||
analyzeRootSchemaElement(definitionObj, obj);
|
||||
}
|
||||
}
|
||||
|
||||
private static final SyntaxValidator VALIDATOR = new SyntaxValidator(ValidationConfiguration.byDefault());
|
||||
|
||||
public static String getJson(String jsonSchema) {
|
||||
if (StringUtils.isEmpty(jsonSchema)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JsonNode jsonNode = JsonLoader.fromString(jsonSchema);
|
||||
ProcessingReport report = VALIDATOR.validateSchema(jsonNode);
|
||||
if (report.isSuccess()) {
|
||||
JSONObject root = new JSONObject();
|
||||
generator(jsonSchema, root);
|
||||
// 格式化返回
|
||||
Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
|
||||
return gson.toJson(root);
|
||||
} else {
|
||||
return report.getExceptionThreshold().toString();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
return ex.getMessage();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import io.metersphere.commons.constants.ParamConstants;
|
|||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.dto.BaseSystemConfigDTO;
|
||||
import io.metersphere.ldap.domain.LdapInfo;
|
||||
import io.metersphere.notice.domain.MailInfo;
|
||||
import io.metersphere.service.SystemParameterService;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
@ -38,7 +39,7 @@ public class SystemParameterController {
|
|||
|
||||
@GetMapping("/mail/info")
|
||||
@RequiresRoles(value = {RoleConstants.ADMIN})
|
||||
public Object mailInfo() {
|
||||
public MailInfo mailInfo() {
|
||||
return SystemParameterService.mailInfo(ParamConstants.Classify.MAIL.getValue());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package io.metersphere.notice.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MailInfo {
|
||||
private String host;
|
||||
private String port;
|
||||
private String account;
|
||||
private String password;
|
||||
private String ssl;
|
||||
private String tls;
|
||||
private String recipient;
|
||||
|
||||
}
|
|
@ -11,15 +11,18 @@ import io.metersphere.commons.utils.LogUtil;
|
|||
import io.metersphere.dto.BaseSystemConfigDTO;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.ldap.domain.LdapInfo;
|
||||
import io.metersphere.notice.domain.MailInfo;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
|
@ -56,7 +59,7 @@ public class SystemParameterService {
|
|||
|
||||
parameters.forEach(parameter -> {
|
||||
SystemParameterExample example = new SystemParameterExample();
|
||||
if (parameter.getParamKey().equals(ParamConstants.MAIL.PASSWORD.getKey())) {
|
||||
if (parameter.getParamKey().equals(ParamConstants.MAIL.PASSWORD.getValue())) {
|
||||
if (!StringUtils.isBlank(parameter.getParamValue())) {
|
||||
String string = EncryptUtils.aesEncrypt(parameter.getParamValue()).toString();
|
||||
parameter.setParamValue(string);
|
||||
|
@ -82,23 +85,16 @@ public class SystemParameterService {
|
|||
public void testConnection(HashMap<String, String> hashMap) {
|
||||
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
|
||||
javaMailSender.setDefaultEncoding("UTF-8");
|
||||
javaMailSender.setHost(hashMap.get(ParamConstants.MAIL.SERVER.getKey()));
|
||||
javaMailSender.setPort(Integer.valueOf(hashMap.get(ParamConstants.MAIL.PORT.getKey())));
|
||||
javaMailSender.setUsername(hashMap.get(ParamConstants.MAIL.ACCOUNT.getKey()));
|
||||
javaMailSender.setPassword(hashMap.get(ParamConstants.MAIL.PASSWORD.getKey()));
|
||||
javaMailSender.setHost(hashMap.get(ParamConstants.MAIL.SERVER.getValue()));
|
||||
javaMailSender.setPort(Integer.valueOf(hashMap.get(ParamConstants.MAIL.PORT.getValue())));
|
||||
javaMailSender.setUsername(hashMap.get(ParamConstants.MAIL.ACCOUNT.getValue()));
|
||||
javaMailSender.setPassword(hashMap.get(ParamConstants.MAIL.PASSWORD.getValue()));
|
||||
Properties props = new Properties();
|
||||
boolean isAnon = Boolean.parseBoolean(hashMap.get(ParamConstants.MAIL.ANON.getKey()));
|
||||
if (isAnon) {
|
||||
props.put("mail.smtp.auth", "false");
|
||||
javaMailSender.setUsername(null);
|
||||
javaMailSender.setPassword(null);
|
||||
} else {
|
||||
props.put("mail.smtp.auth", "true");
|
||||
}
|
||||
if (BooleanUtils.toBoolean(hashMap.get(ParamConstants.MAIL.SSL.getKey()))) {
|
||||
String recipients = hashMap.get(ParamConstants.MAIL.RECIPIENTS.getValue());
|
||||
if (BooleanUtils.toBoolean(hashMap.get(ParamConstants.MAIL.SSL.getValue()))) {
|
||||
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
|
||||
}
|
||||
if (BooleanUtils.toBoolean(hashMap.get(ParamConstants.MAIL.TLS.getKey()))) {
|
||||
if (BooleanUtils.toBoolean(hashMap.get(ParamConstants.MAIL.TLS.getValue()))) {
|
||||
props.put("mail.smtp.starttls.enable", "true");
|
||||
}
|
||||
props.put("mail.smtp.timeout", "30000");
|
||||
|
@ -110,39 +106,53 @@ public class SystemParameterService {
|
|||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException(Translator.get("connection_failed"));
|
||||
}
|
||||
if(!StringUtils.isBlank(recipients)){
|
||||
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
|
||||
MimeMessageHelper helper = null;
|
||||
try {
|
||||
helper = new MimeMessageHelper(mimeMessage, true);
|
||||
helper.setFrom(javaMailSender.getUsername());
|
||||
helper.setSubject("MeterSphere测试邮件 " );
|
||||
helper.setText("这是一封测试邮件,邮件发送成功", true);
|
||||
helper.setTo(recipients);
|
||||
javaMailSender.send(mimeMessage);
|
||||
} catch (MessagingException e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException(Translator.get("connection_failed"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return System.getenv("MS_VERSION");
|
||||
}
|
||||
|
||||
public Object mailInfo(String type) {
|
||||
public MailInfo mailInfo(String type) {
|
||||
List<SystemParameter> paramList = this.getParamList(type);
|
||||
if (CollectionUtils.isEmpty(paramList)) {
|
||||
paramList = new ArrayList<>();
|
||||
ParamConstants.MAIL[] values = ParamConstants.MAIL.values();
|
||||
for (ParamConstants.MAIL value : values) {
|
||||
SystemParameter systemParameter = new SystemParameter();
|
||||
if (value.equals(ParamConstants.MAIL.PASSWORD)) {
|
||||
systemParameter.setType(ParamConstants.Type.PASSWORD.getValue());
|
||||
} else {
|
||||
systemParameter.setType(ParamConstants.Type.TEXT.getValue());
|
||||
MailInfo mailInfo=new MailInfo ();
|
||||
if (!CollectionUtils.isEmpty(paramList)) {
|
||||
for (SystemParameter param : paramList) {
|
||||
if (StringUtils.equals(param.getParamKey(),ParamConstants.MAIL.SERVER.getValue() )) {
|
||||
mailInfo.setHost(param.getParamValue());
|
||||
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.PORT.getValue())) {
|
||||
mailInfo.setPort(param.getParamValue());
|
||||
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.ACCOUNT.getValue())) {
|
||||
mailInfo.setAccount(param.getParamValue());
|
||||
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.PASSWORD.getValue())) {
|
||||
String password = EncryptUtils.aesDecrypt(param.getParamValue()).toString();
|
||||
mailInfo.setPassword(password);
|
||||
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.SSL.getValue())) {
|
||||
mailInfo.setSsl(param.getParamValue());
|
||||
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.TLS.getValue())) {
|
||||
mailInfo.setTls(param.getParamValue());
|
||||
} else if (StringUtils.equals(param.getParamKey(), ParamConstants.MAIL.RECIPIENTS.getValue())) {
|
||||
mailInfo.setRecipient(param.getParamValue());
|
||||
}
|
||||
systemParameter.setParamKey(value.getKey());
|
||||
systemParameter.setSort(value.getValue());
|
||||
paramList.add(systemParameter);
|
||||
}
|
||||
} else {
|
||||
paramList.stream().filter(param -> param.getParamKey().equals(ParamConstants.MAIL.PASSWORD.getKey())).forEach(param -> {
|
||||
if (!StringUtils.isBlank(param.getParamValue())) {
|
||||
String string = EncryptUtils.aesDecrypt(param.getParamValue()).toString();
|
||||
param.setParamValue(string);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
paramList.sort(Comparator.comparingInt(SystemParameter::getSort));
|
||||
return paramList;
|
||||
return mailInfo;
|
||||
}
|
||||
|
||||
public void saveLdap(List<SystemParameter> parameters) {
|
||||
|
|
|
@ -46,11 +46,11 @@ public class TestPlanController {
|
|||
|
||||
/*jenkins测试计划*/
|
||||
@GetMapping("/list/all/{projectId}/{workspaceId}")
|
||||
public List<TestPlanDTO> listByProjectId(@PathVariable String projectId, @PathVariable String workspaceId) {
|
||||
public List<TestPlanDTOWithMetric> listByProjectId(@PathVariable String projectId, @PathVariable String workspaceId) {
|
||||
QueryTestPlanRequest request = new QueryTestPlanRequest();
|
||||
request.setWorkspaceId(workspaceId);
|
||||
request.setProjectId(projectId);
|
||||
return testPlanService.listTestPlanByProject(request);
|
||||
return testPlanService.listTestPlan(request);
|
||||
}
|
||||
|
||||
@PostMapping("/list/all")
|
||||
|
|
|
@ -77,6 +77,9 @@ public class TestPlanApiCaseService {
|
|||
}
|
||||
|
||||
public void deleteApiCaseBath(TestPlanApiCaseBatchRequest request) {
|
||||
if (CollectionUtils.isEmpty(request.getIds())) {
|
||||
return;
|
||||
}
|
||||
apiDefinitionExecResultService.deleteByResourceIds(request.getIds());
|
||||
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
|
||||
example.createCriteria()
|
||||
|
@ -97,4 +100,11 @@ public class TestPlanApiCaseService {
|
|||
apiCase.setStatus(status);
|
||||
testPlanApiCaseMapper.updateByPrimaryKeySelective(apiCase);
|
||||
}
|
||||
|
||||
public void deleteByRelevanceProjectIds(String planId, List<String> relevanceProjectIds) {
|
||||
TestPlanApiCaseBatchRequest request = new TestPlanApiCaseBatchRequest();
|
||||
request.setPlanId(planId);
|
||||
request.setIds(extTestPlanApiCaseMapper.getNotRelevanceCaseIds(planId, relevanceProjectIds));
|
||||
deleteApiCaseBath(request);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,9 @@ public class TestPlanScenarioCaseService {
|
|||
}
|
||||
|
||||
public void deleteApiCaseBath(TestPlanApiCaseBatchRequest request) {
|
||||
if (CollectionUtils.isEmpty(request.getIds())) {
|
||||
return;
|
||||
}
|
||||
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
|
||||
example.createCriteria()
|
||||
.andIdIn(request.getIds());
|
||||
|
@ -110,4 +113,11 @@ public class TestPlanScenarioCaseService {
|
|||
request.setIds(ids);
|
||||
deleteApiCaseBath(request);
|
||||
}
|
||||
|
||||
public void deleteByRelevanceProjectIds(String planId, List<String> relevanceProjectIds) {
|
||||
TestPlanApiCaseBatchRequest request = new TestPlanApiCaseBatchRequest();
|
||||
request.setIds(extTestPlanScenarioCaseMapper.getNotRelevanceCaseIds(planId, relevanceProjectIds));
|
||||
request.setPlanId(planId);
|
||||
deleteApiCaseBath(request);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import io.metersphere.api.dto.definition.ApiTestCaseRequest;
|
|||
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.*;
|
||||
import io.metersphere.base.mapper.ext.ExtProjectMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtTestPlanMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
|
||||
|
@ -27,7 +26,6 @@ import io.metersphere.notice.service.NoticeSendService;
|
|||
import io.metersphere.service.SystemParameterService;
|
||||
import io.metersphere.track.Factory.ReportComponentFactory;
|
||||
import io.metersphere.track.domain.ReportComponent;
|
||||
|
||||
import io.metersphere.track.dto.TestCaseReportMetricDTO;
|
||||
import io.metersphere.track.dto.TestPlanCaseDTO;
|
||||
import io.metersphere.track.dto.TestPlanDTO;
|
||||
|
@ -70,8 +68,6 @@ public class TestPlanService {
|
|||
@Resource
|
||||
TestPlanTestCaseService testPlanTestCaseService;
|
||||
@Resource
|
||||
ExtProjectMapper extProjectMapper;
|
||||
@Resource
|
||||
TestCaseReportMapper testCaseReportMapper;
|
||||
@Resource
|
||||
TestPlanProjectMapper testPlanProjectMapper;
|
||||
|
@ -230,6 +226,14 @@ public class TestPlanService {
|
|||
criteria.andCaseIdNotIn(caseIds);
|
||||
}
|
||||
testPlanTestCaseMapper.deleteByExample(testPlanTestCaseExample);
|
||||
|
||||
List<String> relevanceProjectIds = new ArrayList<>();
|
||||
relevanceProjectIds.add(testPlan.getProjectId());
|
||||
if (!CollectionUtils.isEmpty(testPlan.getProjectIds())) {
|
||||
relevanceProjectIds.addAll(testPlan.getProjectIds());
|
||||
}
|
||||
testPlanApiCaseService.deleteByRelevanceProjectIds(testPlan.getId(), relevanceProjectIds);
|
||||
testPlanScenarioCaseService.deleteByRelevanceProjectIds(testPlan.getId(), relevanceProjectIds);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@ public class TestPlanTestCaseService {
|
|||
}
|
||||
public List<TestPlanCaseDTO> listByPlanId(QueryTestPlanCaseRequest request) {
|
||||
List<TestPlanCaseDTO> list = extTestPlanTestCaseMapper.listByPlanId(request);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,9 +21,12 @@
|
|||
"echarts": "^4.6.0",
|
||||
"el-table-infinite-scroll": "^1.0.10",
|
||||
"element-ui": "^2.13.0",
|
||||
"generate-schema": "^2.6.0",
|
||||
"html2canvas": "^1.0.0-rc.7",
|
||||
"js-base64": "^3.4.4",
|
||||
"json-bigint": "^1.0.0",
|
||||
"json-schema-faker": "^0.5.0-rcv.32",
|
||||
"json5": "^2.1.3",
|
||||
"jsoneditor": "^9.1.2",
|
||||
"jspdf": "^2.1.1",
|
||||
"md5": "^2.3.0",
|
||||
|
|
|
@ -108,7 +108,7 @@ export default {
|
|||
tableData: [],
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
loading: false,
|
||||
currentProjectId: "",
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
<ms-dubbo-basis-parameters :request="request" v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'|| request.type==='DubboSampler'"/>
|
||||
|
||||
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
|
||||
<ms-request-result-tail :response="request.requestResult" ref="runResult"/>
|
||||
<ms-request-result-tail :currentProtocol="request.protocol" :response="request.requestResult" ref="runResult"/>
|
||||
|
||||
<!-- 保存操作 -->
|
||||
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)" v-if="!request.referenced">
|
||||
|
|
|
@ -623,12 +623,19 @@
|
|||
this.$refs.tag.open();
|
||||
},
|
||||
remove(row, node) {
|
||||
const parent = node.parent
|
||||
const hashTree = parent.data.hashTree || parent.data;
|
||||
const index = hashTree.findIndex(d => d.resourceId != undefined && row.resourceId != undefined && d.resourceId === row.resourceId)
|
||||
hashTree.splice(index, 1);
|
||||
this.sort();
|
||||
this.reload();
|
||||
this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + row.name + " ?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
const parent = node.parent
|
||||
const hashTree = parent.data.hashTree || parent.data;
|
||||
const index = hashTree.findIndex(d => d.resourceId != undefined && row.resourceId != undefined && d.resourceId === row.resourceId)
|
||||
hashTree.splice(index, 1);
|
||||
this.sort();
|
||||
this.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
,
|
||||
copyRow(row, node) {
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
ref="codeEdit"/>
|
||||
</el-col>
|
||||
<el-col :span="4" class="script-index">
|
||||
<ms-dropdown :default-command="jsr223ProcessorData.language" :commands="languages" @command="languageChange"/>
|
||||
<ms-dropdown :default-command="jsr223ProcessorData.scriptLanguage" :commands="languages" @command="languageChange"/>
|
||||
<div class="template-title">{{$t('api_test.request.processor.code_template')}}</div>
|
||||
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
|
||||
<el-link :disabled="template.disabled" @click="addTemplate(template)">{{template.title}}</el-link>
|
||||
|
@ -135,7 +135,7 @@
|
|||
this.jsr223ProcessorData.script = "";
|
||||
}
|
||||
this.jsr223ProcessorData.script += template.value;
|
||||
if (this.jsr223ProcessorData.language === 'beanshell') {
|
||||
if (this.jsr223ProcessorData.scriptLanguage === 'beanshell') {
|
||||
this.jsr223ProcessorData.script += ';';
|
||||
}
|
||||
this.reload();
|
||||
|
@ -151,7 +151,7 @@
|
|||
this.$nextTick(() => (this.isCodeEditAlive = true));
|
||||
},
|
||||
languageChange(language) {
|
||||
this.jsr223ProcessorData.language = language;
|
||||
this.jsr223ProcessorData.scriptLanguage = language;
|
||||
},
|
||||
changeActive() {
|
||||
this.jsr223ProcessorData.active = !this.jsr223ProcessorData.active;
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
:is-api-list-enable="isApiListEnable"
|
||||
@isApiListEnableChange="isApiListEnableChange">
|
||||
|
||||
<ms-environment-select :project-id="projectId" v-if="isTestPlan" :is-read-only="isReadOnly" @setEnvironment="setEnvironment"/>
|
||||
<ms-environment-select :project-id="projectId" v-if="isTestPlan" :is-read-only="isReadOnly" @setEnvironment="setEnvironment"/>
|
||||
|
||||
<el-input placeholder="搜索" @blur="initTable" class="search-input" size="small" @keyup.enter.native="initTable" v-model="condition.name"/>
|
||||
|
||||
<el-input placeholder="搜索" @blur="initTable" class="search-input" size="small" @keyup.enter.native="initTable" v-model="condition.name"/>
|
||||
|
||||
<el-table v-loading="result.loading"
|
||||
border
|
||||
|
@ -253,8 +254,8 @@
|
|||
|
||||
.search-input {
|
||||
float: right;
|
||||
width: 300px;
|
||||
/*margin-bottom: 20px;*/
|
||||
width: 30%;
|
||||
margin-bottom: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div style="min-width: 1200px;margin-bottom: 20px">
|
||||
<span class="kv-description" v-if="description">
|
||||
{{ description }}
|
||||
</span>
|
||||
|
|
|
@ -90,193 +90,194 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {calculate, Scenario} from "../model/ApiTestModel";
|
||||
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
|
||||
import {calculate, Scenario} from "../model/ApiTestModel";
|
||||
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
|
||||
|
||||
export default {
|
||||
name: "MsApiVariableAdvance",
|
||||
props: {
|
||||
parameters: Array,
|
||||
environment: Object,
|
||||
scenario: Scenario,
|
||||
currentItem: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
itemValueVisible: false,
|
||||
filterText: '',
|
||||
environmentParams: [],
|
||||
scenarioParams: [],
|
||||
preRequests: [],
|
||||
preRequestParams: [],
|
||||
treeProps: {children: 'children', label: 'name'},
|
||||
currentTab: 0,
|
||||
itemValue: null,
|
||||
itemValuePreview: null,
|
||||
funcs: [
|
||||
{name: "md5"},
|
||||
{name: "base64"},
|
||||
{name: "unbase64"},
|
||||
{
|
||||
name: "substr",
|
||||
params: [{name: "start"}, {name: "length"}]
|
||||
},
|
||||
{
|
||||
name: "concat",
|
||||
params: [{name: "suffix"}]
|
||||
},
|
||||
{name: "lconcat", params: [{name: "prefix"}]},
|
||||
{name: "sha1"},
|
||||
{name: "sha224"},
|
||||
{name: "sha256"},
|
||||
{name: "sha384"},
|
||||
{name: "sha512"},
|
||||
{name: "lower"},
|
||||
{name: "upper"},
|
||||
{name: "length"},
|
||||
{name: "number"}
|
||||
],
|
||||
mockFuncs: MOCKJS_FUNC.map(f => {
|
||||
return {name: f.name, value: f.name}
|
||||
}),
|
||||
jmeterFuncs: JMETER_FUNC,
|
||||
mockVariableFuncs: [],
|
||||
jmeterVariableFuncs: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
valueText() {
|
||||
return this.valuePlaceholder || this.$t("api_test.value");
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.prepareData();
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.tree.filter(val);
|
||||
export default {
|
||||
name: "MsApiVariableAdvance",
|
||||
props: {
|
||||
parameters: Array,
|
||||
environment: Object,
|
||||
scenario: Scenario,
|
||||
currentItem: Object,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.itemValueVisible = true;
|
||||
},
|
||||
prepareData() {
|
||||
if (this.scenario) {
|
||||
let variables = this.scenario.variables;
|
||||
this.scenarioParams = [
|
||||
data() {
|
||||
return {
|
||||
itemValueVisible: false,
|
||||
filterText: '',
|
||||
environmentParams: [],
|
||||
scenarioParams: [],
|
||||
preRequests: [],
|
||||
preRequestParams: [],
|
||||
treeProps: {children: 'children', label: 'name'},
|
||||
currentTab: 0,
|
||||
itemValue: null,
|
||||
itemValuePreview: null,
|
||||
funcs: [
|
||||
{name: "md5"},
|
||||
{name: "base64"},
|
||||
{name: "unbase64"},
|
||||
{
|
||||
name: this.scenario.name,
|
||||
children: variables.filter(v => v.name).map(v => {
|
||||
return {name: v.name, value: '${' + v.name + '}'}
|
||||
}),
|
||||
}
|
||||
];
|
||||
if (this.environment) {
|
||||
let variables = this.environment.config.commonConfig.variables;
|
||||
this.environmentParams = [
|
||||
name: "substr",
|
||||
params: [{name: "start"}, {name: "length"}]
|
||||
},
|
||||
{
|
||||
name: "concat",
|
||||
params: [{name: "suffix"}]
|
||||
},
|
||||
{name: "lconcat", params: [{name: "prefix"}]},
|
||||
{name: "sha1"},
|
||||
{name: "sha224"},
|
||||
{name: "sha256"},
|
||||
{name: "sha384"},
|
||||
{name: "sha512"},
|
||||
{name: "lower"},
|
||||
{name: "upper"},
|
||||
{name: "length"},
|
||||
{name: "number"}
|
||||
],
|
||||
mockFuncs: MOCKJS_FUNC.map(f => {
|
||||
return {name: f.name, value: f.name}
|
||||
}),
|
||||
jmeterFuncs: JMETER_FUNC,
|
||||
mockVariableFuncs: [],
|
||||
jmeterVariableFuncs: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
valueText() {
|
||||
return this.valuePlaceholder || this.$t("api_test.value");
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.prepareData();
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.tree.filter(val);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.itemValueVisible = true;
|
||||
},
|
||||
prepareData() {
|
||||
if (this.scenario) {
|
||||
let variables = this.scenario.variables;
|
||||
this.scenarioParams = [
|
||||
{
|
||||
name: this.environment.name,
|
||||
name: this.scenario.name,
|
||||
children: variables.filter(v => v.name).map(v => {
|
||||
return {name: v.name, value: '${' + v.name + '}'}
|
||||
}),
|
||||
}
|
||||
];
|
||||
if (this.environment) {
|
||||
let variables = this.environment.config.commonConfig.variables;
|
||||
this.environmentParams = [
|
||||
{
|
||||
name: this.environment.name,
|
||||
children: variables.filter(v => v.name).map(v => {
|
||||
return {name: v.name, value: '${' + v.name + '}'}
|
||||
}),
|
||||
}
|
||||
];
|
||||
}
|
||||
let i = this.scenario.requests.indexOf(this.request);
|
||||
this.preRequests = this.scenario.requests.slice(0, i);
|
||||
this.preRequests.forEach(r => {
|
||||
let js = r.extract.json.map(v => {
|
||||
return {name: v.variable, value: v.value}
|
||||
});
|
||||
let xs = r.extract.xpath.map(v => {
|
||||
return {name: v.variable, value: v.value}
|
||||
});
|
||||
let rx = r.extract.regex.map(v => {
|
||||
return {name: v.variable, value: v.value}
|
||||
});
|
||||
let vs = [...js, ...xs, ...rx];
|
||||
if (vs.length > 0) {
|
||||
this.preRequestParams.push({name: r.name, children: vs});
|
||||
}
|
||||
});
|
||||
}
|
||||
let i = this.scenario.requests.indexOf(this.request);
|
||||
this.preRequests = this.scenario.requests.slice(0, i);
|
||||
this.preRequests.forEach(r => {
|
||||
let js = r.extract.json.map(v => {
|
||||
return {name: v.variable, value: v.value}
|
||||
});
|
||||
let xs = r.extract.xpath.map(v => {
|
||||
return {name: v.variable, value: v.value}
|
||||
});
|
||||
let rx = r.extract.regex.map(v => {
|
||||
return {name: v.variable, value: v.value}
|
||||
});
|
||||
let vs = [...js, ...xs, ...rx];
|
||||
if (vs.length > 0) {
|
||||
this.preRequestParams.push({name: r.name, children: vs});
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data.name.indexOf(value) !== -1;
|
||||
},
|
||||
selectVariable(node) {
|
||||
this.itemValue = node.value;
|
||||
},
|
||||
selectTab(tab) {
|
||||
this.currentTab = +tab.index;
|
||||
this.itemValue = null;
|
||||
this.itemValuePreview = null;
|
||||
},
|
||||
showPreview() {
|
||||
// 找到变量本身
|
||||
if (!this.itemValue) {
|
||||
return;
|
||||
}
|
||||
let index = this.itemValue.indexOf("|");
|
||||
if (index > -1) {
|
||||
this.itemValue = this.itemValue.substring(0, index).trim();
|
||||
}
|
||||
|
||||
this.mockVariableFuncs.forEach(f => {
|
||||
if (!f.name) {
|
||||
return;
|
||||
}
|
||||
this.itemValue += "|" + f.name;
|
||||
if (f.params) {
|
||||
this.itemValue += ":" + f.params.map(p => p.value).join(",");
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data.name.indexOf(value) !== -1;
|
||||
},
|
||||
selectVariable(node) {
|
||||
this.itemValue = node.value;
|
||||
},
|
||||
selectTab(tab) {
|
||||
this.currentTab = +tab.index;
|
||||
this.itemValue = null;
|
||||
this.itemValuePreview = null;
|
||||
},
|
||||
showPreview() {
|
||||
// 找到变量本身
|
||||
if (!this.itemValue) {
|
||||
return;
|
||||
}
|
||||
let index = this.itemValue.indexOf("|");
|
||||
if (index > -1) {
|
||||
this.itemValue = this.itemValue.substring(0, index).trim();
|
||||
}
|
||||
|
||||
this.mockVariableFuncs.forEach(f => {
|
||||
if (!f.name) {
|
||||
this.itemValuePreview = calculate(this.itemValue);
|
||||
},
|
||||
methodChange(itemFunc, func) {
|
||||
let index = this.mockVariableFuncs.indexOf(itemFunc);
|
||||
this.mockVariableFuncs = this.mockVariableFuncs.slice(0, index);
|
||||
// 这里要用 deep copy
|
||||
this.mockVariableFuncs.push(JSON.parse(JSON.stringify(func)));
|
||||
this.showPreview();
|
||||
},
|
||||
addFunc() {
|
||||
if (this.mockVariableFuncs.length > 4) {
|
||||
this.$info(this.$t('api_test.request.parameters_advance_add_func_limit'));
|
||||
return;
|
||||
}
|
||||
this.itemValue += "|" + f.name;
|
||||
if (f.params) {
|
||||
this.itemValue += ":" + f.params.map(p => p.value).join(",");
|
||||
}
|
||||
});
|
||||
|
||||
this.itemValuePreview = calculate(this.itemValue);
|
||||
},
|
||||
methodChange(itemFunc, func) {
|
||||
let index = this.mockVariableFuncs.indexOf(itemFunc);
|
||||
this.mockVariableFuncs = this.mockVariableFuncs.slice(0, index);
|
||||
// 这里要用 deep copy
|
||||
this.mockVariableFuncs.push(JSON.parse(JSON.stringify(func)));
|
||||
this.showPreview();
|
||||
},
|
||||
addFunc() {
|
||||
if (this.mockVariableFuncs.length > 4) {
|
||||
this.$info(this.$t('api_test.request.parameters_advance_add_func_limit'));
|
||||
return;
|
||||
}
|
||||
if (this.mockVariableFuncs.length > 0) {
|
||||
let func = this.mockVariableFuncs[this.mockVariableFuncs.length - 1];
|
||||
if (!func.name) {
|
||||
this.$warning(this.$t('api_test.request.parameters_advance_add_func_error'));
|
||||
return;
|
||||
}
|
||||
if (func.params) {
|
||||
for (let j = 0; j < func.params.length; j++) {
|
||||
if (!func.params[j].value) {
|
||||
this.$warning(this.$t('api_test.request.parameters_advance_add_param_error'));
|
||||
return;
|
||||
if (this.mockVariableFuncs.length > 0) {
|
||||
let func = this.mockVariableFuncs[this.mockVariableFuncs.length - 1];
|
||||
if (!func.name) {
|
||||
this.$warning(this.$t('api_test.request.parameters_advance_add_func_error'));
|
||||
return;
|
||||
}
|
||||
if (func.params) {
|
||||
for (let j = 0; j < func.params.length; j++) {
|
||||
if (!func.params[j].value) {
|
||||
this.$warning(this.$t('api_test.request.parameters_advance_add_param_error'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.mockVariableFuncs.push({name: '', params: []});
|
||||
},
|
||||
saveAdvanced() {
|
||||
this.currentItem.value = this.itemValue;
|
||||
this.itemValueVisible = false;
|
||||
this.mockVariableFuncs = [];
|
||||
this.$emit('advancedRefresh', this.itemValue);
|
||||
}
|
||||
this.mockVariableFuncs.push({name: '', params: []});
|
||||
},
|
||||
saveAdvanced() {
|
||||
this.currentItem.value = this.itemValue;
|
||||
this.itemValueVisible = false;
|
||||
this.mockVariableFuncs = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.col-height {
|
||||
height: 40vh;
|
||||
overflow: auto;
|
||||
}
|
||||
.col-height {
|
||||
height: 40vh;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -14,7 +14,10 @@
|
|||
<el-option v-for="(type, index) in typeArr" :key="index" :value="type.id" :label="type.name"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('test_track.case.updated_attr_value')" prop="value">
|
||||
<el-form-item v-if="form.type ==='path'" :label="$t('test_track.case.updated_attr_value')" prop="value">
|
||||
<el-input size="small" v-model="form.value"/>
|
||||
</el-form-item>
|
||||
<el-form-item v-else :label="$t('test_track.case.updated_attr_value')" prop="value">
|
||||
<el-select v-model="form.value" style="width: 80%" :filterable="filterable">
|
||||
<el-option v-for="(option, index) in options" :key="index" :value="option.id" :label="option.label">
|
||||
<div v-if="option.email">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div style="min-width: 1200px;margin-bottom: 20px">
|
||||
<div>
|
||||
<el-radio-group v-model="body.type" size="mini">
|
||||
<el-radio :disabled="isReadOnly" :label="type.FORM_DATA" @change="modeChange">
|
||||
{{ $t('api_test.definition.request.body_form_data') }}
|
||||
|
@ -40,8 +40,12 @@
|
|||
type="body"
|
||||
v-if="body.type == 'WWW_FORM'"/>
|
||||
|
||||
<div class="ms-body" v-if="body.type == 'JSON'">
|
||||
<ms-json-code-edit @json-change="jsonChange" @onError="jsonError" :value="body.raw" ref="jsonCodeEdit"/>
|
||||
<div v-if="body.type == 'JSON'">
|
||||
<div style="padding: 10px">
|
||||
<el-switch active-text="JSON-SCHEMA" v-model="body.format" active-value="JSON-SCHEMA"/>
|
||||
</div>
|
||||
<ms-json-code-edit v-if="body.format==='JSON-SCHEMA'" :body="body" ref="jsonCodeEdit"/>
|
||||
<ms-code-edit v-else :read-only="isReadOnly" height="400px" :data.sync="body.raw" :modes="modes" :mode="'json'" ref="codeEdit"/>
|
||||
</div>
|
||||
|
||||
<div class="ms-body" v-if="body.type == 'XML'">
|
||||
|
@ -67,7 +71,7 @@
|
|||
import MsApiKeyValue from "../ApiKeyValue";
|
||||
import {BODY_TYPE, KeyValue} from "../../model/ApiTestModel";
|
||||
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
|
||||
import MsJsonCodeEdit from "../../../../common/components/MsJsonCodeEdit";
|
||||
import MsJsonCodeEdit from "../../../../common/json-schema/JsonSchemaEditor";
|
||||
import MsDropdown from "../../../../common/components/MsDropdown";
|
||||
import MsApiVariable from "../ApiVariable";
|
||||
import MsApiBinaryVariable from "./ApiBinaryVariable";
|
||||
|
@ -101,10 +105,10 @@
|
|||
data() {
|
||||
return {
|
||||
type: BODY_TYPE,
|
||||
modes: ['text', 'json', 'xml', 'html']
|
||||
modes: ['text', 'json', 'xml', 'html'],
|
||||
jsonSchema: "JSON",
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
modeChange(mode) {
|
||||
switch (this.body.type) {
|
||||
|
@ -148,12 +152,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
jsonChange(json) {
|
||||
this.body.raw = JSON.stringify(json);
|
||||
},
|
||||
jsonError(e) {
|
||||
this.$error(e);
|
||||
},
|
||||
batchAdd() {
|
||||
this.$refs.batchAddParameter.open();
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div style="min-width: 1200px;margin-bottom: 20px">
|
||||
<span class="kv-description" v-if="description">
|
||||
{{ description }}
|
||||
</span>
|
||||
|
|
|
@ -140,10 +140,18 @@
|
|||
methods: {
|
||||
|
||||
deleteCase(index, row) {
|
||||
this.$get('/api/testcase/delete/' + row.id, () => {
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
this.$emit('refresh');
|
||||
this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + row.name + " ?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
this.$get('/api/testcase/delete/' + row.id, () => {
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
this.$emit('refresh');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
singleRun(data) {
|
||||
this.$emit('singleRun', data);
|
||||
|
|
|
@ -43,7 +43,8 @@
|
|||
<el-option :key="0" :value="''">
|
||||
<div style="margin-left: 40px">
|
||||
<span style="font-size: 14px;color: #606266;font-weight: 48.93">{{$t('api_test.definition.select_comp.no_data')}},
|
||||
</span><el-link type="primary" @click="createModules">{{$t('api_test.definition.select_comp.add_data')}}</el-link>
|
||||
</span>
|
||||
<el-link type="primary" @click="createModules">{{$t('api_test.definition.select_comp.add_data')}}</el-link>
|
||||
</div>
|
||||
</el-option>
|
||||
</div>
|
||||
|
@ -106,7 +107,6 @@
|
|||
import {REQ_METHOD, API_STATUS} from "../../model/JsonData";
|
||||
import MsJsr233Processor from "../processor/Jsr233Processor";
|
||||
import {KeyValue} from "../../model/ApiTestModel";
|
||||
// import {append} from "./../../../../track/common/NodeTree";
|
||||
|
||||
export default {
|
||||
name: "MsAddCompleteHttpApi",
|
||||
|
@ -172,7 +172,7 @@
|
|||
}
|
||||
})
|
||||
},
|
||||
createModules(){
|
||||
createModules() {
|
||||
this.$emit("createRootModelInTree");
|
||||
},
|
||||
getPath(id) {
|
||||
|
@ -185,7 +185,7 @@
|
|||
return path[0].path;
|
||||
},
|
||||
urlChange() {
|
||||
if (!this.httpForm.path) return;
|
||||
if (!this.httpForm.path || this.httpForm.path.indexOf('?') === -1) return;
|
||||
let url = this.getURL(this.addProtocol(this.httpForm.path));
|
||||
if (url) {
|
||||
this.httpForm.path = decodeURIComponent("/" + url.hostname + url.pathname);
|
||||
|
@ -202,7 +202,6 @@
|
|||
getURL(urlStr) {
|
||||
try {
|
||||
let url = new URL(urlStr);
|
||||
console.log(urlStr)
|
||||
url.searchParams.forEach((value, key) => {
|
||||
if (key && value) {
|
||||
this.request.arguments.splice(0, 0, new KeyValue({name: key, required: false, value: value}));
|
||||
|
|
|
@ -15,7 +15,7 @@ export default class JSR223PostProcessor extends PostProcessor {
|
|||
constructor(options = DEFAULT_OPTIONS) {
|
||||
super(options);
|
||||
this.type = "JSR223PostProcessor";
|
||||
this.scriptLanguage = "java";
|
||||
this.scriptLanguage = "beanshell";
|
||||
this.parameters = [];
|
||||
this.filename = undefined;
|
||||
this.cacheKey = true;
|
||||
|
|
|
@ -15,7 +15,7 @@ export default class JSR223PreProcessor extends PostProcessor {
|
|||
constructor(options = DEFAULT_OPTIONS) {
|
||||
super(options);
|
||||
this.type = "JSR223PreProcessor";
|
||||
this.scriptLanguage = "java";
|
||||
this.scriptLanguage = "beanshell";
|
||||
this.parameters = [];
|
||||
this.filename = undefined;
|
||||
this.cacheKey = undefined;
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
:is-api-list-enable="isApiListEnable"
|
||||
@isApiListEnableChange="isApiListEnableChange">
|
||||
|
||||
<el-input placeholder="搜索" @blur="search" @keyup.enter.native="search" class="search-input" size="small"
|
||||
v-model="condition.name"/>
|
||||
<el-input placeholder="搜索" @blur="search" @keyup.enter.native="search" class="search-input" size="small" v-model="condition.name"/>
|
||||
|
||||
<el-table v-loading="result.loading"
|
||||
ref="caseTable"
|
||||
|
@ -23,10 +22,10 @@
|
|||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item @click.native.stop="isSelectDataAll(true)">
|
||||
{{ $t('api_test.batch_menus.select_all_data', [total]) }}
|
||||
{{$t('api_test.batch_menus.select_all_data',[total])}}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click.native.stop="isSelectDataAll(false)">
|
||||
{{ $t('api_test.batch_menus.select_show_data', [tableData.length]) }}
|
||||
{{$t('api_test.batch_menus.select_show_data',[tableData.length])}}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
|
@ -73,10 +72,8 @@
|
|||
<el-table-column v-if="!isReadOnly" :label="$t('commons.operating')" min-width="130" align="center">
|
||||
<template v-slot:default="scope">
|
||||
<!--<el-button type="text" @click="reductionApi(scope.row)" v-if="trashEnable">{{$t('commons.reduction')}}</el-button>-->
|
||||
<el-button type="text" @click="handleTestCase(scope.row)" v-if="!trashEnable">{{ $t('commons.edit') }}
|
||||
</el-button>
|
||||
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">{{ $t('commons.delete') }}
|
||||
</el-button>
|
||||
<el-button type="text" @click="handleTestCase(scope.row)" v-if="!trashEnable">{{$t('commons.edit')}}</el-button>
|
||||
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">{{$t('commons.delete')}}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
@ -94,153 +91,154 @@
|
|||
|
||||
<script>
|
||||
|
||||
import MsTableOperator from "../../../../common/components/MsTableOperator";
|
||||
import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton";
|
||||
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
||||
import MsTablePagination from "../../../../common/pagination/TablePagination";
|
||||
import MsTag from "../../../../common/components/MsTag";
|
||||
import MsApiCaseList from "../case/ApiCaseList";
|
||||
import MsContainer from "../../../../common/components/MsContainer";
|
||||
import MsBottomContainer from "../BottomContainer";
|
||||
import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn";
|
||||
import MsBatchEdit from "../basis/BatchEdit";
|
||||
import {API_METHOD_COLOUR, CASE_PRIORITY} from "../../model/JsonData";
|
||||
import {getCurrentProjectID} from "@/common/js/utils";
|
||||
import ApiListContainer from "./ApiListContainer";
|
||||
import PriorityTableItem from "../../../../track/common/tableItems/planview/PriorityTableItem";
|
||||
import ApiCaseList from "../case/ApiCaseList";
|
||||
import {_filter, _sort} from "../../../../../../common/js/utils";
|
||||
import TestPlanCaseListHeader from "../../../../track/plan/view/comonents/api/TestPlanCaseListHeader";
|
||||
import MsEnvironmentSelect from "../case/MsEnvironmentSelect";
|
||||
import {_handleSelect, _handleSelectAll} from "../../../../../../common/js/tableUtils";
|
||||
import MsTableOperator from "../../../../common/components/MsTableOperator";
|
||||
import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton";
|
||||
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
||||
import MsTablePagination from "../../../../common/pagination/TablePagination";
|
||||
import MsTag from "../../../../common/components/MsTag";
|
||||
import MsApiCaseList from "../case/ApiCaseList";
|
||||
import MsContainer from "../../../../common/components/MsContainer";
|
||||
import MsBottomContainer from "../BottomContainer";
|
||||
import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn";
|
||||
import MsBatchEdit from "../basis/BatchEdit";
|
||||
import {API_METHOD_COLOUR, CASE_PRIORITY, REQ_METHOD} from "../../model/JsonData";
|
||||
import {getCurrentProjectID} from "@/common/js/utils";
|
||||
import ApiListContainer from "./ApiListContainer";
|
||||
import PriorityTableItem from "../../../../track/common/tableItems/planview/PriorityTableItem";
|
||||
import ApiCaseList from "../case/ApiCaseList";
|
||||
import {_filter, _sort} from "../../../../../../common/js/utils";
|
||||
import {_handleSelect, _handleSelectAll} from "../../../../../../common/js/tableUtils";
|
||||
|
||||
export default {
|
||||
name: "ApiCaseSimpleList",
|
||||
components: {
|
||||
ApiCaseList,
|
||||
PriorityTableItem,
|
||||
ApiListContainer,
|
||||
MsTableOperatorButton,
|
||||
MsTableOperator,
|
||||
MsTablePagination,
|
||||
MsTag,
|
||||
MsApiCaseList,
|
||||
MsContainer,
|
||||
MsBottomContainer,
|
||||
ShowMoreBtn,
|
||||
MsBatchEdit
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
condition: {},
|
||||
selectCase: {},
|
||||
result: {},
|
||||
moduleId: "",
|
||||
selectDataRange: "all",
|
||||
deletePath: "/test/case/delete",
|
||||
selectRows: new Set(),
|
||||
buttons: [
|
||||
{name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteBatch},
|
||||
{name: this.$t('api_test.definition.request.batch_edit'), handleClick: this.handleEditBatch}
|
||||
],
|
||||
typeArr: [
|
||||
{id: 'priority', name: this.$t('test_track.case.priority')},
|
||||
],
|
||||
priorityFilters: [
|
||||
{text: 'P0', value: 'P0'},
|
||||
{text: 'P1', value: 'P1'},
|
||||
{text: 'P2', value: 'P2'},
|
||||
{text: 'P3', value: 'P3'}
|
||||
],
|
||||
valueArr: {
|
||||
priority: CASE_PRIORITY,
|
||||
},
|
||||
methodColorMap: new Map(API_METHOD_COLOUR),
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
screenHeight: document.documentElement.clientHeight - 330,//屏幕高度
|
||||
environmentId: undefined,
|
||||
selectAll: false,
|
||||
unSelection: [],
|
||||
selectDataCounts: 0,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
currentProtocol: String,
|
||||
selectNodeIds: Array,
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
export default {
|
||||
name: "ApiCaseSimpleList",
|
||||
components: {
|
||||
ApiCaseList,
|
||||
PriorityTableItem,
|
||||
ApiListContainer,
|
||||
MsTableOperatorButton,
|
||||
MsTableOperator,
|
||||
MsTablePagination,
|
||||
MsTag,
|
||||
MsApiCaseList,
|
||||
MsContainer,
|
||||
MsBottomContainer,
|
||||
ShowMoreBtn,
|
||||
MsBatchEdit
|
||||
},
|
||||
trashEnable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isApiListEnable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isCaseRelevance: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
relevanceProjectId: String,
|
||||
model: {
|
||||
type: String,
|
||||
default() {
|
||||
'api'
|
||||
data() {
|
||||
return {
|
||||
condition: {},
|
||||
selectCase: {},
|
||||
result: {},
|
||||
moduleId: "",
|
||||
selectDataRange: "all",
|
||||
deletePath: "/test/case/delete",
|
||||
selectRows: new Set(),
|
||||
buttons: [
|
||||
{name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteBatch},
|
||||
{name: this.$t('api_test.definition.request.batch_edit'), handleClick: this.handleEditBatch}
|
||||
],
|
||||
typeArr: [
|
||||
{id: 'priority', name: this.$t('test_track.case.priority')},
|
||||
{id: 'method', name: this.$t('api_test.definition.api_type')},
|
||||
{id: 'path', name: this.$t('api_test.request.path')},
|
||||
],
|
||||
priorityFilters: [
|
||||
{text: 'P0', value: 'P0'},
|
||||
{text: 'P1', value: 'P1'},
|
||||
{text: 'P2', value: 'P2'},
|
||||
{text: 'P3', value: 'P3'}
|
||||
],
|
||||
valueArr: {
|
||||
priority: CASE_PRIORITY,
|
||||
method: REQ_METHOD,
|
||||
},
|
||||
methodColorMap: new Map(API_METHOD_COLOUR),
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
screenHeight: document.documentElement.clientHeight - 330,//屏幕高度
|
||||
environmentId: undefined,
|
||||
selectAll: false,
|
||||
unSelection: [],
|
||||
selectDataCounts: 0,
|
||||
}
|
||||
},
|
||||
planId: String
|
||||
},
|
||||
created: function () {
|
||||
this.initTable();
|
||||
},
|
||||
watch: {
|
||||
selectNodeIds() {
|
||||
props: {
|
||||
currentProtocol: String,
|
||||
selectNodeIds: Array,
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
trashEnable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isApiListEnable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isCaseRelevance: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
relevanceProjectId: String,
|
||||
model: {
|
||||
type: String,
|
||||
default() {
|
||||
'api'
|
||||
}
|
||||
},
|
||||
planId: String
|
||||
},
|
||||
created: function () {
|
||||
this.initTable();
|
||||
},
|
||||
currentProtocol() {
|
||||
this.initTable();
|
||||
},
|
||||
trashEnable() {
|
||||
if (this.trashEnable) {
|
||||
watch: {
|
||||
selectNodeIds() {
|
||||
this.initTable();
|
||||
},
|
||||
currentProtocol() {
|
||||
this.initTable();
|
||||
},
|
||||
trashEnable() {
|
||||
if (this.trashEnable) {
|
||||
this.initTable();
|
||||
}
|
||||
},
|
||||
relevanceProjectId() {
|
||||
this.initTable();
|
||||
}
|
||||
},
|
||||
relevanceProjectId() {
|
||||
this.initTable();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
computed: {
|
||||
|
||||
// 接口定义用例列表
|
||||
isApiModel() {
|
||||
return this.model === 'api'
|
||||
// 接口定义用例列表
|
||||
isApiModel() {
|
||||
return this.model === 'api'
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isApiListEnableChange(data) {
|
||||
this.$emit('isApiListEnableChange', data);
|
||||
},
|
||||
initTable() {
|
||||
this.selectRows = new Set();
|
||||
this.condition.status = "";
|
||||
this.condition.moduleIds = this.selectNodeIds;
|
||||
if (this.trashEnable) {
|
||||
this.condition.status = "Trash";
|
||||
this.condition.moduleIds = [];
|
||||
}
|
||||
this.selectAll = false;
|
||||
this.unSelection = [];
|
||||
this.selectDataCounts = 0;
|
||||
this.condition.projectId = getCurrentProjectID();
|
||||
methods: {
|
||||
isApiListEnableChange(data) {
|
||||
this.$emit('isApiListEnableChange', data);
|
||||
},
|
||||
initTable() {
|
||||
this.selectRows = new Set();
|
||||
this.condition.status = "";
|
||||
this.condition.moduleIds = this.selectNodeIds;
|
||||
if (this.trashEnable) {
|
||||
this.condition.status = "Trash";
|
||||
this.condition.moduleIds = [];
|
||||
}
|
||||
this.selectAll = false;
|
||||
this.unSelection = [];
|
||||
this.selectDataCounts = 0;
|
||||
this.condition.projectId = getCurrentProjectID();
|
||||
|
||||
if (this.currentProtocol != null) {
|
||||
this.condition.protocol = this.currentProtocol;
|
||||
|
@ -306,170 +304,169 @@ export default {
|
|||
return path + "/" + this.currentPage + "/" + this.pageSize;
|
||||
},
|
||||
|
||||
handleTestCase(testCase) {
|
||||
this.$get('/api/definition/get/' + testCase.apiDefinitionId, (response) => {
|
||||
let api = response.data;
|
||||
let selectApi = api;
|
||||
let request = {};
|
||||
if (Object.prototype.toString.call(api.request).match(/\[object (\w+)\]/)[1].toLowerCase() === 'object') {
|
||||
request = api.request;
|
||||
} else {
|
||||
request = JSON.parse(api.request);
|
||||
}
|
||||
if (!request.hashTree) {
|
||||
request.hashTree = [];
|
||||
}
|
||||
selectApi.url = request.path;
|
||||
this.$refs.caseList.open(selectApi, testCase.id);
|
||||
});
|
||||
},
|
||||
reductionApi(row) {
|
||||
let ids = [row.id];
|
||||
this.$post('/api/testcase/reduction/', ids, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.search();
|
||||
});
|
||||
},
|
||||
handleDeleteBatch() {
|
||||
// if (this.trashEnable) {
|
||||
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
let obj = {};
|
||||
obj.projectId = getCurrentProjectID();
|
||||
obj.selectAllDate = this.isSelectAllDate;
|
||||
obj.unSelectIds = this.unSelection;
|
||||
obj.ids = Array.from(this.selectRows).map(row => row.id);
|
||||
obj = Object.assign(obj, this.condition);
|
||||
this.$post('/api/testcase/deleteBatchByParam/', obj, () => {
|
||||
this.selectRows.clear();
|
||||
this.initTable();
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
});
|
||||
handleTestCase(testCase) {
|
||||
this.$get('/api/definition/get/' + testCase.apiDefinitionId, (response) => {
|
||||
let api = response.data;
|
||||
let selectApi = api;
|
||||
let request = {};
|
||||
if (Object.prototype.toString.call(api.request).match(/\[object (\w+)\]/)[1].toLowerCase() === 'object') {
|
||||
request = api.request;
|
||||
} else {
|
||||
request = JSON.parse(api.request);
|
||||
}
|
||||
if (!request.hashTree) {
|
||||
request.hashTree = [];
|
||||
}
|
||||
selectApi.url = request.path;
|
||||
this.$refs.caseList.open(selectApi, testCase.id);
|
||||
});
|
||||
},
|
||||
reductionApi(row) {
|
||||
let ids = [row.id];
|
||||
this.$post('/api/testcase/reduction/', ids, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.search();
|
||||
});
|
||||
},
|
||||
handleDeleteBatch() {
|
||||
// if (this.trashEnable) {
|
||||
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
let obj = {};
|
||||
obj.projectId = getCurrentProjectID();
|
||||
obj.selectAllDate = this.isSelectAllDate;
|
||||
obj.unSelectIds = this.unSelection;
|
||||
obj.ids = Array.from(this.selectRows).map(row => row.id);
|
||||
obj = Object.assign(obj, this.condition);
|
||||
this.$post('/api/testcase/deleteBatchByParam/', obj, () => {
|
||||
this.selectRows.clear();
|
||||
this.initTable();
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// } else {
|
||||
// this.$alert(this.$t('api_test.definition.request.delete_confirm') + "?", '', {
|
||||
// confirmButtonText: this.$t('commons.confirm'),
|
||||
// callback: (action) => {
|
||||
// if (action === 'confirm') {
|
||||
// let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
// this.$post('/api/testcase/removeToGc/', ids, () => {
|
||||
// this.selectRows.clear();
|
||||
// this.initTable();
|
||||
// this.$success(this.$t('commons.delete_success'));
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
},
|
||||
handleEditBatch() {
|
||||
this.$refs.batchEdit.open();
|
||||
},
|
||||
batchEdit(form) {
|
||||
let arr = Array.from(this.selectRows);
|
||||
let ids = arr.map(row => row.id);
|
||||
let param = {};
|
||||
param[form.type] = form.value;
|
||||
param.ids = ids;
|
||||
param.projectId = getCurrentProjectID();
|
||||
param.selectAllDate = this.isSelectAllDate;
|
||||
param.unSelectIds = this.unSelection;
|
||||
param = Object.assign(param, this.condition);
|
||||
this.$post('/api/testcase/batch/editByParam', param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.initTable();
|
||||
});
|
||||
},
|
||||
handleDelete(apiCase) {
|
||||
// if (this.trashEnable) {
|
||||
this.$get('/api/testcase/delete/' + apiCase.id, () => {
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
this.initTable();
|
||||
});
|
||||
return;
|
||||
// }
|
||||
// this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + apiCase.name + " ?", '', {
|
||||
// confirmButtonText: this.$t('commons.confirm'),
|
||||
// callback: (action) => {
|
||||
// if (action === 'confirm') {
|
||||
// let ids = [apiCase.id];
|
||||
// this.$post('/api/testcase/removeToGc/', ids, () => {
|
||||
// this.$success(this.$t('commons.delete_success'));
|
||||
// this.initTable();
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
},
|
||||
setEnvironment(data) {
|
||||
this.environmentId = data.id;
|
||||
},
|
||||
selectRowsCount(selection) {
|
||||
let selectedIDs = this.getIds(selection);
|
||||
let allIDs = this.tableData.map(s => s.id);
|
||||
this.unSelection = allIDs.filter(function (val) {
|
||||
return selectedIDs.indexOf(val) === -1
|
||||
});
|
||||
if (this.isSelectAllDate) {
|
||||
this.selectDataCounts = this.total - this.unSelection.length;
|
||||
} else {
|
||||
this.selectDataCounts = selection.size;
|
||||
}
|
||||
});
|
||||
// } else {
|
||||
// this.$alert(this.$t('api_test.definition.request.delete_confirm') + "?", '', {
|
||||
// confirmButtonText: this.$t('commons.confirm'),
|
||||
// callback: (action) => {
|
||||
// if (action === 'confirm') {
|
||||
// let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
// this.$post('/api/testcase/removeToGc/', ids, () => {
|
||||
// this.selectRows.clear();
|
||||
// this.initTable();
|
||||
// this.$success(this.$t('commons.delete_success'));
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
},
|
||||
handleEditBatch() {
|
||||
this.$refs.batchEdit.open();
|
||||
},
|
||||
batchEdit(form) {
|
||||
let arr = Array.from(this.selectRows);
|
||||
let ids = arr.map(row => row.id);
|
||||
let param = {};
|
||||
param[form.type] = form.value;
|
||||
param.ids = ids;
|
||||
|
||||
param.projectId = getCurrentProjectID();
|
||||
param.selectAllDate = this.isSelectAllDate;
|
||||
param.unSelectIds = this.unSelection;
|
||||
param = Object.assign(param, this.condition);
|
||||
this.$post('/api/testcase/batch/editByParam', param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.initTable();
|
||||
});
|
||||
},
|
||||
handleDelete(apiCase) {
|
||||
// if (this.trashEnable) {
|
||||
this.$get('/api/testcase/delete/' + apiCase.id, () => {
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
this.initTable();
|
||||
});
|
||||
return;
|
||||
// }
|
||||
// this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + apiCase.name + " ?", '', {
|
||||
// confirmButtonText: this.$t('commons.confirm'),
|
||||
// callback: (action) => {
|
||||
// if (action === 'confirm') {
|
||||
// let ids = [apiCase.id];
|
||||
// this.$post('/api/testcase/removeToGc/', ids, () => {
|
||||
// this.$success(this.$t('commons.delete_success'));
|
||||
// this.initTable();
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
},
|
||||
setEnvironment(data) {
|
||||
this.environmentId = data.id;
|
||||
},
|
||||
selectRowsCount(selection) {
|
||||
let selectedIDs = this.getIds(selection);
|
||||
let allIDs = this.tableData.map(s => s.id);
|
||||
this.unSelection = allIDs.filter(function (val) {
|
||||
return selectedIDs.indexOf(val) === -1
|
||||
});
|
||||
if (this.isSelectAllDate) {
|
||||
this.selectDataCounts = this.total - this.unSelection.length;
|
||||
} else {
|
||||
this.selectDataCounts = selection.size;
|
||||
},
|
||||
isSelectDataAll(dataType) {
|
||||
this.isSelectAllDate = dataType;
|
||||
this.selectRowsCount(this.selectRows)
|
||||
//如果已经全选,不需要再操作了
|
||||
if (this.selectRows.size != this.tableData.length) {
|
||||
this.$refs.caseTable.toggleAllSelection(true);
|
||||
}
|
||||
},
|
||||
//判断是否只显示本周的数据。 从首页跳转过来的请求会带有相关参数
|
||||
isSelectThissWeekData() {
|
||||
this.selectDataRange = "all";
|
||||
let routeParam = this.$route.params.dataSelectRange;
|
||||
let dataType = this.$route.params.dataType;
|
||||
if (dataType === 'apiTestCase') {
|
||||
this.selectDataRange = routeParam;
|
||||
}
|
||||
},
|
||||
changeSelectDataRangeAll() {
|
||||
this.$emit("changeSelectDataRangeAll", "testCase");
|
||||
},
|
||||
getIds(rowSets) {
|
||||
let rowArray = Array.from(rowSets)
|
||||
let ids = rowArray.map(s => s.id);
|
||||
return ids;
|
||||
}
|
||||
},
|
||||
isSelectDataAll(dataType) {
|
||||
this.isSelectAllDate = dataType;
|
||||
this.selectRowsCount(this.selectRows)
|
||||
//如果已经全选,不需要再操作了
|
||||
if (this.selectRows.size != this.tableData.length) {
|
||||
this.$refs.caseTable.toggleAllSelection(true);
|
||||
}
|
||||
},
|
||||
//判断是否只显示本周的数据。 从首页跳转过来的请求会带有相关参数
|
||||
isSelectThissWeekData() {
|
||||
this.selectDataRange = "all";
|
||||
let routeParam = this.$route.params.dataSelectRange;
|
||||
let dataType = this.$route.params.dataType;
|
||||
if (dataType === 'apiTestCase') {
|
||||
this.selectDataRange = routeParam;
|
||||
}
|
||||
},
|
||||
changeSelectDataRangeAll() {
|
||||
this.$emit("changeSelectDataRangeAll", "testCase");
|
||||
},
|
||||
getIds(rowSets) {
|
||||
let rowArray = Array.from(rowSets)
|
||||
let ids = rowArray.map(s => s.id);
|
||||
return ids;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.operate-button > div {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.operate-button > div {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.request-method {
|
||||
padding: 0 5px;
|
||||
color: #1E90FF;
|
||||
}
|
||||
.request-method {
|
||||
padding: 0 5px;
|
||||
color: #1E90FF;
|
||||
}
|
||||
|
||||
.api-el-tag {
|
||||
color: white;
|
||||
}
|
||||
.api-el-tag {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
float: right;
|
||||
width: 300px;
|
||||
/*margin-bottom: 20px;*/
|
||||
margin-right: 20px;
|
||||
}
|
||||
.search-input {
|
||||
float: right;
|
||||
width: 300px;
|
||||
/*margin-bottom: 20px;*/
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -10,25 +10,18 @@
|
|||
<el-table v-loading="result.loading"
|
||||
ref="apiDefinitionTable"
|
||||
border
|
||||
:data="tableData" row-key="id" class="test-content adjust-table api-list"
|
||||
:data="tableData" row-key="id" class="test-content adjust-table ms-select-all"
|
||||
@select-all="handleSelectAll"
|
||||
@select="handleSelect" :height="screenHeight">
|
||||
<el-table-column width="20" type="selection"/>
|
||||
<el-table-column width="50" type="selection"/>
|
||||
|
||||
<ms-table-select-all
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
@selectPageAll="isSelectDataAll(false)"
|
||||
@selectAll="isSelectDataAll(true)"/>
|
||||
|
||||
<el-table-column width="30" :resizable="false" align="center">
|
||||
<el-dropdown slot="header">
|
||||
<span class="el-dropdown-link">
|
||||
<i class="el-icon-arrow-down"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item @click.native.stop="isSelectDataAll(true)">
|
||||
{{ $t('api_test.batch_menus.select_all_data', [total]) }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click.native.stop="isSelectDataAll(false)">
|
||||
{{ $t('api_test.batch_menus.select_show_data', [tableData.length]) }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<template v-slot:default="scope">
|
||||
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectDataCounts"/>
|
||||
</template>
|
||||
|
@ -37,43 +30,38 @@
|
|||
<el-table-column prop="num" label="ID" show-overflow-tooltip/>
|
||||
<el-table-column prop="name" :label="$t('api_test.definition.api_name')" show-overflow-tooltip/>
|
||||
<el-table-column
|
||||
prop="status"
|
||||
column-key="api_status"
|
||||
:label="$t('api_test.definition.api_status')"
|
||||
show-overflow-tooltip>
|
||||
prop="status"
|
||||
column-key="api_status"
|
||||
:label="$t('api_test.definition.api_status')"
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<ms-tag v-if="scope.row.status == 'Prepare'" type="info" effect="plain"
|
||||
:content="$t('test_track.plan.plan_status_prepare')"/>
|
||||
<ms-tag v-if="scope.row.status == 'Underway'" type="warning" effect="plain"
|
||||
:content="$t('test_track.plan.plan_status_running')"/>
|
||||
<ms-tag v-if="scope.row.status == 'Completed'" type="success" effect="plain"
|
||||
:content="$t('test_track.plan.plan_status_completed')"/>
|
||||
<ms-tag v-if="scope.row.status == 'Prepare'" type="info" effect="plain" :content="$t('test_track.plan.plan_status_prepare')"/>
|
||||
<ms-tag v-if="scope.row.status == 'Underway'" type="warning" effect="plain" :content="$t('test_track.plan.plan_status_running')"/>
|
||||
<ms-tag v-if="scope.row.status == 'Completed'" type="success" effect="plain" :content="$t('test_track.plan.plan_status_completed')"/>
|
||||
<ms-tag v-if="scope.row.status == 'Trash'" type="danger" effect="plain" content="废弃"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="method"
|
||||
:label="$t('api_test.definition.api_type')"
|
||||
show-overflow-tooltip>
|
||||
prop="method"
|
||||
:label="$t('api_test.definition.api_type')"
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope" class="request-method">
|
||||
<el-tag size="mini"
|
||||
:style="{'background-color': getColor(true, scope.row.method), border: getColor(true, scope.row.method)}"
|
||||
class="api-el-tag">
|
||||
{{ scope.row.method }}
|
||||
<el-tag size="mini" :style="{'background-color': getColor(true, scope.row.method), border: getColor(true, scope.row.method)}" class="api-el-tag">
|
||||
{{ scope.row.method}}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="path"
|
||||
:label="$t('api_test.definition.api_path')"
|
||||
show-overflow-tooltip/>
|
||||
prop="path"
|
||||
:label="$t('api_test.definition.api_path')"
|
||||
show-overflow-tooltip/>
|
||||
|
||||
<el-table-column
|
||||
prop="userName"
|
||||
:label="$t('api_test.definition.api_principal')"
|
||||
show-overflow-tooltip/>
|
||||
prop="userName"
|
||||
:label="$t('api_test.definition.api_principal')"
|
||||
show-overflow-tooltip/>
|
||||
|
||||
<el-table-column width="160" :label="$t('api_test.definition.api_last_time')" prop="updateTime">
|
||||
<template v-slot:default="scope">
|
||||
|
@ -82,31 +70,27 @@
|
|||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="caseTotal"
|
||||
:label="$t('api_test.definition.api_case_number')"
|
||||
show-overflow-tooltip/>
|
||||
prop="caseTotal"
|
||||
:label="$t('api_test.definition.api_case_number')"
|
||||
show-overflow-tooltip/>
|
||||
|
||||
<el-table-column
|
||||
prop="caseStatus"
|
||||
:label="$t('api_test.definition.api_case_status')"
|
||||
show-overflow-tooltip/>
|
||||
prop="caseStatus"
|
||||
:label="$t('api_test.definition.api_case_status')"
|
||||
show-overflow-tooltip/>
|
||||
|
||||
<el-table-column
|
||||
prop="casePassingRate"
|
||||
:label="$t('api_test.definition.api_case_passing_rate')"
|
||||
show-overflow-tooltip/>
|
||||
prop="casePassingRate"
|
||||
:width="100"
|
||||
:label="$t('api_test.definition.api_case_passing_rate')"
|
||||
show-overflow-tooltip/>
|
||||
|
||||
<el-table-column v-if="!isReadOnly" :label="$t('commons.operating')" min-width="130" align="center">
|
||||
<template v-slot:default="scope">
|
||||
<el-button type="text" @click="reductionApi(scope.row)" v-if="trashEnable" v-tester>
|
||||
{{ $t('commons.reduction') }}
|
||||
</el-button>
|
||||
<el-button type="text" @click="editApi(scope.row)" v-else v-tester>{{ $t('commons.edit') }}</el-button>
|
||||
<el-button type="text" @click="handleTestCase(scope.row)">{{ $t('api_test.definition.request.case') }}
|
||||
</el-button>
|
||||
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C" v-tester>
|
||||
{{ $t('commons.delete') }}
|
||||
</el-button>
|
||||
<el-button type="text" @click="reductionApi(scope.row)" v-if="trashEnable" v-tester>{{$t('commons.reduction')}}</el-button>
|
||||
<el-button type="text" @click="editApi(scope.row)" v-else v-tester>{{$t('commons.edit')}}</el-button>
|
||||
<el-button type="text" @click="handleTestCase(scope.row)">{{$t('api_test.definition.request.case')}}</el-button>
|
||||
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C" v-tester>{{$t('commons.delete')}}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
@ -122,134 +106,133 @@
|
|||
|
||||
<script>
|
||||
|
||||
import MsTableHeader from '../../../../common/components/MsTableHeader';
|
||||
import MsTableOperator from "../../../../common/components/MsTableOperator";
|
||||
import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton";
|
||||
import MsTableButton from "../../../../common/components/MsTableButton";
|
||||
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
||||
import MsTablePagination from "../../../../common/pagination/TablePagination";
|
||||
import MsTag from "../../../../common/components/MsTag";
|
||||
import MsApiCaseList from "../case/ApiCaseList";
|
||||
import MsContainer from "../../../../common/components/MsContainer";
|
||||
import MsBottomContainer from "../BottomContainer";
|
||||
import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn";
|
||||
import MsBatchEdit from "../basis/BatchEdit";
|
||||
import {API_METHOD_COLOUR, REQ_METHOD, API_STATUS} from "../../model/JsonData";
|
||||
import {getCurrentProjectID} from "@/common/js/utils";
|
||||
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
||||
import ApiListContainer from "./ApiListContainer";
|
||||
import MsTableHeader from '../../../../common/components/MsTableHeader';
|
||||
import MsTableOperator from "../../../../common/components/MsTableOperator";
|
||||
import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton";
|
||||
import MsTableButton from "../../../../common/components/MsTableButton";
|
||||
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
||||
import MsTablePagination from "../../../../common/pagination/TablePagination";
|
||||
import MsTag from "../../../../common/components/MsTag";
|
||||
import MsApiCaseList from "../case/ApiCaseList";
|
||||
import MsContainer from "../../../../common/components/MsContainer";
|
||||
import MsBottomContainer from "../BottomContainer";
|
||||
import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn";
|
||||
import MsBatchEdit from "../basis/BatchEdit";
|
||||
import {API_METHOD_COLOUR, REQ_METHOD, API_STATUS} from "../../model/JsonData";
|
||||
import {getCurrentProjectID} from "@/common/js/utils";
|
||||
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
||||
import ApiListContainer from "./ApiListContainer";
|
||||
import MsTableSelectAll from "../../../../common/components/table/MsTableSelectAll";
|
||||
|
||||
export default {
|
||||
name: "ApiList",
|
||||
components: {
|
||||
ApiListContainer,
|
||||
MsTableButton,
|
||||
MsTableOperatorButton,
|
||||
MsTableOperator,
|
||||
MsTableHeader,
|
||||
MsTablePagination,
|
||||
MsTag,
|
||||
MsApiCaseList,
|
||||
MsContainer,
|
||||
MsBottomContainer,
|
||||
ShowMoreBtn,
|
||||
MsBatchEdit
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
condition: {},
|
||||
selectApi: {},
|
||||
result: {},
|
||||
moduleId: "",
|
||||
selectDataRange: "all",
|
||||
deletePath: "/test/case/delete",
|
||||
selectRows: new Set(),
|
||||
buttons: [
|
||||
{name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteBatch},
|
||||
{name: this.$t('api_test.definition.request.batch_edit'), handleClick: this.handleEditBatch}
|
||||
],
|
||||
typeArr: [
|
||||
{id: 'status', name: this.$t('api_test.definition.api_status')},
|
||||
{id: 'method', name: this.$t('api_test.definition.api_type')},
|
||||
{id: 'userId', name: this.$t('api_test.definition.api_principal')},
|
||||
],
|
||||
valueArr: {
|
||||
status: API_STATUS,
|
||||
method: REQ_METHOD,
|
||||
userId: [],
|
||||
export default {
|
||||
name: "ApiList",
|
||||
components: {
|
||||
MsTableSelectAll,
|
||||
ApiListContainer,
|
||||
MsTableButton,
|
||||
MsTableOperatorButton,
|
||||
MsTableOperator,
|
||||
MsTableHeader,
|
||||
MsTablePagination,
|
||||
MsTag,
|
||||
MsApiCaseList,
|
||||
MsContainer,
|
||||
MsBottomContainer,
|
||||
ShowMoreBtn,
|
||||
MsBatchEdit
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
condition: {},
|
||||
selectApi: {},
|
||||
result: {},
|
||||
moduleId: "",
|
||||
selectDataRange: "all",
|
||||
deletePath: "/test/case/delete",
|
||||
selectRows: new Set(),
|
||||
buttons: [
|
||||
{name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteBatch},
|
||||
{name: this.$t('api_test.definition.request.batch_edit'), handleClick: this.handleEditBatch}
|
||||
],
|
||||
typeArr: [
|
||||
{id: 'status', name: this.$t('api_test.definition.api_status')},
|
||||
{id: 'method', name: this.$t('api_test.definition.api_type')},
|
||||
{id: 'userId', name: this.$t('api_test.definition.api_principal')},
|
||||
],
|
||||
valueArr: {
|
||||
status: API_STATUS,
|
||||
method: REQ_METHOD,
|
||||
userId: [],
|
||||
},
|
||||
methodColorMap: new Map(API_METHOD_COLOUR),
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
screenHeight: document.documentElement.clientHeight - 330,//屏幕高度,
|
||||
environmentId: undefined,
|
||||
selectAll: false,
|
||||
unSelection:[],
|
||||
selectDataCounts:0,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
currentProtocol: String,
|
||||
selectNodeIds: Array,
|
||||
isSelectThisWeek: String,
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCaseRelevance: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
trashEnable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isApiListEnable: Boolean,
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
methodColorMap: new Map(API_METHOD_COLOUR),
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
screenHeight: document.documentElement.clientHeight - 330,//屏幕高度,
|
||||
environmentId: undefined,
|
||||
selectAll: false,
|
||||
unSelection: [],
|
||||
selectDataCounts: 0,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
currentProtocol: String,
|
||||
selectNodeIds: Array,
|
||||
isSelectThisWeek: String,
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCaseRelevance: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
trashEnable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isApiListEnable: Boolean,
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
mounted: function () {
|
||||
this.initTable();
|
||||
},
|
||||
created: function () {
|
||||
this.initTable();
|
||||
this.getMaintainerOptions();
|
||||
},
|
||||
watch: {
|
||||
selectNodeIds() {
|
||||
created: function () {
|
||||
this.initTable();
|
||||
this.getMaintainerOptions();
|
||||
},
|
||||
currentProtocol() {
|
||||
this.initTable();
|
||||
},
|
||||
trashEnable() {
|
||||
if (this.trashEnable) {
|
||||
watch: {
|
||||
selectNodeIds() {
|
||||
this.initTable();
|
||||
},
|
||||
currentProtocol() {
|
||||
this.initTable();
|
||||
},
|
||||
trashEnable() {
|
||||
if (this.trashEnable) {
|
||||
this.initTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isApiListEnableChange(data) {
|
||||
this.$emit('isApiListEnableChange', data);
|
||||
},
|
||||
initTable() {
|
||||
this.selectRows = new Set();
|
||||
methods: {
|
||||
isApiListEnableChange(data) {
|
||||
this.$emit('isApiListEnableChange', data);
|
||||
},
|
||||
initTable() {
|
||||
this.selectRows = new Set();
|
||||
|
||||
this.selectAll = false;
|
||||
this.unSelection = [];
|
||||
this.selectDataCounts = 0;
|
||||
this.selectAll = false;
|
||||
this.unSelection = [];
|
||||
this.selectDataCounts = 0;
|
||||
|
||||
this.condition.filters = ["Prepare", "Underway", "Completed"];
|
||||
this.condition.filters = ["Prepare", "Underway", "Completed"];
|
||||
|
||||
this.condition.moduleIds = this.selectNodeIds;
|
||||
if (this.trashEnable) {
|
||||
this.condition.filters = ["Trash"];
|
||||
this.condition.moduleIds = [];
|
||||
}
|
||||
this.condition.moduleIds = this.selectNodeIds;
|
||||
if (this.trashEnable) {
|
||||
this.condition.filters = ["Trash"];
|
||||
this.condition.moduleIds = [];
|
||||
}
|
||||
|
||||
this.condition.projectId = getCurrentProjectID();
|
||||
if (this.currentProtocol != null) {
|
||||
|
@ -342,76 +325,76 @@ export default {
|
|||
return path + "/" + this.currentPage + "/" + this.pageSize;
|
||||
},
|
||||
|
||||
editApi(row) {
|
||||
this.$emit('editApi', row);
|
||||
},
|
||||
reductionApi(row) {
|
||||
row.request = null;
|
||||
row.response = null;
|
||||
let rows = [row];
|
||||
this.$post('/api/definition/reduction/', rows, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.search();
|
||||
});
|
||||
},
|
||||
handleDeleteBatch() {
|
||||
if (this.trashEnable) {
|
||||
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
let deleteParam = {};
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
deleteParam.dataIds = ids;
|
||||
deleteParam.projectId = getCurrentProjectID();
|
||||
deleteParam.selectAllDate = this.isSelectAllDate;
|
||||
deleteParam.unSelectIds = this.unSelection;
|
||||
deleteParam = Object.assign(deleteParam, this.condition);
|
||||
this.$post('/api/definition/deleteBatchByParams/', deleteParam, () => {
|
||||
this.selectRows.clear();
|
||||
this.initTable();
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
});
|
||||
}
|
||||
}
|
||||
editApi(row) {
|
||||
this.$emit('editApi', row);
|
||||
},
|
||||
reductionApi(row) {
|
||||
row.request = null;
|
||||
row.response = null;
|
||||
let rows = [row];
|
||||
this.$post('/api/definition/reduction/', rows, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.search();
|
||||
});
|
||||
} else {
|
||||
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
let deleteParam = {};
|
||||
deleteParam.dataIds = ids;
|
||||
deleteParam.projectId = getCurrentProjectID();
|
||||
deleteParam.selectAllDate = this.isSelectAllDate;
|
||||
deleteParam.unSelectIds = this.unSelection;
|
||||
deleteParam = Object.assign(deleteParam, this.condition);
|
||||
this.$post('/api/definition/removeToGcByParams/', deleteParam, () => {
|
||||
this.selectRows.clear();
|
||||
this.initTable();
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
this.$refs.caseList.apiCaseClose();
|
||||
});
|
||||
},
|
||||
handleDeleteBatch() {
|
||||
if (this.trashEnable) {
|
||||
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
let deleteParam = {};
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
deleteParam.dataIds = ids;
|
||||
deleteParam.projectId = getCurrentProjectID();
|
||||
deleteParam.selectAllDate = this.isSelectAllDate;
|
||||
deleteParam.unSelectIds = this.unSelection;
|
||||
deleteParam = Object.assign(deleteParam, this.condition);
|
||||
this.$post('/api/definition/deleteBatchByParams/', deleteParam, () => {
|
||||
this.selectRows.clear();
|
||||
this.initTable();
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
handleEditBatch() {
|
||||
this.$refs.batchEdit.open();
|
||||
},
|
||||
batchEdit(form) {
|
||||
let arr = Array.from(this.selectRows);
|
||||
let ids = arr.map(row => row.id);
|
||||
let param = {};
|
||||
param[form.type] = form.value;
|
||||
param.ids = ids;
|
||||
});
|
||||
} else {
|
||||
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
let deleteParam = {};
|
||||
deleteParam.dataIds = ids;
|
||||
deleteParam.projectId = getCurrentProjectID();
|
||||
deleteParam.selectAllDate = this.isSelectAllDate;
|
||||
deleteParam.unSelectIds = this.unSelection;
|
||||
deleteParam = Object.assign(deleteParam, this.condition);
|
||||
this.$post('/api/definition/removeToGcByParams/', deleteParam, () => {
|
||||
this.selectRows.clear();
|
||||
this.initTable();
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
this.$refs.caseList.apiCaseClose();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
handleEditBatch() {
|
||||
this.$refs.batchEdit.open();
|
||||
},
|
||||
batchEdit(form) {
|
||||
let arr = Array.from(this.selectRows);
|
||||
let ids = arr.map(row => row.id);
|
||||
let param = {};
|
||||
param[form.type] = form.value;
|
||||
param.ids = ids;
|
||||
|
||||
param.projectId = getCurrentProjectID();
|
||||
param.selectAllDate = this.isSelectAllDate;
|
||||
param.unSelectIds = this.unSelection;
|
||||
param = Object.assign(param, this.condition);
|
||||
param.projectId = getCurrentProjectID();
|
||||
param.selectAllDate = this.isSelectAllDate;
|
||||
param.unSelectIds = this.unSelection;
|
||||
param = Object.assign(param, this.condition);
|
||||
|
||||
this.$post('/api/definition/batch/editByParams', param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
|
@ -505,54 +488,52 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.operate-button > div {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.operate-button > div {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.request-method {
|
||||
padding: 0 5px;
|
||||
color: #1E90FF;
|
||||
}
|
||||
.request-method {
|
||||
padding: 0 5px;
|
||||
color: #1E90FF;
|
||||
}
|
||||
|
||||
.api-el-tag {
|
||||
color: white;
|
||||
}
|
||||
.api-el-tag {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
float: right;
|
||||
width: 300px;
|
||||
/*margin-bottom: 20px;*/
|
||||
margin-right: 20px;
|
||||
}
|
||||
.search-input {
|
||||
float: right;
|
||||
width: 300px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.api-list >>> th:first-child {
|
||||
/*border: 1px solid #DCDFE6;*/
|
||||
/*border-right: 0px;*/
|
||||
/*border-top-left-radius:5px;*/
|
||||
/*border-bottom-left-radius:5px;*/
|
||||
/*width: 20px;*/
|
||||
.api-list >>> th:first-child {
|
||||
/*border: 1px solid #DCDFE6;*/
|
||||
/*border-right: 0px;*/
|
||||
/*border-top-left-radius:5px;*/
|
||||
/*border-bottom-left-radius:5px;*/
|
||||
/*width: 20px;*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.api-list >>> th:nth-child(2) {
|
||||
/*border: 1px solid #DCDFE6;*/
|
||||
/*border-left: 0px;*/
|
||||
/*border-top-right-radius:5px;*/
|
||||
/*border-bottom-right-radius:5px;*/
|
||||
}
|
||||
.api-list >>> th:nth-child(2) {
|
||||
/*border: 1px solid #DCDFE6;*/
|
||||
/*border-left: 0px;*/
|
||||
/*border-top-right-radius:5px;*/
|
||||
/*border-bottom-right-radius:5px;*/
|
||||
}
|
||||
|
||||
.api-list >>> th:first-child > .cell {
|
||||
padding: 5px;
|
||||
width: 30px;
|
||||
}
|
||||
.api-list >>> th:first-child>.cell {
|
||||
padding: 5px;
|
||||
width: 30px;
|
||||
}
|
||||
.api-list >>> th:nth-child(2)>.cell {
|
||||
/*background-color: black;*/
|
||||
}
|
||||
|
||||
.api-list >>> th:nth-child(2) > .cell {
|
||||
/*background-color: black;*/
|
||||
}
|
||||
|
||||
.api-list >>> .el-dropdown {
|
||||
float: left;
|
||||
}
|
||||
.api-list >>> .el-dropdown {
|
||||
float: left;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -122,7 +122,7 @@ export default {
|
|||
<style scoped>
|
||||
|
||||
.protocol-select {
|
||||
width: 95px;
|
||||
width: 92px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
ref="codeEdit"/>
|
||||
</el-col>
|
||||
<el-col :span="4" class="script-index">
|
||||
<ms-dropdown :default-command="jsr223ProcessorData.language" :commands="languages" @command="languageChange"/>
|
||||
<ms-dropdown :default-command="jsr223ProcessorData.scriptLanguage" :commands="languages" @command="languageChange"/>
|
||||
<div class="template-title">{{$t('api_test.request.processor.code_template')}}</div>
|
||||
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
|
||||
<el-link :disabled="template.disabled" @click="addTemplate(template)">{{template.title}}</el-link>
|
||||
|
@ -140,7 +140,7 @@
|
|||
this.jsr223ProcessorData.script = "";
|
||||
}
|
||||
this.jsr223ProcessorData.script += template.value;
|
||||
if (this.jsr223ProcessorData.language === 'beanshell') {
|
||||
if (this.jsr223ProcessorData.scriptLanguage === 'beanshell') {
|
||||
this.jsr223ProcessorData.script += ';';
|
||||
}
|
||||
this.reload();
|
||||
|
@ -156,7 +156,7 @@
|
|||
this.$nextTick(() => (this.isCodeEditAlive = true));
|
||||
},
|
||||
languageChange(language) {
|
||||
this.jsr223ProcessorData.language = language;
|
||||
this.jsr223ProcessorData.scriptLanguage = language;
|
||||
},
|
||||
changeActive() {
|
||||
this.active = !this.active;
|
||||
|
|
|
@ -842,8 +842,7 @@ export class JSR223Processor extends BaseConfig {
|
|||
this.active = false;
|
||||
this.type = "JSR223Processor";
|
||||
this.script = undefined;
|
||||
this.language = "beanshell";
|
||||
this.scriptLanguage = "java";
|
||||
this.scriptLanguage = "beanshell";
|
||||
this.enable = true;
|
||||
this.hashTree = [];
|
||||
this.set(options);
|
||||
|
|
|
@ -97,7 +97,6 @@ export default {
|
|||
methods: {
|
||||
registerEvents() {
|
||||
ApiEvent.$on(LIST_CHANGE, () => {
|
||||
// // todo 这里偶尔会有 refs 为空的情况
|
||||
this.$refs.testRecent.recent();
|
||||
this.$refs.reportRecent.recent();
|
||||
});
|
||||
|
@ -111,6 +110,9 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
this.registerEvents();
|
||||
},
|
||||
beforeDestroy() {
|
||||
ApiEvent.$off(LIST_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ export default {
|
|||
tableData: [],
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
loading: false,
|
||||
statusFilters: [
|
||||
|
|
|
@ -45,7 +45,7 @@ export default {
|
|||
tableData: [],
|
||||
loading: false,
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
}
|
||||
},
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
tableData: [],
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
loading: false,
|
||||
selectIds: new Set(),
|
||||
|
|
|
@ -63,7 +63,7 @@ export default {
|
|||
},
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
selection: false,
|
||||
environmentMap: new Map()
|
||||
|
|
|
@ -118,7 +118,21 @@ export default {
|
|||
},
|
||||
copyRequest(index) {
|
||||
let request = this.scenario.requests[index];
|
||||
this.scenario.requests.push(new RequestFactory(request));
|
||||
let item = new RequestFactory(request);
|
||||
if (item.body && item.body.kvs) {
|
||||
item.body.kvs.forEach(kv => {
|
||||
let files = [];
|
||||
if (kv.files) {
|
||||
kv.files.forEach(file => {
|
||||
let fileCopy = {};
|
||||
Object.assign(fileCopy, file);
|
||||
files.push(fileCopy);
|
||||
})
|
||||
}
|
||||
kv.files = files;
|
||||
});
|
||||
}
|
||||
this.scenario.requests.push(item);
|
||||
},
|
||||
disableRequest(index) {
|
||||
this.scenario.requests[index].enable = false;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<el-table-column width="1" :resizable="false" align="center">
|
||||
<el-dropdown slot="header">
|
||||
<span class="el-dropdown-link">
|
||||
<i class="el-icon-arrow-down"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item @click.native.stop="$emit('selectAll')">
|
||||
{{$t('api_test.batch_menus.select_all_data',[total])}}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click.native.stop="$emit('selectPageAll')">
|
||||
{{$t('api_test.batch_menus.select_show_data',[pageSize])}}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</el-table-column>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsTableSelectAll",
|
||||
props: ['total', 'pageSize']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,82 @@
|
|||
<template>
|
||||
<div id="app" v-loading="loading">
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<el-tab-pane :label="$t('organization.message.template')" name="apiTemplate">
|
||||
<el-button type="primary" size="mini" style="margin-left: 10px" @click="openOneClickOperation">导入</el-button>
|
||||
<div style="min-height: 400px">
|
||||
<json-schema-editor class="schema" :value="schema" lang="zh_CN" custom/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('schema.preview')" name="preview">
|
||||
<div style="min-height: 400px">
|
||||
<pre>{{this.preview}}</pre>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<ms-import-json ref="importJson" @jsonData="jsonData"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {schemaToJson} from './common';
|
||||
import MsImportJson from './import/ImportJson';
|
||||
|
||||
const GenerateSchema = require('generate-schema/src/schemas/json.js');
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {MsImportJson},
|
||||
props: {
|
||||
body: {},
|
||||
},
|
||||
created() {
|
||||
if (!this.body.jsonSchema && this.body.raw) {
|
||||
let obj = {"root": GenerateSchema(JSON.parse(this.body.raw))}
|
||||
this.schema = obj;
|
||||
}
|
||||
else if (this.body.jsonSchema) {
|
||||
this.schema = {"root": this.body.jsonSchema};
|
||||
}
|
||||
this.body.jsonSchema = this.schema.root;
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
schema:
|
||||
{
|
||||
"root": {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
}
|
||||
},
|
||||
loading: false,
|
||||
preview: null,
|
||||
activeName: "apiTemplate",
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
if (this.activeName === 'preview') {
|
||||
// 前端转换
|
||||
//this.preview = schemaToJson(this.schema.root);
|
||||
this.loading = true;
|
||||
// 后台转换
|
||||
this.$post('/api/definition/preview', this.schema.root, response => {
|
||||
this.preview = response.data;
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
openOneClickOperation() {
|
||||
this.$refs.importJson.openOneClickOperation();
|
||||
},
|
||||
jsonData(data) {
|
||||
let obj = {"root": data}
|
||||
this.schema = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,32 @@
|
|||
const Mock = require('mockjs');
|
||||
const jsf = require('json-schema-faker');
|
||||
|
||||
jsf.extend('mock', function () {
|
||||
return {
|
||||
mock: function (xx) {
|
||||
if (xx && xx.startsWith("@")) {
|
||||
return Mock.mock(xx);
|
||||
}
|
||||
return xx;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const defaultOptions = {
|
||||
failOnInvalidTypes: false,
|
||||
failOnInvalidFormat: false
|
||||
};
|
||||
|
||||
export const schemaToJson = (schema, options = {}) => {
|
||||
Object.assign(options, defaultOptions);
|
||||
|
||||
jsf.option(options);
|
||||
let result;
|
||||
try {
|
||||
result = jsf.generate(schema);
|
||||
} catch (err) {
|
||||
result = err.message;
|
||||
}
|
||||
jsf.option(defaultOptions);
|
||||
return result;
|
||||
};
|
|
@ -0,0 +1,117 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
title="导入"
|
||||
:visible.sync="importVisible"
|
||||
width="50%"
|
||||
show-close
|
||||
:close-on-click-modal="false"
|
||||
@closed="handleClose">
|
||||
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane label="JSON" name="JSON">
|
||||
<div style="height: 400px">
|
||||
<ms-code-edit :mode="mode"
|
||||
:data.sync="json" theme="eclipse" :modes="[]"
|
||||
ref="codeEdit"/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="JSON-SCHEMA" name="JSON-SCHEMA">
|
||||
<div style="height: 400px">
|
||||
<ms-code-edit :mode="mode"
|
||||
:data.sync="jsonSchema" theme="eclipse" :modes="[]"
|
||||
ref="codeEdit"/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<ms-dialog-footer
|
||||
@cancel="importVisible = false"
|
||||
@confirm="saveConfirm"/>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsDialogFooter from '../../../common/components/MsDialogFooter'
|
||||
import MsCodeEdit from "../../../common/components/MsCodeEdit";
|
||||
import json5 from 'json5';
|
||||
|
||||
const GenerateSchema = require('generate-schema/src/schemas/json.js');
|
||||
|
||||
export default {
|
||||
name: "MsImportJson",
|
||||
components: {MsDialogFooter, MsCodeEdit},
|
||||
data() {
|
||||
return {
|
||||
importVisible: false,
|
||||
activeName: "JSON",
|
||||
mode: "json",
|
||||
json: "",
|
||||
jsonSchema: "",
|
||||
};
|
||||
},
|
||||
watch: {},
|
||||
props: {},
|
||||
methods: {
|
||||
openOneClickOperation() {
|
||||
this.importVisible = true;
|
||||
},
|
||||
checkIsJson(json) {
|
||||
try {
|
||||
json5.parse(json);
|
||||
return true;
|
||||
} catch (e) {
|
||||
alert(1);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
checkIsJsonSchema(json) {
|
||||
try {
|
||||
json = json5.parse(json);
|
||||
if (json.properties && typeof json.properties === 'object' && !json.type) {
|
||||
json.type = 'object';
|
||||
}
|
||||
if (json.items && typeof json.items === 'object' && !json.type) {
|
||||
json.type = 'array';
|
||||
}
|
||||
if (!json.type) {
|
||||
return false;
|
||||
}
|
||||
json.type = json.type.toLowerCase();
|
||||
let types = ['object', 'string', 'number', 'array', 'boolean', 'integer'];
|
||||
if (types.indexOf(json.type) === -1) {
|
||||
return false;
|
||||
}
|
||||
return JSON.stringify(json);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
saveConfirm() {
|
||||
if (this.activeName === 'JSON') {
|
||||
if (!this.checkIsJson(this.json)) {
|
||||
this.$error("导入的数据非JSON格式");
|
||||
return;
|
||||
}
|
||||
let jsonData = GenerateSchema(json5.parse(this.json));
|
||||
this.$emit('jsonData', jsonData);
|
||||
} else {
|
||||
if (!this.checkIsJsonSchema(this.jsonSchema)) {
|
||||
this.$error("导入的数据非JSON-SCHEMA 格式");
|
||||
return;
|
||||
}
|
||||
let obj = json5.parse(this.jsonSchema);
|
||||
this.$emit('jsonData', obj);
|
||||
}
|
||||
this.importVisible = false;
|
||||
},
|
||||
handleClose() {
|
||||
this.importVisible = false;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
284
frontend/src/business/components/common/json-schema/lib/json-schema-editor-vue.umd.min.js
vendored
Normal file
284
frontend/src/business/components/common/json-schema/lib/json-schema-editor-vue.umd.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,7 @@
|
|||
import JsonSchemaEditor from './main.vue'
|
||||
|
||||
JsonSchemaEditor.install = function (Vue) {
|
||||
Vue.component(JsonSchemaEditor.name, JsonSchemaEditor)
|
||||
}
|
||||
|
||||
export default JsonSchemaEditor
|
|
@ -0,0 +1,398 @@
|
|||
<template>
|
||||
<div class="json-schema-editor">
|
||||
<el-row class="row" :gutter="10">
|
||||
<el-col :span="12" class="ant-col-name">
|
||||
<div :style="{marginLeft:`${10*deep}px`}" class="ant-col-name-c">
|
||||
<span v-if="pickValue.type==='object'" :class="hidden? 'el-tree-node__expand-icon el-icon-caret-right':
|
||||
'expanded el-tree-node__expand-icon el-icon-caret-right'" @click="hidden = !hidden"/>
|
||||
<span v-else style="width:10px;display:inline-block"></span>
|
||||
<input class="el-input el-input__inner" style="height: 32px" :disabled="disabled || root" :value="pickKey" @blur="onInputName" size="small"/>
|
||||
</div>
|
||||
<el-tooltip v-if="root" :content="$t('schema.checked_all')" placement="top">
|
||||
<input type="checkbox" :disabled="!isObject && !isArray" class="ant-col-name-required" @change="onRootCheck"/>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-else :content="$t('schema.required')" placement="top">
|
||||
<input type="checkbox" :disabled="isItem" :checked="checked" class="ant-col-name-required" @change="onCheck"/>
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-select v-model="pickValue.type" :disabled="disabledType" class="ant-col-type" @change="onChangeType" size="small">
|
||||
<el-option :key="t" :value="t" :label="t" v-for="t in TYPE_NAME"/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<ms-mock :disabled="pickValue.type==='object'" :schema="pickValue"/>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-input v-model="pickValue.description" class="ant-col-title" :placeholder="$t('schema.description')" size="small"/>
|
||||
</el-col>
|
||||
<el-col :span="5" class="col-item-setting">
|
||||
<el-tooltip class="item" effect="dark" :content="$t('schema.adv_setting')" placement="top">
|
||||
<i class="el-icon-setting" @click="onSetting"/>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="isObject" :content="$t('schema.add_child_node')" placement="top">
|
||||
<i class="el-icon-plus" @click="addChild" style="margin-left: 10px"/>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="!root && !isItem" :content="$t('schema.remove_node')" placement="top">
|
||||
<i class="el-icon-close" @click="removeNode" style="margin-left: 10px"/>
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<template v-if="!hidden&&pickValue.properties && !isArray">
|
||||
<json-schema-editor v-for="(item,key,index) in pickValue.properties" :value="{[key]:item}" :parent="pickValue" :key="index" :deep="deep+1" :root="false" class="children" :lang="lang" :custom="custom"/>
|
||||
</template>
|
||||
<template v-if="isArray">
|
||||
<json-schema-editor :value="{items:pickValue.items}" :deep="deep+1" disabled isItem :root="false" class="children" :lang="lang" :custom="custom"/>
|
||||
</template>
|
||||
<!-- 高级设置-->
|
||||
<el-dialog :close-on-click-modal="false" :title="$t('schema.adv_setting')" :visible.sync="modalVisible" :destroy-on-close="true"
|
||||
@close="handleClose">
|
||||
<p class="tip">基础设置 </p>
|
||||
<el-form :inline="true" v-model="advancedValue" class="ant-advanced-search-form">
|
||||
<el-row :gutter="6">
|
||||
<el-col :span="8" v-for="(item,key) in advancedValue" :key="key" style="float: right">
|
||||
<el-form-item>
|
||||
<div>{{ $t('schema.'+key)}}</div>
|
||||
<el-input-number v-model="advancedValue[key]" v-if="advancedAttr[key].type === 'integer'" style="width:100%" :placeholder="key" size="small"/>
|
||||
<el-input-number v-model="advancedValue[key]" v-else-if="advancedAttr[key].type === 'number'" style="width:100%" :placeholder="key" size="small"/>
|
||||
<span v-else-if="advancedAttr[key].type === 'boolean'" style="display:inline-block;width:100%">
|
||||
<el-switch v-model="advancedValue[key]"/>
|
||||
</span>
|
||||
<el-select v-else-if="advancedAttr[key].type === 'array'" v-model="advancedValue[key]" style="width:100%" size="small">
|
||||
<el-option value="" :label="$t('schema.nothing')"></el-option>
|
||||
<el-option :key="t" :value="t" :label="t" v-for="t in advancedAttr[key].enums"/>
|
||||
</el-select>
|
||||
<el-input v-model="advancedValue[key]" v-else style="width:100%;" :placeholder="key" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<!--<h3 v-text="$t('schema.add_custom')" v-show="custom">添加自定义属性</h3>
|
||||
<el-form class="ant-advanced-search-form" v-show="custom">
|
||||
<el-row :gutter="6">
|
||||
<el-col :span="8" v-for="item in customProps" :key="item.key">
|
||||
<el-form-item :label="item.key">
|
||||
<el-input v-model="item.value" style="width:calc(100% - 30px)" size="small"/>
|
||||
<el-button icon="close" type="link" @click="customProps.splice(customProps.indexOf(item),1)" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" v-show="addProp.key != undefined">
|
||||
<el-form-item>
|
||||
<el-input slot="label" v-model="addProp.key" size="small"/>
|
||||
<el-input v-model="addProp.value" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item>
|
||||
<el-button icon="check" type="link" @click="confirmAddCustomNode" v-if="customing"/>
|
||||
<el-tooltip content="$t('schema.add_custom')" v-else>
|
||||
<el-button icon="el-icon-plus" type="link" @click="addCustomNode"/>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>-->
|
||||
<p class="tip">{{$t('schema.preview')}} </p>
|
||||
<pre style="width:100%">{{completeNodeValue}}</pre>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<ms-dialog-footer
|
||||
@cancel="modalVisible = false"
|
||||
@confirm="handleOk"/>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {isNull} from './util'
|
||||
import {TYPE_NAME, TYPE} from './type/type'
|
||||
import MsMock from './mock/MockComplete'
|
||||
import MsDialogFooter from '../../../components/MsDialogFooter'
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: 'JsonSchemaEditor',
|
||||
components: {MsMock, MsDialogFooter},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
disabled: { //name不可编辑,根节点name不可编辑,数组元素name不可编辑
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabledType: { //禁用类型选择
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isItem: { //是否数组元素
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
deep: { // 节点深度,根节点deep=0
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
root: { //是否root节点
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
parent: { //父节点
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
custom: { //enable custom properties
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
lang: { // i18n language
|
||||
type: String,
|
||||
default: 'zh_CN'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pickValue() {
|
||||
return Object.values(this.value)[0]
|
||||
},
|
||||
pickKey() {
|
||||
return Object.keys(this.value)[0]
|
||||
},
|
||||
isObject() {
|
||||
return this.pickValue.type === 'object'
|
||||
},
|
||||
isArray() {
|
||||
return this.pickValue.type === 'array'
|
||||
},
|
||||
checked() {
|
||||
return this.parent && this.parent.required && this.parent.required.indexOf(this.pickKey) >= 0
|
||||
},
|
||||
advanced() {
|
||||
return TYPE[this.pickValue.type]
|
||||
},
|
||||
advancedAttr() {
|
||||
return TYPE[this.pickValue.type].attr
|
||||
},
|
||||
advancedNotEmptyValue() {
|
||||
const jsonNode = Object.assign({}, this.advancedValue);
|
||||
for (let key in jsonNode) {
|
||||
isNull(jsonNode[key]) && delete jsonNode[key]
|
||||
}
|
||||
return jsonNode
|
||||
},
|
||||
completeNodeValue() {
|
||||
const t = {}
|
||||
for (const item of this.customProps) {
|
||||
t[item.key] = item.value
|
||||
}
|
||||
return Object.assign({}, this.pickValue, this.advancedNotEmptyValue, t)
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
TYPE_NAME,
|
||||
hidden: false,
|
||||
countAdd: 1,
|
||||
modalVisible: false,
|
||||
advancedValue: {},
|
||||
addProp: {},// 自定义属性
|
||||
customProps: [],
|
||||
customing: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onInputName(e) {
|
||||
const val = e.target.value
|
||||
const p = {};
|
||||
for (let key in this.parent.properties) {
|
||||
if (key != this.pickKey) {
|
||||
p[key] = this.parent.properties[key]
|
||||
} else {
|
||||
p[val] = this.parent.properties[key]
|
||||
delete this.parent.properties[key]
|
||||
}
|
||||
}
|
||||
this.$set(this.parent, 'properties', p)
|
||||
},
|
||||
onChangeType() {
|
||||
this.$delete(this.pickValue, 'properties')
|
||||
this.$delete(this.pickValue, 'items')
|
||||
this.$delete(this.pickValue, 'required')
|
||||
this.$delete(this.pickValue, 'mock')
|
||||
if (this.isArray) {
|
||||
this.$set(this.pickValue, 'items', {type: 'string', mock: {mock: ""}})
|
||||
}
|
||||
},
|
||||
onCheck(e) {
|
||||
this._checked(e.target.checked, this.parent)
|
||||
},
|
||||
onRootCheck(e) {
|
||||
const checked = e.target.checked
|
||||
this._deepCheck(checked, this.pickValue)
|
||||
},
|
||||
_deepCheck(checked, node) {
|
||||
if (node.type === 'object' && node.properties) {
|
||||
checked ? this.$set(node, 'required', Object.keys(node.properties)) : this.$delete(node, 'required')
|
||||
Object.keys(node.properties).forEach(key => this._deepCheck(checked, node.properties[key]))
|
||||
} else if (node.type === 'array' && node.items.type === 'object') {
|
||||
checked ? this.$set(node.items, 'required', Object.keys(node.items.properties)) : this.$delete(node.items, 'required')
|
||||
Object.keys(node.items.properties).forEach(key => this._deepCheck(checked, node.items.properties[key]))
|
||||
}
|
||||
},
|
||||
_checked(checked, parent) {
|
||||
let required = parent.required
|
||||
if (checked) {
|
||||
required || this.$set(this.parent, 'required', [])
|
||||
|
||||
required = this.parent.required
|
||||
required.indexOf(this.pickKey) === -1 && required.push(this.pickKey)
|
||||
} else {
|
||||
const pos = required.indexOf(this.pickKey)
|
||||
pos >= 0 && required.splice(pos, 1)
|
||||
}
|
||||
required.length === 0 && this.$delete(parent, 'required')
|
||||
},
|
||||
addChild() {
|
||||
const name = this._joinName()
|
||||
const type = 'string'
|
||||
const node = this.pickValue
|
||||
node.properties || this.$set(node, 'properties', {})
|
||||
const props = node.properties
|
||||
this.$set(props, name, {type: type, mock: {mock: ""}})
|
||||
},
|
||||
addCustomNode() {
|
||||
this.$set(this.addProp, 'key', this._joinName())
|
||||
this.$set(this.addProp, 'value', '')
|
||||
this.customing = true
|
||||
},
|
||||
confirmAddCustomNode() {
|
||||
this.customProps.push(this.addProp)
|
||||
this.addProp = {}
|
||||
this.customing = false
|
||||
},
|
||||
removeNode() {
|
||||
const {properties, required} = this.parent
|
||||
this.$delete(properties, this.pickKey)
|
||||
if (required) {
|
||||
const pos = required.indexOf(this.pickKey)
|
||||
pos >= 0 && required.splice(pos, 1)
|
||||
required.length === 0 && this.$delete(this.parent, 'required')
|
||||
}
|
||||
},
|
||||
_joinName() {
|
||||
return `feild_${this.deep}_${this.countAdd++}_${getUUID().substring(0, 5)}`
|
||||
},
|
||||
onSetting() {
|
||||
this.modalVisible = true;
|
||||
this.advancedValue = this.advanced.value
|
||||
for (const k in this.advancedValue) {
|
||||
if (this.pickValue[k]) this.advancedValue[k] = this.pickValue[k]
|
||||
}
|
||||
console.log(this.pickValue)
|
||||
},
|
||||
handleClose() {
|
||||
this.modalVisible = false;
|
||||
},
|
||||
handleOk() {
|
||||
this.modalVisible = false
|
||||
for (const key in this.advancedValue) {
|
||||
if (isNull(this.advancedValue[key])) {
|
||||
this.$delete(this.pickValue, key)
|
||||
} else {
|
||||
this.$set(this.pickValue, key, this.advancedValue[key])
|
||||
}
|
||||
}
|
||||
for (const item of this.customProps) {
|
||||
this.$set(this.pickValue, item.key, item.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.json-schema-editor .row {
|
||||
display: flex;
|
||||
margin: 12px;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .ant-col-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .ant-col-name .ant-col-name-c {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .ant-col-name .ant-col-name-required {
|
||||
flex: 0 0 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .ant-col-type {
|
||||
min-width: 100px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .ant-col-setting {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .setting-icon {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .plus-icon {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.json-schema-editor .row .close-icon {
|
||||
color: #888;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.json-schema-editor-advanced-modal {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
.json-schema-editor-advanced-modal pre {
|
||||
font-family: monospace;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.json-schema-editor-advanced-modal h3 {
|
||||
display: block;
|
||||
border-left: 3px solid #1890ff;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.json-schema-editor-advanced-modal .ant-advanced-search-form {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.json-schema-editor-advanced-modal .ant-advanced-search-form .ant-form-item .ant-form-item-control-wrapper {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.col-item-setting {
|
||||
padding-top: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tip {
|
||||
padding: 3px 5px;
|
||||
font-size: 16px;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid #783887;
|
||||
margin: 0px 0px 10px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,236 @@
|
|||
<template>
|
||||
<el-dialog :title="$t('api_test.request.parameters_advance')"
|
||||
:visible.sync="itemValueVisible"
|
||||
class="advanced-item-value"
|
||||
width="70%">
|
||||
<el-tabs tab-position="top" style="height: 50vh;" @tab-click="selectTab">
|
||||
<el-tab-pane :label="$t('api_test.request.parameters_advance_mock')">
|
||||
<el-row type="flex" :gutter="20">
|
||||
<el-col :span="6" class="col-height">
|
||||
<div>
|
||||
<el-input size="small" v-model="filterText"
|
||||
:placeholder="$t('api_test.request.parameters_mock_filter_tips')"/>
|
||||
<el-tree class="filter-tree" ref="tree" :data="mockFuncs" :props="treeProps"
|
||||
default-expand-all @node-click="selectVariable"
|
||||
:filter-node-method="filterNode"></el-tree>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6" v-for="(itemFunc, itemIndex) in mockVariableFuncs" :key="itemIndex">
|
||||
<div v-for="(func, funcIndex) in funcs"
|
||||
:key="`${itemIndex}-${funcIndex}`">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-radio size="mini" v-model="itemFunc.name" :label="func.name"
|
||||
@change="methodChange(itemFunc, func)"/>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="itemFunc.name === func.name">
|
||||
<div v-for="(p, pIndex) in itemFunc.params" :key="`${itemIndex}-${funcIndex}-${pIndex}`">
|
||||
<el-input :placeholder="p.name" size="mini" v-model="p.value" @change="showPreview"/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('api_test.variable')">
|
||||
<el-row>
|
||||
<el-col :span="6" class="col-height">
|
||||
<div v-if="preRequestParams">
|
||||
<p>{{ $t('api_test.request.parameters_pre_request') }}</p>
|
||||
<el-tree :data="preRequestParams" :props="treeProps" @node-click="selectVariable"></el-tree>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="18" class="col-height">
|
||||
<div>
|
||||
<h1>{{ $t('api_test.request.jmeter_func') }}</h1>
|
||||
<el-table border :data="jmeterFuncs" class="adjust-table table-content" height="400">
|
||||
<el-table-column prop="type" label="Type" width="150"/>
|
||||
<el-table-column prop="name" label="Functions" width="250"/>
|
||||
<el-table-column prop="description" label="Description"/>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-form>
|
||||
<el-form-item>
|
||||
<el-input :placeholder="valueText" size="small"
|
||||
v-model="itemValue"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="padding-top: 10px;">
|
||||
<el-row type="flex" align="middle">
|
||||
<el-col :span="12">
|
||||
<el-button size="small" type="primary" plain @click="saveAdvanced()">
|
||||
{{ $t('commons.save') }}
|
||||
</el-button>
|
||||
<el-button size="small" type="info" plain @click="addFunc()" v-if="currentTab === 0">
|
||||
{{ $t('api_test.request.parameters_advance_add_func') }}
|
||||
</el-button>
|
||||
<el-button size="small" type="success" plain @click="showPreview()" v-if="currentTab === 0">
|
||||
{{ $t('api_test.request.parameters_preview') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<div> {{ itemValuePreview }}</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {calculate} from "./calculate";
|
||||
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
|
||||
|
||||
export default {
|
||||
name: "MsApiVariableAdvance",
|
||||
props: {
|
||||
parameters: Array,
|
||||
currentItem: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
itemValueVisible: false,
|
||||
filterText: '',
|
||||
environmentParams: [],
|
||||
scenarioParams: [],
|
||||
Scenario: {},
|
||||
preRequests: [],
|
||||
preRequestParams: [],
|
||||
treeProps: {children: 'children', label: 'name'},
|
||||
currentTab: 0,
|
||||
itemValue: null,
|
||||
itemValuePreview: null,
|
||||
funcs: [
|
||||
{name: "md5"},
|
||||
{name: "base64"},
|
||||
{name: "unbase64"},
|
||||
{
|
||||
name: "substr",
|
||||
params: [{name: "start"}, {name: "length"}]
|
||||
},
|
||||
{
|
||||
name: "concat",
|
||||
params: [{name: "suffix"}]
|
||||
},
|
||||
{name: "lconcat", params: [{name: "prefix"}]},
|
||||
{name: "sha1"},
|
||||
{name: "sha224"},
|
||||
{name: "sha256"},
|
||||
{name: "sha384"},
|
||||
{name: "sha512"},
|
||||
{name: "lower"},
|
||||
{name: "upper"},
|
||||
{name: "length"},
|
||||
{name: "number"}
|
||||
],
|
||||
mockFuncs: MOCKJS_FUNC.map(f => {
|
||||
return {name: f.name, value: f.name}
|
||||
}),
|
||||
jmeterFuncs: JMETER_FUNC,
|
||||
mockVariableFuncs: [],
|
||||
jmeterVariableFuncs: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
valueText() {
|
||||
return this.valuePlaceholder || this.$t("api_test.value");
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.prepareData();
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.tree.filter(val);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.itemValueVisible = true;
|
||||
},
|
||||
prepareData() {
|
||||
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data.name.indexOf(value) !== -1;
|
||||
},
|
||||
selectVariable(node) {
|
||||
this.itemValue = node.value;
|
||||
},
|
||||
selectTab(tab) {
|
||||
this.currentTab = +tab.index;
|
||||
this.itemValue = null;
|
||||
this.itemValuePreview = null;
|
||||
},
|
||||
showPreview() {
|
||||
// 找到变量本身
|
||||
if (!this.itemValue) {
|
||||
return;
|
||||
}
|
||||
let index = this.itemValue.indexOf("|");
|
||||
if (index > -1) {
|
||||
this.itemValue = this.itemValue.substring(0, index).trim();
|
||||
}
|
||||
|
||||
this.mockVariableFuncs.forEach(f => {
|
||||
if (!f.name) {
|
||||
return;
|
||||
}
|
||||
this.itemValue += "|" + f.name;
|
||||
if (f.params) {
|
||||
this.itemValue += ":" + f.params.map(p => p.value).join(",");
|
||||
}
|
||||
});
|
||||
|
||||
this.itemValuePreview = calculate(this.itemValue);
|
||||
},
|
||||
methodChange(itemFunc, func) {
|
||||
let index = this.mockVariableFuncs.indexOf(itemFunc);
|
||||
this.mockVariableFuncs = this.mockVariableFuncs.slice(0, index);
|
||||
// 这里要用 deep copy
|
||||
this.mockVariableFuncs.push(JSON.parse(JSON.stringify(func)));
|
||||
this.showPreview();
|
||||
},
|
||||
addFunc() {
|
||||
if (this.mockVariableFuncs.length > 4) {
|
||||
this.$info(this.$t('api_test.request.parameters_advance_add_func_limit'));
|
||||
return;
|
||||
}
|
||||
if (this.mockVariableFuncs.length > 0) {
|
||||
let func = this.mockVariableFuncs[this.mockVariableFuncs.length - 1];
|
||||
if (!func.name) {
|
||||
this.$warning(this.$t('api_test.request.parameters_advance_add_func_error'));
|
||||
return;
|
||||
}
|
||||
if (func.params) {
|
||||
for (let j = 0; j < func.params.length; j++) {
|
||||
if (!func.params[j].value) {
|
||||
this.$warning(this.$t('api_test.request.parameters_advance_add_param_error'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.mockVariableFuncs.push({name: '', params: []});
|
||||
},
|
||||
saveAdvanced() {
|
||||
this.currentItem.mock = this.itemValue;
|
||||
this.itemValueVisible = false;
|
||||
this.mockVariableFuncs = [];
|
||||
this.$emit('advancedRefresh', this.itemValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.col-height {
|
||||
height: 40vh;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,95 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-autocomplete
|
||||
size="small"
|
||||
class="input-with-autocomplete"
|
||||
v-model="mock.mock"
|
||||
:fetch-suggestions="funcSearch"
|
||||
:disabled="disabled"
|
||||
:placeholder="$t('api_test.value')"
|
||||
value-key="name"
|
||||
highlight-first-item
|
||||
@select="change">
|
||||
<i slot="suffix" class="el-input__icon el-icon-edit pointer" @click="advanced()"></i>
|
||||
</el-autocomplete>
|
||||
|
||||
<ms-advance ref="variableAdvance" :current-item="mock"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
|
||||
import MsAdvance from "./Advance";
|
||||
|
||||
export default {
|
||||
name: 'MsMock',
|
||||
components: {MsAdvance},
|
||||
props: {
|
||||
schema: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
}
|
||||
},
|
||||
disabled: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mock: {mock: ""}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.schema.mock && Object.prototype.toString.call(this.schema.mock).match(/\[object (\w+)\]/)[1].toLowerCase() === 'object') {
|
||||
this.mock = this.schema.mock;
|
||||
} else {
|
||||
this.schema.mock = this.mock;
|
||||
}
|
||||
if (this.schema.type === 'object') {
|
||||
this.$delete(this.schema, 'mock')
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
funcSearch(queryString, cb) {
|
||||
let funcs = MOCKJS_FUNC.concat(JMETER_FUNC);
|
||||
let results = queryString ? funcs.filter(this.funcFilter(queryString)) : funcs;
|
||||
// 调用 callback 返回建议列表的数据
|
||||
cb(results);
|
||||
},
|
||||
funcFilter(queryString) {
|
||||
return (func) => {
|
||||
return (func.name.toLowerCase().indexOf(queryString.toLowerCase()) > -1);
|
||||
};
|
||||
},
|
||||
change: function () {
|
||||
},
|
||||
advanced() {
|
||||
this.$refs.variableAdvance.open();
|
||||
},
|
||||
showEdit() {
|
||||
this.$emit('showEdit')
|
||||
},
|
||||
handleChange(e) {
|
||||
this.$emit('change', e)
|
||||
},
|
||||
querySearchAsync(queryString, cb) {
|
||||
const arr = this.mock || []
|
||||
const results = queryString
|
||||
? arr.filter(this.createStateFilter(queryString))
|
||||
: arr
|
||||
|
||||
cb(results)
|
||||
},
|
||||
createStateFilter(queryString) {
|
||||
return state => {
|
||||
return (
|
||||
state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
|
@ -0,0 +1,31 @@
|
|||
import Mock from "mockjs";
|
||||
import {funcFilters} from "@/common/js/func-filter";
|
||||
|
||||
export const calculate = function (itemValue) {
|
||||
if (!itemValue) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (itemValue.trim().startsWith("${")) {
|
||||
// jmeter 内置函数不做处理
|
||||
return itemValue;
|
||||
}
|
||||
let funcs = itemValue.split("|");
|
||||
let value = Mock.mock(funcs[0].trim());
|
||||
if (funcs.length === 1) {
|
||||
return value;
|
||||
}
|
||||
for (let i = 1; i < funcs.length; i++) {
|
||||
let func = funcs[i].trim();
|
||||
let args = func.split(":");
|
||||
let strings = [];
|
||||
if (args[1]) {
|
||||
strings = args[1].split(",");
|
||||
}
|
||||
value = funcFilters[args[0].trim()](value, ...strings);
|
||||
}
|
||||
return value;
|
||||
} catch (e) {
|
||||
return itemValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
const value = {
|
||||
description: null,
|
||||
minItems:null,
|
||||
maxItems:null,
|
||||
uniqueItems:false
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string'
|
||||
},
|
||||
maxItems:{
|
||||
name: '最大元素个数',
|
||||
type: 'integer'
|
||||
},
|
||||
minItems:{
|
||||
name: '最小元素个数',
|
||||
type: 'integer'
|
||||
},
|
||||
uniqueItems:{
|
||||
name:'元素不可重复',
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
|
@ -0,0 +1,11 @@
|
|||
const value = {
|
||||
description: null
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
|
@ -0,0 +1,31 @@
|
|||
const value = {
|
||||
description: null,
|
||||
maximum: null,
|
||||
minimum: null,
|
||||
exclusiveMaximum:null,
|
||||
exclusiveMinimum:null
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string',
|
||||
},
|
||||
maximum:{
|
||||
name:'最大值',
|
||||
type:'integer'
|
||||
},
|
||||
minimum:{
|
||||
name:'最小值',
|
||||
type:'integer'
|
||||
},
|
||||
exclusiveMaximum:{
|
||||
name:'不包含最大值',
|
||||
type:'boolean'
|
||||
},
|
||||
exclusiveMinimum:{
|
||||
name:'不包含最小值',
|
||||
type:'boolean'
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
|
@ -0,0 +1,31 @@
|
|||
const value = {
|
||||
description: null,
|
||||
maximum: null,
|
||||
minimum: null,
|
||||
exclusiveMaximum:null,
|
||||
exclusiveMinimum:null
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string',
|
||||
},
|
||||
maximum:{
|
||||
name:'最大值',
|
||||
type:'number'
|
||||
},
|
||||
minimum:{
|
||||
name:'最小值',
|
||||
type:'number'
|
||||
},
|
||||
exclusiveMaximum:{
|
||||
name:'不包含最大值',
|
||||
type:'boolean'
|
||||
},
|
||||
exclusiveMinimum:{
|
||||
name:'不包含最小值',
|
||||
type:'boolean'
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
|
@ -0,0 +1,21 @@
|
|||
const value = {
|
||||
description: null,
|
||||
maxProperties: null,
|
||||
minProperties: null
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string',
|
||||
},
|
||||
maxProperties:{
|
||||
name:'最大元素个数',
|
||||
type:'integer'
|
||||
},
|
||||
minProperties:{
|
||||
name:'最小元素个数',
|
||||
type:'integer'
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
|
@ -0,0 +1,32 @@
|
|||
const value = {
|
||||
description: null,
|
||||
maxLength: null,
|
||||
minLength: null,
|
||||
pattern: null,
|
||||
format:null
|
||||
}
|
||||
const attr = {
|
||||
description: {
|
||||
name: '描述',
|
||||
type: 'string',
|
||||
},
|
||||
maxLength:{
|
||||
name:'最大字符数',
|
||||
type:'integer'
|
||||
},
|
||||
minLength:{
|
||||
name:'最小字符数',
|
||||
type:'integer'
|
||||
},
|
||||
pattern: {
|
||||
name: '正则表达式',
|
||||
type:'string'
|
||||
},
|
||||
format: {
|
||||
name:'格式',
|
||||
type:'array',
|
||||
enums:['date','date-time','email','hostname','ipv4','ipv6','uri']
|
||||
}
|
||||
}
|
||||
const wrapper = {value, attr}
|
||||
export default wrapper
|
|
@ -0,0 +1,17 @@
|
|||
import _object from './object'
|
||||
import _string from './string'
|
||||
import _array from './array'
|
||||
import _boolean from './boolean'
|
||||
import _integer from './integer'
|
||||
import _number from './number'
|
||||
const TYPE_NAME = ['string', 'number', 'integer','object', 'array', 'boolean']
|
||||
|
||||
const TYPE = {
|
||||
'object': _object,
|
||||
'string': _string,
|
||||
'array': _array,
|
||||
'boolean': _boolean,
|
||||
'integer': _integer,
|
||||
'number': _number
|
||||
}
|
||||
export {TYPE ,TYPE_NAME}
|
|
@ -0,0 +1,24 @@
|
|||
export function clearAttr(obj) {
|
||||
for(let key in obj){
|
||||
delete obj[key]
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 快速拷贝两个对象的属性值
|
||||
* @param {*} source
|
||||
* @param {*} target
|
||||
*/
|
||||
export function copyAttr(source, target){
|
||||
Object.keys(target).forEach(key=>{target[key]=source[key]})
|
||||
}
|
||||
|
||||
export function isNull(ele){
|
||||
if(typeof ele==='undefined'){
|
||||
return true;
|
||||
}else if(ele==null){
|
||||
return true;
|
||||
}else if(ele==''){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import JsonSchemaEditor from './editor/index'
|
||||
const components = [
|
||||
JsonSchemaEditor
|
||||
]
|
||||
|
||||
// 定义 install 方法
|
||||
const install = function (Vue) {
|
||||
if (install.installed) return
|
||||
install.installed = true
|
||||
// 遍历并注册全局组件
|
||||
components.map(component => {
|
||||
Vue.component(component.name, component)
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && window.Vue) {
|
||||
install(window.Vue)
|
||||
}
|
||||
|
||||
export default {
|
||||
// 导出的对象必须具备一个 install 方法
|
||||
install,
|
||||
// 组件列表
|
||||
...components
|
||||
}
|
|
@ -1,211 +0,0 @@
|
|||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-table
|
||||
:data="tableData"
|
||||
style="width: 100%;margin-bottom: 20px;"
|
||||
row-key="id"
|
||||
default-expand-all
|
||||
@cell-click="editor"
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="名称">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.id === tabClickIndex && tabClickProperty === 'name'" v-model="scope.row.name" size="mini" style="padding-left: 20px" @blur="inputBlur(scope.row)"></el-input>
|
||||
<span v-else>{{scope.row.name}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="required"
|
||||
label="必输项"
|
||||
align="center"
|
||||
width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-checkbox v-model="scope.row.required"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="type"
|
||||
width="120px"
|
||||
label="类型">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.type" slot="prepend" size="small">
|
||||
<el-option v-for="item in typeData" :key="item.id" :label="item.label" :value="item.id"/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="value"
|
||||
label="内容">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.id === tabClickIndex && tabClickProperty === 'value'" v-model="scope.row.value" size="mini"></el-input>
|
||||
<span v-else>{{scope.row.value}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="describe"
|
||||
label="描述">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-if="scope.row.id === tabClickIndex && tabClickProperty === 'describe'" v-model="scope.row.describe" size="mini"></el-input>
|
||||
<span v-else>{{scope.row.describe}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="opt"
|
||||
label="操作"
|
||||
width="100">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<i class="el-icon-setting" style="margin-left: 5px;cursor: pointer" @click="setting(scope.row)"/>
|
||||
<i class="el-icon-plus" style="margin-left: 5px;cursor: pointer" @click="add(scope.row)"/>
|
||||
<i class="el-icon-close" style="margin-left: 5px;cursor: pointer" @click="deleteRow(scope.row)"/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "MsJsonTable",
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
tableData: [{
|
||||
id: "root",
|
||||
parent: null,
|
||||
name: 'root',
|
||||
required: true,
|
||||
type: 'object',
|
||||
value: 'object',
|
||||
describe: 'describe',
|
||||
editor: false,
|
||||
children: [],
|
||||
}]
|
||||
,
|
||||
tabClickProperty: "",
|
||||
tabClickIndex: "",
|
||||
typeData: [
|
||||
{id: 'string', label: 'string'},
|
||||
{id: 'number', label: 'number'},
|
||||
{id: 'array', label: 'array'},
|
||||
{id: 'object', label: 'object'},
|
||||
{id: 'boolean', label: 'boolean'},
|
||||
{id: 'integer', label: 'integer'}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editor(row, column) {
|
||||
switch (column.property) {
|
||||
case 'name':
|
||||
this.tabClickIndex = row.id
|
||||
this.tabClickProperty = column.property
|
||||
break
|
||||
case 'value':
|
||||
this.tabClickIndex = row.id
|
||||
this.tabClickProperty = column.property
|
||||
break;
|
||||
case 'describe':
|
||||
this.tabClickIndex = row.id
|
||||
this.tabClickProperty = column.property
|
||||
break;
|
||||
default:
|
||||
return
|
||||
}
|
||||
},
|
||||
inputBlur() {
|
||||
this.tabClickIndex = null;
|
||||
this.tabClickProperty = '';
|
||||
this.reload();
|
||||
},
|
||||
reload() {
|
||||
this.loading = true;
|
||||
this.$nextTick(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
setting() {
|
||||
|
||||
},
|
||||
add(row) {
|
||||
let obj = {
|
||||
id: getUUID(),
|
||||
name: 'field',
|
||||
required: true,
|
||||
type: 'string',
|
||||
value: 'test',
|
||||
parent: null,
|
||||
describe: 'describe',
|
||||
children: [],
|
||||
}
|
||||
console.log("all", this.tableData)
|
||||
console.log("row", row)
|
||||
|
||||
if (row.type === "object") {
|
||||
obj.parent = row.id;
|
||||
row.children.push(obj);
|
||||
return;
|
||||
}
|
||||
let parentRow = {};
|
||||
const index = this.tableData.findIndex(d => d.id != undefined && row.parent != undefined && d.id === row.parent);
|
||||
if (index != -1) {
|
||||
parentRow = this.tableData[index];
|
||||
} else {
|
||||
for (let i in this.tableData) {
|
||||
if (this.tableData[i].children) {
|
||||
parentRow = this.recursiveRemove(this.tableData[i].children, row);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(parentRow)
|
||||
if (parentRow) {
|
||||
obj.parent = parentRow.id;
|
||||
parentRow.children.push(obj);
|
||||
return;
|
||||
}
|
||||
this.tableData.push(obj);
|
||||
},
|
||||
recursiveRemove(arr, row) {
|
||||
for (let i in arr) {
|
||||
const index = arr.findIndex(d => d.id != undefined && row.id != undefined && d.id === row.id)
|
||||
if (index != -1) {
|
||||
arr.splice(index, 1);
|
||||
return arr[i];
|
||||
}
|
||||
if (arr[i].children != undefined && arr[i].children.length > 0) {
|
||||
this.recursiveRemove(arr[i].children, row);
|
||||
}
|
||||
}
|
||||
},
|
||||
deleteRow(row) {
|
||||
const index = this.tableData.findIndex(d => d.id != undefined && row.id != undefined && d.id === row.id)
|
||||
if (index == -1) {
|
||||
this.tableData.forEach(item => {
|
||||
if (item.children) {
|
||||
this.recursiveRemove(item.children, row);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.tableData.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.name-input >>> .el-input__inner {
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
}
|
||||
</style>
|
|
@ -84,7 +84,6 @@ export default {
|
|||
methods: {
|
||||
registerEvents() {
|
||||
PerformanceEvent.$on(LIST_CHANGE, () => {
|
||||
// // todo 这里偶尔会有 refs 为空的情况
|
||||
this.$refs.testRecent.recent();
|
||||
this.$refs.reportRecent.recent();
|
||||
});
|
||||
|
@ -92,6 +91,9 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
this.registerEvents();
|
||||
},
|
||||
beforeDestroy() {
|
||||
PerformanceEvent.$off(LIST_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ export default {
|
|||
tableData: [],
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
loading: false,
|
||||
testId: null,
|
||||
|
|
|
@ -108,7 +108,7 @@ export default {
|
|||
tableData: [],
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
loading: false,
|
||||
testId: null,
|
||||
|
|
|
@ -143,7 +143,7 @@
|
|||
},
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
options: [],
|
||||
loading: false,
|
||||
|
|
|
@ -458,10 +458,10 @@
|
|||
items: [],
|
||||
userList: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
dialogCurrentPage: 1,
|
||||
dialogPageSize: 5,
|
||||
dialogPageSize: 10,
|
||||
dialogTotal: 0,
|
||||
memberLineData: [],
|
||||
memberForm: {},
|
||||
|
|
|
@ -120,7 +120,7 @@ export default {
|
|||
zentao: false,
|
||||
form: {},
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
rules: {
|
||||
name: [
|
||||
|
|
|
@ -36,16 +36,23 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col>
|
||||
<el-form-item :label="$t('system_parameter_setting.test_recipients')">
|
||||
<el-input v-model="formInline.recipient" :placeholder="$t('system_parameter_setting.test_recipients')"
|
||||
autocomplete="new-password" show-password type="text" ref="input">
|
||||
</el-input>
|
||||
<p style="color: #8a8b8d">({{ $t('system_parameter_setting.tip') }})</p>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!---->
|
||||
<div style="border: 0px;margin-bottom: 20px;margin-top: 20px">
|
||||
<el-checkbox v-model="formInline.SSL" :label="$t('system_parameter_setting.SSL')"></el-checkbox>
|
||||
<div style="border: 0px;margin-bottom: 20px">
|
||||
<el-checkbox v-model="formInline.ssl" :label="$t('system_parameter_setting.SSL')"></el-checkbox>
|
||||
</div>
|
||||
<div style="border: 0px;margin-bottom: 20px">
|
||||
<el-checkbox v-model="formInline.TLS" :label="$t('system_parameter_setting.TLS')"></el-checkbox>
|
||||
</div>
|
||||
<div style="border: 0px;margin-bottom: 20px">
|
||||
<el-checkbox v-model="formInline.ANON" :label="$t('system_parameter_setting.SMTP')"></el-checkbox>
|
||||
<el-checkbox v-model="formInline.tls" :label="$t('system_parameter_setting.TLS')"></el-checkbox>
|
||||
</div>
|
||||
<template v-slot:footer>
|
||||
</template>
|
||||
|
@ -114,13 +121,10 @@ export default {
|
|||
},
|
||||
query() {
|
||||
this.result = this.$get("/system/mail/info", response => {
|
||||
this.$set(this.formInline, "host", response.data[0].paramValue);
|
||||
this.$set(this.formInline, "port", response.data[1].paramValue);
|
||||
this.$set(this.formInline, "account", response.data[2].paramValue);
|
||||
this.$set(this.formInline, "password", response.data[3].paramValue);
|
||||
this.$set(this.formInline, "SSL", JSON.parse(response.data[4].paramValue));
|
||||
this.$set(this.formInline, "TLS", JSON.parse(response.data[5].paramValue));
|
||||
this.$set(this.formInline, "ANON", JSON.parse(response.data[6].paramValue));
|
||||
this.formInline = response.data;
|
||||
this.formInline.ssl = this.formInline.ssl === 'true';
|
||||
this.formInline.tls = this.formInline.tls === 'true';
|
||||
console.log(this.formInline)
|
||||
this.$nextTick(() => {
|
||||
this.$refs.formInline.clearValidate();
|
||||
})
|
||||
|
@ -137,13 +141,13 @@ export default {
|
|||
},
|
||||
testConnection(formInline) {
|
||||
let param = {
|
||||
"smtp.server": this.formInline.host,
|
||||
"smtp.host": this.formInline.host,
|
||||
"smtp.port": this.formInline.port,
|
||||
"smtp.account": this.formInline.account,
|
||||
"smtp.password": this.formInline.password,
|
||||
"smtp.ssl": this.formInline.SSL,
|
||||
"smtp.tls": this.formInline.TLS,
|
||||
"smtp.anon": this.formInline.ANON,
|
||||
"smtp.ssl": this.formInline.ssl,
|
||||
"smtp.tls": this.formInline.tls,
|
||||
"smtp.recipient": this.formInline.recipient,
|
||||
};
|
||||
this.$refs[formInline].validate((valid) => {
|
||||
if (valid) {
|
||||
|
@ -171,9 +175,10 @@ export default {
|
|||
{paramKey: "smtp.port", paramValue: this.formInline.port, type: "text", sort: 2},
|
||||
{paramKey: "smtp.account", paramValue: this.formInline.account, type: "text", sort: 3},
|
||||
{paramKey: "smtp.password", paramValue: this.formInline.password, type: "password", sort: 4},
|
||||
{paramKey: "smtp.ssl", paramValue: this.formInline.SSL, type: "text", sort: 5},
|
||||
{paramKey: "smtp.tls", paramValue: this.formInline.TLS, type: "text", sort: 6},
|
||||
{paramKey: "smtp.anon", paramValue: this.formInline.ANON, type: "text", sort: 7}
|
||||
{paramKey: "smtp.ssl", paramValue: this.formInline.ssl, type: "text", sort: 5},
|
||||
{paramKey: "smtp.tls", paramValue: this.formInline.tls, type: "text", sort: 6},
|
||||
{paramKey: "smtp.recipient", paramValue: this.formInline.recipient, type: "text", sort: 8}
|
||||
|
||||
]
|
||||
|
||||
this.$refs[formInline].validate(valid => {
|
||||
|
|
|
@ -218,10 +218,10 @@ export default {
|
|||
dialogOrgMemberUpdateVisible: false,
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
dialogCurrentPage: 1,
|
||||
dialogPageSize: 5,
|
||||
dialogPageSize: 10,
|
||||
dialogTotal: 0,
|
||||
currentRow: {},
|
||||
condition: {},
|
||||
|
|
|
@ -487,10 +487,10 @@
|
|||
dialogCondition: {},
|
||||
items: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
dialogCurrentPage: 1,
|
||||
dialogPageSize: 5,
|
||||
dialogPageSize: 10,
|
||||
dialogTotal: 0,
|
||||
memberLineData: [],
|
||||
memberForm: {},
|
||||
|
|
|
@ -177,7 +177,7 @@ export default {
|
|||
condition: {},
|
||||
items: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
form: {},
|
||||
requiredRules: [{required: true, message: this.$t('test_resource_pool.fill_the_data'), trigger: 'blur'}],
|
||||
|
|
|
@ -367,7 +367,7 @@ export default {
|
|||
multipleSelection: [],
|
||||
userRole: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
condition: {},
|
||||
tableData: [],
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
},
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
}
|
||||
},
|
||||
|
|
|
@ -66,9 +66,6 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
result: {},
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
total: 0,
|
||||
projects: [],
|
||||
treeNodes: [],
|
||||
selectNodeIds: [],
|
||||
|
|
|
@ -62,7 +62,7 @@ export default {
|
|||
id: '',
|
||||
condition: {},
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
url: '',
|
||||
type: ''
|
||||
|
|
|
@ -131,11 +131,13 @@ export default {
|
|||
},
|
||||
registerEvents() {
|
||||
TrackEvent.$on(LIST_CHANGE, () => {
|
||||
// // todo 这里偶尔会有 refs 为空的情况
|
||||
this.$refs.planRecent.recent();
|
||||
this.$refs.caseRecent.recent();
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
TrackEvent.$off(LIST_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="num" label="ID" show-overflow-tooltip/>
|
||||
<el-table-column prop="name" :label="$t('api_test.definition.api_name')" show-overflow-tooltip/>
|
||||
|
||||
<el-table-column
|
||||
|
|
|
@ -59,7 +59,11 @@
|
|||
<style scoped>
|
||||
|
||||
.el-dialog {
|
||||
min-height: 700px;
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.tree-aside {
|
||||
max-height: 600px;
|
||||
}
|
||||
|
||||
.el-dialog >>> .el-dialog__body {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<template>
|
||||
<ckeditor v-if="!isReportView" :editor="editor" v-model="preview.content" :config="editorConfig"></ckeditor>
|
||||
<div v-if="isReportView" v-html="preview.content"></div>
|
||||
<div class="rich-text-content" v-if="isReportView" v-html="preview.content"></div>
|
||||
</template>
|
||||
|
||||
</common-component>
|
||||
|
@ -53,4 +53,11 @@
|
|||
|
||||
<style scoped>
|
||||
|
||||
.rich-text-content >>> .table td {
|
||||
border: solid 1px #e6e6e6;
|
||||
min-width: 2em;
|
||||
padding: .4em;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
|
|
@ -19,6 +19,8 @@ import '../common/css/main.css';
|
|||
import CKEditor from '@ckeditor/ckeditor5-vue';
|
||||
import VueFab from 'vue-float-action-button'
|
||||
import {horizontalDrag} from "../common/js/directive";
|
||||
import JsonSchemaEditor from './components/common/json-schema/schema/index';
|
||||
Vue.use(JsonSchemaEditor);
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
Vue.use(icon);
|
||||
|
|
|
@ -120,7 +120,6 @@ html,body {
|
|||
padding-right: 60px;
|
||||
}
|
||||
|
||||
|
||||
/* 滚动条样式 */
|
||||
::-webkit-scrollbar{
|
||||
width: 5px;
|
||||
|
@ -137,3 +136,36 @@ html,body {
|
|||
background-color: transparent;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
/* <-- 表格全选样式 */
|
||||
.ms-select-all th:first-child {
|
||||
border: 1px solid #DCDFE6;
|
||||
border-radius:5px;
|
||||
padding: 0px;
|
||||
margin-top: 10px;
|
||||
display: inline-block;
|
||||
/*margin-top: 25px;*/
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.ms-select-all th:nth-child(2) {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.ms-select-all th:first-child>.cell {
|
||||
padding: 5px;
|
||||
width: 35px;
|
||||
}
|
||||
|
||||
.ms-select-all th:nth-child(2)>.cell {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.ms-select-all .el-icon-arrow-down {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
top: -7px;
|
||||
left: -38px;
|
||||
width: 30px;
|
||||
}
|
||||
/* 表格全选样式 --> */
|
||||
|
|
|
@ -489,7 +489,7 @@ export default {
|
|||
file_exist: "The name already exists in the project",
|
||||
upload_limit_size: "Upload file size cannot exceed 30MB!",
|
||||
},
|
||||
batch_menus:{
|
||||
batch_menus: {
|
||||
select_all_data: "Select all datas({0})",
|
||||
select_show_data: "Select show datas({0})",
|
||||
},
|
||||
|
@ -505,9 +505,9 @@ export default {
|
|||
api_case_status: "Ise case status",
|
||||
api_case_passing_rate: "Use case pass rate",
|
||||
create_tip: "Note: Detailed interface information can be filled out on the edit page",
|
||||
select_comp:{
|
||||
no_data:"No Data",
|
||||
add_data:"Add Data"
|
||||
select_comp: {
|
||||
no_data: "No Data",
|
||||
add_data: "Add Data"
|
||||
},
|
||||
request: {
|
||||
grade_info: "Filter by rank",
|
||||
|
@ -1254,6 +1254,8 @@ export default {
|
|||
host: 'Host number cannot be empty',
|
||||
port: 'Port cannot be empty',
|
||||
account: 'Account cannot be empty',
|
||||
test_recipients:'Test recipients',
|
||||
tip:'Tip: use as test mail recipient only',
|
||||
|
||||
},
|
||||
i18n: {
|
||||
|
@ -1365,5 +1367,47 @@ export default {
|
|||
workspace_quota_list: "Workspace quota list of {0}",
|
||||
unlimited: "Unlimited",
|
||||
clean: "Clean"
|
||||
},
|
||||
schema: {
|
||||
title: "Title",
|
||||
import_json: "Import JSON",
|
||||
base_setting: "Base Setting",
|
||||
all_setting: "Source Code",
|
||||
default: "Default",
|
||||
description: "Description",
|
||||
"adv_setting": "Advanced Settings",
|
||||
"add_child_node": "Add child node",
|
||||
add_sibling_node: "Add sibling nodes",
|
||||
add_node: "Add sibling/child nodes",
|
||||
remove_node: "Remove node",
|
||||
child_node: "Child node",
|
||||
sibling_node: "Sibling node",
|
||||
ok: "OK",
|
||||
cancel: "Cancel",
|
||||
minLength: "Min length",
|
||||
maxLength: "Max length",
|
||||
pattern: "MUST be a valid regular expression.",
|
||||
exclusiveMinimum: "Value strictly less than",
|
||||
exclusiveMaximum: "Value strictly more than",
|
||||
minimum: "Min",
|
||||
maximum: "Max",
|
||||
uniqueItems: "Unique Items",
|
||||
minItems: "MinItems",
|
||||
maxItems: "MaxItems",
|
||||
minProperties: "MinProperties",
|
||||
maxProperties: "MaxProperties",
|
||||
checked_all: "Checked All",
|
||||
valid_json: "Not valid json",
|
||||
enum: "Enum",
|
||||
enum_msg: "One value per line",
|
||||
enum_desc: "desc",
|
||||
enum_desc_msg: "enum description",
|
||||
required: "Required",
|
||||
mock: "mock",
|
||||
mockLink: "Help",
|
||||
format: "Format",
|
||||
nothing: "Nothing",
|
||||
preview: "Preview",
|
||||
add_custom: "Add Custom Prop"
|
||||
}
|
||||
};
|
||||
|
|
|
@ -487,7 +487,7 @@ export default {
|
|||
file_exist: "该项目下已存在该jar包",
|
||||
upload_limit_size: "上传文件大小不能超过 30MB!",
|
||||
},
|
||||
batch_menus:{
|
||||
batch_menus: {
|
||||
select_all_data: "选择所有数据(共{0}条)",
|
||||
select_show_data: "选择可见数据(共{0}条)",
|
||||
},
|
||||
|
@ -503,9 +503,9 @@ export default {
|
|||
api_case_status: "用例状态",
|
||||
api_case_passing_rate: "用例通过率",
|
||||
create_tip: "注: 详细的接口信息可以在编辑页面填写",
|
||||
select_comp:{
|
||||
no_data:"无数据",
|
||||
add_data:"去添加"
|
||||
select_comp: {
|
||||
no_data: "无数据",
|
||||
add_data: "去添加"
|
||||
},
|
||||
request: {
|
||||
grade_info: "按等级筛选",
|
||||
|
@ -1255,6 +1255,8 @@ export default {
|
|||
host: '主机号不能为空',
|
||||
port: '端口号不能为空',
|
||||
account: '账户不能为空',
|
||||
test_recipients:'测试收件人',
|
||||
tip:'提示:仅用来作为测试邮件收件人',
|
||||
},
|
||||
i18n: {
|
||||
home: '首页',
|
||||
|
@ -1365,5 +1367,47 @@ export default {
|
|||
workspace_quota_list: "{0}的工作空间配额列表",
|
||||
unlimited: "无限制",
|
||||
clean: "清空"
|
||||
},
|
||||
schema: {
|
||||
title: "标题",
|
||||
import_json: "导入 json",
|
||||
base_setting: "基础设置",
|
||||
all_setting: "编辑源码",
|
||||
default: "默认值",
|
||||
description: "描述",
|
||||
adv_setting: "高级设置",
|
||||
add_child_node: "添加子节点",
|
||||
add_sibling_node: "添加兄弟节点",
|
||||
add_node: "添加兄弟/子节点",
|
||||
remove_node: "删除节点",
|
||||
child_node: "子节点",
|
||||
sibling_node: "兄弟节点",
|
||||
ok: "确定",
|
||||
cancel: "取消",
|
||||
minLength: "最小长度",
|
||||
maxLength: "最大长度",
|
||||
pattern: "用正则表达式约束字符串",
|
||||
exclusiveMinimum: "开启后,数据必须大于最小值",
|
||||
exclusiveMaximum: "开启后,数据必须小于最大值",
|
||||
minimum: "最小值",
|
||||
maximum: "最大值",
|
||||
uniqueItems: "开启后,每个元素都不相同",
|
||||
minItems: "最小元素个数",
|
||||
maxItems: "最大元素个数",
|
||||
minProperties: "最小元素个数",
|
||||
maxProperties: "最大元素个数",
|
||||
checked_all: "全选",
|
||||
valid_json: "不是合法的json字符串",
|
||||
enum: "枚举",
|
||||
enum_msg: "每行只能写一个值",
|
||||
enum_desc: "备注",
|
||||
enum_desc_msg: "备注描述信息",
|
||||
required: "是否必须",
|
||||
mock: "mock",
|
||||
mockLink: "查看文档",
|
||||
format: "格式化",
|
||||
nothing: "无",
|
||||
preview: "预览",
|
||||
add_custom: "添加自定义属性"
|
||||
}
|
||||
};
|
||||
|
|
|
@ -487,7 +487,7 @@ export default {
|
|||
file_exist: "該項目下已存在該jar包",
|
||||
upload_limit_size: "上傳文件大小不能超過 30MB!",
|
||||
},
|
||||
batch_menus:{
|
||||
batch_menus: {
|
||||
select_all_data: "選擇所有數據(共{0}條)",
|
||||
select_show_data: "選擇可見數據(共{0}條)",
|
||||
},
|
||||
|
@ -503,9 +503,9 @@ export default {
|
|||
api_case_status: "用例狀態",
|
||||
api_case_passing_rate: "用例通過率",
|
||||
create_tip: "註: 詳細的接口信息可以在編輯頁面填寫",
|
||||
select_comp:{
|
||||
no_data:"無數據",
|
||||
add_data:"去添加"
|
||||
select_comp: {
|
||||
no_data: "無數據",
|
||||
add_data: "去添加"
|
||||
},
|
||||
request: {
|
||||
grade_info: "按等級筛选",
|
||||
|
@ -1254,6 +1254,8 @@ export default {
|
|||
host: '主機號不能為空',
|
||||
port: '端口號不能為空',
|
||||
account: '賬戶不能為空',
|
||||
test_recipients:'測試收件人',
|
||||
tip:'提示:僅用來作為測試郵件收件人',
|
||||
},
|
||||
i18n: {
|
||||
home: '首頁',
|
||||
|
@ -1364,5 +1366,47 @@ export default {
|
|||
workspace_quota_list: "{0}的工作空間配額列表",
|
||||
unlimited: "無限制",
|
||||
clean: "清空"
|
||||
},
|
||||
schema: {
|
||||
title: "标题",
|
||||
import_json: "导入 json",
|
||||
base_setting: "基础设置",
|
||||
all_setting: "编辑源码",
|
||||
default: "默认值",
|
||||
description: "描述",
|
||||
adv_setting: "高级设置",
|
||||
add_child_node: "添加子节点",
|
||||
add_sibling_node: "添加兄弟节点",
|
||||
add_node: "添加兄弟/子节点",
|
||||
remove_node: "删除节点",
|
||||
child_node: "子节点",
|
||||
sibling_node: "兄弟节点",
|
||||
ok: "确定",
|
||||
cancel: "取消",
|
||||
minLength: "最小长度",
|
||||
maxLength: "最大长度",
|
||||
pattern: "用正则表达式约束字符串",
|
||||
exclusiveMinimum: "开启后,数据必须大于最小值",
|
||||
exclusiveMaximum: "开启后,数据必须小于最大值",
|
||||
minimum: "最小值",
|
||||
maximum: "最大值",
|
||||
uniqueItems: "开启后,每个元素都不相同",
|
||||
minItems: "最小元素个数",
|
||||
maxItems: "最大元素个数",
|
||||
minProperties: "最小元素个数",
|
||||
maxProperties: "最大元素个数",
|
||||
checked_all: "全选",
|
||||
valid_json: "不是合法的json字符串",
|
||||
enum: "枚举",
|
||||
enum_msg: "每行只能写一个值",
|
||||
enum_desc: "备注",
|
||||
enum_desc_msg: "备注描述信息",
|
||||
required: "是否必须",
|
||||
mock: "mock",
|
||||
mockLink: "查看文档",
|
||||
format: "格式化",
|
||||
nothing: "无",
|
||||
preview: "预览",
|
||||
add_custom: "添加自定义属性"
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue