Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
e9482b3ecb
|
@ -5,37 +5,26 @@ import com.github.pagehelper.PageHelper;
|
|||
import io.metersphere.api.dto.JmxInfoDTO;
|
||||
import io.metersphere.api.dto.automation.*;
|
||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||
import io.metersphere.api.dto.definition.request.*;
|
||||
import io.metersphere.api.dto.scenario.KeyValue;
|
||||
import io.metersphere.api.service.ApiAutomationService;
|
||||
import io.metersphere.base.domain.ApiScenario;
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import io.metersphere.base.domain.Schedule;
|
||||
import io.metersphere.commons.constants.ReportTriggerMode;
|
||||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
import io.metersphere.commons.utils.Pager;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.performance.service.PerformanceTestService;
|
||||
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
|
||||
import io.metersphere.track.request.testplan.SaveTestPlanRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
import org.apache.jorphan.collections.ListedHashTree;
|
||||
import io.metersphere.track.request.testplan.FileOperationRequest;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/api/automation")
|
||||
|
@ -44,9 +33,6 @@ public class ApiAutomationController {
|
|||
|
||||
@Resource
|
||||
ApiAutomationService apiAutomationService;
|
||||
@Resource
|
||||
PerformanceTestService performanceTestService;
|
||||
|
||||
|
||||
@PostMapping("/list/{goPage}/{pageSize}")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER}, logical = Logical.OR)
|
||||
|
@ -145,5 +131,14 @@ public class ApiAutomationController {
|
|||
runRequest.setExecuteType(ExecuteType.Completed.name());
|
||||
return apiAutomationService.genPerformanceTestJmx(runRequest);
|
||||
}
|
||||
|
||||
@PostMapping("/file/download")
|
||||
public ResponseEntity<byte[]> download(@RequestBody FileOperationRequest fileOperationRequest) {
|
||||
byte[] bytes = apiAutomationService.loadFileAsBytes(fileOperationRequest);
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileOperationRequest.getName() + "\"")
|
||||
.body(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.alibaba.fastjson.annotation.JSONType;
|
|||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
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.service.ApiAutomationService;
|
||||
|
@ -19,12 +20,16 @@ import lombok.EqualsAndHashCode;
|
|||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.config.Arguments;
|
||||
import org.apache.jmeter.config.CSVDataSet;
|
||||
import org.apache.jmeter.config.RandomVariableConfig;
|
||||
import org.apache.jmeter.modifiers.CounterConfig;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
|
@ -42,11 +47,13 @@ public class MsScenario extends MsTestElement {
|
|||
private String environmentId;
|
||||
|
||||
@JSONField(ordinal = 23)
|
||||
private List<KeyValue> variables;
|
||||
private List<ScenarioVariable> variables;
|
||||
|
||||
@JSONField(ordinal = 24)
|
||||
private boolean enableCookieShare;
|
||||
|
||||
private static final String BODY_FILE_DIR = "/opt/metersphere/data/body";
|
||||
|
||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||
if (!this.isEnable()) {
|
||||
return;
|
||||
|
@ -84,7 +91,9 @@ public class MsScenario extends MsTestElement {
|
|||
}
|
||||
// 场景变量和环境变量
|
||||
tree.add(arguments(config));
|
||||
|
||||
addCsvDataSet(tree);
|
||||
addCounter(tree);
|
||||
addRandom(tree);
|
||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||
for (MsTestElement el : hashTree) {
|
||||
el.toHashTree(tree, el.getHashTree(), config);
|
||||
|
@ -92,6 +101,13 @@ public class MsScenario extends MsTestElement {
|
|||
}
|
||||
}
|
||||
|
||||
public void setOldVariables(List<KeyValue> oldVariables) {
|
||||
if (CollectionUtils.isNotEmpty(oldVariables)) {
|
||||
String json = JSON.toJSONString(oldVariables);
|
||||
this.variables = JSON.parseArray(json, ScenarioVariable.class);
|
||||
}
|
||||
}
|
||||
|
||||
private Arguments arguments(ParameterConfig config) {
|
||||
Arguments arguments = new Arguments();
|
||||
arguments.setEnabled(true);
|
||||
|
@ -99,7 +115,7 @@ public class MsScenario extends MsTestElement {
|
|||
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
||||
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
|
||||
if (CollectionUtils.isNotEmpty(this.getVariables())) {
|
||||
variables.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
|
||||
variables.stream().filter(ScenarioVariable::isConstantValid).forEach(keyValue ->
|
||||
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
|
||||
);
|
||||
}
|
||||
|
@ -111,4 +127,72 @@ public class MsScenario extends MsTestElement {
|
|||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
private void addCsvDataSet(HashTree tree) {
|
||||
if (CollectionUtils.isNotEmpty(this.getVariables())) {
|
||||
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isCSVValid).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
list.forEach(item -> {
|
||||
CSVDataSet csvDataSet = new CSVDataSet();
|
||||
csvDataSet.setEnabled(true);
|
||||
csvDataSet.setProperty(TestElement.TEST_CLASS, CSVDataSet.class.getName());
|
||||
csvDataSet.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
|
||||
csvDataSet.setName(item.getName());
|
||||
csvDataSet.setProperty("fileEncoding", item.getEncoding());
|
||||
csvDataSet.setProperty("variableNames", item.getName());
|
||||
if (CollectionUtils.isNotEmpty(item.getFiles())) {
|
||||
csvDataSet.setProperty("filename", BODY_FILE_DIR + "/" + item.getFiles().get(0).getId() + "_" + item.getFiles().get(0).getName());
|
||||
}
|
||||
csvDataSet.setIgnoreFirstLine(false);
|
||||
csvDataSet.setProperty("delimiter", item.getDelimiter());
|
||||
csvDataSet.setComment(item.getDescription());
|
||||
tree.add(csvDataSet);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addCounter(HashTree tree) {
|
||||
if (CollectionUtils.isNotEmpty(this.getVariables())) {
|
||||
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isCounterValid).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
list.forEach(item -> {
|
||||
CounterConfig counterConfig = new CounterConfig();
|
||||
counterConfig.setEnabled(true);
|
||||
counterConfig.setProperty(TestElement.TEST_CLASS, CounterConfig.class.getName());
|
||||
counterConfig.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("CounterConfigGui"));
|
||||
counterConfig.setName(item.getName());
|
||||
counterConfig.setStart(item.getStartNumber());
|
||||
counterConfig.setEnd(item.getEndNumber());
|
||||
counterConfig.setVarName(item.getName());
|
||||
counterConfig.setIncrement(item.getIncrement());
|
||||
counterConfig.setFormat(item.getValue());
|
||||
counterConfig.setComment(item.getDescription());
|
||||
tree.add(counterConfig);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addRandom(HashTree tree) {
|
||||
if (CollectionUtils.isNotEmpty(this.getVariables())) {
|
||||
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isRandom).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
list.forEach(item -> {
|
||||
RandomVariableConfig randomVariableConfig = new RandomVariableConfig();
|
||||
randomVariableConfig.setEnabled(true);
|
||||
randomVariableConfig.setProperty(TestElement.TEST_CLASS, RandomVariableConfig.class.getName());
|
||||
randomVariableConfig.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
|
||||
randomVariableConfig.setName(item.getName());
|
||||
randomVariableConfig.setProperty("variableName", item.getName());
|
||||
randomVariableConfig.setProperty("outputFormat", item.getValue());
|
||||
randomVariableConfig.setProperty("minimumValue", item.getMinNumber());
|
||||
randomVariableConfig.setProperty("maximumValue", item.getMaxNumber());
|
||||
randomVariableConfig.setComment(item.getDescription());
|
||||
tree.add(randomVariableConfig);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.metersphere.api.dto.definition.request;
|
||||
|
||||
import io.metersphere.api.dto.scenario.KeyValue;
|
||||
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
import lombok.Data;
|
||||
|
||||
|
@ -11,7 +11,7 @@ public class ParameterConfig {
|
|||
// 环境配置
|
||||
private EnvironmentConfig config;
|
||||
// 公共场景参数
|
||||
private List<KeyValue> variables;
|
||||
private List<ScenarioVariable> variables;
|
||||
// 公共Cookie
|
||||
private boolean enableCookieShare;
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package io.metersphere.api.dto.definition.request.variable;
|
||||
|
||||
public enum EnumVariableType {
|
||||
CONSTANT, LIST, CSV, COUNTER, RANDOM,
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package io.metersphere.api.dto.definition.request.variable;
|
||||
|
||||
import io.metersphere.api.dto.scenario.request.BodyFile;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ScenarioVariable {
|
||||
|
||||
// CONSTANT LIST CSV COUNTER RANDOM
|
||||
private String type;
|
||||
private String id;
|
||||
private String name;
|
||||
// 常量值,列表值[] ,计数器输出格式,随机数输出格式
|
||||
private String value;
|
||||
private String description;
|
||||
// csv
|
||||
private List<BodyFile> files;
|
||||
private String delimiter;
|
||||
private String encoding;
|
||||
// counter
|
||||
private int startNumber;
|
||||
private int endNumber;
|
||||
private int increment;
|
||||
// random
|
||||
private String minNumber;
|
||||
private String maxNumber;
|
||||
|
||||
public boolean isConstantValid() {
|
||||
if ((StringUtils.equals(this.type, EnumVariableType.CONSTANT.name()) || StringUtils.equals(this.type, EnumVariableType.LIST.name())) && StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(value)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isCSVValid() {
|
||||
if (StringUtils.equals(this.type, EnumVariableType.CSV.name()) && StringUtils.isNotEmpty(name)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isCounterValid() {
|
||||
if (StringUtils.equals(this.type, EnumVariableType.COUNTER.name()) && StringUtils.isNotEmpty(name)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isRandom() {
|
||||
if (StringUtils.equals(this.type, EnumVariableType.RANDOM.name()) && StringUtils.isNotEmpty(name)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ import io.metersphere.api.dto.automation.*;
|
|||
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||
import io.metersphere.api.dto.definition.request.*;
|
||||
import io.metersphere.api.dto.scenario.KeyValue;
|
||||
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.base.domain.*;
|
||||
|
@ -30,18 +30,16 @@ import io.metersphere.commons.utils.ServiceUtils;
|
|||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.job.sechedule.ApiScenarioTestJob;
|
||||
import io.metersphere.performance.service.PerformanceTestService;
|
||||
import io.metersphere.service.ScheduleService;
|
||||
import io.metersphere.track.dto.TestPlanDTO;
|
||||
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
|
||||
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
|
||||
import io.metersphere.track.request.testplan.SaveTestPlanRequest;
|
||||
import io.metersphere.track.request.testplan.FileOperationRequest;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.ibatis.session.ExecutorType;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
import org.apache.jorphan.collections.ListedHashTree;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@ -50,6 +48,8 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -78,15 +78,13 @@ public class ApiAutomationService {
|
|||
SqlSessionFactory sqlSessionFactory;
|
||||
@Resource
|
||||
private ApiScenarioReportMapper apiScenarioReportMapper;
|
||||
@Resource
|
||||
private PerformanceTestService performanceTestService;
|
||||
|
||||
public List<ApiScenarioDTO> list(ApiScenarioRequest request) {
|
||||
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
|
||||
if(request.isSelectThisWeedData()){
|
||||
if (request.isSelectThisWeedData()) {
|
||||
Map<String, Date> weekFirstTimeAndLastTime = DateUtils.getWeedFirstTimeAndLastTime(new Date());
|
||||
Date weekFirstTime = weekFirstTimeAndLastTime.get("firstTime");
|
||||
if(weekFirstTime!=null){
|
||||
if (weekFirstTime != null) {
|
||||
request.setCreateTime(weekFirstTime.getTime());
|
||||
}
|
||||
}
|
||||
|
@ -285,6 +283,22 @@ public class ApiAutomationService {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public byte[] loadFileAsBytes(FileOperationRequest fileOperationRequest) {
|
||||
File file = new File("/opt/metersphere/data/body/" + fileOperationRequest.getId() + "_" + fileOperationRequest.getName());
|
||||
try (FileInputStream fis = new FileInputStream(file);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);) {
|
||||
byte[] b = new byte[1000];
|
||||
int n;
|
||||
while ((n = fis.read(b)) != -1) {
|
||||
bos.write(b, 0, n);
|
||||
}
|
||||
return bos.toByteArray();
|
||||
} catch (Exception ex) {
|
||||
LogUtil.error(ex.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void createScenarioReport(String id, String scenarioId, String scenarioName, String triggerMode, String execType, String projectId, String userID) {
|
||||
APIScenarioReportResult report = new APIScenarioReportResult();
|
||||
report.setId(id);
|
||||
|
@ -354,12 +368,14 @@ public class ApiAutomationService {
|
|||
// 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取
|
||||
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
|
||||
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
|
||||
new TypeReference<LinkedList<MsTestElement>>() {});
|
||||
new TypeReference<LinkedList<MsTestElement>>() {
|
||||
});
|
||||
scenario.setHashTree(elements);
|
||||
}
|
||||
if (StringUtils.isNotEmpty(element.getString("variables"))) {
|
||||
LinkedList<KeyValue> variables = mapper.readValue(element.getString("variables"),
|
||||
new TypeReference<LinkedList<KeyValue>>() {});
|
||||
LinkedList<ScenarioVariable> variables = mapper.readValue(element.getString("variables"),
|
||||
new TypeReference<LinkedList<ScenarioVariable>>() {
|
||||
});
|
||||
scenario.setVariables(variables);
|
||||
}
|
||||
group.setEnableCookieShare(scenario.isEnableCookieShare());
|
||||
|
@ -592,8 +608,8 @@ public class ApiAutomationService {
|
|||
scenario.setHashTree(elements);
|
||||
}
|
||||
if (StringUtils.isNotEmpty(element.getString("variables"))) {
|
||||
LinkedList<KeyValue> variables = mapper.readValue(element.getString("variables"),
|
||||
new TypeReference<LinkedList<KeyValue>>() {
|
||||
LinkedList<ScenarioVariable> variables = mapper.readValue(element.getString("variables"),
|
||||
new TypeReference<LinkedList<ScenarioVariable>>() {
|
||||
});
|
||||
scenario.setVariables(variables);
|
||||
}
|
||||
|
@ -602,7 +618,6 @@ public class ApiAutomationService {
|
|||
scenarios.add(scenario);
|
||||
group.setHashTree(scenarios);
|
||||
testPlan.getHashTree().add(group);
|
||||
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
MSException.throwException(ex.getMessage());
|
||||
|
@ -615,6 +630,6 @@ public class ApiAutomationService {
|
|||
JmxInfoDTO dto = new JmxInfoDTO();
|
||||
dto.setName(name);
|
||||
dto.setXml(jmx);
|
||||
return dto;
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
|||
import io.metersphere.api.dto.definition.*;
|
||||
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
||||
import io.metersphere.api.dto.definition.request.*;
|
||||
import io.metersphere.api.dto.scenario.KeyValue;
|
||||
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
||||
import io.metersphere.api.dto.scenario.request.RequestType;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.api.jmeter.TestResult;
|
||||
|
@ -367,8 +367,8 @@ public class ApiDefinitionService {
|
|||
scenario.setHashTree(elements);
|
||||
}
|
||||
if (StringUtils.isNotEmpty(element.getString("variables"))) {
|
||||
LinkedList<KeyValue> variables = mapper.readValue(element.getString("variables"),
|
||||
new TypeReference<LinkedList<KeyValue>>() {
|
||||
LinkedList<ScenarioVariable> variables = mapper.readValue(element.getString("variables"),
|
||||
new TypeReference<LinkedList<ScenarioVariable>>() {
|
||||
});
|
||||
scenario.setVariables(variables);
|
||||
}
|
||||
|
@ -624,4 +624,4 @@ public class ApiDefinitionService {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -66,7 +66,7 @@ public class HistoricalDataUpgradeService {
|
|||
|
||||
private MsScenario createScenario(Scenario oldScenario) {
|
||||
MsScenario scenario = new MsScenario();
|
||||
scenario.setVariables(oldScenario.getVariables());
|
||||
scenario.setOldVariables(oldScenario.getVariables());
|
||||
scenario.setName(oldScenario.getName());
|
||||
scenario.setEnableCookieShare(oldScenario.isEnableCookieShare());
|
||||
scenario.setEnvironmentId(oldScenario.getEnvironmentId());
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 068127ce59ea8b016434ed52a9de4a7a4b13bdb4
|
||||
Subproject commit 9f4a9bbf46fc1333dbcccea21f83e27e3ec10b1f
|
|
@ -39,6 +39,7 @@
|
|||
"vue-float-action-button": "^0.6.6",
|
||||
"vue-i18n": "^8.15.3",
|
||||
"vue-input-tag": "^2.0.7",
|
||||
"vue-papa-parse": "^2.0.0",
|
||||
"vue-pdf": "^4.2.0",
|
||||
"vue-router": "^3.1.3",
|
||||
"vuedraggable": "^2.23.2",
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
</el-col>
|
||||
<el-col :span="3" class="ms-col-one ms-font">
|
||||
<el-link class="head" @click="showScenarioParameters">{{$t('api_test.automation.scenario_total')}}</el-link>
|
||||
:{{this.currentScenario.variables!=undefined?this.currentScenario.variables.length-1: 0}}
|
||||
:{{this.currentScenario.variables!=undefined?this.currentScenario.variables.length: 0}}
|
||||
</el-col>
|
||||
<el-col :span="3" class="ms-col-one ms-font">
|
||||
<el-checkbox v-model="enableCookieShare">共享cookie</el-checkbox>
|
||||
|
@ -218,7 +218,7 @@
|
|||
</el-drawer>
|
||||
|
||||
<!--场景公共参数-->
|
||||
<ms-scenario-parameters :currentScenario="currentScenario" @addParameters="addParameters" ref="scenarioParameters"/>
|
||||
<ms-variable-list @setVariables="setVariables" ref="scenarioParameters"/>
|
||||
<!--外部导入-->
|
||||
<api-import ref="apiImport" :saved="false" @refresh="apiImport"/>
|
||||
</div>
|
||||
|
@ -245,7 +245,7 @@
|
|||
import MsLoopController from "./LoopController";
|
||||
import MsApiScenarioComponent from "./ApiScenarioComponent";
|
||||
import MsApiReportDetail from "../report/ApiReportDetail";
|
||||
import MsScenarioParameters from "./ScenarioParameters";
|
||||
import MsVariableList from "./variable/VariableList";
|
||||
import ApiImport from "../../definition/components/import/ApiImport";
|
||||
import InputTag from 'vue-input-tag'
|
||||
import "@/common/css/material-icons.css"
|
||||
|
@ -260,10 +260,10 @@
|
|||
currentScenario: {},
|
||||
},
|
||||
components: {
|
||||
MsVariableList,
|
||||
ScenarioRelevance,
|
||||
ScenarioApiRelevance,
|
||||
ApiEnvironmentConfig,
|
||||
MsScenarioParameters,
|
||||
MsApiReportDetail,
|
||||
MsInputTag, MsRun,
|
||||
MsApiScenarioComponent,
|
||||
|
@ -332,10 +332,7 @@
|
|||
this.operatingElements = ELEMENTS.get("ALL");
|
||||
this.getMaintainerOptions();
|
||||
this.getApiScenario();
|
||||
}
|
||||
,
|
||||
watch: {}
|
||||
,
|
||||
},
|
||||
directives: {OutsideClick},
|
||||
computed: {
|
||||
buttons() {
|
||||
|
@ -456,6 +453,13 @@
|
|||
getIdx(index) {
|
||||
return index - 0.33
|
||||
},
|
||||
setVariables(v) {
|
||||
this.currentScenario.variables = v;
|
||||
if (this.path.endsWith("/update")) {
|
||||
// 直接更新场景防止编辑内容丢失
|
||||
this.editScenario();
|
||||
}
|
||||
},
|
||||
showButton(...names) {
|
||||
for (const name of names) {
|
||||
if (this.operatingElements.includes(name)) {
|
||||
|
@ -682,12 +686,17 @@
|
|||
this.$error(this.$t('api_test.environment.select_environment'));
|
||||
return;
|
||||
}
|
||||
this.debugData = {
|
||||
id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario",
|
||||
variables: this.currentScenario.variables, referenced: 'Created', enableCookieShare: this.enableCookieShare,
|
||||
environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition
|
||||
};
|
||||
this.reportId = getUUID().substring(0, 8);
|
||||
this.$refs['currentScenario'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.editScenario();
|
||||
this.debugData = {
|
||||
id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario",
|
||||
variables: this.currentScenario.variables, referenced: 'Created', enableCookieShare: this.enableCookieShare,
|
||||
environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition
|
||||
};
|
||||
this.reportId = getUUID().substring(0, 8);
|
||||
}
|
||||
})
|
||||
},
|
||||
getEnvironments() {
|
||||
if (this.projectId) {
|
||||
|
@ -808,15 +817,33 @@
|
|||
this.recursiveFile(item.hashTree, bodyUploadFiles, obj);
|
||||
}
|
||||
})
|
||||
// 场景变量csv 文件
|
||||
this.currentScenario.variables.forEach(param => {
|
||||
if (param.type === 'CSV' && param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
if (!item.id) {
|
||||
let fileId = getUUID().substring(0, 12);
|
||||
item.name = item.file.name;
|
||||
item.id = fileId;
|
||||
}
|
||||
obj.bodyUploadIds.push(item.id);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return bodyUploadFiles;
|
||||
},
|
||||
editScenario() {
|
||||
editScenario(showMessage) {
|
||||
this.$refs['currentScenario'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.setParameter();
|
||||
let bodyFiles = this.getBodyUploadFiles(this.currentScenario);
|
||||
this.$fileUpload(this.path, null, bodyFiles, this.currentScenario, response => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
if (showMessage) {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
}
|
||||
this.path = "/api/automation/update";
|
||||
if (response.data) {
|
||||
this.currentScenario.id = response.data.id;
|
||||
|
@ -841,7 +868,20 @@
|
|||
let obj = JSON.parse(response.data.scenarioDefinition);
|
||||
if (obj) {
|
||||
this.currentEnvironmentId = obj.environmentId;
|
||||
this.currentScenario.variables = obj.variables;
|
||||
this.currentScenario.variables = [];
|
||||
let index = 1;
|
||||
obj.variables.forEach(item => {
|
||||
// 兼容历史数据
|
||||
if (item.name) {
|
||||
if (!item.type) {
|
||||
item.type = "CONSTANT";
|
||||
item.id = getUUID();
|
||||
}
|
||||
item.num = index;
|
||||
this.currentScenario.variables.push(item);
|
||||
index++;
|
||||
}
|
||||
})
|
||||
this.enableCookieShare = obj.enableCookieShare;
|
||||
this.scenarioDefinition = obj.hashTree;
|
||||
}
|
||||
|
@ -853,8 +893,7 @@
|
|||
this.getEnvironments();
|
||||
})
|
||||
}
|
||||
}
|
||||
,
|
||||
},
|
||||
setParameter() {
|
||||
this.currentScenario.stepTotal = this.scenarioDefinition.length;
|
||||
this.currentScenario.projectId = getCurrentProjectID();
|
||||
|
@ -878,17 +917,10 @@
|
|||
runRefresh() {
|
||||
this.debugVisible = true;
|
||||
this.loading = false;
|
||||
}
|
||||
,
|
||||
},
|
||||
showScenarioParameters() {
|
||||
this.$refs.scenarioParameters.open(this.currentScenario.variables);
|
||||
}
|
||||
,
|
||||
addParameters(data) {
|
||||
this.currentScenario.variables = data;
|
||||
this.reload();
|
||||
}
|
||||
,
|
||||
},
|
||||
apiImport(importData) {
|
||||
if (importData && importData.data) {
|
||||
importData.data.forEach(item => {
|
||||
|
@ -916,11 +948,6 @@
|
|||
background-color: white;
|
||||
}
|
||||
|
||||
.ms-opt-btn {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.ms-debug-div {
|
||||
border: 1px #DCDFE6 solid;
|
||||
border-radius: 4px;
|
||||
|
@ -1004,9 +1031,8 @@
|
|||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.ms-opt-btn {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
right: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
<template>
|
||||
<el-dialog :close-on-click-modal="false" :title="$t('api_test.scenario.variables')"
|
||||
:visible.sync="visible" class="environment-dialog" width="60%"
|
||||
@close="close">
|
||||
<el-container>
|
||||
<ms-api-scenario-variables :items="variables"
|
||||
:description="$t('api_test.scenario.kv_description')"/>
|
||||
</el-container>
|
||||
<template v-slot:footer>
|
||||
<ms-dialog-footer
|
||||
@cancel="close"
|
||||
@confirm="saveParameters"/>
|
||||
</template>
|
||||
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsApiScenarioVariables from "./ApiScenarioVariables";
|
||||
import {KeyValue} from "../../definition/model/ApiTestModel";
|
||||
import MsDialogFooter from "../../../common/components/MsDialogFooter";
|
||||
|
||||
export default {
|
||||
name: "MsScenarioParameters",
|
||||
components: {
|
||||
MsApiScenarioVariables,
|
||||
MsDialogFooter
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
variables: [new KeyValue()],
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open: function (v) {
|
||||
this.visible = true;
|
||||
if(v){
|
||||
this.variables = v;
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.visible = false;
|
||||
},
|
||||
saveParameters() {
|
||||
this.visible = false;
|
||||
this.$emit('addParameters', this.variables);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,125 @@
|
|||
<template>
|
||||
<span>
|
||||
<el-upload
|
||||
action="#"
|
||||
class="api-body-upload"
|
||||
list-type="picture-card"
|
||||
:http-request="upload"
|
||||
:beforeUpload="uploadValidate"
|
||||
:file-list="parameter.files"
|
||||
:limit="1"
|
||||
:on-exceed="exceed"
|
||||
ref="upload">
|
||||
|
||||
<div class="upload-default">
|
||||
<i class="el-icon-plus"/>
|
||||
</div>
|
||||
<div class="upload-item" slot="file" slot-scope="{file}">
|
||||
<span>{{file.file ? file.file.name : file.name}}</span>
|
||||
<span class="el-upload-list__item-actions">
|
||||
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)">
|
||||
<i class="el-icon-delete"/>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</el-upload>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsApiBodyFileUpload",
|
||||
data() {
|
||||
return {
|
||||
disabled: false,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
parameter: Object,
|
||||
default() {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleRemove(file) {
|
||||
this.$refs.upload.handleRemove(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;
|
||||
}
|
||||
}
|
||||
},
|
||||
exceed() {
|
||||
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
|
||||
},
|
||||
upload(file) {
|
||||
this.parameter.files.push(file);
|
||||
},
|
||||
uploadValidate(file) {
|
||||
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("只能上传CSV文件");
|
||||
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: 6px;
|
||||
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;
|
||||
}
|
||||
|
||||
.upload-item {
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form">
|
||||
<el-form-item :label="$t('api_test.variable_name')" prop="name">
|
||||
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('commons.description')" prop="description">
|
||||
<el-input class="ms-http-textarea"
|
||||
v-model="editData.description"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 10}"
|
||||
:rows="2" size="small"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('api_test.value')" prop="value">
|
||||
<el-input v-model="editData.value" :placeholder="$t('api_test.value')"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsEditConstant",
|
||||
components: {},
|
||||
props: {
|
||||
editData: {},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,41 @@
|
|||
<template>
|
||||
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form2">
|
||||
<el-form-item :label="$t('api_test.variable_name')" prop="name">
|
||||
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('commons.description')" prop="description">
|
||||
<el-input class="ms-http-textarea"
|
||||
v-model="editData.description"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 10}"
|
||||
:rows="2" size="small"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开始" prop="set">
|
||||
<el-input-number size="small" v-model="editData.startNumber" placeholder="0" :max="1000*10000000" :min="0"/>
|
||||
<span style="margin: 0px 10px 10px ">结束</span>
|
||||
<el-input-number size="small" v-model="editData.endNumber" placeholder="10" :max="1000*10000000" :min="0"/>
|
||||
<span style="margin: 0px 10px 10px ">增量</span>
|
||||
<el-input-number size="small" v-model="editData.increment" placeholder="1" :max="1000*10000000" :min="0"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开始" prop="value">
|
||||
<el-input v-model="editData.value" placeholder="000产生至少3位数字。user_000输出形式为user_nnn"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsEditCounter",
|
||||
components: {},
|
||||
props: {
|
||||
editData: {},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,129 @@
|
|||
<template>
|
||||
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form3">
|
||||
<el-form-item :label="$t('api_test.variable_name')" prop="name">
|
||||
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('commons.description')" prop="description">
|
||||
<el-input class="ms-http-textarea"
|
||||
v-model="editData.description"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 10}"
|
||||
:rows="2" size="small"/>
|
||||
</el-form-item>
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick" style="margin-left: 40px">
|
||||
<el-tab-pane label="配置" name="config">
|
||||
<el-row>
|
||||
<el-col :span="4" style="margin-top: 5px">
|
||||
<span>添加文件</span>
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
<ms-csv-file-upload :parameter="editData"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row style="margin-top: 10px">
|
||||
<el-col :span="4" style="margin-top: 5px">
|
||||
<span>Encoding</span>
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
<el-input v-model="editData.encoding" size="small"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row style="margin-top: 10px">
|
||||
<el-col :span="4" style="margin-top: 5px">
|
||||
<span>分隔符</span>
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
<el-input v-model="editData.delimiter" size="small"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('schema.preview')" name="preview">
|
||||
<el-table
|
||||
:data="previewData"
|
||||
style="width: 100%"
|
||||
height="400px"
|
||||
v-loading="loading">
|
||||
<!-- 自定义列的遍历-->
|
||||
<el-table-column v-for="(item, index) in columns" :key="index" :label="columns[index]" align="left" width="180">
|
||||
<!-- 数据的遍历 scope.row就代表数据的每一个对象-->
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row[index]}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsCsvFileUpload from "./CsvFileUpload";
|
||||
|
||||
export default {
|
||||
name: "MsEditCsv",
|
||||
components: {
|
||||
MsCsvFileUpload
|
||||
},
|
||||
props: {
|
||||
editData: {},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: "config",
|
||||
visible: false,
|
||||
loading: false,
|
||||
editFlag: false,
|
||||
previewData: [],
|
||||
columns: [],
|
||||
rule: {
|
||||
name: [
|
||||
{required: true, message: this.$t('api_test.variable_name'), trigger: 'blur'},
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
complete(results) {
|
||||
if (results.errors && results.errors.length > 0) {
|
||||
this.$error(results.errors);
|
||||
return;
|
||||
}
|
||||
if (results.data) {
|
||||
this.columns = results.data[0];
|
||||
this.previewData = results.data;
|
||||
}
|
||||
this.loading = false;
|
||||
},
|
||||
handleClick() {
|
||||
let config = {complete: this.complete};
|
||||
// 本地文件
|
||||
if (this.editData.files && this.editData.files.length > 0 && this.editData.files[0].file) {
|
||||
this.loading = true;
|
||||
this.$papa.parse(this.editData.files[0].file, config);
|
||||
}
|
||||
// 远程下载文件
|
||||
if (this.editData.files && this.editData.files.length > 0 && !this.editData.files[0].file) {
|
||||
let file = this.editData.files[0];
|
||||
let conf = {
|
||||
url: "/api/automation/file/download",
|
||||
method: 'post',
|
||||
data: file,
|
||||
responseType: 'blob',
|
||||
};
|
||||
this.result = this.$request(conf).then(response => {
|
||||
const content = response.data;
|
||||
const blob = new Blob([content]);
|
||||
this.loading = true;
|
||||
this.$papa.parse(blob, config);
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form4">
|
||||
<el-form-item :label="$t('api_test.variable_name')" prop="name">
|
||||
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('commons.description')" prop="description">
|
||||
<el-input class="ms-http-textarea"
|
||||
v-model="editData.description"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 10}"
|
||||
:rows="2" size="small"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('api_test.value')" prop="value">
|
||||
<el-input v-model="editData.value" placeholder="列表数据用,分隔"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsEditListValue",
|
||||
components: {},
|
||||
props: {
|
||||
editData: {},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,40 @@
|
|||
<template>
|
||||
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form5">
|
||||
<el-form-item :label="$t('api_test.variable_name')" prop="name">
|
||||
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('commons.description')" prop="description">
|
||||
<el-input class="ms-http-textarea"
|
||||
v-model="editData.description"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 10}"
|
||||
:rows="2" size="small"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="最小值" prop="minNumber">
|
||||
<el-input size="small" v-model="editData.minNumber" placeholder="0"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="最大值" prop="maxNumber">
|
||||
<el-input size="small" v-model="editData.maxNumber" placeholder="10" />
|
||||
</el-form-item>
|
||||
<el-form-item label="开始" prop="value">
|
||||
<el-input v-model="editData.value" placeholder="000产生至少3位数字。user_000输出形式为user_nnn"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "MsEditRandom",
|
||||
components: {},
|
||||
props: {
|
||||
editData: {},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,156 @@
|
|||
<template>
|
||||
<el-dialog :title="$t('api_test.scenario.variables')"
|
||||
:visible.sync="visible" class="environment-dialog" width="70%"
|
||||
@close="close">
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<div style="border:1px #DCDFE6 solid; min-height: 400px;border-radius: 4px ;width: 100% ;">
|
||||
|
||||
<el-table ref="table" border :data="variables" class="adjust-table" @select-all="select" @select="select"
|
||||
v-loading="loading" @row-click="edit">
|
||||
<el-table-column type="selection" width="38"/>
|
||||
<el-table-column prop="num" label="ID" sortable/>
|
||||
<el-table-column prop="name" :label="$t('api_test.variable_name')" sortable show-overflow-tooltip/>
|
||||
<el-table-column prop="type" :label="$t('test_track.case.type')">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{types.get(scope.row.type)}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="value" :label="$t('api_test.value')" show-overflow-tooltip/>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<ms-edit-constant v-if="editData.type=='CONSTANT'" ref="parameters" :editData.sync="editData"/>
|
||||
<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-list-value v-if="editData.type=='LIST'" ref="listValue" :editData="editData"/>
|
||||
<ms-edit-csv v-if="editData.type=='CSV'" ref="csv" :editData.sync="editData"/>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
|
||||
</div>
|
||||
|
||||
<template v-slot:footer>
|
||||
<div style="margin:20px">
|
||||
<el-button style="margin-right:10px" @click="deleteVariable">{{$t('commons.delete')}}</el-button>
|
||||
|
||||
<el-dropdown split-button type="primary" @command="handleClick" placement="top-end">
|
||||
{{$t('commons.add')}}
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="CONSTANT">常量</el-dropdown-item>
|
||||
<el-dropdown-item command="LIST">列表</el-dropdown-item>
|
||||
<el-dropdown-item command="CSV">CSV</el-dropdown-item>
|
||||
<el-dropdown-item command="COUNTER">计数器</el-dropdown-item>
|
||||
<el-dropdown-item command="RANDOM">随机数</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsEditConstant from "./EditConstant";
|
||||
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
||||
import MsTableHeader from "@/business/components/common/components/MsTableHeader";
|
||||
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
|
||||
import MsEditCounter from "./EditCounter";
|
||||
import MsEditRandom from "./EditRandom";
|
||||
import MsEditListValue from "./EditListValue";
|
||||
import MsEditCsv from "./EditCsv";
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "MsVariableList",
|
||||
components: {
|
||||
MsEditConstant,
|
||||
MsDialogFooter,
|
||||
MsTableHeader,
|
||||
MsTablePagination,
|
||||
MsEditCounter,
|
||||
MsEditRandom,
|
||||
MsEditListValue,
|
||||
MsEditCsv
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
variables: [],
|
||||
types: new Map([
|
||||
['CONSTANT', '常量'],
|
||||
['LIST', '列表'],
|
||||
['CSV', 'CSV'],
|
||||
['COUNTER', '计数器'],
|
||||
['RANDOM', '随机数']
|
||||
]),
|
||||
visible: false,
|
||||
selection: [],
|
||||
loading: false,
|
||||
currentPage: 1,
|
||||
editData: {},
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick(command) {
|
||||
this.editData = {};
|
||||
this.editData.type = command;
|
||||
this.addParameters(this.editData);
|
||||
},
|
||||
edit(row) {
|
||||
this.editData = row;
|
||||
},
|
||||
addParameters(v) {
|
||||
v.id = getUUID();
|
||||
this.variables.push(v);
|
||||
let index = 1;
|
||||
this.variables.forEach(item => {
|
||||
item.num = index;
|
||||
index++;
|
||||
})
|
||||
},
|
||||
select(selection) {
|
||||
this.selection = selection.map(s => s.id);
|
||||
},
|
||||
isSelect(row) {
|
||||
return this.selection.includes(row.id)
|
||||
},
|
||||
open: function (variables) {
|
||||
this.variables = variables;
|
||||
this.visible = true;
|
||||
this.editData = {type: "CONSTANT"};
|
||||
this.addParameters(this.editData);
|
||||
},
|
||||
close() {
|
||||
this.visible = false;
|
||||
this.variables.forEach(item => {
|
||||
if (item.name === undefined || item.name === "") {
|
||||
const index = this.variables.findIndex(d => d.id === item.id);
|
||||
this.variables.splice(index, 1);
|
||||
}
|
||||
})
|
||||
this.$emit('setVariables', this.variables);
|
||||
},
|
||||
deleteVariable() {
|
||||
let ids = Array.from(this.selection);
|
||||
if (ids.length == 0) {
|
||||
this.$warning("请选择一条数据删除");
|
||||
return;
|
||||
}
|
||||
ids.forEach(row => {
|
||||
const index = this.variables.findIndex(d => d.id === row);
|
||||
this.variables.splice(index, 1);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -4,7 +4,7 @@
|
|||
<ms-table-operator-button :isTesterPermission="isTesterPermission" :tip="tip1" icon="el-icon-edit" @exec="editClick" @click.stop="editClickStop"/>
|
||||
<slot name="middle"></slot>
|
||||
<ms-table-operator-button :isTesterPermission="isTesterPermission" :tip="tip2" icon="el-icon-delete" type="danger" @exec="deleteClick" @click.stop="deleteClickStop"/>
|
||||
<slot name="beheind"></slot>
|
||||
<slot name="behind"></slot>
|
||||
</span>
|
||||
|
||||
</template>
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 7d43154a7c19732407a8e9ace8a7d1ea13c91f36
|
||||
Subproject commit 010ad7a5f072a5e9d368c756a2473bbd20781433
|
|
@ -23,6 +23,9 @@ import JsonSchemaEditor from './components/common/json-schema/schema/index';
|
|||
import JSONPathPicker from 'vue-jsonpath-picker';
|
||||
|
||||
Vue.use(JsonSchemaEditor);
|
||||
import VuePapaParse from 'vue-papa-parse'
|
||||
Vue.use(VuePapaParse)
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
Vue.use(icon);
|
||||
Vue.use(ElementUI, {
|
||||
|
|
|
@ -571,7 +571,7 @@ export default {
|
|||
create_tag: "Create tag",
|
||||
scenario_step: "Ccenario step",
|
||||
step_total: "Step total",
|
||||
scenario_total: "Scenario total",
|
||||
scenario_total: "Scenario variable",
|
||||
api_list_import: "Api list import",
|
||||
external_import: "External import",
|
||||
wait_controller: "Wait controller",
|
||||
|
|
|
@ -570,7 +570,7 @@ export default {
|
|||
create_tag: "创建Tag",
|
||||
scenario_step: "场景步骤",
|
||||
step_total: "步骤总数",
|
||||
scenario_total: "场景公共参数",
|
||||
scenario_total: "场景变量",
|
||||
api_list_import: "接口列表导入",
|
||||
external_import: "外部导入",
|
||||
wait_controller: "等待控制器",
|
||||
|
|
|
@ -570,7 +570,7 @@ export default {
|
|||
create_tag: "創建Tag",
|
||||
scenario_step: "場景步驟",
|
||||
step_total: "步驟總數",
|
||||
scenario_total: "場景公共參數",
|
||||
scenario_total: "場景變量",
|
||||
api_list_import: "接口列表導入",
|
||||
external_import: "外部導入",
|
||||
wait_controller: "等待控制器",
|
||||
|
|
Loading…
Reference in New Issue