feat(接口测试): 环境变量增加导入导出 (#17018)
--story=1008922 --user=王孝刚 【接口测试】环境参数的查询功能,以及场景变量和环境参数的导入导出功能; https://www.tapd.cn/55049933/s/1220274 Co-authored-by: wxg0103 <727495428@qq.com>
This commit is contained in:
parent
07ea672ff9
commit
81955c649a
|
@ -65,16 +65,18 @@ public class ApiTestEnvironmentController {
|
||||||
|
|
||||||
@PostMapping("/add")
|
@PostMapping("/add")
|
||||||
@MsAuditLog(module = OperLogModule.PROJECT_ENVIRONMENT_SETTING, type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#apiTestEnvironmentWithBLOBs.id)", msClass = ApiTestEnvironmentService.class)
|
@MsAuditLog(module = OperLogModule.PROJECT_ENVIRONMENT_SETTING, type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#apiTestEnvironmentWithBLOBs.id)", msClass = ApiTestEnvironmentService.class)
|
||||||
public String create(@RequestPart("request") ApiTestEnvironmentDTO apiTestEnvironmentWithBLOBs, @RequestPart(value = "files", required = false) List<MultipartFile> sslFiles) {
|
public String create(@RequestPart("request") ApiTestEnvironmentDTO apiTestEnvironmentWithBLOBs, @RequestPart(value = "files", required = false) List<MultipartFile> sslFiles,
|
||||||
|
@RequestPart(value = "variablesFiles", required = false) List<MultipartFile> variableFile) {
|
||||||
checkParams(apiTestEnvironmentWithBLOBs);
|
checkParams(apiTestEnvironmentWithBLOBs);
|
||||||
return apiTestEnvironmentService.add(apiTestEnvironmentWithBLOBs, sslFiles);
|
return apiTestEnvironmentService.add(apiTestEnvironmentWithBLOBs, sslFiles, variableFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/update")
|
@PostMapping(value = "/update")
|
||||||
@MsAuditLog(module = OperLogModule.PROJECT_ENVIRONMENT_SETTING, type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#apiTestEnvironment.id)", content = "#msClass.getLogDetails(#apiTestEnvironment.id)", msClass = ApiTestEnvironmentService.class)
|
@MsAuditLog(module = OperLogModule.PROJECT_ENVIRONMENT_SETTING, type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#apiTestEnvironment.id)", content = "#msClass.getLogDetails(#apiTestEnvironment.id)", msClass = ApiTestEnvironmentService.class)
|
||||||
public void update(@RequestPart("request") ApiTestEnvironmentDTO apiTestEnvironment, @RequestPart(value = "files", required = false) List<MultipartFile> sslFiles) {
|
public void update(@RequestPart("request") ApiTestEnvironmentDTO apiTestEnvironment, @RequestPart(value = "files", required = false) List<MultipartFile> sslFiles,
|
||||||
|
@RequestPart(value = "variablesFiles", required = false) List<MultipartFile> variableFile) {
|
||||||
checkParams(apiTestEnvironment);
|
checkParams(apiTestEnvironment);
|
||||||
apiTestEnvironmentService.update(apiTestEnvironment, sslFiles);
|
apiTestEnvironmentService.update(apiTestEnvironment, sslFiles, variableFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkParams(ApiTestEnvironmentDTO apiTestEnvironment) {
|
private void checkParams(ApiTestEnvironmentDTO apiTestEnvironment) {
|
||||||
|
|
|
@ -8,4 +8,5 @@ import java.util.List;
|
||||||
@Data
|
@Data
|
||||||
public class ApiTestEnvironmentDTO extends ApiTestEnvironmentWithBLOBs {
|
public class ApiTestEnvironmentDTO extends ApiTestEnvironmentWithBLOBs {
|
||||||
private List<String> uploadIds;
|
private List<String> uploadIds;
|
||||||
|
private List<String> variablesFilesIds;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import io.metersphere.api.dto.EnvironmentType;
|
||||||
import io.metersphere.api.dto.definition.request.controller.MsLoopController;
|
import io.metersphere.api.dto.definition.request.controller.MsLoopController;
|
||||||
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
||||||
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
||||||
import io.metersphere.api.dto.scenario.KeyValue;
|
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||||
import io.metersphere.api.dto.scenario.request.BodyFile;
|
import io.metersphere.api.dto.scenario.request.BodyFile;
|
||||||
import io.metersphere.api.service.ApiTestEnvironmentService;
|
import io.metersphere.api.service.ApiTestEnvironmentService;
|
||||||
|
@ -69,7 +68,7 @@ public class ElementUtil {
|
||||||
arguments.setName(StringUtils.isNoneBlank(name) ? name : "Arguments");
|
arguments.setName(StringUtils.isNoneBlank(name) ? name : "Arguments");
|
||||||
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
||||||
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
|
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
|
||||||
config.getConfig().get(projectId).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
|
config.getConfig().get(projectId).getCommonConfig().getVariables().stream().filter(ScenarioVariable::isConstantValid).filter(ScenarioVariable::isEnable).forEach(keyValue ->
|
||||||
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
|
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
|
||||||
);
|
);
|
||||||
if (arguments.getArguments().size() > 0) {
|
if (arguments.getArguments().size() > 0) {
|
||||||
|
@ -101,9 +100,9 @@ public class ElementUtil {
|
||||||
|
|
||||||
public static void addCsvDataSet(HashTree tree, List<ScenarioVariable> variables, ParameterConfig config, String shareMode) {
|
public static void addCsvDataSet(HashTree tree, List<ScenarioVariable> variables, ParameterConfig config, String shareMode) {
|
||||||
if (CollectionUtils.isNotEmpty(variables)) {
|
if (CollectionUtils.isNotEmpty(variables)) {
|
||||||
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isCSVValid).collect(Collectors.toList());
|
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isCSVValid).filter(ScenarioVariable::isEnable).collect(Collectors.toList());
|
||||||
if (CollectionUtils.isEmpty(list) && CollectionUtils.isNotEmpty(config.getTransferVariables())) {
|
if (CollectionUtils.isEmpty(list) && CollectionUtils.isNotEmpty(config.getTransferVariables())) {
|
||||||
list = config.getTransferVariables().stream().filter(ScenarioVariable::isCSVValid).collect(Collectors.toList());
|
list = config.getTransferVariables().stream().filter(ScenarioVariable::isCSVValid).filter(ScenarioVariable::isEnable).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(list)) {
|
if (CollectionUtils.isNotEmpty(list)) {
|
||||||
list.forEach(item -> {
|
list.forEach(item -> {
|
||||||
|
@ -140,7 +139,7 @@ public class ElementUtil {
|
||||||
|
|
||||||
public static void addCounter(HashTree tree, List<ScenarioVariable> variables, boolean isInternal) {
|
public static void addCounter(HashTree tree, List<ScenarioVariable> variables, boolean isInternal) {
|
||||||
if (CollectionUtils.isNotEmpty(variables)) {
|
if (CollectionUtils.isNotEmpty(variables)) {
|
||||||
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isCounterValid).collect(Collectors.toList());
|
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isCounterValid).filter(ScenarioVariable::isEnable).collect(Collectors.toList());
|
||||||
if (CollectionUtils.isNotEmpty(list)) {
|
if (CollectionUtils.isNotEmpty(list)) {
|
||||||
list.forEach(item -> {
|
list.forEach(item -> {
|
||||||
CounterConfig counterConfig = new CounterConfig();
|
CounterConfig counterConfig = new CounterConfig();
|
||||||
|
@ -166,7 +165,7 @@ public class ElementUtil {
|
||||||
|
|
||||||
public static void addRandom(HashTree tree, List<ScenarioVariable> variables) {
|
public static void addRandom(HashTree tree, List<ScenarioVariable> variables) {
|
||||||
if (CollectionUtils.isNotEmpty(variables)) {
|
if (CollectionUtils.isNotEmpty(variables)) {
|
||||||
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isRandom).collect(Collectors.toList());
|
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isRandom).filter(ScenarioVariable::isEnable).collect(Collectors.toList());
|
||||||
if (CollectionUtils.isNotEmpty(list)) {
|
if (CollectionUtils.isNotEmpty(list)) {
|
||||||
list.forEach(item -> {
|
list.forEach(item -> {
|
||||||
RandomVariableConfig randomVariableConfig = new RandomVariableConfig();
|
RandomVariableConfig randomVariableConfig = new RandomVariableConfig();
|
||||||
|
@ -794,4 +793,62 @@ public class ElementUtil {
|
||||||
return evlValue;
|
return evlValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Arguments getConfigArguments(ParameterConfig config, String name, String projectId, List<ScenarioVariable> variables) {
|
||||||
|
Arguments arguments = new Arguments();
|
||||||
|
arguments.setEnabled(true);
|
||||||
|
arguments.setName(StringUtils.isNotEmpty(name) ? name : "Arguments");
|
||||||
|
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
||||||
|
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
|
||||||
|
|
||||||
|
// 场景变量
|
||||||
|
if (CollectionUtils.isNotEmpty(variables)) {
|
||||||
|
variables.stream().filter(ScenarioVariable::isConstantValid).forEach(keyValue ->
|
||||||
|
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
|
||||||
|
);
|
||||||
|
|
||||||
|
List<ScenarioVariable> variableList = variables.stream().filter(ScenarioVariable::isListValid).collect(Collectors.toList());
|
||||||
|
variableList.forEach(item -> {
|
||||||
|
String[] arrays = item.getValue().split(",");
|
||||||
|
for (int i = 0; i < arrays.length; i++) {
|
||||||
|
arguments.addArgument(item.getName() + "_" + (i + 1), arrays[i], "=");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 环境通用变量
|
||||||
|
if (config.isEffective(projectId) && config.getConfig().get(projectId).getCommonConfig() != null
|
||||||
|
&& CollectionUtils.isNotEmpty(config.getConfig().get(projectId).getCommonConfig().getVariables())) {
|
||||||
|
//常量
|
||||||
|
List<ScenarioVariable> constants = config.getConfig().get(projectId).getCommonConfig().getVariables().stream().filter(ScenarioVariable::isConstantValid).filter(ScenarioVariable::isEnable).collect(Collectors.toList());
|
||||||
|
constants.forEach(keyValue ->
|
||||||
|
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
|
||||||
|
);
|
||||||
|
// List类型的变量
|
||||||
|
List<ScenarioVariable> variableList = config.getConfig().get(projectId).getCommonConfig().getVariables().stream().filter(ScenarioVariable::isListValid).filter(ScenarioVariable::isEnable).collect(Collectors.toList());
|
||||||
|
variableList.forEach(item -> {
|
||||||
|
String[] arrays = item.getValue().split(",");
|
||||||
|
for (int i = 0; i < arrays.length; i++) {
|
||||||
|
arguments.addArgument(item.getName() + "_" + (i + 1), arrays[i], "=");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 清空变量,防止重复添加
|
||||||
|
config.getConfig().get(projectId).getCommonConfig().getVariables().remove(constants);
|
||||||
|
config.getConfig().get(projectId).getCommonConfig().getVariables().remove(variableList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments.getArguments() != null && arguments.getArguments().size() > 0) {
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addOtherVariables(ParameterConfig config, HashTree httpSamplerTree, String projectId) {
|
||||||
|
if (config.isEffective(projectId) && config.getConfig().get(projectId).getCommonConfig() != null
|
||||||
|
&& CollectionUtils.isNotEmpty(config.getConfig().get(projectId).getCommonConfig().getVariables())) {
|
||||||
|
ElementUtil.addCsvDataSet(httpSamplerTree, config.getConfig().get(projectId).getCommonConfig().getVariables(), config, "shareMode.group");
|
||||||
|
ElementUtil.addCounter(httpSamplerTree, config.getConfig().get(projectId).getCommonConfig().getVariables(), false);
|
||||||
|
ElementUtil.addRandom(httpSamplerTree, config.getConfig().get(projectId).getCommonConfig().getVariables());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@ import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ -127,7 +126,7 @@ public class MsScenario extends MsTestElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(this.getVariables()) && (this.variableEnable == null || this.variableEnable)) {
|
if (CollectionUtils.isNotEmpty(this.getVariables()) && (this.variableEnable == null || this.variableEnable)) {
|
||||||
config.setVariables(this.variables);
|
config.setVariables(this.variables);
|
||||||
}
|
}
|
||||||
HashTree scenarioTree = tree;
|
HashTree scenarioTree = tree;
|
||||||
|
@ -145,7 +144,8 @@ public class MsScenario extends MsTestElement {
|
||||||
scenarioTree = MsCriticalSectionController.createHashTree(tree, this.getName(), this.isEnable());
|
scenarioTree = MsCriticalSectionController.createHashTree(tree, this.getName(), this.isEnable());
|
||||||
}
|
}
|
||||||
// 环境变量
|
// 环境变量
|
||||||
Arguments arguments = arguments(this.isEnvironmentEnable() ? newConfig : config);
|
Arguments arguments = ElementUtil.getConfigArguments(this.isEnvironmentEnable() ? newConfig : config, this.getName(), this.getProjectId(), this.getVariables());
|
||||||
|
|
||||||
if (arguments != null && (this.variableEnable == null || this.variableEnable)) {
|
if (arguments != null && (this.variableEnable == null || this.variableEnable)) {
|
||||||
Arguments valueSupposeMock = ParameterConfig.valueSupposeMock(arguments);
|
Arguments valueSupposeMock = ParameterConfig.valueSupposeMock(arguments);
|
||||||
// 这里加入自定义变量解决ForEach循环控制器取值问题,循环控制器无法从vars中取值
|
// 这里加入自定义变量解决ForEach循环控制器取值问题,循环控制器无法从vars中取值
|
||||||
|
@ -309,41 +309,6 @@ public class MsScenario extends MsTestElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Arguments arguments(ParameterConfig config) {
|
|
||||||
Arguments arguments = new Arguments();
|
|
||||||
arguments.setEnabled(true);
|
|
||||||
arguments.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "Arguments");
|
|
||||||
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
|
||||||
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
|
|
||||||
// 场景变量
|
|
||||||
if (CollectionUtils.isNotEmpty(this.getVariables())) {
|
|
||||||
this.getVariables().stream().filter(ScenarioVariable::isConstantValid).forEach(keyValue ->
|
|
||||||
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
|
|
||||||
);
|
|
||||||
|
|
||||||
List<ScenarioVariable> variableList = this.getVariables().stream().filter(ScenarioVariable::isListValid).collect(Collectors.toList());
|
|
||||||
variableList.forEach(item -> {
|
|
||||||
String[] arrays = item.getValue().split(",");
|
|
||||||
for (int i = 0; i < arrays.length; i++) {
|
|
||||||
arguments.addArgument(item.getName() + "_" + (i + 1), arrays[i], "=");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 环境通用变量
|
|
||||||
if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
|
|
||||||
&& CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables())) {
|
|
||||||
config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
|
|
||||||
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
|
|
||||||
);
|
|
||||||
// 清空变量,防止重复添加
|
|
||||||
config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().clear();
|
|
||||||
}
|
|
||||||
if (arguments.getArguments() != null && arguments.getArguments().size() > 0) {
|
|
||||||
return arguments;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setEnv(Map<String, String> environmentMap, Map<String, EnvironmentConfig> envConfig) {
|
private void setEnv(Map<String, String> environmentMap, Map<String, EnvironmentConfig> envConfig) {
|
||||||
for (String projectId : environmentMap.keySet()) {
|
for (String projectId : environmentMap.keySet()) {
|
||||||
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
||||||
|
|
|
@ -2,8 +2,8 @@ package io.metersphere.api.dto.definition.request.dns;
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
|
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
||||||
import io.metersphere.api.dto.scenario.HttpConfig;
|
import io.metersphere.api.dto.scenario.HttpConfig;
|
||||||
import io.metersphere.api.dto.scenario.KeyValue;
|
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||||
import io.metersphere.api.dto.scenario.environment.Host;
|
import io.metersphere.api.dto.scenario.environment.Host;
|
||||||
import io.metersphere.plugin.core.MsParameter;
|
import io.metersphere.plugin.core.MsParameter;
|
||||||
|
@ -65,14 +65,14 @@ public class MsDNSCacheManager extends MsTestElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Arguments arguments(String name, List<KeyValue> variables) {
|
private static Arguments arguments(String name, List<ScenarioVariable> variables) {
|
||||||
Arguments arguments = new Arguments();
|
Arguments arguments = new Arguments();
|
||||||
arguments.setEnabled(true);
|
arguments.setEnabled(true);
|
||||||
arguments.setName(name);
|
arguments.setName(name);
|
||||||
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
||||||
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
|
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
|
||||||
variables.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
|
variables.stream().filter(ScenarioVariable::isConstantValid).filter(ScenarioVariable::isEnable).forEach(ScenarioVariable ->
|
||||||
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
|
arguments.addArgument(ScenarioVariable.getName(), ScenarioVariable.getValue(), "=")
|
||||||
);
|
);
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,10 +226,12 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
setHeader(httpSamplerTree, config.getHeaders());
|
setHeader(httpSamplerTree, config.getHeaders());
|
||||||
}
|
}
|
||||||
// 环境通用请求头
|
// 环境通用请求头
|
||||||
Arguments arguments = getConfigArguments(config);
|
Arguments arguments = ElementUtil.getConfigArguments(config, this.getName(), this.getProjectId(), null);
|
||||||
if (arguments != null) {
|
if (arguments != null) {
|
||||||
httpSamplerTree.add(arguments);
|
httpSamplerTree.add(arguments);
|
||||||
}
|
}
|
||||||
|
//添加csv
|
||||||
|
ElementUtil.addOtherVariables(config, httpSamplerTree, this.getProjectId());
|
||||||
//判断是否要开启DNS
|
//判断是否要开启DNS
|
||||||
if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
|
if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
|
||||||
&& config.getConfig().get(this.getProjectId()).getCommonConfig().isEnableHost()) {
|
&& config.getConfig().get(this.getProjectId()).getCommonConfig().isEnableHost()) {
|
||||||
|
@ -353,6 +355,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotEmpty(useEvnId) && !StringUtils.equals(useEvnId, this.getEnvironmentId())) {
|
if (StringUtils.isNotEmpty(useEvnId) && !StringUtils.equals(useEvnId, this.getEnvironmentId())) {
|
||||||
|
@ -682,7 +685,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
arguments.addArgument(httpArgument);
|
arguments.addArgument(httpArgument);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -728,30 +731,6 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 环境通用变量,这里只适用用接口定义和用例,场景自动化会加到场景中
|
|
||||||
*/
|
|
||||||
private Arguments getConfigArguments(ParameterConfig config) {
|
|
||||||
Arguments arguments = new Arguments();
|
|
||||||
arguments.setEnabled(true);
|
|
||||||
arguments.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "Arguments");
|
|
||||||
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
|
||||||
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
|
|
||||||
// 环境通用变量
|
|
||||||
if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
|
|
||||||
&& CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables())) {
|
|
||||||
config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
|
|
||||||
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
|
|
||||||
);
|
|
||||||
// 清空变量,防止重复添加
|
|
||||||
config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().clear();
|
|
||||||
}
|
|
||||||
if (arguments.getArguments() != null && arguments.getArguments().size() > 0) {
|
|
||||||
return arguments;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addArguments(HashTree tree, String key, String value) {
|
private void addArguments(HashTree tree, String key, String value) {
|
||||||
Arguments arguments = new Arguments();
|
Arguments arguments = new Arguments();
|
||||||
arguments.setEnabled(true);
|
arguments.setEnabled(true);
|
||||||
|
|
|
@ -165,11 +165,12 @@ public class MsJDBCSampler extends MsTestElement {
|
||||||
tree.add(arguments);
|
tree.add(arguments);
|
||||||
}
|
}
|
||||||
// 环境通用请求头
|
// 环境通用请求头
|
||||||
Arguments envArguments = getConfigArguments(config);
|
Arguments envArguments = ElementUtil.getConfigArguments(config, this.getName(), this.getProjectId(), null);
|
||||||
if (envArguments != null) {
|
if (envArguments != null) {
|
||||||
tree.add(envArguments);
|
tree.add(envArguments);
|
||||||
}
|
}
|
||||||
|
//添加csv
|
||||||
|
ElementUtil.addOtherVariables(config, tree, this.getProjectId());
|
||||||
//增加误报、全局断言
|
//增加误报、全局断言
|
||||||
HashTreeUtil.addPositive(envConfig, samplerHashTree, config, this.getProjectId());
|
HashTreeUtil.addPositive(envConfig, samplerHashTree, config, this.getProjectId());
|
||||||
|
|
||||||
|
@ -192,30 +193,6 @@ public class MsJDBCSampler extends MsTestElement {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 环境通用变量
|
|
||||||
*/
|
|
||||||
private Arguments getConfigArguments(ParameterConfig config) {
|
|
||||||
Arguments arguments = new Arguments();
|
|
||||||
arguments.setEnabled(true);
|
|
||||||
arguments.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "Arguments");
|
|
||||||
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
|
||||||
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
|
|
||||||
// 环境通用变量
|
|
||||||
if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
|
|
||||||
&& CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables())) {
|
|
||||||
config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
|
|
||||||
arguments.addArgument(keyValue.getName(), ElementUtil.getEvlValue(keyValue.getValue()), "=")
|
|
||||||
);
|
|
||||||
// 清空变量,防止重复添加
|
|
||||||
config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().clear();
|
|
||||||
}
|
|
||||||
if (arguments.getArguments() != null && arguments.getArguments().size() > 0) {
|
|
||||||
return arguments;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isDataSource(List<DatabaseConfig> databaseConfigs) {
|
private boolean isDataSource(List<DatabaseConfig> databaseConfigs) {
|
||||||
List<String> ids = databaseConfigs.stream().map(DatabaseConfig::getId).collect(Collectors.toList());
|
List<String> ids = databaseConfigs.stream().map(DatabaseConfig::getId).collect(Collectors.toList());
|
||||||
if (StringUtils.isNotEmpty(this.dataSourceId) && ids.contains(this.dataSourceId)) {
|
if (StringUtils.isNotEmpty(this.dataSourceId) && ids.contains(this.dataSourceId)) {
|
||||||
|
|
|
@ -171,11 +171,12 @@ public class MsTCPSampler extends MsTestElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加环境中的公共变量
|
// 添加环境中的公共变量
|
||||||
Arguments arguments = ElementUtil.addArguments(config, this.getProjectId(), this.getName());
|
Arguments arguments = ElementUtil.getConfigArguments(config, this.getName(), this.getProjectId(), null);
|
||||||
if (arguments != null) {
|
if (arguments != null) {
|
||||||
tree.add(arguments);
|
tree.add(arguments);
|
||||||
}
|
}
|
||||||
|
//添加csv
|
||||||
|
ElementUtil.addOtherVariables(config, tree, this.getProjectId());
|
||||||
final HashTree samplerHashTree = new ListedHashTree();
|
final HashTree samplerHashTree = new ListedHashTree();
|
||||||
samplerHashTree.add(tcpConfig());
|
samplerHashTree.add(tcpConfig());
|
||||||
tree.set(tcpSampler(config), samplerHashTree);
|
tree.set(tcpSampler(config), samplerHashTree);
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class ScenarioVariable {
|
||||||
/**
|
/**
|
||||||
* CONSTANT LIST CSV COUNTER RANDOM
|
* CONSTANT LIST CSV COUNTER RANDOM
|
||||||
*/
|
*/
|
||||||
private String type;
|
private String type = VariableTypeConstants.CONSTANT.name();
|
||||||
private String id;
|
private String id;
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@ -41,6 +41,8 @@ public class ScenarioVariable {
|
||||||
private String minNumber;
|
private String minNumber;
|
||||||
private String maxNumber;
|
private String maxNumber;
|
||||||
|
|
||||||
|
private boolean enable = true;
|
||||||
|
|
||||||
public ScenarioVariable() {
|
public ScenarioVariable() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package io.metersphere.api.dto.scenario.environment;
|
package io.metersphere.api.dto.scenario.environment;
|
||||||
|
|
||||||
import io.metersphere.api.dto.scenario.KeyValue;
|
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class CommonConfig {
|
public class CommonConfig {
|
||||||
private List<KeyValue> variables;
|
private List<ScenarioVariable> variables;
|
||||||
private boolean enableHost;
|
private boolean enableHost;
|
||||||
private List<Host> hosts;
|
private List<Host> hosts;
|
||||||
private int requestTimeout;
|
private int requestTimeout;
|
||||||
|
|
|
@ -8,9 +8,12 @@ import io.metersphere.api.dto.mockconfig.MockConfigStaticData;
|
||||||
import io.metersphere.api.tcp.TCPPool;
|
import io.metersphere.api.tcp.TCPPool;
|
||||||
import io.metersphere.base.domain.ApiTestEnvironmentExample;
|
import io.metersphere.base.domain.ApiTestEnvironmentExample;
|
||||||
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
|
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
|
||||||
|
import io.metersphere.base.domain.FileAssociationExample;
|
||||||
import io.metersphere.base.domain.Project;
|
import io.metersphere.base.domain.Project;
|
||||||
import io.metersphere.base.mapper.ApiTestEnvironmentMapper;
|
import io.metersphere.base.mapper.ApiTestEnvironmentMapper;
|
||||||
|
import io.metersphere.base.mapper.FileAssociationMapper;
|
||||||
import io.metersphere.base.mapper.ext.ExtApiTestEnvironmentMapper;
|
import io.metersphere.base.mapper.ext.ExtApiTestEnvironmentMapper;
|
||||||
|
import io.metersphere.commons.constants.FileAssociationType;
|
||||||
import io.metersphere.commons.constants.ProjectApplicationType;
|
import io.metersphere.commons.constants.ProjectApplicationType;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||||
|
@ -25,6 +28,7 @@ import io.metersphere.log.utils.ReflexObjectUtil;
|
||||||
import io.metersphere.log.vo.DetailColumn;
|
import io.metersphere.log.vo.DetailColumn;
|
||||||
import io.metersphere.log.vo.OperatingLogDetails;
|
import io.metersphere.log.vo.OperatingLogDetails;
|
||||||
import io.metersphere.log.vo.system.SystemReference;
|
import io.metersphere.log.vo.system.SystemReference;
|
||||||
|
import io.metersphere.metadata.service.FileAssociationService;
|
||||||
import io.metersphere.service.EnvironmentGroupProjectService;
|
import io.metersphere.service.EnvironmentGroupProjectService;
|
||||||
import io.metersphere.service.ProjectApplicationService;
|
import io.metersphere.service.ProjectApplicationService;
|
||||||
import io.metersphere.service.ProjectService;
|
import io.metersphere.service.ProjectService;
|
||||||
|
@ -50,6 +54,10 @@ public class ApiTestEnvironmentService {
|
||||||
private ProjectApplicationService projectApplicationService;
|
private ProjectApplicationService projectApplicationService;
|
||||||
@Resource
|
@Resource
|
||||||
private ExtApiTestEnvironmentMapper extApiTestEnvironmentMapper;
|
private ExtApiTestEnvironmentMapper extApiTestEnvironmentMapper;
|
||||||
|
@Resource
|
||||||
|
private FileAssociationService fileAssociationService;
|
||||||
|
@Resource
|
||||||
|
private FileAssociationMapper fileAssociationMapper;
|
||||||
|
|
||||||
public List<ApiTestEnvironmentWithBLOBs> list(String projectId) {
|
public List<ApiTestEnvironmentWithBLOBs> list(String projectId) {
|
||||||
ApiTestEnvironmentExample example = new ApiTestEnvironmentExample();
|
ApiTestEnvironmentExample example = new ApiTestEnvironmentExample();
|
||||||
|
@ -85,6 +93,9 @@ public class ApiTestEnvironmentService {
|
||||||
public void delete(String id) {
|
public void delete(String id) {
|
||||||
apiTestEnvironmentMapper.deleteByPrimaryKey(id);
|
apiTestEnvironmentMapper.deleteByPrimaryKey(id);
|
||||||
environmentGroupProjectService.deleteRelateEnv(id);
|
environmentGroupProjectService.deleteRelateEnv(id);
|
||||||
|
FileAssociationExample associationExample = new FileAssociationExample();
|
||||||
|
associationExample.createCriteria().andSourceIdEqualTo(id);
|
||||||
|
fileAssociationMapper.deleteByExample(associationExample);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(ApiTestEnvironmentWithBLOBs apiTestEnvironment) {
|
public void update(ApiTestEnvironmentWithBLOBs apiTestEnvironment) {
|
||||||
|
@ -99,16 +110,19 @@ public class ApiTestEnvironmentService {
|
||||||
return apiTestEnvironmentWithBLOBs.getId();
|
return apiTestEnvironmentWithBLOBs.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String add(ApiTestEnvironmentDTO request, List<MultipartFile> sslFiles) {
|
public String add(ApiTestEnvironmentDTO request, List<MultipartFile> sslFiles, List<MultipartFile> variableFile) {
|
||||||
request.setId(UUID.randomUUID().toString());
|
request.setId(UUID.randomUUID().toString());
|
||||||
request.setCreateUser(SessionUtils.getUserId());
|
request.setCreateUser(SessionUtils.getUserId());
|
||||||
checkEnvironmentExist(request);
|
checkEnvironmentExist(request);
|
||||||
FileUtils.createFiles(request.getUploadIds(), sslFiles, FileUtils.BODY_FILE_DIR + "/ssl");
|
FileUtils.createFiles(request.getUploadIds(), sslFiles, FileUtils.BODY_FILE_DIR + "/ssl");
|
||||||
|
FileUtils.createBodyFiles(request.getVariablesFilesIds(), variableFile);
|
||||||
//检查Config,判断isMock参数是否给True
|
//检查Config,判断isMock参数是否给True
|
||||||
request = this.updateConfig(request, false);
|
request = this.updateConfig(request, false);
|
||||||
request.setCreateTime(System.currentTimeMillis());
|
request.setCreateTime(System.currentTimeMillis());
|
||||||
request.setUpdateTime(System.currentTimeMillis());
|
request.setUpdateTime(System.currentTimeMillis());
|
||||||
apiTestEnvironmentMapper.insert(request);
|
apiTestEnvironmentMapper.insert(request);
|
||||||
|
// 存储附件关系
|
||||||
|
fileAssociationService.saveEnvironment(request.getId(), request.getConfig(), FileAssociationType.ENVIRONMENT.name());
|
||||||
return request.getId();
|
return request.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,10 +142,13 @@ public class ApiTestEnvironmentService {
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(ApiTestEnvironmentDTO apiTestEnvironment, List<MultipartFile> sslFiles) {
|
public void update(ApiTestEnvironmentDTO apiTestEnvironment, List<MultipartFile> sslFiles, List<MultipartFile> variablesFiles) {
|
||||||
checkEnvironmentExist(apiTestEnvironment);
|
checkEnvironmentExist(apiTestEnvironment);
|
||||||
FileUtils.createFiles(apiTestEnvironment.getUploadIds(), sslFiles, FileUtils.BODY_FILE_DIR + "/ssl");
|
FileUtils.createFiles(apiTestEnvironment.getUploadIds(), sslFiles, FileUtils.BODY_FILE_DIR + "/ssl");
|
||||||
|
FileUtils.createBodyFiles(apiTestEnvironment.getVariablesFilesIds(), variablesFiles);
|
||||||
apiTestEnvironment.setUpdateTime(System.currentTimeMillis());
|
apiTestEnvironment.setUpdateTime(System.currentTimeMillis());
|
||||||
|
// 存储附件关系
|
||||||
|
fileAssociationService.saveEnvironment(apiTestEnvironment.getId(), apiTestEnvironment.getConfig(), FileAssociationType.ENVIRONMENT.name());
|
||||||
apiTestEnvironmentMapper.updateByPrimaryKeyWithBLOBs(apiTestEnvironment);
|
apiTestEnvironmentMapper.updateByPrimaryKeyWithBLOBs(apiTestEnvironment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
package io.metersphere.commons.constants;
|
package io.metersphere.commons.constants;
|
||||||
|
|
||||||
public enum FileAssociationType {
|
public enum FileAssociationType {
|
||||||
API, CASE, SCENARIO, UI
|
API, CASE, SCENARIO, UI, ENVIRONMENT
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.metersphere.metadata.service;
|
package io.metersphere.metadata.service;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import io.metersphere.api.dto.definition.request.MsScenario;
|
import io.metersphere.api.dto.definition.request.MsScenario;
|
||||||
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
||||||
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
||||||
|
@ -104,7 +105,7 @@ public class FileAssociationService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveApi(String id, MsTestElement request,String type) {
|
public void saveApi(String id, MsTestElement request, String type) {
|
||||||
this.deleteByResourceId(id);
|
this.deleteByResourceId(id);
|
||||||
if (StringUtils.isNotEmpty(id) && request != null && StringUtils.equalsIgnoreCase(request.getType(), HTTPSamplerProxy.class.getSimpleName())) {
|
if (StringUtils.isNotEmpty(id) && request != null && StringUtils.equalsIgnoreCase(request.getType(), HTTPSamplerProxy.class.getSimpleName())) {
|
||||||
MsHTTPSamplerProxy samplerProxy = (MsHTTPSamplerProxy) request;
|
MsHTTPSamplerProxy samplerProxy = (MsHTTPSamplerProxy) request;
|
||||||
|
@ -134,6 +135,22 @@ public class FileAssociationService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void saveEnvironment(String id, String config, String type) {
|
||||||
|
this.deleteByResourceId(id);
|
||||||
|
List<BodyFile> files = new ArrayList<>();
|
||||||
|
if (StringUtils.isNotEmpty(config)) {
|
||||||
|
JSONObject commonConfig = JSONObject.parseObject(config).getJSONObject("commonConfig");
|
||||||
|
List<ScenarioVariable> list = JSONObject.parseArray(commonConfig.getString("variables"), ScenarioVariable.class);
|
||||||
|
list.stream().filter(ScenarioVariable::isCSVValid).forEach(keyValue -> {
|
||||||
|
files.addAll(keyValue.getFiles().stream().filter(BodyFile::isRef).collect(Collectors.toList()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!CollectionUtils.isEmpty(files)) {
|
||||||
|
List<BodyFile> list = files.stream().distinct().collect(Collectors.toList());
|
||||||
|
this.save(list, type, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void getHashTree(List<MsTestElement> testElements, List<BodyFile> files) {
|
private void getHashTree(List<MsTestElement> testElements, List<BodyFile> files) {
|
||||||
testElements.forEach(item -> {
|
testElements.forEach(item -> {
|
||||||
if (StringUtils.equalsIgnoreCase(item.getType(), HTTPSamplerProxy.class.getSimpleName())) {
|
if (StringUtils.equalsIgnoreCase(item.getType(), HTTPSamplerProxy.class.getSimpleName())) {
|
||||||
|
|
|
@ -129,11 +129,11 @@ export default {
|
||||||
},
|
},
|
||||||
download() {
|
download() {
|
||||||
// 本地文件
|
// 本地文件
|
||||||
if (this.parameter.files && this.parameter.files.length > 0 && this.parameter.files[0].file) {
|
if (this.parameter.files && this.parameter.files.length > 0 && this.parameter.files[0].file && this.parameter.files[0].file.name) {
|
||||||
downloadFile(this.parameter.files[0].file.name, this.parameter.files[0].file);
|
downloadFile(this.parameter.files[0].file.name, this.parameter.files[0].file);
|
||||||
}
|
}
|
||||||
// 远程下载文件
|
// 远程下载文件
|
||||||
if (this.parameter.files && this.parameter.files.length > 0 && !this.parameter.files[0].file) {
|
if (this.parameter.files && this.parameter.files.length > 0 && (!this.parameter.files[0].file || !this.parameter.files[0].file.name)) {
|
||||||
let file = this.parameter.files[0];
|
let file = this.parameter.files[0];
|
||||||
let conf = {
|
let conf = {
|
||||||
url: "/api/automation/file/download",
|
url: "/api/automation/file/download",
|
||||||
|
@ -157,15 +157,15 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleRemove(file) {
|
handleRemove(file) {
|
||||||
let fileName = file.file ? file.file.name : file.name
|
let fileName = file.name ? file.name : file.file.name
|
||||||
this.$alert('是否确认删除CSV文件:【 ' + fileName + " 】?", '', {
|
this.$alert(this.$t('api_test.environment.csv_delete') + ':【 ' + fileName + " 】?", '', {
|
||||||
confirmButtonText: this.$t('commons.confirm'),
|
confirmButtonText: this.$t('commons.confirm'),
|
||||||
callback: (action) => {
|
callback: (action) => {
|
||||||
if (action === 'confirm') {
|
if (action === 'confirm') {
|
||||||
this.$refs.upload.handleRemove(file);
|
this.$refs.upload.handleRemove(file);
|
||||||
for (let i = 0; i < this.parameter.files.length; i++) {
|
for (let i = 0; i < this.parameter.files.length; i++) {
|
||||||
let paramFileName = this.parameter.files[i].file ?
|
let paramFileName = this.parameter.files[i].name ?
|
||||||
this.parameter.files[i].file.name : this.parameter.files[i].name;
|
this.parameter.files[i].name : this.parameter.files[i].file.name;
|
||||||
if (fileName === paramFileName) {
|
if (fileName === paramFileName) {
|
||||||
this.parameter.files.splice(i, 1);
|
this.parameter.files.splice(i, 1);
|
||||||
this.$refs.upload.handleRemove(file);
|
this.$refs.upload.handleRemove(file);
|
||||||
|
@ -180,6 +180,7 @@ export default {
|
||||||
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
|
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
|
||||||
},
|
},
|
||||||
upload(file) {
|
upload(file) {
|
||||||
|
this.parameter.files = [];
|
||||||
this.parameter.files.push(file);
|
this.parameter.files.push(file);
|
||||||
},
|
},
|
||||||
uploadValidate(file) {
|
uploadValidate(file) {
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<el-tab-pane :label="$t('variables.config')" name="config">
|
<el-tab-pane :label="$t('variables.config')" name="config">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="5" style="margin-top: 5px">
|
<el-col :span="5" style="margin-top: 5px">
|
||||||
<span>{{$t('variables.add_file')}}</span>
|
<span>{{ $t('variables.add_file') }}</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="19">
|
<el-col :span="19">
|
||||||
<ms-csv-file-upload :parameter="editData"/>
|
<ms-csv-file-upload :parameter="editData"/>
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row style="margin-top: 10px">
|
<el-row style="margin-top: 10px">
|
||||||
<el-col :span="5" style="margin-top: 5px">
|
<el-col :span="5" style="margin-top: 5px">
|
||||||
<span>{{$t('variables.delimiter')}}</span>
|
<span>{{ $t('variables.delimiter') }}</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="19">
|
<el-col :span="19">
|
||||||
<el-input v-model="editData.delimiter" size="small" :disabled="disabled"/>
|
<el-input v-model="editData.delimiter" size="small" :disabled="disabled"/>
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row style="margin-top: 10px">
|
<el-row style="margin-top: 10px">
|
||||||
<el-col :span="5" style="margin-top: 5px">
|
<el-col :span="5" style="margin-top: 5px">
|
||||||
<span>{{$t('variables.quoted_data')}}</span>
|
<span>{{ $t('variables.quoted_data') }}</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="19">
|
<el-col :span="19">
|
||||||
<el-select v-model="editData.quotedData" size="small" :disabled="disabled">
|
<el-select v-model="editData.quotedData" size="small" :disabled="disabled">
|
||||||
|
@ -66,10 +66,11 @@
|
||||||
height="200px"
|
height="200px"
|
||||||
v-loading="loading">
|
v-loading="loading">
|
||||||
<!-- 自定义列的遍历-->
|
<!-- 自定义列的遍历-->
|
||||||
<el-table-column v-for="(item, index) in columns" :key="index" :label="columns[index]" align="left" width="180">
|
<el-table-column v-for="(item, index) in columns" :key="index" :label="columns[index]" align="left"
|
||||||
|
width="180">
|
||||||
<!-- 数据的遍历 scope.row就代表数据的每一个对象-->
|
<!-- 数据的遍历 scope.row就代表数据的每一个对象-->
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{scope.row[index]}}</span>
|
<span>{{ scope.row[index] }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
@ -79,70 +80,70 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsCsvFileUpload from "./CsvFileUpload";
|
import MsCsvFileUpload from "./CsvFileUpload";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsEditCsv",
|
name: "MsEditCsv",
|
||||||
components: {
|
components: {
|
||||||
MsCsvFileUpload
|
MsCsvFileUpload
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
editData: {},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeName: "config",
|
||||||
|
visible: false,
|
||||||
|
loading: false,
|
||||||
|
editFlag: false,
|
||||||
|
previewData: [],
|
||||||
|
columns: [],
|
||||||
|
allData: [],
|
||||||
|
showMessage: false,
|
||||||
|
rules: {
|
||||||
|
name: [
|
||||||
|
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
disabled() {
|
||||||
|
return !(this.editData.name && this.editData.name !== "");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'editData.name': {
|
||||||
|
handler(v) {
|
||||||
|
this.handleClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
complete(results) {
|
||||||
|
if (results.errors && results.errors.length > 0) {
|
||||||
|
this.$error(results.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.allData) {
|
||||||
|
this.columns = this.allData[0];
|
||||||
|
this.allData.splice(0, 1);
|
||||||
|
this.previewData = this.allData;
|
||||||
|
}
|
||||||
|
this.loading = false;
|
||||||
},
|
},
|
||||||
props: {
|
cleanPreview() {
|
||||||
editData: {},
|
this.allData = [];
|
||||||
|
this.columns = [];
|
||||||
|
this.previewData = [];
|
||||||
},
|
},
|
||||||
data() {
|
step(results, parser) {
|
||||||
return {
|
if (this.allData.length < 500) {
|
||||||
activeName: "config",
|
this.allData.push(results.data);
|
||||||
visible: false,
|
} else {
|
||||||
loading: false,
|
this.showMessage = true;
|
||||||
editFlag: false,
|
|
||||||
previewData: [],
|
|
||||||
columns: [],
|
|
||||||
allData: [],
|
|
||||||
showMessage: false,
|
|
||||||
rules: {
|
|
||||||
name: [
|
|
||||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
disabled() {
|
|
||||||
return !(this.editData.name && this.editData.name !== "");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
'editData.name': {
|
|
||||||
handler(v) {
|
|
||||||
this.handleClick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
complete(results) {
|
|
||||||
if (results.errors && results.errors.length > 0) {
|
|
||||||
this.$error(results.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.allData) {
|
|
||||||
this.columns = this.allData[0];
|
|
||||||
this.allData.splice(0, 1);
|
|
||||||
this.previewData = this.allData;
|
|
||||||
}
|
|
||||||
this.loading = false;
|
|
||||||
},
|
|
||||||
cleanPreview() {
|
|
||||||
this.allData = [];
|
|
||||||
this.columns = [];
|
|
||||||
this.previewData = [];
|
|
||||||
},
|
|
||||||
step(results, parser) {
|
|
||||||
if (this.allData.length < 500) {
|
|
||||||
this.allData.push(results.data);
|
|
||||||
} else {
|
|
||||||
this.showMessage = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleClick() {
|
handleClick() {
|
||||||
let config = {
|
let config = {
|
||||||
|
@ -152,12 +153,12 @@
|
||||||
};
|
};
|
||||||
this.allData = [];
|
this.allData = [];
|
||||||
// 本地文件
|
// 本地文件
|
||||||
if (this.editData.files && this.editData.files.length > 0 && this.editData.files[0].file) {
|
if (this.editData.files && this.editData.files.length > 0 && this.editData.files[0].file && this.editData.files[0].file.name) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.$papa.parse(this.editData.files[0].file, config);
|
this.$papa.parse(this.editData.files[0].file, config);
|
||||||
}
|
}
|
||||||
// 远程下载文件
|
// 远程下载文件
|
||||||
if (this.editData.files && this.editData.files.length > 0 && !this.editData.files[0].file) {
|
if (this.editData.files && this.editData.files.length > 0 && (!this.editData.files[0].file || !this.editData.files[0].file.name)) {
|
||||||
let file = this.editData.files[0];
|
let file = this.editData.files[0];
|
||||||
let conf = {
|
let conf = {
|
||||||
url: "/api/automation/file/download",
|
url: "/api/automation/file/download",
|
||||||
|
@ -186,19 +187,19 @@
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
querySearch(queryString, cb) {
|
querySearch(queryString, cb) {
|
||||||
let restaurants = [{value: "UTF-8"}, {value: "UTF-16"},{value: "GB2312"}, {value: "ISO-8859-15"}, {value: "US-ASCll"}];
|
let restaurants = [{value: "UTF-8"}, {value: "UTF-16"}, {value: "GB2312"}, {value: "ISO-8859-15"}, {value: "US-ASCll"}];
|
||||||
let results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
|
let results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
|
||||||
// 调用 callback 返回建议列表的数据
|
// 调用 callback 返回建议列表的数据
|
||||||
cb(results);
|
cb(results);
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
ms-is-leaf >>> .is-leaf {
|
ms-is-leaf >>> .is-leaf {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog :visible="dialogVisible" :title="dialogTitle"
|
||||||
|
@close="close" :close-on-click-modal="false" append-to-body
|
||||||
|
width="35%">
|
||||||
|
<el-form :rules="rules" label-width="80px" v-model="modeId">
|
||||||
|
<el-form-item prop="modeId" :label="$t('commons.import_mode')">
|
||||||
|
<el-select size="small" v-model="modeId">
|
||||||
|
<el-option v-for="item in modeOptions" :key="item.id" :label="item.name" :value="item.id"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-upload
|
||||||
|
class="api-upload" drag action="alert"
|
||||||
|
:on-change="handleFileChange"
|
||||||
|
:limit="1" :file-list="uploadFiles"
|
||||||
|
:on-remove="handleRemove"
|
||||||
|
:on-exceed="handleExceed"
|
||||||
|
:auto-upload="false" accept=".json">
|
||||||
|
<i class="el-icon-upload"></i>
|
||||||
|
<div class="el-upload__text" v-html="$t('load_test.upload_tips')"></div>
|
||||||
|
<div class="el-upload__tip" slot="tip">
|
||||||
|
{{ $t('api_test.api_import.file_size_limit') }}
|
||||||
|
{{ ',' + $t('api_test.api_import.ms_env_import_file_limit') }}
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template v-slot:footer>
|
||||||
|
<el-button type="primary" @click="save">
|
||||||
|
{{ $t('commons.confirm') }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "VariableImport",
|
||||||
|
props: {
|
||||||
|
projectList: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toImportProjectId: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentProjectId: '', //所选中环境的id
|
||||||
|
uploadFiles: [],
|
||||||
|
dialogTitle: this.$t('commons.import_variable'),
|
||||||
|
dialogVisible: false,
|
||||||
|
modeOptions: [
|
||||||
|
{
|
||||||
|
id: 'fullCoverage',
|
||||||
|
name: this.$t('commons.cover')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'incrementalMerge',
|
||||||
|
name: this.$t('commons.not_cover')
|
||||||
|
}
|
||||||
|
],
|
||||||
|
modeId: 'fullCoverage',
|
||||||
|
rules: {
|
||||||
|
modeId: [
|
||||||
|
{required: true, message: "", trigger: 'blur'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
//导入框激活时重置选中的项目和文件
|
||||||
|
dialogVisible(val, oldVal) {
|
||||||
|
if (oldVal === false) {
|
||||||
|
this.currentProjectId = '';
|
||||||
|
this.uploadFiles = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
handleFileChange(file, uploadFiles) {
|
||||||
|
this.uploadFiles = uploadFiles;
|
||||||
|
},
|
||||||
|
save() {
|
||||||
|
if (this.uploadFiles.length > 0) {
|
||||||
|
for (let i = 0; i < this.uploadFiles.length; i++) {
|
||||||
|
this.uploadValidate(this.uploadFiles[i]);
|
||||||
|
let file = this.uploadFiles[i];
|
||||||
|
if (!file) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.readAsText(file.raw)
|
||||||
|
reader.onload = (e) => {
|
||||||
|
let fileString = e.target.result;
|
||||||
|
let messages = '';
|
||||||
|
try {
|
||||||
|
JSON.parse(fileString).map(env => {
|
||||||
|
if (!env.name) {
|
||||||
|
messages = this.$t('api_test.automation.variable_warning')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (messages !== '') {
|
||||||
|
this.$warning(messages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$emit("mergeData", fileString, this.modeId);
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.$success(this.$t('commons.save_success'));
|
||||||
|
} catch (exception) {
|
||||||
|
this.$warning(this.$t('api_test.api_import.ms_env_import_file_limit'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$warning(this.$t('test_track.case.import.import_file_tips'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleExceed() {
|
||||||
|
this.$warning(this.$t('api_test.api_import.file_exceed_limit'));
|
||||||
|
},
|
||||||
|
handleRemove() {
|
||||||
|
|
||||||
|
},
|
||||||
|
uploadValidate(file) { //判断文件扩展名是不是.json,以及文件大小是否超过20M
|
||||||
|
const extension = file.name.substring(file.name.lastIndexOf('.') + 1);
|
||||||
|
if (!(extension === 'json')) {
|
||||||
|
this.$warning(this.$t('api_test.api_import.ms_env_import_file_limit'));
|
||||||
|
}
|
||||||
|
if (file.size / 1024 / 1024 > 20) {
|
||||||
|
this.$warning(this.$t('api_test.api_import.file_size_limit'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
open() {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.dialogVisible = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.project-item {
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -37,9 +37,23 @@
|
||||||
<el-button size="small" style="margin-left: 10px" type="primary" @click="addVariable">
|
<el-button size="small" style="margin-left: 10px" type="primary" @click="addVariable">
|
||||||
{{ $t('commons.add') }}
|
{{ $t('commons.add') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-link @click="batchAddParameter" type="primary" :disabled="disabled" style="margin-left: 10px">
|
<el-dropdown style="margin-left: 10px">
|
||||||
{{ $t("commons.batch_add") }}
|
<el-button size="small">
|
||||||
</el-link>
|
<span class="tip-font">{{ $t('commons.more_operator') }}</span>
|
||||||
|
<i class="el-icon-arrow-down el-icon--right"/>
|
||||||
|
</el-button>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item @click.native.stop="importVariable" @mergeData="mergeData" :disabled="disabled">
|
||||||
|
{{ $t("commons.import_variable") }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click.native.stop="exportVariable" :disabled="disabled">
|
||||||
|
{{ $t("commons.export_variable") }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click.native.stop="batchAddParameter" :disabled="disabled">
|
||||||
|
{{ $t("commons.batch_add") }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row>
|
<el-row>
|
||||||
|
@ -94,6 +108,13 @@
|
||||||
:label="$t('api_test.value')"
|
:label="$t('api_test.value')"
|
||||||
sortable>
|
sortable>
|
||||||
</ms-table-column>
|
</ms-table-column>
|
||||||
|
<ms-table-column
|
||||||
|
prop="description"
|
||||||
|
:field="item"
|
||||||
|
:fields-width="fieldsWidth"
|
||||||
|
:label="$t('commons.description')"
|
||||||
|
sortable>
|
||||||
|
</ms-table-column>
|
||||||
</span>
|
</span>
|
||||||
</ms-table>
|
</ms-table>
|
||||||
<batch-add-parameter @batchSave="batchSaveParameter" ref="batchAddParameter"/>
|
<batch-add-parameter @batchSave="batchSaveParameter" ref="batchAddParameter"/>
|
||||||
|
@ -149,6 +170,7 @@
|
||||||
</template>
|
</template>
|
||||||
</el-collapse-transition>
|
</el-collapse-transition>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
<variable-import ref="variableImport"></variable-import>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -161,7 +183,7 @@ import MsEditCounter from "./EditCounter";
|
||||||
import MsEditRandom from "./EditRandom";
|
import MsEditRandom from "./EditRandom";
|
||||||
import MsEditListValue from "./EditListValue";
|
import MsEditListValue from "./EditListValue";
|
||||||
import MsEditCsv from "./EditCsv";
|
import MsEditCsv from "./EditCsv";
|
||||||
import {getUUID} from "@/common/js/utils";
|
import {downloadFile, getUUID} from "@/common/js/utils";
|
||||||
import MsApiKeyValue from "../../../definition/components/ApiKeyValue";
|
import MsApiKeyValue from "../../../definition/components/ApiKeyValue";
|
||||||
import BatchAddParameter from "../../../definition/components/basis/BatchAddParameter";
|
import BatchAddParameter from "../../../definition/components/basis/BatchAddParameter";
|
||||||
import {KeyValue} from "../../../definition/model/ApiTestModel";
|
import {KeyValue} from "../../../definition/model/ApiTestModel";
|
||||||
|
@ -170,6 +192,7 @@ import {REQUEST_HEADERS} from "@/common/js/constants";
|
||||||
import MsTable from "@/business/components/common/components/table/MsTable";
|
import MsTable from "@/business/components/common/components/table/MsTable";
|
||||||
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
|
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
|
||||||
import {getCustomTableHeader, getCustomTableWidth} from "@/common/js/tableUtils";
|
import {getCustomTableHeader, getCustomTableWidth} from "@/common/js/tableUtils";
|
||||||
|
import VariableImport from "@/business/components/api/automation/scenario/variable/VariableImport";
|
||||||
|
|
||||||
const jsondiffpatch = require('jsondiffpatch');
|
const jsondiffpatch = require('jsondiffpatch');
|
||||||
|
|
||||||
|
@ -188,6 +211,7 @@ export default {
|
||||||
BatchAddParameter,
|
BatchAddParameter,
|
||||||
MsTableColumn,
|
MsTableColumn,
|
||||||
MsTable,
|
MsTable,
|
||||||
|
VariableImport
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -230,6 +254,46 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
importVariable() {
|
||||||
|
this.$refs.variableImport.open();
|
||||||
|
},
|
||||||
|
mergeData(data, modeId) {
|
||||||
|
JSON.parse(data).map(importData => {
|
||||||
|
importData.id = getUUID();
|
||||||
|
importData.enable = true;
|
||||||
|
importData.showMore = false;
|
||||||
|
let sameNameIndex = this.variables.findIndex(d => d.name === importData.name);
|
||||||
|
if (sameNameIndex !== -1) {
|
||||||
|
if (modeId === 'fullCoverage') {
|
||||||
|
this.variables.splice(sameNameIndex, 1, importData);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.variables.splice(this.variables.length - 1, 0, importData);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
exportVariable() {
|
||||||
|
if (this.$refs.variableTable.selectIds.length < 1) {
|
||||||
|
this.$warning(this.$t('api_test.environment.select_environment'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let variablesJson = [];
|
||||||
|
let messages = '';
|
||||||
|
let rows = this.$refs.variableTable.selectRows;
|
||||||
|
rows.forEach(row => {
|
||||||
|
if (row.type === 'CSV') {
|
||||||
|
messages = this.$t('variables.csv_download')
|
||||||
|
}
|
||||||
|
if (row.name) {
|
||||||
|
variablesJson.push(row);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (messages !== '') {
|
||||||
|
this.$warning(messages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
downloadFile('MS_' + variablesJson.length + '_Environments_variables.json', JSON.stringify(variablesJson));
|
||||||
|
},
|
||||||
batchAddParameter() {
|
batchAddParameter() {
|
||||||
this.$refs.batchAddParameter.open();
|
this.$refs.batchAddParameter.open();
|
||||||
},
|
},
|
||||||
|
@ -241,20 +305,21 @@ export default {
|
||||||
let params = data.split("\n");
|
let params = data.split("\n");
|
||||||
let keyValues = [];
|
let keyValues = [];
|
||||||
params.forEach(item => {
|
params.forEach(item => {
|
||||||
let line = item.split(/:|:/);
|
if (item) {
|
||||||
let required = false;
|
let line = item.split(/:|:/);
|
||||||
keyValues.unshift(new KeyValue({
|
let required = false;
|
||||||
name: line[0],
|
keyValues.push(new KeyValue({
|
||||||
required: required,
|
name: line[0],
|
||||||
value: line[1],
|
required: required,
|
||||||
description: line[2],
|
value: line[1],
|
||||||
type: "text",
|
description: line[2],
|
||||||
valid: false,
|
type: "CONSTANT",
|
||||||
file: false,
|
valid: false,
|
||||||
encode: true,
|
file: false,
|
||||||
enable: true,
|
encode: true,
|
||||||
contentType: "text/plain"
|
enable: true,
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
return keyValues;
|
return keyValues;
|
||||||
}
|
}
|
||||||
|
@ -278,7 +343,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isAdd) {
|
if (isAdd) {
|
||||||
this.headers.unshift(obj);
|
this.headers.splice(this.headers.indexOf(h => !h.name), 0, obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -346,6 +411,18 @@ export default {
|
||||||
this.disabled = disabled;
|
this.disabled = disabled;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.variableTable.doLayout();
|
this.$refs.variableTable.doLayout();
|
||||||
|
let variable = [];
|
||||||
|
let messages = '';
|
||||||
|
this.variables.forEach(item => {
|
||||||
|
if (variable.indexOf(item.name) !== -1) {
|
||||||
|
messages += item.name + ' ,';
|
||||||
|
} else {
|
||||||
|
variable.push(item.name);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (messages !== '') {
|
||||||
|
this.$alert(this.$t('api_test.scenario.variables') + "【" + messages.substr(0, messages.length - 1) + "】" + this.$t('load_test.param_is_duplicate'));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
save() {
|
save() {
|
||||||
|
@ -382,6 +459,18 @@ export default {
|
||||||
this.$warning(this.$t('api_test.automation.variable_warning'));
|
this.$warning(this.$t('api_test.automation.variable_warning'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let repeatKey = "";
|
||||||
|
if (!this.showDelete) {
|
||||||
|
this.variables.forEach((item, index) => {
|
||||||
|
if (item.name === this.editData.name) {
|
||||||
|
repeatKey = item.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (repeatKey !== "") {
|
||||||
|
this.$warning(this.$t('api_test.scenario.variables') + "【" + repeatKey + "】" + this.$t('load_test.param_is_duplicate'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.editData.type === 'CSV' && this.$refs.csv) {
|
if (this.editData.type === 'CSV' && this.$refs.csv) {
|
||||||
if (this.editData.files.length === 0) {
|
if (this.editData.files.length === 0) {
|
||||||
this.$warning(this.$t('api_test.automation.csv_warning'));
|
this.$warning(this.$t('api_test.automation.csv_warning'));
|
||||||
|
@ -407,7 +496,7 @@ export default {
|
||||||
deleteVariable() {
|
deleteVariable() {
|
||||||
let ids = [this.editData.id];
|
let ids = [this.editData.id];
|
||||||
if (ids.length == 0) {
|
if (ids.length == 0) {
|
||||||
this.$warning("请选择一条数据删除");
|
this.$warning(this.$t('api_test.environment.delete_info'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let message = "";
|
let message = "";
|
||||||
|
@ -419,7 +508,7 @@ export default {
|
||||||
});
|
});
|
||||||
if (message !== "") {
|
if (message !== "") {
|
||||||
message = message.substr(0, message.length - 1);
|
message = message.substr(0, message.length - 1);
|
||||||
this.$alert('是否确认删除变量:【 ' + message + " 】?", '', {
|
this.$alert(this.$t('api_test.environment.variables_delete_info') + ':【 ' + message + " 】?", '', {
|
||||||
confirmButtonText: this.$t('commons.confirm'),
|
confirmButtonText: this.$t('commons.confirm'),
|
||||||
callback: (action) => {
|
callback: (action) => {
|
||||||
if (action === 'confirm') {
|
if (action === 'confirm') {
|
||||||
|
@ -442,7 +531,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleDeleteBatch() {
|
handleDeleteBatch() {
|
||||||
this.$alert("是否确认删除所选变量" + ' ' + " ?", '', {
|
this.$alert(this.$t('api_test.environment.variables_delete_info') + ' ' + " ?", '', {
|
||||||
confirmButtonText: this.$t('commons.confirm'),
|
confirmButtonText: this.$t('commons.confirm'),
|
||||||
callback: (action) => {
|
callback: (action) => {
|
||||||
if (action === 'confirm') {
|
if (action === 'confirm') {
|
||||||
|
|
|
@ -8,12 +8,15 @@
|
||||||
<div v-html="$t('api_test.batch_add_parameter')"/>
|
<div v-html="$t('api_test.batch_add_parameter')"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="10" class="buttons">
|
<el-col :span="10" class="buttons">
|
||||||
<el-button size="mini" @click="handleClose">{{$t('commons.cancel')}}</el-button>
|
<el-button size="mini" @click="handleClose">{{ $t('commons.cancel') }}</el-button>
|
||||||
<el-button type="primary" size="mini" @click="confirm" @keydown.enter.native.prevent>{{$t('commons.confirm')}}</el-button>
|
<el-button type="primary" size="mini" @click="confirm" @keydown.enter.native.prevent>
|
||||||
|
{{ $t('commons.confirm') }}
|
||||||
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<div class="ms-code">
|
<div class="ms-code">
|
||||||
<ms-code-edit class="ms-code" :enable-format="false" mode="text" :data.sync="parameters" theme="eclipse" :modes="['text']"
|
<ms-code-edit class="ms-code" :enable-format="false" mode="text" :data.sync="parameters" theme="eclipse"
|
||||||
|
:modes="['text']"
|
||||||
ref="codeEdit"/>
|
ref="codeEdit"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,59 +25,75 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
||||||
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
||||||
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
|
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
|
||||||
import MsDrawer from "../../../../common/components/MsDrawer";
|
import MsDrawer from "../../../../common/components/MsDrawer";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "BatchAddParameter",
|
name: "BatchAddParameter",
|
||||||
components: {
|
components: {
|
||||||
MsDrawer,
|
MsDrawer,
|
||||||
MsDialogFooter,
|
MsDialogFooter,
|
||||||
MsCodeEdit
|
MsCodeEdit
|
||||||
|
},
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
parameters: "",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open() {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
listenGoBack(this.handleClose);
|
||||||
},
|
},
|
||||||
props: {},
|
handleClose() {
|
||||||
data() {
|
this.parameters = "";
|
||||||
return {
|
this.dialogVisible = false;
|
||||||
dialogVisible: false,
|
removeGoBackListener(this.handleClose);
|
||||||
parameters: "",
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
confirm() {
|
||||||
open() {
|
let params = this.parameters.split("\n");
|
||||||
this.dialogVisible = true;
|
let index = 1;
|
||||||
listenGoBack(this.handleClose);
|
let isNormal = true;
|
||||||
},
|
params.forEach(item => {
|
||||||
handleClose() {
|
if (item) {
|
||||||
this.parameters = "";
|
let line = item.split(/:|:/);
|
||||||
this.dialogVisible = false;
|
if (!line[0]) {
|
||||||
removeGoBackListener(this.handleClose);
|
isNormal = false;
|
||||||
},
|
this.$warning(this.$t('api_test.params_format_warning', [index]) + " :" + this.$t('api_test.automation.variable_warning'));
|
||||||
confirm() {
|
return;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (isNormal) {
|
||||||
this.dialogVisible = false;
|
this.dialogVisible = false;
|
||||||
this.$emit("batchSave", this.parameters);
|
this.$emit("batchSave", this.parameters);
|
||||||
this.parameters = "";
|
this.parameters = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
.ms-drawer {
|
.ms-drawer {
|
||||||
padding: 10px 13px;
|
padding: 10px 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ms-code {
|
.ms-code {
|
||||||
height: calc(100vh);
|
height: calc(100vh);
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons .el-button {
|
.buttons .el-button {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons .el-button:nth-child(2) {
|
.buttons .el-button:nth-child(2) {
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -302,7 +302,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isAdd) {
|
if (isAdd) {
|
||||||
this.body.kvs.unshift(obj);
|
this.body.kvs.splice(this.body.kvs.indexOf(kv => !kv.name), 0, obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -311,22 +311,24 @@ export default {
|
||||||
let params = data.split("\n");
|
let params = data.split("\n");
|
||||||
let keyValues = [];
|
let keyValues = [];
|
||||||
params.forEach(item => {
|
params.forEach(item => {
|
||||||
let line = [];
|
if (item) {
|
||||||
line[0] = item.substring(0, item.indexOf(":"));
|
let line = [];
|
||||||
line[1] = item.substring(item.indexOf(":") + 1, item.length);
|
line[0] = item.substring(0, item.indexOf(":"));
|
||||||
let required = false;
|
line[1] = item.substring(item.indexOf(":") + 1, item.length);
|
||||||
keyValues.unshift(new KeyValue({
|
let required = false;
|
||||||
name: line[0],
|
keyValues.push(new KeyValue({
|
||||||
required: required,
|
name: line[0],
|
||||||
value: line[1],
|
required: required,
|
||||||
description: line[2],
|
value: line[1],
|
||||||
type: "text",
|
description: line[2],
|
||||||
valid: false,
|
type: "text",
|
||||||
file: false,
|
valid: false,
|
||||||
encode: true,
|
file: false,
|
||||||
enable: true,
|
encode: true,
|
||||||
contentType: "text/plain"
|
enable: true,
|
||||||
}));
|
contentType: "text/plain"
|
||||||
|
}));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
keyValues.forEach(item => {
|
keyValues.forEach(item => {
|
||||||
this.format(this.body.kvs, item);
|
this.format(this.body.kvs, item);
|
||||||
|
|
|
@ -2,19 +2,22 @@
|
||||||
<el-main v-loading="result.loading">
|
<el-main v-loading="result.loading">
|
||||||
<el-form :model="environment" :rules="rules" ref="environment">
|
<el-form :model="environment" :rules="rules" ref="environment">
|
||||||
|
|
||||||
<span>{{$t('api_test.environment.name')}}</span>
|
<span>{{ $t('api_test.environment.name') }}</span>
|
||||||
<el-form-item prop="name">
|
<el-form-item prop="name">
|
||||||
<el-input v-model="environment.name" :disabled="isReadOnly" :placeholder="this.$t('commons.input_name')" clearable/>
|
<el-input v-model="environment.name" :disabled="isReadOnly" :placeholder="this.$t('commons.input_name')"
|
||||||
|
clearable/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
|
||||||
<el-tabs v-model="activeName">
|
<el-tabs v-model="activeName">
|
||||||
<el-tab-pane :label="$t('api_test.environment.common_config')" name="common">
|
<el-tab-pane :label="$t('api_test.environment.common_config')" name="common">
|
||||||
<ms-environment-common-config :common-config="environment.config.commonConfig" ref="commonConfig" :is-read-only="isReadOnly"/>
|
<ms-environment-common-config :common-config="environment.config.commonConfig" ref="commonConfig"
|
||||||
|
:is-read-only="isReadOnly"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-tab-pane :label="$t('api_test.environment.http_config')" name="http">
|
<el-tab-pane :label="$t('api_test.environment.http_config')" name="http">
|
||||||
<ms-environment-http-config :http-config="environment.config.httpConfig" ref="httpConfig" :is-read-only="isReadOnly"/>
|
<ms-environment-http-config :http-config="environment.config.httpConfig" ref="httpConfig"
|
||||||
|
:is-read-only="isReadOnly"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('api_test.environment.database_config')" name="sql">
|
<el-tab-pane :label="$t('api_test.environment.database_config')" name="sql">
|
||||||
<ms-database-config :configs="environment.config.databaseConfigs" :is-read-only="isReadOnly"/>
|
<ms-database-config :configs="environment.config.databaseConfigs" :is-read-only="isReadOnly"/>
|
||||||
|
@ -34,136 +37,237 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsApiScenarioVariables from "../ApiScenarioVariables";
|
import MsApiScenarioVariables from "../ApiScenarioVariables";
|
||||||
import MsApiKeyValue from "../ApiKeyValue";
|
import MsApiKeyValue from "../ApiKeyValue";
|
||||||
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
||||||
import {REQUEST_HEADERS} from "@/common/js/constants";
|
import {REQUEST_HEADERS} from "@/common/js/constants";
|
||||||
import {Environment} from "../../model/EnvironmentModel";
|
import {Environment} from "../../model/EnvironmentModel";
|
||||||
import MsApiHostTable from "./ApiHostTable";
|
import MsApiHostTable from "./ApiHostTable";
|
||||||
import MsDatabaseConfig from "../request/database/DatabaseConfig";
|
import MsDatabaseConfig from "../request/database/DatabaseConfig";
|
||||||
import MsEnvironmentHttpConfig from "../../../test/components/environment/EnvironmentHttpConfig";
|
import MsEnvironmentHttpConfig from "../../../test/components/environment/EnvironmentHttpConfig";
|
||||||
import MsEnvironmentCommonConfig from "./EnvironmentCommonConfig";
|
import MsEnvironmentCommonConfig from "./EnvironmentCommonConfig";
|
||||||
import EnvironmentTcpConfig from "./EnvironmentTcpConfig";
|
import EnvironmentTcpConfig from "./EnvironmentTcpConfig";
|
||||||
|
import {getUploadConfig, request} from "@/common/js/ajax";
|
||||||
|
import {getUUID} from "@/common/js/utils";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "EnvironmentEdit",
|
name: "EnvironmentEdit",
|
||||||
components: {
|
components: {
|
||||||
EnvironmentTcpConfig,
|
EnvironmentTcpConfig,
|
||||||
MsEnvironmentCommonConfig,
|
MsEnvironmentCommonConfig,
|
||||||
MsEnvironmentHttpConfig,
|
MsEnvironmentHttpConfig,
|
||||||
MsDatabaseConfig, MsApiHostTable, MsDialogFooter, MsApiKeyValue, MsApiScenarioVariables},
|
MsDatabaseConfig, MsApiHostTable, MsDialogFooter, MsApiKeyValue, MsApiScenarioVariables
|
||||||
props: {
|
},
|
||||||
environment: new Environment(),
|
props: {
|
||||||
isReadOnly: {
|
environment: new Environment(),
|
||||||
type: Boolean,
|
isReadOnly: {
|
||||||
default: false
|
type: Boolean,
|
||||||
},
|
default: false
|
||||||
},
|
},
|
||||||
data() {
|
},
|
||||||
|
data() {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: {},
|
result: {},
|
||||||
envEnable: false,
|
envEnable: false,
|
||||||
rules: {
|
rules: {
|
||||||
name: [
|
name: [
|
||||||
{required: true, message: this.$t('commons.input_name'), trigger: 'blur'},
|
{required: true, message: this.$t('commons.input_name'), trigger: 'blur'},
|
||||||
{max: 64, message: this.$t('commons.input_limit', [1, 64]), trigger: 'blur'}
|
{max: 64, message: this.$t('commons.input_limit', [1, 64]), trigger: 'blur'}
|
||||||
],
|
],
|
||||||
},
|
|
||||||
headerSuggestions: REQUEST_HEADERS,
|
|
||||||
activeName: 'common'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
environment: function (o) {
|
|
||||||
this.envEnable = o.enable;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
save() {
|
|
||||||
this.$refs['environment'].validate((valid) => {
|
|
||||||
if (valid && this.$refs.commonConfig.validate() && this.$refs.httpConfig.validate()) {
|
|
||||||
this._save(this.environment);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
validate() {
|
headerSuggestions: REQUEST_HEADERS,
|
||||||
let isValidate = false;
|
activeName: 'common'
|
||||||
this.$refs['environment'].validate((valid) => {
|
}
|
||||||
if (valid && this.$refs.commonConfig.validate() && this.$refs.httpConfig.validate()) {
|
},
|
||||||
isValidate = true;
|
watch: {
|
||||||
} else {
|
environment: function (o) {
|
||||||
isValidate = false;
|
this.envEnable = o.enable;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
return isValidate;
|
methods: {
|
||||||
},
|
save() {
|
||||||
_save(environment) {
|
this.$refs['environment'].validate((valid) => {
|
||||||
let param = this.buildParam(environment);
|
if (valid && this.$refs.commonConfig.validate() && this.$refs.httpConfig.validate()) {
|
||||||
let url = '/api/environment/add';
|
this._save(this.environment);
|
||||||
if (param.id) {
|
|
||||||
url = '/api/environment/update';
|
|
||||||
}
|
}
|
||||||
this.result = this.$fileUpload(url, null, [], param, response => {
|
});
|
||||||
if (!param.id) {
|
},
|
||||||
environment.id = response.data;
|
validate() {
|
||||||
|
let isValidate = false;
|
||||||
|
this.$refs['environment'].validate((valid) => {
|
||||||
|
if (valid && this.$refs.commonConfig.validate() && this.$refs.httpConfig.validate()) {
|
||||||
|
isValidate = true;
|
||||||
|
} else {
|
||||||
|
isValidate = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return isValidate;
|
||||||
|
},
|
||||||
|
_save(environment) {
|
||||||
|
if (!this.projectId) {
|
||||||
|
this.$warning(this.$t('api_test.select_project'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (environment && environment.config && environment.config.commonConfig && environment.config.commonConfig.variables) {
|
||||||
|
let repeatKey = this.check(environment.config.commonConfig && environment.config.commonConfig.variables);
|
||||||
|
if (repeatKey !== "") {
|
||||||
|
this.$warning(this.$t('api_test.environment.common_config') + "【" + repeatKey + "】" + this.$t('load_test.param_is_duplicate'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let message = '';
|
||||||
|
if (environment && environment.config && environment.config.httpConfig && environment.config.httpConfig.conditions) {
|
||||||
|
environment.config.httpConfig.conditions.forEach(env => {
|
||||||
|
if (env.type === "MODULE" && env.details.length === 0) {
|
||||||
|
message += this.$t('load_test.domain') + ":" + env.socket + ":" + this.$t('api_test.environment.module_warning');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (env.type === "PATH" && env.details) {
|
||||||
|
env.details.forEach(item => {
|
||||||
|
if (!item.name) {
|
||||||
|
message += this.$t('load_test.domain') + ":" + env.socket + ":" + this.$t('api_test.environment.path_warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
environment.config.commonConfig.variables.forEach(variable => {
|
||||||
|
if (variable.type === 'CSV' && variable.files.length === 0) {
|
||||||
|
message = this.$t('api_test.automation.csv_warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (message) {
|
||||||
|
this.$warning(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bodyFiles = this.geFiles(environment);
|
||||||
|
let variablesFiles = this.getVariablesFiles(environment);
|
||||||
|
let formData = new FormData();
|
||||||
|
if (bodyFiles) {
|
||||||
|
bodyFiles.forEach(f => {
|
||||||
|
formData.append("files", f);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (variablesFiles) {
|
||||||
|
variablesFiles.forEach(f => {
|
||||||
|
formData.append("variablesFiles", f);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let param = this.buildParam(environment);
|
||||||
|
let url = '/api/environment/add';
|
||||||
|
if (param.id) {
|
||||||
|
url = '/api/environment/update';
|
||||||
|
}
|
||||||
|
formData.append('request', new Blob([JSON.stringify(param)], {type: "application/json"}));
|
||||||
|
let axiosRequestConfig = getUploadConfig(url, formData);
|
||||||
|
request(axiosRequestConfig, (response) => {
|
||||||
|
if (response.success) {
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
});
|
this.$emit('refreshAfterSave'); //在EnvironmentList.vue中监听,使在数据修改后进行刷新
|
||||||
},
|
this.cancel()
|
||||||
buildParam: function (environment) {
|
|
||||||
let param = {};
|
|
||||||
Object.assign(param, environment);
|
|
||||||
let hosts = param.config.commonConfig.hosts;
|
|
||||||
if (hosts != undefined) {
|
|
||||||
let validHosts = [];
|
|
||||||
// 去除掉未确认的host
|
|
||||||
hosts.forEach(host => {
|
|
||||||
if (host.status === '') {
|
|
||||||
validHosts.push(host);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
param.config.commonConfig.hosts = validHosts;
|
|
||||||
}
|
}
|
||||||
param.config = JSON.stringify(param.config);
|
}, error => {
|
||||||
return param;
|
this.$emit('errorRefresh', error);
|
||||||
},
|
});
|
||||||
cancel() {
|
|
||||||
this.$emit('close');
|
|
||||||
},
|
|
||||||
clearValidate() {
|
|
||||||
this.$refs["environment"].clearValidate();
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
geFiles(obj) {
|
||||||
|
let uploadFiles = [];
|
||||||
|
obj.uploadIds = [];
|
||||||
|
if (obj.config && obj.config.sslConfig && obj.config.sslConfig.files) {
|
||||||
|
obj.config.sslConfig.files.forEach(item => {
|
||||||
|
if (item.file && item.file.size > 0) {
|
||||||
|
if (!item.id) {
|
||||||
|
item.name = item.file.name;
|
||||||
|
item.id = getUUID();
|
||||||
|
}
|
||||||
|
obj.uploadIds.push(item.id);
|
||||||
|
uploadFiles.push(item.file);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return uploadFiles;
|
||||||
|
},
|
||||||
|
getVariablesFiles(obj) {
|
||||||
|
let variablesFiles = [];
|
||||||
|
obj.variablesFilesIds = [];
|
||||||
|
// 场景变量csv 文件
|
||||||
|
if (obj.config.commonConfig.variables) {
|
||||||
|
obj.config.commonConfig.variables.forEach(param => {
|
||||||
|
if (param.type === 'CSV' && param.files) {
|
||||||
|
param.files.forEach(item => {
|
||||||
|
if (item.file && item.file.name) {
|
||||||
|
if (!item.id) {
|
||||||
|
let fileId = getUUID().substring(0, 12);
|
||||||
|
item.name = item.file.name;
|
||||||
|
item.id = fileId;
|
||||||
|
}
|
||||||
|
obj.variablesFilesIds.push(item.id);
|
||||||
|
variablesFiles.push(item.file);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return variablesFiles;
|
||||||
|
},
|
||||||
|
buildParam: function (environment) {
|
||||||
|
let param = {};
|
||||||
|
Object.assign(param, environment);
|
||||||
|
let hosts = param.config.commonConfig.hosts;
|
||||||
|
if (hosts != undefined) {
|
||||||
|
let validHosts = [];
|
||||||
|
// 去除掉未确认的host
|
||||||
|
hosts.forEach(host => {
|
||||||
|
if (host.status === '') {
|
||||||
|
validHosts.push(host);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
param.config.commonConfig.hosts = validHosts;
|
||||||
|
}
|
||||||
|
param.config = JSON.stringify(param.config);
|
||||||
|
return param;
|
||||||
|
},
|
||||||
|
cancel() {
|
||||||
|
this.$emit('close');
|
||||||
|
},
|
||||||
|
clearValidate() {
|
||||||
|
this.$refs["environment"].clearValidate();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
.el-main {
|
.el-main {
|
||||||
border: solid 1px #EBEEF5;
|
border: solid 1px #EBEEF5;
|
||||||
margin-left: 200px;
|
margin-left: 200px;
|
||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
max-height: 700px;
|
max-height: 700px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-row {
|
.el-row {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.environment-footer {
|
.environment-footer {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
span:not(:first-child) {
|
span:not(:first-child) {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -274,22 +274,24 @@ export default {
|
||||||
let params = data.split("\n");
|
let params = data.split("\n");
|
||||||
let keyValues = [];
|
let keyValues = [];
|
||||||
params.forEach(item => {
|
params.forEach(item => {
|
||||||
let line = [];
|
if (item) {
|
||||||
line[0] = item.substring(0,item.indexOf(":"));
|
let line = [];
|
||||||
line[1] = item.substring(item.indexOf(":")+1,item.length);
|
line[0] = item.substring(0, item.indexOf(":"));
|
||||||
let required = false;
|
line[1] = item.substring(item.indexOf(":") + 1, item.length);
|
||||||
keyValues.unshift(new KeyValue({
|
let required = false;
|
||||||
name: line[0],
|
keyValues.push(new KeyValue({
|
||||||
required: required,
|
name: line[0],
|
||||||
value: line[1],
|
required: required,
|
||||||
description: line[2],
|
value: line[1],
|
||||||
type: "text",
|
description: line[2],
|
||||||
valid: false,
|
type: "text",
|
||||||
file: false,
|
valid: false,
|
||||||
encode: true,
|
file: false,
|
||||||
enable: true,
|
encode: true,
|
||||||
contentType: "text/plain"
|
enable: true,
|
||||||
}));
|
contentType: "text/plain"
|
||||||
|
}));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
keyValues.forEach(item => {
|
keyValues.forEach(item => {
|
||||||
this.format(this.body.kvs, item);
|
this.format(this.body.kvs, item);
|
||||||
|
|
|
@ -19,51 +19,51 @@
|
||||||
<el-switch active-text="JSON-SCHEMA" v-model="body.format" @change="formatChange" active-value="JSON-SCHEMA"/>
|
<el-switch active-text="JSON-SCHEMA" v-model="body.format" @change="formatChange" active-value="JSON-SCHEMA"/>
|
||||||
</div>
|
</div>
|
||||||
<ms-json-code-edit
|
<ms-json-code-edit
|
||||||
v-if="body.format==='JSON-SCHEMA'"
|
v-if="body.format==='JSON-SCHEMA'"
|
||||||
:body="body"
|
:body="body"
|
||||||
:show-mock-vars="true"
|
:show-mock-vars="true"
|
||||||
ref="jsonCodeEdit"/>
|
ref="jsonCodeEdit"/>
|
||||||
<ms-code-edit
|
<ms-code-edit
|
||||||
v-else-if="codeEditActive && loadIsOver"
|
v-else-if="codeEditActive && loadIsOver"
|
||||||
:read-only="isReadOnly"
|
:read-only="isReadOnly"
|
||||||
:data.sync="body.raw"
|
:data.sync="body.raw"
|
||||||
:modes="modes"
|
:modes="modes"
|
||||||
:mode="'json'"
|
:mode="'json'"
|
||||||
height="90%"
|
height="90%"
|
||||||
ref="codeEdit"/>
|
ref="codeEdit"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ms-body" v-if="body.type == 'fromApi'">
|
<div class="ms-body" v-if="body.type == 'fromApi'">
|
||||||
<ms-code-edit
|
<ms-code-edit
|
||||||
:read-only="true"
|
:read-only="true"
|
||||||
:data.sync="body.apiRspRaw"
|
:data.sync="body.apiRspRaw"
|
||||||
:modes="modes"
|
:modes="modes"
|
||||||
:mode="'text'"
|
:mode="'text'"
|
||||||
v-if="loadIsOver"
|
v-if="loadIsOver"
|
||||||
height="90%"
|
height="90%"
|
||||||
ref="fromApiCodeEdit"/>
|
ref="fromApiCodeEdit"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ms-body" v-if="body.type == 'XML'">
|
<div class="ms-body" v-if="body.type == 'XML'">
|
||||||
<el-input v-model="body.xmlHeader" size="small" style="width: 400px;margin-bottom: 5px"/>
|
<el-input v-model="body.xmlHeader" size="small" style="width: 400px;margin-bottom: 5px"/>
|
||||||
<ms-code-edit
|
<ms-code-edit
|
||||||
:read-only="isReadOnly"
|
:read-only="isReadOnly"
|
||||||
:data.sync="body.xmlRaw"
|
:data.sync="body.xmlRaw"
|
||||||
:modes="modes"
|
:modes="modes"
|
||||||
:mode="'xml'"
|
:mode="'xml'"
|
||||||
v-if="loadIsOver"
|
v-if="loadIsOver"
|
||||||
height="90%"
|
height="90%"
|
||||||
ref="codeEdit"/>
|
ref="codeEdit"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ms-body" v-if="body.type == 'Raw'">
|
<div class="ms-body" v-if="body.type == 'Raw'">
|
||||||
<ms-code-edit
|
<ms-code-edit
|
||||||
:read-only="isReadOnly"
|
:read-only="isReadOnly"
|
||||||
:data.sync="body.raw"
|
:data.sync="body.raw"
|
||||||
:modes="modes"
|
:modes="modes"
|
||||||
v-if="loadIsOver"
|
v-if="loadIsOver"
|
||||||
height="90%"
|
height="90%"
|
||||||
ref="codeEdit"/>
|
ref="codeEdit"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<batch-add-parameter @batchSave="batchSave" ref="batchAddParameter"/>
|
<batch-add-parameter @batchSave="batchSave" ref="batchAddParameter"/>
|
||||||
|
@ -309,22 +309,24 @@ export default {
|
||||||
let params = data.split("\n");
|
let params = data.split("\n");
|
||||||
let keyValues = [];
|
let keyValues = [];
|
||||||
params.forEach(item => {
|
params.forEach(item => {
|
||||||
let line = [];
|
if (item) {
|
||||||
line[0] = item.substring(0, item.indexOf(":"));
|
let line = [];
|
||||||
line[1] = item.substring(item.indexOf(":") + 1, item.length);
|
line[0] = item.substring(0, item.indexOf(":"));
|
||||||
let required = false;
|
line[1] = item.substring(item.indexOf(":") + 1, item.length);
|
||||||
keyValues.unshift(new KeyValue({
|
let required = false;
|
||||||
name: line[0],
|
keyValues.push(new KeyValue({
|
||||||
required: required,
|
name: line[0],
|
||||||
value: line[1],
|
required: required,
|
||||||
description: line[2],
|
value: line[1],
|
||||||
type: "text",
|
description: line[2],
|
||||||
valid: false,
|
type: "text",
|
||||||
file: false,
|
valid: false,
|
||||||
encode: true,
|
file: false,
|
||||||
enable: true,
|
encode: true,
|
||||||
contentType: "text/plain"
|
enable: true,
|
||||||
}));
|
contentType: "text/plain"
|
||||||
|
}));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
keyValues.forEach(item => {
|
keyValues.forEach(item => {
|
||||||
this.format(this.body.kvs, item);
|
this.format(this.body.kvs, item);
|
||||||
|
|
|
@ -19,14 +19,14 @@
|
||||||
</el-link>
|
</el-link>
|
||||||
</el-row>
|
</el-row>
|
||||||
<ms-api-key-value
|
<ms-api-key-value
|
||||||
@editScenarioAdvance="editScenarioAdvance"
|
@editScenarioAdvance="editScenarioAdvance"
|
||||||
:scenario-definition="scenarioDefinition"
|
:scenario-definition="scenarioDefinition"
|
||||||
:show-desc="true"
|
:show-desc="true"
|
||||||
:is-read-only="isReadOnly"
|
:is-read-only="isReadOnly"
|
||||||
:isShowEnable="isShowEnable"
|
:isShowEnable="isShowEnable"
|
||||||
:suggestions="headerSuggestions"
|
:suggestions="headerSuggestions"
|
||||||
:items="headers"
|
:items="headers"
|
||||||
:need-mock="true" v-if="activeName === 'headers'"/>
|
:need-mock="true" v-if="activeName === 'headers'"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<!--query 参数-->
|
<!--query 参数-->
|
||||||
|
@ -45,13 +45,13 @@
|
||||||
</el-link>
|
</el-link>
|
||||||
</el-row>
|
</el-row>
|
||||||
<ms-api-variable
|
<ms-api-variable
|
||||||
@editScenarioAdvance="editScenarioAdvance"
|
@editScenarioAdvance="editScenarioAdvance"
|
||||||
:scenario-definition="scenarioDefinition"
|
:scenario-definition="scenarioDefinition"
|
||||||
:with-mor-setting="true"
|
:with-mor-setting="true"
|
||||||
:is-read-only="isReadOnly"
|
:is-read-only="isReadOnly"
|
||||||
:isShowEnable="isShowEnable"
|
:isShowEnable="isShowEnable"
|
||||||
:parameters="request.arguments"
|
:parameters="request.arguments"
|
||||||
v-if="activeName === 'parameters'"
|
v-if="activeName === 'parameters'"
|
||||||
/>
|
/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
|
@ -72,13 +72,13 @@
|
||||||
</el-link>
|
</el-link>
|
||||||
</el-row>
|
</el-row>
|
||||||
<ms-api-variable
|
<ms-api-variable
|
||||||
@editScenarioAdvance="editScenarioAdvance"
|
@editScenarioAdvance="editScenarioAdvance"
|
||||||
:scenario-definition="scenarioDefinition"
|
:scenario-definition="scenarioDefinition"
|
||||||
:with-mor-setting="true"
|
:with-mor-setting="true"
|
||||||
:is-read-only="isReadOnly"
|
:is-read-only="isReadOnly"
|
||||||
:isShowEnable="isShowEnable"
|
:isShowEnable="isShowEnable"
|
||||||
:parameters="request.rest"
|
:parameters="request.rest"
|
||||||
v-if="activeName === 'rest'"
|
v-if="activeName === 'rest'"
|
||||||
/>
|
/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
|
@ -105,17 +105,17 @@
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<ms-api-auth-config
|
<ms-api-auth-config
|
||||||
:is-read-only="isReadOnly"
|
:is-read-only="isReadOnly"
|
||||||
:request="request"
|
:request="request"
|
||||||
v-if="activeName === 'authConfig'"
|
v-if="activeName === 'authConfig'"
|
||||||
/>
|
/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-tab-pane :label="$t('api_test.definition.request.other_config')" name="advancedConfig">
|
<el-tab-pane :label="$t('api_test.definition.request.other_config')" name="advancedConfig">
|
||||||
<ms-api-advanced-config
|
<ms-api-advanced-config
|
||||||
:is-read-only="isReadOnly"
|
:is-read-only="isReadOnly"
|
||||||
:request="request"
|
:request="request"
|
||||||
v-if="activeName === 'advancedConfig'"
|
v-if="activeName === 'advancedConfig'"
|
||||||
/>
|
/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
|
@ -128,13 +128,13 @@
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
<ms-jmx-step
|
<ms-jmx-step
|
||||||
:request="request"
|
:request="request"
|
||||||
:apiId="request.id"
|
:apiId="request.id"
|
||||||
:response="response"
|
:response="response"
|
||||||
:tab-type="'pre'"
|
:tab-type="'pre'"
|
||||||
:scenarioId="scenarioId"
|
:scenarioId="scenarioId"
|
||||||
ref="preStep"
|
ref="preStep"
|
||||||
v-if="activeName === 'preOperate'"
|
v-if="activeName === 'preOperate'"
|
||||||
/>
|
/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('api_test.definition.request.post_operation')" name="postOperate" v-if="showScript">
|
<el-tab-pane :label="$t('api_test.definition.request.post_operation')" name="postOperate" v-if="showScript">
|
||||||
|
@ -145,13 +145,13 @@
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
<ms-jmx-step
|
<ms-jmx-step
|
||||||
:request="request"
|
:request="request"
|
||||||
:apiId="request.id"
|
:apiId="request.id"
|
||||||
:response="response"
|
:response="response"
|
||||||
:tab-type="'post'"
|
:tab-type="'post'"
|
||||||
:scenarioId="scenarioId"
|
:scenarioId="scenarioId"
|
||||||
ref="postStep"
|
ref="postStep"
|
||||||
v-if="activeName === 'postOperate'"
|
v-if="activeName === 'postOperate'"
|
||||||
/>
|
/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('api_test.definition.request.assertions_rule')" name="assertionsRule" v-if="showScript">
|
<el-tab-pane :label="$t('api_test.definition.request.assertions_rule')" name="assertionsRule" v-if="showScript">
|
||||||
|
@ -162,14 +162,14 @@
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
<ms-jmx-step
|
<ms-jmx-step
|
||||||
:request="request"
|
:request="request"
|
||||||
:apiId="request.id"
|
:apiId="request.id"
|
||||||
:scenarioId="scenarioId"
|
:scenarioId="scenarioId"
|
||||||
:response="response"
|
:response="response"
|
||||||
@reload="reloadBody"
|
@reload="reloadBody"
|
||||||
:tab-type="'assertionsRule'"
|
:tab-type="'assertionsRule'"
|
||||||
ref="assertionsRule"
|
ref="assertionsRule"
|
||||||
v-if="activeName === 'assertionsRule'"/>
|
v-if="activeName === 'assertionsRule'"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
@ -424,13 +424,13 @@ export default {
|
||||||
if (isAdd) {
|
if (isAdd) {
|
||||||
switch (this.activeName) {
|
switch (this.activeName) {
|
||||||
case "parameters":
|
case "parameters":
|
||||||
this.request.arguments.unshift(obj);
|
this.request.arguments.splice(this.request.arguments.indexOf(h => !h.name), 0, obj);
|
||||||
break;
|
break;
|
||||||
case "rest":
|
case "rest":
|
||||||
this.request.rest.unshift(obj);
|
this.request.rest.splice(this.request.rest.indexOf(h => !h.name), 0, obj);
|
||||||
break;
|
break;
|
||||||
case "headers":
|
case "headers":
|
||||||
this.request.headers.unshift(obj);
|
this.request.headers.splice(this.request.headers.indexOf(h => !h.name), 0, obj);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -443,20 +443,22 @@ export default {
|
||||||
let params = data.split("\n");
|
let params = data.split("\n");
|
||||||
let keyValues = [];
|
let keyValues = [];
|
||||||
params.forEach(item => {
|
params.forEach(item => {
|
||||||
let line = item.split(/:|:/);
|
if (item) {
|
||||||
let values = item.split(line[0] + ":");
|
let line = item.split(/:|:/);
|
||||||
let required = false;
|
let values = item.split(line[0] + ":");
|
||||||
keyValues.unshift(new KeyValue({
|
let required = false;
|
||||||
name: line[0],
|
keyValues.push(new KeyValue({
|
||||||
required: required,
|
name: line[0],
|
||||||
value: values[1],
|
required: required,
|
||||||
type: "text",
|
value: values[1],
|
||||||
valid: false,
|
type: "text",
|
||||||
file: false,
|
valid: false,
|
||||||
encode: true,
|
file: false,
|
||||||
enable: true,
|
encode: true,
|
||||||
contentType: "text/plain"
|
enable: true,
|
||||||
}));
|
contentType: "text/plain"
|
||||||
|
}));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
keyValues.forEach(item => {
|
keyValues.forEach(item => {
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
:data="environments" :item-operators="environmentOperators" :add-fuc="addEnvironment"
|
:data="environments" :item-operators="environmentOperators" :add-fuc="addEnvironment"
|
||||||
:env-add-permission="ENV_CREATE"
|
:env-add-permission="ENV_CREATE"
|
||||||
:delete-fuc="openDelEnv" @itemSelected="environmentSelected" ref="environmentItems"/>
|
:delete-fuc="openDelEnv" @itemSelected="environmentSelected" ref="environmentItems"/>
|
||||||
<environment-edit :if-create="ifCreate" :project-id="projectId" :environment="currentEnvironment"
|
<environment-edit :if-create="ifCreate" :environment="currentEnvironment"
|
||||||
ref="environmentEdit" :is-read-only="isReadOnly"
|
ref="environmentEdit" :is-read-only="isReadOnly"
|
||||||
@confirm="save"
|
@confirm="save" :is-project="true"
|
||||||
@close="close"/>
|
@close="close"/>
|
||||||
</el-container>
|
</el-container>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
|
@ -112,7 +112,7 @@ export default {
|
||||||
let line = item.split(/:|:/);
|
let line = item.split(/:|:/);
|
||||||
let values = item.split(line[0] + ":");
|
let values = item.split(line[0] + ":");
|
||||||
let required = false;
|
let required = false;
|
||||||
keyValues.unshift(new KeyValue({
|
keyValues.push(new KeyValue({
|
||||||
name: line[0],
|
name: line[0],
|
||||||
required: required,
|
required: required,
|
||||||
value: values[1],
|
value: values[1],
|
||||||
|
|
|
@ -0,0 +1,399 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div style="padding-bottom: 10px;float: left">
|
||||||
|
<el-input :placeholder="$t('commons.search_by_name')" size="mini" v-model="selectVariable"
|
||||||
|
@change="filter"
|
||||||
|
@keyup.enter="filter">
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
<div style="padding-bottom: 10px; float: right;">
|
||||||
|
<ms-table-button v-permission="['PROJECT_ENVIRONMENT:READ+IMPORT']" icon="el-icon-box"
|
||||||
|
:content="$t('commons.import')" @click="importJSON"/>
|
||||||
|
<ms-table-button v-permission="['PROJECT_ENVIRONMENT:READ+EXPORT']" icon="el-icon-box"
|
||||||
|
:content="$t('commons.export')" @click="exportJSON"/>
|
||||||
|
<el-link style="margin-left: 10px" @click="batchAdd" type="primary" :disabled="isReadOnly">
|
||||||
|
{{ $t("commons.batch_add") }}
|
||||||
|
</el-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style="border:1px #DCDFE6 solid; min-height: 300px;border-radius: 4px ;width: 99% ;margin-top: 10px; clear: both">
|
||||||
|
<ms-table
|
||||||
|
v-loading="loading"
|
||||||
|
row-key="id"
|
||||||
|
:data="variables"
|
||||||
|
:total="items.length"
|
||||||
|
:screen-height="screenHeight"
|
||||||
|
:batch-operators="batchButtons"
|
||||||
|
:remember-order="true"
|
||||||
|
:highlightCurrentRow="true"
|
||||||
|
@refresh="onChange"
|
||||||
|
ref="variableTable">
|
||||||
|
|
||||||
|
<ms-table-column
|
||||||
|
prop="num"
|
||||||
|
sortable
|
||||||
|
label="ID"
|
||||||
|
min-width="60">
|
||||||
|
</ms-table-column>
|
||||||
|
<ms-table-column prop="name" :label="$t('api_test.variable_name')" min-width="200" sortable>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-input
|
||||||
|
v-model="scope.row.name" size="mini"
|
||||||
|
maxlength="200" :placeholder="$t('api_test.variable_name')" show-word-limit
|
||||||
|
@change="change"/>
|
||||||
|
</template>
|
||||||
|
</ms-table-column>
|
||||||
|
<ms-table-column prop="type" :label="$t('test_track.case.type')" min-width="140" sortable>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-select v-model="scope.row.type" :placeholder="$t('commons.please_select')" size="mini"
|
||||||
|
@change="changeType(scope.row)">
|
||||||
|
<el-option v-for="item in typeSelectOptions " :key="item.value" :label="item.label" :value="item.value"/>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</ms-table-column>
|
||||||
|
|
||||||
|
<ms-table-column prop="value" :label="$t('api_test.value')"
|
||||||
|
min-width="200px" sortable>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-input v-model="scope.row.value" size="mini" v-if="scope.row.type !=='CSV'"
|
||||||
|
:placeholder="valueText(scope.row)"
|
||||||
|
:disabled="scope.row.type === 'COUNTER' || scope.row.type === 'RANDOM'"/>
|
||||||
|
<csv-file-upload :parameter="scope.row" v-if="scope.row.type ==='CSV'"/>
|
||||||
|
</template>
|
||||||
|
</ms-table-column>
|
||||||
|
<ms-table-column prop="description" :label="$t('commons.remark')"
|
||||||
|
min-width="160" sortable>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-input v-model="scope.row.description" size="mini"/>
|
||||||
|
</template>
|
||||||
|
</ms-table-column>
|
||||||
|
|
||||||
|
<ms-table-column :label="$t('commons.operating')" width="150" fixed="right">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<span>
|
||||||
|
<el-switch v-model="scope.row.enable" size="mini"/>
|
||||||
|
<el-tooltip effect="dark" :content="$t('commons.remove')" placement="top-start">
|
||||||
|
<el-button icon="el-icon-delete" type="danger" circle size="mini" style="margin-left: 10px"
|
||||||
|
@click="remove(scope.row)" v-if="scope.row.name"/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="dark" :content="$t('schema.adv_setting')" placement="top-start">
|
||||||
|
<el-button icon="el-icon-setting" circle size="mini" style="margin-left: 10px"
|
||||||
|
@click="openSetting(scope.row)" v-if="scope.row.type !=='LIST'"/>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</ms-table-column>
|
||||||
|
</ms-table>
|
||||||
|
</div>
|
||||||
|
<batch-add-parameter @batchSave="batchSave" ref="batchAdd"/>
|
||||||
|
<api-variable-setting ref="apiVariableSetting"></api-variable-setting>
|
||||||
|
<variable-import ref="variableImport" @mergeData="mergeData"></variable-import>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {KeyValue} from "@/business/components/api/test/model/ScenarioModel";
|
||||||
|
import MsApiVariableInput from "@/business/components/api/automation/scenario/ApiVariableInput";
|
||||||
|
import BatchAddParameter from "@/business/components/api/definition/components/basis/BatchAddParameter";
|
||||||
|
import MsTableButton from "@/business/components/common/components/MsTableButton";
|
||||||
|
import MsTable from "@/business/components/common/components/table/MsTable";
|
||||||
|
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
|
||||||
|
import ApiVariableSetting from "@/business/components/api/test/components/environment/ApiVariableSetting";
|
||||||
|
import CsvFileUpload from "@/business/components/api/test/components/environment/CsvFileUpload";
|
||||||
|
import {downloadFile, getUUID} from "@/common/js/utils";
|
||||||
|
import VariableImport from "@/business/components/api/test/components/environment/VariableImport";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MsApiScenarioVariables",
|
||||||
|
components: {
|
||||||
|
BatchAddParameter,
|
||||||
|
MsApiVariableInput,
|
||||||
|
MsTableButton,
|
||||||
|
MsTable,
|
||||||
|
MsTableColumn,
|
||||||
|
ApiVariableSetting,
|
||||||
|
CsvFileUpload,
|
||||||
|
VariableImport
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
description: String,
|
||||||
|
items: Array,
|
||||||
|
isReadOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
showVariable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
showCopy: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
screenHeight: '400px',
|
||||||
|
batchButtons: [
|
||||||
|
{
|
||||||
|
name: this.$t('api_test.definition.request.batch_delete'),
|
||||||
|
handleClick: this.handleDeleteBatch,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
typeSelectOptions: [
|
||||||
|
{value: 'CONSTANT', label: this.$t('api_test.automation.constant')},
|
||||||
|
{value: 'LIST', label: this.$t('test_track.case.list')},
|
||||||
|
{value: 'CSV', label: 'CSV'},
|
||||||
|
{value: 'COUNTER', label: this.$t('api_test.automation.counter')},
|
||||||
|
{value: 'RANDOM', label: this.$t('api_test.automation.random')},
|
||||||
|
],
|
||||||
|
variables: {},
|
||||||
|
selectVariable: '',
|
||||||
|
editData: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
items: {
|
||||||
|
handler(v) {
|
||||||
|
this.variables = v;
|
||||||
|
this.sortParameters();
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
remove: function (index) {
|
||||||
|
const dataIndex = this.variables.findIndex(d => d.name === index.name);
|
||||||
|
this.variables.splice(dataIndex, 1);
|
||||||
|
this.$emit('change', this.variables);
|
||||||
|
},
|
||||||
|
change: function () {
|
||||||
|
let isNeedCreate = true;
|
||||||
|
let removeIndex = -1;
|
||||||
|
let repeatKey = "";
|
||||||
|
this.variables.forEach((item, index) => {
|
||||||
|
this.variables.forEach((row, rowIndex) => {
|
||||||
|
if (item.name === row.name && index !== rowIndex) {
|
||||||
|
repeatKey = item.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!item.name && !item.value) {
|
||||||
|
// 多余的空行
|
||||||
|
if (index !== this.items.length - 1) {
|
||||||
|
removeIndex = index;
|
||||||
|
}
|
||||||
|
// 没有空行,需要创建空行
|
||||||
|
isNeedCreate = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (repeatKey !== "") {
|
||||||
|
this.$warning(this.$t('api_test.environment.common_config') + "【" + repeatKey + "】" + this.$t('load_test.param_is_duplicate'));
|
||||||
|
}
|
||||||
|
if (isNeedCreate && !repeatKey) {
|
||||||
|
this.variables.push(new KeyValue({enable: true, id: getUUID(), type: 'CONSTANT'}));
|
||||||
|
}
|
||||||
|
this.$emit('change', this.variables);
|
||||||
|
// TODO 检查key重复
|
||||||
|
|
||||||
|
},
|
||||||
|
changeType(data) {
|
||||||
|
if (!data.delimiter || (!data.files && data.files.length === 0) || !data.quotedData) {
|
||||||
|
data.delimiter = ',';
|
||||||
|
data.files = [];
|
||||||
|
data.quotedData = 'false';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
valueText(data) {
|
||||||
|
switch (data.type) {
|
||||||
|
case 'LIST':
|
||||||
|
return this.$t('api_test.environment.list_info');
|
||||||
|
case 'CONSTANT':
|
||||||
|
return this.$t('api_test.value');
|
||||||
|
case 'COUNTER':
|
||||||
|
case 'RANDOM':
|
||||||
|
return this.$t('api_test.environment.advanced_setting');
|
||||||
|
default:
|
||||||
|
return this.$t('api_test.value');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
querySearch(queryString, cb) {
|
||||||
|
let restaurants = [{value: "UTF-8"}, {value: "UTF-16"}, {value: "GB2312"}, {value: "ISO-8859-15"}, {value: "US-ASCll"}];
|
||||||
|
let results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
|
||||||
|
// 调用 callback 返回建议列表的数据
|
||||||
|
cb(results);
|
||||||
|
},
|
||||||
|
sortParameters() {
|
||||||
|
let index = 1;
|
||||||
|
this.variables.forEach(item => {
|
||||||
|
item.num = index;
|
||||||
|
if (!item.type || item.type === 'text') {
|
||||||
|
item.type = 'CONSTANT';
|
||||||
|
}
|
||||||
|
if (!item.id) {
|
||||||
|
item.id = getUUID();
|
||||||
|
}
|
||||||
|
if (item.remark) {
|
||||||
|
item.description = item.remark;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleDeleteBatch() {
|
||||||
|
this.$alert(this.$t('api_test.environment.variables_delete_info') + ' ' + " ?", '', {
|
||||||
|
confirmButtonText: this.$t('commons.confirm'),
|
||||||
|
callback: (action) => {
|
||||||
|
if (action === 'confirm') {
|
||||||
|
let ids = this.$refs.variableTable.selectRows;
|
||||||
|
ids.forEach(row => {
|
||||||
|
if (row.name) {
|
||||||
|
const index = this.variables.findIndex(d => d.name === row.name);
|
||||||
|
this.variables.splice(index, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.sortParameters();
|
||||||
|
this.$refs.variableTable.cancelCurrentRow();
|
||||||
|
this.$refs.variableTable.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
filter() {
|
||||||
|
let datas = [];
|
||||||
|
this.variables.forEach(item => {
|
||||||
|
if (this.selectVariable && this.selectVariable != "" && item.name) {
|
||||||
|
if (item.name.toLowerCase().indexOf(this.selectVariable.toLowerCase()) == -1) {
|
||||||
|
item.hidden = true;
|
||||||
|
} else {
|
||||||
|
item.hidden = undefined;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.hidden = undefined;
|
||||||
|
}
|
||||||
|
datas.push(item);
|
||||||
|
});
|
||||||
|
this.variables = datas;
|
||||||
|
},
|
||||||
|
openSetting(data) {
|
||||||
|
this.$refs.apiVariableSetting.open(data);
|
||||||
|
},
|
||||||
|
isDisable: function (index) {
|
||||||
|
return this.items.length - 1 === index;
|
||||||
|
},
|
||||||
|
_handleBatchVars(data) {
|
||||||
|
let params = data.split("\n");
|
||||||
|
let keyValues = [];
|
||||||
|
params.forEach(item => {
|
||||||
|
if (item) {
|
||||||
|
let line = item.split(/:|:/);
|
||||||
|
let values = item.split(line[0] + ":");
|
||||||
|
let required = false;
|
||||||
|
keyValues.push(new KeyValue({
|
||||||
|
name: line[0],
|
||||||
|
required: required,
|
||||||
|
value: values[1],
|
||||||
|
type: 'CONSTANT',
|
||||||
|
valid: false,
|
||||||
|
file: false,
|
||||||
|
encode: true,
|
||||||
|
enable: true,
|
||||||
|
description: undefined
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return keyValues;
|
||||||
|
},
|
||||||
|
batchAdd() {
|
||||||
|
this.$refs.batchAdd.open();
|
||||||
|
},
|
||||||
|
batchSave(data) {
|
||||||
|
if (data) {
|
||||||
|
let keyValues = this._handleBatchVars(data);
|
||||||
|
keyValues.forEach(keyValue => {
|
||||||
|
let isAdd = true;
|
||||||
|
this.variables.forEach(item => {
|
||||||
|
if (item.name === keyValue.name) {
|
||||||
|
item.value = keyValue.value;
|
||||||
|
isAdd = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (isAdd) {
|
||||||
|
this.variables.splice(this.variables.indexOf(i => !i.name), 0, keyValue);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onChange() {
|
||||||
|
this.sortParameters();
|
||||||
|
},
|
||||||
|
exportJSON() {
|
||||||
|
if (this.$refs.variableTable.selectIds.length < 1) {
|
||||||
|
this.$warning(this.$t('api_test.environment.select_variable'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let variablesJson = [];
|
||||||
|
let messages = '';
|
||||||
|
let rows = this.$refs.variableTable.selectRows;
|
||||||
|
rows.forEach(row => {
|
||||||
|
if (row.type === 'CSV') {
|
||||||
|
messages = this.$t('variables.csv_download')
|
||||||
|
}
|
||||||
|
if (row.name) {
|
||||||
|
variablesJson.push(row);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (messages !== '') {
|
||||||
|
this.$warning(messages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
downloadFile('MS_' + variablesJson.length + '_Environments_variables.json', JSON.stringify(variablesJson));
|
||||||
|
},
|
||||||
|
importJSON() {
|
||||||
|
this.$refs.variableImport.open();
|
||||||
|
},
|
||||||
|
mergeData(data, modeId) {
|
||||||
|
JSON.parse(data).map(importData => {
|
||||||
|
importData.id = getUUID();
|
||||||
|
importData.enable = true;
|
||||||
|
importData.showMore = false;
|
||||||
|
let sameNameIndex = this.variables.findIndex(d => d.name === importData.name);
|
||||||
|
if (sameNameIndex !== -1) {
|
||||||
|
if (modeId === 'fullCoverage') {
|
||||||
|
this.variables.splice(sameNameIndex, 1, importData);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.variables.splice(this.variables.length - 1, 0, importData);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (this.items.length === 0) {
|
||||||
|
this.items.push(new KeyValue({enable: true}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.kv-description {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kv-checkbox {
|
||||||
|
width: 20px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kv-row {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kv-delete {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,306 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-tabs tab-position="top" @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)" @click.native.prevent="radioClick(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="environment">
|
||||||
|
<p>{{ $t('api_test.environment.environment') }}</p>
|
||||||
|
<el-tree :data="environmentParams" :props="treeProps" @node-click="selectVariable"></el-tree>
|
||||||
|
</div>
|
||||||
|
<div v-if="scenario">
|
||||||
|
<p>{{ $t('api_test.scenario.scenario') }}</p>
|
||||||
|
<el-tree :data="scenarioParams" :props="treeProps" @node-click="selectVariable"></el-tree>
|
||||||
|
</div>
|
||||||
|
<div v-if="preRequestParams">
|
||||||
|
<p>{{ $t('api_test.request.parameters_pre_request') }}</p>
|
||||||
|
<el-tree :data="preRequestParams" :props="treeProps" @node-click="selectVariable"></el-tree>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="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="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>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {calculate, Scenario} from "@/business/components/api/test/model/ScenarioModel";
|
||||||
|
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MsApiVariableAdvance",
|
||||||
|
props: {
|
||||||
|
parameters: Array,
|
||||||
|
environment: Object,
|
||||||
|
scenario: Scenario,
|
||||||
|
currentItem: Object,
|
||||||
|
appendToBody: {
|
||||||
|
type: Boolean,
|
||||||
|
default() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
itemValueVisible: false,
|
||||||
|
filterText: '',
|
||||||
|
environmentParams: [],
|
||||||
|
scenarioParams: [],
|
||||||
|
preRequests: [],
|
||||||
|
preRequestParams: [],
|
||||||
|
treeProps: {children: 'children', label: 'name'},
|
||||||
|
currentTab: 0,
|
||||||
|
itemValue: null,
|
||||||
|
itemValuePreview: null,
|
||||||
|
funcs: [
|
||||||
|
{name: "md5"},
|
||||||
|
{name: "base64"},
|
||||||
|
{name: "unbase64"},
|
||||||
|
{
|
||||||
|
name: "substr",
|
||||||
|
params: [{name: "start"}, {name: "length"}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "concat",
|
||||||
|
params: [{name: "suffix"}]
|
||||||
|
},
|
||||||
|
{name: "lconcat", params: [{name: "prefix"}]},
|
||||||
|
{name: "sha1"},
|
||||||
|
{name: "sha224"},
|
||||||
|
{name: "sha256"},
|
||||||
|
{name: "sha384"},
|
||||||
|
{name: "sha512"},
|
||||||
|
{name: "lower"},
|
||||||
|
{name: "upper"},
|
||||||
|
{name: "length"},
|
||||||
|
{name: "number"}
|
||||||
|
],
|
||||||
|
mockFuncs: MOCKJS_FUNC.map(f => {
|
||||||
|
return {name: f.name, value: f.name}
|
||||||
|
}),
|
||||||
|
jmeterFuncs: JMETER_FUNC,
|
||||||
|
mockVariableFuncs: [],
|
||||||
|
jmeterVariableFuncs: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
valueText() {
|
||||||
|
return this.valuePlaceholder || this.$t("api_test.value");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.prepareData();
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
filterText(val) {
|
||||||
|
this.$refs.tree.filter(val);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open() {
|
||||||
|
this.itemValueVisible = true;
|
||||||
|
},
|
||||||
|
prepareData() {
|
||||||
|
if (this.scenario) {
|
||||||
|
let variables = this.scenario.variables;
|
||||||
|
this.scenarioParams = [
|
||||||
|
{
|
||||||
|
name: this.scenario.name,
|
||||||
|
children: variables.filter(v => v.name).map(v => {
|
||||||
|
return {name: v.name, value: '${' + v.name + '}'}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
];
|
||||||
|
if (this.environment) {
|
||||||
|
let variables = 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});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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();
|
||||||
|
},
|
||||||
|
radioClick(itemFunc, func) {
|
||||||
|
if (itemFunc.name === func.name) {
|
||||||
|
let index = this.mockVariableFuncs.indexOf(itemFunc);
|
||||||
|
this.mockVariableFuncs = this.mockVariableFuncs.slice(0, index);
|
||||||
|
this.mockVariableFuncs.push({name: '', params: []});
|
||||||
|
let valindex = this.itemValue.indexOf('|' + func.name);
|
||||||
|
this.itemValue = this.itemValue.slice(0, valindex);
|
||||||
|
} else {
|
||||||
|
this.methodChange(itemFunc, func);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addFunc() {
|
||||||
|
if (this.itemValue.indexOf('@') == -1) {
|
||||||
|
this.itemValue = '@' + this.itemValue;
|
||||||
|
} else {
|
||||||
|
this.itemValue = this.itemValue;
|
||||||
|
}
|
||||||
|
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() {
|
||||||
|
if (this.itemValue && this.itemValue.indexOf('@') == -1) {
|
||||||
|
this.currentItem.value = '@' + this.itemValue;
|
||||||
|
} else {
|
||||||
|
this.currentItem.value = this.itemValue;
|
||||||
|
}
|
||||||
|
this.itemValueVisible = false;
|
||||||
|
this.mockVariableFuncs = [];
|
||||||
|
this.$emit('advancedRefresh', this.currentItem.value);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.col-height {
|
||||||
|
height: 40vh;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,88 @@
|
||||||
|
<template>
|
||||||
|
<ms-edit-dialog
|
||||||
|
:visible.sync="visible"
|
||||||
|
width="700px"
|
||||||
|
:title="$t('schema.adv_setting')"
|
||||||
|
:with-footer="false"
|
||||||
|
append-to-body
|
||||||
|
:close-on-click-modal="true">
|
||||||
|
<ms-api-variable-advance v-if="editData.type=='CONSTANT'" ref="variableAdvance" :current-item="editData"
|
||||||
|
@advancedRefresh="reload"/>
|
||||||
|
<ms-edit-counter v-if="editData.type=='COUNTER'" ref="counter" :editData.sync="editData"/>
|
||||||
|
<ms-edit-random v-if="editData.type=='RANDOM'" ref="random" :editData.sync="editData"/>
|
||||||
|
<ms-edit-csv v-if="editData.type=='CSV'" ref="csv" :editData.sync="editData"/>
|
||||||
|
|
||||||
|
<template v-slot:footer>
|
||||||
|
<ms-dialog-footer
|
||||||
|
@cancel="handleCancel"
|
||||||
|
@confirm="handleConfirm"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</ms-edit-dialog>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import MsEditDialog from "@/business/components/common/components/MsEditDialog";
|
||||||
|
import MsEditConstant from "@/business/components/api/automation/scenario/variable/EditConstant";
|
||||||
|
import MsEditCounter from "@/business/components/api/automation/scenario/variable/EditCounter";
|
||||||
|
import MsEditRandom from "@/business/components/api/automation/scenario/variable/EditRandom";
|
||||||
|
import MsEditListValue from "@/business/components/api/automation/scenario/variable/EditListValue";
|
||||||
|
import MsEditCsv from "@/business/components/api/automation/scenario/variable/EditCsv";
|
||||||
|
import MsApiVariableAdvance from "@/business/components/api/test/components/environment/ApiVariableAdvance";
|
||||||
|
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ApiVariableSetting",
|
||||||
|
components: {
|
||||||
|
MsEditDialog,
|
||||||
|
MsEditConstant,
|
||||||
|
MsEditCounter,
|
||||||
|
MsEditRandom,
|
||||||
|
MsEditListValue,
|
||||||
|
MsEditCsv,
|
||||||
|
MsApiVariableAdvance,
|
||||||
|
MsDialogFooter
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
data: {},
|
||||||
|
editData: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open(item) {
|
||||||
|
this.visible = true;
|
||||||
|
this.editData = item;
|
||||||
|
},
|
||||||
|
handleConfirm() {
|
||||||
|
if (this.editData.type === 'CONSTANT') {
|
||||||
|
this.$refs.variableAdvance.saveAdvanced();
|
||||||
|
}
|
||||||
|
if (this.editData.type === 'CSV' && this.$refs.csv) {
|
||||||
|
if (this.editData.files.length === 0) {
|
||||||
|
this.$warning(this.$t('api_test.automation.csv_warning'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.visible = false;
|
||||||
|
},
|
||||||
|
handleCancel() {
|
||||||
|
this.visible = false;
|
||||||
|
},
|
||||||
|
reload() {
|
||||||
|
this.isActive = false;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.isActive = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,273 @@
|
||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-upload
|
||||||
|
action="#"
|
||||||
|
class="api-body-upload"
|
||||||
|
list-type="picture-card"
|
||||||
|
:file-list="parameter.files"
|
||||||
|
:beforeUpload="uploadValidate"
|
||||||
|
:on-exceed="exceed"
|
||||||
|
:limit="1"
|
||||||
|
ref="upload">
|
||||||
|
<div class="upload-default" @click.stop>
|
||||||
|
<el-popover
|
||||||
|
placement="right"
|
||||||
|
trigger="hover">
|
||||||
|
<div>
|
||||||
|
<el-upload
|
||||||
|
action="#"
|
||||||
|
class="ms-body-upload"
|
||||||
|
:http-request="upload"
|
||||||
|
:limit="1"
|
||||||
|
:on-exceed="exceed"
|
||||||
|
:beforeUpload="uploadValidate"
|
||||||
|
ref="uploadLocal">
|
||||||
|
<el-button type="text"> {{ $t('permission.project_file.local_upload') }}</el-button>
|
||||||
|
<span slot="file"/>
|
||||||
|
</el-upload>
|
||||||
|
</div>
|
||||||
|
<el-button type="text" @click="associationFile">{{
|
||||||
|
$t('permission.project_file.associated_files')
|
||||||
|
}}</el-button>
|
||||||
|
<i class="el-icon-plus" slot="reference"/>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
<div class="upload-item" slot="file" slot-scope="{file}">
|
||||||
|
<span>{{ file.file && file.file.name ? file.file.name : file.name }}</span>
|
||||||
|
<span class="el-upload-list__item-actions" v-if="file.storage === 'FILE_REF'">
|
||||||
|
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleUnlock(file)">
|
||||||
|
<i class="el-icon-unlock"/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class="el-upload-list__item-actions" v-else>
|
||||||
|
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleUpload(file)">
|
||||||
|
<i class="el-icon-upload" style="font-size: 23px"/>
|
||||||
|
</span>
|
||||||
|
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)">
|
||||||
|
<i class="el-icon-delete"/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<ms-file-batch-move ref="module" @setModuleId="setModuleId"/>
|
||||||
|
<ms-file-metadata-list ref="metadataList" @checkRows="checkRows"/>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {downloadFile} from "@/common/js/utils";
|
||||||
|
import MsFileBatchMove from "@/business/components/project/menu/file/module/FileBatchMove";
|
||||||
|
import MsFileMetadataList from "@/business/components/project/menu/file/quote/QuoteFileList";
|
||||||
|
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MsCsvFileUpload",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
disabled: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
MsFileBatchMove,
|
||||||
|
MsFileMetadataList
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
parameter: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setModuleId(moduleId) {
|
||||||
|
let files = [];
|
||||||
|
if (this.file && this.file.file) {
|
||||||
|
files.push(this.file.file);
|
||||||
|
}
|
||||||
|
let request = {
|
||||||
|
id: getUUID(),
|
||||||
|
resourceId: this.id,
|
||||||
|
moduleId: moduleId,
|
||||||
|
projectId: getCurrentProjectID(),
|
||||||
|
fileName: this.file.name
|
||||||
|
};
|
||||||
|
this.$fileUpload("/file/metadata/api/upload", null, files, request, (response) => {
|
||||||
|
this.$success(this.$t("organization.integration.successful_operation"));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleUpload(file) {
|
||||||
|
this.$refs.module.init();
|
||||||
|
this.file = file;
|
||||||
|
},
|
||||||
|
associationFile() {
|
||||||
|
this.$refs.metadataList.open();
|
||||||
|
},
|
||||||
|
checkRows(rows) {
|
||||||
|
if (rows && rows.size !== 1 || this.parameter.files.length > 0) {
|
||||||
|
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rows.forEach(item => {
|
||||||
|
if (!item.type || item.type.toLowerCase() !== "csv") {
|
||||||
|
this.$warning(this.$t('variables.cvs_info'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let file = {
|
||||||
|
name: item.name,
|
||||||
|
id: getUUID(),
|
||||||
|
fileId: item.id,
|
||||||
|
storage: "FILE_REF",
|
||||||
|
projectId: item.projectId,
|
||||||
|
fileType: item.type
|
||||||
|
};
|
||||||
|
this.parameter.files.push(file);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleUnlock(file) {
|
||||||
|
for (let i = 0; i < this.parameter.files.length; i++) {
|
||||||
|
let fileName = file.file ? file.file.name : file.name;
|
||||||
|
let paramFileName = this.parameter.files[i].file ?
|
||||||
|
this.parameter.files[i].file.name : this.parameter.files[i].name;
|
||||||
|
if (fileName === paramFileName) {
|
||||||
|
this.parameter.files.splice(i, 1);
|
||||||
|
this.$refs.upload.handleRemove(file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
download() {
|
||||||
|
// 本地文件
|
||||||
|
if (this.parameter.files && this.parameter.files.length > 0 && this.parameter.files[0].file) {
|
||||||
|
downloadFile(this.parameter.files[0].file.name, this.parameter.files[0].file);
|
||||||
|
}
|
||||||
|
// 远程下载文件
|
||||||
|
if (this.parameter.files && this.parameter.files.length > 0 && !this.parameter.files[0].file) {
|
||||||
|
let file = this.parameter.files[0];
|
||||||
|
let conf = {
|
||||||
|
url: "/api/automation/file/download",
|
||||||
|
method: 'post',
|
||||||
|
data: file,
|
||||||
|
responseType: 'blob',
|
||||||
|
};
|
||||||
|
if (file.storage === "FILE_REF") {
|
||||||
|
conf = {
|
||||||
|
url: "/file/metadata/download/" + file.fileId,
|
||||||
|
method: 'get',
|
||||||
|
responseType: 'blob',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.result = this.$request(conf).then(response => {
|
||||||
|
const content = response.data;
|
||||||
|
if (content && this.parameter.files[0]) {
|
||||||
|
downloadFile(this.parameter.files[0].name, content);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleRemove(file) {
|
||||||
|
let fileName = file.file.name ? file.file.name : file.name
|
||||||
|
this.$alert(this.$t('api_test.environment.csv_delete') + ':【 ' + fileName + " 】?", '', {
|
||||||
|
confirmButtonText: this.$t('commons.confirm'),
|
||||||
|
callback: (action) => {
|
||||||
|
if (action === 'confirm') {
|
||||||
|
this.$refs.upload.handleRemove(file);
|
||||||
|
for (let i = 0; i < this.parameter.files.length; i++) {
|
||||||
|
let paramFileName = this.parameter.files[i].name ?
|
||||||
|
this.parameter.files[i].name : this.parameter.files[i].file.name;
|
||||||
|
if (fileName === paramFileName) {
|
||||||
|
this.parameter.files.splice(i, 1);
|
||||||
|
this.$refs.upload.handleRemove(file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
exceed() {
|
||||||
|
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
|
||||||
|
},
|
||||||
|
upload(file) {
|
||||||
|
this.parameter.files = [];
|
||||||
|
this.parameter.files.push(file);
|
||||||
|
},
|
||||||
|
uploadValidate(file) {
|
||||||
|
if (this.parameter.files.length > 0) {
|
||||||
|
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (file.size / 1024 / 1024 > 500) {
|
||||||
|
this.$warning(this.$t('api_test.request.body_upload_limit_size'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!file.name.endsWith(".csv")) {
|
||||||
|
this.$warning(this.$t('variables.cvs_info'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (!this.parameter.files) {
|
||||||
|
this.parameter.files = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.el-upload {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-body-upload >>> .el-upload {
|
||||||
|
height: 30px;
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-default {
|
||||||
|
min-height: 30px;
|
||||||
|
width: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon-plus {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-body-upload >>> .el-upload-list__item {
|
||||||
|
height: 30px;
|
||||||
|
width: auto;
|
||||||
|
padding: 2px 5px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-body-upload >>> .el-upload-list--picture-card {
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-body-upload {
|
||||||
|
min-height: 30px;
|
||||||
|
border: 1px solid #EBEEF5;
|
||||||
|
padding: 2px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-body-upload {
|
||||||
|
min-height: 0px;
|
||||||
|
height: 30px;
|
||||||
|
border: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
border-radius: 0px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-item {
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {CommonConfig} from "../../model/EnvironmentModel";
|
import {CommonConfig} from "../../model/EnvironmentModel";
|
||||||
import MsApiScenarioVariables from "../ApiScenarioVariables";
|
import MsApiScenarioVariables from "@/business/components/api/test/components/environment/ApiScenarioVariables";
|
||||||
import MsApiHostTable from "../ApiHostTable";
|
import MsApiHostTable from "../ApiHostTable";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -2,19 +2,27 @@
|
||||||
<el-main v-loading="result.loading" class="environment-edit" style="margin-left: 0px">
|
<el-main v-loading="result.loading" class="environment-edit" style="margin-left: 0px">
|
||||||
<el-form :model="environment" :rules="rules" ref="environment" label-width="80px">
|
<el-form :model="environment" :rules="rules" ref="environment" label-width="80px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="10" v-if="!isProject">
|
||||||
<el-form-item prop="name" :label="$t('api_test.environment.name')">
|
<el-form-item class="project-item" prop="currentProjectId" :label="$t('project.select')">
|
||||||
<el-input v-model="environment.name" :disabled="isReadOnly" :placeholder="this.$t('commons.input_name')"
|
<el-select @change="handleProjectChange" v-model="environment.currentProjectId" filterable clearable
|
||||||
clearable/>
|
size="small">
|
||||||
|
<el-option v-for="item in projectList" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4" v-if="!hideButton">
|
<el-col :span="10">
|
||||||
|
<el-form-item prop="name" :label="$t('api_test.environment.name')">
|
||||||
|
<el-input v-model="environment.name" :disabled="isReadOnly" :placeholder="this.$t('commons.input_name')"
|
||||||
|
clearable size="small"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="4" v-if="!hideButton" :offset="isProject ? 10 : 0">
|
||||||
<div style="float: right;width: fit-content;">
|
<div style="float: right;width: fit-content;">
|
||||||
<div style="float: left; margin-right: 8px;">
|
<div style="float: left; margin-right: 8px;">
|
||||||
<slot name="other"></slot>
|
<slot name="other"></slot>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms_btn">
|
<div class="ms_btn">
|
||||||
<el-button type="primary" @click="confirm" @keydown.enter.native.prevent>
|
<el-button type="primary" @click="confirm" @keydown.enter.native.prevent size="small">
|
||||||
{{ $t('commons.confirm') }}
|
{{ $t('commons.confirm') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,7 +38,7 @@
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-tab-pane :label="$t('api_test.environment.http_config')" name="http">
|
<el-tab-pane :label="$t('api_test.environment.http_config')" name="http">
|
||||||
<ms-environment-http-config :project-id="projectId" :http-config="environment.config.httpConfig"
|
<ms-environment-http-config :project-id="environment.projectId" :http-config="environment.config.httpConfig"
|
||||||
ref="httpConfig" :is-read-only="isReadOnly"/>
|
ref="httpConfig" :is-read-only="isReadOnly"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('api_test.environment.database_config')" name="sql">
|
<el-tab-pane :label="$t('api_test.environment.database_config')" name="sql">
|
||||||
|
@ -40,7 +48,7 @@
|
||||||
<ms-tcp-config :config="environment.config.tcpConfig" :is-read-only="isReadOnly"/>
|
<ms-tcp-config :config="environment.config.tcpConfig" :is-read-only="isReadOnly"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('commons.ssl.config')" name="ssl">
|
<el-tab-pane :label="$t('commons.ssl.config')" name="ssl">
|
||||||
<ms-environment-s-s-l-config :project-id="projectId" :ssl-config="environment.config.sslConfig"
|
<ms-environment-s-s-l-config :project-id="environment.projectId" :ssl-config="environment.config.sslConfig"
|
||||||
:is-read-only="isReadOnly"/>
|
:is-read-only="isReadOnly"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('api_test.definition.request.all_pre_script')" name="prescript">
|
<el-tab-pane :label="$t('api_test.definition.request.all_pre_script')" name="prescript">
|
||||||
|
@ -95,9 +103,10 @@
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item style="margin-bottom: 0px;"
|
<el-form-item style="margin-bottom: 0px;"
|
||||||
:label="$t('error_report_library.use_error_report')"
|
:label="$t('error_report_library.use_error_report')"
|
||||||
prop="status">
|
prop="status">
|
||||||
<el-switch v-model="environment.config.useErrorCode" style="margin-right: 10px" :disabled="isReadOnly"/>
|
<el-switch v-model="environment.config.useErrorCode" style="margin-right: 10px"
|
||||||
|
:disabled="isReadOnly"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
@ -128,11 +137,7 @@
|
||||||
:is-show-json-path-suggest="false"/>
|
:is-show-json-path-suggest="false"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<!-- <div class="environment-footer">-->
|
|
||||||
<!-- <ms-dialog-footer-->
|
|
||||||
<!-- @cancel="cancel"-->
|
|
||||||
<!-- @confirm="save()"/>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
</el-form>
|
</el-form>
|
||||||
<ms-change-history ref="changeHistory"/>
|
<ms-change-history ref="changeHistory"/>
|
||||||
</el-main>
|
</el-main>
|
||||||
|
@ -158,6 +163,7 @@ import EnvironmentGlobalScript from "@/business/components/api/test/components/e
|
||||||
import GlobalAssertions from "@/business/components/api/definition/components/assertion/GlobalAssertions";
|
import GlobalAssertions from "@/business/components/api/definition/components/assertion/GlobalAssertions";
|
||||||
import MsChangeHistory from "../../../../history/ChangeHistory";
|
import MsChangeHistory from "../../../../history/ChangeHistory";
|
||||||
import MsDialogHeader from "../../../../common/components/MsDialogHeader";
|
import MsDialogHeader from "../../../../common/components/MsDialogHeader";
|
||||||
|
import {getUploadConfig, request} from "@/common/js/ajax";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "EnvironmentEdit",
|
name: "EnvironmentEdit",
|
||||||
|
@ -185,6 +191,13 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
projectList: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isProject: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -196,6 +209,9 @@ export default {
|
||||||
{required: true, message: this.$t('commons.input_name'), trigger: 'blur'},
|
{required: true, message: this.$t('commons.input_name'), trigger: 'blur'},
|
||||||
{max: 64, message: this.$t('commons.input_limit', [1, 64]), trigger: 'blur'}
|
{max: 64, message: this.$t('commons.input_limit', [1, 64]), trigger: 'blur'}
|
||||||
],
|
],
|
||||||
|
currentProjectId: [
|
||||||
|
{required: true, message: "", trigger: 'blur'},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
headerSuggestions: REQUEST_HEADERS,
|
headerSuggestions: REQUEST_HEADERS,
|
||||||
activeName: 'common'
|
activeName: 'common'
|
||||||
|
@ -295,6 +311,15 @@ export default {
|
||||||
this.isRefresh = true;
|
this.isRefresh = true;
|
||||||
});
|
});
|
||||||
this.envEnable = o.enable;
|
this.envEnable = o.enable;
|
||||||
|
},
|
||||||
|
//当创建及复制环境所选择的项目变化时,改变当前环境对应的projectId
|
||||||
|
'environment.currentProjectId'() {
|
||||||
|
// el-select什么都不选时值为'',为''的话也会被当成有效的projectId传给后端,转化使其无效
|
||||||
|
if (!this.environment.currentProjectId) {
|
||||||
|
this.environment.projectId = null;
|
||||||
|
} else {
|
||||||
|
this.environment.projectId = this.environment.currentProjectId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -361,6 +386,29 @@ export default {
|
||||||
}
|
}
|
||||||
return uploadFiles;
|
return uploadFiles;
|
||||||
},
|
},
|
||||||
|
getVariablesFiles(obj) {
|
||||||
|
let variablesFiles = [];
|
||||||
|
obj.variablesFilesIds = [];
|
||||||
|
// 场景变量csv 文件
|
||||||
|
if (obj.config.commonConfig.variables) {
|
||||||
|
obj.config.commonConfig.variables.forEach(param => {
|
||||||
|
if (param.type === 'CSV' && param.files) {
|
||||||
|
param.files.forEach(item => {
|
||||||
|
if (item.file && item.file.name) {
|
||||||
|
if (!item.id) {
|
||||||
|
let fileId = getUUID().substring(0, 12);
|
||||||
|
item.name = item.file.name;
|
||||||
|
item.id = fileId;
|
||||||
|
}
|
||||||
|
obj.variablesFilesIds.push(item.id);
|
||||||
|
variablesFiles.push(item.file);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return variablesFiles;
|
||||||
|
},
|
||||||
check(items) {
|
check(items) {
|
||||||
let repeatKey = "";
|
let repeatKey = "";
|
||||||
items.forEach((item, index) => {
|
items.forEach((item, index) => {
|
||||||
|
@ -373,7 +421,7 @@ export default {
|
||||||
return repeatKey;
|
return repeatKey;
|
||||||
},
|
},
|
||||||
_save(environment) {
|
_save(environment) {
|
||||||
if (!this.projectId) {
|
if (!environment.projectId) {
|
||||||
this.$warning(this.$t('api_test.select_project'));
|
this.$warning(this.$t('api_test.select_project'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -401,25 +449,47 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
environment.config.commonConfig.variables.forEach(variable => {
|
||||||
|
if (variable.type === 'CSV' && variable.files.length === 0) {
|
||||||
|
message = this.$t('api_test.automation.csv_warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
})
|
||||||
if (message) {
|
if (message) {
|
||||||
this.$warning(message);
|
this.$warning(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bodyFiles = this.geFiles(environment);
|
let bodyFiles = this.geFiles(environment);
|
||||||
|
let variablesFiles = this.getVariablesFiles(environment);
|
||||||
|
let formData = new FormData();
|
||||||
|
if (bodyFiles) {
|
||||||
|
bodyFiles.forEach(f => {
|
||||||
|
formData.append("files", f);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (variablesFiles) {
|
||||||
|
variablesFiles.forEach(f => {
|
||||||
|
formData.append("variablesFiles", f);
|
||||||
|
})
|
||||||
|
}
|
||||||
let param = this.buildParam(environment);
|
let param = this.buildParam(environment);
|
||||||
let url = '/api/environment/add';
|
let url = '/api/environment/add';
|
||||||
if (param.id) {
|
if (param.id) {
|
||||||
url = '/api/environment/update';
|
url = '/api/environment/update';
|
||||||
}
|
}
|
||||||
this.$fileUpload(url, null, bodyFiles, param, response => {
|
formData.append('request', new Blob([JSON.stringify(param)], {type: "application/json"}));
|
||||||
//this.result = this.$post(url, param, response => {
|
let axiosRequestConfig = getUploadConfig(url, formData);
|
||||||
if (!param.id) {
|
request(axiosRequestConfig, (response) => {
|
||||||
environment.id = response.data;
|
if (response.success) {
|
||||||
|
this.$success(this.$t('commons.save_success'));
|
||||||
|
this.$emit('refreshAfterSave'); //在EnvironmentList.vue中监听,使在数据修改后进行刷新
|
||||||
|
this.cancel()
|
||||||
}
|
}
|
||||||
this.$success(this.$t('commons.save_success'));
|
}, error => {
|
||||||
this.$emit('refreshAfterSave'); //在EnvironmentList.vue中监听,使在数据修改后进行刷新
|
this.$emit('errorRefresh', error);
|
||||||
this.cancel();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
buildParam: function (environment) {
|
buildParam: function (environment) {
|
||||||
let param = {};
|
let param = {};
|
||||||
|
@ -447,6 +517,9 @@ export default {
|
||||||
clearValidate() {
|
clearValidate() {
|
||||||
this.$refs["environment"].clearValidate();
|
this.$refs["environment"].clearValidate();
|
||||||
},
|
},
|
||||||
|
handleProjectChange() { //项目选择下拉框选择其他项目后清空“启用条件”,因为项目变了模块也就变了。
|
||||||
|
this.environment.config.httpConfig.conditions = [];
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -468,10 +541,11 @@ span:not(:first-child) {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.errorReportConfigSwitch /deep/ .el-switch__label{
|
.errorReportConfigSwitch /deep/ .el-switch__label {
|
||||||
color: #D8DAE2;
|
color: #D8DAE2;
|
||||||
}
|
}
|
||||||
.errorReportConfigSwitch /deep/ .is-active{
|
|
||||||
|
.errorReportConfigSwitch /deep/ .is-active {
|
||||||
color: var(--count_number);
|
color: var(--count_number);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
<el-row type="flex" justify="space-between">
|
<el-row type="flex" justify="space-between">
|
||||||
<el-col :span="14">
|
<el-col :span="14">
|
||||||
<span class="ms-env-span" style="line-height: 30px;">{{ $t('api_test.environment.socket') }}</span>
|
<span class="ms-env-span" style="line-height: 30px;">{{ $t('api_test.environment.socket') }}</span>
|
||||||
<el-input v-model="condition.socket" style="width: 85%" :placeholder="$t('api_test.request.url_description')" clearable size="small">
|
<el-input v-model="condition.socket" style="width: 85%"
|
||||||
|
:placeholder="$t('api_test.request.url_description')" clearable size="small">
|
||||||
<template slot="prepend">
|
<template slot="prepend">
|
||||||
<el-select v-model="condition.protocol" class="request-protocol-select" size="small">
|
<el-select v-model="condition.protocol" class="request-protocol-select" size="small">
|
||||||
<el-option label="http://" value="http"/>
|
<el-option label="http://" value="http"/>
|
||||||
|
@ -17,7 +18,8 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="10">
|
<el-col :span="10">
|
||||||
<span style="margin-right: 12px; line-height: 30px;">{{ $t('commons.description') }}</span>
|
<span style="margin-right: 12px; line-height: 30px;">{{ $t('commons.description') }}</span>
|
||||||
<el-input v-model="condition.description" maxlength="200" :show-word-limit="true" size="small" style="width: 70%;"/>
|
<el-input v-model="condition.description" maxlength="200" :show-word-limit="true" size="small"
|
||||||
|
style="width: 70%;"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -29,7 +31,8 @@
|
||||||
<el-radio label="PATH">{{ $t('api_test.definition.api_path') }}</el-radio>
|
<el-radio label="PATH">{{ $t('api_test.definition.api_path') }}</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
<div v-if="condition.type === 'MODULE'" style="margin-top: 6px">
|
<div v-if="condition.type === 'MODULE'" style="margin-top: 6px">
|
||||||
<ms-select-tree size="small" :data="moduleOptions" :default-key="condition.ids" @getValue="setModule" :obj="moduleObj" clearable :checkStrictly="true" multiple v-if="!loading"/>
|
<ms-select-tree size="small" :data="moduleOptions" :default-key="condition.ids" @getValue="setModule"
|
||||||
|
:obj="moduleObj" clearable :checkStrictly="true" multiple v-if="!loading"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="condition.type === 'PATH'" style="margin-top: 6px">
|
<div v-if="condition.type === 'PATH'" style="margin-top: 6px">
|
||||||
<el-input v-model="pathDetails.name" :placeholder="$t('api_test.value')" clearable size="small">
|
<el-input v-model="pathDetails.name" :placeholder="$t('api_test.value')" clearable size="small">
|
||||||
|
@ -70,7 +73,8 @@
|
||||||
{{ getUrl(row) }}
|
{{ getUrl(row) }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="type" :label="$t('api_test.environment.condition_enable')" show-overflow-tooltip min-width="100px">
|
<el-table-column prop="type" :label="$t('api_test.environment.condition_enable')" show-overflow-tooltip
|
||||||
|
min-width="100px">
|
||||||
<template v-slot:default="{row}">
|
<template v-slot:default="{row}">
|
||||||
{{ getName(row) }}
|
{{ getName(row) }}
|
||||||
</template>
|
</template>
|
||||||
|
@ -153,7 +157,15 @@ export default {
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
pathDetails: new KeyValue({name: "", value: "contains"}),
|
pathDetails: new KeyValue({name: "", value: "contains"}),
|
||||||
condition: {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]},
|
condition: {
|
||||||
|
type: "NONE",
|
||||||
|
details: [new KeyValue({name: "", value: "contains"})],
|
||||||
|
protocol: "http",
|
||||||
|
socket: "",
|
||||||
|
domain: "",
|
||||||
|
port: 0,
|
||||||
|
headers: [new KeyValue()]
|
||||||
|
},
|
||||||
beforeCondition: {}
|
beforeCondition: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -174,7 +186,16 @@ export default {
|
||||||
this.condition.description = this.httpConfig.description;
|
this.condition.description = this.httpConfig.description;
|
||||||
this.add();
|
this.add();
|
||||||
}
|
}
|
||||||
this.condition = {id: undefined, type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]};
|
this.condition = {
|
||||||
|
id: undefined,
|
||||||
|
type: "NONE",
|
||||||
|
details: [new KeyValue({name: "", value: "contains"})],
|
||||||
|
protocol: "http",
|
||||||
|
socket: "",
|
||||||
|
domain: "",
|
||||||
|
port: 0,
|
||||||
|
headers: [new KeyValue()]
|
||||||
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -216,7 +237,15 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectRow(row) {
|
selectRow(row) {
|
||||||
this.condition = {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]};
|
this.condition = {
|
||||||
|
type: "NONE",
|
||||||
|
details: [new KeyValue({name: "", value: "contains"})],
|
||||||
|
protocol: "http",
|
||||||
|
socket: "",
|
||||||
|
domain: "",
|
||||||
|
port: 0,
|
||||||
|
headers: [new KeyValue()]
|
||||||
|
};
|
||||||
if (row) {
|
if (row) {
|
||||||
this.httpConfig.socket = row.socket;
|
this.httpConfig.socket = row.socket;
|
||||||
this.httpConfig.protocol = row.protocol;
|
this.httpConfig.protocol = row.protocol;
|
||||||
|
@ -309,7 +338,14 @@ export default {
|
||||||
this.$refs.envTable.setCurrentRow(0);
|
this.$refs.envTable.setCurrentRow(0);
|
||||||
},
|
},
|
||||||
clear() {
|
clear() {
|
||||||
this.condition = {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", headers: [new KeyValue()]};
|
this.condition = {
|
||||||
|
type: "NONE",
|
||||||
|
details: [new KeyValue({name: "", value: "contains"})],
|
||||||
|
protocol: "http",
|
||||||
|
socket: "",
|
||||||
|
domain: "",
|
||||||
|
headers: [new KeyValue()]
|
||||||
|
};
|
||||||
this.$refs.envTable.setCurrentRow(0);
|
this.$refs.envTable.setCurrentRow(0);
|
||||||
},
|
},
|
||||||
reload() {
|
reload() {
|
||||||
|
@ -336,8 +372,15 @@ export default {
|
||||||
}
|
}
|
||||||
this.validateSocket();
|
this.validateSocket();
|
||||||
let obj = {
|
let obj = {
|
||||||
id: getUUID(), type: this.condition.type, socket: this.condition.socket, protocol: this.condition.protocol, headers: this.condition.headers,
|
id: getUUID(),
|
||||||
domain: this.condition.domain, port: this.condition.port, time: new Date().getTime(), description: this.condition.description
|
type: this.condition.type,
|
||||||
|
socket: this.condition.socket,
|
||||||
|
protocol: this.condition.protocol,
|
||||||
|
headers: this.condition.headers,
|
||||||
|
domain: this.condition.domain,
|
||||||
|
port: this.condition.port,
|
||||||
|
time: new Date().getTime(),
|
||||||
|
description: this.condition.description
|
||||||
};
|
};
|
||||||
if (this.condition.type === "PATH") {
|
if (this.condition.type === "PATH") {
|
||||||
obj.details = [JSON.parse(JSON.stringify(this.pathDetails))];
|
obj.details = [JSON.parse(JSON.stringify(this.pathDetails))];
|
||||||
|
@ -358,7 +401,16 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const index = this.httpConfig.conditions.findIndex((d) => d.id === row.id);
|
const index = this.httpConfig.conditions.findIndex((d) => d.id === row.id);
|
||||||
let obj = {id: getUUID(), type: row.type, socket: row.socket, details: row.details, protocol: row.protocol, headers: JSON.parse(JSON.stringify(row.headers)), domain: row.domain, time: new Date().getTime()};
|
let obj = {
|
||||||
|
id: getUUID(),
|
||||||
|
type: row.type,
|
||||||
|
socket: row.socket,
|
||||||
|
details: row.details,
|
||||||
|
protocol: row.protocol,
|
||||||
|
headers: JSON.parse(JSON.stringify(row.headers)),
|
||||||
|
domain: row.domain,
|
||||||
|
time: new Date().getTime()
|
||||||
|
};
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
this.httpConfig.conditions.splice(index, 0, obj);
|
this.httpConfig.conditions.splice(index, 0, obj);
|
||||||
} else {
|
} else {
|
||||||
|
@ -402,7 +454,7 @@ export default {
|
||||||
let line = item.split(/:|:/);
|
let line = item.split(/:|:/);
|
||||||
let values = item.split(line[0] + ":");
|
let values = item.split(line[0] + ":");
|
||||||
let required = false;
|
let required = false;
|
||||||
keyValues.unshift(new KeyValue({
|
keyValues.push(new KeyValue({
|
||||||
name: line[0],
|
name: line[0],
|
||||||
required: required,
|
required: required,
|
||||||
value: values[1],
|
value: values[1],
|
||||||
|
@ -429,7 +481,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isAdd) {
|
if (isAdd) {
|
||||||
this.condition.headers.unshift(keyValue);
|
this.condition.headers.splice(this.condition.headers.indexOf(h => !h.name), 0, keyValue);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog :visible="dialogVisible" :title="dialogTitle"
|
||||||
|
@close="close" :close-on-click-modal="false" append-to-body
|
||||||
|
width="35%">
|
||||||
|
<el-form>
|
||||||
|
<el-form :rules="rules" label-width="80px" v-model="modeId">
|
||||||
|
<el-form-item prop="modeId" :label="$t('commons.import_mode')">
|
||||||
|
<el-select size="small" v-model="modeId">
|
||||||
|
<el-option v-for="item in modeOptions" :key="item.id" :label="item.name" :value="item.id"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-upload
|
||||||
|
class="api-upload" drag action="alert"
|
||||||
|
:on-change="handleFileChange"
|
||||||
|
:limit="1" :file-list="uploadFiles"
|
||||||
|
:on-remove="handleRemove"
|
||||||
|
:on-exceed="handleExceed"
|
||||||
|
:auto-upload="false" accept=".json">
|
||||||
|
<i class="el-icon-upload"></i>
|
||||||
|
<div class="el-upload__text" v-html="$t('load_test.upload_tips')"></div>
|
||||||
|
<div class="el-upload__tip" slot="tip">
|
||||||
|
{{ $t('api_test.api_import.file_size_limit') }}
|
||||||
|
{{ ',' + $t('api_test.api_import.ms_env_import_file_limit') }}
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-form>
|
||||||
|
<template v-slot:footer>
|
||||||
|
<el-button type="primary" @click="save">
|
||||||
|
{{ $t('commons.confirm') }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "VariableImport",
|
||||||
|
props: {
|
||||||
|
projectList: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toImportProjectId: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentProjectId: '', //所选中环境的id
|
||||||
|
uploadFiles: [],
|
||||||
|
dialogTitle: this.$t('commons.import_variable'),
|
||||||
|
dialogVisible: false,
|
||||||
|
modeOptions: [
|
||||||
|
{
|
||||||
|
id: 'fullCoverage',
|
||||||
|
name: this.$t('commons.cover')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'incrementalMerge',
|
||||||
|
name: this.$t('commons.not_cover')
|
||||||
|
}
|
||||||
|
],
|
||||||
|
modeId: 'fullCoverage',
|
||||||
|
rules: {
|
||||||
|
modeId: [
|
||||||
|
{required: true, message: "", trigger: 'blur'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
//导入框激活时重置选中的项目和文件
|
||||||
|
dialogVisible(val, oldVal) {
|
||||||
|
if (oldVal === false) {
|
||||||
|
this.currentProjectId = '';
|
||||||
|
this.uploadFiles = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
handleFileChange(file, uploadFiles) {
|
||||||
|
this.uploadFiles = uploadFiles;
|
||||||
|
},
|
||||||
|
save() {
|
||||||
|
if (this.uploadFiles.length > 0) {
|
||||||
|
for (let i = 0; i < this.uploadFiles.length; i++) {
|
||||||
|
this.uploadValidate(this.uploadFiles[i]);
|
||||||
|
let file = this.uploadFiles[i];
|
||||||
|
if (!file) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.readAsText(file.raw)
|
||||||
|
reader.onload = (e) => {
|
||||||
|
let fileString = e.target.result;
|
||||||
|
let messages = '';
|
||||||
|
try {
|
||||||
|
JSON.parse(fileString).map(env => {
|
||||||
|
if (!env.name) {
|
||||||
|
messages = this.$t('api_test.automation.variable_warning')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (messages !== '') {
|
||||||
|
this.$warning(messages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$emit("mergeData", fileString, this.modeId);
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.$success(this.$t('commons.save_success'));
|
||||||
|
} catch (exception) {
|
||||||
|
this.$warning(this.$t('api_test.api_import.ms_env_import_file_limit'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$warning(this.$t('test_track.case.import.import_file_tips'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleExceed() {
|
||||||
|
this.$warning(this.$t('api_test.api_import.file_exceed_limit'));
|
||||||
|
},
|
||||||
|
handleRemove() {
|
||||||
|
|
||||||
|
},
|
||||||
|
uploadValidate(file) { //判断文件扩展名是不是.json,以及文件大小是否超过20M
|
||||||
|
const extension = file.name.substring(file.name.lastIndexOf('.') + 1);
|
||||||
|
if (!(extension === 'json')) {
|
||||||
|
this.$warning(this.$t('api_test.api_import.ms_env_import_file_limit'));
|
||||||
|
}
|
||||||
|
if (file.size / 1024 / 1024 > 20) {
|
||||||
|
this.$warning(this.$t('api_test.api_import.file_size_limit'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
open() {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.dialogVisible = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.project-item {
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -2,7 +2,12 @@
|
||||||
|
|
||||||
<div class="msDialogHeader">
|
<div class="msDialogHeader">
|
||||||
<span style="float: left;font-size: 18px;color: #303133;">{{ title }}</span>
|
<span style="float: left;font-size: 18px;color: #303133;">{{ title }}</span>
|
||||||
|
<div style="float: right; margin-right: 30px">
|
||||||
|
<el-tooltip effect="dark" :content="$t('commons.full_screen_editing')"
|
||||||
|
placement="top-start">
|
||||||
|
<font-awesome-icon class="alt-ico" :icon="['fa', 'expand-alt']" size="lg" @click="fullScreen"/>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
<div v-if="!hideButton" style="float: right;width: fit-content;">
|
<div v-if="!hideButton" style="float: right;width: fit-content;">
|
||||||
<div style="float: left; margin-right: 8px;">
|
<div style="float: left; margin-right: 8px;">
|
||||||
<slot name="other"></slot>
|
<slot name="other"></slot>
|
||||||
|
@ -39,6 +44,9 @@ export default {
|
||||||
},
|
},
|
||||||
confirm() {
|
confirm() {
|
||||||
this.$emit("confirm");
|
this.$emit("confirm");
|
||||||
|
},
|
||||||
|
fullScreen() {
|
||||||
|
this.$emit("fullScreen");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,4 +61,9 @@ export default {
|
||||||
.msDialogHeader {
|
.msDialogHeader {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alt-ico {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #8c939d;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -32,7 +32,9 @@
|
||||||
<el-table-column :label="$t('api_test.environment.socket')" show-overflow-tooltip>
|
<el-table-column :label="$t('api_test.environment.socket')" show-overflow-tooltip>
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<span v-if="parseDomainName(scope.row)!='SHOW_INFO'">{{ parseDomainName(scope.row) }}</span>
|
<span v-if="parseDomainName(scope.row)!='SHOW_INFO'">{{ parseDomainName(scope.row) }}</span>
|
||||||
<el-button size="mini" icon="el-icon-s-data" @click="showInfo(scope.row)" v-else>{{ $t('workspace.env_group.view_details') }}</el-button>
|
<el-button size="mini" icon="el-icon-s-data" @click="showInfo(scope.row)" v-else>
|
||||||
|
{{ $t('workspace.env_group.view_details') }}
|
||||||
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('commons.operating')">
|
<el-table-column :label="$t('commons.operating')">
|
||||||
|
@ -57,18 +59,20 @@
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 创建、编辑、复制环境时的对话框 -->
|
<!-- 创建、编辑、复制环境时的对话框 -->
|
||||||
<el-dialog :visible.sync="dialogVisible" :close-on-click-modal="false" width="66%" top="50px">
|
<el-dialog :visible.sync="dialogVisible" :close-on-click-modal="false" width="66%" top="50px"
|
||||||
|
:fullscreen="isFullScreen">
|
||||||
<template #title>
|
<template #title>
|
||||||
<ms-dialog-header :title="dialogTitle" :hide-button="true"
|
<ms-dialog-header :title="dialogTitle" :hide-button="true"
|
||||||
@cancel="dialogVisible = false"
|
@cancel="dialogVisible = false"
|
||||||
@confirm="save"/>
|
@confirm="save" @fullScreen="fullScreen"/>
|
||||||
</template>
|
</template>
|
||||||
<environment-edit :if-create="ifCreate" :environment="currentEnvironment" ref="environmentEdit" @close="close"
|
<environment-edit :if-create="ifCreate" :environment="currentEnvironment" ref="environmentEdit" @close="close"
|
||||||
@confirm="save"
|
@confirm="save" :is-project="true"
|
||||||
:project-id="currentProjectId" @refreshAfterSave="refresh">
|
:project-list="projectList" @refreshAfterSave="refresh">
|
||||||
</environment-edit>
|
</environment-edit>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<environment-import :project-list="projectList" :to-import-project-id="currentProjectId" @refresh="refresh" ref="envImport"></environment-import>
|
<environment-import :project-list="projectList" :to-import-project-id="currentProjectId" @refresh="refresh"
|
||||||
|
ref="envImport"></environment-import>
|
||||||
|
|
||||||
<el-dialog title="域名列表" :visible.sync="domainVisible">
|
<el-dialog title="域名列表" :visible.sync="domainVisible">
|
||||||
<el-table :data="conditions">
|
<el-table :data="conditions">
|
||||||
|
@ -94,12 +98,14 @@
|
||||||
{{ row.conditionType ? "-" : getDetails(row) }}
|
{{ row.conditionType ? "-" : getDetails(row) }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="description" show-overflow-tooltip min-width="120px" :label="$t('commons.description')">
|
<el-table-column prop="description" show-overflow-tooltip min-width="120px"
|
||||||
|
:label="$t('commons.description')">
|
||||||
<template v-slot:default="{row}">
|
<template v-slot:default="{row}">
|
||||||
<span>{{ row.description ? row.description : "-" }}</span>
|
<span>{{ row.description ? row.description : "-" }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="createTime" show-overflow-tooltip min-width="120px" :label="$t('commons.create_time')">
|
<el-table-column prop="createTime" show-overflow-tooltip min-width="120px"
|
||||||
|
:label="$t('commons.create_time')">
|
||||||
<template v-slot:default="{row}">
|
<template v-slot:default="{row}">
|
||||||
<span v-if="!row.conditionType">{{ row.time | timestampFormatDate }}</span>
|
<span v-if="!row.conditionType">{{ row.time | timestampFormatDate }}</span>
|
||||||
<span v-else>-</span>
|
<span v-else>-</span>
|
||||||
|
@ -170,6 +176,7 @@ export default {
|
||||||
projectFilters: [],
|
projectFilters: [],
|
||||||
screenHeight: 'calc(100vh - 155px)',
|
screenHeight: 'calc(100vh - 155px)',
|
||||||
ifCreate: false, //是否是创建环境
|
ifCreate: false, //是否是创建环境
|
||||||
|
isFullScreen: false //是否全屏
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
@ -180,6 +187,9 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
fullScreen() {
|
||||||
|
this.isFullScreen = !this.isFullScreen;
|
||||||
|
},
|
||||||
showInfo(row) {
|
showInfo(row) {
|
||||||
const config = JSON.parse(row.config);
|
const config = JSON.parse(row.config);
|
||||||
this.conditions = config.httpConfig.conditions;
|
this.conditions = config.httpConfig.conditions;
|
||||||
|
@ -193,7 +203,7 @@ export default {
|
||||||
}
|
}
|
||||||
this.domainVisible = true;
|
this.domainVisible = true;
|
||||||
},
|
},
|
||||||
save(){
|
save() {
|
||||||
this.$refs.environmentEdit.save();
|
this.$refs.environmentEdit.save();
|
||||||
},
|
},
|
||||||
getName(row) {
|
getName(row) {
|
||||||
|
@ -387,8 +397,7 @@ export default {
|
||||||
} else { //旧版本没有对应的config数据,其域名保存在protocol和domain中
|
} else { //旧版本没有对应的config数据,其域名保存在protocol和domain中
|
||||||
return environment.protocol + '://' + environment.domain;
|
return environment.protocol + '://' + environment.domain;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,9 @@
|
||||||
<el-table-column :label="$t('api_test.environment.socket')" show-overflow-tooltip>
|
<el-table-column :label="$t('api_test.environment.socket')" show-overflow-tooltip>
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<span v-if="parseDomainName(scope.row)!='SHOW_INFO'">{{ parseDomainName(scope.row) }}</span>
|
<span v-if="parseDomainName(scope.row)!='SHOW_INFO'">{{ parseDomainName(scope.row) }}</span>
|
||||||
<el-button size="mini" icon="el-icon-s-data" @click="showInfo(scope.row)" v-else>{{ $t('workspace.env_group.view_details') }}</el-button>
|
<el-button size="mini" icon="el-icon-s-data" @click="showInfo(scope.row)" v-else>
|
||||||
|
{{ $t('workspace.env_group.view_details') }}
|
||||||
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('commons.operating')">
|
<el-table-column :label="$t('commons.operating')">
|
||||||
|
@ -62,26 +64,16 @@
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 创建、编辑、复制环境时的对话框 -->
|
<!-- 创建、编辑、复制环境时的对话框 -->
|
||||||
<el-dialog :visible.sync="dialogVisible" :close-on-click-modal="false" top="50px" width="66%">
|
<el-dialog :visible.sync="dialogVisible" :close-on-click-modal="false" top="50px" width="66%"
|
||||||
|
:fullscreen="isFullScreen">
|
||||||
<template #title>
|
<template #title>
|
||||||
<ms-dialog-header :title="dialogTitle"
|
<ms-dialog-header :title="dialogTitle"
|
||||||
@cancel="dialogVisible = false"
|
@cancel="dialogVisible = false" :hide-button="true"
|
||||||
@confirm="save"/>
|
@confirm="save" @fullScreen="fullScreen"/>
|
||||||
</template>
|
</template>
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form label-width="80px" :rules="rules" style="display: flow-root">
|
|
||||||
<el-form-item class="project-item" prop="currentProjectId" :label="$t('project.select')">
|
|
||||||
<el-select @change="handleProjectChange" v-model="currentProjectId" filterable clearable>
|
|
||||||
<el-option v-for="item in projectList" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<environment-edit :if-create="ifCreate" :environment="currentEnvironment" ref="environmentEdit" @close="close"
|
<environment-edit :if-create="ifCreate" :environment="currentEnvironment" ref="environmentEdit" @close="close"
|
||||||
:hide-button="true"
|
:project-list="projectList" @confirm="save" :is-project="false"
|
||||||
:project-id="currentProjectId" @refreshAfterSave="refresh">
|
@refreshAfterSave="refresh">
|
||||||
</environment-edit>
|
</environment-edit>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<environment-import :project-list="projectList" @refresh="refresh" ref="envImport"></environment-import>
|
<environment-import :project-list="projectList" @refresh="refresh" ref="envImport"></environment-import>
|
||||||
|
@ -203,6 +195,7 @@ export default {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
ifCreate: false, //是否是创建环境
|
ifCreate: false, //是否是创建环境
|
||||||
|
isFullScreen: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
@ -227,6 +220,9 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
fullScreen() {
|
||||||
|
this.isFullScreen = !this.isFullScreen;
|
||||||
|
},
|
||||||
showInfo(row) {
|
showInfo(row) {
|
||||||
const config = JSON.parse(row.config);
|
const config = JSON.parse(row.config);
|
||||||
this.conditions = config.httpConfig.conditions;
|
this.conditions = config.httpConfig.conditions;
|
||||||
|
@ -316,6 +312,7 @@ export default {
|
||||||
editEnv(environment) {
|
editEnv(environment) {
|
||||||
this.dialogTitle = this.$t('api_test.environment.config_environment');
|
this.dialogTitle = this.$t('api_test.environment.config_environment');
|
||||||
this.currentProjectId = environment.projectId;
|
this.currentProjectId = environment.projectId;
|
||||||
|
environment.currentProjectId = environment.projectId;
|
||||||
const temEnv = {};
|
const temEnv = {};
|
||||||
Object.assign(temEnv, environment);
|
Object.assign(temEnv, environment);
|
||||||
parseEnvironment(temEnv); //parseEnvironment会改变环境对象的内部结构,从而影响前端列表的显示,所以复制一个环境对象作为代替
|
parseEnvironment(temEnv); //parseEnvironment会改变环境对象的内部结构,从而影响前端列表的显示,所以复制一个环境对象作为代替
|
||||||
|
@ -323,11 +320,12 @@ export default {
|
||||||
this.dialogVisible = true;
|
this.dialogVisible = true;
|
||||||
this.ifCreate = false;
|
this.ifCreate = false;
|
||||||
},
|
},
|
||||||
save(){
|
save() {
|
||||||
this.$refs.environmentEdit.save();
|
this.$refs.environmentEdit.save();
|
||||||
},
|
},
|
||||||
copyEnv(environment) {
|
copyEnv(environment) {
|
||||||
this.currentProjectId = environment.projectId; //复制时默认选择所要复制环境对应的项目
|
this.currentProjectId = environment.projectId; //复制时默认选择所要复制环境对应的项目
|
||||||
|
environment.currentProjectId = environment.projectId;
|
||||||
this.dialogTitle = this.$t('api_test.environment.copy_environment');
|
this.dialogTitle = this.$t('api_test.environment.copy_environment');
|
||||||
const temEnv = {};
|
const temEnv = {};
|
||||||
Object.assign(temEnv, environment);
|
Object.assign(temEnv, environment);
|
||||||
|
@ -458,7 +456,7 @@ export default {
|
||||||
this.selectRow.forEach(row => {
|
this.selectRow.forEach(row => {
|
||||||
map.set(row.projectId, row.id);
|
map.set(row.projectId, row.id);
|
||||||
})
|
})
|
||||||
this.$post("/environment/group/batch/add", {map: strMapToObj(map), groupIds:value}, () => {
|
this.$post("/environment/group/batch/add", {map: strMapToObj(map), groupIds: value}, () => {
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
this.getEnvironments();
|
this.getEnvironments();
|
||||||
})
|
})
|
||||||
|
|
|
@ -246,6 +246,7 @@ export let CUSTOM_TABLE_HEADER = {
|
||||||
{id: 'name', key: '2', label: 'api_test.variable_name'},
|
{id: 'name', key: '2', label: 'api_test.variable_name'},
|
||||||
{id: 'type', key: '3', label: 'test_track.case.type'},
|
{id: 'type', key: '3', label: 'test_track.case.type'},
|
||||||
{id: 'value', key: '4', label: 'api_test.value'},
|
{id: 'value', key: '4', label: 'api_test.value'},
|
||||||
|
{id: 'description', key: '5', label: 'commons.description'}
|
||||||
],
|
],
|
||||||
|
|
||||||
//缺陷列表
|
//缺陷列表
|
||||||
|
|
|
@ -211,6 +211,8 @@ export default {
|
||||||
modifier: 'Modifier',
|
modifier: 'Modifier',
|
||||||
validate: "Validate",
|
validate: "Validate",
|
||||||
batch_add: "Batch add",
|
batch_add: "Batch add",
|
||||||
|
import_variable: "Import variable",
|
||||||
|
export_variable: "Export variable",
|
||||||
batch_restore: "Batch restore",
|
batch_restore: "Batch restore",
|
||||||
batch_gc: "Batch gc",
|
batch_gc: "Batch gc",
|
||||||
check_project_tip: "Create or select the project first",
|
check_project_tip: "Create or select the project first",
|
||||||
|
@ -1193,7 +1195,8 @@ export default {
|
||||||
copy: "Copy Test",
|
copy: "Copy Test",
|
||||||
please_select_case: "Please select case",
|
please_select_case: "Please select case",
|
||||||
fail_to_stop: "Fail to stop",
|
fail_to_stop: "Fail to stop",
|
||||||
batch_add_parameter: "Format: parameter name: parameter value <br/> like:Accept-Encoding:utf-8",
|
batch_add_parameter: "Format: parameter name: parameter value <br/> like:Accept-Encoding:utf-8 <br/> Note: The parameter names in batch addition are repeated, and the last data is the latest data by default",
|
||||||
|
params_format_warning: "Incorrect data format at line {0}",
|
||||||
create_performance_test_tips: 'This operation cannot be completed without permission to create performance tests',
|
create_performance_test_tips: 'This operation cannot be completed without permission to create performance tests',
|
||||||
jar_config: {
|
jar_config: {
|
||||||
title: "Upload jar package",
|
title: "Upload jar package",
|
||||||
|
@ -1510,9 +1513,15 @@ export default {
|
||||||
environment_json: "Environment Config",
|
environment_json: "Environment Config",
|
||||||
environment_group_id: "Environment Group ID",
|
environment_group_id: "Environment Group ID",
|
||||||
select_environment: "Please select environment",
|
select_environment: "Please select environment",
|
||||||
|
select_variable: "Please select variable",
|
||||||
please_save_test: "Please Save Test First",
|
please_save_test: "Please Save Test First",
|
||||||
common_config: "Common Config",
|
common_config: "Common Config",
|
||||||
http_config: "HTTP Config",
|
http_config: "HTTP Config",
|
||||||
|
advanced_setting: "Click Advanced settings to add variable values",
|
||||||
|
variables_delete_info: "Are you sure you want to delete the selected variable",
|
||||||
|
csv_delete: "Are you sure you want to delete the CSV file",
|
||||||
|
delete_info: "Please select a data deletion",
|
||||||
|
list_info: "List data is separated by ,",
|
||||||
database_config: "Database Config",
|
database_config: "Database Config",
|
||||||
tcp_config: "TCP Config",
|
tcp_config: "TCP Config",
|
||||||
import: "Import Environment",
|
import: "Import Environment",
|
||||||
|
@ -2792,6 +2801,7 @@ export default {
|
||||||
delimiter: "Delimiter",
|
delimiter: "Delimiter",
|
||||||
format: "Output format",
|
format: "Output format",
|
||||||
quoted_data: "Whether to allow quotes",
|
quoted_data: "Whether to allow quotes",
|
||||||
|
csv_download: "CSV file does not support exporting"
|
||||||
},
|
},
|
||||||
auth_source: {
|
auth_source: {
|
||||||
delete_prompt: 'This operation will delete the authentication source, do you want to continue? ',
|
delete_prompt: 'This operation will delete the authentication source, do you want to continue? ',
|
||||||
|
|
|
@ -212,6 +212,8 @@ export default {
|
||||||
modifier: '修改人',
|
modifier: '修改人',
|
||||||
validate: "校验",
|
validate: "校验",
|
||||||
batch_add: "批量添加",
|
batch_add: "批量添加",
|
||||||
|
import_variable: "导入变量",
|
||||||
|
export_variable: "导出变量",
|
||||||
batch_restore: "批量恢复",
|
batch_restore: "批量恢复",
|
||||||
batch_gc: "批量回收",
|
batch_gc: "批量回收",
|
||||||
check_project_tip: "请先创建或选择项目",
|
check_project_tip: "请先创建或选择项目",
|
||||||
|
@ -1203,7 +1205,8 @@ export default {
|
||||||
copy: "复制测试",
|
copy: "复制测试",
|
||||||
please_select_case: "请选择用例",
|
please_select_case: "请选择用例",
|
||||||
fail_to_stop: "失败停止",
|
fail_to_stop: "失败停止",
|
||||||
batch_add_parameter: "格式:参数名:参数值 <br/> 如:Accept-Encoding:utf-8",
|
batch_add_parameter: "格式:参数名:参数值 <br/> 如:Accept-Encoding:utf-8 <br/> 注:批量添加里的参数名重复,默认以最后一条数据为最新数据",
|
||||||
|
params_format_warning: "第{0}行数据格式有误",
|
||||||
create_performance_test_tips: '没有创建性能测试的权限,无法完成此操作',
|
create_performance_test_tips: '没有创建性能测试的权限,无法完成此操作',
|
||||||
jar_config: {
|
jar_config: {
|
||||||
title: "上传jar包",
|
title: "上传jar包",
|
||||||
|
@ -1519,8 +1522,14 @@ export default {
|
||||||
environment_json: "环境配置",
|
environment_json: "环境配置",
|
||||||
environment_group_id: "环境组ID",
|
environment_group_id: "环境组ID",
|
||||||
select_environment: "请选择环境",
|
select_environment: "请选择环境",
|
||||||
|
select_variable: "请选择变量",
|
||||||
please_save_test: "请先保存测试",
|
please_save_test: "请先保存测试",
|
||||||
common_config: "通用配置",
|
common_config: "通用配置",
|
||||||
|
list_info: "列表数据用,分隔",
|
||||||
|
advanced_setting: "点击高级设置,添加变量值",
|
||||||
|
variables_delete_info: "是否确认删除所选变量",
|
||||||
|
csv_delete: "是否确认删除CSV文件",
|
||||||
|
delete_info: "请选择一条数据删除",
|
||||||
http_config: "HTTP配置",
|
http_config: "HTTP配置",
|
||||||
database_config: "数据库配置",
|
database_config: "数据库配置",
|
||||||
tcp_config: "TCP配置",
|
tcp_config: "TCP配置",
|
||||||
|
@ -2801,6 +2810,7 @@ export default {
|
||||||
delimiter: "分隔符",
|
delimiter: "分隔符",
|
||||||
format: "输出格式",
|
format: "输出格式",
|
||||||
quoted_data: "是否允许带引号",
|
quoted_data: "是否允许带引号",
|
||||||
|
csv_download: "CSV文件暂不支持导出"
|
||||||
},
|
},
|
||||||
auth_source: {
|
auth_source: {
|
||||||
delete_prompt: '此操作会删除认证源,是否继续?',
|
delete_prompt: '此操作会删除认证源,是否继续?',
|
||||||
|
|
|
@ -212,6 +212,8 @@ export default {
|
||||||
modifier: '修改人',
|
modifier: '修改人',
|
||||||
validate: "校驗",
|
validate: "校驗",
|
||||||
batch_add: "批量添加",
|
batch_add: "批量添加",
|
||||||
|
import_variable: "導出變量",
|
||||||
|
export_variable: "导出变量",
|
||||||
batch_restore: "批量恢復",
|
batch_restore: "批量恢復",
|
||||||
batch_gc: "批量回收",
|
batch_gc: "批量回收",
|
||||||
check_project_tip: "請先創建或選擇項目",
|
check_project_tip: "請先創建或選擇項目",
|
||||||
|
@ -1200,7 +1202,8 @@ export default {
|
||||||
copy: "復製測試",
|
copy: "復製測試",
|
||||||
please_select_case: "請選擇用例",
|
please_select_case: "請選擇用例",
|
||||||
fail_to_stop: "失敗停止",
|
fail_to_stop: "失敗停止",
|
||||||
batch_add_parameter: "格式:參數名:參數值 <br/> 如:Accept-Encoding:utf-8",
|
batch_add_parameter: "格式:參數名:參數值 <br/> 如:Accept-Encoding:utf-8 <br/> 注:批量添加里的參數名重複,默認以最後一條數據為最新數據",
|
||||||
|
params_format_warning: "第{0}行數據格式有誤",
|
||||||
create_performance_test_tips: '沒有創建性能測試的權限,無法完成此操作',
|
create_performance_test_tips: '沒有創建性能測試的權限,無法完成此操作',
|
||||||
jar_config: {
|
jar_config: {
|
||||||
title: "上傳jar包",
|
title: "上傳jar包",
|
||||||
|
@ -1516,9 +1519,15 @@ export default {
|
||||||
environment_json: "環境配置",
|
environment_json: "環境配置",
|
||||||
environment_group_id: "環境組ID",
|
environment_group_id: "環境組ID",
|
||||||
select_environment: "請選擇環境",
|
select_environment: "請選擇環境",
|
||||||
|
select_variable: "請選擇变量",
|
||||||
please_save_test: "請先保存測試",
|
please_save_test: "請先保存測試",
|
||||||
common_config: "通用配置",
|
common_config: "通用配置",
|
||||||
http_config: "HTTP配置",
|
http_config: "HTTP配置",
|
||||||
|
list_info: "清單數據用,分隔",
|
||||||
|
advanced_setting: "點擊高級設定,添加變數值",
|
||||||
|
variables_delete_info: "是否確認刪除所選變量",
|
||||||
|
csv_delete: "是否確認删除CSV檔案",
|
||||||
|
delete_info: "請選擇一條數據刪除",
|
||||||
database_config: "數據庫配置",
|
database_config: "數據庫配置",
|
||||||
tcp_config: "TCP配置",
|
tcp_config: "TCP配置",
|
||||||
import: "導入環境",
|
import: "導入環境",
|
||||||
|
@ -2795,6 +2804,7 @@ export default {
|
||||||
delimiter: "分隔符",
|
delimiter: "分隔符",
|
||||||
format: "輸出格式",
|
format: "輸出格式",
|
||||||
quoted_data: "是否允許帶引號",
|
quoted_data: "是否允許帶引號",
|
||||||
|
csv_download: "CSV文件暫不支持導出"
|
||||||
},
|
},
|
||||||
auth_source: {
|
auth_source: {
|
||||||
delete_prompt: '此操作會刪除認證源,是否繼續?',
|
delete_prompt: '此操作會刪除認證源,是否繼續?',
|
||||||
|
|
Loading…
Reference in New Issue